9 XmlNode* xml_new(char * name, char * attrib)
\r
11 XmlNode * ret = malloc(sizeof(XmlNode));
\r
12 if(!ret)return NULL;
\r
16 ret->child = ret->next = NULL;
\r
23 void xml_free(XmlNode *target)
\r
26 for(i=0; i<target->nattrib*2; i++)
\r
27 if(target->attrib[i])
\r
28 free(target->attrib[i]);
\r
30 if(target->attrib)free(target->attrib);
\r
31 if(target->child)xml_free(target->child);
\r
32 if(target->next)xml_free(target->next);
\r
37 #define XML_LETTER 1
\r
38 #define XML_NUMBER 2
\r
42 #define XML_EQUALS 32
\r
43 #define XML_CLOSE 64
\r
44 #define XML_QUOTE 128
\r
45 #define XML_OTHER 256
\r
47 #define XML_ALL 0xFFFFFFFF
\r
49 static int is_special(char item)
\r
51 if((item >= 'a' && item <= 'z') || (item >= 'A' && item <='Z'))
\r
53 if( item >= '0' && item <='9' )
\r
55 if( item == 0x20 || item == '\t' || item == 0x0D || item == 0x0A )
\r
65 if( item == '"' || item == '\'' )
\r
79 static void xml_consume(struct XMLBUF *xml, int offset)
\r
81 int size, request, received;
\r
83 size = xml->len - offset;
\r
90 // printf("Size=%d, off=%d, len=%d\n", size, offset, xml->len);
\r
91 memmove(xml->buf, xml->buf + offset, size);
\r
101 request = xml->len - size;
\r
102 received = fread(xml->buf + size, 1, request, xml->fptr);
\r
103 if( received == request )
\r
106 xml->len = size + received;
\r
108 xml->buf[xml->len] = 0;
\r
113 static void xml_skip( struct XMLBUF *xml, int mask )
\r
116 if(!xml->len)return;
\r
117 while( is_special(xml->buf[offset]) & mask )
\r
120 if(offset == xml->len)
\r
122 xml_consume(xml, offset);
\r
128 xml_consume(xml, offset);
\r
131 static char quotechar = 0;
\r
132 static int test_quote(const char x)
\r
134 static int escaped=0;
\r
135 if( escaped || '\\' == x )
\r
137 escaped = !escaped;
\r
140 if( x != quotechar )
\r
145 static int feed_mask = 0;
\r
146 static int test_mask(const char x)
\r
148 return !(is_special(x) & feed_mask);
\r
151 static char* xml_feed( struct XMLBUF *xml, int (*test)(char) )
\r
157 while( test(xml->buf[offset]) )
\r
160 if(offset == xml->len)
\r
162 ret = realloc(ret, size+offset+1);
\r
163 memcpy(ret+size, xml->buf, offset);
\r
166 xml_consume(xml, offset);
\r
168 if(!xml->len)return ret;
\r
174 ret = realloc(ret, size+offset+1);
\r
175 memcpy(ret+size, xml->buf, offset);
\r
178 xml_consume(xml, offset);
\r
183 static void xml_read_attr(struct XMLBUF *xml, XmlNode *node)
\r
187 // how does this tag finish?
\r
190 if( is_special(xml->buf[0]) & (XML_CLOSE | XML_SLASH) )
\r
193 n = ++node->nattrib;
\r
194 node->attrib = realloc(node->attrib, n * 2 * sizeof(char*) );
\r
195 node->attrib[--n*2+1] = 0;
\r
197 feed_mask = XML_EQUALS | XML_SPACE | XML_CLOSE | XML_SLASH;
\r
198 node->attrib[n*2] = xml_feed(xml, test_mask );
\r
199 if( xml->buf[0] == '=' )
\r
201 if( is_special(xml->buf[1]) & XML_QUOTE )
\r
203 quotechar = xml->buf[1];
\r
204 xml_consume(xml, 2);
\r
205 node->attrib[n*2+1] = xml_feed(xml, test_quote);
\r
206 xml_consume(xml, 1);
\r
210 feed_mask = XML_SPACE | XML_CLOSE | XML_SLASH;
\r
211 xml_consume(xml, 1);
\r
212 node->attrib[n*2+1] = xml_feed(xml, test_mask);
\r
215 xml_skip(xml, XML_SPACE);
\r
219 static XmlNode* xml_parse(struct XMLBUF *xml)
\r
224 XmlNode **this, *ret = NULL;
\r
228 xml_skip(xml, XML_SPACE); // skip whitespace
\r
232 switch(is_special(xml->buf[offset]))
\r
235 xml_consume(xml, 1);
\r
236 if(xml->buf[offset] == '/')
\r
237 return ret; // parents close tag
\r
238 // read the tag name
\r
239 feed_mask = XML_SPACE | XML_SLASH | XML_CLOSE;
\r
240 *this = xml_new( xml_feed(xml, test_mask), NULL );
\r
241 xml_skip(xml, XML_SPACE); // skip any whitespace
\r
243 xml_read_attr(xml, *this); // read attributes
\r
245 // how does this tag finish?
\r
246 switch(is_special(xml->buf[0]))
\r
248 case XML_CLOSE: // child-nodes ahead
\r
249 xml_consume(xml, 1);
\r
250 (*this)->child = xml_parse(xml);
\r
251 xml_skip(xml, XML_ALL ^ XML_CLOSE);
\r
252 xml_consume(xml, 1);
\r
254 case XML_SLASH: // self closing tag
\r
255 xml_consume(xml, 2);
\r
260 default: // text node
\r
261 *this = xml_new(0, 0);
\r
262 xml_skip(xml, XML_SPACE); // skip any whitespace
\r
263 feed_mask = XML_OPEN;
\r
264 (*this)->nattrib=1;
\r
265 (*this)->attrib = malloc(sizeof(char*)*2);
\r
266 tmp = (*this)->attrib[0] = xml_feed(xml, test_mask);
\r
267 toff = strlen(tmp)-1;
\r
268 while( ( is_special(tmp[toff]) & XML_SPACE ) )
\r
274 (*this)->attrib[1] = NULL;
\r
277 this = &(*this)->next;
\r
278 xml_skip(xml, XML_SPACE); // skip whitespace
\r
287 XmlNode* xml_load(const char * filename)
\r
290 XmlNode *ret = NULL;
\r
293 xml.fptr = fopen(filename, "rb");
\r
296 printf("Opening file failed\n");
\r
300 xml.buf = malloc(BUF);
\r
302 goto xml_load_fail_malloc_buf;
\r
304 xml.len = fread(xml.buf, 1, BUF, xml.fptr);
\r
308 ret = xml_parse(&xml);
\r
311 xml_load_fail_malloc_buf:
\r
317 XmlNode * xml_find(XmlNode *xml, const char *name)
\r
320 if(xml->name)if(!strcmp(xml->name, name))return xml;
\r
323 ret = xml_find(xml->child, name);
\r
328 ret = xml_find(xml->next, name);
\r
335 char* xml_attr(XmlNode *x, const char *name)
\r
338 for(i=0; i<x->nattrib; i++)
\r
340 if(!strcmp(x->attrib[i*2], name))
\r
341 return x->attrib[i*2+1];
\r
347 void xp(XmlNode *x, int level, int max)
\r
350 char text[] = "text";
\r
352 if(level > max)return;
\r
354 if(x->name)name = x->name;
\r
355 for(i=0; i<level; i++)printf(" ");
\r
356 printf("%s:", name);
\r
358 for(i=0; i<x->nattrib; i++)
\r
359 printf("%s=\"%s\",", x->attrib[i*2], x->attrib[i*2+1]);
\r
361 if(x->child)xp(x->child, level+1, max);
\r
362 if(x->next)xp(x->next, level, max);
\r
366 int main(int argc, char *argv[])
\r
372 printf("USAGE: %s name\n\t reads name where name is an XML file.\n",
\r
377 printf("Loading file \"%s\"\n", argv[1]);
\r
379 x = xml_load(argv[1]);
\r
383 printf("Failed to load.\n");
\r
389 printf("Happily free.\n");
\r