summaryrefslogtreecommitdiffstats
path: root/dom.c
diff options
context:
space:
mode:
authorSadeep Madurange <sadeep@asciimx.com>2026-05-24 18:00:38 +0800
committerSadeep Madurange <sadeep@asciimx.com>2026-05-28 15:34:29 +0800
commit95428c41f0ee3ac108cf1a4acfaa67157ad954dc (patch)
tree8565027758cd931f49ebe78738fb41126254b253 /dom.c
parent7aea09077aad335ac32bfd9858ded60ffd4d8a5b (diff)
downloadglacier-95428c41f0ee3ac108cf1a4acfaa67157ad954dc.tar.gz
Build DOM.
Diffstat (limited to 'dom.c')
-rw-r--r--dom.c132
1 files changed, 121 insertions, 11 deletions
diff --git a/dom.c b/dom.c
index a4d75e1..71679bc 100644
--- a/dom.c
+++ b/dom.c
@@ -1,37 +1,147 @@
#include <stdio.h>
+#include <err.h>
+#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;
}