чување 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:
измењених датотека: 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 © _someguy_{/span}
+{span}([Link to index](../../../index.html), from include) Copyright © _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 <<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