@@ -1,29 +1,488 @@
11
2+#include "../cbits/hexml.h"
3+#include <stdlib.h>
4+#include <string.h>
5+#include <assert.h>
26#include <stdio.h>
3−#define ARGUMENTS
47
5−#define parse_table hexml_parse_table
6−#define parser hexml_parser
8+/////////////////////////////////////////////////////////////////////
9+// TYPES
710
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)
11+static inline int end(str s) { return s.start + s.length; }
2112
22−#include "test.h"
13+static inline str start_length(int32_t start, int32_t length)
14+{
15+ assert(start >= 0 && length >= 0);
16+ str res;
17+ res.start = start;
18+ res.length = length;
19+ return res;
20+}
21+
22+static inline str start_end(int32_t start, int32_t end)
23+{
24+ return start_length(start, end - start);
25+}
26+
27+typedef struct
28+{
29+ int size;
30+ int used;
31+ attr* attrs; // dynamically allocated buffer
32+ attr* alloc; // what to call free on
33+} attr_buffer;
34+
35+typedef struct
36+{
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
40+
41+ // nodes
42+ int size;
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
48+} node_buffer;
49+
50+
51+struct document
52+{
53+ const char* body; // pointer to initial argument, not owned by us
54+ int body_len; // length of the body
55+
56+ char* error_message;
57+ node_buffer nodes;
58+ attr_buffer attrs;
59+};
60+
61+
62+/////////////////////////////////////////////////////////////////////
63+// RENDER CODE
64+
65+typedef struct
66+{
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
72+} render;
73+
74+static inline void render_char(render* r, char c)
75+{
76+ if (r->cursor < r->length)
77+ r->buffer[r->cursor] = c;
78+ r->cursor++;
79+}
80+
81+static inline void bound(int idx, int mn, int mx)
82+{
83+ assert(idx >= mn && idx <= mx);
84+}
85+
86+static inline void bound_str(str s, int mn, int mx)
87+{
88+ assert(s.length >= 0);
89+ bound(s.start, mn, mx);
90+ bound(end(s), mn, mx);
91+}
92+
93+static void render_str(render* r, str s)
94+{
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]);
98+}
99+
100+static void render_tag(render* r, const node* n);
101+
102+static void render_content(render* r, const node* n)
103+{
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);
107+
108+ int done = n->inner.start;
109+ for (int i = 0; i < n->nodes.length; i++)
110+ {
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);
114+ render_tag(r, x);
115+ }
116+ render_str(r, start_end(done, end(n->inner)));
117+}
118+
119+static void render_tag(render* r, const node* n)
120+{
121+ render_char(r, '<');
122+ render_str(r, n->name);
123+ for (int i = 0; i < n->attrs.length; i++)
124+ {
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, '\"');
132+ }
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, '>');
139+}
140+
141+int hexml_node_render(const document* d, const node* n, char* buffer, int length)
142+{
143+ render r;
144+ r.d = d;
145+ r.buffer = buffer;
146+ r.length = length;
147+ r.cursor = 0;
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);
151+ else
152+ render_tag(&r, n);
153+ return r.cursor;
154+}
155+
156+
157+/////////////////////////////////////////////////////////////////////
158+// NOT THE PARSER
159+
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];}
162+
163+void hexml_document_free(document* d)
164+{
165+ free(d->error_message);
166+ free(d->nodes.alloc);
167+ free(d->attrs.alloc);
168+ free(d);
169+}
170+
171+node* hexml_node_children(const document* d, const node* n, int* res)
172+{
173+ *res = n->nodes.length;
174+ return &d->nodes.nodes[n->nodes.start];
175+}
176+
177+attr* hexml_node_attributes(const document* d, const node* n, int* res)
178+{
179+ *res = n->attrs.length;
180+ return &d->attrs.attrs[n->attrs.start];
181+}
182+
183+attr* hexml_node_attribute(const document* d, const node* n, const char* s, int slen)
184+{
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++)
188+ {
189+ attr* r = &d->attrs.attrs[i];
190+ if (r->name.length == slen && memcmp(s, &d->body[r->name.start], slen) == 0)
191+ return r;
192+ }
193+ return NULL;
194+}
195+
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)
198+{
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++)
203+ {
204+ node* r = &d->nodes.nodes[i];
205+ if (r->name.length == slen && memcmp(s, &d->body[r->name.start], slen) == 0)
206+ return r;
207+ }
208+ return NULL;
209+}
210+
211+/////////////////////////////////////////////////////////////////////
212+// PARSING CODE
213+
214+static inline node* node_alloc(node_buffer* b)
215+{
216+ int space = b->size - b->used_back - b->used_front;
217+ if (space < 1)
218+ {
219+ int size2 = (b->size + 1000) * 2;
220+ node* buf2 = malloc(size2 * sizeof(node));
221+ assert(buf2);
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));
224+ free(b->alloc);
225+ b->size = size2;
226+ b->nodes = buf2;
227+ b->alloc = buf2;
228+ }
229+ b->used_back++;
230+ return &b->nodes[b->size - b->used_back];
231+}
232+
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)
236+{
237+ for (int to = from + n - 1; to > from; from++, to--)
238+ {
239+ node temp = buffer[to];
240+ buffer[to] = buffer[from];
241+ buffer[from] = temp;
242+ }
243+}
244+
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)
248+{
249+ int end = from + n - 1;
250+ for (int i = 0; i < n; i++)
251+ buffer[to+i] = buffer[end-i];
252+}
253+
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)
257+{
258+ assert(from >= to); // always the case in my usages
259+ if (to + n < from)
260+ memcpy_reverse(buffer, from, to, n);
261+ else
262+ {
263+ int overlap = from - to;
264+ memcpy_reverse(buffer, from, to + n - overlap, overlap);
265+ reverse(buffer, to, n - overlap);
266+ }
267+}
268+
269+static inline str node_commit(node_buffer* b)
270+{
271+ // first search for an "open" node (nodes.length == -1)
272+ int open;
273+ for (open = b->size - b->used_back; open < b->size; open++)
274+ {
275+ if (b->nodes[open].nodes.length == -1)
276+ break;
277+ }
278+
279+ int n = open - (b->size - b->used_back);
280+ memmove_reverse(b->nodes, b->size - b->used_back, b->used_front, n);
281+ b->used_back -= n;
282+ b->used_front += n;
283+ return start_length(b->used_front - n, n);
284+}
285+
286+static inline attr* attr_alloc(attr_buffer* b)
287+{
288+ // Ensure there is at least one node left
289+ int space = b->size - b->used;
290+ if (space < 1)
291+ {
292+ int size2 = (b->size + 1000) * 2;
293+ attr* buf2 = malloc(size2 * sizeof(attr));
294+ assert(buf2);
295+ memcpy(buf2, b->attrs, b->used * sizeof(attr));
296+ free(b->alloc);
297+ b->size = size2;
298+ b->attrs = buf2;
299+ b->alloc = buf2;
300+ }
301+ b->used++;
302+ return &b->attrs[b->used - 1];
303+}
304+
305+static void set_error(document* d, const char* msg)
306+{
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);
311+}
312+
313+static inline str gap(const char* ref, const char* start, const char* end)
314+{
315+ return start_end(start - ref, end - ref);
316+}
317+
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
329+#define P_QuoteEnd \
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
335+#define P_TagOpen \
336+ me->nodes.length = -1; \
337+ me->inner = gap(d->body, p, p); \
338+ me->outer = gap(d->body, tag_start, tag_start);
339+#define P_TagClose \
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);
354+
355+// Given the parsed string, return either NULL (success) or an error message (failure)
356+static const char* parser(const char* p, document* d)
357+{
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
362+# include "test.h"
363+ return NULL;
364+}
365+
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.
368+typedef struct
369+{
370+ document document;
371+ attr attrs[1000];
372+ node nodes[500];
373+} buffer;
374+
375+document* hexml_document_parse(const char* s, int slen)
376+{
377+ if (slen == -1) slen = (int) strlen(s);
378+ assert(s[slen] == 0);
379+
380+ buffer* buf = malloc(sizeof(buffer));
381+ assert(buf);
382+ document* d = &buf->document;
383+ d->body = s;
384+ d->body_len = slen;
385+ d->error_message = NULL;
386+ d->attrs.size = 1000;
387+ d->attrs.used = 0;
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;
395+
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);
400+
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);
404+ if (res != NULL)
405+ set_error(d, res);
406+ else
407+ {
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");
411+ }
412+ return d;
413+}
414+
415+/////////////////////////////////////////////////////////////////////
416+// TEST HARNESS (temporary)
417+
418+#ifdef TEST
419+
420+static char* resolve(const document* d, str loc)
421+{
422+ char* buf = malloc(loc.length + 3);
423+ memcpy(&buf[1], &d->body[loc.start], loc.length);
424+ buf[0] = '\"';
425+ buf[loc.length+1] = '\"';
426+ buf[loc.length+2] = 0;
427+ return buf;
428+}
429+
430+static char* disp(str loc)
431+{
432+ char* buf = malloc(100);
433+ if (loc.length == 0)
434+ strcpy(buf, "[]");
435+ else
436+ sprintf(buf, "[%i..%i]", loc.start, end(loc)-1);
437+ return buf;
438+}
439+
440+int main()
441+{
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);
447+ else
448+ {
449+ char buf[1000];
450+ int len = hexml_node_render(d, hexml_document_node(d), buf, sizeof(buf));
451+ buf[len] = 0;
452+ printf("Result = %s\n", buf);
453+ printf("Used nodes = %i, attributes = %i\n", d->nodes.used_front, d->attrs.used);
454+
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++)
458+ {
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));
461+ }
462+ }
463+ hexml_document_free(d);
464+ return 0;
465+}
23466
467+#endif
24468
469+/*
25470void main()
26471{
27− const char* res = hexml_parser("<test foo='123 xyz'/>");
28− printf("Result %s\n", res);
472+ setbuf(stdout, NULL);
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 />";
474+ body = "<test>X</test> ";
475+ document* doc = document_parse(body, -1);
476+ char* err = document_error(doc);
477+ if (err == NULL)
478+ {
479+ int len = document_render(doc, NULL, 0);
480+ char* s = malloc(len + 1);
481+ document_render(doc, s, len);
482+ s[len] = 0;
483+ printf("Parse successful, %s\n", s);
484+ }
485+ else
486+ printf("Parse failed, %s\n", err);
29487}
488+*/