sht PropertyIndex(str name) { int i=0; for (i=0; i<nr_properties; i++) { if (strcmp(properties[i], name) == 0) return i; } MT_lock_set(&mal_contextLock, "propertyIndex"); /* small change it's already added */ for (i=0; i<nr_properties; i++) { if (strcmp(properties[i], name) == 0) { MT_lock_unset(&mal_contextLock, "propertyIndex"); return i; } } if (i >= max_properties) { max_properties += 256; properties = GDKrealloc(properties, max_properties * sizeof(str)); if( properties == NULL){ GDKerror("PropertyIndex" MAL_MALLOC_FAIL); MT_lock_unset(&mal_contextLock, "propertyIndex"); return nr_properties; } } properties[nr_properties] = GDKstrdup(name); MT_lock_unset(&mal_contextLock, "propertyIndex"); return nr_properties++; }
/* COMMAND "unescape": Convert hexadecimal representations to ASCII characters. * All sequences of the form "% HEX HEX" are unescaped. * SIGNATURE: unescape(str) : str; */ str unescape_str(str *retval, str s) { int x, y; str res; if (!s) throw(ILLARG, "url.escape", "url missing"); res = (str) GDKmalloc(strlen(s)); if (!res) throw(MAL, "url.unescape", "malloc failed"); for (x = 0, y = 0; s[x]; ++x, ++y) { if (s[x] == '%') { res[y] = x2c(&s[x + 1]); x += 2; } else { res[y] = s[x]; } } res[y] = '\0'; *retval = GDKrealloc(res, strlen(res)+1); return MAL_SUCCEED; }
static str createExceptionInternal(enum malexception type, const char *fcn, const char *format, va_list ap) { char *message; int len; // if there is an error we allow memory allocation once again #ifndef NDEBUG GDKsetmallocsuccesscount(-1); #endif message = GDKmalloc(GDKMAXERRLEN); if (message == NULL) return M5OutOfMemory; /* last resort */ len = snprintf(message, GDKMAXERRLEN, "%s:%s:", exceptionNames[type], fcn); if (len >= GDKMAXERRLEN) /* shouldn't happen */ return message; len += vsnprintf(message + len, GDKMAXERRLEN - len, format, ap); /* realloc to reduce amount of allocated memory (GDKMAXERRLEN is * way more than what is normally needed) */ if (len < GDKMAXERRLEN) { /* in the extremely unlikely case that GDKrealloc fails, the * original pointer is still valid, so use that and don't * overwrite */ char *newmsg = GDKrealloc(message, len + 1); if (newmsg != NULL) message = newmsg; } char *q = message; for (char *p = strchr(q, '\n'); p; q = p + 1, p = strchr(q, '\n')) fprintf(stderr, "#%s:!ERROR:%.*s\n", MT_thread_getname(), (int) (p - q), q); if (*q) fprintf(stderr, "#%s:!ERROR:%s\n", MT_thread_getname(), q); return message; }
/* COMMAND "escape": this function applies the URI escaping rules defined in * section 2 of [RFC 3986] to the string supplied as 's'. * The effect of the function is to escape a set of identified characters in * the string. Each such character is replaced in the string by an escape * sequence, which is formed by encoding the character as a sequence of octets * in UTF-8, and then reprensenting each of these octets in the form %HH. * * All characters are escaped other than: * [a-z], [A-Z], [0-9], "#", "-", "_", ".", "!", "~", "*", "'", "(", ")" * * This function must always generate hexadecimal values using the upper-case * letters A-F. * * SIGNATURE: escape(str) : str; */ str escape_str(str *retval, str s) { int x, y; str res; if (!s) throw(ILLARG, "url.escape", "url missing"); if (!( res = (str) GDKmalloc( strlen(s) * 3 ) )) throw(MAL, "url.escape", "malloc failed"); for (x = 0, y = 0; s[x]; ++x, ++y) { if (needEscape(s[x])) { if (s[x] == ' ') { res[y] = '+'; } else { sprintf(res+y, "%%%2x", s[x]); y += 2; } } else { res[y] = s[x]; } } res[y] = '\0'; *retval = GDKrealloc(res, strlen(res)+1); return MAL_SUCCEED; }
/* we might actually sort it for better scheduling behavior */ static void q_enqueue_(Queue *q, FlowEvent d) { assert(q); assert(d); if (q->last == q->size) { q->size <<= 1; q->data = (FlowEvent*) GDKrealloc(q->data, sizeof(FlowEvent) * q->size); assert(q->data); } q->data[q->last++] = d; }
static QEP QEPexpandChildren(QEP qep, int extra){ int i; /*extend node */ qep->children = (QEP*) GDKrealloc( (char*) qep->children, sizeof(QEP) * (qep->climit + extra)); if( qep->children == NULL) return NULL; for(i=qep->climit;i <qep->climit + extra; i++) qep->children[i]=0; qep->climit = qep->climit + extra; return qep; }
str BATXMLgroup(xml *ret, const bat *bid) { BAT *b; BUN p, q; const char *t; size_t len, size = BUFSIZ, offset; str buf = GDKmalloc(size); BATiter bi; const char *err = NULL; if (buf == NULL) throw(MAL, "xml.aggr",MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.aggr", RUNTIME_OBJECT_MISSING); } strcpy(buf, str_nil); offset = 0; bi = bat_iterator(b); BATloop(b, p, q) { int n; t = (const char *) BUNtail(bi, p); if (strNil(t)) continue; len = strlen(t) + 1; if (len >= size - offset) { size += len + 128; buf = GDKrealloc(buf, size); if (buf == NULL) { err= MAL_MALLOC_FAIL; goto failed; } } if (offset == 0) n = snprintf(buf, size, "%s", t); else if (buf[0] != *t) { err = "incompatible values in group"; goto failed; } else if (buf[0] == 'A') n = snprintf(buf + offset, size - offset, " %s", t + 1); else if (buf[0] == 'C') n = snprintf(buf + offset, size - offset, "%s", t + 1); else { err = "can only group attributes and element content"; goto failed; } offset += n; }
/* the MAL beautifier is meant to simplify correlation of MAL variables and * the columns in the underlying database. * If the status is set, then we consider the instruction DONE and the result variables * should be shown as well. */ static str shortRenderingTerm(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int idx) { str s, nme; BAT *b; ValRecord *val; char *cv =0; int varid = getArg(p,idx); size_t len = BUFSIZ; s= GDKmalloc(len); if( s == NULL) return NULL; *s = 0; if( isVarConstant(mb,varid) ){ val =&getVarConstant(mb, varid); if ((cv = VALformat(val)) == NULL) { GDKfree(s); return NULL; } if (strlen(cv) >= len) { char *nbuf; len = strlen(cv); nbuf = GDKrealloc(s, len + 1); if (nbuf == NULL) { GDKfree(s); GDKfree(cv); return NULL; } s = nbuf; } snprintf(s,len + 1,"%s",cv); } else { val = &stk->stk[varid]; if ((cv = VALformat(val)) == NULL) { GDKfree(s); return NULL; } nme = getVarName(mb, varid); if ( isaBatType(getArgType(mb,p,idx))){ b = BBPquickdesc(stk->stk[varid].val.bval, true); snprintf(s,BUFSIZ,"%s["BUNFMT"]" ,nme, b?BATcount(b):0); } else snprintf(s,BUFSIZ,"%s=%s ",nme,cv); } GDKfree(cv); return s; }
/* COMMAND "getContent": Retrieve the file referenced * SIGNATURE: getContent(str) : str; */ str URLgetContent(str *retval, url *Str1) { stream *f; str retbuf = NULL; str oldbuf = NULL; char *buf[8096]; ssize_t len; size_t rlen; if ((f = open_urlstream(*Str1)) == NULL) throw(MAL, "url.getContent", "failed to open urlstream"); if (mnstr_errnr(f) != 0) { str err = createException(MAL, "url.getContent", "opening stream failed: %s", mnstr_error(f)); mnstr_destroy(f); *retval = NULL; return err; } rlen = 0; while ((len = mnstr_read(f, buf, 1, sizeof(buf))) > 0) { if (retbuf != NULL) { oldbuf = retbuf; retbuf = GDKrealloc(retbuf, rlen + len + 1); } else { retbuf = GDKmalloc(len + 1); } if (retbuf == NULL) { if (oldbuf != NULL) GDKfree(oldbuf); mnstr_destroy(f); throw(MAL, "url.getContent", "contents too large"); } oldbuf = NULL; (void)memcpy(retbuf + rlen, buf, len); rlen += len; } if (len < 0) { GDKfree(retbuf); throw(MAL, "url.getContent", "read error"); } retbuf[rlen] = '\0'; *retval = retbuf; return MAL_SUCCEED; }
static void q_requeue_(Queue *q, FlowEvent d) { int i; assert(q); assert(d); if (q->last == q->size) { /* enlarge buffer */ q->size <<= 1; q->data = (FlowEvent*) GDKrealloc(q->data, sizeof(FlowEvent) * q->size); assert(q->data); } for (i = q->last; i > 0; i--) q->data[i] = q->data[i - 1]; q->data[0] = d; q->last++; }
static int JSONnew(JSON *js) { JSONterm *term; if (js->free == js->size) { term = (JSONterm *) GDKrealloc(js->elm, sizeof(JSONterm) * (js->size + 8)); if (term == NULL) { js->error = createException(MAL, "json.new", MAL_MALLOC_FAIL); return js->free - 1; } js->elm = term; memset(((char *) term) + sizeof(JSONterm) * js->size, 0, 8 * sizeof(JSONterm)); js->size += 8; if (jsonhint < js->size) jsonhint = js->size; } return js->free++; }
str JSONrenderobject(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { BAT **bl; char *result, *row; int i; size_t len, lim, l; json *ret; BUN j, cnt; (void) cntxt; bl = JSONargumentlist(mb, stk, pci); if (bl == 0) throw(MAL, "json.renderobject", "Non-aligned BAT sizes"); for (i = pci->retc; i < pci->argc; i += 2) if (getArgType(mb, pci, i) != TYPE_str) throw(MAL, "json.renderobject", "Keys missing"); cnt = BATcount(bl[pci->retc + 1]); result = (char *) GDKmalloc(lim = BUFSIZ); result[0] = '['; result[1] = 0; len = 1; for (j = 0; j < cnt; j++) { row = JSONrenderRowObject(bl, mb, stk, pci, j); l = strlen(row); while (l + 2 > lim - len) row = (char *) GDKrealloc(row, lim = cnt * l <= lim ? cnt * l : lim + BUFSIZ); strcpy(result + len, row); GDKfree(row); len += l; result[len++] = ','; result[len] = 0; } result[len - 1] = ']'; ret = getArgReference_TYPE(stk, pci, 0, json); *ret = result; return MAL_SUCCEED; }
str mnstr_read_stringwrap(str *res, Stream *S) { stream *s = *(stream **)S; ssize_t len = 0; size_t size = CHUNK + 1; char *buf = GDKmalloc(size), *start = buf; while ((len = mnstr_read(s, start, 1, CHUNK)) > 0) { size += len; buf = GDKrealloc(buf, size); start = buf + size - CHUNK - 1; *start = '\0'; } if (len < 0) throw(IO, "streams.readStr", "failed to read string"); start += len; *start = '\0'; *res = buf; return MAL_SUCCEED; }
static str JSONrenderRowObject(BAT **bl, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, BUN idx) { int i, tpe; char *row, *name = 0, *val = 0; size_t len, lim, l; void *p; BATiter bi; row = (char *) GDKmalloc(lim = BUFSIZ); row[0] = '{'; row[1] = 0; len = 1; val = (char *) GDKmalloc(BUFSIZ); for (i = pci->retc; i < pci->argc; i += 2) { name = stk->stk[getArg(pci, i)].val.sval; bi = bat_iterator(bl[i + 1]); p = BUNtail(bi, BUNfirst(bl[i + 1]) + idx); tpe = getColumnType(getArgType(mb, pci, i + 1)); ATOMformat(tpe, p, &val); if (strncmp(val, "nil", 3) == 0) strcpy(val, "null"); l = strlen(name) + strlen(val); while (l > lim - len) row = (char *) GDKrealloc(row, lim += BUFSIZ); snprintf(row + len, lim - len, "\"%s\":%s,", name, val); len += l + 4; } if (row[1]) row[len - 1] = '}'; else { row[1] = '}'; row[2] = 0; } GDKfree(val); return row; }
static str JSONrenderRowArray(BAT **bl, MalBlkPtr mb, InstrPtr pci, BUN idx) { int i, tpe; char *row, *val = 0; size_t len, lim, l; void *p; BATiter bi; row = (char *) GDKmalloc(lim = BUFSIZ); row[0] = '['; row[1] = 0; len = 1; val = (char *) GDKmalloc(BUFSIZ); for (i = pci->retc; i < pci->argc; i++) { bi = bat_iterator(bl[i]); p = BUNtail(bi, BUNfirst(bl[i]) + idx); tpe = getColumnType(getArgType(mb, pci, i)); ATOMformat(tpe, p, &val); if (strncmp(val, "nil", 3) == 0) strcpy(val, "null"); l = strlen(val); while (l > lim - len) row = (char *) GDKrealloc(row, lim += BUFSIZ); snprintf(row + len, lim - len, "%s,", val); len += l + 1; } if (row[1]) row[len - 1] = ']'; else { row[1] = '}'; row[2] = 0; } GDKfree(val); return row; }
static str renderTerm(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int idx, int flg) { char *buf =0; char *nme =0; int nameused = 0; size_t len = 0, maxlen = BUFSIZ; ValRecord *val = 0; char *cv =0; str tpe; int showtype = 0, closequote=0; int varid = getArg(p,idx); buf = GDKzalloc(maxlen); if( buf == NULL) { addMalException(mb, "renderTerm:Failed to allocate"); return NULL; } // show the name when required or is used if ((flg & LIST_MAL_NAME) && !isVarConstant(mb,varid) && !isVarTypedef(mb,varid)) { nme = getVarName(mb,varid); len +=snprintf(buf, maxlen, "%s", nme); nameused =1; } // show the value when required or being a constant if( ((flg & LIST_MAL_VALUE) && stk != 0) || isVarConstant(mb,varid) ){ if (nameused){ strcat(buf + len,"="); len++; } // locate value record if (isVarConstant(mb,varid)){ val = &getVarConstant(mb, varid); showtype= getVarType(mb,varid) != TYPE_str && getVarType(mb,varid) != TYPE_bit; } else if( stk) val = &stk->stk[varid]; if ((cv = VALformat(val)) == NULL) { addMalException(mb, "renderTerm:Failed to allocate"); GDKfree(buf); return NULL; } if (len + strlen(cv) >= maxlen) { char *nbuf= GDKrealloc(buf, maxlen =len + strlen(cv) + BUFSIZ); if( nbuf == 0){ GDKfree(buf); GDKfree(cv); addMalException(mb,"renderTerm:Failed to allocate"); return NULL; } buf = nbuf; } if( strcmp(cv,"nil") == 0){ strcat(buf+len,cv); len += strlen(buf+len); GDKfree(cv); showtype = showtype || getBatType(getVarType(mb,varid)) > TYPE_str || ((isVarUDFtype(mb,varid) || isVarTypedef(mb,varid)) && isVarConstant(mb,varid)) || isaBatType(getVarType(mb,varid)); } else{ if ( !isaBatType(getVarType(mb,varid)) && getBatType(getVarType(mb,varid)) > TYPE_str ){ closequote = 1; strcat(buf+len,"\""); len++; } strcat(buf+len,cv); len += strlen(buf+len); GDKfree(cv); if( closequote ){ strcat(buf+len,"\""); len++; } showtype = showtype || closequote > TYPE_str || ((isVarUDFtype(mb,varid) || isVarTypedef(mb,varid) || (flg & (LIST_MAL_REMOTE | LIST_MAL_TYPE))) && isVarConstant(mb,varid)) || (isaBatType(getVarType(mb,varid)) && idx < p->retc); if (stk && isaBatType(getVarType(mb,varid)) && stk->stk[varid].val.bval ){ BAT *d= BBPquickdesc(stk->stk[varid].val.bval, true); if( d) len += snprintf(buf+len,maxlen-len,"[" BUNFMT "]", BATcount(d)); } } } // show the type when required or frozen by the user // special care should be taken with constants, they may have been casted if ((flg & LIST_MAL_TYPE) || (isVarUDFtype(mb, varid) && idx < p->retc) || isVarTypedef(mb,varid) || showtype){ strcat(buf + len,":"); len++; tpe = getTypeName(getVarType(mb, varid)); len += snprintf(buf+len,maxlen-len,"%s",tpe); GDKfree(tpe); } if( len >= maxlen) addMalException(mb,"renderTerm:Value representation too large"); return buf; }
static str JSONfoldKeyValue(str *ret, const bat *id, const bat *key, const bat *values) { BAT *bo = 0, *bk = 0, *bv; BATiter boi, bki, bvi; int tpe; char *row, *val = 0, *nme = 0; BUN i, cnt; size_t len, lim, l; void *p; oid o = 0;; if (key) { bk = BATdescriptor(*key); if (bk == NULL) { *ret = GDKstrdup(str_nil); throw(MAL, "json.fold", RUNTIME_OBJECT_MISSING); } } bv = BATdescriptor(*values); if (bv == NULL) { if (bk) BBPunfix(bk->batCacheid); *ret = GDKstrdup(str_nil); throw(MAL, "json.fold", RUNTIME_OBJECT_MISSING); } tpe = bv->ttype; cnt = BATcount(bv); if (bk) bki = bat_iterator(bk); bvi = bat_iterator(bv); if (id) { bo = BATdescriptor(*id); if (bo == NULL) { if (bk) BBPunfix(bk->batCacheid); BBPunfix(bv->batCacheid); throw(MAL, "json.nest", RUNTIME_OBJECT_MISSING); } } row = (char *) GDKmalloc(lim = BUFSIZ); row[0] = '['; row[1] = 0; len = 1; val = (char *) GDKmalloc(BUFSIZ); if (id) { boi = bat_iterator(bo); o = *(oid *) BUNtail(boi, BUNfirst(bo)); } if (bk) bki = bat_iterator(bk); bvi = bat_iterator(bv); for (i = 0; i < cnt; i++) { if (id &&bk) { p = BUNtail(boi, BUNfirst(bo) + i); if (*(oid *) p != o) { snprintf(row + len, lim - len, ", "); len += 2; o = *(oid *) p; } } if (bk) { nme = (str) BUNtail(bki, BUNfirst(bk) + i); l = strlen(nme); while (l + 3 > lim - len) row = (char *) GDKrealloc(row, lim = (lim / (i + 1)) * cnt + BUFSIZ + l + 3); if (row == NULL) { *ret = GDKstrdup(str_nil); if (bo) BBPunfix(bo->batCacheid); if (bk) BBPunfix(bk->batCacheid); BBPunfix(bv->batCacheid); throw(MAL, "json.fold", MAL_MALLOC_FAIL); } if (strcmp(nme, str_nil)) { snprintf(row + len, lim - len, "\"%s\":", nme); len += l + 3; } } bvi = bat_iterator(bv); p = BUNtail(bvi, BUNfirst(bv) + i); if (tpe == TYPE_json) val = p; else { ATOMformat(tpe, p, &val); if (strncmp(val, "nil", 3) == 0) strcpy(val, "null"); } l = strlen(val); while (l > lim - len) row = (char *) GDKrealloc(row, lim = (lim / (i + 1)) * cnt + BUFSIZ + l + 3); if (row == NULL) { if (bo) BBPunfix(bo->batCacheid); if (bk) BBPunfix(bk->batCacheid); BBPunfix(bv->batCacheid); *ret = GDKstrdup(str_nil); throw(MAL, "json.fold", MAL_MALLOC_FAIL); } strncpy(row + len, val, l); len += l; row[len++] = ','; row[len] = 0; } if (row[1]) { row[len - 1] = ']'; row[len] = 0; } else { row[1] = ']'; row[2] = 0; } if (tpe != TYPE_json) GDKfree(val); if (bo) BBPunfix(bo->batCacheid); if (bk) BBPunfix(bk->batCacheid); BBPunfix(bv->batCacheid); *ret = row; return MAL_SUCCEED; }
/* * The dataflow administration is based on administration of * how many variables are still missing before it can be executed. * For each instruction we keep a list of instructions whose * blocking counter should be decremented upon finishing it. */ static str DFLOWinitBlk(DataFlow flow, MalBlkPtr mb, int size) { int pc, i, j, k, l, n, etop = 0; int *assign; InstrPtr p; if (flow == NULL) throw(MAL, "dataflow", "DFLOWinitBlk(): Called with flow == NULL"); if (mb == NULL) throw(MAL, "dataflow", "DFLOWinitBlk(): Called with mb == NULL"); PARDEBUG fprintf(stderr, "#Initialize dflow block\n"); assign = (int *) GDKzalloc(mb->vtop * sizeof(int)); if (assign == NULL) throw(MAL, "dataflow", "DFLOWinitBlk(): Failed to allocate assign"); etop = flow->stop - flow->start; for (n = 0, pc = flow->start; pc < flow->stop; pc++, n++) { p = getInstrPtr(mb, pc); if (p == NULL) { GDKfree(assign); throw(MAL, "dataflow", "DFLOWinitBlk(): getInstrPtr() returned NULL"); } /* initial state, ie everything can run */ flow->status[n].flow = flow; flow->status[n].pc = pc; flow->status[n].state = DFLOWpending; flow->status[n].cost = -1; flow->status[n].flow->error = NULL; /* administer flow dependencies */ for (j = p->retc; j < p->argc; j++) { /* list of instructions that wake n-th instruction up */ if (!isVarConstant(mb, getArg(p, j)) && (k = assign[getArg(p, j)])) { assert(k < pc); /* only dependencies on earlier instructions */ /* add edge to the target instruction for wakeup call */ k -= flow->start; if (flow->nodes[k]) { /* add wakeup to tail of list */ for (i = k; flow->edges[i] > 0; i = flow->edges[i]) ; flow->nodes[etop] = n; flow->edges[etop] = -1; flow->edges[i] = etop; etop++; (void) size; if( etop == size){ flow->nodes = (int*) GDKrealloc(flow->nodes, sizeof(int) * 2 * size); flow->edges = (int*) GDKrealloc(flow->edges, sizeof(int) * 2 * size); size *=2; } } else { flow->nodes[k] = n; flow->edges[k] = -1; } flow->status[n].blocks++; } /* list of instructions to be woken up explicitly */ if (!isVarConstant(mb, getArg(p, j))) { /* be careful, watch out for garbage collection interference */ /* those should be scheduled after all its other uses */ l = getEndOfLife(mb, getArg(p, j)); if (l != pc && l < flow->stop && l > flow->start) { /* add edge to the target instruction for wakeup call */ PARDEBUG fprintf(stderr, "#endoflife for %s is %d -> %d\n", getVarName(mb, getArg(p, j)), n + flow->start, l); assert(pc < l); /* only dependencies on earlier instructions */ l -= flow->start; if (flow->nodes[n]) { /* add wakeup to tail of list */ for (i = n; flow->edges[i] > 0; i = flow->edges[i]) ; flow->nodes[etop] = l; flow->edges[etop] = -1; flow->edges[i] = etop; etop++; if( etop == size){ flow->nodes = (int*) GDKrealloc(flow->nodes, sizeof(int) * 2 * size); flow->edges = (int*) GDKrealloc(flow->edges, sizeof(int) * 2 * size); size *=2; } } else { flow->nodes[n] = l; flow->edges[n] = -1; } flow->status[l].blocks++; } } } for (j = 0; j < p->retc; j++) assign[getArg(p, j)] = pc; /* ensure recognition of dependency on first instruction and constant */ } GDKfree(assign); PARDEBUG { for (n = 0; n < flow->stop - flow->start; n++) { mnstr_printf(GDKstdout, "#[%d] %d: ", flow->start + n, n); printInstruction(GDKstdout, mb, 0, getInstrPtr(mb, n + flow->start), LIST_MAL_STMT | LIST_MAPI); mnstr_printf(GDKstdout, "#[%d]Dependents block count %d wakeup", flow->start + n, flow->status[n].blocks); for (j = n; flow->edges[j]; j = flow->edges[j]) { mnstr_printf(GDKstdout, "%d ", flow->start + flow->nodes[j]); if (flow->edges[j] == -1) break; } mnstr_printf(GDKstdout, "\n"); } } #ifdef USE_MAL_ADMISSION memorypool = memoryclaims = 0; #endif return MAL_SUCCEED; }
char * locate_file(const char *basename, const char *ext, bit recurse) { const char *mod_path = GDKgetenv("monet_mod_path"); char *fullname; size_t fullnamelen; size_t filelen = strlen(basename) + strlen(ext); str strs[MAXMULTISCRIPT]; /* hardwired limit */ int lasts = 0; if (mod_path == NULL) return NULL; while (*mod_path == PATH_SEP) mod_path++; if (*mod_path == 0) return NULL; fullnamelen = 512; fullname = GDKmalloc(fullnamelen); if (fullname == NULL) return NULL; while (*mod_path) { size_t i; const char *p; int fd; DIR *rdir; if ((p = strchr(mod_path, PATH_SEP)) != NULL) { i = p - mod_path; } else { i = strlen(mod_path); } while (i + filelen + 2 > fullnamelen) { char *tmp; fullnamelen += 512; tmp = GDKrealloc(fullname, fullnamelen); if (tmp == NULL) { GDKfree(fullname); return NULL; } fullname = tmp; } /* we are now sure the directory name, file base name, extension, and separator fit into fullname, so we don't need to do any extra checks */ strncpy(fullname, mod_path, i); fullname[i] = DIR_SEP; strcpy(fullname + i + 1, basename); /* see if this is a directory, if so, recurse */ if (recurse == 1 && (rdir = opendir(fullname)) != NULL) { struct dirent *e; /* list *ext, sort, return */ while ((e = readdir(rdir)) != NULL) { if (strcmp(e->d_name, "..") == 0 || strcmp(e->d_name, ".") == 0) continue; if (strcmp(e->d_name + strlen(e->d_name) - strlen(ext), ext) == 0) { int len; strs[lasts] = GDKmalloc(strlen(fullname) + sizeof(DIR_SEP) + strlen(e->d_name) + sizeof(PATH_SEP) + 1); if (strs[lasts] == NULL) { while (lasts >= 0) GDKfree(strs[lasts--]); GDKfree(fullname); (void)closedir(rdir); return NULL; } len = sprintf(strs[lasts], "%s%c%s%c", fullname, DIR_SEP, e->d_name, PATH_SEP); if (len == -1 || len >= FILENAME_MAX) { while (lasts >= 0) GDKfree(strs[lasts--]); GDKfree(fullname); (void)closedir(rdir); return NULL; } lasts++; } if (lasts >= MAXMULTISCRIPT) break; } (void)closedir(rdir); } else { strcat(fullname + i + 1, ext); if ((fd = open(fullname, O_RDONLY | O_CLOEXEC)) >= 0) { char *tmp; close(fd); tmp = GDKrealloc(fullname, strlen(fullname) + 1); if (tmp == NULL) GDKfree(fullname); return tmp; } } if ((mod_path = p) == NULL) break; while (*mod_path == PATH_SEP) mod_path++; } if (lasts > 0) { size_t i = 0; int c; char *tmp; /* assure that an ordering such as 10_first, 20_second works */ qsort(strs, lasts, sizeof(char *), cmpstr); for (c = 0; c < lasts; c++) i += strlen(strs[c]) + 1; /* PATH_SEP or \0 */ tmp = GDKrealloc(fullname, i); if( tmp == NULL){ GDKfree(fullname); return NULL; } fullname = tmp; i = 0; for (c = 0; c < lasts; c++) { if (strstr(fullname, strs[c]) == NULL) { strcpy(fullname + i, strs[c]); i += strlen(strs[c]); } GDKfree(strs[c]); } fullname[i - 1] = '\0'; return fullname; } /* not found */ GDKfree(fullname); return NULL; }
str BATXMLforest(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { bat *ret = getArgReference_bat(stk, pci, 0); BAT *bn; BATiter *bi; BUN *p, *q; str buf; int i; size_t offset, len, size = BUFSIZ; const char *err = OPERATION_FAILED; (void) mb; (void) cntxt; buf = GDKmalloc(size); bi = GDKmalloc(sizeof(BATiter) * pci->argc); p = GDKmalloc(sizeof(BUN) * pci->argc); q = GDKmalloc(sizeof(BUN) * pci->argc); if (buf == NULL || bi == NULL || p == NULL || q == NULL) { if (buf) GDKfree(buf); if (bi) GDKfree(bi); if (p) GDKfree(p); if (q) GDKfree(q); throw(MAL, "xml.forest", MAL_MALLOC_FAIL); } /* collect the admin for the xml elements */ for (i = pci->retc; i < pci->argc; i++) { if ((bi[i].b = BATdescriptor(*getArgReference_bat(stk, pci, i))) == NULL) break; p[i] = BUNfirst(bi[i].b); q[i] = BUNlast(bi[i].b); } /* check for errors */ if (i != pci->argc) { for (i--; i >= pci->retc; i--) if (bi[i].b) BBPunfix(bi[i].b->batCacheid); GDKfree(bi); GDKfree(p); GDKfree(q); GDKfree(buf); throw(MAL, "xml.forest", INTERNAL_BAT_ACCESS); } prepareResult(bn, bi[pci->retc].b, TYPE_xml, "forest", for (i = pci->retc; i < pci->argc; i++) BBPunfix(bi[i].b->batCacheid); GDKfree(bi); GDKfree(p); GDKfree(q); GDKfree(buf)); while (p[pci->retc] < q[pci->retc]) { const char *t; /* fetch the elements */ offset = 0; strcpy(buf, str_nil); for (i = pci->retc; i < pci->argc; i++) { int n; t = (const char *) BUNtail(bi[i], p[i]); if (strNil(t)) continue; if ((len = strlen(t)) >= size - offset) { size += len + 128; buf = GDKrealloc(buf, size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } if (offset == 0) n = snprintf(buf, size, "%s", t); else if (buf[0] != *t) { err = "incompatible values in forest"; goto bunins_failed; } else if (buf[0] == 'A') n = snprintf(buf + offset, size - offset, " %s", t + 1); else if (buf[0] == 'C') n = snprintf(buf + offset, size - offset, "%s", t + 1); else { err = "can only combine attributes and element content"; goto bunins_failed; } offset += n; } bunfastapp(bn, buf); if (offset == 0) bn->T->nonil = 0; for (i = pci->retc; i < pci->argc; i++) if (bi[i].b) p[i]++; } GDKfree(buf); finalizeResult(ret, bn, bi[pci->retc].b); GDKfree(bi); GDKfree(p); GDKfree(q); return MAL_SUCCEED; bunins_failed: for (i = pci->retc; i < pci->argc; i++) if (bi[i].b) BBPunfix(bi[i].b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); GDKfree(bi); GDKfree(p); GDKfree(q); throw(MAL, "xml.forest", "%s", err); }
/* * The standard supports specific mappings for * NULL values,i.e. {null,absent,empty,nil,niloncontent) * in the context of an element and forest construction. * The standard should be studied in more detail, because * the syntax(rules) seem ambiguous. * It applies to all components of an element or their * concatenation. * * For the time being, the variaton on XMLtag seems the * most reasonable interpretation. */ str BATXMLoptions(bat *ret, const char * const *name, const char * const *options, const bat *bid) { BAT *b, *bn; BUN p, q; str buf = GDKmalloc(BUFSIZ); str val = GDKmalloc(BUFSIZ); size_t size = BUFSIZ, len = strlen(*name); BATiter bi; const char *err = OPERATION_FAILED " During bulk options analysis"; if (val == NULL || buf == NULL) { if (val != NULL) GDKfree(val); if (buf != NULL) GDKfree(buf); throw(MAL, "batxml.options", MAL_MALLOC_FAIL); } if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(val); GDKfree(buf); throw(MAL, "xml.options", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "options", GDKfree(val); GDKfree(buf)); if (strcmp(*options, "absent") == 0) buf[0] = 0; else if (strcmp(*options, "empty") == 0) snprintf(buf, size, "<%s></%s>", *name, *name); else if (strcmp(*options, "null") == 0) snprintf(buf, size, "null"); else if (strcmp(*options, "nil") == 0) snprintf(buf, size, "nil"); else { /*if(strcmp(*options,"niloncontent")==0) */ err = PROGRAM_NYI; goto bunins_failed; } snprintf(val, size, "<%s>", *name); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); if (strNil(t)) { bunfastapp(bn, buf); } else { if (strlen(t) > size - 2 * len - 6) { size += strlen(t); val = (char *) GDKrealloc(val, size + strlen(t)); if (val == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } snprintf(val + len + 2, size - len, "%s</%s>", t, *name); bunfastapp(bn, val); } } GDKfree(val); GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); if (val != NULL) GDKfree(val); throw(MAL, "batxml.options", "%s", err); }
str JSONgroupStr(str *ret, const bat *bid) { BAT *b; BUN p, q; const char *t = NULL; size_t len, size = BUFSIZ, offset, cnt = 0; str buf = GDKmalloc(size); BATiter bi; const char *err = NULL; char temp[128] = ""; const double *val = NULL; if (buf == NULL) throw(MAL, "json.group", MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "json.agg", RUNTIME_OBJECT_MISSING); } assert(b->ttype == TYPE_str || b->ttype == TYPE_dbl); strcpy(buf, str_nil); offset = 0; bi = bat_iterator(b); BATloop(b, p, q) { int n = 0, nil = 0; switch (b->ttype) { case TYPE_str: t = (const char *) BUNtail(bi, p); nil = (strNil(t)); break; case TYPE_dbl: val = (const double *) BUNtail(bi, p); nil = (*val == dbl_nil); if (!nil) snprintf(temp, sizeof(temp), "%f", *val); t = (const char *) temp; break; } if (nil) continue; if (!cnt) offset = snprintf(buf, size, "[ "); len = strlen(t) + 1 + 4; /* closing bracket and optional ',' */ if (len >= size - offset) { str nbuf; size += len + 128; nbuf = GDKrealloc(buf, size); if (nbuf == NULL) { err = MAL_MALLOC_FAIL; goto failed; } buf = nbuf; } if (cnt) offset += snprintf(buf + offset, size - offset, ", "); switch (b->ttype) { case TYPE_str: n = snprintf(buf + offset, size - offset, "\"%s\"", t); break; case TYPE_dbl: n = snprintf(buf + offset, size - offset, "%s", t); break; } cnt++; offset += n; }