чување 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:
измењених датотека: 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 © John Doe. <br />
+All rights reserved.{/=copyright}
+
+{header}{=copyright}{/header}
+
+{main}
+# Title
+
+Some text. The next `<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>{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 <https://www.gnu.org/licenses/>. </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 `{git-log}`.
```
$ 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,
¯os, ¯os_count, &links, &links_count,