@@ -39,7 +39,6 @@ typedef struct
3939 // when you commit, you copy over from end to front
4040
4141 // nodes
42− // Invariant: Always at least one free spot (to do copying from front to back)
4342 int size;
4443 int used_front; // front entries, stored for good
4544 int used_back; // back entries, stack based, copied into front on </close>
@@ -214,9 +213,8 @@ node* hexml_node_child(const document* d, const node* parent, const node* prev,
214213
215214static inline node* node_alloc(node_buffer* b)
216215{
217− // Invariant: node_commit requires at least one spare spot
218216 int space = b->size - b->used_back - b->used_front;
219− if (space < 2)
217+ if (space < 1)
220218 {
221219 int size2 = (b->size + 1000) * 2;
222220 node* buf2 = malloc(size2 * sizeof(node));
@@ -232,9 +230,59 @@ static inline node* node_alloc(node_buffer* b)
232230 return &b->nodes[b->size - b->used_back - 1];
233231}
234232
235−static inline void node_commit(node_buffer* b)
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+ int to = from + n - 1;
238+ for (int to = from + n - 1; to > from; from++, to--)
239+ while (to > from)
240+ {
241+ node temp = buffer[to];
242+ buffer[to] = buffer[from];
243+ buffer[from] = temp;
244+ }
245+}
246+
247+// buffer[to .. to+n] = reverse (buffer[from .. from+n])
248+// The ranges may not overlap
249+static inline void memcpy_reverse(node* buffer, int from, int to, int n)
250+{
251+ int end = from + n - 1;
252+ for (int i = 0; i < n; i++)
253+ buffer[to+i] = buffer[end-i];
254+}
255+
256+// buffer[to .. to+n] = reverse (buffer[from .. from+n])
257+// The ranges may overlap
258+static inline void memmove_reverse(node* buffer, int from, int to, int n)
236259{
260+ assert(from < to); // always the case in my usages
261+ if (to - from >= n)
262+ memcpy_reverse(buffer, from, to, n);
263+ else
264+ {
265+ int overlap = from - to;
266+ memcpy_reverse(buffer, from, to + n - overlap, overlap);
267+ reverse(buffer, to, n - overlap);
268+ }
269+}
270+
271+static inline str node_commit(node_buffer* b)
272+{
273+ // first search for an "open" node (nodes.length == -1)
274+ int open;
275+ for (open = b->size - b->used_back; open < b->size; open++)
276+ {
277+ if (b->nodes[open].nodes.length == -1)
278+ break;
279+ }
237280
281+ int n = open - (b->size - b->used_back);
282+ memmove_reverse(b->nodes, b->used_front, b->used_back, n);
283+ b->used_back -= n;
284+ b->used_front += n;
285+ return start_length(b->used_front - n, n);
238286}
239287
240288static inline attr* attr_alloc(attr_buffer* b)
@@ -287,7 +335,7 @@ static inline str gap(const char* ref, const char* start, const char* end)
287335 attr->name = gap(d->body, name_start, name_end); \
288336 attr->value = gap(d->body, quote_start, quote_end);
289337#define P_TagComment printf("TagComment %s\n", p)
290−#define P_TagOpen printf("TagOpen %s\n", p)
338+#define P_TagOpen printf("TagOpen - missed %s\n", p)
291339#define P_TagClose printf("TagClose %s\n", p)
292340#define P_TagOpenClose \
293341 node->nodes = start_end(0, 0); \
@@ -317,7 +365,6 @@ document* hexml_document_parse(const char* s, int slen)
317365{
318366 if (slen == -1) slen = (int) strlen(s);
319367 assert(s[slen] == 0);
320− // init_parse_table();
321368
322369 buffer* buf = malloc(sizeof(buffer));
323370 assert(buf);
@@ -346,7 +393,7 @@ document* hexml_document_parse(const char* s, int slen)
346393 if (res != NULL)
347394 d->error_message = strdup(res);
348395 else
349− d->nodes.nodes[0].nodes = start_end(1, d->nodes.used_front);
396+ d->nodes.nodes[0].nodes = node_commit(&d->nodes);
350397 return d;
351398}
352399