diff --git a/apps/markup.c b/apps/markup.c new file mode 100644 index 00000000..0f12c0e9 --- /dev/null +++ b/apps/markup.c @@ -0,0 +1,192 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * marked up text demo + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Pointer to graphics memory */ +static yutani_t * yctx; +static yutani_window_t * window = NULL; +static gfx_context_t * ctx = NULL; + +static int width = 500; +static int height = 500; + +static int left = 200; +static int top = 200; + +static int size = 16; + +static void decors() { + render_decorations(window, ctx, "Markup Demo"); +} + +static int cursor_x = 0; +static int state = 0; + +static int parser_open(struct markup_state * self, void * user, struct markup_tag * tag) { + if (!strcmp(tag->name, "b")) { + state = 1; /* State append bold */ + } + markup_free_tag(tag); + return 0; +} + +static int parser_close(struct markup_state * self, void * user, char * tag_name) { + if (!strcmp(tag_name, "b")) { + state = 0; /* State pop bold */ + } + return 0; +} + +static int parser_data(struct markup_state * self, void * user, char * data) { + cursor_x += draw_sdf_string(ctx, cursor_x, 30, data, size, rgb(0,0,0), state ? SDF_FONT_BOLD : SDF_FONT_THIN); + return 0; +} + + +void redraw() { + draw_fill(ctx, rgb(255,255,255)); + + decors(); + + struct markup_state * parser = markup_init(NULL, parser_open, parser_close, parser_data); + + char * str = "This is a test with data at the end"; + cursor_x = 20; + state = 0; + + while (*str) { + //fprintf(stderr, "Parser state in: %d Character: %c\n", parser->state, *str); + if (markup_parse(parser, *str++)) { + fprintf(stderr, "bailing\n"); + return; + } + } + markup_finish(parser); + +} + +void resize_finish(int w, int h) { + yutani_window_resize_accept(yctx, window, w, h); + reinit_graphics_yutani(ctx, window); + + struct decor_bounds bounds; + decor_get_bounds(window, &bounds); + + width = w - bounds.left_width - bounds.right_width; + height = h - bounds.top_height - bounds.bottom_height; + + redraw(); + + yutani_window_resize_done(yctx, window); + yutani_flip(yctx, window); +} + + +int main(int argc, char * argv[]) { + + yctx = yutani_init(); + if (!yctx) { + fprintf(stderr, "%s: failed to connect to compositor\n", argv[0]); + return 1; + } + init_decorations(); + + struct decor_bounds bounds; + decor_get_bounds(NULL, &bounds); + + window = yutani_window_create(yctx, width + bounds.width, height + bounds.height); + yutani_window_move(yctx, window, left, top); + + yutani_window_advertise_icon(yctx, window, "SDF Demo", "sdf"); + + ctx = init_graphics_yutani(window); + + redraw(); + yutani_flip(yctx, window); + + int playing = 1; + while (playing) { + yutani_msg_t * m = yutani_poll(yctx); + if (m) { + switch (m->type) { + case YUTANI_MSG_KEY_EVENT: + { + struct yutani_msg_key_event * ke = (void*)m->data; + if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') { + playing = 0; + } else if (ke->event.action == KEY_ACTION_DOWN) { + if (size <= 20) { + size += 1; + } else if (size > 20) { + size += 5; + } + if (size > 100) { + size = 1; + } + redraw(); + yutani_flip(yctx,window); + } + } + break; + case YUTANI_MSG_WINDOW_FOCUS_CHANGE: + { + struct yutani_msg_window_focus_change * wf = (void*)m->data; + yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + if (win) { + win->focused = wf->focused; + decors(); + yutani_flip(yctx, window); + } + } + break; + case YUTANI_MSG_RESIZE_OFFER: + { + struct yutani_msg_window_resize * wr = (void*)m->data; + resize_finish(wr->width, wr->height); + } + break; + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + { + int result = decor_handle_event(yctx, m); + switch (result) { + case DECOR_CLOSE: + playing = 0; + break; + default: + /* Other actions */ + break; + } + } + break; + case YUTANI_MSG_SESSION_END: + playing = 0; + break; + default: + break; + } + } + free(m); + } + + yutani_close(yctx, window); + + return 0; +} + diff --git a/base/usr/include/toaru/markup.h b/base/usr/include/toaru/markup.h new file mode 100644 index 00000000..fb763c8c --- /dev/null +++ b/base/usr/include/toaru/markup.h @@ -0,0 +1,23 @@ +#pragma once + +#include <_cheader.h> +#include + +_Begin_C_Header + +struct markup_tag { + char * name; + hashmap_t * options; +}; + +struct markup_state; +typedef int (*markup_callback_tag_open)(struct markup_state * self, void * user, struct markup_tag * tag); +typedef int (*markup_callback_tag_close)(struct markup_state * self, void * user, char * tag_name); +typedef int (*markup_callback_data)(struct markup_state * self, void * user, char * data); + +extern struct markup_state * markup_init(void * user, markup_callback_tag_open open, markup_callback_tag_close close, markup_callback_data data); +extern int markup_free_tag(struct markup_tag * tag); +extern int markup_parse(struct markup_state * state, char c); +extern int markup_finish(struct markup_state * state); + +_End_C_Header diff --git a/lib/markup.c b/lib/markup.c new file mode 100644 index 00000000..19ee2ffc --- /dev/null +++ b/lib/markup.c @@ -0,0 +1,208 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * Markup parser. + */ +#include +#include + +struct markup_state { + int state; + void * user; + markup_callback_tag_open callback_tag_open; + markup_callback_tag_close callback_tag_close; + markup_callback_data callback_data; + + /* Private stuff */ + struct markup_tag tag; + size_t len; + char data[64]; + char * attr; +}; + +struct markup_state * markup_init(void * user, markup_callback_tag_open open, markup_callback_tag_close close, markup_callback_data data) { + struct markup_state * out = malloc(sizeof(out)); + + out->state = 0; + out->user = user; + out->len = 0; + + out->callback_tag_open = open; + out->callback_tag_close = close; + out->callback_data = data; + + return out; +} + +static void _dump_buffer(struct markup_state * state) { + if (state->len) { + state->data[state->len] = '\0'; + state->callback_data(state, state->user, state->data); + state->data[0] = '\0'; + state->len = 0; + } +} + +static void _finish_name(struct markup_state * state) { + state->data[state->len] = '\0'; + state->tag.name = strdup(state->data); + state->tag.options = hashmap_create(5); + state->data[0] = '\0'; + state->len = 0; + state->state = 2; +} + +static void _finish_close(struct markup_state * state) { + state->data[state->len] = '\0'; + state->callback_tag_close(state, state->user, state->data); + state->data[0] = '\0'; + state->len = 0; + state->state = 0; +} + +static void _finish_tag(struct markup_state * state) { + state->callback_tag_open(state, state->user, &state->tag); + state->state = 0; +} + +static void _finish_bare_attr(struct markup_state * state) { + state->data[state->len] = '\0'; + hashmap_set(state->tag.options, state->data, strdup(state->data)); + state->data[0] = '\0'; + state->len = 0; +} + +static void _finish_attr(struct markup_state * state) { + state->data[state->len] = '\0'; + state->attr = strdup(state->data); + state->data[0] = '\0'; + state->len = 0; + state->state = 4; +} + +static void _finish_attr_value(struct markup_state * state) { + state->data[state->len] = '\0'; + hashmap_set(state->tag.options, state->attr, strdup(state->data)); + free(state->attr); + state->data[0] = '\0'; + state->len = 0; + state->state = 2; +} + +int markup_free_tag(struct markup_tag * tag) { + free(tag->name); + list_t * keys = hashmap_keys(tag->options); + if (keys->length) { + foreach(node, keys) { + free(hashmap_get(tag->options, node->value)); + } + } + list_free(keys); + free(keys); + hashmap_free(tag->options); + return 0; +} + +int markup_parse(struct markup_state * state, char c) { + switch (state->state) { + case 0: /* STATE_NORMAL */ + if (state->len == 63) { + _dump_buffer(state); + } + switch (c) { + case '<': + _dump_buffer(state); + state->state = 1; + return 0; + default: + state->data[state->len] = c; + state->len++; + return 0; + } + break; + case 1: /* STATE_TAG_OPEN */ + switch (c) { + case '/': + if (state->len) { + fprintf(stderr, "syntax error\n"); + return 1; + } + state->state = 3; /* STATE_TAG_CLOSE */ + return 0; + case '>': + _finish_name(state); + _finish_tag(state); + return 0; + case ' ': + _finish_name(state); + return 0; + default: + state->data[state->len] = c; + state->len++; + return 0; + } + break; + case 2: /* STATE_TAG_ATTRIB */ + switch (c) { + case ' ': /* attribute has no value, end it and append it with = self */ + _finish_bare_attr(state); + return 0; + case '>': + _finish_bare_attr(state); + _finish_tag(state); + return 0; + case '=': /* attribute has a value, go to next mode */ + _finish_attr(state); + return 0; + default: + state->data[state->len] = c; + state->len++; + return 0; + } + return 0; + case 3: /* STATE_TAG_CLOSE */ + switch (c) { + case '>': + _finish_close(state); + return 0; + default: + state->data[state->len] = c; + state->len++; + return 0; + } + break; + case 4: /* STATE_ATTR_VALUE */ + switch (c) { + case ' ': + _finish_attr_value(state); + return 0; + case '>': + _finish_attr_value(state); + _finish_tag(state); + return 0; + default: + state->data[state->len] = c; + state->len++; + return 0; + } + break; + default: + fprintf(stderr, "parser in unknown state\n"); + return 1; + } + return 0; +} + +int markup_finish(struct markup_state * state) { + if (state->state != 0) { + fprintf(stderr, "unexpected end of data\n"); + return 1; + } else { + _dump_buffer(state); + free(state); + return 0; + } +} + diff --git a/util/auto-dep.py b/util/auto-dep.py index cb9e8338..d25d5809 100755 --- a/util/auto-dep.py +++ b/util/auto-dep.py @@ -23,6 +23,7 @@ class Classifier(object): '': (None, '-ltoaru_rline', ['']), '': (None, '-ltoaru_rline_exp', ['']), '': (None, '-ltoaru_confreader', ['']), + '': (None, '-ltoaru_markup', ['']), '': (None, '-ltoaru_yutani', ['', '', '', '', '']), '': (None, '-ltoaru_decorations', ['', '', '', '']), '': (None, '-ltoaru_termemu', ['']),