str BATXMLxml2str(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; BATiter bi; if ((b = BATdescriptor(*bid)) == NULL) throw(MAL, "xml.str", INTERNAL_BAT_ACCESS); prepareResult(bn, b, TYPE_str, "str", (void) 0); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); if (strNil(t)) { bunfastapp(bn, t); bn->T->nonil = 0; } else { assert(*t == 'A' || *t == 'C' || *t == 'D'); bunfastapp(bn, t + 1); } } finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); throw(MAL, "xml.str", OPERATION_FAILED " during bulk coercion"); }
/****************************** * QGRAMNORMALIZE * * This function 'normalizes' a string so valid q-grams can be made of it: * All characters are transformed to uppercase, and all characters * which are not letters or digits are stripped to a single space. * * qgramnormalize("Hallo, allemaal!").print(); --> "HALLO ALLEMAAL" * qgramnormalize(" '' t ' est").print(); --> [ "T EST" ] * *****************************/ str CMDqgramnormalize(str *res, str *Input) { char *input = *Input; int i, j = 0; char c, last = ' '; RETURN_NIL_IF(strNil(input), TYPE_str); *res = (str) GDKmalloc(sizeof(char) * (strlen(input) + 1)); /* normalized strings are never longer than original */ for (i = 0; input[i]; i++) { c = toupper(input[i]); if (!(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9'))) c = ' '; if (c != ' ' || last != ' ') { (*res)[j++] = c; } last = c; } (*res)[j] = 0; /* strip final whitespace */ while (j > 0 && (*res)[--j] == ' ') (*res)[j] = 0; return MAL_SUCCEED; }
str BATXMLdocument(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; BATiter bi; size_t size = BUFSIZ; str buf = GDKmalloc(size); const char *err = OPERATION_FAILED; if (buf == NULL) throw(MAL,"xml.document",MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.document", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "document", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); xmlDocPtr doc; int len; xmlChar *s; if (strNil(t)) { bunfastapp(bn, str_nil); bn->T->nonil = 0; continue; } len = (int) strlen(t); doc = xmlParseMemory(t, len); if (doc == NULL) { err = OPERATION_FAILED XML_PARSE_ERROR; goto bunins_failed; } xmlDocDumpMemory(doc, &s, &len); xmlFreeDoc(doc); if ((size_t) len + 2 >= size) { GDKfree(buf); size = (size_t) len + 128; buf = GDKmalloc(size); if (buf == NULL) { err= MAL_MALLOC_FAIL; goto bunins_failed; } } buf[0] = 'D'; strcpy(buf + 1, (char *) s); bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: GDKfree(buf); BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); throw(MAL, "xml.document", "%s", err); }
str BATXMLcomment(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf = GDKmalloc(size); BATiter bi; const char *err= OPERATION_FAILED; if (buf == NULL) throw(MAL, "xml.comment", MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.comment", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "comment", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; if (strNil(t)) { bunfastapp(bn, str_nil); bn->T->nonil = 0; continue; } if (strstr(t, "--") != NULL) { err = XML_COMMENT_ERROR; goto bunins_failed; } len = strlen(t); if (len + 9 >= size) { /* make sure there is enough space */ size = len + 128; /* free/malloc so we don't copy */ GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } snprintf(buf, size, "C<!--%s-->", t); bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.comment", "%s", err); }
str soundex_impl(str *res, str *Name) { RETURN_NIL_IF(strNil(*Name), TYPE_str); *res = (str) GDKmalloc(sizeof(char) * (SoundexLen + 1)); /* calculate Key for Name */ soundex_code(*Name, *res); return MAL_SUCCEED; }
/* * The core of the activity is str2xml, where the actual strings * are constructed. * To avoid repetitive copying we make sure that the garbage * collector does not remove the xml intermediates. * This way, we know that as long as the xml-variables are not * reused, the complete structure of the xml document(s) are available. * We merely have to collect the pieces. * [FOR LATER, FIRST GO FOR THE EASY IMPLEMENTATION] * XML values are represented by strings already. */ str BATXMLstr2xml(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf; const char *err= OPERATION_FAILED; BATiter bi; buf = GDKmalloc(size); if (buf == NULL) throw(MAL,"xml.str2xml",MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.xml", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "xml", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; if (strNil(t)) { bunfastapp(bn, str_nil); bn->T->nonil = 0; continue; } len = strlen(t) * 6 + 1; if (size < len) { size = len + 128; GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } buf[0] = 'C'; XMLquotestring(t, buf + 1, size - 1); bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.xml", "%s", err); }
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; }
str soundex_impl(str *res, str *Name) { RETURN_NIL_IF(strNil(*Name), TYPE_str); *res = (str) GDKmalloc(sizeof(char) * (SoundexLen + 1)); if( *res == NULL) throw(MAL,"soundex", MAL_MALLOC_FAIL); /* calculate Key for Name */ soundex_code(*Name, *res); return MAL_SUCCEED; }
static str JSONfilterInternal(json *ret, json *js, str *expr, str other) { pattern terms[MAXTERMS]; int tidx = 0; JSON *jt; str j = *js, msg = MAL_SUCCEED, s; json result = 0; size_t l; (void) other; if (strNil(j)) { *ret = GDKstrdup(j); return MAL_SUCCEED; } memset((char *) terms, 0, MAXTERMS * sizeof(pattern)); msg = JSONcompile(*expr, terms); if (msg) return msg; jt = JSONparse(j, FALSE); CHECK_JSON(jt); result = s = JSONmatch(jt, 0, terms, tidx); // process all other PATH expression for (tidx++; tidx < MAXTERMS && terms[tidx].token; tidx++) if (terms[tidx].token == END_STEP && tidx + 1 < MAXTERMS && terms[tidx + 1].token) { s = JSONmatch(jt, 0, terms, ++tidx); result = JSONglue(result, s, ','); } if (result) { l = strlen(result); if (result[l - 1] == ',') result[l - 1] = 0; } else l = 3; s = GDKzalloc(l + 3); snprintf(s, l + 3, "[%s]", (result ? result : "")); GDKfree(result); for (l = 0; terms[l].token; l++) if (terms[l].name) GDKfree(terms[l].name); JSONfree(jt); *ret = s; return msg; }
str BATXMLisdocument(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; BATiter bi; if ((b = BATdescriptor(*bid)) == NULL) throw(MAL, "xml.isdocument", INTERNAL_BAT_ACCESS); prepareResult(bn, b, TYPE_bit, "isdocument", (void) 0); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); xmlDocPtr doc; bit val; if (strNil(t)) { val = bit_nil; bn->T->nonil = 0; } else { doc = xmlParseMemory(t, (int) strlen(t)); if (doc == NULL) { val = 0; } else { xmlFreeDoc(doc); val = 1; } } bunfastapp(bn, &val); } finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); throw(MAL, "xml.isdocument", OPERATION_FAILED " During bulk processing"); }
/* * 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 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); }
str BATXMLelement(bat *ret, const char * const *name, xml *nspace, xml *attr, const bat *bid) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf; BATiter bi; size_t elemlen, namelen; const char *err = OPERATION_FAILED; if (strNil(*name)) throw(MAL, "xml.element", XML_NO_ELEMENT); if (xmlValidateName((xmlChar *) *name, 0) != 0) throw(MAL, "xml.element", XML_ATTRIBUTE_INVALID); if (nspace && !strNil(*nspace) && **nspace) throw(MAL, "xml.element", XML_NO_NAMESPACE); namelen = strlen(*name); elemlen = namelen + 5; if (nspace && !strNil(*nspace)) { if (**nspace != 'A') throw(MAL, "xml.element", XML_ILLEGAL_NAMESPACE); elemlen += strlen(*nspace); /* " " + nspace (nspace contains initial 'A' which is replaced by space) */ } if (attr && !strNil(*attr)) { if (**attr != 'A') throw(MAL, "xml.element", XML_ILLEGAL_ATTRIBUTE); elemlen += strlen(*attr); /* " " + attr (attr contains initial 'A' which is replaced by space) */ } buf = GDKmalloc(size); if (buf == NULL) throw(MAL, "xml.attribute", MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.element", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "element", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; len = elemlen; if (!strNil(t)) { if (*t != 'C') { err = XML_ILLEGAL_CONTENT; goto bunins_failed; } len += strlen(t + 1) + namelen + 2; /* extra "<", ">", and name ("/" already counted) */ } if (len >= size) { /* make sure there is enough space */ size = len + 128; /* free/malloc so we don't copy */ GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } if (strNil(t) && (!attr || strNil(*attr))) { strcpy(buf, str_nil); bn->T->nonil = 0; } else { int i = snprintf(buf, size, "C<%s", *name); if (nspace && !strNil(*nspace)) i += snprintf(buf + i, size - i, " %s", *nspace + 1); if (attr && !strNil(*attr)) i += snprintf(buf + i, size - i, " %s", *attr + 1); if (!strNil(t)) i += snprintf(buf + i, size - i, ">%s</%s>", t + 1, *name); else i += snprintf(buf + i, size - i, "/>"); } bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.element", "%s", err); }
str BATXMLattribute(bat *ret, const char * const *name, const bat *bid) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf; BATiter bi; size_t attrlen; const char *err = OPERATION_FAILED; if (strNil(*name)) throw(MAL, "xml.attribute", XML_ATTRIBUTE_ERROR); if (xmlValidateName((xmlChar *) *name, 0) != 0) throw(MAL, "xml.attribute", XML_ATTRIBUTE_INVALID); attrlen = strlen(*name) + 5; buf = GDKmalloc(size); if (buf == NULL) throw(MAL, "xml.attribute", MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.attribute", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "attribute", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; len = attrlen; if (!strNil(t)) len += strlen(t) * 6 + 1; if (len >= size) { /* make sure there is enough space */ size = len + 128; /* free/malloc so we don't copy */ GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } if (strNil(t)) { strcpy(buf, str_nil); bn->T->nonil = 0; } else { int n = snprintf(buf, size, "A%s = \"", *name); size_t m = XMLquotestring(t, buf + n, size - n); strcpy(buf + n + m, "\""); } bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.attribute", "%s", err); }
str BATXMLroot(bat *ret, const bat *bid, const char * const *version, const char * const *standalone) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf; BATiter bi; size_t hdrlen; const char *err = OPERATION_FAILED; hdrlen = 8; if (!strNil(*version) && **version) { if (strcmp(*version, "1.0") != 0 && strcmp(*version, "1.1") != 0) throw(MAL, "xml.root", XML_VERSION_ERROR); hdrlen += 11 + strlen(*version); /* strlen(" version=\"\"") */ } if (!strNil(*standalone) && **standalone) { if (strcmp(*standalone, "yes") != 0 && strcmp(*standalone, "no") != 0) throw(MAL, "xml.root", XML_STANDALONE_ERROR "illegal XML standalone value"); hdrlen += 14 + strlen(*standalone); /* strlen(" standalone=\"\"") */ } buf = GDKmalloc(size); if (buf == NULL) throw(MAL, "xml.root", MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.pi", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "pi", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len, i; bit isdoc; len = hdrlen; if (!strNil(t)) len += strlen(t); if (len >= size) { /* make sure there is enough space */ size = len + 128; /* free/malloc so we don't copy */ GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } if (strNil(t)) { strcpy(buf, str_nil); bn->T->nonil = 0; } else { strcpy(buf, "D<?xml"); i = strlen(buf); if (!strNil(*version) && **version) i += snprintf(buf + i, len - i, " version=\"%s\"", *version); if (!strNil(*standalone) && **standalone) i += snprintf(buf + i, len - i, " standalone=\"%s\"", *standalone); snprintf(buf + i, len - i, "?>%s", t + 1); buf++; XMLisdocument(&isdoc, &buf); /* check well-formedness */ buf--; if (!isdoc) { err = XML_NOT_WELL_FORMED; goto bunins_failed; } } bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.root", "%s", err); }
str BATXMLpi(bat *ret, const char * const *target, const bat *bid) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf; BATiter bi; size_t tgtlen; const char *err = OPERATION_FAILED; if (strNil(*target)) throw(MAL, "xml.pi", XML_PI_ERROR); buf = GDKmalloc(size); if (buf == NULL) throw(MAL, "xml.pi", MAL_MALLOC_FAIL); tgtlen = strlen(*target) + 6; if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.pi", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "pi", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; len = tgtlen; if (!strNil(t)) len += strlen(t) * 6 + 1; if (len >= size) { /* make sure there is enough space */ size = len + 128; /* free/malloc so we don't copy */ GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } if (strNil(t)) snprintf(buf, size, "C<?%s?>", *target); else { int n = snprintf(buf, size, "C<?%s ", *target); size_t m = XMLquotestring(t, buf + n, size - n); strcpy(buf + n + m, "?>"); } bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.pi", "%s", err); }
str BATXMLconcat(bat *ret, const bat *bid, const bat *rid) { BAT *b, *r = 0, *bn; BUN p, q, rp = 0; size_t len, size = BUFSIZ; str buf = GDKmalloc(size); BATiter bi, ri; const char *err = OPERATION_FAILED; if (buf == NULL) throw(MAL, "xml.concat", MAL_MALLOC_FAIL); b = BATdescriptor(*bid); r = BATdescriptor(*rid); if (b == NULL || r == NULL) { GDKfree(buf); if (b) BBPunfix(b->batCacheid); if (r) BBPunfix(r->batCacheid); throw(MAL, "xml.concat", INTERNAL_BAT_ACCESS); } p = BUNfirst(b); q = BUNlast(b); rp = BUNfirst(r); prepareResult(bn, b, TYPE_xml, "concat", GDKfree(buf); BBPunfix(r->batCacheid)); bi = bat_iterator(b); ri = bat_iterator(r); while (p < q) { const char *t = (const char *) BUNtail(bi, p); const char *v = (const char *) BUNtail(ri, rp); len = strlen(t) + strlen(v) + 1; if (len >= size) { GDKfree(buf); size = len + 128; buf = GDKmalloc(size); if (buf == NULL) { err= MAL_MALLOC_FAIL; goto bunins_failed; } } if (strNil(t)) { if (strNil(v)) { strcpy(buf, str_nil); bn->T->nonil = 0; } else strcpy(buf, v); } else { if (strNil(v)) strcpy(buf, t); else if (*t != *v) { err = "arguments not compatible"; goto bunins_failed; } else if (*t == 'A') snprintf(buf, size, "A%s %s", t + 1, v + 1); else if (*t == 'C') snprintf(buf, size, "C%s%s", t + 1, v + 1); else { err = "can only concatenate attributes and element content"; goto bunins_failed; } } bunfastapp(bn, buf); rp++; p++; } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(r->batCacheid); BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.concat", "%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; }
str BATXMLcontent(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; BATiter bi; xmlDocPtr doc; xmlNodePtr root; size_t size = BUFSIZ; str buf = GDKmalloc(size); const char *err = OPERATION_FAILED; xmlBufferPtr xbuf; if (buf == NULL) throw(MAL,"xml.content",MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.content", INTERNAL_BAT_ACCESS); } doc = xmlParseMemory("<doc/>", 6); root = xmlDocGetRootElement(doc); prepareResult(bn, b, TYPE_xml, "content", GDKfree(buf)); bi = bat_iterator(b); xbuf = xmlBufferCreate(); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; xmlNodePtr elem; xmlParserErrors xerr; const xmlChar *s; if (strNil(t)) { bunfastapp(bn, str_nil); bn->T->nonil = 0; continue; } len = strlen(t); xerr = xmlParseInNodeContext(root, t, (int) len, 0, &elem); if (xerr != XML_ERR_OK) { err = XML_PARSE_ERROR; goto bunins_failed; } xmlNodeDump(xbuf, doc, elem, 0, 0); s = xmlBufferContent(xbuf); len = strlen((const char *) s); if (len + 2 >= size) { GDKfree(buf); size = len + 128; buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } buf[0] = 'C'; strcpy(buf + 1, (const char *) s); bunfastapp(bn, buf); xmlBufferEmpty(xbuf); xmlFreeNodeList(elem); } xmlBufferFree(xbuf); xmlFreeDoc(doc); GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: xmlBufferFree(xbuf); xmlFreeDoc(doc); if (buf != NULL) GDKfree(buf); BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); throw(MAL, "xml.document", "%s", err); }
str BATXMLxmltext(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; BATiter bi; size_t size = 0; str buf = NULL; xmlDocPtr doc = NULL; xmlNodePtr elem; str content = NULL; const char *err = OPERATION_FAILED; if ((b = BATdescriptor(*bid)) == NULL) throw(MAL, "xml.text", INTERNAL_BAT_ACCESS); prepareResult(bn, b, TYPE_str, "text", (void) 0); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; if (strNil(t)) { bunfastapp(bn, t); bn->T->nonil = 0; continue; } len = strlen(t); switch (*t) { case 'D': { xmlDocPtr d = xmlParseMemory(t + 1, (int) (len - 1)); elem = xmlDocGetRootElement(d); content = (str) xmlNodeGetContent(elem); xmlFreeDoc(d); if (content == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } break; } case 'C': if (doc == NULL) doc = xmlParseMemory("<doc/>", 6); xmlParseInNodeContext(xmlDocGetRootElement(doc), t + 1, (int) (len - 1), 0, &elem); content = (str) xmlNodeGetContent(elem); xmlFreeNodeList(elem); if (content == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } break; case 'A': { str s; if (buf == NULL || size < len) { size = len + 128; if (buf != NULL) GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } s = buf; t++; while (*t) { if (*t == '"' || *t == '\'') { char q = *t++; s += XMLunquotestring(&t, q, s); } t++; } *s = 0; break; } default: assert(*t == 'A' || *t == 'C' || *t == 'D'); bunfastapp(bn, str_nil); bn->T->nonil = 0; continue; } assert(content != NULL || buf != NULL); bunfastapp(bn, content != NULL ? content : buf); if (content != NULL) GDKfree(content); content = NULL; } finalizeResult(ret, bn, b); if (buf != NULL) GDKfree(buf); if (doc != NULL) xmlFreeDoc(doc); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); if (doc != NULL) xmlFreeDoc(doc); if (content != NULL) GDKfree(content); throw(MAL, "xml.text", "%s", err); }