@@ -1,488 +1,29 @@
2−#include "../cbits/hexml.h"
6#include <stdio.h>
2#include <stdio.h>
8−/////////////////////////////////////////////////////////////////////
5+#define parse_table hexml_parse_table
9−// TYPES
6+#define parser hexml_parser
11−static inline int end(str s) { return s.start + s.length; }
8+#define abort(x) return x
9+#define NameStart printf("NameStart %s\n", p)
10+#define NameEnd printf("NameEnd %s\n", p)
11+#define QuoteStart printf("QuoteStart %s\n", p)
12+#define QuoteEnd printf("QuoteEnd %s\n", p)
13+#define AttribsStart printf("AttribsStart %s\n", p)
14+#define AttribsEnd printf("AttribsEnd %s\n", p)
15+#define Tag printf("Tag %s\n", p)
16+#define hexml_Tag printf("Tag %s\n", p)
17+#define TagComment printf("TagComment %s\n", p)
18+#define TagOpen printf("TagOpen %s\n", p)
19+#define TagClose printf("TagClose %s\n", p)
20+#define TagOpenClose printf("TagOpenClose %s\n", p)
13−static inline str start_length(int32_t start, int32_t length)
22+#include "test.h"
15− assert(start >= 0 && length >= 0);
22−static inline str start_end(int32_t start, int32_t end)
24− return start_length(start, end - start);
31− attr* attrs; // dynamically allocated buffer
32− attr* alloc; // what to call free on
37− // have a cursor at the front, which is all the stuff I have written out, final
38− // have a cursor at the end, which is stack scoped, so children write out, then I do
39− // when you commit, you copy over from end to front
43− int used_front; // front entries, stored for good
44− int used_back; // back entries, stack based, copied into front on </close>
45− // back entries which haven't yet been closed have nodes.length == -1
46− node* nodes; // dynamically allocated buffer
47− node* alloc; // what to call free on
53− const char* body; // pointer to initial argument, not owned by us
54− int body_len; // length of the body
62−/////////////////////////////////////////////////////////////////////
67− const document* d; // Document, used to get at the body
68− char* buffer; // Buffer we are writing too
69− int length; // Length of buffer, do not write past the end.
70− // No character is reserved for a NULL terminator.
71− int cursor; // Cursor of where we are writing now
74−static inline void render_char(render* r, char c)
76− if (r->cursor < r->length)
77− r->buffer[r->cursor] = c;
81−static inline void bound(int idx, int mn, int mx)
83− assert(idx >= mn && idx <= mx);
86−static inline void bound_str(str s, int mn, int mx)
88− assert(s.length >= 0);
89− bound(s.start, mn, mx);
90− bound(end(s), mn, mx);
93−static void render_str(render* r, str s)
95− bound_str(s, 0, r->d->body_len);
96− for (int i = 0; i < s.length; i++)
97− render_char(r, r->d->body[s.start + i]);
100−static void render_tag(render* r, const node* n);
102−static void render_content(render* r, const node* n)
104− bound_str(n->inner, 0, r->d->body_len);
105− bound_str(n->nodes, 0, r->d->nodes.used_front);
106− bound_str(n->attrs, 0, r->d->attrs.used);
108− int done = n->inner.start;
109− for (int i = 0; i < n->nodes.length; i++)
111− node* x = &r->d->nodes.nodes[n->nodes.start + i];
112− render_str(r, start_end(done, x->outer.start));
113− done = end(x->outer);
116− render_str(r, start_end(done, end(n->inner)));
119−static void render_tag(render* r, const node* n)
121− render_char(r, '<');
122− render_str(r, n->name);
123− for (int i = 0; i < n->attrs.length; i++)
125− attr* x = &r->d->attrs.attrs[n->attrs.start + i];
126− render_char(r, ' ');
127− render_str(r, x->name);
128− render_char(r, '=');
129− render_char(r, '\"');
130− render_str(r, x->value);
131− render_char(r, '\"');
133− render_char(r, '>');
134− render_content(r, n);
135− render_char(r, '<');
136− render_char(r, '/');
137− render_str(r, n->name);
138− render_char(r, '>');
141−int hexml_node_render(const document* d, const node* n, char* buffer, int length)
148− // The root node (and only the root node) has an empty length, so just render its innards
149− if (n->name.length == 0)
150− render_content(&r, n);
157−/////////////////////////////////////////////////////////////////////
160−char* hexml_document_error(const document* d){return d->error_message;}
161−node* hexml_document_node(const document* d){return &d->nodes.nodes[0];}
163−void hexml_document_free(document* d)
165− free(d->error_message);
166− free(d->nodes.alloc);
167− free(d->attrs.alloc);
171−node* hexml_node_children(const document* d, const node* n, int* res)
173− *res = n->nodes.length;
174− return &d->nodes.nodes[n->nodes.start];
177−attr* hexml_node_attributes(const document* d, const node* n, int* res)
179− *res = n->attrs.length;
180− return &d->attrs.attrs[n->attrs.start];
183−attr* hexml_node_attribute(const document* d, const node* n, const char* s, int slen)
185− if (slen == -1) slen = (int) strlen(s);
186− const int limit = end(n->attrs);
187− for (int i = n->attrs.start; i < limit; i++)
189− attr* r = &d->attrs.attrs[i];
190− if (r->name.length == slen && memcmp(s, &d->body[r->name.start], slen) == 0)
196−// Search for given strings within a node
197−node* hexml_node_child(const document* d, const node* parent, const node* prev, const char* s, int slen)
199− if (slen == -1) slen = (int) strlen(s);
200− int i = prev == NULL ? parent->nodes.start : (int) (prev + 1 - d->nodes.nodes);
201− const int limit = end(parent->nodes);
202− for (; i < limit; i++)
204− node* r = &d->nodes.nodes[i];
205− if (r->name.length == slen && memcmp(s, &d->body[r->name.start], slen) == 0)
211−/////////////////////////////////////////////////////////////////////
214−static inline node* node_alloc(node_buffer* b)
216− int space = b->size - b->used_back - b->used_front;
219− int size2 = (b->size + 1000) * 2;
220− node* buf2 = malloc(size2 * sizeof(node));
222− memcpy(buf2, b->nodes, b->used_front * sizeof(node));
223− memcpy(&buf2[size2 - b->used_back], &b->nodes[b->size - b->used_back], b->used_back * sizeof(node));
230− return &b->nodes[b->size - b->used_back];
233−// buffer[from .. from+n] = reverse (buffer[from .. from+n])
234−// The ranges completely overlap
235−static inline void reverse(node* buffer, int from, int n)
237− for (int to = from + n - 1; to > from; from++, to--)
239− node temp = buffer[to];
240− buffer[to] = buffer[from];
241− buffer[from] = temp;
245−// buffer[to .. to+n] = reverse (buffer[from .. from+n])
246−// The ranges may not overlap
247−static inline void memcpy_reverse(node* buffer, int from, int to, int n)
249− int end = from + n - 1;
250− for (int i = 0; i < n; i++)
251− buffer[to+i] = buffer[end-i];
254−// buffer[to .. to+n] = reverse (buffer[from .. from+n])
255−// The ranges may overlap
256−static inline void memmove_reverse(node* buffer, int from, int to, int n)
258− assert(from >= to); // always the case in my usages
260− memcpy_reverse(buffer, from, to, n);
263− int overlap = from - to;
264− memcpy_reverse(buffer, from, to + n - overlap, overlap);
265− reverse(buffer, to, n - overlap);
269−static inline str node_commit(node_buffer* b)
271− // first search for an "open" node (nodes.length == -1)
273− for (open = b->size - b->used_back; open < b->size; open++)
275− if (b->nodes[open].nodes.length == -1)
279− int n = open - (b->size - b->used_back);
280− memmove_reverse(b->nodes, b->size - b->used_back, b->used_front, n);
283− return start_length(b->used_front - n, n);
286−static inline attr* attr_alloc(attr_buffer* b)
288− // Ensure there is at least one node left
289− int space = b->size - b->used;
292− int size2 = (b->size + 1000) * 2;
293− attr* buf2 = malloc(size2 * sizeof(attr));
295− memcpy(buf2, b->attrs, b->used * sizeof(attr));
302− return &b->attrs[b->used - 1];
305−static void set_error(document* d, const char* msg)
307− if (d->error_message != NULL) return; // keep the first error message
308− d->error_message = malloc(strlen(msg)+1);
309− assert(d->error_message);
310− strcpy(d->error_message, msg);
313−static inline str gap(const char* ref, const char* start, const char* end)
315− return start_end(start - ref, end - ref);
318−#define P_Abort(x) return x
319−#define P_Tag tag_start = p;
320−#define P_NameStart name_start = p
321−#define P_NameEnd name_end = p
322−#define P_AttribsStart \
323− me = node_alloc(&d->nodes); \
324− me->attrs.start = d->attrs.used; \
325− me->name = gap(d->body, name_start, name_end);
326−#define P_AttribsEnd \
327− me->attrs = start_end(me->attrs.start, d->attrs.used);
328−#define P_QuoteStart quote_start = p
330− attr* attr = attr_alloc(&d->attrs); \
331− attr->name = gap(d->body, name_start, name_end); \
332− attr->value = gap(d->body, quote_start, p);
333−#define P_TagComment \
334− // No action required - comments just flow as normal text
336− me->nodes.length = -1; \
337− me->inner = gap(d->body, p, p); \
338− me->outer = gap(d->body, tag_start, tag_start);
340− str nodes = node_commit(&d->nodes); \
341− if (d->nodes.used_back == 0) \
342− return "Closing tag with no openning"; \
343− me = &d->nodes.nodes[d->nodes.size - d->nodes.used_back]; \
344− me->nodes = nodes; \
345− if (me->name.length != gap(d->body, name_start, name_end).length || \
346− memcmp(&d->body[me->name.start], name_start, me->name.length) != 0) \
347− return "Mismatch in closing tag"; \
348− me->inner = gap(d->body, &d->body[me->inner.start], tag_start); \
349− me->outer = gap(d->body, &d->body[me->outer.start], p);
350−#define P_TagOpenClose \
351− me->nodes = start_end(0, 0); \
352− me->inner = gap(d->body, p, p); \
353− me->outer = gap(d->body, tag_start, p);
355−// Given the parsed string, return either NULL (success) or an error message (failure)
356−static const char* parser(const char* p, document* d)
358− const char *tag_start; // Where the tag starts [<foo
359− const char *name_start, *name_end; // Where a name is <[foo] or <foo [bar]=
360− const char *quote_start; // Where an attribute quote is <foo bar='[123'>
361− node* me; // The current node I'm working on
366−// Based on looking at ~50Kb XML documents, they seem to have ~700 attributes
367−// and ~300 nodes, so size appropriately to cope with that.
375−document* hexml_document_parse(const char* s, int slen)
377− if (slen == -1) slen = (int) strlen(s);
378− assert(s[slen] == 0);
380− buffer* buf = malloc(sizeof(buffer));
382− document* d = &buf->document;
385− d->error_message = NULL;
386− d->attrs.size = 1000;
388− d->attrs.attrs = buf->attrs;
389− d->attrs.alloc = NULL;
390− d->nodes.size = 500;
391− d->nodes.used_back = 0;
392− d->nodes.used_front = 1;
393− d->nodes.nodes = buf->nodes;
394− d->nodes.alloc = NULL;
396− d->nodes.nodes[0].name = start_length(0, 0);
397− d->nodes.nodes[0].outer = start_length(0, slen);
398− d->nodes.nodes[0].inner = start_length(0, slen);
399− d->nodes.nodes[0].attrs = start_length(0, 0);
401− // Introduce an intermediate result, otherwise behaviour is undefined
402− // because there is no guaranteed ordering between LHS and RHS evaluation
403− const char* res = parser(s, d);
408− d->nodes.nodes[0].nodes = node_commit(&d->nodes);
409− if (d->nodes.used_back != 0)
410− d->error_message = strdup("used_back failure");
415−/////////////////////////////////////////////////////////////////////
416−// TEST HARNESS (temporary)
420−static char* resolve(const document* d, str loc)
422− char* buf = malloc(loc.length + 3);
423− memcpy(&buf[1], &d->body[loc.start], loc.length);
425− buf[loc.length+1] = '\"';
426− buf[loc.length+2] = 0;
430−static char* disp(str loc)
432− char* buf = malloc(100);
433− if (loc.length == 0)
436− sprintf(buf, "[%i..%i]", loc.start, end(loc)-1);
442− setbuf(stdout, NULL);
443− const char* example = "<test foo='123 xyz' bar='t'><inner /> value</test>";
444− document* d = hexml_document_parse(example, -1);
445− if (d->error_message != NULL)
446− printf("Parse failure: %s\n", d->error_message);
450− int len = hexml_node_render(d, hexml_document_node(d), buf, sizeof(buf));
452− printf("Result = %s\n", buf);
453− printf("Used nodes = %i, attributes = %i\n", d->nodes.used_front, d->attrs.used);
455− for (int i = 0; i < d->attrs.used; i++)
456− printf("Attr %i: %s=%s\n", i, resolve(d, d->attrs.attrs[i].name), resolve(d, d->attrs.attrs[i].value));
457− for (int i = 0; i < d->nodes.used_front; i++)
459− printf("Node %i: %s attrs=%s, nodes=%s\n", i, resolve(d, d->nodes.nodes[i].name), disp(d->nodes.nodes[i].attrs), disp(d->nodes.nodes[i].nodes));
460− printf(" inner %s\n outer %s\n", resolve(d, d->nodes.nodes[i].inner), resolve(d, d->nodes.nodes[i].outer));
463− hexml_document_free(d);
470void main()
25void main()
472− setbuf(stdout, NULL);
27+ const char* res = hexml_parser("<test foo='123 xyz'/>");
473− char* body = "<?xml version=\"1.0\" lang=\"ja\"?><foo><bar baz=\"qux\">quux</bar><bar baz=\"bar\">hoge</bar><piyo>>piyopiyo<</piyo></foo><foo2 />";
28+ printf("Result %s\n", res);
474− body = "<test>X</test> ";
475− document* doc = document_parse(body, -1);
476− char* err = document_error(doc);
479− int len = document_render(doc, NULL, 0);
480− char* s = malloc(len + 1);
481− document_render(doc, s, len);
483− printf("Parse successful, %s\n", s);
486− printf("Parse failed, %s\n", err);