LCOV - code coverage report
Current view: top level - monetdb5/modules/atoms - xml.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 128 427 30.0 %
Date: 2021-10-13 02:24:04 Functions: 13 23 56.5 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * @f xml
      11             :  * @a Sjoerd Mullender, Niels Nes, Martin Kersten
      12             :  * @v 0.1
      13             :  * @+ MAL support for XQL
      14             :  * This module contains the primitives needed in the SQL
      15             :  * front-end to support SQL/XML.
      16             :  */
      17             : #include "monetdb_config.h"
      18             : #include "xml.h"
      19             : #include "mal_interpreter.h"
      20             : 
      21             : #ifdef HAVE_LIBXML
      22             : #include <libxml/parser.h>
      23             : #include <libxml/xmlmemory.h>
      24             : 
      25             : /* The xml atom is used to represent XML data.  It is implemented as a
      26             :    subtype of str.  The first character of the string representation
      27             :    indicates the type of XML data.  There are three possibilities:
      28             :    * D - an XML document (possibly including <?xml?> and DOCTYPE);
      29             :    * C - XML content, i.e. something that can occur inside an XML element;
      30             :    * A - XML name/attribute pair.
      31             : */
      32             : 
      33             : size_t
      34         119 : XMLquotestring(const char *s, char *buf, size_t len)
      35             : {
      36             :         size_t i = 0;
      37             : 
      38         119 :         assert(len > 0);
      39         918 :         while (*s && i + 6 < len) {
      40         799 :                 if (*s == '&') {
      41           0 :                         buf[i++] = '&';
      42           0 :                         buf[i++] = 'a';
      43           0 :                         buf[i++] = 'm';
      44           0 :                         buf[i++] = 'p';
      45           0 :                         buf[i++] = ';';
      46         799 :                 } else if (*s == '<') {
      47           0 :                         buf[i++] = '&';
      48           0 :                         buf[i++] = 'l';
      49           0 :                         buf[i++] = 't';
      50           0 :                         buf[i++] = ';';
      51         799 :                 } else if (*s == '>') {
      52           0 :                         buf[i++] = '&';
      53           0 :                         buf[i++] = 'g';
      54           0 :                         buf[i++] = 't';
      55           0 :                         buf[i++] = ';';
      56         799 :                 } else if (*s == '"') {
      57           0 :                         buf[i++] = '&';
      58           0 :                         buf[i++] = 'q';
      59           0 :                         buf[i++] = 'u';
      60           0 :                         buf[i++] = 'o';
      61           0 :                         buf[i++] = 't';
      62           0 :                         buf[i++] = ';';
      63         799 :                 } else if (*s == '\'') {
      64           0 :                         buf[i++] = '&';
      65           0 :                         buf[i++] = 'a';
      66           0 :                         buf[i++] = 'p';
      67           0 :                         buf[i++] = 'o';
      68           0 :                         buf[i++] = 's';
      69           0 :                         buf[i++] = ';';
      70         799 :                 } else if ((*s & 0xFF) < 0x20) {
      71           0 :                         int n = snprintf(buf, len - i, "&#%d;", *s & 0xFF);
      72             : 
      73           0 :                         if (n < 0)
      74             :                                 break;
      75           0 :                         i += n;
      76             :                 } else {
      77         799 :                         buf[i++] = *s;
      78             :                 }
      79         799 :                 s++;
      80             :         }
      81         119 :         if (i < len)
      82         119 :                 buf[i] = 0;
      83             :         else
      84           0 :                 buf[len - 1] = 0;
      85         119 :         return i;
      86             : }
      87             : 
      88             : size_t
      89           0 : XMLunquotestring(const char **p, char q, char *buf)
      90             : {
      91           0 :         const char *s = *p;
      92             :         size_t i = 0;
      93             : 
      94           0 :         while (*s && *s != q) {
      95           0 :                 if (*s == '&') {
      96           0 :                         s++;
      97           0 :                         if (strncmp(s, "lt;", 3) == 0) {
      98           0 :                                 buf[i++] = '<';
      99           0 :                                 s += 3;
     100           0 :                         } else if (strncmp(s, "gt;", 3) == 0) {
     101           0 :                                 buf[i++] = '>';
     102           0 :                                 s += 3;
     103           0 :                         } else if (strncmp(s, "apos;", 5) == 0) {
     104           0 :                                 buf[i++] = '\'';
     105           0 :                                 s += 5;
     106           0 :                         } else if (strncmp(s, "quot;", 5) == 0) {
     107           0 :                                 buf[i++] = '"';
     108           0 :                                 s += 5;
     109           0 :                         } else if (strncmp(s, "amp;", 4) == 0) {
     110           0 :                                 buf[i++] = '&';
     111           0 :                                 s += 4;
     112           0 :                         } else if (*s == '#') {
     113             :                                 char *e;
     114             :                                 int base;
     115             :                                 unsigned long n; /* type unsigned long returned by strtoul() */
     116             : 
     117           0 :                                 s++;
     118           0 :                                 if (*s == 'x' || *s == 'X') {
     119           0 :                                         s++;
     120             :                                         base = 16;
     121             :                                 } else
     122             :                                         base = 10;
     123           0 :                                 n = strtoul(s, &e, base);
     124           0 :                                 assert(e > s && *e == ';');
     125           0 :                                 assert(n <= 0x7FFFFFFF);
     126           0 :                                 s = e + 1;
     127           0 :                                 if (n <= 0x7F)
     128           0 :                                         buf[i++] = (char) n;
     129           0 :                                 else if (n <= 0x7FF) {
     130           0 :                                         buf[i++] = (char) (0xC0 | (n >> 6));
     131           0 :                                         buf[i++] = (char) (0x80 | (n & 0x3F));
     132           0 :                                 } else if (n <= 0xFFFF) {
     133           0 :                                         buf[i++] = (char) (0xE0 | (n >> 12));
     134           0 :                                         buf[i++] = (char) (0x80 | ((n >> 6) & 0x3F));
     135           0 :                                         buf[i++] = (char) (0x80 | (n & 0x3F));
     136           0 :                                 } else if (n <= 0x1FFFFF) {
     137           0 :                                         buf[i++] = (char) (0xF0 | (n >> 18));
     138           0 :                                         buf[i++] = (char) (0x80 | ((n >> 12) & 0x3F));
     139           0 :                                         buf[i++] = (char) (0x80 | ((n >> 6) & 0x3F));
     140           0 :                                         buf[i++] = (char) (0x80 | (n & 0x3F));
     141           0 :                                 } else if (n <= 0x3FFFFFF) {
     142           0 :                                         buf[i++] = (char) (0xF8 | (n >> 24));
     143           0 :                                         buf[i++] = (char) (0x80 | ((n >> 18) & 0x3F));
     144           0 :                                         buf[i++] = (char) (0x80 | ((n >> 12) & 0x3F));
     145           0 :                                         buf[i++] = (char) (0x80 | ((n >> 6) & 0x3F));
     146           0 :                                         buf[i++] = (char) (0x80 | (n & 0x3F));
     147             :                                 } else if (n <= 0x7FFFFFFF) {
     148           0 :                                         buf[i++] = (char) (0xFC | (n >> 30));
     149           0 :                                         buf[i++] = (char) (0x80 | ((n >> 24) & 0x3F));
     150           0 :                                         buf[i++] = (char) (0x80 | ((n >> 18) & 0x3F));
     151           0 :                                         buf[i++] = (char) (0x80 | ((n >> 12) & 0x3F));
     152           0 :                                         buf[i++] = (char) (0x80 | ((n >> 6) & 0x3F));
     153           0 :                                         buf[i++] = (char) (0x80 | (n & 0x3F));
     154             :                                 }
     155             :                         } else {
     156             :                                 /* unrecognized entity: just leave it */
     157           0 :                                 buf[i++] = '&';
     158             :                         }
     159             :                 } else
     160           0 :                         buf[i++] = *s++;
     161             :         }
     162           0 :         buf[i] = 0;
     163           0 :         *p = s;
     164           0 :         return i;
     165             : }
     166             : 
     167             : str
     168           2 : XMLxml2str(str *s, xml *x)
     169             : {
     170           4 :         if (strNil(*x)) {
     171           1 :                 *s = GDKstrdup(str_nil);
     172           1 :                 return MAL_SUCCEED;
     173             :         }
     174           1 :         assert(**x == 'A' || **x == 'C' || **x == 'D');
     175           1 :         *s = GDKstrdup(*x + 1);
     176           1 :         return MAL_SUCCEED;
     177             : }
     178             : 
     179             : str
     180           2 : XMLstr2xml(xml *x, const char **val)
     181             : {
     182           2 :         const char *t = *val;
     183             :         str buf;
     184             :         size_t len;
     185             : 
     186           2 :         if (strNil(t)) {
     187           0 :                 *x = (xml) GDKstrdup(str_nil);
     188           0 :                 if (*x == NULL)
     189           0 :                         throw(MAL, "xml.xml", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     190             :                 return MAL_SUCCEED;
     191             :         }
     192           2 :         len = 6 * strlen(t) + 1;
     193           2 :         buf = GDKmalloc(len + 1);
     194           2 :         if (buf == NULL)
     195           0 :                 throw(MAL, "xml.xml", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     196           2 :         buf[0] = 'C';
     197           2 :         XMLquotestring(t, buf + 1, len);
     198           2 :         *x = buf;
     199           2 :         return MAL_SUCCEED;
     200             : }
     201             : 
     202             : str
     203           0 : XMLxmltext(str *s, xml *x)
     204             : {
     205             :         xmlDocPtr doc;
     206             :         xmlNodePtr elem;
     207             :         str content = NULL;
     208             : 
     209           0 :         if (strNil(*x)) {
     210           0 :                 *s = GDKstrdup(str_nil);
     211           0 :                 if (*s == NULL)
     212           0 :                         throw(MAL, "xml.text", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     213             :                 return MAL_SUCCEED;
     214             :         }
     215           0 :         if (**x == 'D') {
     216           0 :                 doc = xmlParseMemory(*x + 1, (int) strlen(*x + 1));
     217           0 :                 elem = xmlDocGetRootElement(doc);
     218           0 :                 content = (str) xmlNodeGetContent(elem);
     219           0 :                 xmlFreeDoc(doc);
     220           0 :         } else if (**x == 'C') {
     221           0 :                 doc = xmlParseMemory("<doc/>", 6);
     222           0 :                 xmlParseInNodeContext(xmlDocGetRootElement(doc), *x + 1, (int) strlen(*x + 1), 0, &elem);
     223           0 :                 content = (str) xmlNodeGetContent(elem);
     224           0 :                 xmlFreeNodeList(elem);
     225           0 :                 xmlFreeDoc(doc);
     226           0 :         } else if (**x == 'A') {
     227           0 :                 const char *t = *x + 1;
     228             :                 str p;
     229             : 
     230           0 :                 p = content = GDKmalloc(strlen(*x) + 1);
     231           0 :                 if (p == NULL)
     232           0 :                         throw(MAL, "xml.text", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     233           0 :                 while (*t) {
     234           0 :                         if (*t == '"' || *t == '\'') {
     235           0 :                                 char q = *t++;
     236             : 
     237           0 :                                 p += XMLunquotestring(&t, q, p);
     238             :                         }
     239           0 :                         t++;
     240             :                 }
     241           0 :                 *p = 0;
     242             :         }
     243           0 :         if (content == NULL) {
     244           0 :                 *s = GDKstrdup("");
     245           0 :                 if (*s == NULL)
     246           0 :                         throw(MAL, "xml.text", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     247             :         } else
     248           0 :                 *s = (str) content;
     249             :         return MAL_SUCCEED;
     250             : }
     251             : 
     252             : str
     253           0 : XMLxml2xml(xml *s, xml *x)
     254             : {
     255           0 :         *s = GDKstrdup(*x);
     256           0 :         if (*s == NULL)
     257           0 :                 throw(MAL, "xml.xml", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     258             :         return MAL_SUCCEED;
     259             : }
     260             : 
     261             : str
     262           0 : XMLdocument(xml *x, str *val)
     263             : {
     264             :         xmlDocPtr doc;
     265             : 
     266           0 :         if (strNil(*val)) {
     267           0 :                 *x = (xml) GDKstrdup(str_nil);
     268           0 :                 if (*x == NULL)
     269           0 :                         throw(MAL, "xml.document", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     270             :                 return MAL_SUCCEED;
     271             :         }
     272             :         /* call the libxml2 library to perform the test */
     273           0 :         doc = xmlParseMemory(*val, (int) strlen(*val));
     274           0 :         if (doc) {
     275             :                 int len;
     276             :                 xmlChar *buf;
     277             : 
     278           0 :                 xmlDocDumpMemory(doc, &buf, &len);
     279           0 :                 xmlFreeDoc(doc);
     280           0 :                 *x = GDKmalloc(len + 2);
     281           0 :                 if (*x == NULL)
     282           0 :                         throw(MAL, "xml.document", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     283           0 :                 snprintf(*x, len + 2, "D%s", (char *) buf);
     284           0 :                 GDKfree(buf);
     285           0 :                 return MAL_SUCCEED;
     286             :         }
     287           0 :         throw(MAL, "xml.document", "Document parse error");
     288             : }
     289             : 
     290             : str
     291           0 : XMLcontent(xml *x, str *val)
     292             : {
     293             :         xmlDocPtr doc;
     294             :         xmlNodePtr elem;
     295             :         xmlParserErrors err;
     296             :         xmlBufferPtr buf;
     297             :         const xmlChar *s;
     298             :         size_t len;
     299             : 
     300           0 :         if (strNil(*val)) {
     301           0 :                 *x = (xml) GDKstrdup(str_nil);
     302           0 :                 if (*x == NULL)
     303           0 :                         throw(MAL, "xml.content", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     304             :                 return MAL_SUCCEED;
     305             :         }
     306             :         /* call the libxml2 library to perform the test */
     307           0 :         doc = xmlParseMemory("<doc/>", 6);
     308           0 :         err = xmlParseInNodeContext(xmlDocGetRootElement(doc), *val, (int) strlen(*val), 0, &elem);
     309           0 :         if (err != XML_ERR_OK) {
     310           0 :                 xmlFreeDoc(doc);
     311           0 :                 throw(MAL, "xml.content", "Content parse error");
     312             :         }
     313           0 :         buf = xmlBufferCreate();
     314           0 :         xmlNodeDump(buf, doc, elem, 0, 0);
     315           0 :         s = xmlBufferContent(buf);
     316           0 :         len = strlen((const char *) s) + 2;
     317           0 :         *x = GDKmalloc(len);
     318           0 :         if (*x == NULL)
     319           0 :                 throw(MAL, "xml.content", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     320           0 :         snprintf(*x, len, "C%s", (const char *) s);
     321           0 :         xmlBufferFree(buf);
     322           0 :         xmlFreeNodeList(elem);
     323           0 :         xmlFreeDoc(doc);
     324           0 :         return MAL_SUCCEED;
     325             : }
     326             : 
     327             : str
     328           2 : XMLisdocument(bit *x, str *s)
     329             : {
     330             :         xmlDocPtr doc;
     331             : 
     332             :         /* call the libxml2 library to perform the test */
     333           4 :         if (strNil(*s))
     334           0 :                 *x = bit_nil;
     335             :         else {
     336           2 :                 doc = xmlParseMemory(*s, (int) strlen(*s));
     337           2 :                 *x = doc != NULL;
     338           2 :                 if (doc)
     339           2 :                         xmlFreeDoc(doc);
     340             :         }
     341           2 :         return MAL_SUCCEED;
     342             : }
     343             : 
     344             : str
     345           1 : XMLcomment(xml *x, str *s)
     346             : {
     347             :         size_t len;
     348             :         str buf;
     349             : 
     350           2 :         if (strNil(*s)) {
     351           0 :                 *x = (xml) GDKstrdup(str_nil);
     352           0 :                 if (*x == NULL)
     353           0 :                         throw(MAL, "xml.comment", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     354             :                 return MAL_SUCCEED;
     355             :         }
     356           1 :         if (strstr(*s, "--") != NULL)
     357           0 :                 throw(MAL, "xml.comment", "comment may not contain `--'");
     358           1 :         len = strlen(*s) + 9;
     359           1 :         buf = (str) GDKmalloc(len);
     360           1 :         if (buf == NULL)
     361           0 :                 throw(MAL, "xml.comment", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     362           1 :         snprintf(buf, len, "C<!--%s-->", *s);
     363           1 :         *x = buf;
     364           1 :         return MAL_SUCCEED;
     365             : }
     366             : 
     367             : str
     368           0 : XMLparse(xml *x, str *doccont, str *val, str *option)
     369             : {
     370             :         (void) option;
     371           0 :         if (strcmp(*doccont, "content") == 0)
     372           0 :                 return XMLcontent(x, val);
     373           0 :         if (strcmp(*doccont, "document") == 0)
     374           0 :                 return XMLdocument(x, val);
     375           0 :         throw(MAL, "xml.parse", "invalid parameter");
     376             : }
     377             : 
     378             : str
     379           0 : XMLpi(xml *ret, str *target, str *value)
     380             : {
     381             :         size_t len;
     382             :         str buf;
     383             :         str val = NULL;
     384             : 
     385           0 :         if (strNil(*target)) {
     386           0 :                 *ret = GDKstrdup(str_nil);
     387           0 :                 if (*ret == NULL)
     388           0 :                         throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     389             :                 return MAL_SUCCEED;
     390             :         }
     391           0 :         if (xmlValidateName((xmlChar *) *target, 0) != 0 || strcasecmp(*target, "xml") == 0)
     392           0 :                 throw(MAL, "xml.attribute", "invalid processing instruction target");
     393           0 :         len = strlen(*target) + 6;
     394           0 :         if (strNil(*value) || **value == 0) {
     395           0 :                 size_t n = 6 * strlen(*value) + 1;
     396             : 
     397           0 :                 val = GDKmalloc(n);
     398           0 :                 if (val == NULL)
     399           0 :                         throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     400           0 :                 len += XMLquotestring(*value, val, n) + 1;
     401             :         }
     402           0 :         buf = GDKmalloc(len);
     403           0 :         if (buf == NULL) {
     404           0 :                 if (val)
     405           0 :                         GDKfree(val);
     406           0 :                 throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     407             :         }
     408           0 :         if (val == NULL) {
     409           0 :                 snprintf(buf, len, "C<?%s?>", *target);
     410             :         } else {
     411           0 :                 snprintf(buf, len, "C<?%s %s?>", *target, val);
     412           0 :                 GDKfree(val);
     413             :         }
     414           0 :         *ret = buf;
     415           0 :         return MAL_SUCCEED;
     416             : }
     417             : 
     418             : str
     419           0 : XMLroot(xml *ret, xml *val, str *version, str *standalone)
     420             : {
     421             :         size_t len = 0, i = 0;
     422             :         str buf;
     423           0 :         bit isdoc = 0;
     424             : 
     425           0 :         if (strNil(*val)) {
     426           0 :                 *ret = GDKstrdup(str_nil);
     427           0 :                 if (*ret == NULL)
     428           0 :                         throw(MAL, "xml.root", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     429             :                 return MAL_SUCCEED;
     430             :         }
     431           0 :         if (**val != 'C')
     432           0 :                 throw(MAL, "xml.root", "value must be an XML node");
     433             :         len = 8;
     434           0 :         len = strlen(*val);
     435           0 :         if (!strNil(*version) && **version) {
     436           0 :                 if (strcmp(*version, "1.0") != 0 && strcmp(*version, "1.1") != 0)
     437           0 :                         throw(MAL, "xml.root", "illegal XML version");
     438           0 :                 len += 11 + strlen(*version);   /* strlen(" version=\"\"") */
     439             :         }
     440           0 :         if (!strNil(*standalone) && **standalone) {
     441           0 :                 if (strcmp(*standalone, "yes") != 0 && strcmp(*standalone, "no") != 0)
     442           0 :                         throw(MAL, "xml.root", "illegal XML standalone value");
     443           0 :                 len += 14 + strlen(*standalone);        /* strlen(" standalone=\"\"") */
     444             :         }
     445           0 :         buf = GDKmalloc(len);
     446           0 :         if (buf == NULL)
     447           0 :                 throw(MAL, "xml.root", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     448           0 :         strcpy(buf, "D<?xml");
     449           0 :         i = strlen(buf);
     450           0 :         if (!strNil(*version) && **version)
     451           0 :                 i += snprintf(buf + i, len - i, " version=\"%s\"", *version);
     452           0 :         if (!strNil(*standalone) && **standalone)
     453           0 :                 i += snprintf(buf + i, len - i, " standalone=\"%s\"", *standalone);
     454           0 :         snprintf(buf + i, len - i, "?>%s", *val + 1);
     455           0 :         buf++;
     456           0 :         XMLisdocument(&isdoc, &buf);    /* check well-formedness */
     457           0 :         buf--;
     458           0 :         if (!isdoc) {
     459           0 :                 GDKfree(buf);
     460           0 :                 throw(MAL, "xml.root", "resulting document not well-formed");
     461             :         }
     462           0 :         *ret = buf;
     463           0 :         return MAL_SUCCEED;
     464             : }
     465             : 
     466             : str
     467           1 : XMLattribute(xml *x, str *name, str *val)
     468             : {
     469           1 :         str t = *val;
     470             :         str buf;
     471             :         size_t len;
     472             : 
     473           2 :         if (strNil(t) || strNil(*name)) {
     474           0 :                 *x = (xml) GDKstrdup(str_nil);
     475           0 :                 if (*x == NULL)
     476           0 :                         throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     477             :                 return MAL_SUCCEED;
     478             :         }
     479           1 :         if (xmlValidateName((xmlChar *) *name, 0) != 0)
     480           0 :                 throw(MAL, "xml.attribute", "invalid attribute name");
     481           1 :         len = 6 * strlen(t) + 1;
     482           1 :         buf = GDKmalloc(len);
     483           1 :         if (buf == NULL)
     484           0 :                 throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     485           1 :         len = XMLquotestring(t, buf, len);
     486           1 :         len += strlen(*name) + 5;
     487           1 :         *x = GDKmalloc(len);
     488           1 :         if (*x == NULL) {
     489           0 :                 GDKfree(buf);
     490           0 :                 throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     491             :         }
     492           1 :         snprintf(*x, len, "A%s=\"%s\"", *name, buf);
     493           1 :         GDKfree(buf);
     494           1 :         return MAL_SUCCEED;
     495             : }
     496             : 
     497             : str
     498          23 : XMLelement(xml *ret, str *name, xml *nspace, xml *attr, xml *val)
     499             : {
     500             :         size_t len, i, namelen;
     501             :         str buf;
     502             : 
     503          46 :         if (strNil(*name))
     504           0 :                 throw(MAL, "xml.element", "no element name specified");
     505          23 :         if (xmlValidateName((xmlChar *) *name, 0) != 0)
     506           0 :                 throw(MAL, "xml.element", "invalid element name");
     507             :         /* len is composed of several parts:
     508             :            "C" + "<" + name + (nspace ? " " + nspace : "") + (attr ? " " + attr : "") + (val ? ">" + val + "</" + name + ">" : "/>")
     509             :          */
     510          23 :         namelen = strlen(*name);
     511          23 :         len = namelen + 5;      /* "C", "<", "/", ">", terminating NUL */
     512          44 :         if (nspace && !strNil(*nspace)) {
     513           0 :                 if (**nspace != 'A')
     514           0 :                         throw(MAL, "xml.element", "illegal namespace");
     515           0 :                 len += strlen(*nspace); /* " " + nspace (nspace contains initial 'A' which is replaced by space) */
     516             :         }
     517          44 :         if (attr && !strNil(*attr)) {
     518          19 :                 if (**attr != 'A')
     519           0 :                         throw(MAL, "xml.element", "illegal attribute");
     520          19 :                 len += strlen(*attr);   /* " " + attr (attr contains initial 'A' which is replaced by space) */
     521             :         }
     522          46 :         if (!strNil(*val) && **val != 0) {
     523          21 :                 if (**val != 'C')
     524           0 :                         throw(MAL, "xml.element", "illegal content");
     525          21 :                 len += strlen(*val + 1) + namelen + 2;  /* extra "<", ">", and name ("/" already counted) */
     526             :         }
     527          23 :         buf = GDKmalloc(len);
     528          23 :         if (buf == NULL)
     529           0 :                 throw(MAL, "xml.element", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     530          48 :         if (strNil(*val) && (!attr || strNil(*attr))) {
     531           1 :                 strcpy(buf, str_nil);
     532             :         } else {
     533          22 :                 i = snprintf(buf, len, "C<%s", *name);
     534          42 :                 if (nspace && !strNil(*nspace))
     535           0 :                         i += snprintf(buf + i, len - i, " %s", *nspace + 1);
     536          42 :                 if (attr && !strNil(*attr))
     537          19 :                         i += snprintf(buf + i, len - i, " %s", *attr + 1);
     538          44 :                 if (!strNil(*val))
     539          21 :                         i += snprintf(buf + i, len - i, ">%s</%s>", *val + 1, *name);
     540             :                 else
     541           1 :                         i += snprintf(buf + i, len - i, "/>");
     542             :         }
     543          23 :         *ret = buf;
     544          23 :         return MAL_SUCCEED;
     545             : }
     546             : 
     547             : str
     548           2 : XMLelementSmall(xml *ret, str *name, xml *val)
     549             : {
     550           2 :         return XMLelement(ret, name, NULL, NULL, val);
     551             : }
     552             : 
     553             : str
     554           0 : XMLconcat(xml *ret, xml *left, xml *right)
     555             : {
     556             :         size_t len;
     557             :         str buf;
     558             : 
     559             :         /* if either side is nil, return the other, otherwise concatenate */
     560           0 :         if (strNil(*left))
     561           0 :                 buf = GDKstrdup(*right);
     562           0 :         else if (strNil(*right))
     563           0 :                 buf = GDKstrdup(*left);
     564           0 :         else if (**left != **right)
     565           0 :                 throw(MAL, "xml.concat", "arguments not compatible");
     566           0 :         else if (**left == 'A') {
     567           0 :                 len = strlen(*left) + strlen(*right) + 1;
     568           0 :                 buf = GDKmalloc(len);
     569           0 :                 if (buf == NULL)
     570           0 :                         throw(MAL, "xml.concat", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     571           0 :                 snprintf(buf, len, "A%s %s", *left + 1, *right + 1);
     572           0 :         } else if (**left == 'C') {
     573           0 :                 len = strlen(*left) + strlen(*right) +2;
     574           0 :                 buf = GDKmalloc(len);
     575           0 :                 if (buf == NULL)
     576           0 :                         throw(MAL, "xml.concat", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     577           0 :                 snprintf(buf, len, "C%s%s", *left + 1, *right + 1);
     578             :         } else
     579           0 :                 throw(MAL, "xml.concat", "can only concatenate attributes and element content");
     580           0 :         if (buf == NULL)
     581           0 :                 throw(MAL, "xml.concat", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     582           0 :         *ret = buf;
     583           0 :         return MAL_SUCCEED;
     584             : }
     585             : 
     586             : str
     587           1 : XMLforest(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     588             : {
     589           1 :         xml *ret = getArgReference_TYPE(stk, p, 0, xml);
     590             :         int i;
     591             :         size_t len;
     592             :         str buf;
     593             :         xml x;
     594             : 
     595             :         (void) cntxt;
     596             :         (void) mb;
     597             : 
     598             :         len = 2;
     599           3 :         for (i = p->retc; i < p->argc; i++) {
     600           2 :                 x = *getArgReference_TYPE(stk, p, i, xml);
     601           2 :                 if (!strNil(x))
     602           2 :                         if (*x != 'C')
     603           0 :                                 throw(MAL, "xml.forest", "arguments must be element content");
     604           2 :                 len += strlen(x + 1);
     605             :         }
     606           1 :         buf = (str) GDKmalloc(len);
     607           1 :         if (buf == NULL)
     608           0 :                 throw(MAL, "xml.forest", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     609           1 :         *ret = buf;
     610           1 :         *buf++ = 'C';
     611           1 :         *buf = 0;
     612             : 
     613           3 :         for (i = p->retc; i < p->argc; i++) {
     614           2 :                 x = *getArgReference_TYPE(stk, p, i, xml);
     615           2 :                 if (!strNil(x)) {
     616           2 :                         len = strlen(x + 1);
     617           2 :                         strcpy(buf, x + 1);
     618           2 :                         buf += len;
     619             :                 }
     620             :         }
     621             :         return MAL_SUCCEED;
     622             : }
     623             : 
     624             : int TYPE_xml;
     625             : 
     626             : str
     627         266 : XMLprelude(void *ret)
     628             : {
     629             :         (void) ret;
     630         266 :         TYPE_xml = ATOMindex("xml");
     631         266 :         xmlMemSetup(GDKfree, GDKmalloc, GDKrealloc, GDKstrdup);
     632         266 :         xmlInitParser();
     633         266 :         return MAL_SUCCEED;
     634             : }
     635             : 
     636             : str
     637         264 : XMLepilogue(void *ret)
     638             : {
     639             :         (void)ret;
     640         264 :         xmlCleanupParser();
     641         264 :         return MAL_SUCCEED;
     642             : }
     643             : 
     644             : static ssize_t
     645           0 : XMLfromString(const char *src, size_t *len, void **X, bool external)
     646             : {
     647             :         xml *x = (xml *) X;
     648           0 :         if (*x){
     649           0 :                 GDKfree(*x);
     650           0 :                 *x = NULL;
     651             :         }
     652           0 :         if (external && strcmp(src, "nil") == 0) {
     653           0 :                 *x = GDKstrdup(str_nil);
     654           0 :                 if (*x == NULL)
     655             :                         return -1;
     656           0 :                 return 3;
     657           0 :         } else if (strNil(src)) {
     658           0 :                 *x = GDKstrdup(str_nil);
     659           0 :                 if (*x == NULL)
     660             :                         return -1;
     661           0 :                 return 1;
     662             :         } else {
     663           0 :                 char *err = XMLstr2xml(x, &src);
     664           0 :                 if (err != MAL_SUCCEED) {
     665           0 :                         GDKerror("%s", getExceptionMessageAndState(err));
     666           0 :                         freeException(err);
     667           0 :                         return -1;
     668             :                 }
     669             :         }
     670           0 :         *len = strlen(*x) + 1;
     671           0 :         return (ssize_t) *len - 1;
     672             : }
     673             : 
     674             : static ssize_t
     675          48 : XMLtoString(str *s, size_t *len, const void *SRC, bool external)
     676             : {
     677             :         const char *src = SRC;
     678             :         size_t l;
     679             : 
     680          48 :         if (strNil(src))
     681           1 :                 src = external ? "nil" : str_nil;
     682             :         else
     683          47 :                 src++;
     684          48 :         l = strlen(src) + 1;
     685          48 :         if (l >= *len || *s == NULL) {
     686           5 :                 GDKfree(*s);
     687           5 :                 *s = GDKmalloc(l);
     688           5 :                 if (*s == NULL)
     689             :                         return -1;
     690           5 :                 *len = l;
     691             :         }
     692          48 :         strcpy(*s, src);
     693          48 :         return (ssize_t) l - 1;
     694             : }
     695             : 
     696             : #else
     697             : 
     698             : #define NO_LIBXML_FATAL "xml: MonetDB was built without libxml, but what you are trying to do requires it."
     699             : 
     700             : static ssize_t XMLfromString(const char *src, size_t *len, void **x, bool external) {
     701             :         (void) src;
     702             :         (void) len;
     703             :         (void) x;
     704             :         (void) external;
     705             :         GDKerror("not implemented\n");
     706             :         return -1;
     707             : }
     708             : static ssize_t XMLtoString(str *s, size_t *len, const void *src, bool external) {
     709             :         (void) s;
     710             :         (void) len;
     711             :         (void) src;
     712             :         (void) external;
     713             :         GDKerror("not implemented\n");
     714             :         return -1;
     715             : }
     716             : str XMLxml2str(str *s, xml *x) {
     717             :         (void) s;
     718             :         (void) x;
     719             :         return createException(MAL, "xml.xml2str", SQLSTATE(HY005) NO_LIBXML_FATAL);
     720             : }
     721             : str XMLstr2xml(xml *x, const char **s) {
     722             :         (void) s;
     723             :         (void) x;
     724             :         return createException(MAL, "xml.xml2str", SQLSTATE(HY005) NO_LIBXML_FATAL);
     725             : }
     726             : str XMLxmltext(str *s, xml *x) {
     727             :         (void) s;
     728             :         (void) x;
     729             :         return createException(MAL, "xml.xmltext", SQLSTATE(HY005) NO_LIBXML_FATAL);
     730             : }
     731             : str XMLxml2xml(xml *x, xml *s) {
     732             :         (void) s;
     733             :         (void) x;
     734             :         return createException(MAL, "xml.xml2xml", SQLSTATE(HY005) NO_LIBXML_FATAL);
     735             : }
     736             : str XMLdocument(xml *x, str *s) {
     737             :         (void) s;
     738             :         (void) x;
     739             :         return createException(MAL, "xml.document", SQLSTATE(HY005) NO_LIBXML_FATAL);
     740             : }
     741             : str XMLcontent(xml *x, str *s) {
     742             :         (void) s;
     743             :         (void) x;
     744             :         return createException(MAL, "xml.content", SQLSTATE(HY005) NO_LIBXML_FATAL);
     745             : }
     746             : str XMLisdocument(bit *x, str *s) {
     747             :         (void) s;
     748             :         (void) x;
     749             :         return createException(MAL, "xml.isdocument", SQLSTATE(HY005) NO_LIBXML_FATAL);
     750             : }
     751             : str XMLcomment(xml *x, str *s) {
     752             :         (void) s;
     753             :         (void) x;
     754             :         return createException(MAL, "xml.comment", SQLSTATE(HY005) NO_LIBXML_FATAL);
     755             : }
     756             : str XMLpi(xml *x, str *target, str *s) {
     757             :         (void) s;
     758             :         (void) target;
     759             :         (void) x;
     760             :         return createException(MAL, "xml.pi", SQLSTATE(HY005) NO_LIBXML_FATAL);
     761             : }
     762             : str XMLroot(xml *x, xml *v, str *version, str *standalone) {
     763             :         (void) x;
     764             :         (void) v;
     765             :         (void) version;
     766             :         (void) standalone;
     767             :         return createException(MAL, "xml.root", SQLSTATE(HY005) NO_LIBXML_FATAL);
     768             : }
     769             : str XMLparse(xml *x, str *doccont, str *s, str *option) {
     770             :         (void) x;
     771             :         (void) doccont;
     772             :         (void) s;
     773             :         (void) option;
     774             :         return createException(MAL, "xml.parse", SQLSTATE(HY005) NO_LIBXML_FATAL);
     775             : }
     776             : str XMLattribute(xml *ret, str *name, str *val) {
     777             :         (void) ret;
     778             :         (void) name;
     779             :         (void) val;
     780             :         return createException(MAL, "xml.attribute", SQLSTATE(HY005) NO_LIBXML_FATAL);
     781             : }
     782             : str XMLelement(xml *ret, str *name, xml *nspace, xml *attr, xml *val) {
     783             :         (void) ret;
     784             :         (void) name;
     785             :         (void) nspace;
     786             :         (void) attr;
     787             :         (void) val;
     788             :         return createException(MAL, "xml.element", SQLSTATE(HY005) NO_LIBXML_FATAL);
     789             : }
     790             : str XMLelementSmall(xml *ret, str *name, xml *val) {
     791             :         (void) ret;
     792             :         (void) name;
     793             :         (void) val;
     794             :         return createException(MAL, "xml.elementSmall", SQLSTATE(HY005) NO_LIBXML_FATAL);
     795             : }
     796             : str XMLconcat(xml *ret, xml *left, xml *right) {
     797             :         (void) ret;
     798             :         (void) left;
     799             :         (void) right;
     800             :         return createException(MAL, "xml.concat", SQLSTATE(HY005) NO_LIBXML_FATAL);
     801             : }
     802             : str XMLforest(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p) {
     803             :         (void) cntxt;
     804             :         (void) mb;
     805             :         (void) stk;
     806             :         (void) p;
     807             :         return createException(MAL, "xml.forest", SQLSTATE(HY005) NO_LIBXML_FATAL);
     808             : }
     809             : size_t XMLquotestring(const char *s, char *buf, size_t len) {
     810             :         (void) s;
     811             :         (void) buf;
     812             :         (void) len;
     813             :         return 0;
     814             : }
     815             : size_t XMLunquotestring(const char **p, char q, char *buf) {
     816             :         (void) p;
     817             :         (void) q;
     818             :         (void) buf;
     819             :         return 0;
     820             : }
     821             : str XMLprelude(void *ret) {
     822             :         (void) ret;
     823             :         return MAL_SUCCEED; /* to not break init */
     824             : }
     825             : str XMLepilogue(void *ret) {
     826             :         (void)ret;
     827             :         return MAL_SUCCEED;
     828             : }
     829             : 
     830             : #endif /* HAVE_LIBXML */
     831             : 
     832             : #include "mel.h"
     833             : mel_atom xml_init_atoms[] = {
     834             :  { .name="xml", .basetype="str", .fromstr=XMLfromString, .tostr=XMLtoString, },  { .cmp=NULL }
     835             : };
     836             : mel_func xml_init_funcs[] = {
     837             :  command("xml", "xml", XMLstr2xml, false, "Cast the string to an xml compliant string", args(1,2, arg("",xml),arg("src",str))),
     838             :  command("xml", "str", XMLxml2str, false, "Cast the string to an xml compliant string", args(1,2, arg("",str),arg("src",xml))),
     839             :  command("xml", "text", XMLxmltext, false, "Extract text from an xml atom", args(1,2, arg("",str),arg("src",xml))),
     840             :  command("xml", "comment", XMLcomment, false, "Construct an comment struction ", args(1,2, arg("",xml),arg("val",str))),
     841             :  command("xml", "parse", XMLparse, false, "Parse the XML document or element string values ", args(1,4, arg("",xml),arg("doccont",str),arg("val",str),arg("option",str))),
     842             :  command("xml", "pi", XMLpi, false, "Construct a processing instruction", args(1,3, arg("",xml),arg("target",str),arg("val",str))),
     843             :  command("xml", "document", XMLdocument, false, "Check the value for compliance as XML document", args(1,2, arg("",xml),arg("val",str))),
     844             :  command("xml", "content", XMLcontent, false, "Check the value for compliance as content, i.e.  it may contain multiple roots and character data.", args(1,2, arg("",xml),arg("val",str))),
     845             :  command("xml", "root", XMLroot, false, "Construct the root nodes", args(1,4, arg("",xml),arg("val",xml),arg("version",str),arg("standalone",str))),
     846             :  command("xml", "attribute", XMLattribute, false, "Construct an attribute value pair", args(1,3, arg("",xml),arg("name",str),arg("val",str))),
     847             :  command("xml", "element", XMLelement, false, "The basic building block for XML elements are namespaces, attributes and a sequence of xml elements. The name space and the attributes may be left unspecified(=nil:bat).", args(1,5, arg("",xml),arg("name",str),arg("ns",xml),arg("attr",xml),arg("s",xml))),
     848             :  command("xml", "element", XMLelementSmall, false, "The basic building block for XML elements are namespaces, attributes and a sequence of xml elements. The name space and the attributes may be left unspecified(=nil:bat).", args(1,3, arg("",xml),arg("name",str),arg("s",xml))),
     849             :  command("xml", "concat", XMLconcat, false, "Concatenate the xml values", args(1,3, arg("",xml),arg("val1",xml),arg("val2",xml))),
     850             :  pattern("xml", "forest", XMLforest, false, "Construct an element list", args(1,2, arg("",xml),vararg("val",xml))),
     851             :  command("xml", "isdocument", XMLisdocument, false, "Validate the string as a document", args(1,2, arg("",bit),arg("val",str))),
     852             :  command("xml", "prelude", XMLprelude, false, "", args(1,1, arg("",void))),
     853             :  command("xml", "epilogue", XMLepilogue, false, "", args(1,1, arg("",void))),
     854             :  command("calc", "xml", XMLstr2xml, false, "", args(1,2, arg("",xml),arg("src",str))),
     855             :  command("calc", "xml", XMLxml2xml, false, "", args(1,2, arg("",xml),arg("src",xml))),
     856             :  { .imp=NULL }
     857             : };
     858             : #include "mal_import.h"
     859             : #ifdef _MSC_VER
     860             : #undef read
     861             : #pragma section(".CRT$XCU",read)
     862             : #endif
     863         259 : LIB_STARTUP_FUNC(init_xml_mal)
     864         259 : { mal_module("xml", xml_init_atoms, xml_init_funcs); }

Generated by: LCOV version 1.14