]> git.ozlabs.org Git - ccan/commitdiff
ttxml: new module.
authorRusty Russell <rusty@rustcorp.com.au>
Fri, 20 May 2011 07:12:45 +0000 (16:42 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Fri, 20 May 2011 07:42:06 +0000 (17:12 +0930)
ccan/ttxml/LICENSE [new symlink]
ccan/ttxml/_info [new file with mode: 0644]
ccan/ttxml/ttxml.c [new file with mode: 0644]
ccan/ttxml/ttxml.h [new file with mode: 0644]

diff --git a/ccan/ttxml/LICENSE b/ccan/ttxml/LICENSE
new file mode 120000 (symlink)
index 0000000..190cfd5
--- /dev/null
@@ -0,0 +1 @@
+../../licenses/GPL-3
\ No newline at end of file
diff --git a/ccan/ttxml/_info b/ccan/ttxml/_info
new file mode 100644 (file)
index 0000000..9bf0ddb
--- /dev/null
@@ -0,0 +1,23 @@
+#include <string.h>
+#include "config.h"
+
+/**
+ * ttxml - tiny XML library for parsing (trusted!) XML documents.
+ *
+ * This parses an XML file into a convenient data structure.
+ *
+ * License: GPL
+ * Author: Daniel Burke <dan.p.burke@gmail.com>
+ */
+int main(int argc, char *argv[])
+{
+       /* Expect exactly one argument */
+       if (argc != 2)
+               return 1;
+
+       if (strcmp(argv[1], "depends") == 0) {
+               return 0;
+       }
+
+       return 1;
+}
diff --git a/ccan/ttxml/ttxml.c b/ccan/ttxml/ttxml.c
new file mode 100644 (file)
index 0000000..e362ed2
--- /dev/null
@@ -0,0 +1,393 @@
+\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
diff --git a/ccan/ttxml/ttxml.h b/ccan/ttxml/ttxml.h
new file mode 100644 (file)
index 0000000..0b8c156
--- /dev/null
@@ -0,0 +1,16 @@
+
+typedef struct XmlNode {
+       char * name;
+       char ** attrib;
+       int nattrib;
+       struct XmlNode * child;
+       struct XmlNode * next;
+} XmlNode;
+
+
+XmlNode* xml_new(char * name, char * attrib);
+XmlNode* xml_load(const char * filename);
+void xml_free(XmlNode *target);
+char* xml_attr(XmlNode *x, const char *name);
+XmlNode * xml_find(XmlNode *xml, const char *name);
+