slweb

Једноставни генератор статичких веб страна
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување b43f045d796425519b8759d7cf60551b0b0d2d34
родитељ f07f2e1dbc0bf46b19ae26088cde97e948de394f
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Sun, 20 Dec 2020 19:59:10 +0100

Added the parsing of macros and examples/macros/index.slw

Signed-off-by: Страхиња Радић <contact@strahinja.org>

Diffstat:
MMakefile | 4++--
MREADME | 8++++++--
MTODO | 2+-
Mdefs.h | 2++
Aexamples/macros/index.slw | 20++++++++++++++++++++
Mindex.html | 7++++++-
Mindex.slw | 5+++++
Mslweb.c | 304++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
измењених датотека: 8, додавања: 288(+), брисања: 64(-)

diff --git a/Makefile b/Makefile @@ -5,8 +5,8 @@ MANDIR = /usr/local/share/man/man1 CFLAGS=-g LIBS=-lunistring BROWSER = surf -EXAMPLE_PAGES = $(addsuffix /index.slw,examples/basic examples/blockquote \ - examples/includes examples/links examples/tags) +EXAMPLE_PAGES = $(addsuffix /index.slw,$(addprefix examples/,\ + basic blockquote includes links macros tags)) #EXAMPLE_PAGES += $(addprefix examples/includes, EXAMPLE_PAGES_HTML = $(EXAMPLE_PAGES:.slw=.html) diff --git a/README b/README @@ -6,8 +6,8 @@ Slweb is a static website generator which aims at being simplistic. It transforms custom Markdown-like syntax into HTML. - Prerequisites - ------------- + Prerequisites + ------------- Aside from the obvious (GCC and GNU make), slweb requires groff(1) and gzip(1) to create and compress documentation. git(1) is, aside from cloning the @@ -19,6 +19,10 @@ repository, required to use the directive {git-log}. $ git clone https://github.com/Strahinja/slweb.git $ cd slweb +$ make && doas make install + +or with sudo(1): + $ make && sudo make install diff --git a/TODO b/TODO @@ -4,7 +4,7 @@ Migration to C checklist ------------------------ - [ ] Add {=macro} parsing + [x] Add {=macro} parsing [ ] Add [=command Link](link) form of links [x] Add [(Link)](link) form of links [ ] Add {include} processing diff --git a/defs.h b/defs.h @@ -58,6 +58,7 @@ typedef struct { uint8_t* key; uint8_t* value; + BOOL seen; /* for use with macros */ } KeyValue; #pragma GCC diagnostic push @@ -80,6 +81,7 @@ const USHORT ST_LINK_SECOND_ARG = 1 << 11; const USHORT ST_LINK_SPAN = 1 << 12; const USHORT ST_IMAGE = 1 << 13; const USHORT ST_IMAGE_SECOND_ARG = 1 << 14; +const USHORT ST_MACRO_BODY = 1 << 15; #pragma GCC diagnostic pop #endif /* __DEFS_H */ diff --git a/examples/macros/index.slw b/examples/macros/index.slw @@ -0,0 +1,20 @@ +{=copyright}Copyright &copy; John Doe. <br /> +All rights reserved.{/=copyright} + +{header}{=copyright}{/header} + +{main} +# Title + +Some text. The next `&lt;pre>` will use a macro: + +{pre} +{=copyright} +{/pre} + +Some more text. + +{/main} + +{footer}{=copyright}{/footer} + diff --git a/index.html b/index.html @@ -26,6 +26,11 @@ cloning the repository, required to use the directive <code>&lbrace;git-log&rbra <pre> $ git clone https://github.com/Strahinja/slweb.git $ cd slweb +$ make && <a href="https://github.com/slicer69/doas">doas</a> make install +</pre> +or with <strong>sudo</strong>(1): + +<pre> $ make && sudo make install </pre> @@ -109,7 +114,7 @@ this program. If not, see &lt;https://www.gnu.org/licenses/&gt;. </p> <div id="git-log"> Previous commit: -index.slw a147dd6 2020-12-18 16:19:27 +0100 (Страхиња Радић) (HEAD -> master, origin/master, origin/HEAD) +index.slw f07f2e1 2020-12-18 16:21:25 +0100 (Страхиња Радић) (HEAD -> master, origin/master, origin/HEAD) </div><!--git-log--> diff --git a/index.slw b/index.slw @@ -20,6 +20,11 @@ cloning the repository, required to use the directive `&lbrace;git-log&rbrace;`. ``` $ git clone https://github.com/Strahinja/slweb.git $ cd slweb +$ make && <a href="https://github.com/slicer69/doas">doas</a> make install +``` +or with **sudo**(1): + +``` $ make && sudo make install ``` diff --git a/slweb.c b/slweb.c @@ -84,13 +84,20 @@ substr(char* src, int start, int finish) } uint8_t* -get_value(KeyValue* list, size_t list_count, uint8_t* key) +get_value(KeyValue* list, size_t list_count, uint8_t* key, BOOL* seen) { KeyValue* plist = list; while (plist < list + list_count) { if (!u8_strcmp(plist->key, key)) + { + if (seen) + { + *seen = plist->seen; + plist->seen = TRUE; + } return plist->value; + } plist++; } return NULL; @@ -140,12 +147,16 @@ process_heading(uint8_t* token, FILE* output, UBYTE heading_level) } int -process_tag(uint8_t* token, FILE* output, BOOL end_tag) +process_tag(uint8_t* token, FILE* output, KeyValue** macros, + size_t* macros_count, KeyValue** pmacros, USHORT* state, + BOOL read_yaml_macros_and_links, BOOL* skip_eol, + BOOL end_tag) { if (!token || u8_strlen(token) < 1) return warning(1, (uint8_t*)"No tag\n"); - if (!strcmp((char*)token, "git-log")) + if (!strcmp((char*)token, "git-log") + && !read_yaml_macros_and_links) { if (!filename) return warning(1, (uint8_t*)"Cannot use git-log in stdin\n"); @@ -191,7 +202,8 @@ process_tag(uint8_t* token, FILE* output, BOOL end_tag) free(basename); } - else if (!strcmp((char*)token, "made-by")) + else if (!strcmp((char*)token, "made-by") + && !read_yaml_macros_and_links) { fprintf(output, "<div id=\"made-by\">\n" "Generated by <a href=\"https://github.com/Strahinja/slweb\">" @@ -199,7 +211,55 @@ process_tag(uint8_t* token, FILE* output, BOOL end_tag) "© 2020 Strahinya Radich.\n" "</div><!--made-by-->\n"); } - else + else if (*token == '=') + { + *skip_eol = TRUE; + if (!end_tag) + { + BOOL seen = FALSE; + + uint8_t* macro_body = get_value(*macros, *macros_count, token+1, + read_yaml_macros_and_links ? NULL : &seen); + + if (macro_body) + { + if (!read_yaml_macros_and_links) + { + if (seen) + fprintf(output, "%s", macro_body); + else + *state |= ST_MACRO_BODY; + } + } + else + { + if (read_yaml_macros_and_links) + { + (*macros_count)++; + + if (*macros_count > 1) + { + *macros = (KeyValue*) realloc(*macros, + *macros_count * sizeof(KeyValue)); + *pmacros = *macros + *macros_count - 1; + } + (*pmacros)->key = (uint8_t*) calloc(u8_strlen(token+1), + sizeof(uint8_t)); + (*pmacros)->seen = FALSE; + u8_strcpy((*pmacros)->key, token+1); + (*pmacros)->value = NULL; + } + *state |= ST_MACRO_BODY; + *skip_eol = TRUE; + } + } + else + { + *state &= ~ST_MACRO_BODY; + *skip_eol = TRUE; + } + } + else if (!read_yaml_macros_and_links) { fprintf(output, "<"); if (end_tag) @@ -288,7 +348,7 @@ int process_link(uint8_t* link_text, uint8_t* link_id, KeyValue* links, size_t links_count, FILE* output) { - uint8_t* url = get_value(links, links_count, link_id); + uint8_t* url = get_value(links, links_count, link_id, NULL); fprintf(output, "<a href=\"%s\">%s</a>", url ? (char*)url : "", link_text); return 0; @@ -306,7 +366,7 @@ int process_image(uint8_t* image_text, uint8_t* image_id, KeyValue* links, size_t links_count, FILE* output) { - uint8_t* url = get_value(links, links_count, image_id); + uint8_t* url = get_value(links, links_count, image_id, NULL); fprintf(output, "<img src=\"%s\" alt=\"%s\" />", url ? (char*)url : "", image_text); return 0; @@ -349,13 +409,16 @@ process_text_token(USHORT* state, uint8_t** ptoken, BOOL add_enclosing_paragraph) { - if (add_enclosing_paragraph) - process_line_start(state, first_line_in_doc, previous_line_blank, - processed_start_of_line, read_yaml_macros_and_links, - output, token, ptoken); - **ptoken = '\0'; - if (!read_yaml_macros_and_links && **token) - fprintf(output, "%s", *token); + if (!read_yaml_macros_and_links && !(*state & ST_YAML)) + { + if (add_enclosing_paragraph) + process_line_start(state, first_line_in_doc, previous_line_blank, + processed_start_of_line, read_yaml_macros_and_links, + output, token, ptoken); + **ptoken = '\0'; + if (**token && !(*state & ST_MACRO_BODY)) + fprintf(output, "%s", *token); + } **token = '\0'; *ptoken = *token; return 0; @@ -365,8 +428,8 @@ int begin_html_and_head(FILE* output, KeyValue* vars, size_t vars_count) { KeyValue* pvars = vars; - uint8_t* site_name = get_value(vars, vars_count, (uint8_t*)"site-name"); - uint8_t* site_desc = get_value(vars, vars_count, (uint8_t*)"site-desc"); + uint8_t* site_name = get_value(vars, vars_count, (uint8_t*)"site-name", NULL); + uint8_t* site_desc = get_value(vars, vars_count, (uint8_t*)"site-desc", NULL); fprintf(output, "<!DOCTYPE html>\n" "<html lang=\"en\">\n" @@ -401,7 +464,7 @@ add_css(FILE* output, KeyValue* vars, size_t vars_count) int end_head_start_body(FILE* output, KeyValue* vars, size_t vars_count) { - uint8_t* title = get_value(vars, vars_count, (uint8_t*)"title"); + uint8_t* title = get_value(vars, vars_count, (uint8_t*)"title", NULL); fprintf(output, "</head>\n<body>\n"); @@ -434,6 +497,7 @@ slweb_parse(uint8_t* buffer, FILE* output, uint8_t* link_text = NULL; KeyValue* pvars = NULL; KeyValue* plinks = NULL; + KeyValue* pmacros = NULL; USHORT state = ST_NONE; UBYTE heading_level = 0; BOOL end_tag = FALSE; @@ -462,6 +526,7 @@ slweb_parse(uint8_t* buffer, FILE* output, pbuffer = buffer; pvars = *vars; plinks = *links; + pmacros = *macros; lineno = 0; if (!read_yaml_macros_and_links && !body_only) @@ -498,7 +563,7 @@ slweb_parse(uint8_t* buffer, FILE* output, { case '-': if (colno == 1 - && !(state & ST_PRE) + && !(state & (ST_MACRO_BODY | ST_PRE)) && u8_strlen(pline) > 2 && !strcmp(substr((char*)pline, 0, 3), "---")) { @@ -519,7 +584,7 @@ slweb_parse(uint8_t* buffer, FILE* output, case ':': if (state & ST_YAML - && !(state & ST_YAML_VAL) + && !(state & (ST_MACRO_BODY | ST_YAML_VAL)) && read_yaml_macros_and_links) { *ptoken = '\0'; @@ -556,6 +621,13 @@ slweb_parse(uint8_t* buffer, FILE* output, break; case '`': + if (state & ST_MACRO_BODY) + { + *ptoken++ = *pline++; + colno++; + break; + } + if (colno == 1 && u8_strlen(pline) > 2 && !strcmp(substr((char*)pline, 0, 3), "```")) @@ -624,6 +696,13 @@ slweb_parse(uint8_t* buffer, FILE* output, break; case '#': + if (state & ST_MACRO_BODY) + { + *ptoken++ = *pline++; + colno++; + break; + } + if (colno == 1 && !(state & (ST_PRE | ST_YAML))) { @@ -648,7 +727,8 @@ slweb_parse(uint8_t* buffer, FILE* output, case '_': if (read_yaml_macros_and_links - || state & (ST_TAG | ST_PRE | ST_CODE)) + || state & (ST_MACRO_BODY | ST_TAG | ST_PRE + | ST_CODE)) { *ptoken++ = *pline++; colno++; @@ -743,7 +823,8 @@ slweb_parse(uint8_t* buffer, FILE* output, case '*': if (read_yaml_macros_and_links - || state & (ST_TAG | ST_PRE | ST_CODE)) + || state & (ST_MACRO_BODY | ST_TAG | ST_PRE + | ST_CODE)) { *ptoken++ = *pline++; colno++; @@ -837,6 +918,13 @@ slweb_parse(uint8_t* buffer, FILE* output, break; case ' ': + if (state & ST_MACRO_BODY) + { + *ptoken++ = *pline++; + colno++; + break; + } + if (u8_strlen(pline) == 2 && *(pline+1) == ' ') { @@ -855,24 +943,54 @@ slweb_parse(uint8_t* buffer, FILE* output, break; case '{': - if (read_yaml_macros_and_links - || (state & (ST_PRE | ST_YAML | ST_YAML_VAL | ST_HEADING))) + if (state & (ST_PRE | ST_YAML | ST_YAML_VAL | ST_HEADING)) { *ptoken++ = *pline++; colno++; break; } - /* Output existing text up to { */ - process_text_token(&state, first_line_in_doc, - previous_line_blank, - processed_start_of_line, - read_yaml_macros_and_links, - output, - &token, - &ptoken, - FALSE); - processed_start_of_line = TRUE; + if (state & ST_MACRO_BODY) + { + *ptoken = '\0'; + size_t token_len = u8_strlen(token); + + skip_eol = TRUE; + if (read_yaml_macros_and_links) + { + if (pmacros->value) + { + size_t value_len = u8_strlen(pmacros->value); + + if (sizeof(pmacros->value) < value_len + token_len + 1) + { + pmacros->value = (uint8_t*) realloc(pmacros->value, + sizeof(pmacros->value) + + BUFSIZE * sizeof(uint8_t)); + } + u8_strncat(pmacros->value, token, token_len); + } + else + { + pmacros->value = (uint8_t*) calloc(BUFSIZE, + sizeof(uint8_t)); + u8_strcpy(pmacros->value, token); + } + } + } + else + { + /* Output existing text up to { */ + process_text_token(&state, first_line_in_doc, + previous_line_blank, + processed_start_of_line, + read_yaml_macros_and_links, + output, + &token, + &ptoken, + FALSE); + processed_start_of_line = TRUE; + } state |= ST_TAG; *token = '\0'; @@ -883,8 +1001,7 @@ slweb_parse(uint8_t* buffer, FILE* output, break; case '/': - if (read_yaml_macros_and_links - || state & (ST_PRE | ST_HEADING)) + if (state & (ST_PRE | ST_HEADING)) { *ptoken++ = *pline++; colno++; @@ -906,8 +1023,7 @@ slweb_parse(uint8_t* buffer, FILE* output, break; case '}': - if (read_yaml_macros_and_links - || state & (ST_PRE | ST_HEADING)) + if (state & (ST_PRE | ST_HEADING)) { *ptoken++ = *pline++; colno++; @@ -917,8 +1033,9 @@ slweb_parse(uint8_t* buffer, FILE* output, state &= ~ST_TAG; *ptoken = '\0'; - if (!read_yaml_macros_and_links) - process_tag(token, output, end_tag); + process_tag(token, output, macros, macros_count, + &pmacros, &state, read_yaml_macros_and_links, + &skip_eol, end_tag); *token = '\0'; ptoken = token; @@ -929,6 +1046,13 @@ slweb_parse(uint8_t* buffer, FILE* output, break; case '>': + if (state & ST_MACRO_BODY) + { + *ptoken++ = *pline++; + colno++; + break; + } + if (!read_yaml_macros_and_links && !(state & (ST_PRE | ST_HEADING)) && colno == 1) @@ -950,7 +1074,7 @@ slweb_parse(uint8_t* buffer, FILE* output, break; case '!': - if (state & (ST_PRE | ST_HEADING | ST_CODE)) + if (state & (ST_MACRO_BODY | ST_PRE | ST_HEADING | ST_CODE)) { *ptoken++ = *pline++; colno++; @@ -979,7 +1103,7 @@ slweb_parse(uint8_t* buffer, FILE* output, break; case '[': - if (state & (ST_PRE | ST_HEADING | ST_CODE)) + if (state & (ST_MACRO_BODY | ST_PRE | ST_HEADING | ST_CODE)) { *ptoken++ = *pline++; colno++; @@ -1008,6 +1132,13 @@ slweb_parse(uint8_t* buffer, FILE* output, break; case '(': + if (state & ST_MACRO_BODY) + { + *ptoken++ = *pline++; + colno++; + break; + } + if (state & ST_LINK) { uint8_t* tag = (uint8_t*)"<span>"; @@ -1034,6 +1165,13 @@ slweb_parse(uint8_t* buffer, FILE* output, break; case ')': + if (state & ST_MACRO_BODY) + { + *ptoken++ = *pline++; + colno++; + break; + } + if (state & ST_LINK_SPAN) { if (u8_strlen(pline) > 1 @@ -1083,7 +1221,7 @@ slweb_parse(uint8_t* buffer, FILE* output, break; case ']': - if (!(state & (ST_LINK | ST_IMAGE))) + if (!(state & (ST_MACRO_BODY | ST_LINK | ST_IMAGE))) { *ptoken++ = *pline++; colno++; @@ -1177,6 +1315,13 @@ slweb_parse(uint8_t* buffer, FILE* output, break; case '\\': + if (state & ST_MACRO_BODY) + { + *ptoken++ = *pline++; + colno++; + break; + } + /* *if (state & (ST_PRE | ST_CODE | ST_LINK_SECOND_ARG)) *{ @@ -1197,16 +1342,57 @@ slweb_parse(uint8_t* buffer, FILE* output, } } - if (!(state & ST_YAML)) + if (*token && read_yaml_macros_and_links + && (state & ST_YAML_VAL)) + { + *ptoken = '\0'; + pvars->value = (uint8_t*) calloc(u8_strlen(token)+1, + sizeof(uint8_t)); + u8_strcpy(pvars->value, token); + } + else { if (*token) { - if (state & ST_LINK_SECOND_ARG) + if (state & ST_MACRO_BODY) { *ptoken = '\0'; - plinks->value = (uint8_t*) calloc(u8_strlen(token), - sizeof(uint8_t)); - u8_strcpy(plinks->value, token); + size_t token_len = u8_strlen(token); + + skip_eol = TRUE; + if (read_yaml_macros_and_links) + { + if (pmacros->value) + { + size_t value_len = u8_strlen(pmacros->value); + + if (sizeof(pmacros->value) < value_len + token_len + 1) + { + pmacros->value = (uint8_t*) realloc(pmacros->value, + sizeof(pmacros->value) + + BUFSIZE * sizeof(uint8_t)); + } + u8_strncat(pmacros->value, token, token_len); + u8_strncat(pmacros->value, (uint8_t*)"\n", 1); + } + else + { + pmacros->value = (uint8_t*) calloc(BUFSIZE, + sizeof(uint8_t)); + u8_strcpy(pmacros->value, token); + u8_strncat(pmacros->value, (uint8_t*)"\n", 1); + } + } + } + else if (state & ST_LINK_SECOND_ARG) + { + *ptoken = '\0'; + if (read_yaml_macros_and_links) + { + plinks->value = (uint8_t*) calloc(u8_strlen(token), + sizeof(uint8_t)); + u8_strcpy(plinks->value, token); + } } else if (state & ST_HEADING) { @@ -1249,15 +1435,6 @@ slweb_parse(uint8_t* buffer, FILE* output, } previous_line_blank = FALSE; - - } - else if (*token && read_yaml_macros_and_links - && state & ST_YAML_VAL) - { - *ptoken = '\0'; - pvars->value = (uint8_t*) calloc(u8_strlen(token)+1, - sizeof(uint8_t)); - u8_strcpy(pvars->value, token); } if (!skip_eol) @@ -1375,7 +1552,7 @@ main(int argc, char** argv) return result; } else - filename = arg; + filename = (uint8_t*)arg; cmd = CMD_NONE; } } @@ -1394,7 +1571,7 @@ main(int argc, char** argv) { struct stat fs; - input = fopen(filename, "r"); + input = fopen((char*)filename, "r"); if (!input) return error(ENOENT, (uint8_t*)"No such file: %s\n", filename); @@ -1476,6 +1653,17 @@ main(int argc, char** argv) &links, &links_count, body_only, TRUE); + /* + *fprintf(stderr, "MACROS[%lu]:\n", macros_count); + *KeyValue* pmacros = macros; + *while (pmacros != macros + macros_count) + *{ + * fprintf(stderr, "macro[=%s]=[%s]\n", pmacros->key, pmacros->value); + * pmacros++; + *} + *fprintf(stderr, "END MACROS\n"); + */ + /* Second pass: parse and output */ return slweb_parse(buffer, output, &vars, &vars_count, &macros, &macros_count, &links, &links_count,