+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <stdio.h>\r
+\r
+#include "ttxml.h"\r
+\r
+\r
+XmlNode* xml_new(char * name, char * attrib)\r
+{\r
+ XmlNode * ret = malloc(sizeof(XmlNode));\r
+ if(!ret)return NULL;\r
+\r
+ ret->attrib = NULL;\r
+ ret->nattrib = 0;\r
+ ret->child = ret->next = NULL;\r
+\r
+ ret->name = name;\r
+ return ret;\r
+}\r
+\r
+\r
+void xml_free(XmlNode *target)\r
+{\r
+ int i;\r
+ for(i=0; i<target->nattrib*2; i++)\r
+ if(target->attrib[i])\r
+ free(target->attrib[i]);\r
+\r
+ if(target->attrib)free(target->attrib);\r
+ if(target->child)xml_free(target->child);\r
+ if(target->next)xml_free(target->next);\r
+ free(target->name);\r
+ free(target);\r
+}\r
+\r
+#define XML_LETTER 1\r
+#define XML_NUMBER 2\r
+#define XML_SPACE 4\r
+#define XML_SLASH 8\r
+#define XML_OPEN 16\r
+#define XML_EQUALS 32\r
+#define XML_CLOSE 64\r
+#define XML_QUOTE 128\r
+#define XML_OTHER 256\r
+\r
+#define XML_ALL 0xFFFFFFFF\r
+\r
+static int is_special(char item)\r
+{\r
+ if((item >= 'a' && item <= 'z') || (item >= 'A' && item <='Z'))\r
+ return XML_LETTER;\r
+ if( item >= '0' && item <='9' )\r
+ return XML_NUMBER;\r
+ if( item == 0x20 || item == '\t' || item == 0x0D || item == 0x0A )\r
+ return XML_SPACE;\r
+ if( item == '/' )\r
+ return XML_SLASH;\r
+ if( item == '<' )\r
+ return XML_OPEN;\r
+ if( item == '=' )\r
+ return XML_EQUALS;\r
+ if( item == '>' )\r
+ return XML_CLOSE;\r
+ if( item == '"' || item == '\'' )\r
+ return XML_QUOTE;\r
+ return 128;\r
+}\r
+\r
+struct XMLBUF\r
+{\r
+ FILE * fptr;\r
+ char * buf;\r
+ int len;\r
+ int eof;\r
+};\r
+\r
+\r
+static void xml_consume(struct XMLBUF *xml, int offset)\r
+{\r
+ int size, request, received;\r
+ \r
+ size = xml->len - offset;\r
+\r
+ if(!xml->len)\r
+ return;\r
+\r
+ if(size)\r
+ {\r
+// printf("Size=%d, off=%d, len=%d\n", size, offset, xml->len);\r
+ memmove(xml->buf, xml->buf + offset, size);\r
+ }\r
+\r
+ if(xml->eof)\r
+ {\r
+ xml->len = size;\r
+ xml->buf[size]=0;\r
+ return;\r
+ }\r
+\r
+ request = xml->len - size;\r
+ received = fread(xml->buf + size, 1, request, xml->fptr);\r
+ if( received == request )\r
+ return;\r
+\r
+ xml->len = size + received;\r
+ xml->eof = 1;\r
+ xml->buf[xml->len] = 0;\r
+ return;\r
+}\r
+\r
+\r
+static void xml_skip( struct XMLBUF *xml, int mask )\r
+{\r
+ int offset = 0;\r
+ if(!xml->len)return;\r
+ while( is_special(xml->buf[offset]) & mask )\r
+ {\r
+ offset ++;\r
+ if(offset == xml->len)\r
+ {\r
+ xml_consume(xml, offset);\r
+ offset = 0;\r
+ if(!xml->len)\r
+ return;\r
+ }\r
+ }\r
+ xml_consume(xml, offset);\r
+}\r
+\r
+static char quotechar = 0;\r
+static int test_quote(const char x)\r
+{\r
+ static int escaped=0;\r
+ if( escaped || '\\' == x )\r
+ {\r
+ escaped = !escaped;\r
+ return 1;\r
+ }\r
+ if( x != quotechar )\r
+ return 1;\r
+ return 0;\r
+}\r
+\r
+static int feed_mask = 0;\r
+static int test_mask(const char x)\r
+{\r
+ return !(is_special(x) & feed_mask);\r
+}\r
+\r
+static char* xml_feed( struct XMLBUF *xml, int (*test)(char) )\r
+{\r
+ int offset = 0;\r
+ char *ret = NULL;\r
+ int size = 0;\r
+\r
+ while( test(xml->buf[offset]) )\r
+ {\r
+ offset++;\r
+ if(offset == xml->len)\r
+ {\r
+ ret = realloc(ret, size+offset+1);\r
+ memcpy(ret+size, xml->buf, offset);\r
+ size += offset;\r
+ ret[size]=0;\r
+ xml_consume(xml, offset);\r
+ offset = 0;\r
+ if(!xml->len)return ret;\r
+ }\r
+ }\r
+\r
+ if(offset)\r
+ {\r
+ ret = realloc(ret, size+offset+1);\r
+ memcpy(ret+size, xml->buf, offset);\r
+ size += offset;\r
+ ret[size]=0;\r
+ xml_consume(xml, offset);\r
+ }\r
+ return ret;\r
+}\r
+\r
+static void xml_read_attr(struct XMLBUF *xml, XmlNode *node)\r
+{\r
+ int n=0;\r
+\r
+ // how does this tag finish?\r
+ while(xml->len)\r
+ {\r
+ if( is_special(xml->buf[0]) & (XML_CLOSE | XML_SLASH) )\r
+ return;\r
+\r
+ n = ++node->nattrib;\r
+ node->attrib = realloc(node->attrib, n * 2 * sizeof(char*) );\r
+ node->attrib[--n*2+1] = 0;\r
+ \r
+ feed_mask = XML_EQUALS | XML_SPACE | XML_CLOSE | XML_SLASH;\r
+ node->attrib[n*2] = xml_feed(xml, test_mask );\r
+ if( xml->buf[0] == '=' )\r
+ {\r
+ if( is_special(xml->buf[1]) & XML_QUOTE )\r
+ {\r
+ quotechar = xml->buf[1];\r
+ xml_consume(xml, 2);\r
+ node->attrib[n*2+1] = xml_feed(xml, test_quote);\r
+ xml_consume(xml, 1);\r
+ }\r
+ else\r
+ {\r
+ feed_mask = XML_SPACE | XML_CLOSE | XML_SLASH;\r
+ xml_consume(xml, 1);\r
+ node->attrib[n*2+1] = xml_feed(xml, test_mask);\r
+ }\r
+ }\r
+ xml_skip(xml, XML_SPACE);\r
+ }\r
+}\r
+\r
+static XmlNode* xml_parse(struct XMLBUF *xml)\r
+{\r
+ int offset;\r
+ int toff;\r
+ char *tmp;\r
+ XmlNode **this, *ret = NULL;\r
+ \r
+ this = &ret;\r
+\r
+ xml_skip(xml, XML_SPACE); // skip whitespace\r
+ offset=0;\r
+ while(xml->len)\r
+ {\r
+ switch(is_special(xml->buf[offset]))\r
+ {\r
+ case XML_OPEN:\r
+ xml_consume(xml, 1);\r
+ if(xml->buf[offset] == '/')\r
+ return ret; // parents close tag\r
+ // read the tag name\r
+ feed_mask = XML_SPACE | XML_SLASH | XML_CLOSE;\r
+ *this = xml_new( xml_feed(xml, test_mask), NULL );\r
+ xml_skip(xml, XML_SPACE); // skip any whitespace\r
+\r
+ xml_read_attr(xml, *this); // read attributes\r
+\r
+ // how does this tag finish?\r
+ switch(is_special(xml->buf[0]))\r
+ {\r
+ case XML_CLOSE: // child-nodes ahead\r
+ xml_consume(xml, 1);\r
+ (*this)->child = xml_parse(xml);\r
+ xml_skip(xml, XML_ALL ^ XML_CLOSE);\r
+ xml_consume(xml, 1);\r
+ break;\r
+ case XML_SLASH: // self closing tag\r
+ xml_consume(xml, 2);\r
+ break;\r
+ }\r
+ break;\r
+\r
+ default: // text node\r
+ *this = xml_new(0, 0);\r
+ xml_skip(xml, XML_SPACE); // skip any whitespace\r
+ feed_mask = XML_OPEN;\r
+ (*this)->nattrib=1;\r
+ (*this)->attrib = malloc(sizeof(char*)*2);\r
+ tmp = (*this)->attrib[0] = xml_feed(xml, test_mask);\r
+ toff = strlen(tmp)-1;\r
+ while( ( is_special(tmp[toff]) & XML_SPACE ) )\r
+ {\r
+ tmp[toff] = 0;\r
+ toff --;\r
+ }\r
+\r
+ (*this)->attrib[1] = NULL;\r
+ break;\r
+ }\r
+ this = &(*this)->next; \r
+ xml_skip(xml, XML_SPACE); // skip whitespace\r
+ } \r
+\r
+ return ret;\r
+}\r
+\r
+\r
+\r
+#define BUF 3264\r
+XmlNode* xml_load(const char * filename)\r
+{\r
+ struct XMLBUF xml;\r
+ XmlNode *ret = NULL;\r
+\r
+ xml.eof = 0;\r
+ xml.fptr = fopen(filename, "rb");\r
+ if(!xml.fptr)\r
+ {\r
+ printf("Opening file failed\n");\r
+ return NULL;\r
+ }\r
+\r
+ xml.buf = malloc(BUF);\r
+ if(!xml.buf)\r
+ goto xml_load_fail_malloc_buf;\r
+ \r
+ xml.len = fread(xml.buf, 1, BUF, xml.fptr);\r
+ if(xml.len < BUF)\r
+ xml.eof = 1;\r
+\r
+ ret = xml_parse(&xml);\r
+\r
+ free(xml.buf);\r
+xml_load_fail_malloc_buf:\r
+ fclose(xml.fptr);\r
+ return ret;\r
+}\r
+#undef BUF\r
+\r
+XmlNode * xml_find(XmlNode *xml, const char *name)\r
+{\r
+ XmlNode * ret;\r
+ if(xml->name)if(!strcmp(xml->name, name))return xml;\r
+ if(xml->child)\r
+ {\r
+ ret = xml_find(xml->child, name);\r
+ if(ret)return ret;\r
+ }\r
+ if(xml->next)\r
+ {\r
+ ret = xml_find(xml->next, name);\r
+ if(ret)return ret;\r
+ }\r
+ return NULL;\r
+}\r
+\r
+\r
+char* xml_attr(XmlNode *x, const char *name)\r
+{\r
+ int i;\r
+ for(i=0; i<x->nattrib; i++)\r
+ if(x->attrib[i*2])\r
+ if(!strcmp(x->attrib[i*2], name))\r
+ return x->attrib[i*2+1];\r
+ return 0;\r
+}\r
+\r
+\r
+#ifdef TEST\r
+void xp(XmlNode *x, int level, int max)\r
+{\r
+ int i;\r
+ char text[] = "text";\r
+ char *name = text;\r
+ if(level > max)return;\r
+ if(!x)return;\r
+ if(x->name)name = x->name;\r
+ for(i=0; i<level; i++)printf(" ");\r
+ printf("%s:", name);\r
+ if(x->name)\r
+ for(i=0; i<x->nattrib; i++)\r
+ printf("%s=\"%s\",", x->attrib[i*2], x->attrib[i*2+1]);\r
+ printf("\n");\r
+ if(x->child)xp(x->child, level+1, max);\r
+ if(x->next)xp(x->next, level, max);\r
+}\r
+\r
+\r
+int main(int argc, char *argv[])\r
+{\r
+ XmlNode *x;\r
+\r
+ if(!argv[1])\r
+ {\r
+ printf("USAGE: %s name\n\t reads name where name is an XML file.\n",\r
+ argv[0]);\r
+ return 1;\r
+ }\r
+\r
+ printf("Loading file \"%s\"\n", argv[1]);\r
+\r
+ x = xml_load(argv[1]);\r
+\r
+ if(!x)\r
+ {\r
+ printf("Failed to load.\n");\r
+ return 2;\r
+ }\r
+\r
+ xp(x, 1, 6);\r
+ xml_free(x);\r
+ printf("Happily free.\n");\r
+ return 0;\r
+}\r
+#endif\r
+\r