@@ -62,15 +62,18 @@ struct document
6262 char* body; // pointer to initial argument, not owned by us
6363
6464 // things only used while parsing
65− int cursor; // pointer to where we are in body
66− int length; // total length of body
67− // if cursor is >= length we have gone past the end
65+ char* cursor; // pointer to where we are in body
66+ char* end; // pointer to one past the last char
67+ // if cursor is > end we have gone past the end
6868
6969 char* error_message;
7070 node_buffer nodes;
7171 attr_buffer attrs;
7272};
7373
74+int static inline doc_length(document* d) { return d->end - d->body; }
75+int static inline doc_position(document* d) { return d->cursor - d->body; }
76+
7477
7578/////////////////////////////////////////////////////////////////////
7679// RENDER CODE
@@ -108,7 +111,7 @@ void static inline bound_str(char* msg, str s, int mn, int mx)
108111
109112void render_str(render* r, str s)
110113{
111− bound_str("render_str", s, 0, r->d->length);
114+ bound_str("render_str", s, 0, doc_length(r->d));
112115 render_char(r, '[');
113116 for (int i = 0; i < s.length; i++)
114117 render_char(r, r->d->body[s.start + i]);
@@ -119,7 +122,7 @@ void render_tag(render* r, node* n);
119122
120123void render_content(render* r, node* n)
121124{
122− bound_str("render_conent inner", n->inner, 0, r->d->length);
125+ bound_str("render_conent inner", n->inner, 0, doc_length(r->d));
123126 bound_str("render_conent nodes", n->nodes, 0, r->d->nodes.used_front);
124127 bound_str("render_conent attrs", n->attrs, 0, r->d->attrs.used);
125128
@@ -257,15 +260,10 @@ bool static inline is_space(char c) { return is(c, tag_space); }
257260/////////////////////////////////////////////////////////////////////
258261// PARSER COMBINATORS
259262
260−char static inline peekAt(document* d, int i)
261−{
262− int j = d->cursor + i;
263− return j >= d->length ? 0 : d->body[j];
264−}
265−
266−void static inline skip(document* d, int i){d->cursor += i;}
267−char static inline peek(document* d){return peekAt(d, 0);}
268−char static inline get(document* d){char c = peek(d); skip(d, 1); return c;}
263+char static inline peekAt(document* d, int i) { return d->cursor[i]; }
264+void static inline skip(document* d, int i) { d->cursor += i; }
265+char static inline peek(document* d) { return peekAt(d, 0); }
266+char static inline get(document* d) { char c = peek(d); skip(d, 1); return c; }
269267
270268// Remove whitespace characters from the cursor while they are still whitespace
271269void static inline trim(document* d)
@@ -277,16 +275,15 @@ void static inline trim(document* d)
277275// Find this character form the cursor onwards, if true adjust the cursor to that char, otherwise leave it at the end
278276bool find(document* d, char c)
279277{
280− char* start = &d->body[d->cursor];
281− char* end = memchr(start, c, d->length - d->cursor);
282− if (end == NULL)
278+ char* x = memchr(d->cursor, c, d->end - d->cursor);
279+ if (x == NULL)
283280 {
284− d->cursor = d->length;
281+ d->cursor = d->end;
285282 return 0;
286283 }
287284 else
288285 {
289− d->cursor += end - start;
286+ d->cursor = x;
290287 return 1;
291288 }
292289}
@@ -318,15 +315,13 @@ void attr_alloc(attr_buffer* b, int ask)
318315str parse_name(document* d)
319316{
320317 trim(d);
321− str res;
322− res.start = d->cursor;
318+ int start = doc_position(d);
323319 if (!is_name1(peek(d)))
324− return start_length(d->cursor, 0);
320+ return start_length(start, 0);
325321 skip(d, 1);
326322 while (is_name(peek(d)))
327323 skip(d, 1);
328− res.length = d->cursor - res.start;
329− return res;
324+ return start_end(start, doc_position(d));
330325}
331326
332327str parse_attrval(document* d)
@@ -346,7 +341,7 @@ str parse_attrval(document* d)
346341 return start_length(0, 0);
347342 }
348343 skip(d, 1);
349− return start_end(start, d->cursor - 1);
344+ return start_end(start, doc_position(d) - 1);
350345 }
351346 else
352347 return parse_name(d);
@@ -383,7 +378,7 @@ void parse_tag(document* d)
383378 d->nodes.used_back++;
384379 int me = d->nodes.size - d->nodes.used_back;
385380
386− d->nodes.nodes[me].outer.start = d->cursor;
381+ d->nodes.nodes[me].outer.start = doc_position(d);
387382 char c = get(d);
388383 assert(c == '<');
389384 if (peek(d) == '?') skip(d, 1);
@@ -395,8 +390,8 @@ void parse_tag(document* d)
395390 {
396391 skip(d, 1);
397392 d->nodes.nodes[me].nodes = start_length(0, 0);
398− d->nodes.nodes[me].outer.length = start_end(d->nodes.nodes[me].outer.start, d->cursor).length;
399− d->nodes.nodes[me].inner = start_length(d->cursor, 0);
393+ d->nodes.nodes[me].outer.length = start_end(d->nodes.nodes[me].outer.start, doc_position(d)).length;
394+ d->nodes.nodes[me].inner = start_length(doc_position(d), 0);
400395 return;
401396 }
402397 else if (c != '>')
@@ -404,23 +399,23 @@ void parse_tag(document* d)
404399 d->error_message = _strdup("Gunk at the end of the tag");
405400 return;
406401 }
407− d->nodes.nodes[me].inner.start = d->cursor;
402+ d->nodes.nodes[me].inner.start = doc_position(d);
408403 d->nodes.nodes[me].nodes = parse_content(d);
409− d->nodes.nodes[me].inner.length = start_end(d->nodes.nodes[me].inner.start, d->cursor).length;
404+ d->nodes.nodes[me].inner.length = start_end(d->nodes.nodes[me].inner.start, doc_position(d)).length;
410405
411406 if (d->error_message != NULL) return;
412407 if (peek(d) == '<' && peekAt(d, 1) == '/')
413408 {
414409 skip(d, 2);
415410 trim(d);
416− if (d->length - d->cursor >= d->nodes.nodes[me].name.length &&
417− memcmp(&d->body[d->cursor], &d->body[d->nodes.nodes[me].name.start], d->nodes.nodes[me].name.length) == 0)
411+ if (d->end - d->cursor >= d->nodes.nodes[me].name.length &&
412+ memcmp(d->cursor, &d->body[d->nodes.nodes[me].name.start], d->nodes.nodes[me].name.length) == 0)
418413 {
419414 skip(d, d->nodes.nodes[me].name.length);
420415 trim(d);
421416 if (get(d) == '>')
422417 {
423− d->nodes.nodes[me].outer.length = start_end(d->nodes.nodes[me].outer.start, d->cursor).length;
418+ d->nodes.nodes[me].outer.length = start_end(d->nodes.nodes[me].outer.start, doc_position(d)).length;
424419 return;
425420 }
426421 }
@@ -464,12 +459,13 @@ str parse_content(document* d)
464459document* document_parse(char* s, int slen)
465460{
466461 if (slen == -1) slen = strlen(s);
462+ assert(s[slen] == 0);
467463 init_parse_table();
468464
469465 document* d = malloc(sizeof(document));
470466 d->body = s;
471− d->cursor = 0;
472− d->length = slen;
467+ d->cursor = s;
468+ d->end = &s[slen];
473469 d->error_message = NULL;
474470 d->attrs.size = 0;
475471 d->attrs.used = 0;
@@ -485,7 +481,7 @@ document* document_parse(char* s, int slen)
485481 d->nodes.nodes[0].attrs = start_length(0, 0);
486482 d->nodes.nodes[0].nodes = parse_content(d);
487483
488− if (d->cursor < d->length && d->error_message == NULL)
484+ if (d->cursor < d->end && d->error_message == NULL)
489485 {
490486 d->error_message = _strdup("Trailing junk at the end of the document");
491487 }