From 95428c41f0ee3ac108cf1a4acfaa67157ad954dc Mon Sep 17 00:00:00 2001 From: Sadeep Madurange Date: Sun, 24 May 2026 18:00:38 +0800 Subject: Build DOM. --- dom.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 121 insertions(+), 11 deletions(-) (limited to 'dom.c') diff --git a/dom.c b/dom.c index a4d75e1..71679bc 100644 --- a/dom.c +++ b/dom.c @@ -1,37 +1,147 @@ #include +#include +#include "mem.h" #include "dom.h" +#include "vec.h" #include "parse.h" -void init_dom(const char *html) +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; + } } -/* Parser event handlers */ extern void on_open(const char *tag, size_t n) { - printf("Tag opened: %.*s\n", (int)n, tag); + 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) { - printf("Tag closed: %.*s\n", (int)n, tag); + 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) { - printf("Text: %.*s\n", (int)n, text); + 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) +extern void on_attr(const char *name, size_t nname, + const char *val, size_t nval) { - printf("Attribute: name=%.*s", (int)nname, name); + struct attr *a; + struct node *v; - if (val && nval > 0) - printf(", value=%.*s", (int)nval, val); + a = MALLOC(sizeof(struct attr)); + a->key = name; + a->keylen = nname; + a->val = val; + a->vallen = nval; + a->next = NULL; - printf("\n"); + v = *(struct node **)vec_top(&stack); + a->next = v->attrs; + v->attrs = a; } -- cgit v1.2.3