3 Copyright (C) 2003 Elwood C. Downey
5 This library is free software;
6 you can redistribute it and / or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation;
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT
ANY WARRANTY;
14 without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License
for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with
this library;
20 if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301 USA
40 #define snprintf _snprintf
43 #pragma warning(disable : 4996)
57 static int oneXMLchar(
LilXML *lp,
int c,
char ynot[]);
58 static void initParser(
LilXML *lp);
59 static void pushXMLEle(
LilXML *lp);
60 static void popXMLEle(
LilXML *lp);
61 static void resetEndTag(
LilXML *lp);
64 static void freeAtt(
XMLAtt *a);
65 static int isTokenChar(
int start,
int c);
66 static void growString(
String *sp,
int c);
67 static void appendString(
String *sp,
const char *str);
68 static void freeString(
String *sp);
69 static void newString(
String *sp);
70 static void *moremem(
void *old,
size_t n);
131 static char entities[] =
"&<>'\"";
134 static void *(*mymalloc)(
size_t size) = malloc;
135 static void *(*myrealloc)(
void *ptr,
size_t size) = realloc;
136 static void (*myfree)(
void *ptr) = free;
141 void lilxmlMalloc(
void *(*newmalloc)(
size_t size),
void *(*newrealloc)(
void *ptr,
size_t size),
142 void (*newfree)(
void *ptr))
144 mymalloc = newmalloc;
145 myrealloc = newrealloc;
153 memset(lp, 0,
sizeof * lp);
176 freeString(&ep->
tag);
180 for (i = 0; i < ep->
nat; i++)
186 for (i = 0; i < ep->
nel; i++)
189 ep->
el[i]->
pe = NULL;
200 for (i = 0; i < pe->
nel; i++)
204 memmove(&pe->
el[i], &pe->
el[i + 1], (--pe->
nel - i) *
sizeof(
XMLEle *));
217 unsigned int nnodes = 1;
218 XMLEle **nodes = (
XMLEle **)malloc(nnodes *
sizeof * nodes);
227 if (size < lp->ce->pcdata.sm - lp->
ce->
pcdata.
sl)
237 char *ltpos = memchr(buf,
'<', size);
255 if (ctag && !(strcmp(ctag,
"oneBLOB")) && (lp->
cs ==
INCON))
265 blen += (blen / 72) + 1;
270 if (size <= blen - lp->ce->pcdata.sl)
280 char *ltpos = memchr(buf,
'<', size);
296 while (curr - buf < size)
302 sprintf(ynot,
"Line %d: early XML EOF", lp->
ln);
313 if (!lp->
skipping && lp->
lastc ==
'<' && (newc ==
'?' || newc ==
'!'))
336 if (lp->
lastc ==
'<')
338 if (oneXMLchar(lp,
'<', ynot) < 0)
348 s = oneXMLchar(lp, newc, ynot);
365 nodes[nnodes - 1] = lp->
ce;
366 nodes = (
XMLEle **)realloc(nodes, (nnodes + 1) *
sizeof * nodes);
367 nodes[nnodes] = NULL;
396 sprintf(ynot,
"Line %d: early XML EOF", lp->
ln);
406 if (!lp->
skipping && lp->
lastc ==
'<' && (newc ==
'?' || newc ==
'!'))
426 if (lp->
lastc ==
'<')
428 if (oneXMLchar(lp,
'<', ynot) < 0)
437 s = oneXMLchar(lp, newc, ynot);
470 while (!root && !ynot[0]);
485 buf = (
char*)(*mymalloc)(
sprlXMLEle(ep, 0) + 1);
495 XMLEle * result =
nullptr;
496 if (replace && (*replace)(
self, ep, &result))
502 for(
int i = 0; i < ep->
nel; ++i)
509 appXMLEle(result, repl);
528 for (i = 0; i < ep->
nat; i++)
529 if (!strcmp(ep->
at[i]->
name.
s, name))
539 int tl = (int)strlen(tag);
542 for (i = 0; i < ep->
nel; i++)
545 if (sp->
sl == tl && !strcmp(sp->
s, tag))
563 if (eit < 0 || eit >= ep->
nel)
565 return (ep->
el[eit]);
580 if (ait < 0 || ait >= ep->
nat)
582 return (ep->
at[ait]);
647 return (a ? a->
valu.
s :
"");
657 while ((c = fgetc(fp)) != EOF)
672 XMLEle *ep = growEle(parent);
673 appendString(&ep->
tag, tag);
683 ep->
el[ep->
nel++] = newep;
690 freeString(&ep->
tag);
692 appendString(&ep->
tag, tag);
701 appendString(&ep->
pcdata, pcdata);
709 appendString(&ap->
name, name);
710 appendString(&ap->
valu, valu);
719 for (i = 0; i < ep->
nat; i++)
721 if (strcmp(ep->
at[i]->
name.
s, name) == 0)
724 memmove(&ep->
at[i], &ep->
at[i + 1], (--ep->
nat - i) *
sizeof(
XMLAtt *));
735 for(
int i = 0; i < ele->
nat; ++i)
737 auto att = ele->
at[i];
747 freeString(&ap->
valu);
748 appendString(&ap->
valu, str);
752 #define PRINDENTSTR " "
767 virtual void put(
const char * str,
size_t len) = 0;
768 void put(
const char * str)
770 put(str, strlen(str));
789 for (i = 0; i < ep->
nat; i++)
801 for (i = 0; i < ep->
nel; i++)
835 virtual void put(
const char * str,
size_t len)
837 fwrite(str, len, 1, file);
858 virtual void put(
const char * str,
size_t len)
860 memcpy(buffer + offset, str, len);
890 if (ele == cdataWatch && cdataWatch)
892 cdataOffset = offset;
898 virtual void put(
const char * str,
size_t len)
940 const char *ep = NULL;
941 for (; (ep = strpbrk(s, entities)) != NULL; s = ep + 1)
944 size_t nnew = size_t(ep - s);
984 for (sret = s; (ep = strpbrk(s, entities)) != NULL; s = ep + 1)
987 size_t nnew = size_t(ep - s);
988 sret = malbuf = (
char*)moremem(malbuf, nmalbuf + nnew + 10);
989 memcpy(malbuf + nmalbuf, s, nnew);
996 nmalbuf += sprintf(malbuf + nmalbuf,
"&");
999 nmalbuf += sprintf(malbuf + nmalbuf,
"<");
1002 nmalbuf += sprintf(malbuf + nmalbuf,
">");
1005 nmalbuf += sprintf(malbuf + nmalbuf,
"'");
1008 nmalbuf += sprintf(malbuf + nmalbuf,
""");
1027 size_t nleft = strlen(s) + 1;
1028 sret = malbuf = (
char*)moremem(malbuf, nmalbuf + nleft);
1029 memcpy(malbuf + nmalbuf, s, nleft);
1038 static int decodeEntity(
char *ent,
int *cp)
1046 {
"&",
'&' }, {
"'",
'\'' }, {
"<",
'<' }, {
">",
'>' }, {
""",
'"' },
1048 for (
size_t i = 0; i < (
sizeof(enttable) /
sizeof(enttable[0])); i++)
1050 if (strcmp(ent, enttable[i].ent) == 0)
1052 *cp = enttable[i].c;
1065 static int oneXMLchar(
LilXML *lp,
int c,
char ynot[])
1079 if (isTokenChar(1, c))
1081 growString(&lp->
ce->
tag, c);
1084 else if (!isspace(c))
1086 sprintf(ynot,
"Line %d: Bogus tag char %c", lp->
ln, c);
1092 if (isTokenChar(0, c))
1093 growString(&lp->
ce->
tag, c);
1107 else if (isTokenChar(1, c))
1110 growString(&ap->
name, c);
1113 else if (!isspace(c))
1115 sprintf(ynot,
"Line %d: Bogus leading attr name char: %c", lp->
ln, c);
1130 sprintf(ynot,
"Line %d: Bogus char %c before >", lp->
ln, c);
1136 if (isTokenChar(0, c))
1138 else if (isspace(c) || c ==
'=')
1142 sprintf(ynot,
"Line %d: Bogus attr name char: %c", lp->
ln, c);
1148 if (c ==
'\'' || c ==
'"')
1153 else if (!(isspace(c) || c ==
'='))
1155 sprintf(ynot,
"Line %d: No value for attribute %s", lp->
ln, lp->
ce->
at[lp->
ce->
nat - 1]->
name.
s);
1164 growString(&lp->
entity, c);
1167 else if (c == lp->
delim)
1169 else if (!iscntrl(c))
1177 growString(&lp->
entity, c);
1178 if (decodeEntity(lp->
entity.
s, &c))
1186 growString(&lp->
entity, c);
1192 else if (!isspace(c))
1203 growString(&lp->
entity, c);
1223 growString(&lp->
entity, c);
1224 if (decodeEntity(lp->
entity.
s, &c))
1239 growString(&lp->
entity, c);
1251 if (isTokenChar(1, c))
1253 growString(&lp->
ce->
tag, c);
1262 if (isTokenChar(1, c))
1264 growString(&lp->
endtag, c);
1267 else if (!isspace(c))
1269 sprintf(ynot,
"Line %d: Bogus preend tag char %c", lp->
ln, c);
1275 if (isTokenChar(0, c))
1276 growString(&lp->
endtag, c);
1281 sprintf(ynot,
"Line %d: closing tag %s does not match %s", lp->
ln, lp->
endtag.
s, lp->
ce->
tag.
s);
1284 else if (lp->
ce->
pe)
1292 else if (!isspace(c))
1294 sprintf(ynot,
"Line %d: Bogus end tag char %c", lp->
ln, c);
1304 static void initParser(
LilXML *lp)
1308 memset(lp, 0,
sizeof(*lp));
1319 static void pushXMLEle(
LilXML *lp)
1321 lp->
ce = growEle(lp->
ce);
1328 static void popXMLEle(
LilXML *lp)
1339 memset(newe, 0,
sizeof(
XMLEle));
1340 newString(&newe->
tag);
1341 newString(&newe->
pcdata);
1347 pe->
el[pe->
nel++] = newe;
1358 memset(newa, 0,
sizeof(*newa));
1359 newString(&newa->
name);
1360 newString(&newa->
valu);
1364 ep->
at[ep->
nat++] = newa;
1370 static void freeAtt(
XMLAtt *a)
1374 freeString(&a->
name);
1375 freeString(&a->
valu);
1380 static void resetEndTag(
LilXML *lp)
1389 static int isTokenChar(
int start,
int c)
1391 return (isalpha(c) || c ==
'_' || (!start && isdigit(c)));
1395 static void growString(
String *sp,
int c)
1405 sp->
s = (
char *)moremem(sp->
s, sp->
sm *= 2);
1409 sp->
s[--l] = (char)c;
1414 static void appendString(
String *sp,
const char *str)
1419 int strl = int(strlen(str));
1420 int l = sp->
sl + strl + 1;
1428 sp->
s = (
char *)moremem(sp->
s, (sp->
sm = l));
1433 strcpy(&sp->
s[sp->
sl], str);
1439 static void newString(
String *sp)
1444 sp->
s = (
char *)moremem(NULL,
MINMEM);
1451 static void freeString(
String *sp)
1461 static void *moremem(
void *old,
size_t n)
1463 void *p = (old ? (*myrealloc)(old, n) : (*mymalloc)(n));
1466 fprintf(stderr,
"%s(%s): Failed to allocate memory.\n", __FILE__, __func__);
1472 #if defined(MAIN_TST)
1473 int main(
int ac,
char *av[])
1492 fprintf(stderr,
"::::::::::::: %s\n",
tagXMLEle(root));
1496 str = malloc(l + 1);
1497 fprintf(stderr,
"::::::::::::: %s : %d : %d",
tagXMLEle(root), l,
sprXMLEle(str, root, 0));
1498 fprintf(stderr,
": %d\n", printf(
"%s", str));
1504 fprintf(stderr,
"Error: %s\n", ynot);
1513 #if defined(_MSC_VER)
1515 #pragma warning(pop)
int main(int argc, char *argv[])
virtual ~BufferXMLOutput()
BufferXMLOutput(char *buffer)
virtual void put(const char *str, size_t len)
virtual void put(const char *str, size_t len)
virtual void put(const char *str, size_t len)
void setCdataWatch(XMLEle *ele)
virtual void cdataCb(XMLEle *ele)
virtual void cdataCb(XMLEle *ele)
virtual void put(const char *str, size_t len)=0
void put(const char *str)
void putXML(XMLEle *el, int level)
void putEntityXML(const char *str)
void lilxmlMalloc(void *(*newmalloc)(size_t size), void *(*newrealloc)(void *ptr, size_t size), void(*newfree)(void *ptr))
int nXMLEle(XMLEle *ep)
Return the number of nested XML elements in a parent XML element.
XMLEle * parentXMLAtt(XMLAtt *ap)
Return the parent of an XML attribute.
XMLAtt * nextXMLAtt(XMLEle *ep, int init)
Iterate an XML element for a list of XML attributes.
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
XMLEle * shallowCloneXMLEle(XMLEle *ele)
return a surface copy of a node. Don't copy childs or cdata.
LilXML * newLilXML()
Create a new lilxml parser.
XMLEle * cloneXMLEle(XMLEle *ep)
char * entityXML(char *s)
return a string with all xml-sensitive characters within the passed string replaced with their entity...
XMLEle * parentXMLEle(XMLEle *ep)
Return the parent of an XML element.
int nXMLAtt(XMLEle *ep)
Return the number of XML attributes in a parent XML element.
XMLEle ** parseXMLChunk(LilXML *lp, char *buf, int size, char ynot[])
Process an XML chunk.
size_t sprXMLEle(char *s, XMLEle *ep, int level)
sample print ep to string s. N.B. s must be at least as large as that reported by sprlXMLEle()+1....
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
XMLAtt * addXMLAtt(XMLEle *ep, const char *name, const char *valu)
Add an XML attribute to an existing XML element.
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
void editXMLEle(XMLEle *ep, const char *pcdata)
set the pcdata of the given element
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
size_t sprXMLCDataOffset(XMLEle *root, XMLEle *ep, int level)
return exact position of cdata of child in printed representation of root N.B. set level = 0 on first...
void rmXMLAtt(XMLEle *ep, const char *name)
Remove an XML attribute from an XML element.
void prXMLEle(FILE *fp, XMLEle *ep, int level)
Print an XML element.
size_t sprlXMLEle(XMLEle *ep, int level)
return number of bytes in a string guaranteed able to hold result of sprXLMEle(ep) (sans trailing \0@...
XMLEle * readXMLFile(FILE *fp, LilXML *lp, char ynot[])
Handy wrapper to read one xml file.
XMLEle * readXMLEle(LilXML *lp, int newc, char ynot[])
Process an XML one char at a time.
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
char * nameXMLAtt(XMLAtt *ap)
Return the name of an XML attribute.
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
void editXMLAtt(XMLAtt *ap, const char *str)
change the value of an attribute to str.
void delLilXML(LilXML *lp)
Delete a lilxml parser.
XMLEle * setXMLEleTag(XMLEle *ep, const char *tag)
Update the tag of an element.
XMLEle * parseXML(char buf[], char ynot[])
XMLEle * addXMLEle(XMLEle *parent, const char *tag)
add an element with the given tag to the given element. parent can be NULL to make a new root.
int pcdatalenXMLEle(XMLEle *ep)
Return the number of characters in pcdata in an XML element.
XMLEle * findXMLEle(XMLEle *ep, const char *tag)
Find an XML element within an XML element.
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
A little DOM-style library to handle parsing and processing an XML file.