#include #include #include "mem.h" #include "dom.h" #include "vec.h" #include "parse.h" static struct node **nodes; static size_t count; static size_t capacity; static struct vec stack; static struct node *root; static inline struct node *node_alloc(void) { struct node *v; if (count == capacity) { capacity = capacity ? capacity * 2 : 64; nodes = REALLOC(nodes, capacity * sizeof(struct node *)); } v = CALLOC(1, sizeof(struct node)); nodes[count++] = v; return v; } struct node *dom_init(const char *html) { vec_init(&stack, sizeof(struct node *)); parse(html); return root; } void dom_free(void) { size_t i; for (i = 0; i < count; i++) free(nodes[i]); free(nodes); nodes = NULL; count = 0; capacity = 0; vec_free(&stack); } static inline int is_self_closing(tag_type tag) { switch (tag) { case TAG_META: case TAG_LINK: return 1; default: return 0; } } static inline void close_tag(struct node *v) { void *top; struct node *parent; top = vec_top(&stack); if (!top) { root = v; return; } parent = *(struct node **)top; v->parent = parent; if (!parent->first_child) { parent->first_child = v; parent->last_child = v; } else { parent->last_child->next_sibling = v; parent->last_child = v; } } extern void on_open(const char *tag, size_t n) { struct node *v; v = node_alloc(); v->tag = str_to_tag(tag, n); vec_push(&stack, &v); } extern void on_open_end(void) { struct node *v; v = *(struct node **)vec_top(&stack); if (is_self_closing(v->tag)) { v = *(struct node **)vec_pop(&stack); close_tag(v); } } extern void on_close(const char *tag, size_t n) { tag_type type; struct node *top; type = str_to_tag(tag, n); top = *(struct node **)vec_top(&stack); if (top->tag != type) errx(1, "Unmatched closing tag: %.*s", (int)n, tag); top = *(struct node **)vec_pop(&stack); close_tag(top); } extern void on_text(const char *text, size_t n) { struct node *v; v = node_alloc(); v->tag = TAG_TEXT; v->text = text; v->textlen = n; close_tag(v); } extern void on_attr(const char *name, size_t nname, const char *val, size_t nval) { struct attr *a; struct node *v; a = MALLOC(sizeof(struct attr)); a->key = name; a->keylen = nname; a->val = val; a->vallen = nval; a->next = NULL; v = *(struct node **)vec_top(&stack); a->next = v->attrs; v->attrs = a; }