slweb

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

чување 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:
Mdefs.h | 2++
Aindex-meta.csv | 11+++++++++++
Mindex.html | 14++++++++++++--
Mindex.slw | 4+++-
Mslweb.1.in | 48++++++++++++++++++++++++++++++++++++++++++++++++
Mslweb.c | 280+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
измењених датотека: 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 &lt;<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",