summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSadeep Madurange <sadeep@asciimx.com>2026-05-05 16:05:19 +0800
committerSadeep Madurange <sadeep@asciimx.com>2026-05-05 16:05:19 +0800
commitfd2d93f4a97ab5a3bc18764c353b971b4035ac6a (patch)
tree26c6b13590dfa727a0e5efbddf5f343982d89cbf
parent49304ca2f667b8d82e9346654477c10a27a63931 (diff)
downloadweb-view-fd2d93f4a97ab5a3bc18764c353b971b4035ac6a.tar.gz
Defined basic DOM operations.
-rw-r--r--.gitignore3
-rw-r--r--Makefile4
-rw-r--r--wv_dom.c88
-rw-r--r--wv_dom.h69
-rw-r--r--wv_mem.c10
-rw-r--r--wv_mem.h3
6 files changed, 167 insertions, 10 deletions
diff --git a/.gitignore b/.gitignore
index c0b8288..083c749 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
**/*a.out
**/*.swp
**/*.core
+
+**/*.o
+webview
diff --git a/Makefile b/Makefile
index 7c9c6c3..f10ad4c 100644
--- a/Makefile
+++ b/Makefile
@@ -2,8 +2,8 @@ CC = cc
CFLAGS = -std=c11 -Wall -Wextra -Wpedantic -g -O0
LDFLAGS =
-HDRS = wv_mem.h wv_err.h
-SRCS = wv_mem.c wv_main.c
+HDRS = wv_mem.h wv_err.h wv_dom.h
+SRCS = wv_mem.c wv_dom.c wv_main.c
OBJS = $(SRCS:.c=.o)
TARGET = webview
diff --git a/wv_dom.c b/wv_dom.c
new file mode 100644
index 0000000..ee24e98
--- /dev/null
+++ b/wv_dom.c
@@ -0,0 +1,88 @@
+#include <string.h>
+#include <stdio.h>
+
+#include "wv_dom.h"
+
+wv_ref wv_node_new(struct wv_arena *arena, wv_node_type type)
+{
+ wv_ref ref;
+ struct wv_node *node;
+
+ ref = wv_alloc(arena, sizeof(struct wv_node));
+ node = (struct wv_node *)WV_ADDR(arena, ref);
+ memset(node, 0, sizeof(struct wv_node));
+ node->type = type;
+
+ return ref;
+}
+
+void wv_node_append(struct wv_arena *arena, wv_ref parent_ref,
+ wv_ref child_ref)
+{
+ struct wv_node *p, *c, *last;
+
+ if (!parent_ref || !child_ref)
+ return;
+
+ p = (struct wv_node *)WV_ADDR(arena, parent_ref);
+ c = (struct wv_node *)WV_ADDR(arena, child_ref);
+
+ c->parent = parent_ref;
+
+ if (!p->first_child) {
+ /* This is the parent's only child */
+ p->first_child = child_ref;
+ } else {
+ /* Link to the current tail of the child list */
+ last = (struct wv_node *)WV_ADDR(arena, p->last_child);
+ last->next_sibling = child_ref;
+ c->prev_sibling = p->last_child;
+ }
+
+ p->last_child = child_ref;
+}
+
+void wv_attr_set(struct wv_arena *arena, wv_ref node_ref,
+ wv_ref key_str, wv_ref val_str)
+{
+ wv_ref attr_ref;
+ struct wv_node *n;
+ struct wv_attr *a;
+
+ n = (struct wv_node *)WV_ADDR(arena, node_ref);
+ if (n->type != WV_NODE_ELEMENT) return;
+
+ attr_ref = wv_alloc(arena, sizeof(struct wv_attr));
+ a = (struct wv_attr *)WV_ADDR(arena, attr_ref);
+
+ a->key = key_str;
+ a->val = val_str;
+
+ // Link attribute to the head of the list (prepend)
+ a->next = n->u.element.attr_head;
+ n->u.element.attr_head = attr_ref;
+}
+
+wv_ref wv_attr_get(struct wv_arena *arena, wv_ref node_ref,
+ const char *key_name)
+{
+ wv_ref curr;
+ struct wv_node *n;
+ struct wv_attr *a;
+
+ n = (struct wv_node *)WV_ADDR(arena, node_ref);
+ if (n->type != WV_NODE_ELEMENT)
+ return 0;
+
+ curr = n->u.element.attr_head;
+ while (curr != 0) {
+ a = (struct wv_attr *)WV_ADDR(arena, curr);
+ const char *attr_key = (const char *)WV_ADDR(arena, a->key);
+ if (strcmp(attr_key, key_name) == 0)
+ return a->val;
+ curr = a->next;
+ }
+
+ return 0;
+}
+
diff --git a/wv_dom.h b/wv_dom.h
new file mode 100644
index 0000000..9a2c281
--- /dev/null
+++ b/wv_dom.h
@@ -0,0 +1,69 @@
+#ifndef WV_DOM_H
+#define WV_DOM_H
+
+#include "wv_mem.h"
+
+typedef enum {
+ WV_TAG_UNKNOWN = 0,
+ WV_TAG_DOCUMENT,
+ WV_TAG_HTML,
+ WV_TAG_HEAD,
+ WV_TAG_META,
+ WV_TAG_TITLE,
+ WV_TAG_LINK,
+ WV_TAG_BODY,
+ WV_TAG_HEADER,
+ WV_TAG_H1,
+ WV_TAG_A,
+ WV_TAG_ARTICLE,
+ WV_TAG_UL,
+ WV_TAG_LI,
+ WV_TAG_TIME,
+ WV_TAG_FOOTER,
+ WV_TAG_P
+} wv_tag_id;
+
+typedef enum {
+ WV_NODE_DOCUMENT,
+ WV_NODE_ELEMENT,
+ WV_NODE_TEXT
+} wv_node_type;
+
+struct wv_attr {
+ wv_ref key; /* E.g., "href" */
+ wv_ref val; /* E.g., "/log/vcs-1/" */
+ wv_ref next; /* Next attribute in the list */
+};
+
+struct wv_node {
+ wv_node_type type;
+
+ wv_ref parent;
+ wv_ref first_child;
+ wv_ref last_child;
+ wv_ref prev_sibling;
+ wv_ref next_sibling;
+
+ union {
+ struct {
+ wv_tag_id tag_id;
+ wv_ref attr_head;
+ } element;
+
+ struct {
+ wv_ref str;
+ size_t len;
+ } text;
+ } u;
+};
+
+/* DOM operations */
+wv_ref wv_node_new(struct wv_arena *arena, wv_node_type type);
+void wv_node_append(struct wv_arena *arena, wv_ref parent, wv_ref child);
+
+/* Attribute operations */
+wv_ref wv_attr_get(struct wv_arena *arena, wv_ref node_ref, const char *key_name);
+void wv_attr_set(struct wv_arena *arena, wv_ref node_ref, wv_ref key_str, wv_ref val_str);
+
+#endif /* WV_DOM_H */
+
diff --git a/wv_mem.c b/wv_mem.c
index 1f6542b..7bf54d6 100644
--- a/wv_mem.c
+++ b/wv_mem.c
@@ -20,11 +20,11 @@ struct wv_arena *wv_arena_create(size_t n)
n = WV_ARENA_MIN_SIZE;
arena = malloc(sizeof(struct wv_arena));
- if (arena == NULL)
+ if (!arena)
err(1, "malloc arena struct");
arena->buf = malloc(n);
- if (arena->buf == NULL)
+ if (!arena->buf)
err(1, "malloc arena buffer");
arena->size = n;
@@ -59,7 +59,7 @@ wv_ref wv_alloc(struct wv_arena *arena, size_t n)
}
new_buf = realloc(arena->buf, new_size);
- if (new_buf == NULL)
+ if (!new_buf)
err(1, "realloc arena failed at %zu bytes", new_size);
arena->buf = new_buf;
@@ -73,7 +73,7 @@ wv_ref wv_alloc(struct wv_arena *arena, size_t n)
void wv_arena_reset(struct wv_arena *arena)
{
- if (arena == NULL)
+ if (!arena)
return;
memset(arena->buf, 0, arena->offset);
@@ -82,7 +82,7 @@ void wv_arena_reset(struct wv_arena *arena)
void wv_arena_destroy(struct wv_arena *arena)
{
- if (arena == NULL)
+ if (!arena)
return;
free(arena->buf);
diff --git a/wv_mem.h b/wv_mem.h
index 9d23ae8..dc95c7c 100644
--- a/wv_mem.h
+++ b/wv_mem.h
@@ -7,9 +7,6 @@
/* Relative offset into the arena */
typedef uint32_t wv_ref;
-/* 0 is our 'NULL' */
-#define WV_REF_NULL 0
-
/* Resolve a ref into a memory address */
#define WV_ADDR(arena, ref) ((void *)((arena)->buf + (ref)))