slweb

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

чување 050330558e035e7a04f1a4d4f135244c1fae5268
родитељ 388802f43ee8b213c7271d5f1dd55e1068713e60
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Wed, 30 Dec 2020 14:18:28 +0100

Completed the migration to C; added the directive incdir, replacing the old lsdirs

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

Diffstat:
MREADME | 4----
MTODO | 8++++++--
Mdefault.html.do | 2+-
Mdefault.o.do | 2+-
Mdefs.h | 4++++
Mexamples/includes/inc/copy.slw | 2+-
Aexamples/includes/index.html.do | 4++++
Mindex.html | 2+-
Mslweb.1.in | 52++++++++++++++++++++++------------------------------
Mslweb.c | 611+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mslweb.do | 2+-
измењених датотека: 11, додавања: 480(+), брисања: 213(-)

diff --git a/README b/README @@ -39,10 +39,6 @@ $ sudo ./do install See the examples/ directory in this repository. -NOTE: Since the migration to C, not all of the features of bash/sed-based slweb -are yet ported, so not all of the examples work as intended. This is still a -WIP, see the file TODO for more details. - License ------- diff --git a/TODO b/TODO @@ -1,6 +1,10 @@ TODO ==== + [ ] Make {timestamp "d.m.y"} directive + [ ] Add a switch to signal inclusion from incdir + + Migration to C checklist ------------------------ @@ -12,8 +16,8 @@ Migration to C checklist [x] Add {#id} processing [x] Convert strncat token processing to individual token-based [x] -d support (determine real pathname in links) - [ ] Add {lsdir} + [x] Add {incdir} [x] Add title: processing - [ ] Update manpage + [x] Update manpage [x] Add backslash-escaping of blank lines for normal tags diff --git a/default.html.do b/default.html.do @@ -1,3 +1,3 @@ redo-ifchange $2.slw slweb -./slweb $2.slw >$3 +./slweb -d $(dirname $2.slw) $2.slw >$3 diff --git a/default.o.do b/default.o.do @@ -1,3 +1,3 @@ redo-ifchange $2.c -cc -g -Wall -o $3 -c $2.c +cc -g -Wall -std=c99 -o $3 -c $2.c diff --git a/defs.h b/defs.h @@ -20,6 +20,9 @@ #ifndef __DEFS_H #define __DEFS_H +#define _POSIX_C_SOURCE 200809L + +#include <dirent.h> #include <errno.h> #include <stdarg.h> #include <stdio.h> @@ -27,6 +30,7 @@ #include <stdint.h> #include <string.h> #include <sys/stat.h> +#include <sys/types.h> #include <unistr.h> #include <unistdio.h> #include <uniwidth.h> diff --git a/examples/includes/inc/copy.slw b/examples/includes/inc/copy.slw @@ -1,2 +1,2 @@ -{span}([Link to index](../index.html), from include) Copyright &copy; _someguy_{/span} +{span}([Link to index](../../../index.html), from include) Copyright &copy; _someguy_{/span} diff --git a/examples/includes/index.html.do b/examples/includes/index.html.do @@ -0,0 +1,4 @@ +for f in *.slw inc/*.slw; do + echo $f +done | xargs redo-ifchange + diff --git a/index.html b/index.html @@ -127,7 +127,7 @@ this program. If not, see &lt;<a href="https://www.gnu.org/licenses">https://www <div id="git-log"> Previous commit: -index.slw 4ed6157 2020-12-29 12:48:34 +0100 (Страхиња Радић) (HEAD -> master, origin/redo-instead-of-make, origin/master, origin/HEAD, redo-instead-of-make) +index.slw 388802f 2020-12-29 19:54:19 +0100 (Страхиња Радић) (HEAD -> master, tag: v0.3.1-beta, origin/master, origin/HEAD) </div><!--git-log--> diff --git a/slweb.1.in b/slweb.1.in @@ -195,7 +195,7 @@ file, it will be replaced by the macro body. . .IP \[bu] 4 .BR "Subdirectory inclusion (blogging directive)" . -The command \fC{lsdirs \fInum\fC =\fImacroname\fC}\fR +The command \fC{incdir \fInum\fC =\fImacroname\fC}\fR .RI ( num and .I macroname @@ -203,8 +203,8 @@ are optional) will be expanded as follows: . .RS .IP 1. 4 -A \fC<ul class="dir">\fR tag will be inserted into the document instead of the -directive. +A \fC<ul class="incdir">\fR tag will be inserted into the document instead of +the directive. . .IP 2. 4 For every subdirectory of the directory containing the input file, up to @@ -221,18 +221,16 @@ name of the subdirectory. If .I macroname is present, the name of the subdirectory will be prepended with the body of a macro -.IR macroname . +.I macroname +(for example, this can be used to include custom +.SM SVG +files as arrows). . .IP 5. 4 After the \fC<summary>\fR tag a \fC<div>\fR tag will be inserted into -\fC<details>\fR, containing the concatenated contents of each +\fC<details>\fR, containing the concatenated output from processing each of the .I .slw -file inside that subdirectory in reverse lexicographical order (\fCsort -r\fR). -For each file included in this manner, a \fC<h1>\fR tag will be prepended, -containing the contents of that file's \fCtitle:\fR -.SM YAML -variable. -. +files inside that subdirectory in reverse lexicographical order. .RE . .IP \[bu] @@ -255,17 +253,17 @@ home page. supported by slweb are: . .IP \[bu] 4 -.BR site-name . -The contents of this variable will be inserted inside the \fC<title></title>\fR -tags. -. -.IP \[bu] 4 .BR site-desc . The contents of this variable will be inserted as the value of the .I content attribute of the \fC<meta name="description">\fR tag. . .IP \[bu] 4 +.BR site-name . +The contents of this variable will be inserted inside the \fC<title></title>\fR +tags. +. +.IP \[bu] 4 .BR stylesheet . The contents of this variable will be treated as a .sm CSS @@ -274,8 +272,14 @@ have more than one \fCstylesheet\fR declaration per \fI.slw\fR file. . .IP \[bu] 4 .BR title . -If present, contents of this variable will be prepended to the body as a second -level heading (\fCtitle: Some title\fR becomes \fC<h2>Some title</h2>\fR). +If present, contents of this variable will be prepended to the body as a heading +with the level determined by the \fCtitle-heading-level\fR variable, defaulting +to 2. (\fCtitle: Some title\fR becomes \fC<h2>Some title</h2>\fR). +. +.IP \[bu] 4 +.BR title-heading-level . +See +.BR title . . .SH "SEE ALSO" .BR sed (1) @@ -339,18 +343,6 @@ file \fCindex.html\fR contains: .SH "KNOWN LIMITATIONS" . .IP \[bu] 4 -As of v0.3.0, -.B slweb -is undergoing a migration from Bash script using -.BR sed (1) -to a C program. Not all old features will be working or working as intended -until this migration is complete. See the file -.SM TODO -in the Github repository and the -.SM BUGS -section below. -. -.IP \[bu] 4 Currently there is no way to determine where the paragraph inside a tag should begin and end without adding blank lines or using the \fC{p}{/p}\fR notation. For example, the code diff --git a/slweb.c b/slweb.c @@ -18,7 +18,6 @@ */ #include "defs.h" -#include <string.h> static size_t lineno = 0; static size_t colno = 1; @@ -27,16 +26,16 @@ static char* input_dirname = NULL; static char* basedir = NULL; static char* arg_zero = NULL; -#define CHECKEXITNOMEM(ptr) if (!ptr) exit(error(ENOMEM, \ - (uint8_t*)"Memory allocation failed (out of memory?)\n")) +#define CHECKEXITNOMEM(ptr) { if (!ptr) exit(error(ENOMEM, \ + (uint8_t*)"Memory allocation failed (out of memory?)\n")); } #define CALLOC(ptr, ptrtype, nmemb) { \ - ptr = (ptrtype*) calloc(nmemb, sizeof(ptrtype)); \ - CHECKEXITNOMEM(ptr); } + ptr = calloc(nmemb, sizeof(ptrtype)); \ + CHECKEXITNOMEM(ptr) } #define REALLOC(ptr, ptrtype, newsize) { \ - ptr = (ptrtype*) realloc(ptr, newsize); \ - CHECKEXITNOMEM(ptr); } + ptr = realloc(ptr, newsize); \ + CHECKEXITNOMEM(ptr) } int version() @@ -142,6 +141,54 @@ set_basedir(char* arg, char** basedir) return 0; } +char* +strip_ext(const char* fn) +{ + char* newname = NULL; + char* pnewname = NULL; + const char* pfn = NULL; + char* dot = NULL; + dot = strrchr(fn, '.'); + if (!dot) + return NULL; + CALLOC(newname, char, strlen(fn)) + pnewname = newname; + pfn = fn; + while (pfn != dot && *pfn) + *pnewname++ = *pfn++; + return newname; +} + +int +print_command(uint8_t* command, FILE* output) +{ + FILE* cmd_output = popen((char*)command, "r"); + + if (!cmd_output) + { + perror("popen"); + return 1; + } + + uint8_t* cmd_output_line = NULL; + CALLOC(cmd_output_line, uint8_t, BUFSIZE) + while (!feof(cmd_output)) + { + if (!fgets((char*)cmd_output_line, BUFSIZE, cmd_output)) + continue; + + char* eol = strchr((char*)cmd_output_line, '\n'); + if (eol) + *eol = '\0'; + + fprintf(output, "%s\n", cmd_output_line); + + } + pclose(cmd_output); + + return 0; +} + int process_heading(uint8_t* token, FILE* output, UBYTE heading_level) { @@ -155,186 +202,412 @@ process_heading(uint8_t* token, FILE* output, UBYTE heading_level) } int -process_tag(uint8_t* token, FILE* output, KeyValue** macros, - size_t* macros_count, KeyValue** pmacros, ULONG* state, - BOOL read_yaml_macros_and_links, BOOL* skip_eol, - BOOL end_tag) +process_git_log(FILE* output) { - if (!token || u8_strlen(token) < 1) - return warning(1, (uint8_t*)"Empty tag name\n"); + if (!input_filename) + return warning(1, (uint8_t*)"Cannot use 'git-log' in stdin\n"); + + char* basename = NULL; + CALLOC(basename, char, strlen(input_filename)) + char* slash = strrchr(input_filename, '/'); + if (slash) + strncpy(basename, slash+1, strlen(slash+1)); + else + strncpy(basename, input_filename, strlen(input_filename)); - if (!strcmp((char*)token, "git-log") - && !read_yaml_macros_and_links) /* {git-log} */ + fprintf(output, "<div id=\"git-log\">\nPrevious commit:\n"); + uint8_t* command = NULL; + CALLOC(command, uint8_t, BUFSIZE) + u8_snprintf(command, BUFSIZE, + "git log -1 --pretty=format:\"%s %%h %%ci (%%cn) %%d\"" + " || echo \"(Not in a Git repository)\"", + basename); + if (print_command(command, output)) { - if (!input_filename) - return warning(1, (uint8_t*)"Cannot use 'git-log' in stdin\n"); + fprintf(output, "</div><!--git-log-->\n"); + return error(1, (uint8_t*)"git-log: Cannot run git\n"); + } + fprintf(output, "</div><!--git-log-->\n"); - char* basename = NULL; - CALLOC(basename, char, strlen(input_filename)) - char* slash = strrchr(input_filename, '/'); - if (slash) - strncpy(basename, slash+1, strlen(slash+1)); - else - strncpy(basename, input_filename, strlen(input_filename)); - - fprintf(output, "<div id=\"git-log\">\nPrevious commit:\n"); - uint8_t* command = NULL; - CALLOC(command, uint8_t, BUFSIZE) - u8_snprintf(command, BUFSIZE, - "git log -1 --pretty=format:\"%s %%h %%ci (%%cn) %%d\"" - " || echo \"(Not in a Git repository)\"", - basename); - FILE* cmd_output = popen((char*)command, "r"); - if (!cmd_output) - { - fprintf(output, "</div><!--git-log-->\n"); - perror(PROGRAMNAME); - return warning(1, (uint8_t*)"git-log: Cannot popen\n"); - } - uint8_t* cmd_output_line = NULL; - CALLOC(cmd_output_line, uint8_t, BUFSIZE) - while (!feof(cmd_output)) - { - if (!fgets((char*)cmd_output_line, BUFSIZE, cmd_output)) - continue; + free(command); + free(basename); - char* eol = strchr((char*)cmd_output_line, '\n'); - if (eol) - *eol = '\0'; + return 0; +} - fprintf(output, "%s\n", cmd_output_line); +int +process_include(uint8_t* token, FILE* output, ULONG* state, + BOOL read_yaml_macros_and_links) +{ + if (read_yaml_macros_and_links) + return 0; - } - pclose(cmd_output); - fprintf(output, "</div><!--git-log-->\n"); + if (!arg_zero) + exit(error(EINVAL, (uint8_t*)"Invalid argument zero\n")); - free(command); - free(cmd_output_line); - free(basename); + if (!input_filename) + return warning(1, (uint8_t*)"Cannot use 'include' in stdin\n"); - } - else if (!strcmp((char*)token, "made-by") - && !read_yaml_macros_and_links) /* {made-by} */ + uint8_t* command = NULL; + uint8_t* ptoken = u8_strchr(token, (ucs4_t)' '); + char* include_filename = NULL; + char* pinclude_filename = NULL; + CALLOC(include_filename, char, BUFSIZE) + pinclude_filename = include_filename; + + if (!ptoken) + return warning(1, (uint8_t*)"Directive 'include' requires" + " an argument\n"); + + ptoken++; + while (ptoken && *ptoken) + if (*ptoken != '"') + *pinclude_filename++ = *ptoken++; + else + ptoken++; + + CALLOC(command, uint8_t, BUFSIZE) + u8_snprintf(command, BUFSIZE, "%s -b -d %s %s/%s.slw", + arg_zero, + !strcmp(basedir, ".") ? input_dirname : basedir, + input_dirname, + include_filename); + + if (print_command(command, output)) { - fprintf(output, "<div id=\"made-by\">\n" - "Generated by <a href=\"https://github.com/Strahinja/slweb\">" - "slweb</a>\n" - "© 2020 Strahinya Radich.\n" - "</div><!--made-by-->\n"); + return error(1, (uint8_t*)"include: Cannot process include\n"); } - else if (!strcmp(substr((char*)token, 0, strlen("include")), "include")) - /* {include} */ + + free(command); + free(include_filename); + + return 0; +} + +int +filter_subdirs(const struct dirent* node) +{ + if (!node || !strcmp(node->d_name, ".") || !strcmp(node->d_name, "..")) + return 0; + + struct stat st; + char* nodename = NULL; + + CALLOC(nodename, char, BUFSIZE) + snprintf(nodename, BUFSIZE, "%s/%s", basedir, node->d_name); + + if (lstat(nodename, &st) < 0 || !S_ISDIR(st.st_mode)) { - if (!read_yaml_macros_and_links) - { - if (!arg_zero) - exit(error(EINVAL, (uint8_t*)"Invalid argument zero\n")); + free(nodename); + return 0; + } - if (!input_filename) - return warning(1, (uint8_t*)"Cannot use 'include' in stdin\n"); + free(nodename); - uint8_t* command = NULL; - uint8_t* ptoken = u8_strchr(token, (ucs4_t)' '); - char* include_filename = NULL; - char* pinclude_filename = NULL; - CALLOC(include_filename, char, BUFSIZE) - pinclude_filename = include_filename; - - *skip_eol = TRUE; + return 1; +} - if (!ptoken) - return warning(1, (uint8_t*)"Directive 'include' requires" - " an argument\n"); +int +filter_slw(const struct dirent* node) +{ + if (!node || !strcmp(node->d_name, ".") || !strcmp(node->d_name, "..")) + return 0; - ptoken++; - while (ptoken && *ptoken) - if (*ptoken != '"') - *pinclude_filename++ = *ptoken++; - else - ptoken++; + size_t node_len = strlen(node->d_name); + size_t slw_len = strlen(".slw"); - CALLOC(command, uint8_t, BUFSIZE) - u8_snprintf(command, BUFSIZE, "%s -b -d %s %s/%s.slw", - arg_zero, - !strcmp(basedir, ".") ? input_dirname : basedir, - input_dirname, - include_filename); + if (slw_len >= node_len) + return 0; - FILE* cmd_output = popen((char*)command, "r"); - if (!cmd_output) - { - perror(PROGRAMNAME); - return warning(1, (uint8_t*)"include: Cannot popen\n"); - } - uint8_t* cmd_output_line = NULL; - CALLOC(cmd_output_line, uint8_t, BUFSIZE) - while (!feof(cmd_output)) - { - if (!fgets((char*)cmd_output_line, BUFSIZE, cmd_output)) - continue; + return (!strcmp(substr(node->d_name, + node_len - slw_len, + node_len), ".slw")); +} - char* eol = strchr((char*)cmd_output_line, '\n'); - if (eol) - *eol = '\0'; +int +reverse_alphacompare(const struct dirent** a, const struct dirent** b) +{ + if (!a || !b) + return 0; - fprintf(output, "%s\n", cmd_output_line); + return -1 * strcmp((*a)->d_name, (*b)->d_name); +} - } - pclose(cmd_output); +int +process_incdir_subdir(const char* subdirname, FILE* output, BOOL details_open, + uint8_t* macro_body) +{ + fprintf(output, "<li>\n<details%s>\n<summary>", + details_open ? " open" : ""); + if (macro_body) + fprintf(stdout, "%s", macro_body); + fprintf(output, "%s</summary>\n<div>\n", subdirname); + + struct dirent** namelist; + struct dirent** pnamelist; + long names_total; + long names_output; + uint8_t* command = NULL; + char* abs_subdirname = NULL; + char* filename_noext = NULL; - free(cmd_output_line); - free(command); - free(include_filename); - } - *skip_eol = TRUE; - } - else if (*token == '=') /* {=macro} */ + CALLOC(abs_subdirname, char, BUFSIZE) + snprintf(abs_subdirname, BUFSIZE, "%s/%s", basedir, subdirname); + + if ((names_total = scandir(abs_subdirname, &namelist, &filter_slw, + &reverse_alphacompare)) < 0) { - *skip_eol = TRUE; - if (!end_tag) - { - BOOL seen = FALSE; + perror("scandir"); + exit(error(errno, (uint8_t*)"incdir_subdir: scandir error\n")); + } - uint8_t* macro_body = get_value(*macros, *macros_count, token+1, - read_yaml_macros_and_links ? NULL : &seen); + CALLOC(command, uint8_t, BUFSIZE); - if (macro_body) + pnamelist = namelist; + names_output = 0; + while (names_output < names_total && pnamelist && *pnamelist) + { + filename_noext = strip_ext((*pnamelist)->d_name); + char* in_filename = NULL; + char* in_line = NULL; + char* date = NULL; + char* day = NULL; + char* month = NULL; + char* year = NULL; + CALLOC(in_filename, char, BUFSIZE) + CALLOC(in_line, char, BUFSIZE) + snprintf(in_filename, BUFSIZE, "%s/%s", + abs_subdirname, (*pnamelist)->d_name); + FILE* in = fopen(in_filename, "rt"); + while (!feof(in)) + { + if (!fgets(in_line, BUFSIZE, in)) + break; + char* eol = strchr(in_line, '\n'); + if (eol) + *eol = '\0'; + if (startswith(in_line, "date: ")) { - if (!read_yaml_macros_and_links) - { - if (seen) - fprintf(output, "%s", macro_body); - else - *state |= ST_MACRO_BODY; - } + date = strchr(in_line, ' ')+1; + break; } - else + } + /* TODO: - Make this a separate directive, to make it more general. + * For example, {timestamp "d.m.y"}. + * + * - Make a new switch to talk to slweb subprocess from + * incdir inclusion and signal the different handling + * when standalone vs when included in incdir + * + * -- SR */ + if (date) + { + year = strtok(date, "-"); + if (year) { - if (read_yaml_macros_and_links) + month = strtok(NULL, "-"); + if (month) { - (*macros_count)++; - - if (*macros_count > 1) + day = strtok(NULL, "T"); + if (day) { - REALLOC(*macros, KeyValue, - *macros_count * sizeof(KeyValue)) - *pmacros = *macros + *macros_count - 1; + fprintf(output, "<a href=\"%s/%s.html\">%s.%s.%s</a>", + abs_subdirname, + filename_noext ? filename_noext + : (*pnamelist)->d_name, + day, + month, + year); } - CALLOC((*pmacros)->key, uint8_t, u8_strlen(token+1)) - (*pmacros)->seen = FALSE; - u8_strcpy((*pmacros)->key, token+1); - (*pmacros)->value = NULL; } - *state |= ST_MACRO_BODY; - *skip_eol = TRUE; + } + } + free(in_line); + free(in_filename); + + u8_snprintf(command, BUFSIZE, "%s -b -d %s %s/%s", + arg_zero, abs_subdirname, abs_subdirname, + (*pnamelist)->d_name); + if (print_command(command, output)) + { + fprintf(output, "</div>\b</details>\n</li>\n"); + if (filename_noext) + free(filename_noext); + free(abs_subdirname); + free(command); + return error(1, (uint8_t*)"process_incdir_subdir: Cannot process file '%s'\n", (*pnamelist)->d_name); + } + if (filename_noext) + free(filename_noext); + pnamelist++; + names_output++; + } + + free(abs_subdirname); + free(command); + + fprintf(output, "</div>\n</details>\n</li>\n"); + return 0; +} + +int +process_incdir(uint8_t* token, FILE* output, KeyValue** macros, + size_t* macros_count, KeyValue** pmacros, ULONG* state, + BOOL read_yaml_macros_and_links) +{ + if (read_yaml_macros_and_links) + return 0; + + uint8_t* saveptr = NULL; + /* skipping the first token (incdir) */ + uint8_t* arg = u8_strtok(token, (uint8_t*)" ", &saveptr); + long num = 5; + uint8_t* macro_body = NULL; + struct dirent** namelist; + struct dirent** pnamelist; + long names_output; + BOOL details_open = TRUE; + + arg = u8_strtok(NULL, (uint8_t*)" ", &saveptr); + if (!arg) + return warning(1, (uint8_t*)"incdir: Arguments required\n"); + if (*arg == '=') + { + macro_body = get_value(*macros, *macros_count, arg+1, NULL); + } + else + { + uint8_t* parg = arg; + while (parg && *parg) + { + if (*parg < '0' || *parg > '9') + return warning(1, (uint8_t*)"incdir: Non-numeric argument\n"); + parg++; + } + num = strtol((char*)arg, NULL, 10); + if (errno) + return warning(errno, (uint8_t*)"incdir: Invalid num\n"); + arg = u8_strtok(NULL, (uint8_t*)" ", &saveptr); + if (*arg != '=') + return warning(1, (uint8_t*)"incdir: Second argument not macro\n"); + macro_body = get_value(*macros, *macros_count, arg+1, NULL); + } + + fprintf(output, "<ul class=\"incdir\">\n"); + + if (scandir(basedir, &namelist, &filter_subdirs, + &reverse_alphacompare) < 0) + { + perror("scandir"); + exit(error(errno, (uint8_t*)"incdir: scandir error\n")); + } + + pnamelist = namelist; + names_output = 0; + while (names_output < num && pnamelist && *pnamelist) + { + process_incdir_subdir((*pnamelist)->d_name, output, details_open, + macro_body); + details_open = FALSE; + pnamelist++; + names_output++; + } + free(namelist); + + fprintf(output, "</ul>\n"); + + return 0; +} + +int +process_macro(uint8_t* token, FILE* output, KeyValue** macros, + size_t* macros_count, KeyValue** pmacros, ULONG* state, + BOOL read_yaml_macros_and_links, BOOL end_tag) +{ + 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 { - *state &= ~ST_MACRO_BODY; - *skip_eol = TRUE; + if (read_yaml_macros_and_links) + { + (*macros_count)++; + + if (*macros_count > 1) + { + REALLOC(*macros, KeyValue, + *macros_count * sizeof(KeyValue)) + *pmacros = *macros + *macros_count - 1; + } + CALLOC((*pmacros)->key, uint8_t, u8_strlen(token+1)) + (*pmacros)->seen = FALSE; + u8_strcpy((*pmacros)->key, token+1); + (*pmacros)->value = NULL; + } + *state |= ST_MACRO_BODY; } } + else + { + *state &= ~ST_MACRO_BODY; + } + return 0; +} + +int +process_tag(uint8_t* token, FILE* output, KeyValue** macros, + size_t* macros_count, KeyValue** pmacros, ULONG* state, + BOOL read_yaml_macros_and_links, BOOL* skip_eol, + BOOL end_tag) +{ + if (!token || u8_strlen(token) < 1) + return warning(1, (uint8_t*)"Empty tag name\n"); + + if (!strcmp((char*)token, "git-log") + && !read_yaml_macros_and_links) /* {git-log} */ + { + process_git_log(output); + } + else if (!strcmp((char*)token, "made-by") + && !read_yaml_macros_and_links) /* {made-by} */ + { + fprintf(output, "<div id=\"made-by\">\n" + "Generated by <a href=\"https://github.com/Strahinja/slweb\">" + "slweb</a>\n" + "© 2020 Strahinya Radich.\n" + "</div><!--made-by-->\n"); + } + else if (startswith((char*)token, "include")) /* {include} */ + { + process_include(token, output, state, read_yaml_macros_and_links); + *skip_eol = TRUE; + } + else if (startswith((char*)token, "incdir")) /* {incdir} */ + { + process_incdir(token, output, macros, macros_count, pmacros, state, + read_yaml_macros_and_links); + *skip_eol = TRUE; + } + else if (*token == '=') /* {=macro} */ + { + process_macro(token, output, macros, macros_count, pmacros, state, + read_yaml_macros_and_links, end_tag); + *skip_eol = TRUE; + } else if (!read_yaml_macros_and_links) /* general tags */ { fprintf(output, "<"); @@ -630,13 +903,8 @@ 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", NULL); - fprintf(output, "</head>\n<body>\n"); - if (title) - fprintf(output, "<h2>%s</h2>\n", (char*)title); - return 0; } @@ -654,6 +922,9 @@ slweb_parse(uint8_t* buffer, FILE* output, KeyValue** links, size_t* links_count, BOOL body_only, BOOL read_yaml_macros_and_links) { + uint8_t* title = get_value(*vars, *vars_count, (uint8_t*)"title", NULL); + uint8_t* title_heading_level = get_value(*vars, *vars_count, + (uint8_t*)"title-heading-level", NULL); uint8_t* pbuffer = NULL; uint8_t* line = NULL; uint8_t* pline = NULL; @@ -697,6 +968,12 @@ slweb_parse(uint8_t* buffer, FILE* output, end_head_start_body(output, *vars, *vars_count); } + if (title) + fprintf(output, "<h%s>%s</h%s>\n", + title_heading_level ? (char*)title_heading_level : "2", + (char*)title, + title_heading_level ? (char*)title_heading_level : "2"); + do { uint8_t* eol = u8_strchr(pbuffer, (ucs4_t)'\n'); @@ -1089,8 +1366,7 @@ slweb_parse(uint8_t* buffer, FILE* output, && *(pline+1) == ' ') { *ptoken = '\0'; - u8_strncat(ptoken, (uint8_t*)"<br />", - strlen("<br />")); + u8_strncat(ptoken, (uint8_t*)"<br />", strlen("<br />")); ptoken += strlen("<br />"); pline++; colno++; @@ -1372,7 +1648,8 @@ slweb_parse(uint8_t* buffer, FILE* output, { if (state & ST_LINK_SECOND_ARG) process_inline_link(link_text, - get_value(*macros, *macros_count, link_macro, NULL), + get_value(*macros, *macros_count, + link_macro, NULL), token, output); else process_inline_image(link_text, token, output); @@ -1401,7 +1678,8 @@ slweb_parse(uint8_t* buffer, FILE* output, { if (!read_yaml_macros_and_links) process_link(link_text, - get_value(*macros, *macros_count, link_macro, NULL), + get_value(*macros, *macros_count, + link_macro, NULL), token, *links, *links_count, output); *token = '\0'; ptoken = token; @@ -1558,7 +1836,6 @@ slweb_parse(uint8_t* buffer, FILE* output, heading_level = 0; } else - { process_text_token(&state, first_line_in_doc, previous_line_blank, processed_start_of_line, @@ -1567,7 +1844,6 @@ slweb_parse(uint8_t* buffer, FILE* output, &token, &ptoken, TRUE); - } } if ((state & ST_PARA_OPEN) @@ -1589,15 +1865,10 @@ slweb_parse(uint8_t* buffer, FILE* output, previous_line_blank = FALSE; } - if (!skip_eol) - { - if (!read_yaml_macros_and_links - && !(state & (ST_YAML | ST_YAML_VAL - | ST_LINK_SECOND_ARG))) - { + if (!skip_eol && !read_yaml_macros_and_links + && !(state & (ST_YAML | ST_YAML_VAL + | ST_LINK_SECOND_ARG))) fprintf(output, "\n"); - } - } *token = '\0'; ptoken = token; @@ -1607,7 +1878,6 @@ slweb_parse(uint8_t* buffer, FILE* output, first_line_in_doc = FALSE; skip_change_first_line_in_doc = FALSE; - ; if (line_len == 0) previous_line_blank = TRUE; @@ -1746,9 +2016,6 @@ main(int argc, char** argv) CALLOC(input_dirname, char, 2) *input_dirname = '.'; } - - if (!strcmp(basedir, ".")) - strcpy(basedir, input_dirname); } else { diff --git a/slweb.do b/slweb.do @@ -1,3 +1,3 @@ redo-ifchange slweb.o slweb.c defs.h -cc -g -Wall -o $3 slweb.o -lunistring +cc -g -Wall -std=c99 -o $3 slweb.o -lunistring