чување cb512a8b8a31311d0c47f1a744fd4c9d702953f9
родитељ 92a411ceec8bdb2c0b36444d99df81085cb1dcb8
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Fri, 17 Jun 2022 15:11:02 +0200
Clearly separate macro definitions from macro calls; update manpage accordingly
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
измењених датотека: 5, додавања: 137(+), брисања: 112(-)
diff --git a/defs.h b/defs.h
@@ -68,7 +68,6 @@ typedef struct {
u8* key;
u8* value;
size_t value_size;
- int seen; /* for use with macros */
} KeyValue;
typedef int (*csv_callback_t)(FILE* output, u8** csv_header, u8** csv_register);
diff --git a/examples/links/index.slw b/examples/links/index.slw
@@ -2,11 +2,11 @@
stylesheet: style.css
site-name: Links test
---
-{=icon}<svg style="width:24px;height:24px" viewBox="0 0 24 24">
+{=!icon}<svg style="width:24px;height:24px" viewBox="0 0 24 24">
<path fill="currentColor"
d="M12,17.56L16.07,16.43L16.62,10.33H9.38L9.2,8.3H16.8L17,6.31H7L7.56,12.32H14.45L14.22,14.9L12,15.5L9.78,14.9L9.64,13.24H7.64L7.93,16.43L12,17.56M4.07,3H19.93L18.5,19.2L12,21L5.5,19.2L4.07,3Z"
/>
-</svg>{/=icon}
+</svg>{/=!icon}
Links [Test][1].
diff --git a/examples/macros/index.slw b/examples/macros/index.slw
@@ -2,8 +2,8 @@
stylesheet: style.css
---
-{=copyright}Copyright © John Doe. <br />
-All rights reserved.{/=copyright}
+{=!copyright}Copyright © John Doe. <br />
+All rights reserved.{/=!copyright}
{header}Header: {=copyright}{/header}
diff --git a/slweb.1.in b/slweb.1.in
@@ -572,19 +572,20 @@ Directive \fC{include "somefile"}\fP will fork, parse
.IR basedir )
and output the resulting
.SM HTML
-as if the option \fC\-\-body\-only\fP was specified. All macros and
+as if the option \fC\-\-body\-only\fP was specified. All
.SM YAML
variables will be preserved.
.
.IP \[bu]
.BR Macros .
-Macros can be declared using the directive \fC{=macroname}{/=macroname}\fP,
+Macros can be declared using the directive \fC{=!macroname}{/=!macroname}\fP,
where
.I macroname
is the name of the macro. Anything between those two tags will then become the
body of a macro. Whenever \fC{=macroname}\fP is subsequently encountered in the
file, it will be replaced by the macro body. Macro definitions can't be nested
-nor can they contain macro calls, and doing so will produce an error.
+nor can they contain macro calls, and doing so will produce an error. Tags won't
+be processed within the body of a macro.
.
.IP \[bu]
.BR "Previous Git commit information" .
diff --git a/slweb.c b/slweb.c
@@ -211,7 +211,7 @@ endswith(const char* s, const char* what)
}
u8*
-get_value(KeyValue* list, const size_t list_count, const u8* key, int* seen)
+get_value(KeyValue* list, const size_t list_count, const u8* key)
{
if (!list)
return NULL;
@@ -219,14 +219,7 @@ get_value(KeyValue* list, const size_t list_count, const u8* key, int* seen)
while (plist < list + list_count)
{
if (!strcmp((char*)plist->key, (char*)key))
- {
- if (seen)
- {
- *seen = plist->seen;
- plist->seen = 1;
- }
return plist->value;
- }
plist++;
}
return NULL;
@@ -502,7 +495,7 @@ print_meta_var(FILE* output, u8** tsv_header, u8** tsv_register)
u8* var_name = NULL;
var_name = (u8*)strdup((char*)pvalue + 1);
*(var_name + value_len - 2) = 0;
- u8* value = get_value(vars, vars_count, var_name, NULL);
+ u8* value = get_value(vars, vars_count, var_name);
if (value)
print_output(output,
@@ -1121,8 +1114,7 @@ read_csv(FILE* output, const char* filename, csv_callback_t callback)
UBYTE current_header = 0;
u8* csv_register[MAX_CSV_REGISTERS];
UBYTE current_register = 0;
- u8* csv_delimiter
- = get_value(vars, vars_count, (u8*)"csv-delimiter", NULL);
+ u8* csv_delimiter = get_value(vars, vars_count, (u8*)"csv-delimiter");
if (!(csv = fopen(filename, "rt")))
exit(error(ENOENT, (u8*)"csv: No such file: %s", filename));
@@ -1301,7 +1293,7 @@ int
process_include(FILE* output, const u8* token,
const int read_yaml_macros_and_links)
{
- u8* ptoken = (u8*)strchr((char*)token, ' ');
+ u8* ptoken;
char* include_filename = NULL;
char* pinclude_filename = NULL;
pid_t pid = 0;
@@ -1309,6 +1301,8 @@ process_include(FILE* output, const u8* token,
int arg_pipe_fds[2];
int output_pipe_fds[2];
+ ptoken = (u8*)strchr((char*)token, ' ');
+
if (!input_filename)
return warning(1, (u8*)"Cannot use 'include' in stdin");
@@ -1426,6 +1420,7 @@ process_include(FILE* output, const u8* token,
result = slweb_parse(output, filename, buffer, 1, 0);
process_include_child_cleanup:
+ fflush(output);
slweb_cleanup();
free(filename);
free(buffer);
@@ -1714,7 +1709,7 @@ process_incdir(FILE* output, const u8* token, const u8* link_prefix,
exit(error(1, (u8*)"incdir: Second argument required"));
if (*arg == '=')
- macro_body = get_value(macros, macros_count, arg + 1, NULL);
+ macro_body = get_value(macros, macros_count, arg + 1);
else
{
u8* parg = arg;
@@ -1740,8 +1735,7 @@ process_incdir(FILE* output, const u8* token, const u8* link_prefix,
(u8*)"incdir: Third argument not "
"macro"));
}
- macro_body = get_value(macros, macros_count, arg + 1,
- NULL);
+ macro_body = get_value(macros, macros_count, arg + 1);
}
}
@@ -1838,70 +1832,66 @@ process_timestamp_cleanup:
}
int
-process_macro(FILE* output, const u8* token,
+process_macro_def(FILE* output, const u8* token,
const int read_yaml_macros_and_links, const int end_tag)
{
- if (!end_tag)
+ if (end_tag)
{
- if (IN(state, ST_MACRO_BODY))
- exit(error(1, (u8*)"Macro undefined or nested"));
+ fflush(output);
+ state &= ~ST_MACRO_BODY;
+ return 0;
+ }
- int seen = 0;
- u8* macro_body = get_value(macros, macros_count, token + 1,
- read_yaml_macros_and_links ? NULL : &seen);
+ if (IN(state, ST_MACRO_BODY))
+ exit(error(1, (u8*)"Cannot nest definitions"));
- if (macro_body && !read_yaml_macros_and_links)
+ if (read_yaml_macros_and_links)
+ {
+ macros_count++;
+
+ if (!macros)
{
- if (seen)
- {
- u8* eol = (u8*)strrchr((char*)macro_body, '\n');
- size_t macro_body_len
- = strlen((char*)macro_body);
- if (eol)
- output_firstcol = macro_body
- + macro_body_len
- - (u8*)strrchr(
- (char*)macro_body,
- '\n')
- > 0;
- else
- output_firstcol = !*macro_body
- || *(macro_body + macro_body_len
- - 1)
- == '\n';
- print_output(output, "%s", macro_body);
- }
- else
- state |= ST_MACRO_BODY;
+ CALLOC(macros, KeyValue, macros_count);
+ pmacros = macros;
}
- else if (!macro_body)
+ else
{
- if (read_yaml_macros_and_links)
- {
- macros_count++;
-
- if (!macros)
- {
- CALLOC(macros, KeyValue, macros_count);
- pmacros = macros;
- }
- else
- {
- REALLOC(macros, KeyValue,
- macros_count * sizeof(KeyValue));
- pmacros = macros + macros_count - 1;
- }
- CALLOC(pmacros->key, u8, KEYSIZE);
- pmacros->seen = 0;
- strcpy((char*)pmacros->key, (char*)token + 1);
- pmacros->value = NULL;
- pmacros->value_size = 0;
- }
- state |= ST_MACRO_BODY;
+ REALLOC(macros, KeyValue,
+ macros_count * sizeof(KeyValue));
+ pmacros = macros + macros_count - 1;
}
+ CALLOC(pmacros->key, u8, KEYSIZE);
+ strcpy((char*)pmacros->key, (char*)token + 2);
+ pmacros->value = NULL;
+ pmacros->value_size = 0;
}
+ fflush(output);
+ state |= ST_MACRO_BODY;
+
+ return 0;
+}
+
+int
+process_macro(FILE* output, const u8* token, const int end_tag)
+{
+ u8* macro_body;
+ u8* eol;
+ size_t macro_body_len;
+
+ macro_body = get_value(macros, macros_count, token + 1);
+ if (!macro_body)
+ exit(error(1, (u8*)"Macro '%s' undefined", token + 1));
+
+ eol = (u8*)strrchr((char*)macro_body, '\n');
+ macro_body_len = strlen((char*)macro_body);
+ if (eol)
+ output_firstcol = macro_body + macro_body_len
+ - (u8*)strrchr((char*)macro_body, '\n')
+ > 0;
else
- state &= ~ST_MACRO_BODY;
+ output_firstcol = !*macro_body
+ || *(macro_body + macro_body_len - 1) == '\n';
+ print_output(output, "%s", macro_body);
return 0;
}
@@ -1948,8 +1938,11 @@ process_tag(FILE* output, const u8* token, const u8* link_prefix,
}
else if (*token == '=') /* {=macro} */
{
- process_macro(output, token, read_yaml_macros_and_links,
- end_tag);
+ if (*(token + 1) == '!')
+ process_macro_def(output, token,
+ read_yaml_macros_and_links, end_tag);
+ else if ((*(token + 1) != '!') && !read_yaml_macros_and_links)
+ process_macro(output, token, end_tag);
*skip_eol = 1;
}
else if (!read_yaml_macros_and_links) /* general tags */
@@ -2138,7 +2131,7 @@ int
process_link(FILE* output, const u8* link_text, const u8* link_prefix,
const u8* link_macro_body, const u8* link_id)
{
- u8* url = get_value(links, links_count, link_id, NULL);
+ u8* url = get_value(links, links_count, link_id);
return process_inline_link(output, link_text, link_prefix,
link_macro_body, url);
}
@@ -2225,7 +2218,7 @@ process_image(FILE* output, const u8* image_text, const u8* image_file_prefix,
const u8* link_prefix, const u8* image_id, const int add_link,
const int add_figcaption)
{
- u8* url = get_value(links, links_count, image_id, NULL);
+ u8* url = get_value(links, links_count, image_id);
return process_inline_image(output, image_text, image_file_prefix,
link_prefix, url, add_link, add_figcaption);
}
@@ -2436,14 +2429,14 @@ process_formula(FILE* output, const u8* token, const int display_formula)
int
begin_html_and_head(FILE* output)
{
- u8* lang = get_value(vars, vars_count, (u8*)"lang", NULL);
- u8* site_name = get_value(vars, vars_count, (u8*)"site-name", NULL);
- u8* site_desc = get_value(vars, vars_count, (u8*)"site-desc", NULL);
- u8* canonical = get_value(vars, vars_count, (u8*)"canonical", NULL);
- u8* favicon_url = get_value(vars, vars_count, (u8*)"favicon-url", NULL);
- u8* meta = get_value(vars, vars_count, (u8*)"meta", NULL);
- u8* feed = get_value(vars, vars_count, (u8*)"feed", NULL);
- u8* feed_desc = get_value(vars, vars_count, (u8*)"feed-desc", NULL);
+ u8* lang = get_value(vars, vars_count, (u8*)"lang");
+ u8* site_name = get_value(vars, vars_count, (u8*)"site-name");
+ u8* site_desc = get_value(vars, vars_count, (u8*)"site-desc");
+ u8* canonical = get_value(vars, vars_count, (u8*)"canonical");
+ u8* favicon_url = get_value(vars, vars_count, (u8*)"favicon-url");
+ u8* meta = get_value(vars, vars_count, (u8*)"meta");
+ u8* feed = get_value(vars, vars_count, (u8*)"feed");
+ u8* feed_desc = get_value(vars, vars_count, (u8*)"feed-desc");
print_output(output,
"<!DOCTYPE html>\n"
@@ -2546,10 +2539,10 @@ begin_article(FILE* output, const char* source_filename, const u8* link_prefix,
if (date && source_filename)
{
- char* link = strip_ext((const char*)source_filename);
- char* real_link = NULL;
- u8* permalink_macro = get_value(macros, macros_count,
- (u8*)"permalink", NULL);
+ char* link = strip_ext((const char*)source_filename);
+ char* real_link = NULL;
+ u8* permalink_macro
+ = get_value(macros, macros_count, (u8*)"permalink");
CALLOC(real_link, char, BUFSIZE);
if (ext_in_permalink)
@@ -2761,29 +2754,27 @@ slweb_parse(FILE* output, const char* source_filename, const u8* buffer,
if (!buffer)
exit(error(1, (u8*)"Empty buffer"));
- title = get_value(vars, vars_count, (u8*)"title", NULL);
+ title = get_value(vars, vars_count, (u8*)"title");
title_heading_level
- = get_value(vars, vars_count, (u8*)"title-heading-level", NULL);
- header_text = get_value(vars, vars_count, (u8*)"header-text", NULL);
- author = get_value(vars, vars_count, (u8*)"author", NULL);
- date = get_value(vars, vars_count, (u8*)"date", NULL);
- permalink_url = get_value(vars, vars_count, (u8*)"permalink-url", NULL);
+ = get_value(vars, vars_count, (u8*)"title-heading-level");
+ header_text = get_value(vars, vars_count, (u8*)"header-text");
+ author = get_value(vars, vars_count, (u8*)"author");
+ date = get_value(vars, vars_count, (u8*)"date");
+ permalink_url = get_value(vars, vars_count, (u8*)"permalink-url");
image_file_prefix
- = get_value(vars, vars_count, (u8*)"image-file-prefix", NULL);
- ext_in_permalink
- = get_value(vars, vars_count, (u8*)"ext-in-permalink", NULL);
+ = get_value(vars, vars_count, (u8*)"image-file-prefix");
+ ext_in_permalink = get_value(vars, vars_count, (u8*)"ext-in-permalink");
var_add_article_header
- = get_value(vars, vars_count, (u8*)"add-article-header", NULL);
+ = get_value(vars, vars_count, (u8*)"add-article-header");
var_add_image_links
- = get_value(vars, vars_count, (u8*)"add-image-links", NULL);
+ = get_value(vars, vars_count, (u8*)"add-image-links");
add_image_links = !(var_add_image_links && *var_add_image_links == '0');
- var_add_figcaption
- = get_value(vars, vars_count, (u8*)"add-figcaption", NULL);
+ var_add_figcaption = get_value(vars, vars_count, (u8*)"add-figcaption");
add_figcaption = !(var_add_figcaption && *var_add_figcaption == '0');
var_add_footnote_div
- = get_value(vars, vars_count, (u8*)"add-footnote-div", NULL);
+ = get_value(vars, vars_count, (u8*)"add-footnote-div");
add_footnote_div = var_add_footnote_div && *var_add_footnote_div == '1';
- link_prefix = get_value(vars, vars_count, (u8*)"link-prefix", NULL);
+ link_prefix = get_value(vars, vars_count, (u8*)"link-prefix");
CALLOC(line, u8, BUFSIZE);
token_size = BUFSIZE;
@@ -3645,7 +3636,7 @@ do_line:
break;
}
- if ((IN(state, ST_TAG)) && pline - 1 && *(pline - 1) == '{')
+ if ((IN(state, ST_TAG)) && *(pline - 1) == '{')
{
end_tag = 1;
pline++;
@@ -3666,10 +3657,44 @@ do_line:
break;
}
- if (IN(state, ST_TAG))
+ *ptoken = 0;
+
+ if (IN(state, ST_MACRO_BODY)
+ && !(end_tag && startswith((const char*)token, "=")))
+ {
+ size_t token_len;
+ size_t value_len;
+
+ if (read_yaml_macros_and_links)
+ {
+ token_len = strlen((char*)token);
+
+ skip_eol = 1;
+ value_len = strlen((char*)pmacros->value);
+
+ if (pmacros->value_size
+ < value_len + token_len + 1)
+ {
+ pmacros->value_size += token_len;
+ REALLOC(pmacros->value, u8,
+ pmacros->value_size);
+ }
+ strcat((char*)pmacros->value, "{");
+ if (end_tag)
+ strcat((char*)pmacros->value, "/");
+ strcat(strcat((char*)pmacros->value,
+ (char*)token),
+ "}");
+ }
+
+ *token = 0;
+ ptoken = token;
+ state &= ~ST_TAG;
+ end_tag = 0;
+ }
+ else if (IN(state, ST_TAG))
{
state &= ~ST_TAG;
- *ptoken = 0;
process_tag(output, token, link_prefix,
read_yaml_macros_and_links, &skip_eol, end_tag);
@@ -4176,7 +4201,7 @@ do_line:
process_inline_link(output, link_text,
link_prefix,
get_value(macros, macros_count,
- link_macro, NULL),
+ link_macro),
token);
else
process_inline_image(output, link_text,
@@ -4250,7 +4275,7 @@ do_line:
if (!read_yaml_macros_and_links)
process_link(output, link_text, link_prefix,
get_value(macros, macros_count,
- link_macro, NULL),
+ link_macro),
token);
RESET_TOKEN(token, ptoken, token_size);
state &= ~(ST_LINK | ST_LINK_SECOND_ARG);