From e00ffe6f708f1460ca1d2b00d94c739ebb2cb184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilja=20Karta=C5=A1ov?= Date: Sun, 14 Jul 2019 20:55:27 +0200 Subject: [PATCH] Add implementation of html module --- components/html.c | 465 ++++++++++++++++++++++++++++++++++++++++++++++ components/html.h | 56 ++++++ 2 files changed, 521 insertions(+) create mode 100644 components/html.c create mode 100644 components/html.h diff --git a/components/html.c b/components/html.c new file mode 100644 index 0000000..6aa6c5d --- /dev/null +++ b/components/html.c @@ -0,0 +1,465 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file html.c + * @author Ilja Kartašov + * @brief + * + * @see https://lowenware.com/ + */ + +#include +#include +#include +#include +#include +#include + +#include "html.h" + + +static char * +ax_html_escape(char *src, uint32_t len) +{ + uint32_t extra = 0; + char *ptr = src; + char ch, *result; + + while ((ch = *ptr) != 0) { + switch (ch) { + case '"': + case '\\': + case '\n': + extra++; + break; + default: + break; + } + ptr++; + } + + if ((result = calloc(len + extra + 1, sizeof (char))) != NULL) { + if (extra) { + ptr = result; + while (len--) { + switch (*src) { + case '"': + case '\\': + *(ptr++) = '\\'; + break; + case '\n': + *(ptr++) = '\\'; + *(ptr++) = 'n'; + case '\r': /* go through */ + src++; + continue; + default: + break; + } + if (!(*(ptr++) = *(src++))) + break; + } + } else { + strncpy(result, src, len); + result[len] = 0; + } + } + return result; +} + +static struct ax_html * +ax_html_append_new(CStuffList list, const struct ax_html *src) +{ + struct ax_html *result; + + if ((result = malloc(sizeof (*result))) != NULL) { + result->type = src->type; + result->offset = src->offset; + result->size = src->size; + if ((result->data = ax_html_escape(src->data, src->size)) != NULL) { + if (cstuff_list_append(list, result) != -1) { + return result; + } + free(result->data); + } + free(result); + } + return NULL; +} + + +static int +ax_html_check_chars(char *begin, char *end) +{ + int result = 0; + while (begin < end) { + char c = *begin; + if (c == '-') { + c = (*begin = '_'); + } + if (isalnum(c) || c == '_') { + result++; + } else { + return 0; + } + begin++; + } + return result; +} + + +static AislStatus +ax_html_read_line(CStuffList list, char *line) +{ + const char input_open[] = "${", + input_close[] = "}", + block_open[] = ""; + + struct ax_html node; + size_t offset; + char *cur; + + offset = strspn(line, "\t "); + cur = &line[offset]; + + while (*cur) { + char *p1, *p2, *p; + uint16_t type = AX_HTML_PLAIN; + uint32_t close_len = 0; + + p1 = strstr(cur, input_open); + p2 = strstr(cur, block_open); + + if (p1 && (!p2 || p2 > p1)) { + p = &p1[sizeof (input_open) - 1]; + if ((p2 = strstr(p, input_close)) && ax_html_check_chars(p, p2)) { + type = AX_HTML_INPUT; + close_len = sizeof (input_close) - 1; + } + } else if (p2 && (!p1 || p1 > p2)) { + p1 = p2; + p = &p1[sizeof (block_open) - 1]; + if ((p2 = strstr(p, block_close)) && ax_html_check_chars(p, p2)) { + type = AX_HTML_BLOCK; + close_len = sizeof (block_close) - 1; + } + } + + if (type != AX_HTML_PLAIN) { + if (p1 != cur) { + node.type = AX_HTML_PLAIN; + node.offset = offset; + node.size = (uint32_t)(p1 - cur); + node.data = cur; + offset = 0; + if (ax_html_append_new(list, &node) == NULL) { + return AISL_MALLOC_ERROR; + } + } + node.type = type; + node.offset = offset; + node.size = (uint32_t)(p2 - p); + node.data = p; + offset = 0; + if (ax_html_append_new(list, &node) == NULL) { + return AISL_MALLOC_ERROR; + } + cur = p2 + close_len; + if (type == AX_HTML_BLOCK) { + size_t lfcr = strspn(cur, "\r\n"); + if (lfcr) { + cur += lfcr; + } + } + } else { + node.type = type; + node.offset = offset; + node.size = strlen(cur); + node.data = cur; + if (ax_html_append_new(list, &node) == NULL) { + return AISL_MALLOC_ERROR; + } + cur = &cur[node.size]; + } + } + return AISL_SUCCESS; +} + + +AislStatus +ax_html_import(CStuffList list, const char *html_file) +{ + FILE *f = NULL; + size_t sz = 256; + char *line; + ssize_t rs; + AislStatus result = AISL_SUCCESS; + + if (!(line = malloc(sz))) + goto e_malloc; + + if (!(f = fopen(html_file, "r"))) + goto e_syscall; + + while ((rs = getdelim(&line, &sz, '\n', f)) != -1) { + if ((result = ax_html_read_line(list, line)) != AISL_SUCCESS) { + goto finally; + } + } + + switch(errno) { + case 0: + break; + + case ENOMEM: + goto e_malloc; + + default: + goto e_syscall; + } + goto finally; + +e_malloc: + result = AISL_MALLOC_ERROR; + goto finally; + +e_syscall: + result = AISL_SYSCALL_ERROR; + goto finally; + +finally: + if (line) + free(line); + if (f) + fclose(f); + return result; +} + + +AislStatus +ax_html_export(CStuffList list, const struct ax_html_options *opts) +{ + AislStatus result = AISL_SUCCESS; + FILE *out = NULL; + int i, l; + char *c_prefix = NULL, *u_prefix = NULL, *f = NULL; + const char *ofst = opts->offset; + + /* Cammel case prefix */ + if (cstuff_strcpy(&c_prefix, opts->name) == -1) + goto e_malloc; + + *c_prefix = toupper(*c_prefix); + + /* Upper case prefix */ + if ((i = cstuff_strcpy(&u_prefix, opts->name)) == -1) + goto e_malloc; + + while (i--) { + u_prefix[i] = toupper(u_prefix[i]); + } + + /* header file */ + if ((l = cstuff_sprintf(&f, "%s/%s.h", opts->path, opts->name)) == -1) + goto e_malloc; + + if (!(out = fopen(f, "w"))) + goto e_syscall; + + fprintf(out, "#ifndef %s_H_AISL_COMPOSED\n", u_prefix); + fprintf(out, "#define %s_H_AISL_COMPOSED\n\n", u_prefix); + fprintf(out, "#include \n"); + + fprintf(out, "#ifdef DEVEL\n\n"); + fprintf(out, "#include \n"); + fprintf(out, "#else\n\n"); + fprintf(out, "#define %s_put(STREAM, BLOCK, CB, CTX) ", opts->name); + fprintf(out, "%s_put_##BLOCK##(STREAM, CB, CTX)\n\n", opts->name); + fprintf(out, "#endif\n\n"); + fprintf(out, "typedef int\n(*%sCallback)(AislStream s, const char *input, " + "void *ctx);\n\n", c_prefix); + + fprintf(out, "#ifdef DEVEL\n\n"); + fprintf(out, "int\n%s_put(AislStream s, %sCallback callback, " + "void *ctx, const char *block);\n\n", opts->name, c_prefix); + fprintf(out, "int\n%s_set(CStuffList list);\n\n", opts->name); + fprintf(out, "#else\n\n"); + for (i = 0; i < list->length; i++) { + struct ax_html *html = list->items[i]; + + if (html->type == AX_HTML_BLOCK) { + fprintf(out, "int\n%s_put_%s(AislStream s, %sCallback callback, void *ctx);\n\n", + opts->name, html->data, c_prefix); + } + } + fprintf(out, "#endif\n\n"); + + fprintf(out, "#endif\n"); + fprintf(out, "\n\n"); + + fclose(out); + + /* source file */ + f[l-1] = 'c'; + + if (!(out = fopen(f, "w"))) + goto e_syscall; + + fprintf(out, "#include \n"); + fprintf(out, "#include \"%s.h\"\n\n", opts->name); + fprintf(out, "#define %s_PLAIN %d\n", u_prefix, AX_HTML_PLAIN); + fprintf(out, "#define %s_BLOCK %d\n", u_prefix, AX_HTML_BLOCK); + fprintf(out, "#define %s_INPUT %d\n\n", u_prefix, AX_HTML_INPUT); + fprintf(out, "struct %s {\n", opts->name); + fprintf(out, "%suint16_t type;\n", ofst); + fprintf(out, "%suint16_t offset;\n", ofst); + fprintf(out, "%suint32_t size;\n", ofst); + fprintf(out, "%sconst char *code;\n", ofst); + fprintf(out, "};\n\n"); + + fprintf(out, "#ifdef DEVEL\n\n"); + + fprintf(out, "static struct %s *m_%s = NULL;\n\n", opts->name, opts->name); + fprintf(out, "#else\n\n"); + + fprintf(out, "static const struct %s m_%s[] = {\n", opts->name, opts->name); + + for (i = 0; i < list->length; i++) { + struct ax_html *html = list->items[i]; + uint32_t offset, size = html->size; + + if (opts->minimize) { + offset = 0; + if (html->type == AX_HTML_PLAIN) { + int l = strlen(html->data); + + if (!(l < 2) && !strcmp(&html->data[l - 2], "\\n")) { + size--; + } + } + } else { + offset = html->offset & 0xFFFF; + } + + fprintf(out, "%s{%u, %u, %u, \"%s\"},\n", ofst, html->type, offset, + size, html->data); + } + fprintf(out, "%s{0, 0, 0, NULL}\n};\n\n", ofst); + + fprintf(out, "#endif\n\n"); + + fprintf(out, "static int\nput_from(AislStream s, %sCallback callback, " + "void *ctx, uint32_t from)\n{\n", c_prefix); + fprintf(out, "%sint result = 0, r;\n", ofst); + fprintf(out, "%swhile (m_%s[from]->data) {\n", ofst, opts->name); + fprintf(out, "%s%sswitch (m_%s[from]->type) {\n", ofst, ofst, + opts->name); + fprintf(out, "%s%scase %s_PLAIN:\n", ofst, ofst, u_prefix); + fprintf(out, "%s%s%sr = aisl_write(s, m_%s[from]->data, m_%s[from]->size);\n", + ofst, ofst, ofst, opts->name, opts->name); + fprintf(out, "%s%s%sbreak;\n", ofst, ofst, ofst); + + fprintf(out, "%s%scase %s_INPUT:\n", ofst, ofst, u_prefix); + fprintf(out, "%s%s%sr = callback(s, m_%s[from]->data, ctx);\n", + ofst, ofst, ofst, opts->name); + fprintf(out, "%s%s%sbreak;\n", ofst, ofst, ofst); + fprintf(out, "%s%scase %s_BLOCK:\n", ofst, ofst, u_prefix); + fprintf(out, "%s%s%sreturn result;\n", ofst, ofst, ofst); + fprintf(out, "%s%sdefault:\n", ofst, ofst); + fprintf(out, "%s%s%sreturn -1;\n", ofst, ofst, ofst); + fprintf(out, "%s%s}\n", ofst, ofst); + fprintf(out, "%s%sif (r == -1) return r;\n", ofst, ofst); + fprintf(out, "%s%sresult += r;\n", ofst, ofst); + fprintf(out, "%s%sfrom++;\n", ofst, ofst); + fprintf(out, "%s}\n", ofst); + fprintf(out, "%sreturn result;\n}\n\n", ofst); + + fprintf(out, "#ifdef DEVEL\n\n"); + fprintf(out, "int\n%s_put(AislStream s, %sCallback callback, " + "void *ctx, const char *block)\n{\n", opts->name, c_prefix); + fprintf(out, "%sint i = 0;\n", ofst); + fprintf(out, "%swhile (m_%s[i]->data) {\n", ofst, opts->name); + fprintf(out, "%s%sif (m_%s[i]->type == %s_BLOCK && " + "!strcmp(m_%s[i]->data, block)) {\n", ofst, ofst, opts->name, u_prefix, + opts->name); + fprintf(out, "%s%s%sreturn put_from(s, callback, ctx, i + 1);\n", ofst, ofst, + ofst); + fprintf(out, "%s%s}\n", ofst, ofst); + fprintf(out, "%s}\n", ofst); + fprintf(out, "%sreturn 0;\n}\n\n", ofst); + + fprintf(out, "int\n%s_set(CStuffList list)\n{\n", opts->name); + fprintf(out, "%sint i;\n", ofst); + fprintf(out, "%sif (m_%s) {\n", ofst, opts->name); + fprintf(out, "%s%si = 0;\n", ofst, ofst); + fprintf(out, "%s%swhile (m_%s[i].data) {\n", ofst, ofst, opts->name); + fprintf(out, "%s%s%sfree(m_%s[i].data);\n", ofst, ofst, ofst, opts->name); + fprintf(out, "%s%s}\n", ofst, ofst); + fprintf(out, "%s%sfree(m_%s);\n", ofst, ofst, opts->name); + fprintf(out, "%s}\n", ofst); + fprintf(out, "%sif (!(m_%s = malloc(list->length * sizeof (*m_%s))))\n", ofst, + opts->name, opts->name); + fprintf(out, "%s%sreturn -1;\n", ofst, ofst); + fprintf(out, "%sfor (i = 0; i < list->length; i++) {\n", ofst); + fprintf(out, "%s%smemcpy(&m_%s[i], list->items[i], sizeof (*m_%s));\n", ofst, + ofst, opts->name, opts->name); + fprintf(out, "%s}\n", ofst); + fprintf(out, "%smemset(&m_%s[i], 0, sizeof (m_%s[i]));\n", ofst, opts->name, + opts->name); + fprintf(out, "%sreturn i;\n", ofst); + fprintf(out, "}\n\n"); + + + fprintf(out, "#else\n\n"); + + for (i = 0; i < list->length; i++) { + struct ax_html *html = list->items[i]; + if (html->type == AX_HTML_BLOCK) { + fprintf(out, "int\n%s_put_%s(AislStream s, %sCallback callback, " + "void *ctx)\n", opts->name, html->data, c_prefix); + fprintf(out, "{\n"); + fprintf(out, "%sreturn put_from(s, callback, ctx, %u);\n", ofst, i + 1); + fprintf(out, "}\n\n"); + } + } + fprintf(out, "#endif\n\n"); + + fclose(out); + + goto finally; + +e_syscall: + result = AISL_SYSCALL_ERROR; + goto finally; + +e_malloc: + result = AISL_MALLOC_ERROR; + +finally: + if (c_prefix) + free(c_prefix); + + if (u_prefix) + free(u_prefix); + + if (f) + free(f); + + return result; +} + + +void +ax_html_free(struct ax_html *html) +{ + if (html->data) { + free(html->data); + } + free(html); +} diff --git a/components/html.h b/components/html.h new file mode 100644 index 0000000..c45b860 --- /dev/null +++ b/components/html.h @@ -0,0 +1,56 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file template.h + * @author Ilja Kartašov + * @brief + * + * @see https://lowenware.com/ + */ + +#ifndef AX_HTML_H_92C08532_E423_4CE4_A44C_27CF864A2C60 +#define AX_HTML_H_92C08532_E423_4CE4_A44C_27CF864A2C60 + +#include +#include +#include +#include + +#define AX_HTML_NULL 0 +#define AX_HTML_PLAIN 1 +#define AX_HTML_BLOCK 2 +#define AX_HTML_INPUT 3 + +struct ax_html { + uint16_t type; + uint16_t offset; + uint32_t size; + char *data; +}; + +struct ax_html_options { + const char *offset; + const char *path; + const char *name; + bool minimize; +}; + + +AislStatus +ax_html_import(CStuffList list, const char *html_file); + + +AislStatus +ax_html_export(CStuffList list, const struct ax_html_options *opts); + + +void +ax_html_free(struct ax_html *html); + + +#endif /* !HTML_H */