From 0bc77c8c0dbc1737e2909ff5a2d5e5af48b298f7 Mon Sep 17 00:00:00 2001
From: Marvin Borner
Date: Tue, 24 Nov 2020 22:28:40 +0100
Subject: Started HTML rendering

---
 apps/browser.c        |  87 ++---------------------------------
 kernel/features/net.c |  15 ------
 libtxt/Makefile       |   2 +-
 libtxt/html.c         | 124 ++++++++++++++++++++++++++++++++++++++++++++++++--
 libtxt/inc/html.h     |  12 ++++-
 libtxt/xml.c          |   4 --
 res/www/index.html    |   1 +
 7 files changed, 138 insertions(+), 107 deletions(-)

diff --git a/apps/browser.c b/apps/browser.c
index 83292e9..160b626 100644
--- a/apps/browser.c
+++ b/apps/browser.c
@@ -53,80 +53,6 @@ void print_indent(char *buf, u32 n)
 		strcat(buf, "\t");
 }
 
-void parse(void *data, u32 len, char *out)
-{
-	struct xml_token tokens[128];
-	struct xml parser;
-	xml_init(&parser);
-	void *buffer = data;
-	len = strlen(data);
-	out[0] = '\0';
-	enum xml_error err = xml_parse(&parser, buffer, len, tokens, 128);
-
-	if (err != XML_SUCCESS) {
-		printf("\nXML parse error: %d\n", err);
-		return;
-	}
-
-	u32 indent = 0;
-	char name[16] = { 0 };
-	for (u32 i = 0; i < parser.ntokens; i++) {
-		const struct xml_token *token = tokens + i;
-		name[0] = '\0';
-		switch (token->type) {
-		case XML_START_TAG:
-			memcpy(&name, (u8 *)buffer + token->start_pos,
-			       token->end_pos - token->start_pos);
-			name[token->end_pos - token->start_pos] = '\0';
-			if (html_self_closing(name))
-				print_indent(out, indent);
-			else
-				print_indent(out, indent++);
-			strcat(out, name);
-			strcat(out, "\n");
-			break;
-		case XML_END_TAG:
-			print_indent(out, --indent);
-			memcpy(&name, (u8 *)buffer + token->start_pos,
-			       token->end_pos - token->start_pos);
-			name[token->end_pos - token->start_pos] = '\0';
-			strcat(out, name);
-			strcat(out, "/\n");
-			break;
-		case XML_CHARACTER:
-			if (token->end_pos == token->start_pos + 2) {
-				const char *ptr = (char *)buffer + token->start_pos;
-
-				if (ptr[0] == '\r' && ptr[1] == '\n')
-					continue;
-			}
-			memcpy(&name, (u8 *)buffer + token->start_pos,
-			       token->end_pos - token->start_pos);
-			name[token->end_pos - token->start_pos] = '\0';
-			char *clean_name = name;
-			for (u32 j = 0; j < strlen(name); j++) {
-				if (name[j] == ' ' || name[j] == '\n' || name[j] == '\r' ||
-				    name[j] == '\t') {
-					clean_name++;
-				} else {
-					break;
-				}
-			}
-			if (!strlen(clean_name))
-				break;
-			print_indent(out, indent++);
-			strcat(out, clean_name);
-			strcat(out, "\n");
-			indent--;
-			break;
-		default:
-			break;
-		}
-
-		i += token->size;
-	}
-}
-
 void on_submit(void *event, struct element *box)
 {
 	(void)event;
@@ -152,22 +78,20 @@ void on_submit(void *event, struct element *box)
 		ip = dns_request(url);
 	}
 
-	struct element_text_box *l = output->data;
 	struct element_label *c = code_label->data;
 
 	struct socket *socket = net_open(S_TCP);
 	if (socket && net_connect(socket, ip, port, NET_TIMEOUT)) {
 		net_send(socket, query, strlen(query));
 		char buf[4096] = { 0 };
-		char parsed[4096] = { 0 };
-		if (!net_receive(socket, buf, 4096, NET_TIMEOUT))
+		if (!net_receive(socket, buf, 4096, NET_TIMEOUT) ||
+		    !html_render(output, http_data(buf), 4096))
 			return;
-		parse(http_data(buf), 4096, parsed);
-		l->text = parsed[0] ? parsed : http_data(buf);
+
 		c->text = http_code(buf);
 		c->color_fg = status_color(c->text);
 	} else {
-		l->text = strdup("Can't connect to server.");
+		/* l->text = strdup("Can't connect to server."); */
 		c->text = strdup("000");
 		c->color_fg = COLOR_RED;
 	}
@@ -183,8 +107,7 @@ int main()
 	code_label = gui_add_label(root, 0, 0, FONT_24, "000", COLOR_BLACK, COLOR_WHITE);
 	struct element *text_input =
 		gui_add_text_input(root, LABEL_WIDTH, 0, 100, FONT_24, COLOR_WHITE, COLOR_BLACK);
-	output = gui_add_text_box(root, 0, FONT_HEIGHT + 2, 100, 100, FONT_16,
-				  "Enter URL and press Enter :)", COLOR_WHITE, COLOR_BLACK);
+	output = gui_add_container(root, 0, FONT_HEIGHT + 2, 100, 100, COLOR_GREEN);
 
 	text_input->event.on_submit = on_submit;
 
diff --git a/kernel/features/net.c b/kernel/features/net.c
index 3fa28c9..cc46cd4 100644
--- a/kernel/features/net.c
+++ b/kernel/features/net.c
@@ -863,19 +863,4 @@ void net_install(void)
 		loop();
 		return;
 	}
-
-	// Request
-	/* struct socket *socket = net_open(S_TCP); */
-	/* if (socket && net_connect(socket, ip(91, 89, 253, 227), 80)) */
-	/* 	net_send(socket, strdup(http_req), strlen(http_req)); */
-	/* else */
-	/* 	print("Couldn't connect!\n"); */
-
-	// Server // TODO: Serve using sockets
-	/* struct socket *socket2 = net_open(S_TCP); */
-	/* socket2->src_port = 8000; */
-	/* while (socket2->prot.tcp.state != 3) */
-	/* 	; */
-	/* while (socket2->prot.tcp.state == 3) */
-	/* 	net_send(socket2, strdup(http_res), strlen(http_res)); */
 }
diff --git a/libtxt/Makefile b/libtxt/Makefile
index 3536250..087b54c 100644
--- a/libtxt/Makefile
+++ b/libtxt/Makefile
@@ -6,7 +6,7 @@ LD = ccache ../cross/opt/bin/i686-elf-ld
 AR = ccache ../cross/opt/bin/i686-elf-ar
 
 WARNINGS = -Wall -Wextra -pedantic-errors -Wshadow -Wpointer-arith -Wwrite-strings -Wredundant-decls -Wnested-externs -Wno-long-long
-CFLAGS = $(WARNINGS) -nostdlib -nostdinc -fno-builtin -mgeneral-regs-only -std=c99 -m32 -Iinc/ -I../libc/inc/ -fPIE -Duserspace -Ofast
+CFLAGS = $(WARNINGS) -nostdlib -nostdinc -fno-builtin -mgeneral-regs-only -std=c99 -m32 -Iinc/ -I../libc/inc/ -I../libgui/inc/ -fPIE -Duserspace -Ofast
 
 all: libtxt
 
diff --git a/libtxt/html.c b/libtxt/html.c
index 0c07323..171de78 100644
--- a/libtxt/html.c
+++ b/libtxt/html.c
@@ -1,14 +1,19 @@
 // MIT License, Copyright (c) 2020 Marvin Borner
 // HTML parsing is mainly based on the XML parser
 
+#include <assert.h>
+#include <gui.h>
+#include <html.h>
+#include <list.h>
+#include <mem.h>
 #include <print.h>
 #include <str.h>
+#include <xml.h>
 
-int html_self_closing(const char *tag)
+static int is_self_closing(const char *tag)
 {
-	// TODO: Add 'meta'?
-	const char *void_elements[] = { "area",	 "base", "br",	  "col",    "embed", "hr", "img",
-					"input", "link", "param", "source", "track", "wbr" };
+	const char *void_elements[] = { "area",	 "base", "br",	 "col",	  "embed",  "hr",    "img",
+					"input", "link", "meta", "param", "source", "track", "wbr" };
 
 	for (u32 i = 0; i < sizeof(void_elements) / sizeof(void_elements[0]); ++i) {
 		if (!strcmp(void_elements[i], tag))
@@ -16,3 +21,114 @@ int html_self_closing(const char *tag)
 	}
 	return 0;
 }
+
+static struct dom *new_object(const char *tag, struct dom *parent)
+{
+	struct dom *object = malloc(sizeof(*object));
+	object->tag = strdup(tag);
+	object->parent = parent;
+	object->content = NULL;
+	object->children = list_new();
+	return object;
+}
+
+static void print_dom(struct dom *dom, u32 level)
+{
+	struct node *iterator = dom->children->head;
+	while (iterator != NULL) {
+		struct dom *obj = iterator->data;
+		for (u32 i = 0; i < level; i++)
+			print("\t");
+		printf("'%s': '%s'\n", obj->tag, obj->content ? obj->content : "");
+		if (obj->children->head)
+			print_dom(obj, level + 1);
+		iterator = iterator->next;
+	}
+}
+
+static struct dom *generate_dom(char *data, u32 length)
+{
+	struct xml_token tokens[128];
+	struct xml parser;
+	xml_init(&parser);
+	void *buffer = data;
+	enum xml_error err = xml_parse(&parser, buffer, length, tokens, 128);
+
+	if (err != XML_SUCCESS && err != XML_ERROR_BUFFERDRY) {
+		printf("\nXML parse error: %d\n", err);
+		return 0;
+	}
+
+	struct dom *root = new_object("root", NULL);
+	struct dom *current = root;
+
+	char name[256] = { 0 };
+	for (u32 i = 0; i < parser.ntokens; i++) {
+		const struct xml_token *token = tokens + i;
+		name[0] = '\0';
+		switch (token->type) {
+		case XML_START_TAG:
+			memcpy(&name, (u8 *)buffer + token->start_pos,
+			       token->end_pos - token->start_pos);
+			name[token->end_pos - token->start_pos] = '\0';
+			current = new_object(name, current);
+			printf("Adding %s to %s\n", current->tag, current->parent->tag);
+			list_add(current->parent->children, current);
+			break;
+		case XML_END_TAG:
+			memcpy(&name, (u8 *)buffer + token->start_pos,
+			       token->end_pos - token->start_pos);
+			name[token->end_pos - token->start_pos] = '\0';
+			assert(current && !strcmp(name, current->tag));
+			current = current->parent;
+			break;
+		case XML_CHARACTER:
+			if (!current)
+				continue;
+
+			if (token->end_pos == token->start_pos + 2) {
+				const char *ptr = (char *)buffer + token->start_pos;
+
+				if (ptr[0] == '\r' && ptr[1] == '\n')
+					continue;
+			}
+			memcpy(&name, (u8 *)buffer + token->start_pos,
+			       token->end_pos - token->start_pos);
+			name[token->end_pos - token->start_pos] = '\0';
+			char *clean_name = name;
+			for (u32 j = 0; j < strlen(name); j++) {
+				if (name[j] == ' ' || name[j] == '\n' || name[j] == '\r' ||
+				    name[j] == '\t') {
+					clean_name++;
+				} else {
+					break;
+				}
+			}
+			if (!strlen(clean_name))
+				break;
+			current->content = strdup(clean_name);
+			break;
+		default:
+			break;
+		}
+
+		i += token->size;
+	}
+
+	print("GENERATED!\n");
+	print_dom(root, 0);
+	return root;
+}
+
+int html_render_dom(struct element *container, struct dom *dom)
+{
+	(void)container;
+	(void)dom;
+	return 1;
+}
+
+int html_render(struct element *container, char *data, u32 length)
+{
+	struct dom *dom = generate_dom(data, length);
+	return dom && html_render_dom(container, dom);
+}
diff --git a/libtxt/inc/html.h b/libtxt/inc/html.h
index dd2b59f..4eaca0b 100644
--- a/libtxt/inc/html.h
+++ b/libtxt/inc/html.h
@@ -4,6 +4,16 @@
 #ifndef HTML_H
 #define HTML_H
 
-int html_self_closing(const char *tag);
+#include <def.h>
+#include <list.h>
+
+struct dom {
+	char *tag;
+	char *content;
+	struct dom *parent;
+	struct list *children;
+};
+
+int html_render(struct element *container, char *data, u32 length);
 
 #endif
diff --git a/libtxt/xml.c b/libtxt/xml.c
index b92181b..f40b289 100644
--- a/libtxt/xml.c
+++ b/libtxt/xml.c
@@ -485,10 +485,6 @@ enum xml_error xml_parse(struct xml *state, const char *buffer, u32 buffer_lengt
 			state_commit(state, &temp);
 		}
 
-		// TODO: Only for self-closing tags
-		if (end - lt == 0)
-			break;
-
 		if (end - lt < TAG_MINSIZE)
 			return XML_ERROR_BUFFERDRY;
 
diff --git a/res/www/index.html b/res/www/index.html
index 49e1b07..59e08fa 100644
--- a/res/www/index.html
+++ b/res/www/index.html
@@ -8,5 +8,6 @@
     </head>
     <body>
         <h1>This is a test page.</h1>
+        <hr />
     </body>
 </html>
-- 
cgit v1.2.3