@@ -211,33 +211,95 @@ node* hexml_node_child(const document* d, const node* parent, const node* prev,
211/////////////////////////////////////////////////////////////////////
211/////////////////////////////////////////////////////////////////////
212// PARSING CODE
212// PARSING CODE
214−static inline void node_alloc(node_buffer* b, int ask)
214+static inline node* node_alloc(node_buffer* b)
216 int space = b->size - b->used_back - b->used_front;
216 int space = b->size - b->used_back - b->used_front;
217− if (space >= ask) return;
217+ if (space < 1)
218− int size2 = (b->size + 1000 + ask) * 2;
219+ int size2 = (b->size + 1000) * 2;
219− node* buf2 = malloc(size2 * sizeof(node));
220+ node* buf2 = malloc(size2 * sizeof(node));
220− assert(buf2);
221+ assert(buf2);
221− memcpy(buf2, b->nodes, b->used_front * sizeof(node));
222+ memcpy(buf2, b->nodes, b->used_front * sizeof(node));
222− memcpy(&buf2[size2 - b->used_back], &b->nodes[b->size - b->used_back], b->used_back * sizeof(node));
223+ memcpy(&buf2[size2 - b->used_back], &b->nodes[b->size - b->used_back], b->used_back * sizeof(node));
223− free(b->alloc);
224+ free(b->alloc);
224− b->size = size2;
225+ b->size = size2;
225− b->nodes = buf2;
226+ b->nodes = buf2;
226− b->alloc = buf2;
227+ b->alloc = buf2;
230+ return &b->nodes[b->size - b->used_back];
233+// buffer[from .. from+n] = reverse (buffer[from .. from+n])
234+// The ranges completely overlap
229−static inline void attr_alloc(attr_buffer* b, int ask)
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
231 int space = b->size - b->used;
289 int space = b->size - b->used;
232− if (space >= ask) return;
290+ if (space < 1)
233− int size2 = (b->size + 1000 + ask) * 2;
292+ int size2 = (b->size + 1000) * 2;
234− attr* buf2 = malloc(size2 * sizeof(attr));
293+ attr* buf2 = malloc(size2 * sizeof(attr));
235− assert(buf2);
294+ assert(buf2);
236− memcpy(buf2, b->attrs, b->used * sizeof(attr));
295+ memcpy(buf2, b->attrs, b->used * sizeof(attr));
237− free(b->alloc);
296+ free(b->alloc);
238− b->size = size2;
297+ b->size = size2;
239− b->attrs = buf2;
298+ b->attrs = buf2;
240− b->alloc = buf2;
299+ b->alloc = buf2;
302+ return &b->attrs[b->used - 1];
243static void set_error(document* d, const char* msg)
305static void set_error(document* d, const char* msg)
@@ -254,38 +316,48 @@ static inline str gap(const char* ref, const char* start, const char* end)
256#define P_Abort(x) return x
318#define P_Abort(x) return x
257−#define P_Tag \
319+#define P_Tag tag_start = p;
258− node_alloc(&d->nodes, 1); \
259− me = &d->nodes.nodes[d->nodes.size - d->nodes.used_back]; \
260− me->outer = gap(d->body, p, p);
261#define P_NameStart name_start = p
320#define P_NameStart name_start = p
262#define P_NameEnd name_end = p
321#define P_NameEnd name_end = p
263#define P_AttribsStart \
322#define P_AttribsStart \
323+ me = node_alloc(&d->nodes); \
264 me->attrs.start = d->attrs.used; \
324 me->attrs.start = d->attrs.used; \
265 me->name = gap(d->body, name_start, name_end);
325 me->name = gap(d->body, name_start, name_end);
266#define P_AttribsEnd \
326#define P_AttribsEnd \
267 me->attrs = start_end(me->attrs.start, d->attrs.used);
327 me->attrs = start_end(me->attrs.start, d->attrs.used);
268#define P_QuoteStart quote_start = p
328#define P_QuoteStart quote_start = p
269#define P_QuoteEnd \
329#define P_QuoteEnd \
271− attr_alloc(&d->attrs, 1); \
330+ attr* attr = attr_alloc(&d->attrs); \
272− d->attrs.attrs[d->attrs.used].name = gap(d->body, name_start, name_end); \
331+ attr->name = gap(d->body, name_start, name_end); \
273− d->attrs.attrs[d->attrs.used].value = gap(d->body, quote_start, quote_end); \
332+ attr->value = gap(d->body, quote_start, p);
275−#define P_TagComment printf("TagComment %s\n", p)
333+#define P_TagComment \
334+ // No action required - comments just flow as normal text
276−#define P_TagOpen printf("TagOpen %s\n", p)
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);
277−#define P_TagClose printf("TagClose %s\n", p)
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);
278#define P_TagOpenClose \
350#define P_TagOpenClose \
279 me->nodes = start_end(0, 0); \
351 me->nodes = start_end(0, 0); \
280− printf("TagOpenClose %s\n", p)
352+ me->inner = gap(d->body, p, p); \
281−// d->nodes.nodes[d->nodes.used_front].outer = gap(d->body, tag_start, p); \
353+ me->outer = gap(d->body, tag_start, p);
284// Given the parsed string, return either NULL (success) or an error message (failure)
355// Given the parsed string, return either NULL (success) or an error message (failure)
285static const char* parser(const char* p, document* d)
356static const char* parser(const char* p, document* d)
358+ const char *tag_start; // Where the tag starts [<foo
287 const char *name_start, *name_end; // Where a name is <[foo] or <foo [bar]=
359 const char *name_start, *name_end; // Where a name is <[foo] or <foo [bar]=
288− const char *quote_start, *quote_end; // Where an attribute quote is <foo bar='[123]'>
360+ const char *quote_start; // Where an attribute quote is <foo bar='[123'>
289 node* me; // The current node I'm working on
361 node* me; // The current node I'm working on
290# include "test.h"
362# include "test.h"
291 return NULL;
363 return NULL;
@@ -304,7 +376,6 @@ document* hexml_document_parse(const char* s, int slen)
305 if (slen == -1) slen = (int) strlen(s);
377 if (slen == -1) slen = (int) strlen(s);
306 assert(s[slen] == 0);
378 assert(s[slen] == 0);
307− // init_parse_table();
309 buffer* buf = malloc(sizeof(buffer));
380 buffer* buf = malloc(sizeof(buffer));
310 assert(buf);
381 assert(buf);
@@ -331,28 +402,70 @@ document* hexml_document_parse(const char* s, int slen)
331 // because there is no guaranteed ordering between LHS and RHS evaluation
402 // because there is no guaranteed ordering between LHS and RHS evaluation
332 const char* res = parser(s, d);
403 const char* res = parser(s, d);
333 if (res != NULL)
404 if (res != NULL)
334− d->error_message = strdup(res);
405+ set_error(d, res);
336− d->nodes.nodes[0].nodes = start_end(1, d->nodes.used_front);
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");
337 return d;
412 return d;
340/////////////////////////////////////////////////////////////////////
415/////////////////////////////////////////////////////////////////////
341// TEST HARNESS (temporary)
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);
343int main()
440int main()
345 setbuf(stdout, NULL);
442 setbuf(stdout, NULL);
346− const char* example = "<bob />"; // "<test foo='123 xyz' bar='t'><inner /> value</test>";
443+ const char* example = "<test foo='123 xyz' bar='t'><inner /> value</test>";
347− const document* d = hexml_document_parse(example, -1);
444+ document* d = hexml_document_parse(example, -1);
445+ if (d->error_message != NULL)
446+ printf("Parse failure: %s\n", d->error_message);
348− char buf[1000];
449+ char buf[1000];
349− int len = hexml_node_render(d, hexml_document_node(d), buf, sizeof(buf));
450+ int len = hexml_node_render(d, hexml_document_node(d), buf, sizeof(buf));
350− buf[len] = 0;
451+ buf[len] = 0;
351− printf("Result = %s\n", buf);
452+ printf("Result = %s\n", buf);
352− printf("Used nodes = %i, attributes = %i\n", d->nodes.used_front, d->attrs.used);
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);
353 return 0;
464 return 0;
357void main()
470void main()