aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--apps/browser.c65
-rw-r--r--apps/server.c3
-rw-r--r--libc/inc/mem.h1
-rw-r--r--libc/mem.c12
-rw-r--r--libgui/gfx.c3
-rw-r--r--libtxt/Makefile2
-rw-r--r--libtxt/inc/xml.h51
-rw-r--r--libtxt/xml.c512
-rw-r--r--res/www/index.html2
10 files changed, 645 insertions, 7 deletions
diff --git a/README.md b/README.md
index 6e41f56..8a0f9da 100644
--- a/README.md
+++ b/README.md
@@ -91,3 +91,4 @@ Resources:
Libraries:
- [upng (heavily modified lodepng)](https://github.com/elanthis/upng) - [ZLIB License](https://github.com/lvandeve/lodepng/blob/7fdcc96a5e5864eee72911c3ca79b1d9f0d12292/LICENSE)
+- [sxml](https://github.com/capmar/sxml) - [Unlicense License](https://github.com/capmar/sxml/blob/91176b4c62ef7c6342804e02fc440b2e82326469/UNLICENSE)
diff --git a/apps/browser.c b/apps/browser.c
index bdc7b14..179acb1 100644
--- a/apps/browser.c
+++ b/apps/browser.c
@@ -9,6 +9,7 @@
#include <net.h>
#include <print.h>
#include <str.h>
+#include <xml.h>
#define WIDTH 640
#define HEIGHT 400
@@ -45,6 +46,62 @@ u32 status_color(char *http_code)
return c;
}
+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);
+ enum xml_error err = xml_parse(&parser, buffer, len, tokens, 128);
+ printf("%s\n", data);
+ if (err != XML_SUCCESS) {
+ printf("ERROR %d\n", err);
+ return;
+ }
+
+ *out[0] = '\0';
+
+ u32 pos = 0;
+ 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:
+ for (u32 j = 0; j < indent; j++)
+ strcat(*out, "\t");
+ indent++;
+ memcpy(&name, (u8 *)buffer + token->start_pos,
+ token->end_pos - token->start_pos);
+ name[token->end_pos - token->start_pos] = '\0';
+ printf("%s\n", name);
+ print("START TAG\n");
+ strcat(*out, name);
+ strcat(*out, "\n");
+ break;
+ case XML_END_TAG:
+ indent--;
+ for (u32 j = 0; j < indent; j++)
+ strcat(*out, "\t");
+ memcpy(&name, (u8 *)buffer + token->start_pos,
+ token->end_pos - token->start_pos);
+ name[token->end_pos - token->start_pos] = '\0';
+ print("END TAG\n");
+ strcat(*out, name);
+ strcat(*out, "/\n");
+ break;
+ default:
+ break;
+ }
+
+ i += token->size;
+ }
+ printf("%s\n", *out);
+}
+
void on_submit(void *event, struct element *box)
{
(void)event;
@@ -66,11 +123,13 @@ void on_submit(void *event, struct element *box)
struct element_label *c = code_label->data;
struct socket *socket = net_open(S_TCP);
- if (socket && net_connect(socket, ip, 80)) {
+ if (socket && net_connect(socket, ip, 8000)) {
net_send(socket, query, strlen(query));
char buf[4096] = { 0 };
+ char parsed[4096] = { 0 };
net_receive(socket, buf, 4096);
- l->text = http_data(buf);
+ parse(http_data(buf), 4096, (char **)&parsed);
+ l->text = http_data(parsed);
c->text = http_code(buf);
c->color_fg = status_color(c->text);
} else {
@@ -90,8 +149,10 @@ 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);
+ memcpy(((struct element_text_input *)text_input->data)->text, strdup("127.0.0.1"), 10);
output = gui_add_text_box(root, 0, FONT_HEIGHT + 2, 100, 100, FONT_16,
"Enter URL and press Enter :)", COLOR_WHITE, COLOR_BLACK);
+ gui_sync(root, text_input);
text_input->event.on_submit = on_submit;
diff --git a/apps/server.c b/apps/server.c
index fe2c17c..4ab3369 100644
--- a/apps/server.c
+++ b/apps/server.c
@@ -7,9 +7,8 @@
#include <str.h>
#define PORT 8000
-#define FILE "/res/www/index.html"
#define PATH "/res/www"
-#define ERROR "/res/www/404.html"
+#define ERROR PATH "/404.html"
int main()
{
diff --git a/libc/inc/mem.h b/libc/inc/mem.h
index 8977a48..964b24b 100644
--- a/libc/inc/mem.h
+++ b/libc/inc/mem.h
@@ -22,6 +22,7 @@ void free(void *ptr);
void *memcpy(void *dest, const void *src, u32 n);
void *memset(void *dest, int val, u32 n);
+void *memchr(void *src, int c, u32 n);
int memcmp(const void *s1, const void *s2, u32 n);
#endif
diff --git a/libc/mem.c b/libc/mem.c
index 2fde00b..c81a13f 100644
--- a/libc/mem.c
+++ b/libc/mem.c
@@ -43,6 +43,18 @@ void *memset(void *dest, int val, u32 n)
return dest;
}
+void *memchr(void *src, int c, u32 n)
+{
+ const u8 *s = (const u8 *)src;
+
+ while (n-- > 0) {
+ if (*s == c)
+ return (void *)s;
+ s++;
+ }
+ return NULL;
+}
+
int memcmp(const void *s1, const void *s2, u32 n)
{
const u8 *a = (const u8 *)s1;
diff --git a/libgui/gfx.c b/libgui/gfx.c
index 3d3785e..6d54550 100644
--- a/libgui/gfx.c
+++ b/libgui/gfx.c
@@ -121,7 +121,10 @@ void gfx_write(struct context *ctx, int x, int y, enum font_type font_type, u32
cnt = 0;
} else if (text[i] == '\n') {
cnt = 0;
+ x = 0;
y += font->height;
+ } else if (text[i] == '\t') {
+ x += 4 * font->width;
} else {
// TODO: Overflow on single line input
if ((cnt + 1) * font->width > ctx->width) {
diff --git a/libtxt/Makefile b/libtxt/Makefile
index 436cb3b..543a90d 100644
--- a/libtxt/Makefile
+++ b/libtxt/Makefile
@@ -1,6 +1,6 @@
# MIT License, Copyright (c) 2020 Marvin Borner
-COBJS = keymap.o
+COBJS = keymap.o xml.o
CC = ccache ../cross/opt/bin/i686-elf-gcc
LD = ccache ../cross/opt/bin/i686-elf-ld
AR = ccache ../cross/opt/bin/i686-elf-ar
diff --git a/libtxt/inc/xml.h b/libtxt/inc/xml.h
new file mode 100644
index 0000000..43a8005
--- /dev/null
+++ b/libtxt/inc/xml.h
@@ -0,0 +1,51 @@
+// Inspired by sxml (capmar)
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef XML_H
+#define XML_H
+
+#include <def.h>
+
+enum xml_error {
+ XML_ERROR_INVALID = -1,
+ XML_SUCCESS = 0,
+ XML_ERROR_BUFFERDRY = 1,
+ XML_ERROR_TOKENSFULL = 2
+};
+
+struct xml_token {
+ u16 type;
+ u16 size;
+ u32 start_pos;
+ u32 end_pos;
+};
+
+struct xml_args {
+ const char *buffer;
+ u32 buffer_length;
+ struct xml_token *tokens;
+ u32 num_tokens;
+};
+
+enum xml_type {
+ XML_START_TAG,
+ XML_END_TAG,
+ XML_CHARACTER,
+ XML_CDATA,
+ XML_INSTRUCTION,
+ XML_DOCTYPE,
+ XML_COMMENT
+};
+
+struct xml {
+ u32 buffer_pos;
+ u32 ntokens;
+ u32 tag_level;
+};
+
+enum xml_error xml_parse(struct xml *parser, const char *buffer, u32 buffer_length,
+ struct xml_token *tokens, u32 num_tokens);
+
+void xml_init(struct xml *parser);
+
+#endif
diff --git a/libtxt/xml.c b/libtxt/xml.c
new file mode 100644
index 0000000..3a69ea7
--- /dev/null
+++ b/libtxt/xml.c
@@ -0,0 +1,512 @@
+// Inspired by sxml (capmar)
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#include <assert.h>
+#include <mem.h>
+#include <str.h>
+#include <xml.h>
+
+static const char *str_findchr(const char *start, const char *end, int c)
+{
+ const char *it;
+
+ assert(start <= end);
+ assert(0 <= c && c <= 127);
+
+ it = (const char *)memchr((void *)start, c, end - start);
+ return (it != NULL) ? it : end;
+}
+
+static const char *str_findstr(const char *start, const char *end, const char *needle)
+{
+ u32 needlelen;
+ int first;
+ assert(start <= end);
+
+ needlelen = strlen(needle);
+ assert(0 < needlelen);
+ first = (u8)needle[0];
+
+ while (start + needlelen <= end) {
+ const char *it =
+ (const char *)memchr((void *)start, first, (end - start) - (needlelen - 1));
+ if (it == NULL)
+ break;
+
+ if (memcmp(it, needle, needlelen) == 0)
+ return it;
+
+ start = it + 1;
+ }
+
+ return end;
+}
+
+static int str_starts_with(const char *start, const char *end, const char *prefix)
+{
+ long nbytes;
+ assert(start <= end);
+
+ nbytes = strlen(prefix);
+ if (end - start < nbytes)
+ return 0;
+
+ return memcmp(prefix, start, nbytes) == 0;
+}
+
+static int white_space(int c)
+{
+ switch (c) {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ return 1;
+ }
+
+ return 0;
+}
+
+static int name_start_char(int c)
+{
+ if (0x80 <= c)
+ return 1;
+
+ return c == ':' || ('A' <= c && c <= 'Z') || c == '_' || ('a' <= c && c <= 'z');
+}
+
+static int name_char(int c)
+{
+ return name_start_char(c) || c == '-' || c == '.' || ('0' <= c && c <= '9') || c == 0xB7 ||
+ (0x0300 <= c && c <= 0x036F) || (0x203F <= c && c <= 0x2040);
+}
+
+#define is_space(c) (white_space(((u8)(c))))
+#define is_alpha(c) (name_start_char(((u8)(c))))
+#define is_alnum(c) (name_char(((u8)(c))))
+
+static const char *str_ltrim(const char *start, const char *end)
+{
+ const char *it;
+ assert(start <= end);
+
+ for (it = start; it != end && is_space(*it); it++)
+ ;
+
+ return it;
+}
+
+static const char *str_rtrim(const char *start, const char *end)
+{
+ const char *it, *prev;
+ assert(start <= end);
+
+ for (it = end; start != it; it = prev) {
+ prev = it - 1;
+ if (!is_space(*prev))
+ return it;
+ }
+
+ return start;
+}
+
+static const char *str_find_notalnum(const char *start, const char *end)
+{
+ const char *it;
+ assert(start <= end);
+
+ for (it = start; it != end && is_alnum(*it); it++)
+ ;
+
+ return it;
+}
+
+#define buffer_from_offset(args, i) ((args)->buffer + (i))
+#define buffer_tooffset(args, ptr) (unsigned)((ptr) - (args)->buffer)
+#define buffer_getend(args) ((args)->buffer + (args)->buffer_length)
+
+static int state_push_token(struct xml *state, struct xml_args *args, enum xml_type type,
+ const char *start, const char *end)
+{
+ struct xml_token *token;
+ u32 i = state->ntokens++;
+ if (args->num_tokens < state->ntokens)
+ return 0;
+
+ token = &args->tokens[i];
+ token->type = type;
+ token->start_pos = buffer_tooffset(args, start);
+ token->end_pos = buffer_tooffset(args, end);
+ token->size = 0;
+
+ switch (type) {
+ case XML_START_TAG:
+ state->tag_level++;
+ break;
+
+ case XML_END_TAG:
+ assert(0 < state->tag_level);
+ state->tag_level--;
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+static enum xml_error state_set_pos(struct xml *state, const struct xml_args *args, const char *ptr)
+{
+ state->buffer_pos = buffer_tooffset(args, ptr);
+ return (state->ntokens <= args->num_tokens) ? XML_SUCCESS : XML_ERROR_TOKENSFULL;
+}
+
+#define state_commit(dest, src) memcpy((dest), (src), sizeof(struct xml))
+
+#define XML_ERROR_STRICT XML_ERROR_INVALID
+#define ENTITY_MAXLEN 8
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static enum xml_error parse_characters(struct xml *state, struct xml_args *args, const char *end)
+{
+ const char *start = buffer_from_offset(args, state->buffer_pos);
+ const char *limit, *colon, *ampr = str_findchr(start, end, '&');
+ assert(end <= buffer_getend(args));
+
+ if (ampr != start)
+ state_push_token(state, args, XML_CHARACTER, start, ampr);
+
+ if (ampr == end)
+ return state_set_pos(state, args, ampr);
+
+ limit = MIN(ampr + ENTITY_MAXLEN, end);
+ colon = str_findchr(ampr, limit, ';');
+ if (colon == limit)
+ return (limit == end) ? XML_ERROR_BUFFERDRY : XML_ERROR_INVALID;
+
+ start = colon + 1;
+ state_push_token(state, args, XML_CHARACTER, ampr, start);
+ return state_set_pos(state, args, start);
+}
+
+static enum xml_error parse_attrvalue(struct xml *state, struct xml_args *args, const char *end)
+{
+ while (buffer_from_offset(args, state->buffer_pos) != end) {
+ enum xml_error err = parse_characters(state, args, end);
+ if (err != XML_SUCCESS)
+ return err;
+ }
+
+ return XML_SUCCESS;
+}
+
+static enum xml_error parse_attributes(struct xml *state, struct xml_args *args)
+{
+ const char *start = buffer_from_offset(args, state->buffer_pos);
+ const char *end = buffer_getend(args);
+ const char *name = str_ltrim(start, end);
+
+ u32 ntokens = state->ntokens;
+ assert(0 < ntokens);
+
+ while (name != end && is_alpha(*name)) {
+ const char *eq, *space, *quot, *value;
+ enum xml_error err;
+
+ eq = str_findchr(name, end, '=');
+ if (eq == end)
+ return XML_ERROR_BUFFERDRY;
+
+ space = str_rtrim(name, eq);
+ state_push_token(state, args, XML_CDATA, name, space);
+
+ quot = str_ltrim(eq + 1, end);
+ if (quot == end)
+ return XML_ERROR_BUFFERDRY;
+ else if (*quot != '\'' && *quot != '"')
+ return XML_ERROR_INVALID;
+
+ value = quot + 1;
+ quot = str_findchr(value, end, *quot);
+ if (quot == end)
+ return XML_ERROR_BUFFERDRY;
+
+ state_set_pos(state, args, value);
+ err = parse_attrvalue(state, args, quot);
+ if (err != XML_SUCCESS)
+ return err;
+
+ name = str_ltrim(quot + 1, end);
+ }
+
+ {
+ struct xml_token *token = args->tokens + (ntokens - 1);
+ token->size = (u16)(state->ntokens - ntokens);
+ }
+
+ return state_set_pos(state, args, name);
+}
+
+#define TAG_LEN(str) (sizeof(str) - 1)
+#define TAG_MINSIZE 3
+
+static enum xml_error parse_comment(struct xml *state, struct xml_args *args)
+{
+ static const char START_TAG[] = "<!--";
+ static const char END_TAG[] = "-->";
+
+ const char *dash;
+ const char *start = buffer_from_offset(args, state->buffer_pos);
+ const char *end = buffer_getend(args);
+ if (end - start < (int)TAG_LEN(START_TAG))
+ return XML_ERROR_BUFFERDRY;
+
+ if (!str_starts_with(start, end, START_TAG))
+ return XML_ERROR_INVALID;
+
+ start += TAG_LEN(START_TAG);
+ dash = str_findstr(start, end, END_TAG);
+ if (dash == end)
+ return XML_ERROR_BUFFERDRY;
+
+ state_push_token(state, args, XML_COMMENT, start, dash);
+ return state_set_pos(state, args, dash + TAG_LEN(END_TAG));
+}
+
+static enum xml_error parse_instruction(struct xml *state, struct xml_args *args)
+{
+ static const char START_TAG[] = "<?";
+ static const char END_TAG[] = "?>";
+
+ enum xml_error err;
+ const char *quest, *space;
+ const char *start = buffer_from_offset(args, state->buffer_pos);
+ const char *end = buffer_getend(args);
+ assert(TAG_MINSIZE <= end - start);
+
+ if (!str_starts_with(start, end, START_TAG))
+ return XML_ERROR_INVALID;
+
+ start += TAG_LEN(START_TAG);
+ space = str_find_notalnum(start, end);
+ if (space == end)
+ return XML_ERROR_BUFFERDRY;
+
+ state_push_token(state, args, XML_INSTRUCTION, start, space);
+
+ state_set_pos(state, args, space);
+ err = parse_attributes(state, args);
+ if (err != XML_SUCCESS)
+ return err;
+
+ quest = buffer_from_offset(args, state->buffer_pos);
+ if (end - quest < (int)TAG_LEN(END_TAG))
+ return XML_ERROR_BUFFERDRY;
+
+ if (!str_starts_with(quest, end, END_TAG))
+ return XML_ERROR_INVALID;
+
+ return state_set_pos(state, args, quest + TAG_LEN(END_TAG));
+}
+
+static enum xml_error parse_doctype(struct xml *state, struct xml_args *args)
+{
+ static const char START_TAG[] = "<!DOCTYPE";
+ static const char END_TAG[] = "]>";
+
+ const char *bracket;
+ const char *start = buffer_from_offset(args, state->buffer_pos);
+ const char *end = buffer_getend(args);
+ if (end - start < (int)TAG_LEN(START_TAG))
+ return XML_ERROR_BUFFERDRY;
+
+ if (!str_starts_with(start, end, START_TAG))
+ return XML_ERROR_BUFFERDRY;
+
+ start += TAG_LEN(START_TAG);
+ bracket = str_findstr(start, end, END_TAG);
+ if (bracket == end)
+ return XML_ERROR_BUFFERDRY;
+
+ state_push_token(state, args, XML_DOCTYPE, start, bracket);
+ return state_set_pos(state, args, bracket + TAG_LEN(END_TAG));
+}
+
+static enum xml_error parse_start(struct xml *state, struct xml_args *args)
+{
+ enum xml_error err;
+ const char *gt, *name, *space;
+ const char *start = buffer_from_offset(args, state->buffer_pos);
+ const char *end = buffer_getend(args);
+ assert(TAG_MINSIZE <= end - start);
+
+ if (!(start[0] == '<' && is_alpha(start[1])))
+ return XML_ERROR_INVALID;
+
+ name = start + 1;
+ space = str_find_notalnum(name, end);
+ if (space == end)
+ return XML_ERROR_BUFFERDRY;
+
+ state_push_token(state, args, XML_START_TAG, name, space);
+
+ state_set_pos(state, args, space);
+ err = parse_attributes(state, args);
+ if (err != XML_SUCCESS)
+ return err;
+
+ gt = buffer_from_offset(args, state->buffer_pos);
+
+ if (gt != end && *gt == '/') {
+ state_push_token(state, args, XML_END_TAG, name, space);
+ gt++;
+ }
+
+ if (gt == end)
+ return XML_ERROR_BUFFERDRY;
+
+ if (*gt != '>')
+ return XML_ERROR_INVALID;
+
+ return state_set_pos(state, args, gt + 1);
+}
+
+static enum xml_error parse_end(struct xml *state, struct xml_args *args)
+{
+ const char *gt, *space;
+ const char *start = buffer_from_offset(args, state->buffer_pos);
+ const char *end = buffer_getend(args);
+ assert(TAG_MINSIZE <= end - start);
+
+ if (!(str_starts_with(start, end, "</") && is_alpha(start[2])))
+ return XML_ERROR_INVALID;
+
+ start += 2;
+ gt = str_findchr(start, end, '>');
+ if (gt == end)
+ return XML_ERROR_BUFFERDRY;
+
+ space = str_find_notalnum(start, gt);
+ if (str_ltrim(space, gt) != gt)
+ return XML_ERROR_STRICT;
+
+ state_push_token(state, args, XML_END_TAG, start, space);
+ return state_set_pos(state, args, gt + 1);
+}
+
+static enum xml_error parse_cdata(struct xml *state, struct xml_args *args)
+{
+ static const char START_TAG[] = "<![CDATA[";
+ static const char END_TAG[] = "]]>";
+
+ const char *bracket;
+ const char *start = buffer_from_offset(args, state->buffer_pos);
+ const char *end = buffer_getend(args);
+ if (end - start < (int)TAG_LEN(START_TAG))
+ return XML_ERROR_BUFFERDRY;
+
+ if (!str_starts_with(start, end, START_TAG))
+ return XML_ERROR_INVALID;
+
+ start += TAG_LEN(START_TAG);
+ bracket = str_findstr(start, end, END_TAG);
+ if (bracket == end)
+ return XML_ERROR_BUFFERDRY;
+
+ state_push_token(state, args, XML_CDATA, start, bracket);
+ return state_set_pos(state, args, bracket + TAG_LEN(END_TAG));
+}
+
+void xml_init(struct xml *state)
+{
+ state->buffer_pos = 0;
+ state->ntokens = 0;
+ state->tag_level = 0;
+}
+
+#define ROOT_FOUND(state) (0 < (state)->tag_level)
+#define ROOT_PARSED(state) ((state)->tag_level == 0)
+
+enum xml_error xml_parse(struct xml *state, const char *buffer, u32 buffer_length,
+ struct xml_token tokens[], u32 num_tokens)
+{
+ struct xml temp = *state;
+ const char *end = buffer + buffer_length;
+
+ struct xml_args args;
+ args.buffer = buffer;
+ args.buffer_length = buffer_length;
+ args.tokens = tokens;
+ args.num_tokens = num_tokens;
+
+ while (!ROOT_FOUND(&temp)) {
+ enum xml_error err;
+ const char *start = buffer_from_offset(&args, temp.buffer_pos);
+ const char *lt = str_ltrim(start, end);
+ state_set_pos(&temp, &args, lt);
+ state_commit(state, &temp);
+
+ if (end - lt < TAG_MINSIZE)
+ return XML_ERROR_BUFFERDRY;
+
+ if (*lt != '<')
+ return XML_ERROR_INVALID;
+
+ switch (lt[1]) {
+ case '?':
+ err = parse_instruction(&temp, &args);
+ break;
+ case '!':
+ err = parse_doctype(&temp, &args);
+ break;
+ default:
+ err = parse_start(&temp, &args);
+ break;
+ }
+
+ if (err != XML_SUCCESS)
+ return err;
+
+ state_commit(state, &temp);
+ }
+
+ while (!ROOT_PARSED(&temp)) {
+ enum xml_error err;
+ const char *start = buffer_from_offset(&args, temp.buffer_pos);
+ const char *lt = str_findchr(start, end, '<');
+ while (buffer_from_offset(&args, temp.buffer_pos) != lt) {
+ err = parse_characters(&temp, &args, lt);
+ if (err != XML_SUCCESS)
+ return err;
+
+ state_commit(state, &temp);
+ }
+
+ if (end - lt < TAG_MINSIZE)
+ return XML_ERROR_BUFFERDRY;
+
+ switch (lt[1]) {
+ case '?':
+ err = parse_instruction(&temp, &args);
+ break;
+ case '/':
+ err = parse_end(&temp, &args);
+ break;
+ case '!':
+ err = (lt[2] == '-') ? parse_comment(&temp, &args) :
+ parse_cdata(&temp, &args);
+ break;
+ default:
+ err = parse_start(&temp, &args);
+ break;
+ }
+
+ if (err != XML_SUCCESS)
+ return err;
+
+ state_commit(state, &temp);
+ }
+
+ return XML_SUCCESS;
+}
diff --git a/res/www/index.html b/res/www/index.html
index 49e1b07..15a9a7b 100644
--- a/res/www/index.html
+++ b/res/www/index.html
@@ -1,5 +1,3 @@
-<!DOCTYPE html>
-<!-- MIT License, Copyright (c) 2020 Marvin Borner -->
<html>
<head>
<meta charset="UTF-8" />