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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines