@@ -1,5 +1,5 @@
11#include "hexml.h"
2−#include <malloc.h>
2+#include <stdlib.h>
33#include <string.h>
44#include <assert.h>
55#include <ctype.h>
@@ -10,18 +10,18 @@ typedef int bool;
1010/////////////////////////////////////////////////////////////////////
1111// TYPES
1212
13−int static inline end(str s) { return s.start + s.length; }
13+static inline int end(str s) { return s.start + s.length; }
1414
15−str static inline start_length(int32_t start, int32_t length)
15+static inline str start_length(int32_t start, int32_t length)
1616{
17− if (start < 0 || length < 0) assert(0);
17+ assert(start >= 0 && length >= 0);
1818 str res;
1919 res.start = start;
2020 res.length = length;
2121 return res;
2222}
2323
24−str static inline start_end(int32_t start, int32_t end)
24+static inline str start_end(int32_t start, int32_t end)
2525{
2626 return start_length(start, end - start);
2727}
@@ -40,7 +40,7 @@ typedef struct
4040 // have a cursor at the end, which is stack scoped, so children write out, then I do
4141 // when you commit, you copy over from end to front
4242
43− // nodes
43+ // nodes
4444 int size;
4545 int used_front; // front entries, stored for good
4646 int used_back; // back entries, stack based, copied into front
@@ -51,11 +51,11 @@ typedef struct
5151
5252struct document
5353{
54− char* body; // pointer to initial argument, not owned by us
54+ const char* body; // pointer to initial argument, not owned by us
5555
5656 // things only used while parsing
57− char* cursor; // pointer to where we are in body
58− char* end; // pointer to one past the last char
57+ const char* cursor; // pointer to where we are in body
58+ const char* end; // pointer to one past the last char
5959 // if cursor is > end we have gone past the end
6060
6161 char* error_message;
@@ -63,8 +63,8 @@ struct document
6363 attr_buffer attrs;
6464};
6565
66−int static inline doc_length(document* d) { return (int) (d->end - d->body); }
67−int static inline doc_position(document* d) { return (int) (d->cursor - d->body); }
66+static inline int doc_length(const document* d) { return (int) (d->end - d->body); }
67+static inline int doc_position(const document* d) { return (int) (d->cursor - d->body); }
6868
6969
7070/////////////////////////////////////////////////////////////////////
@@ -72,49 +72,45 @@ int static inline doc_position(document* d) { return (int) (d->cursor - d->body)
7272
7373typedef struct
7474{
75− document* d;
75+ const document* d;
7676 char* buffer;
7777 int length;
7878 int cursor;
7979} render;
8080
81−void static inline render_char(render* r, char c)
81+static inline void render_char(render* r, char c)
8282{
8383 if (r->cursor < r->length)
8484 r->buffer[r->cursor] = c;
8585 r->cursor++;
8686}
8787
88−void static inline bound(char* msg, int index, int mn, int mx)
88+static inline void bound(int idx, int mn, int mx)
8989{
90− if (index < mn || index > mx)
91− {
92− //printf("Bounds checking failed %s, got %i, which should be in %i:%i\n", msg, index, mn, mx);
93− assert(0);
94− }
90+ assert(idx >= mn && idx <= mx);
9591}
9692
97−void static inline bound_str(char* msg, str s, int mn, int mx)
93+static inline void bound_str(str s, int mn, int mx)
9894{
99− if (s.length < 0) assert(0);
100− bound(msg, s.start, mn, mx);
101− bound(msg, end(s), mn, mx);
95+ assert(s.length >= 0);
96+ bound(s.start, mn, mx);
97+ bound(end(s), mn, mx);
10298}
10399
104−void render_str(render* r, str s)
100+static void render_str(render* r, str s)
105101{
106− bound_str("render_str", s, 0, doc_length(r->d));
102+ bound_str(s, 0, doc_length(r->d));
107103 for (int i = 0; i < s.length; i++)
108104 render_char(r, r->d->body[s.start + i]);
109105}
110106
111−void render_tag(render* r, node* n);
107+static void render_tag(render* r, const node* n);
112108
113−void render_content(render* r, node* n)
109+static void render_content(render* r, const node* n)
114110{
115− bound_str("render_conent inner", n->inner, 0, doc_length(r->d));
116− bound_str("render_conent nodes", n->nodes, 0, r->d->nodes.used_front);
117− bound_str("render_conent attrs", n->attrs, 0, r->d->attrs.used);
111+ bound_str(n->inner, 0, doc_length(r->d));
112+ bound_str(n->nodes, 0, r->d->nodes.used_front);
113+ bound_str(n->attrs, 0, r->d->attrs.used);
118114
119115 int done = n->inner.start;
120116 for (int i = 0; i < n->nodes.length; i++)
@@ -127,7 +123,7 @@ void render_content(render* r, node* n)
127123 render_str(r, start_end(done, end(n->inner)));
128124}
129125
130−void render_tag(render* r, node* n)
126+static void render_tag(render* r, const node* n)
131127{
132128 render_char(r, '<');
133129 render_str(r, n->name);
@@ -149,7 +145,7 @@ void render_tag(render* r, node* n)
149145 render_char(r, '>');
150146}
151147
152−int node_render(document* d, node* n, char* buffer, int length)
148+int hexml_node_render(const document* d, const node* n, char* buffer, int length)
153149{
154150 render r;
155151 r.d = d;
@@ -168,10 +164,10 @@ int node_render(document* d, node* n, char* buffer, int length)
168164/////////////////////////////////////////////////////////////////////
169165// NOT THE PARSER
170166
171−char* document_error(document* d){return d->error_message;}
172−node* document_node(document* d){return &d->nodes.nodes[0];}
167+char* hexml_document_error(const document* d){return d->error_message;}
168+node* hexml_document_node(const document* d){return &d->nodes.nodes[0];}
173169
174−void document_free(document* d)
170+void hexml_document_free(document* d)
175171{
176172 free(d->error_message);
177173 free(d->nodes.alloc);
@@ -179,20 +175,20 @@ void document_free(document* d)
179175 free(d);
180176}
181177
182−node* node_children(document* d, node* n, int* res)
178+node* hexml_node_children(const document* d, const node* n, int* res)
183179{
184180 *res = n->nodes.length;
185181 return &d->nodes.nodes[n->nodes.start];
186182}
187183
188−attr* node_attributes(document* d, node* n, int* res)
184+attr* hexml_node_attributes(const document* d, const node* n, int* res)
189185{
190186 *res = n->attrs.length;
191187 return &d->attrs.attrs[n->attrs.start];
192188}
193189
194190
195−attr* node_attributeBy(document* d, node* n, char* s, int slen)
191+attr* hexml_node_attribute(const document* d, const node* n, const char* s, int slen)
196192{
197193 if (slen == -1) slen = (int) strlen(s);
198194 const int limit = end(n->attrs);
@@ -206,7 +202,7 @@ attr* node_attributeBy(document* d, node* n, char* s, int slen)
206202}
207203
208204// Search for given strings within a node
209−node* node_childBy(document* d, node* parent, node* prev, char* s, int slen)
205+node* hexml_node_child(const document* d, const node* parent, const node* prev, const char* s, int slen)
210206{
211207 if (slen == -1) slen = (int) strlen(s);
212208 int i = prev == NULL ? parent->nodes.start : (int) (prev + 1 - d->nodes.nodes);
@@ -224,49 +220,49 @@ node* node_childBy(document* d, node* parent, node* prev, char* s, int slen)
224220/////////////////////////////////////////////////////////////////////
225221// PARSE TABLE
226222
227−const char tag_name1 = 0x1;
228−const char tag_name = 0x2;
229−const char tag_space = 0x4;
223+static const char tag_name1 = 0x1;
224+static const char tag_name = 0x2;
225+static const char tag_space = 0x4;
230226
231−char parse_table[256];
227+static char parse_table[256];
232228
233−void init_parse_table()
229+static void init_parse_table()
234230{
235231 static bool done = 0;
236232 if (done) return;
237233 for (int i = 0; i < 256; i++)
238234 {
239235 bool name1 = i == ':' || i == '_' || (i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z');
240− bool name = name1 || i == '-' || (i >= '0' && i <= '9');
236+ bool name = name1 || i == '-' || i == '.' || (i >= '0' && i <= '9');
241237 bool space = i == ' ' || i == '\t' || i == '\r' || i == '\n';
242238 parse_table[i] = (name1 ? tag_name1 : 0) | (name ? tag_name : 0) | (space ? tag_space : 0);
243239 }
244240 done = 1;
245241}
246242
247−bool static inline is(char c, char tag) { return parse_table[c] & tag; }
248−bool static inline is_name1(char c) { return is(c, tag_name1); }
249−bool static inline is_name(char c) { return is(c, tag_name); }
250−bool static inline is_space(char c) { return is(c, tag_space); }
243+static inline bool is(char c, char tag) { return parse_table[(unsigned char) c] & tag; }
244+static inline bool is_name1(char c) { return is(c, tag_name1); }
245+static inline bool is_name(char c) { return is(c, tag_name); }
246+static inline bool is_space(char c) { return is(c, tag_space); }
251247
252248
253249/////////////////////////////////////////////////////////////////////
254250// PARSER COMBINATORS
255251
256−char static inline peekAt(document* d, int i) { return d->cursor[i]; }
257−void static inline skip(document* d, int i) { d->cursor += i; }
258−char static inline peek(document* d) { return peekAt(d, 0); }
259−char static inline get(document* d) { char c = peek(d); skip(d, 1); return c; }
252+static inline char peek_at(const document* d, int i) { return d->cursor[i]; }
253+static inline char peek(const document* d) { return peek_at(d, 0); }
254+static inline void skip(document* d, int i) { d->cursor += i; }
255+static inline char get(document* d) { char c = peek(d); skip(d, 1); return c; }
260256
261257// Remove whitespace characters from the cursor while they are still whitespace
262−void static inline trim(document* d)
258+static inline void trim(document* d)
263259{
264260 while (is_space(peek(d)))
265261 skip(d, 1);
266262}
267263
268264// Find this character form the cursor onwards, if true adjust the cursor to that char, otherwise leave it at the end
269−bool find(document* d, char c)
265+static bool find(document* d, char c)
270266{
271267 char* x = memchr(d->cursor, c, d->end - d->cursor);
272268 if (x == NULL)
@@ -285,12 +281,13 @@ bool find(document* d, char c)
285281/////////////////////////////////////////////////////////////////////
286282// PARSING CODE
287283
288−void static inline node_alloc(node_buffer* b, int ask)
284+static inline void node_alloc(node_buffer* b, int ask)
289285{
290286 int space = b->size - b->used_back - b->used_front;
291287 if (space >= ask) return;
292288 int size2 = (b->size + 1000 + ask) * 2;
293289 node* buf2 = malloc(size2 * sizeof(node));
290+ assert(buf2);
294291 memcpy(buf2, b->nodes, b->used_front * sizeof(node));
295292 memcpy(&buf2[size2 - b->used_back], &b->nodes[b->size - b->used_back], b->used_back * sizeof(node));
296293 free(b->alloc);
@@ -299,12 +296,13 @@ void static inline node_alloc(node_buffer* b, int ask)
299296 b->alloc = buf2;
300297}
301298
302−void static inline attr_alloc(attr_buffer* b, int ask)
299+static inline void attr_alloc(attr_buffer* b, int ask)
303300{
304301 int space = b->size - b->used;
305302 if (space >= ask) return;
306303 int size2 = (b->size + 1000 + ask) * 2;
307304 attr* buf2 = malloc(size2 * sizeof(attr));
305+ assert(buf2);
308306 memcpy(buf2, b->attrs, b->used * sizeof(attr));
309307 free(b->alloc);
310308 b->size = size2;
@@ -312,16 +310,17 @@ void static inline attr_alloc(attr_buffer* b, int ask)
312310 b->alloc = buf2;
313311}
314312
315−void set_error(document* d, char* msg)
313+static void set_error(document* d, const char* msg)
316314{
317315 if (d->error_message != NULL) return; // keep the first error message
318316 d->error_message = malloc(strlen(msg)+1);
317+ assert(d->error_message);
319318 strcpy(d->error_message, msg);
320319}
321320
322321// you now expect a name, perhaps preceeded by whitespace
323322// the name may be empty
324−str static inline parse_name(document* d)
323+static inline str parse_name(document* d)
325324{
326325 int start = doc_position(d);
327326 if (!is_name1(peek(d)))
@@ -332,14 +331,15 @@ str static inline parse_name(document* d)
332331 return start_end(start, doc_position(d));
333332}
334333
335−str static inline parse_attrval(document* d)
334+static inline str parse_attrval(document* d)
336335{
337336 trim(d);
338− if (get(d) != '=')
337+ if (peek(d) != '=')
339338 {
340339 set_error(d, "Expected = in attribute, but missing");
341340 return start_length(0, 0);
342341 }
342+ skip(d, 1);
343343 trim(d);
344344 char c = peek(d);
345345 if (c == '\"' || c == '\'')
@@ -365,10 +365,10 @@ str static inline parse_attrval(document* d)
365365
366366// seen a tag name, now looking for attributes terminated by >
367367// puts the attributes it finds in the attribute buffer
368−str static inline parse_attributes(document* d)
368+static inline str parse_attributes(document* d)
369369{
370370 int start = d->attrs.used;
371− for (int i = 0; ; i++)
371+ while (d->error_message == NULL)
372372 {
373373 trim(d);
374374 str name = parse_name(d);
@@ -381,11 +381,11 @@ str static inline parse_attributes(document* d)
381381 return start_end(start, d->attrs.used);
382382}
383383
384−str parse_content(document* d);
384+static str parse_content(document* d);
385385
386386
387387// Add a new entry into tag, am at a '<'
388−void static inline parse_tag(document* d)
388+static inline void parse_tag(document* d)
389389{
390390 node_alloc(&d->nodes, 1);
391391 d->nodes.used_back++;
@@ -396,12 +396,18 @@ void static inline parse_tag(document* d)
396396 assert(c == '<');
397397 if (peek(d) == '?') skip(d, 1);
398398 me->name = parse_name(d);
399+ if (me->name.length == 0)
400+ {
401+ set_error(d, "Missing tag name");
402+ return;
403+ }
399404 me->attrs = parse_attributes(d);
405+ if (d->error_message != NULL) return;
400406
401− c = get(d);
402− if ((c == '/' || c == '?') && peek(d) == '>')
407+ c = peek(d);
408+ if ((c == '/' || c == '?') && peek_at(d, 1) == '>')
403409 {
404− skip(d, 1);
410+ skip(d, 2);
405411 me->nodes = start_length(0, 0);
406412 me->outer.length = start_end(me->outer.start, doc_position(d)).length;
407413 me->inner = start_length(doc_position(d), 0);
@@ -412,6 +418,8 @@ void static inline parse_tag(document* d)
412418 set_error(d, "Gunk at the end of the tag");
413419 return;
414420 }
421+ else
422+ skip(d, 1);
415423 me->inner.start = doc_position(d);
416424 str content = parse_content(d);
417425
@@ -421,7 +429,7 @@ void static inline parse_tag(document* d)
421429 me->inner.length = start_end(me->inner.start, doc_position(d)).length;
422430
423431 if (d->error_message != NULL) return;
424− if (peek(d) == '<' && peekAt(d, 1) == '/')
432+ if (peek(d) == '<' && peek_at(d, 1) == '/')
425433 {
426434 skip(d, 2);
427435 if (d->end - d->cursor >= me->name.length &&
@@ -443,7 +451,7 @@ void static inline parse_tag(document* d)
443451
444452// Parser until </, return the index of your node children
445453// Not inline as it is recursive
446−str parse_content(document* d)
454+static str parse_content(document* d)
447455{
448456 int before = d->nodes.used_back;
449457 while (d->error_message == NULL)
@@ -453,22 +461,22 @@ str parse_content(document* d)
453461 {
454462 break;
455463 }
456− else if (peekAt(d, 1) == '/')
464+ else if (peek_at(d, 1) == '/')
457465 {
458466 // have found a </
459467 break;
460468 }
461− else if (peekAt(d, 1) == '!' && peekAt(d, 2) == '-' && peekAt(d, 3) == '-')
469+ else if (peek_at(d, 1) == '!' && peek_at(d, 2) == '-' && peek_at(d, 3) == '-')
462470 {
463471 skip(d, 3);
464472 // you can't reuse the two '-' characters for the closing as well
465− if (peekAt(d, 0) == '\0' || peekAt(d, 1) == '\0')
473+ if (peek_at(d, 0) == '\0' || peek_at(d, 1) == '\0')
466474 {
467475 set_error(d, "Didn't get a closing comment");
468476 return start_end(0, 0);
469477 }
470478 skip(d, 2);
471− while (1)
479+ for (;;)
472480 {
473481 if (!find(d, '>'))
474482 {
@@ -476,7 +484,7 @@ str parse_content(document* d)
476484 return start_end(0, 0);
477485 }
478486 skip(d, 1);
479− if (peekAt(d, -3) == '-' && peekAt(d, -2))
487+ if (peek_at(d, -3) == '-' && peek_at(d, -2) == '-')
480488 break;
481489 }
482490 }
@@ -504,13 +512,14 @@ typedef struct
504512 node nodes[500];
505513} buffer;
506514
507−document* document_parse(char* s, int slen)
515+document* hexml_document_parse(const char* s, int slen)
508516{
509517 if (slen == -1) slen = (int) strlen(s);
510518 assert(s[slen] == 0);
511519 init_parse_table();
512520
513521 buffer* buf = malloc(sizeof(buffer));
522+ assert(buf);
514523 document* d = &buf->document;
515524 d->body = s;
516525 d->cursor = s;
@@ -530,15 +539,13 @@ document* document_parse(char* s, int slen)
530539 d->nodes.nodes[0].outer = start_length(0, slen);
531540 d->nodes.nodes[0].inner = start_length(0, slen);
532541 d->nodes.nodes[0].attrs = start_length(0, 0);
533−
542+
534543 // Introduce an intermediate result, otherwise behaviour is undefined
535544 // because there is no guaranteed ordering between LHS and RHS evaluation
536545 str content = parse_content(d);
537546 d->nodes.nodes[0].nodes = content;
538547
539− if (d->cursor < d->end && d->error_message == NULL)
540− {
548+ if (d->cursor < d->end)
541549 set_error(d, "Trailing junk at the end of the document");
542− }
543550 return d;
544551}