чување 1a90eb5b61baad995ba2461c9f9baed701e39179
родитељ f2304d16aef289cb15d5e59881c54e72123cca1b
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Sun, 7 Feb 2021 15:39:48 +0100
Added canonical and meta YAML variables; index-meta.csv: New file
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
измењених датотека: 6, додавања: 236(+), брисања: 123(-)
diff --git a/defs.h b/defs.h
@@ -86,6 +86,8 @@ typedef struct
BOOL seen; /* for use with macros */
} KeyValue;
+typedef int (*csv_callback_t)(FILE* output, uint8_t** csv_header, uint8_t** csv_register);
+
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-const-variable"
#define MAX_HEADING_LEVEL 4
diff --git a/index-meta.csv b/index-meta.csv
@@ -0,0 +1,11 @@
+"Name","Content"
+"og:type","website"
+"og:url","%canonical%"
+"og:title","%site-name%"
+"og:description","%site-desc%"
+"twitter:card","summary_large_image"
+"twitter:url","%canonical%"
+"twitter:title","%site-name%"
+"twitter:creator","@strahinja_radic"
+"twitter:description","%site-desc%"
+
diff --git a/index.html b/index.html
@@ -1,9 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
-<title>slweb - Simple static website generator. </title>
+<title>slweb - Simple static website generator</title>
<meta charset="utf-8" />
<link rel="shortcut icon" type="image/x-icon" href="/slweb/favicon.ico" />
+<meta name="og:type" content="website" />
+<meta name="og:url" content="https://strahinja.github.io/slweb/" />
+<meta name="og:title" content="slweb - Simple static website generator" />
+<meta name="og:description" content="Simple static website generator" />
+<meta name="twitter:card" content="summary_large_image" />
+<meta name="twitter:url" content="https://strahinja.github.io/slweb/" />
+<meta name="twitter:title" content="slweb - Simple static website generator" />
+<meta name="twitter:creator" content="@strahinja_radic" />
+<meta name="twitter:description" content="Simple static website generator" />
+<link rel="canonical" href="https://strahinja.github.io/slweb/" />
<meta name="description" content="Simple static website generator" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="generator" content="slweb" />
@@ -136,7 +146,7 @@ this program. If not, see <<a href="https://www.gnu.org/licenses">https://www
<div id="git-log">
Previous commit:
-index.slw d9b80ba 2021-02-07 14:05:09 +0100 (Страхиња Радић) (HEAD -> master, origin/master, origin/HEAD)
+index.slw f2304d1 2021-02-07 14:06:23 +0100 (Страхиња Радић) (HEAD -> master, origin/master, origin/HEAD)
</div><!--git-log-->
diff --git a/index.slw b/index.slw
@@ -1,9 +1,11 @@
---
-site-name: slweb - Simple static website generator.
+site-name: slweb - Simple static website generator
site-desc: Simple static website generator
stylesheet: index.css
stylesheet: https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css
favicon-url: /slweb/favicon.ico
+canonical: https://strahinja.github.io/slweb/
+meta: index-meta.csv
---
{main}
# slweb
diff --git a/slweb.1.in b/slweb.1.in
@@ -718,6 +718,11 @@ body (inside a \fC<header>\fP tag if it is set), surrounded by
\fC<address></address>\fP.
.
.IP \[bu]
+.BR canonical .
+Contents of this variable will be added as a value of a \fCrel\fP attribute for
+the \fC<link rel="canonical" />\fP tag.
+.
+.IP \[bu]
.BR csv-delimiter .
Changes the delimiter used for
.I .csv
@@ -764,6 +769,49 @@ Contents of this variable will be used for the \fClang\fP attribute of the
\fC<html>\fP tag.
.
.IP \[bu]
+.BR meta .
+Contents of this variable is treated as a filename specifying the CSV file
+containing a list of values to be inserted into meta tags. The first row of this
+CSV file is treated as the header row and ignored. First column in this CSV file
+contains the meta variable names, and the second column contains meta variable
+values. For each row, a \fC<meta name="\f[CI]firstcol\fC"
+content="\f[CI]secondcol\fC" />\fR is inserted, where
+.I firstcol
+is the first column, and
+.I secondcol
+is the second column. If the values in the second column are surrounded with
+percent signs (\fC%\fP), the value between them is treated as the name of the
+YAML variable to insert. For example, having the file
+.IR m.csv :
+.
+.CDS 8
+"Name","Content"
+"og:url","%canonical%"
+.CDE
+.
+.IP ""
+and
+.
+.CDS 8
+---
+canonical: https://example.com/
+meta: m.csv
+---
+.CDE
+.
+.IP ""
+in the
+.I .slw
+file, a
+.
+.CDS 8
+<meta name="og:url" content="https://example.com/" />
+.CDE
+.
+.IP ""
+line will be added to the output.
+.
+.IP \[bu]
.BR permalink-url .
If present, this
.SM URL
diff --git a/slweb.c b/slweb.c
@@ -402,16 +402,32 @@ read_file_into_buffer(uint8_t** buffer, size_t* buffer_size, char* input_filenam
}
int
-process_meta(FILE* output, const uint8_t* csv_filename)
-{
- FILE* csv = fopen((const char*)csv_filename, "r");
- uint8_t* bufline = NULL;
- uint8_t* pbufline = NULL;
- size_t csv_lineno = 0;
- if (!csv)
- exit(error(ENOENT, (uint8_t*)"meta: No such file: %s", csv_filename));
- /*while (*/
- fclose(csv);
+read_csv(FILE* output, const char* filename, csv_callback_t callback);
+
+int
+print_meta_var(FILE* output, uint8_t** csv_header, uint8_t** csv_register)
+{
+ if (*csv_register && *(csv_register+1))
+ {
+ uint8_t* pvalue = *(csv_register+1);
+ size_t value_len = u8_strlen(pvalue);
+ if (*pvalue == '%' && *(pvalue+value_len-1) == '%')
+ {
+ uint8_t* var_name = NULL;
+ var_name = u8_strdup(pvalue+1);
+ *(var_name+value_len-2) = 0;
+ uint8_t* value = get_value(vars, vars_count, var_name, NULL);
+
+ if (value)
+ print_output(output, "<meta name=\"%s\" content=\"%s\" />\n",
+ *csv_register, value);
+
+ free(var_name);
+ }
+ else
+ print_output(output, "<meta name=\"%s\" content=\"%s\" />\n",
+ *csv_register, *(csv_register+1));
+ }
return 0;
}
@@ -606,70 +622,89 @@ print_csv_row(FILE* output, uint8_t** csv_header, uint8_t** csv_register)
}
int
-process_csv(uint8_t* arg_token, FILE* output, BOOL read_yaml_macros_and_links,
- BOOL end_tag)
-{
- if (end_tag)
- {
- state &= ~ST_CSV_BODY;
-
- if (read_yaml_macros_and_links)
- return 0;
-
- FILE* csv = fopen(csv_filename, "rt");
- size_t csv_lineno = 0;
- uint8_t* bufline = NULL;
- uint8_t* pbufline = NULL;
- uint8_t* token = NULL;
- uint8_t* ptoken = NULL;
- size_t token_size = 0;
- UBYTE csv_state = ST_CS_NONE;
- uint8_t* csv_header[MAX_CSV_REGISTERS];
- UBYTE current_header = 0;
- uint8_t* csv_register[MAX_CSV_REGISTERS];
- UBYTE current_register = 0;
- uint8_t* csv_delimiter = get_value(vars, vars_count,
- (uint8_t*)"csv-delimiter", NULL);
-
- if (!csv)
- exit(error(ENOENT, (uint8_t*)"csv: No such file: %s", csv_filename));
+read_csv(FILE* output, const char* filename, csv_callback_t callback)
+{
+ if (!callback)
+ exit(error(EINVAL, (uint8_t*)"read_csv: Invalid callback argument"));
+
+ FILE* csv = NULL;
+ size_t csv_lineno = 0;
+ uint8_t* bufline = NULL;
+ uint8_t* pbufline = NULL;
+ uint8_t* token = NULL;
+ uint8_t* ptoken = NULL;
+ size_t token_size = 0;
+ UBYTE csv_state = ST_CS_NONE;
+ uint8_t* csv_header[MAX_CSV_REGISTERS];
+ UBYTE current_header = 0;
+ uint8_t* csv_register[MAX_CSV_REGISTERS];
+ UBYTE current_register = 0;
+ uint8_t* csv_delimiter = get_value(vars, vars_count,
+ (uint8_t*)"csv-delimiter", NULL);
+
+ if (!(csv = fopen(filename, "rt")))
+ exit(error(ENOENT, (uint8_t*)"csv: No such file: %s", filename));
+
+ CALLOC(bufline, uint8_t, BUFSIZE)
+ token_size = BUFSIZE;
+ CALLOC(token, uint8_t, token_size)
+ for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
+ CALLOC(csv_header[i], uint8_t, BUFSIZE)
+ for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
+ CALLOC(csv_register[i], uint8_t, BUFSIZE)
- CALLOC(bufline, uint8_t, BUFSIZE)
- token_size = BUFSIZE;
- CALLOC(token, uint8_t, token_size)
- for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
- CALLOC(csv_header[i], uint8_t, BUFSIZE)
- for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
- CALLOC(csv_register[i], uint8_t, BUFSIZE)
+ while (!feof(csv) && (!csv_iter || csv_lineno <= csv_iter))
+ {
+ uint8_t* eol = NULL;
+ if (!fgets((char*)bufline, BUFSIZE, csv))
+ break;
+ eol = u8_strchr(bufline, (ucs4_t)'\n');
+ if (eol)
+ *eol = 0;
- while (!feof(csv) && (!csv_iter || csv_lineno <= csv_iter))
+ pbufline = bufline;
+ RESET_TOKEN(token, ptoken, token_size)
+ current_register = 0;
+ while (*pbufline)
{
- uint8_t* eol = NULL;
- if (!fgets((char*)bufline, BUFSIZE, csv))
- break;
- eol = u8_strchr(bufline, (ucs4_t)'\n');
- if (eol)
- *eol = 0;
-
- pbufline = bufline;
- RESET_TOKEN(token, ptoken, token_size)
- current_register = 0;
- while (*pbufline)
+ switch (*pbufline)
{
- switch (*pbufline)
+ case '"':
+ if (csv_state & ST_CS_QUOTE)
+ csv_state &= ~ST_CS_QUOTE;
+ else
+ csv_state |= ST_CS_QUOTE;
+ pbufline++;
+ break;
+ case ';':
+ case ',':
+ if (csv_state & ST_CS_QUOTE)
+ CHECKCOPY(token, ptoken, token_size, pbufline)
+ else
{
- case '"':
- if (csv_state & ST_CS_QUOTE)
- csv_state &= ~ST_CS_QUOTE;
+ *ptoken = 0;
+ if (csv_lineno > 0)
+ {
+ if (current_register < MAX_CSV_REGISTERS)
+ u8_strncpy(csv_register[current_register++], token,
+ BUFSIZE-1);
+ }
else
- csv_state |= ST_CS_QUOTE;
+ {
+ if (current_header < MAX_CSV_REGISTERS)
+ u8_strncpy(csv_header[current_header++], token,
+ BUFSIZE-1);
+ }
+ RESET_TOKEN(token, ptoken, token_size)
pbufline++;
- break;
- case ';':
- case ',':
- if (csv_state & ST_CS_QUOTE)
- CHECKCOPY(token, ptoken, token_size, pbufline)
- else
+ }
+ break;
+ default:
+ if (csv_state & ST_CS_QUOTE)
+ CHECKCOPY(token, ptoken, token_size, pbufline)
+ else
+ {
+ if (csv_delimiter && *pbufline == *csv_delimiter)
{
*ptoken = 0;
if (csv_lineno > 0)
@@ -687,64 +722,58 @@ process_csv(uint8_t* arg_token, FILE* output, BOOL read_yaml_macros_and_links,
RESET_TOKEN(token, ptoken, token_size)
pbufline++;
}
- break;
- default:
- if (csv_state & ST_CS_QUOTE)
- CHECKCOPY(token, ptoken, token_size, pbufline)
else
- {
- if (csv_delimiter && *pbufline == *csv_delimiter)
- {
- *ptoken = 0;
- if (csv_lineno > 0)
- {
- if (current_register < MAX_CSV_REGISTERS)
- u8_strncpy(csv_register[current_register++], token,
- BUFSIZE-1);
- }
- else
- {
- if (current_header < MAX_CSV_REGISTERS)
- u8_strncpy(csv_header[current_header++], token,
- BUFSIZE-1);
- }
- RESET_TOKEN(token, ptoken, token_size)
- pbufline++;
- }
- else
- CHECKCOPY(token, ptoken, token_size, pbufline)
- }
+ CHECKCOPY(token, ptoken, token_size, pbufline)
}
}
- *ptoken = 0;
- if (csv_lineno > 0)
- {
- if (current_register < MAX_CSV_REGISTERS)
- u8_strncpy(csv_register[current_register++], token,
- BUFSIZE-1);
- }
- else
- {
- if (current_header < MAX_CSV_REGISTERS)
- u8_strncpy(csv_header[current_header++], token, BUFSIZE-1);
- }
- RESET_TOKEN(token, ptoken, token_size)
+ }
+ *ptoken = 0;
+ if (csv_lineno > 0)
+ {
+ if (current_register < MAX_CSV_REGISTERS)
+ u8_strncpy(csv_register[current_register++], token,
+ BUFSIZE-1);
+ }
+ else
+ {
+ if (current_header < MAX_CSV_REGISTERS)
+ u8_strncpy(csv_header[current_header++], token, BUFSIZE-1);
+ }
+ RESET_TOKEN(token, ptoken, token_size)
- if (csv_lineno > 0 && pbufline != bufline)
- print_csv_row(output, csv_header, csv_register);
+ if (csv_lineno > 0 && pbufline != bufline)
+ (*callback)(output, csv_header, csv_register);
- for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
- *csv_register[i] = 0;
- csv_lineno++;
- }
- fclose(csv);
- for (UBYTE i = MAX_CSV_REGISTERS; i > 0; i--)
- free(csv_register[i-1]);
- for (UBYTE i = MAX_CSV_REGISTERS; i > 0; i--)
- free(csv_header[i-1]);
- free(token);
- free(bufline);
+ for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
+ *csv_register[i] = 0;
+ csv_lineno++;
+ }
+ fclose(csv);
+ for (UBYTE i = MAX_CSV_REGISTERS; i > 0; i--)
+ free(csv_register[i-1]);
+ for (UBYTE i = MAX_CSV_REGISTERS; i > 0; i--)
+ free(csv_header[i-1]);
+ free(token);
+ free(bufline);
+
+ return 0;
+}
+
+int
+process_csv(uint8_t* arg_token, FILE* output, BOOL read_yaml_macros_and_links,
+ BOOL end_tag)
+{
+ if (end_tag)
+ {
+ state &= ~ST_CSV_BODY;
+ if (read_yaml_macros_and_links)
+ return 0;
+
+ read_csv(output, csv_filename, &print_csv_row);
+
+ free(csv_filename);
+ csv_filename = NULL;
free(csv_template);
csv_template = NULL;
csv_template_size = 0;
@@ -1764,6 +1793,7 @@ begin_html_and_head(FILE* output)
uint8_t* lang = get_value(vars, vars_count, (uint8_t*)"lang", NULL);
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);
+ uint8_t* canonical = get_value(vars, vars_count, (uint8_t*)"canonical", NULL);
uint8_t* favicon_url = get_value(vars, vars_count, (uint8_t*)"favicon-url", NULL);
uint8_t* meta = get_value(vars, vars_count, (uint8_t*)"meta", NULL);
@@ -1785,7 +1815,17 @@ begin_html_and_head(FILE* output)
free(favicon);
if (meta)
- process_meta(output, meta);
+ {
+ char* filename = NULL;
+ CALLOC(filename, char, BUFSIZE)
+ snprintf(filename, BUFSIZE, "%s/%s", input_dirname, (char*)meta);
+ read_csv(output, filename, &print_meta_var);
+ free(filename);
+ }
+
+ if (canonical && *canonical)
+ print_output(output, "<link rel=\"canonical\" href=\"%s\" />\n",
+ (char*)canonical);
if (site_desc && *site_desc)
print_output(output, "<meta name=\"description\" content=\"%s\" />\n",