ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/ezxml.c
(Generate patch)

Comparing ray/src/common/ezxml.c (file contents):
Revision 2.1 by greg, Wed Jun 17 20:41:47 2009 UTC vs.
Revision 2.3 by greg, Thu Jun 9 17:09:39 2011 UTC

# Line 34 | Line 34 | static const char RCSid[] = "$Id$";
34   #ifndef EZXML_NOMMAP
35   #include <unistd.h>
36   #include <sys/mman.h>
37 < #endif // EZXML_NOMMAP
37 > #endif /* EZXML_NOMMAP */
38   #include <sys/stat.h>
39   #include "ezxml.h"
40  
41 < #define EZXML_WS   "\t\r\n "  // whitespace
42 < #define EZXML_ERRL 128        // maximum error string length
41 > #ifdef _WIN32
42 > #include <io.h>
43 > #define snprintf        printf_s
44 > #define read            _read
45 > #define open            _open
46 > #define close           _close  
47 > #endif
48  
49 + #define EZXML_WS   "\t\r\n "  /* whitespace */
50 + #define EZXML_ERRL 128        /* maximum error string length */
51 +
52   typedef struct ezxml_root *ezxml_root_t;
53 < struct ezxml_root {       // additional data for the root tag
54 <    struct ezxml xml;     // is a super-struct built on top of ezxml struct
55 <    ezxml_t cur;          // current xml tree insertion point
56 <    char *m;              // original xml string
57 <    size_t len;           // length of allocated memory for mmap, -1 for malloc
58 <    char *u;              // UTF-8 conversion of string if original was UTF-16
59 <    char *s;              // start of work area
60 <    char *e;              // end of work area
61 <    char **ent;           // general entities (ampersand sequences)
62 <    char ***attr;         // default attributes
63 <    char ***pi;           // processing instructions
64 <    short standalone;     // non-zero if <?xml standalone="yes"?>
65 <    char err[EZXML_ERRL]; // error string
53 > struct ezxml_root {       /* additional data for the root tag */
54 >    struct ezxml xml;     /* is a super-struct built on top of ezxml struct */
55 >    ezxml_t cur;          /* current xml tree insertion point */
56 >    char *m;              /* original xml string */
57 >    size_t len;           /* length of allocated memory for mmap, -1 for malloc */
58 >    char *u;              /* UTF-8 conversion of string if original was UTF-16 */
59 >    char *s;              /* start of work area */
60 >    char *e;              /* end of work area */
61 >    char **ent;           /* general entities (ampersand sequences) */
62 >    char ***attr;         /* default attributes */
63 >    char ***pi;           /* processing instructions */
64 >    short standalone;     /* non-zero if <?xml standalone="yes"?> */
65 >    char err[EZXML_ERRL]; /* error string */
66   };
67  
68 < char *EZXML_NIL[] = { NULL }; // empty, null terminated array of strings
68 > char *EZXML_NIL[] = { NULL }; /* empty, null terminated array of strings */
69  
70 < // returns the first child tag with the given name or NULL if not found
70 > /* returns the first child tag with the given name or NULL if not found */
71   ezxml_t ezxml_child(ezxml_t xml, const char *name)
72   {
73      xml = (xml) ? xml->child : NULL;
# Line 67 | Line 75 | ezxml_t ezxml_child(ezxml_t xml, const char *name)
75      return xml;
76   }
77  
78 < // returns the Nth tag with the same name in the same subsection or NULL if not
79 < // found
78 > /* returns the Nth tag with the same name in the same subsection or NULL if not */
79 > /* found */
80   ezxml_t ezxml_idx(ezxml_t xml, int idx)
81   {
82      for (; xml && idx; idx--) xml = xml->next;
83      return xml;
84   }
85  
86 < // returns the value of the requested tag attribute or NULL if not found
86 > /* returns the value of the requested tag attribute or NULL if not found */
87   const char *ezxml_attr(ezxml_t xml, const char *attr)
88   {
89      int i = 0, j = 1;
# Line 83 | Line 91 | const char *ezxml_attr(ezxml_t xml, const char *attr)
91  
92      if (! xml || ! xml->attr) return NULL;
93      while (xml->attr[i] && strcmp(attr, xml->attr[i])) i += 2;
94 <    if (xml->attr[i]) return xml->attr[i + 1]; // found attribute
94 >    if (xml->attr[i]) return xml->attr[i + 1]; /* found attribute */
95  
96 <    while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
96 >    while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; /* root tag */
97      for (i = 0; root->attr[i] && strcmp(xml->name, root->attr[i][0]); i++);
98 <    if (! root->attr[i]) return NULL; // no matching default attributes
98 >    if (! root->attr[i]) return NULL; /* no matching default attributes */
99      while (root->attr[i][j] && strcmp(attr, root->attr[i][j])) j += 3;
100 <    return (root->attr[i][j]) ? root->attr[i][j + 1] : NULL; // found default
100 >    return (root->attr[i][j]) ? root->attr[i][j + 1] : NULL; /* found default */
101   }
102  
103 < // same as ezxml_get but takes an already initialized va_list
103 > /* same as ezxml_get but takes an already initialized va_list */
104   ezxml_t ezxml_vget(ezxml_t xml, va_list ap)
105   {
106      char *name = va_arg(ap, char *);
# Line 105 | Line 113 | ezxml_t ezxml_vget(ezxml_t xml, va_list ap)
113      return (idx < 0) ? xml : ezxml_vget(ezxml_idx(xml, idx), ap);
114   }
115  
116 < // Traverses the xml tree to retrieve a specific subtag. Takes a variable
117 < // length list of tag names and indexes. The argument list must be terminated
118 < // by either an index of -1 or an empty string tag name. Example:
119 < // title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1);
120 < // This retrieves the title of the 3rd book on the 1st shelf of library.
121 < // Returns NULL if not found.
116 > /* Traverses the xml tree to retrieve a specific subtag. Takes a variable */
117 > /* length list of tag names and indexes. The argument list must be terminated */
118 > /* by either an index of -1 or an empty string tag name. Example:  */
119 > /* title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1); */
120 > /* This retrieves the title of the 3rd book on the 1st shelf of library. */
121 > /* Returns NULL if not found. */
122   ezxml_t ezxml_get(ezxml_t xml, ...)
123   {
124      va_list ap;
# Line 122 | Line 130 | ezxml_t ezxml_get(ezxml_t xml, ...)
130      return r;
131   }
132  
133 < // returns a null terminated array of processing instructions for the given
134 < // target
133 > /* returns a null terminated array of processing instructions for the given */
134 > /* target */
135   const char **ezxml_pi(ezxml_t xml, const char *target)
136   {
137      ezxml_root_t root = (ezxml_root_t)xml;
138      int i = 0;
139  
140      if (! root) return (const char **)EZXML_NIL;
141 <    while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
142 <    while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target
141 >    while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; /* root tag */
142 >    while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; /* find target */
143      return (const char **)((root->pi[i]) ? root->pi[i] + 1 : EZXML_NIL);
144   }
145  
146 < // set an error string and return root
146 > /* set an error string and return root */
147   ezxml_t ezxml_err(ezxml_root_t root, char *s, const char *err, ...)
148   {
149      va_list ap;
# Line 152 | Line 160 | ezxml_t ezxml_err(ezxml_root_t root, char *s, const ch
160      return &root->xml;
161   }
162  
163 < // Recursively decodes entity and character references and normalizes new lines
164 < // ent is a null terminated array of alternating entity names and values. set t
165 < // to '&' for general entity decoding, '%' for parameter entity decoding, 'c'
166 < // for cdata sections, ' ' for attribute normalization, or '*' for non-cdata
167 < // attribute normalization. Returns s, or if the decoded string is longer than
168 < // s, returns a malloced string that must be freed.
163 > /* Recursively decodes entity and character references and normalizes new lines */
164 > /* ent is a null terminated array of alternating entity names and values. set t */
165 > /* to '&' for general entity decoding, '%' for parameter entity decoding, 'c' */
166 > /* for cdata sections, ' ' for attribute normalization, or '*' for non-cdata */
167 > /* attribute normalization. Returns s, or if the decoded string is longer than */
168 > /* s, returns a malloced string that must be freed. */
169   char *ezxml_decode(char *s, char **ent, char t)
170   {
171      char *e, *r = s, *m = s;
172      long b, c, d, l;
173  
174 <    for (; *s; s++) { // normalize line endings
174 >    for (; *s; s++) { /* normalize line endings */
175          while (*s == '\r') {
176              *(s++) = '\n';
177              if (*s == '\n') memmove(s, (s + 1), strlen(s));
# Line 174 | Line 182 | char *ezxml_decode(char *s, char **ent, char t)
182          while (*s && *s != '&' && (*s != '%' || t != '%') && !isspace(*s)) s++;
183  
184          if (! *s) break;
185 <        else if (t != 'c' && ! strncmp(s, "&#", 2)) { // character reference
186 <            if (s[2] == 'x') c = strtol(s + 3, &e, 16); // base 16
187 <            else c = strtol(s + 2, &e, 10); // base 10
188 <            if (! c || *e != ';') { s++; continue; } // not a character ref
185 >        else if (t != 'c' && ! strncmp(s, "&#", 2)) { /* character reference */
186 >            if (s[2] == 'x') c = strtol(s + 3, &e, 16); /* base 16 */
187 >            else c = strtol(s + 2, &e, 10); /* base 10 */
188 >            if (! c || *e != ';') { s++; continue; } /* not a character ref */
189  
190 <            if (c < 0x80) *(s++) = c; // US-ASCII subset
191 <            else { // multi-byte UTF-8 sequence
192 <                for (b = 0, d = c; d; d /= 2) b++; // number of bits in c
193 <                b = (b - 2) / 5; // number of bytes in payload
194 <                *(s++) = (0xFF << (7 - b)) | (c >> (6 * b)); // head
195 <                while (b) *(s++) = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload
190 >            if (c < 0x80) *(s++) = c; /* US-ASCII subset */
191 >            else { /* multi-byte UTF-8 sequence */
192 >                for (b = 0, d = c; d; d /= 2) b++; /* number of bits in c */
193 >                b = (b - 2) / 5; /* number of bytes in payload */
194 >                *(s++) = (0xFF << (7 - b)) | (c >> (6 * b)); /* head */
195 >                while (b) *(s++) = 0x80 | ((c >> (6 * --b)) & 0x3F); /* payload */
196              }
197  
198              memmove(s, strchr(s, ';') + 1, strlen(strchr(s, ';')));
199          }
200          else if ((*s == '&' && (t == '&' || t == ' ' || t == '*')) ||
201 <                 (*s == '%' && t == '%')) { // entity reference
201 >                 (*s == '%' && t == '%')) { /* entity reference */
202              for (b = 0; ent[b] && strncmp(s + 1, ent[b], strlen(ent[b]));
203 <                 b += 2); // find entity in entity list
203 >                 b += 2); /* find entity in entity list */
204  
205 <            if (ent[b++]) { // found a match
205 >            if (ent[b++]) { /* found a match */
206                  if ((c = strlen(ent[b])) - 1 > (e = strchr(s, ';')) - s) {
207 <                    l = (d = (s - r)) + c + strlen(e); // new length
207 >                    l = (d = (s - r)) + c + strlen(e); /* new length */
208                      r = (r == m) ? strcpy(malloc(l), r) : realloc(r, l);
209 <                    e = strchr((s = r + d), ';'); // fix up pointers
209 >                    e = strchr((s = r + d), ';'); /* fix up pointers */
210                  }
211  
212 <                memmove(s + c, e + 1, strlen(e)); // shift rest of string
213 <                strncpy(s, ent[b], c); // copy in replacement text
212 >                memmove(s + c, e + 1, strlen(e)); /* shift rest of string */
213 >                strncpy(s, ent[b], c); /* copy in replacement text */
214              }
215 <            else s++; // not a known entity
215 >            else s++; /* not a known entity */
216          }
217          else if ((t == ' ' || t == '*') && isspace(*s)) *(s++) = ' ';
218 <        else s++; // no decoding needed
218 >        else s++; /* no decoding needed */
219      }
220  
221 <    if (t == '*') { // normalize spaces for non-cdata attributes
221 >    if (t == '*') { /* normalize spaces for non-cdata attributes */
222          for (s = r; *s; s++) {
223              if ((l = strspn(s, " "))) memmove(s, s + l, strlen(s + l) + 1);
224              while (*s && *s != ' ') s++;
225          }
226 <        if (--s >= r && *s == ' ') *s = '\0'; // trim any trailing space
226 >        if (--s >= r && *s == ' ') *s = '\0'; /* trim any trailing space */
227      }
228      return r;
229   }
230  
231 < // called when parser finds start of new tag
231 > /* called when parser finds start of new tag */
232   void ezxml_open_tag(ezxml_root_t root, char *name, char **attr)
233   {
234      ezxml_t xml = root->cur;
235      
236      if (xml->name) xml = ezxml_add_child(xml, name, strlen(xml->txt));
237 <    else xml->name = name; // first open tag
237 >    else xml->name = name; /* first open tag */
238  
239      xml->attr = attr;
240 <    root->cur = xml; // update tag insertion point
240 >    root->cur = xml; /* update tag insertion point */
241   }
242  
243 < // called when parser finds character content between open and closing tag
243 > /* called when parser finds character content between open and closing tag */
244   void ezxml_char_content(ezxml_root_t root, char *s, size_t len, char t)
245   {
246      ezxml_t xml = root->cur;
247      char *m = s;
248      size_t l;
249  
250 <    if (! xml || ! xml->name || ! len) return; // sanity check
250 >    if (! xml || ! xml->name || ! len) return; /* sanity check */
251  
252 <    s[len] = '\0'; // null terminate text (calling functions anticipate this)
252 >    s[len] = '\0'; /* null terminate text (calling functions anticipate this) */
253      len = strlen(s = ezxml_decode(s, root->ent, t)) + 1;
254  
255 <    if (! *(xml->txt)) xml->txt = s; // initial character content
256 <    else { // allocate our own memory and make a copy
257 <        xml->txt = (xml->flags & EZXML_TXTM) // allocate some space
255 >    if (! *(xml->txt)) xml->txt = s; /* initial character content */
256 >    else { /* allocate our own memory and make a copy */
257 >        xml->txt = (xml->flags & EZXML_TXTM) /* allocate some space */
258                     ? realloc(xml->txt, (l = strlen(xml->txt)) + len)
259                     : strcpy(malloc((l = strlen(xml->txt)) + len), xml->txt);
260 <        strcpy(xml->txt + l, s); // add new char content
261 <        if (s != m) free(s); // free s if it was malloced by ezxml_decode()
260 >        strcpy(xml->txt + l, s); /* add new char content */
261 >        if (s != m) free(s); /* free s if it was malloced by ezxml_decode() */
262      }
263  
264      if (xml->txt != m) ezxml_set_flag(xml, EZXML_TXTM);
265   }
266  
267 < // called when parser finds closing tag
267 > /* called when parser finds closing tag */
268   ezxml_t ezxml_close_tag(ezxml_root_t root, char *name, char *s)
269   {
270      if (! root->cur || ! root->cur->name || strcmp(name, root->cur->name))
# Line 266 | Line 274 | ezxml_t ezxml_close_tag(ezxml_root_t root, char *name,
274      return NULL;
275   }
276  
277 < // checks for circular entity references, returns non-zero if no circular
278 < // references are found, zero otherwise
277 > /* checks for circular entity references, returns non-zero if no circular */
278 > /* references are found, zero otherwise */
279   int ezxml_ent_ok(char *name, char *s, char **ent)
280   {
281      int i;
282  
283      for (; ; s++) {
284 <        while (*s && *s != '&') s++; // find next entity reference
284 >        while (*s && *s != '&') s++; /* find next entity reference */
285          if (! *s) return 1;
286 <        if (! strncmp(s + 1, name, strlen(name))) return 0; // circular ref.
286 >        if (! strncmp(s + 1, name, strlen(name))) return 0; /* circular ref. */
287          for (i = 0; ent[i] && strncmp(ent[i], s + 1, strlen(ent[i])); i += 2);
288          if (ent[i] && ! ezxml_ent_ok(name, ent[i + 1], ent)) return 0;
289      }
290   }
291  
292 < // called when the parser finds a processing instruction
292 > /* called when the parser finds a processing instruction */
293   void ezxml_proc_inst(ezxml_root_t root, char *s, size_t len)
294   {
295      int i = 0, j = 1;
296      char *target = s;
297  
298 <    s[len] = '\0'; // null terminate instruction
298 >    s[len] = '\0'; /* null terminate instruction */
299      if (*(s += strcspn(s, EZXML_WS))) {
300 <        *s = '\0'; // null terminate target
301 <        s += strspn(s + 1, EZXML_WS) + 1; // skip whitespace after target
300 >        *s = '\0'; /* null terminate target */
301 >        s += strspn(s + 1, EZXML_WS) + 1; /* skip whitespace after target */
302      }
303  
304 <    if (! strcmp(target, "xml")) { // <?xml ... ?>
304 >    if (! strcmp(target, "xml")) { /* <?xml ... ?> */
305          if ((s = strstr(s, "standalone")) && ! strncmp(s + strspn(s + 10,
306              EZXML_WS "='\"") + 10, "yes", 3)) root->standalone = 1;
307          return;
308      }
309  
310 <    if (! root->pi[0]) *(root->pi = malloc(sizeof(char **))) = NULL; //first pi
310 >    if (! root->pi[0]) *(root->pi = malloc(sizeof(char **))) = NULL; /*first pi */
311  
312 <    while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target
313 <    if (! root->pi[i]) { // new target
312 >    while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; /* find target */
313 >    if (! root->pi[i]) { /* new target */
314          root->pi = realloc(root->pi, sizeof(char **) * (i + 2));
315          root->pi[i] = malloc(sizeof(char *) * 3);
316          root->pi[i][0] = target;
317 <        root->pi[i][1] = (char *)(root->pi[i + 1] = NULL); // terminate pi list
318 <        root->pi[i][2] = strdup(""); // empty document position list
317 >        root->pi[i][1] = (char *)(root->pi[i + 1] = NULL); /* terminate pi list */
318 >        root->pi[i][2] = strdup(""); /* empty document position list */
319      }
320  
321 <    while (root->pi[i][j]) j++; // find end of instruction list for this target
321 >    while (root->pi[i][j]) j++; /* find end of instruction list for this target */
322      root->pi[i] = realloc(root->pi[i], sizeof(char *) * (j + 3));
323      root->pi[i][j + 2] = realloc(root->pi[i][j + 1], j + 1);
324      strcpy(root->pi[i][j + 2] + j - 1, (root->xml.name) ? ">" : "<");
325 <    root->pi[i][j + 1] = NULL; // null terminate pi list for this target
326 <    root->pi[i][j] = s; // set instruction
325 >    root->pi[i][j + 1] = NULL; /* null terminate pi list for this target */
326 >    root->pi[i][j] = s; /* set instruction */
327   }
328  
329 < // called when the parser finds an internal doctype subset
329 > /* called when the parser finds an internal doctype subset */
330   short ezxml_internal_dtd(ezxml_root_t root, char *s, size_t len)
331   {
332      char q, *c, *t, *n = NULL, *v, **ent, **pe;
# Line 327 | Line 335 | short ezxml_internal_dtd(ezxml_root_t root, char *s, s
335      pe = memcpy(malloc(sizeof(EZXML_NIL)), EZXML_NIL, sizeof(EZXML_NIL));
336  
337      for (s[len] = '\0'; s; ) {
338 <        while (*s && *s != '<' && *s != '%') s++; // find next declaration
338 >        while (*s && *s != '<' && *s != '%') s++; /* find next declaration */
339  
340          if (! *s) break;
341 <        else if (! strncmp(s, "<!ENTITY", 8)) { // parse entity definitions
342 <            c = s += strspn(s + 8, EZXML_WS) + 8; // skip white space separator
343 <            n = s + strspn(s, EZXML_WS "%"); // find name
344 <            *(s = n + strcspn(n, EZXML_WS)) = ';'; // append ; to name
341 >        else if (! strncmp(s, "<!ENTITY", 8)) { /* parse entity definitions */
342 >            c = s += strspn(s + 8, EZXML_WS) + 8; /* skip white space separator */
343 >            n = s + strspn(s, EZXML_WS "%"); /* find name */
344 >            *(s = n + strcspn(n, EZXML_WS)) = ';'; /* append ; to name */
345  
346 <            v = s + strspn(s + 1, EZXML_WS) + 1; // find value
347 <            if ((q = *(v++)) != '"' && q != '\'') { // skip externals
346 >            v = s + strspn(s + 1, EZXML_WS) + 1; /* find value */
347 >            if ((q = *(v++)) != '"' && q != '\'') { /* skip externals */
348                  s = strchr(s, '>');
349                  continue;
350              }
351  
352              for (i = 0, ent = (*c == '%') ? pe : root->ent; ent[i]; i++);
353 <            ent = realloc(ent, (i + 3) * sizeof(char *)); // space for next ent
353 >            ent = realloc(ent, (i + 3) * sizeof(char *)); /* space for next ent */
354              if (*c == '%') pe = ent;
355              else root->ent = ent;
356  
357 <            *(++s) = '\0'; // null terminate name
358 <            if ((s = strchr(v, q))) *(s++) = '\0'; // null terminate value
359 <            ent[i + 1] = ezxml_decode(v, pe, '%'); // set value
360 <            ent[i + 2] = NULL; // null terminate entity list
361 <            if (! ezxml_ent_ok(n, ent[i + 1], ent)) { // circular reference
357 >            *(++s) = '\0'; /* null terminate name */
358 >            if ((s = strchr(v, q))) *(s++) = '\0'; /* null terminate value */
359 >            ent[i + 1] = ezxml_decode(v, pe, '%'); /* set value */
360 >            ent[i + 2] = NULL; /* null terminate entity list */
361 >            if (! ezxml_ent_ok(n, ent[i + 1], ent)) { /* circular reference */
362                  if (ent[i + 1] != v) free(ent[i + 1]);
363                  ezxml_err(root, v, "circular entity declaration &%s", n);
364                  break;
365              }
366 <            else ent[i] = n; // set entity name
366 >            else ent[i] = n; /* set entity name */
367          }
368 <        else if (! strncmp(s, "<!ATTLIST", 9)) { // parse default attributes
369 <            t = s + strspn(s + 9, EZXML_WS) + 9; // skip whitespace separator
368 >        else if (! strncmp(s, "<!ATTLIST", 9)) { /* parse default attributes */
369 >            t = s + strspn(s + 9, EZXML_WS) + 9; /* skip whitespace separator */
370              if (! *t) { ezxml_err(root, t, "unclosed <!ATTLIST"); break; }
371              if (*(s = t + strcspn(t, EZXML_WS ">")) == '>') continue;
372 <            else *s = '\0'; // null terminate tag name
372 >            else *s = '\0'; /* null terminate tag name */
373              for (i = 0; root->attr[i] && strcmp(n, root->attr[i][0]); i++);
374  
375              while (*(n = ++s + strspn(s, EZXML_WS)) && *n != '>') {
376 <                if (*(s = n + strcspn(n, EZXML_WS))) *s = '\0'; // attr name
376 >                if (*(s = n + strcspn(n, EZXML_WS))) *s = '\0'; /* attr name */
377                  else { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
378  
379 <                s += strspn(s + 1, EZXML_WS) + 1; // find next token
380 <                c = (strncmp(s, "CDATA", 5)) ? "*" : " "; // is it cdata?
379 >                s += strspn(s + 1, EZXML_WS) + 1; /* find next token */
380 >                c = (strncmp(s, "CDATA", 5)) ? "*" : " "; /* is it cdata? */
381                  if (! strncmp(s, "NOTATION", 8))
382                      s += strspn(s + 8, EZXML_WS) + 8;
383                  s = (*s == '(') ? strchr(s, ')') : s + strcspn(s, EZXML_WS);
384                  if (! s) { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
385  
386 <                s += strspn(s, EZXML_WS ")"); // skip white space separator
386 >                s += strspn(s, EZXML_WS ")"); /* skip white space separator */
387                  if (! strncmp(s, "#FIXED", 6))
388                      s += strspn(s + 6, EZXML_WS) + 6;
389 <                if (*s == '#') { // no default value
389 >                if (*s == '#') { /* no default value */
390                      s += strcspn(s, EZXML_WS ">") - 1;
391 <                    if (*c == ' ') continue; // cdata is default, nothing to do
391 >                    if (*c == ' ') continue; /* cdata is default, nothing to do */
392                      v = NULL;
393                  }
394 <                else if ((*s == '"' || *s == '\'')  &&  // default value
394 >                else if ((*s == '"' || *s == '\'')  &&  /* default value */
395                           (s = strchr(v = s + 1, *s))) *s = '\0';
396                  else { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
397  
398 <                if (! root->attr[i]) { // new tag name
398 >                if (! root->attr[i]) { /* new tag name */
399                      root->attr = (! i) ? malloc(2 * sizeof(char **))
400                                         : realloc(root->attr,
401                                                   (i + 2) * sizeof(char **));
402                      root->attr[i] = malloc(2 * sizeof(char *));
403 <                    root->attr[i][0] = t; // set tag name
403 >                    root->attr[i][0] = t; /* set tag name */
404                      root->attr[i][1] = (char *)(root->attr[i + 1] = NULL);
405                  }
406  
407 <                for (j = 1; root->attr[i][j]; j += 3); // find end of list
407 >                for (j = 1; root->attr[i][j]; j += 3); /* find end of list */
408                  root->attr[i] = realloc(root->attr[i],
409                                          (j + 4) * sizeof(char *));
410  
411 <                root->attr[i][j + 3] = NULL; // null terminate list
412 <                root->attr[i][j + 2] = c; // is it cdata?
411 >                root->attr[i][j + 3] = NULL; /* null terminate list */
412 >                root->attr[i][j + 2] = c; /* is it cdata? */
413                  root->attr[i][j + 1] = (v) ? ezxml_decode(v, root->ent, *c)
414                                             : NULL;
415 <                root->attr[i][j] = n; // attribute name
415 >                root->attr[i][j] = n; /* attribute name  */
416              }
417          }
418 <        else if (! strncmp(s, "<!--", 4)) s = strstr(s + 4, "-->"); // comments
419 <        else if (! strncmp(s, "<?", 2)) { // processing instructions
418 >        else if (! strncmp(s, "<!--", 4)) s = strstr(s + 4, "-->"); /* comments */
419 >        else if (! strncmp(s, "<?", 2)) { /* processing instructions */
420              if ((s = strstr(c = s + 2, "?>")))
421                  ezxml_proc_inst(root, c, s++ - c);
422          }
423 <        else if (*s == '<') s = strchr(s, '>'); // skip other declarations
423 >        else if (*s == '<') s = strchr(s, '>'); /* skip other declarations */
424          else if (*(s++) == '%' && ! root->standalone) break;
425      }
426  
# Line 420 | Line 428 | short ezxml_internal_dtd(ezxml_root_t root, char *s, s
428      return ! *root->err;
429   }
430  
431 < // Converts a UTF-16 string to UTF-8. Returns a new string that must be freed
432 < // or NULL if no conversion was needed.
431 > /* Converts a UTF-16 string to UTF-8. Returns a new string that must be freed */
432 > /* or NULL if no conversion was needed. */
433   char *ezxml_str2utf8(char **s, size_t *len)
434   {
435      char *u;
# Line 429 | Line 437 | char *ezxml_str2utf8(char **s, size_t *len)
437      long c, d;
438      int b, be = (**s == '\xFE') ? 1 : (**s == '\xFF') ? 0 : -1;
439  
440 <    if (be == -1) return NULL; // not UTF-16
440 >    if (be == -1) return NULL; /* not UTF-16 */
441  
442      u = malloc(max);
443      for (sl = 2; sl < *len - 1; sl += 2) {
444 <        c = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF)  //UTF-16BE
445 <                 : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF); //UTF-16LE
446 <        if (c >= 0xD800 && c <= 0xDFFF && (sl += 2) < *len - 1) { // high-half
444 >        c = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF)  /*UTF-16BE */
445 >                 : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF); /*UTF-16LE */
446 >        if (c >= 0xD800 && c <= 0xDFFF && (sl += 2) < *len - 1) { /* high-half */
447              d = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF)
448                       : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF);
449              c = (((c & 0x3FF) << 10) | (d & 0x3FF)) + 0x10000;
450          }
451  
452          while (l + 6 > max) u = realloc(u, max += EZXML_BUFSIZE);
453 <        if (c < 0x80) u[l++] = c; // US-ASCII subset
454 <        else { // multi-byte UTF-8 sequence
455 <            for (b = 0, d = c; d; d /= 2) b++; // bits in c
456 <            b = (b - 2) / 5; // bytes in payload
457 <            u[l++] = (0xFF << (7 - b)) | (c >> (6 * b)); // head
458 <            while (b) u[l++] = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload
453 >        if (c < 0x80) u[l++] = c; /* US-ASCII subset */
454 >        else { /* multi-byte UTF-8 sequence */
455 >            for (b = 0, d = c; d; d /= 2) b++; /* bits in c */
456 >            b = (b - 2) / 5; /* bytes in payload */
457 >            u[l++] = (0xFF << (7 - b)) | (c >> (6 * b)); /* head */
458 >            while (b) u[l++] = 0x80 | ((c >> (6 * --b)) & 0x3F); /* payload */
459          }
460      }
461      return *s = realloc(u, *len = l);
462   }
463  
464 < // frees a tag attribute list
464 > /* frees a tag attribute list */
465   void ezxml_free_attr(char **attr) {
466      int i = 0;
467      char *m;
468      
469 <    if (! attr || attr == EZXML_NIL) return; // nothing to free
470 <    while (attr[i]) i += 2; // find end of attribute list
471 <    m = attr[i + 1]; // list of which names and values are malloced
469 >    if (! attr || attr == EZXML_NIL) return; /* nothing to free */
470 >    while (attr[i]) i += 2; /* find end of attribute list */
471 >    m = attr[i + 1]; /* list of which names and values are malloced */
472      for (i = 0; m[i]; i++) {
473          if (m[i] & EZXML_NAMEM) free(attr[i * 2]);
474          if (m[i] & EZXML_TXTM) free(attr[(i * 2) + 1]);
# Line 469 | Line 477 | void ezxml_free_attr(char **attr) {
477      free(attr);
478   }
479  
480 < // parse the given xml string and return an ezxml structure
480 > /* parse the given xml string and return an ezxml structure */
481   ezxml_t ezxml_parse_str(char *s, size_t len)
482   {
483      ezxml_root_t root = (ezxml_root_t)ezxml_new(NULL);
484 <    char q, e, *d, **attr, **a = NULL; // initialize a to avoid compile warning
484 >    char q, e, *d, **attr, **a = NULL; /* initialize a to avoid compile warning */
485      int l, i, j;
486  
487      root->m = s;
488      if (! len) return ezxml_err(root, NULL, "root tag missing");
489 <    root->u = ezxml_str2utf8(&s, &len); // convert utf-16 to utf-8
490 <    root->e = (root->s = s) + len; // record start and end of work area
489 >    root->u = ezxml_str2utf8(&s, &len); /* convert utf-16 to utf-8 */
490 >    root->e = (root->s = s) + len; /* record start and end of work area */
491      
492 <    e = s[len - 1]; // save end char
493 <    s[len - 1] = '\0'; // turn end char into null terminator
492 >    e = s[len - 1]; /* save end char */
493 >    s[len - 1] = '\0'; /* turn end char into null terminator */
494  
495 <    while (*s && *s != '<') s++; // find first tag
495 >    while (*s && *s != '<') s++; /* find first tag */
496      if (! *s) return ezxml_err(root, s, "root tag missing");
497  
498      for (; ; ) {
499          attr = (char **)EZXML_NIL;
500          d = ++s;
501          
502 <        if (isalpha(*s) || *s == '_' || *s == ':' || *s < '\0') { // new tag
502 >        if (isalpha(*s) || *s == '_' || *s == ':' || *s < '\0') { /* new tag */
503              if (! root->cur)
504                  return ezxml_err(root, d, "markup outside of root element");
505  
506              s += strcspn(s, EZXML_WS "/>");
507 <            while (isspace(*s)) *(s++) = '\0'; // null terminate tag name
507 >            while (isspace(*s)) *(s++) = '\0'; /* null terminate tag name */
508    
509 <            if (*s && *s != '/' && *s != '>') // find tag in default attr list
509 >            if (*s && *s != '/' && *s != '>') /* find tag in default attr list */
510                  for (i = 0; (a = root->attr[i]) && strcmp(a[0], d); i++);
511  
512 <            for (l = 0; *s && *s != '/' && *s != '>'; l += 2) { // new attrib
512 >            for (l = 0; *s && *s != '/' && *s != '>'; l += 2) { /* new attrib */
513                  attr = (l) ? realloc(attr, (l + 4) * sizeof(char *))
514 <                           : malloc(4 * sizeof(char *)); // allocate space
514 >                           : malloc(4 * sizeof(char *)); /* allocate space */
515                  attr[l + 3] = (l) ? realloc(attr[l + 1], (l / 2) + 2)
516 <                                  : malloc(2); // mem for list of maloced vals
517 <                strcpy(attr[l + 3] + (l / 2), " "); // value is not malloced
518 <                attr[l + 2] = NULL; // null terminate list
519 <                attr[l + 1] = ""; // temporary attribute value
520 <                attr[l] = s; // set attribute name
516 >                                  : malloc(2); /* mem for list of maloced vals */
517 >                strcpy(attr[l + 3] + (l / 2), " "); /* value is not malloced */
518 >                attr[l + 2] = NULL; /* null terminate list */
519 >                attr[l + 1] = ""; /* temporary attribute value */
520 >                attr[l] = s; /* set attribute name */
521  
522                  s += strcspn(s, EZXML_WS "=/>");
523                  if (*s == '=' || isspace(*s)) {
524 <                    *(s++) = '\0'; // null terminate tag attribute name
524 >                    *(s++) = '\0'; /* null terminate tag attribute name */
525                      q = *(s += strspn(s, EZXML_WS "="));
526 <                    if (q == '"' || q == '\'') { // attribute value
526 >                    if (q == '"' || q == '\'') { /* attribute value */
527                          attr[l + 1] = ++s;
528                          while (*s && *s != q) s++;
529 <                        if (*s) *(s++) = '\0'; // null terminate attribute val
529 >                        if (*s) *(s++) = '\0'; /* null terminate attribute val */
530                          else {
531                              ezxml_free_attr(attr);
532                              return ezxml_err(root, d, "missing %c", q);
# Line 528 | Line 536 | ezxml_t ezxml_parse_str(char *s, size_t len)
536                          attr[l + 1] = ezxml_decode(attr[l + 1], root->ent, (a
537                                                     && a[j]) ? *a[j + 2] : ' ');
538                          if (attr[l + 1] < d || attr[l + 1] > s)
539 <                            attr[l + 3][l / 2] = EZXML_TXTM; // value malloced
539 >                            attr[l + 3][l / 2] = EZXML_TXTM; /* value malloced */
540                      }
541                  }
542                  while (isspace(*s)) s++;
543              }
544  
545 <            if (*s == '/') { // self closing tag
545 >            if (*s == '/') { /* self closing tag */
546                  *(s++) = '\0';
547                  if ((*s && *s != '>') || (! *s && e != '>')) {
548                      if (l) ezxml_free_attr(attr);
# Line 543 | Line 551 | ezxml_t ezxml_parse_str(char *s, size_t len)
551                  ezxml_open_tag(root, d, attr);
552                  ezxml_close_tag(root, d, s);
553              }
554 <            else if ((q = *s) == '>' || (! *s && e == '>')) { // open tag
555 <                *s = '\0'; // temporarily null terminate tag name
554 >            else if ((q = *s) == '>' || (! *s && e == '>')) { /* open tag */
555 >                *s = '\0'; /* temporarily null terminate tag name */
556                  ezxml_open_tag(root, d, attr);
557                  *s = q;
558              }
# Line 553 | Line 561 | ezxml_t ezxml_parse_str(char *s, size_t len)
561                  return ezxml_err(root, d, "missing >");
562              }
563          }
564 <        else if (*s == '/') { // close tag
564 >        else if (*s == '/') { /* close tag */
565              s += strcspn(d = s + 1, EZXML_WS ">") + 1;
566              if (! (q = *s) && e != '>') return ezxml_err(root, d, "missing >");
567 <            *s = '\0'; // temporarily null terminate tag name
567 >            *s = '\0'; /* temporarily null terminate tag name */
568              if (ezxml_close_tag(root, d, s)) return &root->xml;
569              if (isspace(*s = q)) s += strspn(s, EZXML_WS);
570          }
571 <        else if (! strncmp(s, "!--", 3)) { // xml comment
571 >        else if (! strncmp(s, "!--", 3)) { /* xml comment */
572              if (! (s = strstr(s + 3, "--")) || (*(s += 2) != '>' && *s) ||
573                  (! *s && e != '>')) return ezxml_err(root, d, "unclosed <!--");
574          }
575 <        else if (! strncmp(s, "![CDATA[", 8)) { // cdata
575 >        else if (! strncmp(s, "![CDATA[", 8)) { /* cdata */
576              if ((s = strstr(s, "]]>")))
577                  ezxml_char_content(root, d + 8, (s += 2) - d - 10, 'c');
578              else return ezxml_err(root, d, "unclosed <![CDATA[");
579          }
580 <        else if (! strncmp(s, "!DOCTYPE", 8)) { // dtd
580 >        else if (! strncmp(s, "!DOCTYPE", 8)) { /* dtd */
581              for (l = 0; *s && ((! l && *s != '>') || (l && (*s != ']' ||
582                   *(s + strspn(s + 1, EZXML_WS) + 1) != '>')));
583                   l = (*s == '[') ? 1 : l) s += strcspn(s + 1, "[]>") + 1;
# Line 578 | Line 586 | ezxml_t ezxml_parse_str(char *s, size_t len)
586              d = (l) ? strchr(d, '[') + 1 : d;
587              if (l && ! ezxml_internal_dtd(root, d, s++ - d)) return &root->xml;
588          }
589 <        else if (*s == '?') { // <?...?> processing instructions
589 >        else if (*s == '?') { /* <?...?> processing instructions */
590              do { s = strchr(s, '?'); } while (s && *(++s) && *s != '>');
591              if (! s || (! *s && e != '>'))
592                  return ezxml_err(root, d, "unclosed <?");
# Line 589 | Line 597 | ezxml_t ezxml_parse_str(char *s, size_t len)
597          if (! s || ! *s) break;
598          *s = '\0';
599          d = ++s;
600 <        if (*s && *s != '<') { // tag character content
600 >        if (*s && *s != '<') { /* tag character content */
601              while (*s && *s != '<') s++;
602              if (*s) ezxml_char_content(root, d, s - d, '&');
603              else break;
# Line 602 | Line 610 | ezxml_t ezxml_parse_str(char *s, size_t len)
610      else return ezxml_err(root, d, "unclosed tag <%s>", root->cur->name);
611   }
612  
613 < // Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire
614 < // stream into memory and then parses it. For xml files, use ezxml_parse_file()
615 < // or ezxml_parse_fd()
613 > /* Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire */
614 > /* stream into memory and then parses it. For xml files, use ezxml_parse_file() */
615 > /* or ezxml_parse_fd() */
616   ezxml_t ezxml_parse_fp(FILE *fp)
617   {
618      ezxml_root_t root;
# Line 619 | Line 627 | ezxml_t ezxml_parse_fp(FILE *fp)
627  
628      if (! s) return NULL;
629      root = (ezxml_root_t)ezxml_parse_str(s, len);
630 <    root->len = -1; // so we know to free s in ezxml_free()
630 >    root->len = -1; /* so we know to free s in ezxml_free() */
631      return &root->xml;
632   }
633  
634 < // A wrapper for ezxml_parse_str() that accepts a file descriptor. First
635 < // attempts to mem map the file. Failing that, reads the file into memory.
636 < // Returns NULL on failure.
634 > /* A wrapper for ezxml_parse_str() that accepts a file descriptor. First */
635 > /* attempts to mem map the file. Failing that, reads the file into memory. */
636 > /* Returns NULL on failure. */
637   ezxml_t ezxml_parse_fd(int fd)
638   {
639      ezxml_root_t root;
# Line 640 | Line 648 | ezxml_t ezxml_parse_fd(int fd)
648      l = (st.st_size + sysconf(_SC_PAGESIZE) - 1) & ~(sysconf(_SC_PAGESIZE) -1);
649      if ((m = mmap(NULL, l, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0))
650                  !=  MAP_FAILED) {
651 <        madvise(m, l, MADV_SEQUENTIAL); // optimize for sequential access
651 >        madvise(m, l, MADV_SEQUENTIAL); /* optimize for sequential access */
652          root = (ezxml_root_t)ezxml_parse_str(m, st.st_size);
653 <        madvise(m, root->len = l, MADV_NORMAL); // put it back to normal
653 >        madvise(m, root->len = l, MADV_NORMAL); /* put it back to normal */
654      }
655 <    else { // mmap failed, read file into memory
656 < #endif // EZXML_NOMMAP
655 >    else { /* mmap failed, read file into memory */
656 > #endif /* EZXML_NOMMAP */
657          l = read(fd, m = malloc(st.st_size), st.st_size);
658          root = (ezxml_root_t)ezxml_parse_str(m, l);
659 <        root->len = -1; // so we know to free s in ezxml_free()
659 >        root->len = -1; /* so we know to free s in ezxml_free() */
660   #ifndef EZXML_NOMMAP
661      }
662 < #endif // EZXML_NOMMAP
662 > #endif /* EZXML_NOMMAP */
663      return &root->xml;
664   }
665  
666 < // a wrapper for ezxml_parse_fd that accepts a file name
666 > /* a wrapper for ezxml_parse_fd that accepts a file name */
667   ezxml_t ezxml_parse_file(const char *file)
668   {
669      int fd = open(file, O_RDONLY, 0);
# Line 665 | Line 673 | ezxml_t ezxml_parse_file(const char *file)
673      return xml;
674   }
675  
676 < // Encodes ampersand sequences appending the results to *dst, reallocating *dst
677 < // if length excedes max. a is non-zero for attribute encoding. Returns *dst
676 > /* Encodes ampersand sequences appending the results to *dst, reallocating *dst */
677 > /* if length excedes max. a is non-zero for attribute encoding. Returns *dst */
678   char *ezxml_ampencode(const char *s, size_t len, char **dst, size_t *dlen,
679                        size_t *max, short a)
680   {
# Line 690 | Line 698 | char *ezxml_ampencode(const char *s, size_t len, char
698      return *dst;
699   }
700  
701 < // Recursively converts each tag to xml appending it to *s. Reallocates *s if
702 < // its length excedes max. start is the location of the previous tag in the
703 < // parent tag's character content. Returns *s.
701 > /* Recursively converts each tag to xml appending it to *s. Reallocates *s if */
702 > /* its length excedes max. start is the location of the previous tag in the */
703 > /* parent tag's character content. Returns *s. */
704   char *ezxml_toxml_r(ezxml_t xml, char **s, size_t *len, size_t *max,
705                      size_t start, char ***attr)
706   {
# Line 700 | Line 708 | char *ezxml_toxml_r(ezxml_t xml, char **s, size_t *len
708      char *txt = (xml->parent) ? xml->parent->txt : "";
709      size_t off = 0;
710  
711 <    // parent character content up to this tag
711 >    /* parent character content up to this tag */
712      *s = ezxml_ampencode(txt + start, xml->off - start, s, len, max, 0);
713  
714 <    while (*len + strlen(xml->name) + 4 > *max) // reallocate s
714 >    while (*len + strlen(xml->name) + 4 > *max) /* reallocate s */
715          *s = realloc(*s, *max += EZXML_BUFSIZE);
716  
717 <    *len += sprintf(*s + *len, "<%s", xml->name); // open tag
718 <    for (i = 0; xml->attr[i]; i += 2) { // tag attributes
717 >    *len += sprintf(*s + *len, "<%s", xml->name); /* open tag */
718 >    for (i = 0; xml->attr[i]; i += 2) { /* tag attributes */
719          if (ezxml_attr(xml, xml->attr[i]) != xml->attr[i + 1]) continue;
720 <        while (*len + strlen(xml->attr[i]) + 7 > *max) // reallocate s
720 >        while (*len + strlen(xml->attr[i]) + 7 > *max) /* reallocate s */
721              *s = realloc(*s, *max += EZXML_BUFSIZE);
722  
723          *len += sprintf(*s + *len, " %s=\"", xml->attr[i]);
# Line 718 | Line 726 | char *ezxml_toxml_r(ezxml_t xml, char **s, size_t *len
726      }
727  
728      for (i = 0; attr[i] && strcmp(attr[i][0], xml->name); i++);
729 <    for (j = 1; attr[i] && attr[i][j]; j += 3) { // default attributes
729 >    for (j = 1; attr[i] && attr[i][j]; j += 3) { /* default attributes */
730          if (! attr[i][j + 1] || ezxml_attr(xml, attr[i][j]) != attr[i][j + 1])
731 <            continue; // skip duplicates and non-values
732 <        while (*len + strlen(attr[i][j]) + 7 > *max) // reallocate s
731 >            continue; /* skip duplicates and non-values */
732 >        while (*len + strlen(attr[i][j]) + 7 > *max) /* reallocate s */
733              *s = realloc(*s, *max += EZXML_BUFSIZE);
734  
735          *len += sprintf(*s + *len, " %s=\"", attr[i][j]);
# Line 730 | Line 738 | char *ezxml_toxml_r(ezxml_t xml, char **s, size_t *len
738      }
739      *len += sprintf(*s + *len, ">");
740  
741 <    *s = (xml->child) ? ezxml_toxml_r(xml->child, s, len, max, 0, attr) //child
742 <                      : ezxml_ampencode(xml->txt, -1, s, len, max, 0);  //data
741 >    *s = (xml->child) ? ezxml_toxml_r(xml->child, s, len, max, 0, attr) /*child */
742 >                      : ezxml_ampencode(xml->txt, -1, s, len, max, 0);  /*data */
743      
744 <    while (*len + strlen(xml->name) + 4 > *max) // reallocate s
744 >    while (*len + strlen(xml->name) + 4 > *max) /* reallocate s */
745          *s = realloc(*s, *max += EZXML_BUFSIZE);
746  
747 <    *len += sprintf(*s + *len, "</%s>", xml->name); // close tag
747 >    *len += sprintf(*s + *len, "</%s>", xml->name); /* close tag */
748  
749 <    while (txt[off] && off < xml->off) off++; // make sure off is within bounds
749 >    while (txt[off] && off < xml->off) off++; /* make sure off is within bounds */
750      return (xml->ordered) ? ezxml_toxml_r(xml->ordered, s, len, max, off, attr)
751                            : ezxml_ampencode(txt + off, -1, s, len, max, 0);
752   }
753  
754 < // Converts an ezxml structure back to xml. Returns a string of xml data that
755 < // must be freed.
754 > /* Converts an ezxml structure back to xml. Returns a string of xml data that */
755 > /* must be freed. */
756   char *ezxml_toxml(ezxml_t xml)
757   {
758      ezxml_t p = (xml) ? xml->parent : NULL, o = (xml) ? xml->ordered : NULL;
# Line 754 | Line 762 | char *ezxml_toxml(ezxml_t xml)
762      int i, j, k;
763  
764      if (! xml || ! xml->name) return realloc(s, len + 1);
765 <    while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
765 >    while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; /* root tag */
766  
767 <    for (i = 0; ! p && root->pi[i]; i++) { // pre-root processing instructions
767 >    for (i = 0; ! p && root->pi[i]; i++) { /* pre-root processing instructions */
768          for (k = 2; root->pi[i][k - 1]; k++);
769          for (j = 1; (n = root->pi[i][j]); j++) {
770 <            if (root->pi[i][k][j - 1] == '>') continue; // not pre-root
770 >            if (root->pi[i][k][j - 1] == '>') continue; /* not pre-root */
771              while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max)
772                  s = realloc(s, max += EZXML_BUFSIZE);
773              len += sprintf(s + len, "<?%s%s%s?>\n", t, *n ? " " : "", n);
# Line 771 | Line 779 | char *ezxml_toxml(ezxml_t xml)
779      xml->parent = p;
780      xml->ordered = o;
781  
782 <    for (i = 0; ! p && root->pi[i]; i++) { // post-root processing instructions
782 >    for (i = 0; ! p && root->pi[i]; i++) { /* post-root processing instructions */
783          for (k = 2; root->pi[i][k - 1]; k++);
784          for (j = 1; (n = root->pi[i][j]); j++) {
785 <            if (root->pi[i][k][j - 1] == '<') continue; // not post-root
785 >            if (root->pi[i][k][j - 1] == '<') continue; /* not post-root */
786              while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max)
787                  s = realloc(s, max += EZXML_BUFSIZE);
788              len += sprintf(s + len, "\n<?%s%s%s?>", t, *n ? " " : "", n);
# Line 783 | Line 791 | char *ezxml_toxml(ezxml_t xml)
791      return realloc(s, len + 1);
792   }
793  
794 < // free the memory allocated for the ezxml structure
794 > /* free the memory allocated for the ezxml structure */
795   void ezxml_free(ezxml_t xml)
796   {
797      ezxml_root_t root = (ezxml_root_t)xml;
# Line 794 | Line 802 | void ezxml_free(ezxml_t xml)
802      ezxml_free(xml->child);
803      ezxml_free(xml->ordered);
804  
805 <    if (! xml->parent) { // free root tag allocations
806 <        for (i = 10; root->ent[i]; i += 2) // 0 - 9 are default entites (<>&"')
805 >    if (! xml->parent) { /* free root tag allocations */
806 >        for (i = 10; root->ent[i]; i += 2) /* 0 - 9 are default entites (<>&"') */
807              if ((s = root->ent[i + 1]) < root->s || s > root->e) free(s);
808 <        free(root->ent); // free list of general entities
808 >        free(root->ent); /* free list of general entities */
809  
810          for (i = 0; (a = root->attr[i]); i++) {
811 <            for (j = 1; a[j++]; j += 2) // free malloced attribute values
811 >            for (j = 1; a[j++]; j += 2) /* free malloced attribute values */
812                  if (a[j] && (a[j] < root->s || a[j] > root->e)) free(a[j]);
813              free(a);
814          }
815 <        if (root->attr[0]) free(root->attr); // free default attribute list
815 >        if (root->attr[0]) free(root->attr); /* free default attribute list */
816  
817          for (i = 0; root->pi[i]; i++) {
818              for (j = 1; root->pi[i][j]; j++);
819              free(root->pi[i][j + 1]);
820              free(root->pi[i]);
821          }            
822 <        if (root->pi[0]) free(root->pi); // free processing instructions
822 >        if (root->pi[0]) free(root->pi); /* free processing instructions */
823  
824 <        if (root->len == -1) free(root->m); // malloced xml data
824 >        if (root->len == -1) free(root->m); /* malloced xml data */
825   #ifndef EZXML_NOMMAP
826 <        else if (root->len) munmap(root->m, root->len); // mem mapped xml data
827 < #endif // EZXML_NOMMAP
828 <        if (root->u) free(root->u); // utf8 conversion
826 >        else if (root->len) munmap(root->m, root->len); /* mem mapped xml data */
827 > #endif /* EZXML_NOMMAP */
828 >        if (root->u) free(root->u); /* utf8 conversion */
829      }
830  
831 <    ezxml_free_attr(xml->attr); // tag attributes
832 <    if ((xml->flags & EZXML_TXTM)) free(xml->txt); // character content
833 <    if ((xml->flags & EZXML_NAMEM)) free(xml->name); // tag name
831 >    ezxml_free_attr(xml->attr); /* tag attributes */
832 >    if ((xml->flags & EZXML_TXTM)) free(xml->txt); /* character content */
833 >    if ((xml->flags & EZXML_NAMEM)) free(xml->name); /* tag name */
834      free(xml);
835   }
836  
837 < // return parser error message or empty string if none
837 > /* return parser error message or empty string if none */
838   const char *ezxml_error(ezxml_t xml)
839   {
840 <    while (xml && xml->parent) xml = xml->parent; // find root tag
840 >    while (xml && xml->parent) xml = xml->parent; /* find root tag */
841      return (xml) ? ((ezxml_root_t)xml)->err : "";
842   }
843  
844 < // returns a new empty ezxml structure with the given root tag name
844 > /* returns a new empty ezxml structure with the given root tag name */
845   ezxml_t ezxml_new(const char *name)
846   {
847      static char *ent[] = { "lt;", "&#60;", "gt;", "&#62;", "quot;", "&#34;",
# Line 848 | Line 856 | ezxml_t ezxml_new(const char *name)
856      return &root->xml;
857   }
858  
859 < // inserts an existing tag into an ezxml structure
859 > /* inserts an existing tag into an ezxml structure */
860   ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off)
861   {
862      ezxml_t cur, prev, head;
# Line 857 | Line 865 | ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t
865      xml->off = off;
866      xml->parent = dest;
867  
868 <    if ((head = dest->child)) { // already have sub tags
869 <        if (head->off <= off) { // not first subtag
868 >    if ((head = dest->child)) { /* already have sub tags */
869 >        if (head->off <= off) { /* not first subtag */
870              for (cur = head; cur->ordered && cur->ordered->off <= off;
871                   cur = cur->ordered);
872              xml->ordered = cur->ordered;
873              cur->ordered = xml;
874          }
875 <        else { // first subtag
875 >        else { /* first subtag */
876              xml->ordered = head;
877              dest->child = xml;
878          }
879  
880          for (cur = head, prev = NULL; cur && strcmp(cur->name, xml->name);
881 <             prev = cur, cur = cur->sibling); // find tag type
882 <        if (cur && cur->off <= off) { // not first of type
881 >             prev = cur, cur = cur->sibling); /* find tag type */
882 >        if (cur && cur->off <= off) { /* not first of type */
883              while (cur->next && cur->next->off <= off) cur = cur->next;
884              xml->next = cur->next;
885              cur->next = xml;
886          }
887 <        else { // first tag of this type
888 <            if (prev && cur) prev->sibling = cur->sibling; // remove old first
889 <            xml->next = cur; // old first tag is now next
887 >        else { /* first tag of this type */
888 >            if (prev && cur) prev->sibling = cur->sibling; /* remove old first */
889 >            xml->next = cur; /* old first tag is now next */
890              for (cur = head, prev = NULL; cur && cur->off <= off;
891 <                 prev = cur, cur = cur->sibling); // new sibling insert point
891 >                 prev = cur, cur = cur->sibling); /* new sibling insert point */
892              xml->sibling = cur;
893              if (prev) prev->sibling = xml;
894          }
895      }
896 <    else dest->child = xml; // only sub tag
896 >    else dest->child = xml; /* only sub tag */
897  
898      return xml;
899   }
900  
901 < // Adds a child tag. off is the offset of the child tag relative to the start
902 < // of the parent tag's character content. Returns the child tag.
901 > /* Adds a child tag. off is the offset of the child tag relative to the start */
902 > /* of the parent tag's character content. Returns the child tag. */
903   ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off)
904   {
905      ezxml_t child;
# Line 906 | Line 914 | ezxml_t ezxml_add_child(ezxml_t xml, const char *name,
914      return ezxml_insert(child, xml, off);
915   }
916  
917 < // sets the character content for the given tag and returns the tag
917 > /* sets the character content for the given tag and returns the tag */
918   ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt)
919   {
920      if (! xml) return NULL;
921 <    if (xml->flags & EZXML_TXTM) free(xml->txt); // existing txt was malloced
921 >    if (xml->flags & EZXML_TXTM) free(xml->txt); /* existing txt was malloced */
922      xml->flags &= ~EZXML_TXTM;
923      xml->txt = (char *)txt;
924      return xml;
925   }
926  
927 < // Sets the given tag attribute or adds a new attribute if not found. A value
928 < // of NULL will remove the specified attribute. Returns the tag given.
927 > /* Sets the given tag attribute or adds a new attribute if not found. A value */
928 > /* of NULL will remove the specified attribute. Returns the tag given. */
929   ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value)
930   {
931      int l = 0, c;
932  
933      if (! xml) return NULL;
934      while (xml->attr[l] && strcmp(xml->attr[l], name)) l += 2;
935 <    if (! xml->attr[l]) { // not found, add as new attribute
936 <        if (! value) return xml; // nothing to do
937 <        if (xml->attr == EZXML_NIL) { // first attribute
935 >    if (! xml->attr[l]) { /* not found, add as new attribute */
936 >        if (! value) return xml; /* nothing to do */
937 >        if (xml->attr == EZXML_NIL) { /* first attribute */
938              xml->attr = malloc(4 * sizeof(char *));
939 <            xml->attr[1] = strdup(""); // empty list of malloced names/vals
939 >            xml->attr[1] = strdup(""); /* empty list of malloced names/vals */
940          }
941          else xml->attr = realloc(xml->attr, (l + 4) * sizeof(char *));
942  
943 <        xml->attr[l] = (char *)name; // set attribute name
944 <        xml->attr[l + 2] = NULL; // null terminate attribute list
943 >        xml->attr[l] = (char *)name; /* set attribute name */
944 >        xml->attr[l + 2] = NULL; /* null terminate attribute list */
945          xml->attr[l + 3] = realloc(xml->attr[l + 1],
946                                     (c = strlen(xml->attr[l + 1])) + 2);
947 <        strcpy(xml->attr[l + 3] + c, " "); // set name/value as not malloced
947 >        strcpy(xml->attr[l + 3] + c, " "); /* set name/value as not malloced */
948          if (xml->flags & EZXML_DUP) xml->attr[l + 3][c] = EZXML_NAMEM;
949      }
950 <    else if (xml->flags & EZXML_DUP) free((char *)name); // name was strduped
950 >    else if (xml->flags & EZXML_DUP) free((char *)name); /* name was strduped */
951  
952 <    for (c = l; xml->attr[c]; c += 2); // find end of attribute list
953 <    if (xml->attr[c + 1][l / 2] & EZXML_TXTM) free(xml->attr[l + 1]); //old val
952 >    for (c = l; xml->attr[c]; c += 2); /* find end of attribute list */
953 >    if (xml->attr[c + 1][l / 2] & EZXML_TXTM) free(xml->attr[l + 1]); /*old val */
954      if (xml->flags & EZXML_DUP) xml->attr[c + 1][l / 2] |= EZXML_TXTM;
955      else xml->attr[c + 1][l / 2] &= ~EZXML_TXTM;
956  
957 <    if (value) xml->attr[l + 1] = (char *)value; // set attribute value
958 <    else { // remove attribute
957 >    if (value) xml->attr[l + 1] = (char *)value; /* set attribute value */
958 >    else { /* remove attribute */
959          if (xml->attr[c + 1][l / 2] & EZXML_NAMEM) free(xml->attr[l]);
960          memmove(xml->attr + l, xml->attr + l + 2, (c - l + 2) * sizeof(char*));
961          xml->attr = realloc(xml->attr, (c + 2) * sizeof(char *));
962          memmove(xml->attr[c + 1] + (l / 2), xml->attr[c + 1] + (l / 2) + 1,
963 <                (c / 2) - (l / 2)); // fix list of which name/vals are malloced
963 >                (c / 2) - (l / 2)); /* fix list of which name/vals are malloced */
964      }
965 <    xml->flags &= ~EZXML_DUP; // clear strdup() flag
965 >    xml->flags &= ~EZXML_DUP; /* clear strdup() flag */
966      return xml;
967   }
968  
969 < // sets a flag for the given tag and returns the tag
969 > /* sets a flag for the given tag and returns the tag */
970   ezxml_t ezxml_set_flag(ezxml_t xml, short flag)
971   {
972      if (xml) xml->flags |= flag;
973      return xml;
974   }
975  
976 < // removes a tag along with its subtags without freeing its memory
976 > /* removes a tag along with its subtags without freeing its memory */
977   ezxml_t ezxml_cut(ezxml_t xml)
978   {
979      ezxml_t cur;
980  
981 <    if (! xml) return NULL; // nothing to do
982 <    if (xml->next) xml->next->sibling = xml->sibling; // patch sibling list
981 >    if (! xml) return NULL; /* nothing to do */
982 >    if (xml->next) xml->next->sibling = xml->sibling; /* patch sibling list */
983  
984 <    if (xml->parent) { // not root tag
985 <        cur = xml->parent->child; // find head of subtag list
986 <        if (cur == xml) xml->parent->child = xml->ordered; // first subtag
987 <        else { // not first subtag
984 >    if (xml->parent) { /* not root tag */
985 >        cur = xml->parent->child; /* find head of subtag list */
986 >        if (cur == xml) xml->parent->child = xml->ordered; /* first subtag */
987 >        else { /* not first subtag */
988              while (cur->ordered != xml) cur = cur->ordered;
989 <            cur->ordered = cur->ordered->ordered; // patch ordered list
989 >            cur->ordered = cur->ordered->ordered; /* patch ordered list */
990  
991 <            cur = xml->parent->child; // go back to head of subtag list
992 <            if (strcmp(cur->name, xml->name)) { // not in first sibling list
991 >            cur = xml->parent->child; /* go back to head of subtag list */
992 >            if (strcmp(cur->name, xml->name)) { /* not in first sibling list */
993                  while (strcmp(cur->sibling->name, xml->name))
994                      cur = cur->sibling;
995 <                if (cur->sibling == xml) { // first of a sibling list
995 >                if (cur->sibling == xml) { /* first of a sibling list */
996                      cur->sibling = (xml->next) ? xml->next
997                                                 : cur->sibling->sibling;
998                  }
999 <                else cur = cur->sibling; // not first of a sibling list
999 >                else cur = cur->sibling; /* not first of a sibling list */
1000              }
1001  
1002              while (cur->next && cur->next != xml) cur = cur->next;
1003 <            if (cur->next) cur->next = cur->next->next; // patch next list
1003 >            if (cur->next) cur->next = cur->next->next; /* patch next list */
1004          }        
1005      }
1006      xml->ordered = xml->sibling = xml->next = NULL;
1007      return xml;
1008   }
1009  
1010 < #ifdef EZXML_TEST // test harness
1010 > #ifdef EZXML_TEST /* test harness */
1011   int main(int argc, char **argv)
1012   {
1013      ezxml_t xml;
# Line 1015 | Line 1023 | int main(int argc, char **argv)
1023      ezxml_free(xml);
1024      return (i) ? 1 : 0;
1025   }
1026 < #endif // EZXML_TEST
1026 > #endif /* EZXML_TEST */

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines