чување 63fe27d7488a401c47ad9911b7026c6fd5221b6a
родитељ a873fe3d22e59c34a01aea5346ee44aaacebb608
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Fri, 18 Mar 2022 23:06:34 +0100
Adjust for current slweb (0.4.5+)
Diffstat:
измењених датотека: 9, додавања: 826(+), брисања: 402(-)
diff --git a/AUTHORS b/AUTHORS
@@ -0,0 +1 @@
+Strahinya Radich <contact@strahinja.org>
diff --git a/all.do b/all.do
@@ -1,2 +1 @@
-redo-ifchange slw2gmi
-redo-ifchange slw2gmi.1.gz
+redo-ifchange version.h slw2gmi slw2gmi.1.gz
diff --git a/default.h.do b/default.h.do
@@ -0,0 +1,12 @@
+if [ -r $1.in ]; then
+ redo-ifchange $1.in version date
+ read VERSION <version
+ read DATE <date
+ sed -e "s/%VERSION%/$VERSION/g" \
+ -e "s/%DATE%/$DATE/g" <$1.in
+else
+ if [ -f $2.def.h ]; then
+ redo-ifchange $2.def.h
+ cat $2.def.h > $3
+ fi
+fi
diff --git a/defs.h b/defs.h
@@ -5,6 +5,7 @@
#define _POSIX_C_SOURCE 200809L
+#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <stdarg.h>
@@ -18,11 +19,10 @@
#include <sys/wait.h>
#include <unistd.h>
+#include "version.h"
#include "utf8.h"
-#define PROGRAMNAME "slw2gmi"
-#define VERSION "0.1.4"
-#define COPYRIGHTYEAR "2021"
+#define COPYRIGHTYEAR "2021, 2022"
#define MADEBY_URL "https://strahinja.srht.site/slw2gmi/"
#define BUFSIZE 1024
@@ -41,6 +41,8 @@ static const char* CMD_GIT_LOG_ARGS[] = {"xargs", "-I{}", "git", "log", "-1",
#define ANY(var, mask) (((var) & (mask)) != 0)
#define IN(var, mask) ALL(var, mask)
+#define MIN(a, b) ((a < b) ? (a) : (b))
+
typedef unsigned char UBYTE;
typedef unsigned long ULONG;
typedef unsigned long long ULLONG;
@@ -55,14 +57,14 @@ typedef enum {
} Command;
typedef struct {
- uint8_t* key;
- uint8_t* value;
+ u8* key;
+ u8* value;
size_t value_size;
int seen; /* for use with macros */
} KeyValue;
-typedef int (*csv_callback_t)(FILE* output, uint8_t** csv_header,
- uint8_t** csv_register);
+typedef int (*csv_callback_t)(FILE* output, u8** csv_header, u8** csv_register);
+typedef int (*tsv_callback_t)(FILE* output, u8** tsv_header, u8** tsv_register);
#ifdef __GNUC__
#pragma GCC diagnostic push
@@ -70,6 +72,7 @@ typedef int (*csv_callback_t)(FILE* output, uint8_t** csv_header,
#endif
#define MAX_HEADING_LEVEL 4
#define MAX_CSV_REGISTERS 9
+#define MAX_TSV_REGISTERS 9
#define ST_NONE 0
#define ST_YAML 1
@@ -92,19 +95,20 @@ typedef int (*csv_callback_t)(FILE* output, uint8_t** csv_header,
#define ST_IMAGE_SECOND_ARG ((ULLONG)1 << 17)
#define ST_MACRO_BODY ((ULLONG)1 << 18)
#define ST_CSV_BODY ((ULLONG)1 << 19)
-#define ST_HTML_TAG ((ULLONG)1 << 20)
-#define ST_KBD ((ULLONG)1 << 21)
-#define ST_LIST ((ULLONG)1 << 22)
-#define ST_NUMLIST ((ULLONG)1 << 23)
-#define ST_FOOTNOTE ((ULLONG)1 << 24)
-#define ST_FOOTNOTE_TEXT ((ULLONG)1 << 25)
-#define ST_INLINE_FOOTNOTE ((ULLONG)1 << 26)
-#define ST_FORMULA ((ULLONG)1 << 27)
-#define ST_DISPLAY_FORMULA ((ULLONG)1 << 28)
-#define ST_TABLE_HEADER ((ULLONG)1 << 29)
-#define ST_TABLE_LINE ((ULLONG)1 << 30)
-#define ST_TABLE ((ULLONG)1 << 31)
-#define ST_STRIKE ((ULLONG)1 << 32)
+#define ST_TSV_BODY ((ULLONG)1 << 20)
+#define ST_HTML_TAG ((ULLONG)1 << 21)
+#define ST_KBD ((ULLONG)1 << 22)
+#define ST_LIST ((ULLONG)1 << 23)
+#define ST_NUMLIST ((ULLONG)1 << 24)
+#define ST_FOOTNOTE ((ULLONG)1 << 25)
+#define ST_FOOTNOTE_TEXT ((ULLONG)1 << 26)
+#define ST_INLINE_FOOTNOTE ((ULLONG)1 << 27)
+#define ST_FORMULA ((ULLONG)1 << 28)
+#define ST_DISPLAY_FORMULA ((ULLONG)1 << 29)
+#define ST_TABLE_HEADER ((ULLONG)1 << 30)
+#define ST_TABLE_LINE ((ULLONG)1 << 31)
+#define ST_TABLE ((ULLONG)1 << 32)
+#define ST_STRIKE ((ULLONG)1 << 33)
#define ST_ENT ((ULLONG)1 << 33)
#define ST_CS_NONE 0
diff --git a/slw2gmi.c b/slw2gmi.c
@@ -36,6 +36,10 @@ static u8* csv_template = NULL;
static size_t csv_template_size = 0;
static char* csv_filename = NULL;
static long csv_iter = 0;
+static u8* tsv_template = NULL;
+static size_t tsv_template_size = 0;
+static char* tsv_filename = NULL;
+static long tsv_iter = 0;
static ULLONG state = ST_NONE;
#define CHECKEXITNOMEM(ptr) \
@@ -90,7 +94,7 @@ static ULLONG state = ST_NONE;
int
version()
{
- printf("%s v%s\n", PROGRAMNAME, VERSION);
+ printf("%s %s\n", PROGRAMNAME, VERSION);
return 0;
}
@@ -139,10 +143,8 @@ free_keyvalue(KeyValue** list, const size_t list_count)
for (size_t index = 0; index < list_count; index++)
{
KeyValue* current = *list + index;
- if (current->value)
- free(current->value);
- if (current->key)
- free(current->key);
+ free(current->value);
+ free(current->key);
}
return 0;
}
@@ -150,32 +152,27 @@ free_keyvalue(KeyValue** list, const size_t list_count)
int
slweb_cleanup()
{
- if (basedir)
- free(basedir);
+ free(basedir);
free(input_dirname);
while (inline_footnote_count--)
free(inline_footnotes[inline_footnote_count]);
- if (inline_footnotes)
- free(inline_footnotes);
+ free(inline_footnotes);
free_keyvalue(&footnotes, footnote_count);
free_keyvalue(¶links, paralinks_count);
free_keyvalue(&links, links_count);
free_keyvalue(¯os, macros_count);
free_keyvalue(&vars, vars_count);
- if (footnotes)
- free(footnotes);
- if (paralinks)
- free(paralinks);
- if (links)
- free(links);
- if (macros)
- free(macros);
- if (vars)
- free(vars);
+ free(footnotes);
+ free(paralinks);
+ free(links);
+ free(macros);
+ free(vars);
return 0;
}
+int simple_parse_yaml_line(const u8* line, KeyValue** vars, size_t* vars_count,
+ KeyValue** pvars);
int slweb_parse(FILE* output, const char* source_filename, const u8* buffer,
const int read_yaml_macros_and_links);
@@ -212,12 +209,10 @@ endswith(const char* s, const char* what)
pwhat++;
while (ps != s && pwhat != what)
- {
if (*ps-- != *pwhat--)
return 0;
- }
- return pwhat == what;
+ return *ps == *pwhat && pwhat == what;
}
u8*
@@ -256,7 +251,7 @@ set_basedir(char** basedir, size_t* basedir_size, const char* arg)
*basedir_size = arg_len + 1;
REALLOC(*basedir, char, *basedir_size);
}
- strncpy(*basedir, arg, *basedir_size - 1);
+ strcpy(*basedir, arg);
*(*basedir + arg_len) = 0;
basedir_len = strlen(*basedir);
if (*(*basedir + basedir_len - 1) == '/')
@@ -279,7 +274,7 @@ set_global_link_prefix(char** global_link_prefix,
*global_link_prefix_size = arg_len + 1;
REALLOC(*global_link_prefix, char, *global_link_prefix_size);
}
- strncpy(*global_link_prefix, arg, *global_link_prefix_size - 1);
+ strcpy(*global_link_prefix, arg);
*(*global_link_prefix + arg_len) = 0;
return 0;
@@ -327,8 +322,7 @@ print_output(FILE* output, const char* fmt, ...)
{
csv_template_size = BUFSIZE;
CALLOC(csv_template, u8, csv_template_size);
- strncpy((char*)csv_template, buf, BUFSIZE - 1);
- *(csv_template + buf_len) = 0;
+ strcpy((char*)csv_template, buf);
}
else
{
@@ -338,9 +332,29 @@ print_output(FILE* output, const char* fmt, ...)
csv_template_size += BUFSIZE;
REALLOC(csv_template, u8, csv_template_size);
}
- strncat((char*)csv_template, buf,
- csv_template_size - strlen((char*)csv_template)
- - 1);
+ strcat((char*)csv_template, buf);
+ }
+ }
+ else if (IN(state, ST_TSV_BODY))
+ {
+ size_t buf_len = 0;
+ vsnprintf((char*)buf, BUFSIZE, fmt, args);
+ buf_len = strlen(buf);
+ if (!tsv_template)
+ {
+ tsv_template_size = BUFSIZE;
+ CALLOC(tsv_template, u8, tsv_template_size);
+ strcpy((char*)tsv_template, buf);
+ }
+ else
+ {
+ if (strlen((char*)tsv_template) + buf_len
+ > tsv_template_size)
+ {
+ tsv_template_size += BUFSIZE;
+ REALLOC(tsv_template, u8, tsv_template_size);
+ }
+ strcat((char*)tsv_template, buf);
}
}
else
@@ -359,10 +373,10 @@ print_command(FILE* output, const char* command, const u8* pass_arguments[],
if (!command || !pass_arguments)
exit(error(EINVAL, (u8*)"print_command: Invalid argument"));
- pid_t pid = 0;
+ pid_t pid = 0;
+ int pstatus = 0;
int arg_pipe_fds[2];
int output_pipe_fds[2];
- int pstatus = 0;
fflush(output);
pipe(arg_pipe_fds);
@@ -408,10 +422,12 @@ print_command(FILE* output, const char* command, const u8* pass_arguments[],
CALLOC(cmd_output_line, u8, BUFSIZE);
while (!feof(cmd_output))
{
+ char* eol = NULL;
+
if (!fgets((char*)cmd_output_line, BUFSIZE, cmd_output))
continue;
- char* eol = strchr((char*)cmd_output_line, '\n');
+ eol = strchr((char*)cmd_output_line, '\n');
if (eol)
*eol = 0;
@@ -448,14 +464,12 @@ read_file_into_buffer(FILE** input, u8** buffer, size_t* buffer_size,
return error(ENOENT, (u8*)"No such file: %s", input_filename);
fstat(fileno(*input), &fs);
- if (*buffer)
- free(*buffer);
+ free(*buffer);
*buffer_size = fs.st_size + 1;
CALLOC(*buffer, u8, *buffer_size);
fread((void*)*buffer, 1, *buffer_size, *input);
- if (*input_dirname)
- free(*input_dirname);
+ free(*input_dirname);
slash = strrchr(input_filename, '/');
if (slash)
@@ -479,15 +493,13 @@ read_file_into_buffer(FILE** input, u8** buffer, size_t* buffer_size,
}
int read_csv(FILE* output, const char* filename, csv_callback_t callback);
+int read_tsv(FILE* output, const char* filename, tsv_callback_t callback);
int
-process_heading_start(FILE* output, const UBYTE heading_level,
- int first_line_in_doc, const int previous_line_blank)
+process_heading_start(FILE* output, const UBYTE heading_level)
{
if (!output_firstcol)
print_output(output, "\n");
- /*if (!previous_line_blank && !first_line_in_doc)
- print_output(output, "\n");*/
for (size_t i = 0; i < heading_level; i++)
print_output(output, "#");
print_output(output, " ");
@@ -520,9 +532,9 @@ process_git_log(FILE* output)
pid_t result = 0;
if (slash)
- strncpy(basename, slash + 1, basename_size - 1);
+ strcpy(basename, slash + 1);
else
- strncpy(basename, input_filename, basename_size - 1);
+ strcpy(basename, input_filename);
u8* pipe_args[] = {(u8*)basename, NULL};
@@ -537,7 +549,322 @@ process_git_log(FILE* output)
return result ? warning(result, (u8*)"git-log: Cannot run git") : 0;
}
-#define PRINTIF(format, arg) \
+#define PRINTTSVIF(format, arg) \
+ do \
+ { \
+ if ((ALL(tsv_state, ST_CS_COND_NONEMPTY) \
+ && *tsv_register[conditional_index - 1]) \
+ || (ALL(tsv_state, ST_CS_COND_EMPTY) \
+ && !*tsv_register[conditional_index - 1]) \
+ || !ANY(tsv_state, \
+ ST_CS_COND_EMPTY | ST_CS_COND_NONEMPTY)) \
+ { \
+ fprintf(output, format, arg); \
+ } \
+ } while (0)
+
+int
+print_tsv_row(FILE* output, u8** tsv_header, u8** tsv_register)
+{
+ u8* ptsv_template = tsv_template;
+ UBYTE tsv_state = ST_CS_NONE;
+ UBYTE num = 0;
+ UBYTE conditional_index = 0;
+
+tsv_template_start:
+ if (!*ptsv_template)
+ goto tsv_template_done;
+ if (IN(tsv_state, ST_CS_ESCAPE))
+ {
+ PRINTTSVIF("%c", *ptsv_template);
+ tsv_state &= ~ST_CS_ESCAPE;
+ ptsv_template++;
+ goto tsv_template_start;
+ }
+
+ switch (*ptsv_template)
+ {
+ case '\\':
+ tsv_state |= ST_CS_ESCAPE;
+ ptsv_template++;
+ break;
+ case '$':
+ if (IN(tsv_state, ST_CS_REGISTER))
+ {
+ PRINTTSVIF("%c", '$');
+ tsv_state &= ~ST_CS_REGISTER;
+ }
+ else
+ tsv_state |= ST_CS_REGISTER;
+ ptsv_template++;
+ break;
+ case '#':
+ if (IN(tsv_state, ST_CS_HEADER))
+ {
+ error(1, (u8*)"tsv: Invalid header register mark");
+ tsv_state &= ~(ST_CS_REGISTER | ST_CS_HEADER);
+ }
+ else if (IN(tsv_state, ST_CS_REGISTER))
+ {
+ tsv_state &= ~ST_CS_REGISTER;
+ tsv_state |= ST_CS_HEADER;
+ }
+ else
+ PRINTTSVIF("%c", '#');
+ ptsv_template++;
+ break;
+ case '?':
+ if (IN(tsv_state, ST_CS_COND))
+ {
+ error(1, (u8*)"tsv: Invalid conditional mark");
+ tsv_state &= ~ST_CS_COND;
+ }
+ else if (IN(tsv_state, ST_CS_REGISTER))
+ {
+ tsv_state &= ~ST_CS_REGISTER;
+ tsv_state |= ST_CS_COND;
+ }
+ else
+ PRINTTSVIF("%c", '?');
+ ptsv_template++;
+ break;
+ case '!':
+ if (ALL(tsv_state, ST_CS_COND | ST_CS_COND_NONEMPTY))
+ {
+ tsv_state &= ~(ST_CS_COND | ST_CS_COND_NONEMPTY);
+ tsv_state |= ST_CS_COND_EMPTY;
+ }
+ else if (IN(tsv_state, ST_CS_COND))
+ {
+ error(1,
+ (u8*)"Empty conditional before/without nonempty"
+ " conditional");
+ tsv_state &= ~(ST_CS_COND | ST_CS_COND_EMPTY);
+ }
+ else
+ PRINTTSVIF("%c", '!');
+ ptsv_template++;
+ break;
+ case '/':
+ if (ALL(tsv_state, ST_CS_COND | ST_CS_COND_EMPTY))
+ tsv_state &= ~(ST_CS_COND | ST_CS_COND_EMPTY);
+ else if (ALL(tsv_state, ST_CS_COND))
+ tsv_state &= ~(ST_CS_COND | ST_CS_COND_NONEMPTY);
+ else
+ PRINTTSVIF("%c", '/');
+ ptsv_template++;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (IN(tsv_state, ST_CS_COND))
+ {
+ conditional_index = *ptsv_template - '0';
+ tsv_state &= ~ST_CS_COND;
+ tsv_state |= ST_CS_COND_NONEMPTY;
+ }
+ else if (IN(tsv_state, ST_CS_HEADER))
+ {
+ num = *ptsv_template - '0';
+ PRINTTSVIF("%s", tsv_header[num - 1]);
+ tsv_state &= ~ST_CS_HEADER;
+ }
+ else if (IN(tsv_state, ST_CS_REGISTER))
+ {
+ num = *ptsv_template - '0';
+ PRINTTSVIF("%s", tsv_register[num - 1]);
+ tsv_state &= ~ST_CS_REGISTER;
+ }
+ else
+ PRINTTSVIF("%c", *ptsv_template);
+ ptsv_template++;
+ break;
+ default:
+ if (IN(tsv_state, ST_CS_HEADER))
+ {
+ error(1, (u8*)"tsv: Invalid header register mark");
+ tsv_state &= ~ST_CS_HEADER;
+ }
+ else if (IN(tsv_state, ST_CS_REGISTER))
+ {
+ error(1, (u8*)"tsv: Invalid register mark");
+ tsv_state &= ~ST_CS_REGISTER;
+ }
+ else
+ PRINTTSVIF("%c", *ptsv_template);
+ ptsv_template++;
+ }
+ goto tsv_template_start;
+tsv_template_done:
+ return 0;
+}
+
+int
+read_tsv(FILE* output, const char* filename, tsv_callback_t callback)
+{
+ if (!callback)
+ exit(error(EINVAL, (u8*)"read_tsv: Invalid callback argument"));
+
+ FILE* tsv = NULL;
+ size_t tsv_lineno = 0;
+ u8* bufline = NULL;
+ u8* pbufline = NULL;
+ u8* token = NULL;
+ u8* ptoken = NULL;
+ size_t token_size = 0;
+ u8* tsv_header[MAX_TSV_REGISTERS];
+ UBYTE current_header = 0;
+ u8* tsv_register[MAX_TSV_REGISTERS];
+ UBYTE current_register = 0;
+
+ if (!(tsv = fopen(filename, "rt")))
+ exit(error(ENOENT, (u8*)"tsv: No such file: %s", filename));
+
+ CALLOC(bufline, u8, BUFSIZE);
+ token_size = BUFSIZE;
+ CALLOC(token, u8, token_size);
+ for (UBYTE i = 0; i < MAX_TSV_REGISTERS; i++)
+ CALLOC(tsv_header[i], u8, BUFSIZE);
+ for (UBYTE i = 0; i < MAX_TSV_REGISTERS; i++)
+ CALLOC(tsv_register[i], u8, BUFSIZE);
+
+ while (!feof(tsv) && (!tsv_iter || tsv_lineno <= tsv_iter))
+ {
+ u8* eol = NULL;
+ if (!fgets((char*)bufline, BUFSIZE, tsv))
+ break;
+ eol = (u8*)strchr((char*)bufline, '\n');
+ if (eol)
+ *eol = 0;
+
+ pbufline = bufline;
+ RESET_TOKEN(token, ptoken, token_size);
+ current_register = 0;
+ tsv_bufline_start:
+ if (!*pbufline)
+ goto tsv_bufline_done;
+ switch (*pbufline)
+ {
+ case '\t':
+ *ptoken = 0;
+ if (tsv_lineno > 0
+ && current_register < MAX_TSV_REGISTERS)
+ strcpy((char*)tsv_register[current_register++],
+ (char*)token);
+ else if (tsv_lineno <= 0
+ && current_header < MAX_TSV_REGISTERS)
+ strcpy((char*)tsv_header[current_header++],
+ (char*)token);
+ RESET_TOKEN(token, ptoken, token_size);
+ pbufline++;
+ break;
+ default:
+ CHECKCOPY(token, ptoken, token_size, pbufline);
+ }
+ goto tsv_bufline_start;
+ tsv_bufline_done:
+ *ptoken = 0;
+ if (tsv_lineno > 0)
+ {
+ if (current_register < MAX_TSV_REGISTERS)
+ strcpy((char*)tsv_register[current_register++],
+ (char*)token);
+ }
+ else
+ {
+ if (current_header < MAX_TSV_REGISTERS)
+ strcpy((char*)tsv_header[current_header++],
+ (char*)token);
+ }
+ RESET_TOKEN(token, ptoken, token_size);
+
+ if (tsv_lineno > 0 && pbufline != bufline)
+ (*callback)(output, tsv_header, tsv_register);
+
+ for (UBYTE i = 0; i < MAX_TSV_REGISTERS; i++)
+ *tsv_register[i] = 0;
+ tsv_lineno++;
+ }
+ fclose(tsv);
+ for (UBYTE i = MAX_TSV_REGISTERS; i > 0; i--)
+ free(tsv_register[i - 1]);
+ for (UBYTE i = MAX_TSV_REGISTERS; i > 0; i--)
+ free(tsv_header[i - 1]);
+ free(token);
+ free(bufline);
+
+ return 0;
+}
+
+int
+process_tsv(FILE* output, const u8* arg_token,
+ const int read_yaml_macros_and_links, const int end_tag)
+{
+ if (end_tag)
+ {
+ state &= ~ST_TSV_BODY;
+
+ if (read_yaml_macros_and_links)
+ return 0;
+
+ read_tsv(output, tsv_filename, &print_tsv_row);
+
+ free(tsv_filename);
+ tsv_filename = NULL;
+ free(tsv_template);
+ tsv_template = NULL;
+ tsv_template_size = 0;
+ }
+ else
+ {
+ if (ANY(state, ST_CSV_BODY | ST_TSV_BODY))
+ exit(error(1, (u8*)"Can't nest csv/tsv directives"));
+
+ state |= ST_TSV_BODY;
+
+ if (read_yaml_macros_and_links)
+ return 0;
+
+ tsv_iter = 0;
+ u8* saveptr = NULL;
+ u8* args = (u8*)strtok_r((char*)arg_token, " ",
+ (char**)&saveptr);
+ args = (u8*)strtok_r(NULL, " ", (char**)&saveptr);
+ if (!args)
+ exit(error(EINVAL, (u8*)"tsv: Arguments required"));
+ size_t args_len = strlen((char*)args);
+ if (*args != '"' || *(args + args_len - 1) != '"')
+ exit(error(EINVAL,
+ (u8*)"tsv: First argument must be a string"));
+ if (!tsv_filename)
+ CALLOC(tsv_filename, u8, BUFSIZE);
+ u8* args_base = (u8*)strdup((char*)args + 1);
+ *(args_base + strlen((char*)args_base) - 1) = 0;
+ snprintf(tsv_filename, BUFSIZE, "%s/%s.tsv", input_dirname,
+ (char*)args_base);
+ free(args_base);
+ args = (u8*)strtok_r(NULL, " ", (char**)&saveptr);
+ if (args)
+ {
+ errno = 0;
+ tsv_iter = strtol((char*)args, NULL, 10);
+ if (errno)
+ exit(error(errno,
+ (u8*)"tsv: Invalid argument '%s'",
+ args));
+ }
+ }
+
+ return 0;
+}
+
+#define PRINTCSVIF(format, arg) \
do \
{ \
if ((ALL(csv_state, ST_CS_COND_NONEMPTY) \
@@ -559,143 +886,137 @@ print_csv_row(FILE* output, u8** csv_header, u8** csv_register)
UBYTE num = 0;
UBYTE conditional_index = 0;
- while (*pcsv_template)
+csv_template_start:
+ if (!*pcsv_template)
+ goto csv_template_done;
+ if (IN(csv_state, ST_CS_ESCAPE))
{
- if (IN(csv_state, ST_CS_ESCAPE))
+ PRINTCSVIF("%c", *pcsv_template);
+ csv_state &= ~ST_CS_ESCAPE;
+ pcsv_template++;
+ goto csv_template_start;
+ }
+
+ switch (*pcsv_template)
+ {
+ case '\\':
+ csv_state |= ST_CS_ESCAPE;
+ pcsv_template++;
+ break;
+ case '$':
+ if (IN(csv_state, ST_CS_REGISTER))
{
- PRINTIF("%c", *pcsv_template);
- csv_state &= ~ST_CS_ESCAPE;
- pcsv_template++;
- continue;
+ PRINTCSVIF("%c", '$');
+ csv_state &= ~ST_CS_REGISTER;
}
-
- switch (*pcsv_template)
+ else
+ csv_state |= ST_CS_REGISTER;
+ pcsv_template++;
+ break;
+ case '#':
+ if (IN(csv_state, ST_CS_HEADER))
{
- case '\\':
- csv_state |= ST_CS_ESCAPE;
- pcsv_template++;
- break;
- case '$':
- if (IN(csv_state, ST_CS_REGISTER))
- {
- PRINTIF("%c", '$');
- csv_state &= ~ST_CS_REGISTER;
- }
- else
- csv_state |= ST_CS_REGISTER;
- pcsv_template++;
- break;
- case '#':
- if (IN(csv_state, ST_CS_HEADER))
- {
- error(1,
- (u8*)"csv: Invalid header "
- "register mark");
- csv_state &= ~(ST_CS_REGISTER | ST_CS_HEADER);
- }
- else if (IN(csv_state, ST_CS_REGISTER))
- {
- csv_state &= ~ST_CS_REGISTER;
- csv_state |= ST_CS_HEADER;
- }
- else
- PRINTIF("%c", '#');
- pcsv_template++;
- break;
- case '?':
- if (IN(csv_state, ST_CS_COND))
- {
- error(1, (u8*)"csv: Invalid conditional mark");
- csv_state &= ~ST_CS_COND;
- }
- else if (IN(csv_state, ST_CS_REGISTER))
- {
- csv_state &= ~ST_CS_REGISTER;
- csv_state |= ST_CS_COND;
- }
- else
- PRINTIF("%c", '?');
- pcsv_template++;
- break;
- case '!':
- if (ALL(csv_state, ST_CS_COND | ST_CS_COND_NONEMPTY))
- {
- csv_state
- &= ~(ST_CS_COND | ST_CS_COND_NONEMPTY);
- csv_state |= ST_CS_COND_EMPTY;
- }
- else if (IN(csv_state, ST_CS_COND))
- {
- error(1,
- (u8*)"Empty conditional "
- "before/without "
- "nonempty"
- " conditional");
- csv_state &= ~(ST_CS_COND | ST_CS_COND_EMPTY);
- }
- else
- PRINTIF("%c", '!');
- pcsv_template++;
- break;
- case '/':
- if (ALL(csv_state, ST_CS_COND | ST_CS_COND_EMPTY))
- csv_state &= ~(ST_CS_COND | ST_CS_COND_EMPTY);
- else if (ALL(csv_state, ST_CS_COND))
- csv_state
- &= ~(ST_CS_COND | ST_CS_COND_NONEMPTY);
- else
- PRINTIF("%c", '/');
- pcsv_template++;
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- if (IN(csv_state, ST_CS_COND))
- {
- conditional_index = *pcsv_template - '0';
- csv_state &= ~ST_CS_COND;
- csv_state |= ST_CS_COND_NONEMPTY;
- }
- else if (IN(csv_state, ST_CS_HEADER))
- {
- num = *pcsv_template - '0';
- PRINTIF("%s", csv_header[num - 1]);
- csv_state &= ~ST_CS_HEADER;
- }
- else if (IN(csv_state, ST_CS_REGISTER))
- {
- num = *pcsv_template - '0';
- PRINTIF("%s", csv_register[num - 1]);
- csv_state &= ~ST_CS_REGISTER;
- }
- else
- PRINTIF("%c", *pcsv_template);
- pcsv_template++;
- break;
- default:
- if (IN(csv_state, ST_CS_HEADER))
- {
- error(1,
- (u8*)"csv: Invalid header "
- "register mark");
- csv_state &= ~ST_CS_HEADER;
- }
- else if (IN(csv_state, ST_CS_REGISTER))
- {
- error(1, (u8*)"csv: Invalid register mark");
- csv_state &= ~ST_CS_REGISTER;
- }
- else
- PRINTIF("%c", *pcsv_template);
- pcsv_template++;
+ error(1, (u8*)"csv: Invalid header register mark");
+ csv_state &= ~(ST_CS_REGISTER | ST_CS_HEADER);
+ }
+ else if (IN(csv_state, ST_CS_REGISTER))
+ {
+ csv_state &= ~ST_CS_REGISTER;
+ csv_state |= ST_CS_HEADER;
+ }
+ else
+ PRINTCSVIF("%c", '#');
+ pcsv_template++;
+ break;
+ case '?':
+ if (IN(csv_state, ST_CS_COND))
+ {
+ error(1, (u8*)"csv: Invalid conditional mark");
+ csv_state &= ~ST_CS_COND;
+ }
+ else if (IN(csv_state, ST_CS_REGISTER))
+ {
+ csv_state &= ~ST_CS_REGISTER;
+ csv_state |= ST_CS_COND;
+ }
+ else
+ PRINTCSVIF("%c", '?');
+ pcsv_template++;
+ break;
+ case '!':
+ if (ALL(csv_state, ST_CS_COND | ST_CS_COND_NONEMPTY))
+ {
+ csv_state &= ~(ST_CS_COND | ST_CS_COND_NONEMPTY);
+ csv_state |= ST_CS_COND_EMPTY;
+ }
+ else if (IN(csv_state, ST_CS_COND))
+ {
+ error(1,
+ (u8*)"Empty conditional before/without nonempty"
+ " conditional");
+ csv_state &= ~(ST_CS_COND | ST_CS_COND_EMPTY);
}
+ else
+ PRINTCSVIF("%c", '!');
+ pcsv_template++;
+ break;
+ case '/':
+ if (ALL(csv_state, ST_CS_COND | ST_CS_COND_EMPTY))
+ csv_state &= ~(ST_CS_COND | ST_CS_COND_EMPTY);
+ else if (ALL(csv_state, ST_CS_COND))
+ csv_state &= ~(ST_CS_COND | ST_CS_COND_NONEMPTY);
+ else
+ PRINTCSVIF("%c", '/');
+ pcsv_template++;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (IN(csv_state, ST_CS_COND))
+ {
+ conditional_index = *pcsv_template - '0';
+ csv_state &= ~ST_CS_COND;
+ csv_state |= ST_CS_COND_NONEMPTY;
+ }
+ else if (IN(csv_state, ST_CS_HEADER))
+ {
+ num = *pcsv_template - '0';
+ PRINTCSVIF("%s", csv_header[num - 1]);
+ csv_state &= ~ST_CS_HEADER;
+ }
+ else if (IN(csv_state, ST_CS_REGISTER))
+ {
+ num = *pcsv_template - '0';
+ PRINTCSVIF("%s", csv_register[num - 1]);
+ csv_state &= ~ST_CS_REGISTER;
+ }
+ else
+ PRINTCSVIF("%c", *pcsv_template);
+ pcsv_template++;
+ break;
+ default:
+ if (IN(csv_state, ST_CS_HEADER))
+ {
+ error(1, (u8*)"csv: Invalid header register mark");
+ csv_state &= ~ST_CS_HEADER;
+ }
+ else if (IN(csv_state, ST_CS_REGISTER))
+ {
+ error(1, (u8*)"csv: Invalid register mark");
+ csv_state &= ~ST_CS_REGISTER;
+ }
+ else
+ PRINTCSVIF("%c", *pcsv_template);
+ pcsv_template++;
}
+ goto csv_template_start;
+csv_template_done:
return 0;
}
@@ -743,97 +1064,73 @@ read_csv(FILE* output, const char* filename, csv_callback_t callback)
pbufline = bufline;
RESET_TOKEN(token, ptoken, token_size);
current_register = 0;
- while (*pbufline)
- {
- switch (*pbufline)
+ csv_bufline_start:
+ if (!*pbufline)
+ goto csv_bufline_done;
+ switch (*pbufline)
+ {
+ case '"':
+ if (IN(csv_state, ST_CS_QUOTE))
+ csv_state &= ~ST_CS_QUOTE;
+ else
+ csv_state |= ST_CS_QUOTE;
+ pbufline++;
+ break;
+ case ';':
+ case ',':
+ if (IN(csv_state, ST_CS_QUOTE))
+ CHECKCOPY(token, ptoken, token_size, pbufline);
+ else
{
- case '"':
- if (IN(csv_state, ST_CS_QUOTE))
- csv_state &= ~ST_CS_QUOTE;
- else
- csv_state |= ST_CS_QUOTE;
+ *ptoken = 0;
+ if (csv_lineno > 0
+ && current_register < MAX_CSV_REGISTERS)
+ strcpy((char*)csv_register
+ [current_register++],
+ (char*)token);
+ else if (csv_lineno <= 0
+ && current_header < MAX_CSV_REGISTERS)
+ strcpy((char*)csv_header[current_header++],
+ (char*)token);
+ RESET_TOKEN(token, ptoken, token_size);
+ pbufline++;
+ }
+ break;
+ default:
+ if (IN(csv_state, ST_CS_QUOTE))
+ CHECKCOPY(token, ptoken, token_size, pbufline);
+ else if (csv_delimiter && *pbufline == *csv_delimiter)
+ {
+ *ptoken = 0;
+ if (csv_lineno > 0
+ && current_register < MAX_CSV_REGISTERS)
+ strcpy((char*)csv_register
+ [current_register++],
+ (char*)token);
+ else if (csv_lineno <= 0
+ && current_header < MAX_CSV_REGISTERS)
+ strcpy((char*)csv_header[current_header++],
+ (char*)token);
+ RESET_TOKEN(token, ptoken, token_size);
pbufline++;
- break;
- case ';':
- case ',':
- if (IN(csv_state, ST_CS_QUOTE))
- CHECKCOPY(token, ptoken, token_size,
- pbufline);
- else
- {
- *ptoken = 0;
- if (csv_lineno > 0)
- {
- if (current_register
- < MAX_CSV_REGISTERS)
- strncpy((char*)csv_register
- [current_register++],
- (char*)token,
- BUFSIZE - 1);
- }
- else
- {
- if (current_header
- < MAX_CSV_REGISTERS)
- strncpy((char*)csv_header
- [current_header++],
- (char*)token,
- BUFSIZE - 1);
- }
- RESET_TOKEN(token, ptoken, token_size);
- pbufline++;
- }
- break;
- default:
- if (IN(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)
- strncpy((char*)csv_register
- [current_register++],
- (char*)token,
- BUFSIZE - 1);
- }
- else
- {
- if (current_header
- < MAX_CSV_REGISTERS)
- strncpy((char*)csv_header
- [current_header++],
- (char*)token,
- BUFSIZE - 1);
- }
- RESET_TOKEN(token, ptoken,
- token_size);
- pbufline++;
- }
- else
- CHECKCOPY(token, ptoken,
- token_size, pbufline);
- }
}
+ else
+ CHECKCOPY(token, ptoken, token_size, pbufline);
}
+ goto csv_bufline_start;
+ csv_bufline_done:
*ptoken = 0;
if (csv_lineno > 0)
{
if (current_register < MAX_CSV_REGISTERS)
- strncpy((char*)csv_register[current_register++],
- (char*)token, BUFSIZE - 1);
+ strcpy((char*)csv_register[current_register++],
+ (char*)token);
}
else
{
if (current_header < MAX_CSV_REGISTERS)
- strncpy((char*)csv_header[current_header++],
- (char*)token, BUFSIZE - 1);
+ strcpy((char*)csv_header[current_header++],
+ (char*)token);
}
RESET_TOKEN(token, ptoken, token_size);
@@ -876,8 +1173,8 @@ process_csv(FILE* output, const u8* arg_token,
}
else
{
- if (IN(state, ST_CSV_BODY))
- exit(error(1, (u8*)"Can't nest csv directives"));
+ if (ANY(state, ST_CSV_BODY | ST_TSV_BODY))
+ exit(error(1, (u8*)"Can't nest csv/tsv directives"));
state |= ST_CSV_BODY;
@@ -902,7 +1199,7 @@ process_csv(FILE* output, const u8* arg_token,
snprintf(csv_filename, BUFSIZE, "%s/%s.csv", input_dirname,
(char*)args_base);
free(args_base);
- args = (u8*)strtok_r((char*)NULL, " ", (char**)&saveptr);
+ args = (u8*)strtok_r(NULL, " ", (char**)&saveptr);
if (args)
{
errno = 0;
@@ -921,15 +1218,16 @@ int
process_include(FILE* output, const u8* token,
const int read_yaml_macros_and_links)
{
- if (read_yaml_macros_and_links)
- return 0;
-
- if (!input_filename)
- return warning(1, (u8*)"Cannot use 'include' in stdin");
-
u8* ptoken = (u8*)strchr((char*)token, ' ');
char* include_filename = NULL;
char* pinclude_filename = NULL;
+ pid_t pid = 0;
+ int pstatus = 0;
+ int arg_pipe_fds[2];
+ int output_pipe_fds[2];
+
+ if (!input_filename)
+ return warning(1, (u8*)"Cannot use 'include' in stdin");
if (!ptoken)
exit(error(1,
@@ -937,15 +1235,59 @@ process_include(FILE* output, const u8* token,
" an argument"));
fflush(output);
- pid_t pid = fork();
- int pstatus = 0;
+ pipe(arg_pipe_fds);
+ pipe(output_pipe_fds);
+ pid = fork();
+
+ if (pid > 0) /* parent */
+ {
+ FILE* child_output = NULL;
+ u8* child_output_line = NULL;
+ close(arg_pipe_fds[PIPE_READ_INDEX]);
+ close(output_pipe_fds[PIPE_WRITE_INDEX]);
+ if (!(child_output
+ = fdopen(output_pipe_fds[PIPE_READ_INDEX], "r")))
+ {
+ wait(&pstatus);
+ exit(error(1, (u8*)"Cannot fdopen"));
+ }
+
+ CALLOC(child_output_line, u8, BUFSIZE);
+ while (!feof(child_output))
+ {
+ char* eol = NULL;
+
+ if (!fgets((char*)child_output_line, BUFSIZE,
+ child_output))
+ continue;
+
+ eol = strchr((char*)child_output_line, '\n');
+ if (eol)
+ *eol = 0;
+ simple_parse_yaml_line(child_output_line, &vars,
+ &vars_count, &pvars);
+ }
+ free(child_output_line);
+ fclose(child_output);
- if (pid > 0)
wait(&pstatus);
- else if (pid == 0)
+ }
+ else if (pid == 0) /* child */
{
- char* filename = NULL;
+ char* filename = NULL;
+ FILE* input = NULL;
+ FILE* output = stdout;
+ u8* buffer = NULL;
+ size_t buffer_size = 0;
+ int result = 0;
+ FILE* child_output = NULL;
+
prctl(PR_SET_PDEATHSIG, SIGTERM);
+ close(arg_pipe_fds[PIPE_WRITE_INDEX]);
+ close(output_pipe_fds[PIPE_READ_INDEX]);
+ if (!(child_output
+ = fdopen(output_pipe_fds[PIPE_WRITE_INDEX], "w")))
+ exit(error(1, (u8*)"Cannot fdopen"));
CALLOC(include_filename, char, BUFSIZE);
pinclude_filename = include_filename;
@@ -964,17 +1306,8 @@ process_include(FILE* output, const u8* token,
include_filename);
free(include_filename);
- FILE* input = NULL;
- FILE* output = stdout;
- u8* buffer = NULL;
- size_t buffer_size = 0;
- int result = 0;
- ULLONG saved_state = ST_NONE;
- int saved_output_firstcol = 1;
- int saved_skip_para_end = 0;
-
- read_file_into_buffer(&input, &buffer, &buffer_size,
- input_filename, &input_dirname);
+ read_file_into_buffer(&input, &buffer, &buffer_size, filename,
+ &input_dirname);
free_keyvalue(&links, links_count);
free(links);
@@ -994,45 +1327,30 @@ process_include(FILE* output, const u8* token,
while (inline_footnote_count--)
free(inline_footnotes[inline_footnote_count]);
- if (inline_footnotes)
- free(inline_footnotes);
+ free(inline_footnotes);
inline_footnotes = NULL;
inline_footnote_count = 0;
current_inline_footnote = 0;
-
- saved_state = state;
- saved_output_firstcol = output_firstcol;
- saved_skip_para_end = skip_para_end;
- state = ST_NONE;
- output_firstcol = 1;
- skip_para_end = 0;
+ state = ST_NONE;
/* First pass: read YAML, macros and links */
- result = slweb_parse(output, input_filename, buffer, 1);
+ result = slweb_parse(output, filename, buffer, 1);
+
+ if (result || read_yaml_macros_and_links)
+ goto process_include_child_cleanup;
- if (result)
- {
- slweb_cleanup();
- free(filename);
- free(buffer);
- return result;
- }
state = ST_NONE;
- output_firstcol = 1;
- skip_para_end = 0;
current_footnote = 0;
current_inline_footnote = 0;
/* Second pass: parse and output */
- result = slweb_parse(output, input_filename, buffer, 0);
-
- state = saved_state;
- output_firstcol = saved_output_firstcol;
- skip_para_end = saved_skip_para_end;
+ result = slweb_parse(output, filename, buffer, 0);
+ process_include_child_cleanup:
slweb_cleanup();
free(filename);
free(buffer);
+ fclose(child_output);
exit(result);
}
else
@@ -1147,7 +1465,7 @@ int process_timestamp(FILE* output, const u8* link_prefix, const char* link,
int
process_incdir_subdir(FILE* output, const char* subdirname,
- const u8* link_prefix, int details_open, u8* macro_body)
+ const u8* link_prefix, const int details_open, const u8* macro_body)
{
struct dirent** namelist;
struct dirent** pnamelist;
@@ -1156,7 +1474,8 @@ process_incdir_subdir(FILE* output, const char* subdirname,
char* abs_subdirname = NULL;
CALLOC(abs_subdirname, char, BUFSIZE);
- snprintf(abs_subdirname, BUFSIZE, "%s/%s", basedir, subdirname);
+ snprintf(abs_subdirname, BUFSIZE, "%s/%s/%s", basedir, incdir,
+ subdirname);
if ((names_total = scandir(abs_subdirname, &namelist, &filter_slw,
&reverse_alphacompare))
@@ -1169,7 +1488,7 @@ process_incdir_subdir(FILE* output, const char* subdirname,
pnamelist = namelist;
names_output = 0;
- while (names_output < names_total && pnamelist && *pnamelist)
+ while (names_output < names_total)
{
int pstatus = 0;
char* basename = strip_ext((*pnamelist)->d_name);
@@ -1191,14 +1510,12 @@ process_incdir_subdir(FILE* output, const char* subdirname,
snprintf(filename, BUFSIZE, "%s/%s", abs_subdirname,
(*pnamelist)->d_name);
- FILE* input = NULL;
- FILE* output = stdout;
- u8* buffer = NULL;
- size_t buffer_size = 0;
- int result = 0;
- ULONG saved_state = ST_NONE;
- int saved_output_firstcol = 1;
- int saved_skip_para_end = 0;
+ FILE* input = NULL;
+ FILE* output = stdout;
+ u8* buffer = NULL;
+ size_t buffer_size = 0;
+ int result = 0;
+ ULLONG saved_state = ST_NONE;
read_file_into_buffer(&input, &buffer, &buffer_size,
filename, &input_dirname);
@@ -1215,24 +1532,21 @@ process_incdir_subdir(FILE* output, const char* subdirname,
free_keyvalue(&footnotes, footnote_count);
free(footnotes);
- footnotes = 0;
+ footnotes = NULL;
footnote_count = 0;
current_footnote = 0;
while (inline_footnote_count--)
free(inline_footnotes[inline_footnote_count]);
- if (inline_footnotes)
- free(inline_footnotes);
+ free(inline_footnotes);
inline_footnotes = NULL;
inline_footnote_count = 0;
current_inline_footnote = 0;
- saved_state = state;
- saved_output_firstcol = output_firstcol;
- saved_skip_para_end = skip_para_end;
- state = ST_NONE;
- output_firstcol = 1;
- skip_para_end = 0;
+ saved_state = state;
+ state = ST_NONE;
+ output_firstcol = 1;
+ skip_para_end = 0;
/* Read YAML, macros and links */
result = slweb_parse(output, filename, buffer, 1);
@@ -1259,9 +1573,7 @@ process_incdir_subdir(FILE* output, const char* subdirname,
process_timestamp(output, link_prefix, link,
NULL, date, title);
- state = saved_state;
- output_firstcol = saved_output_firstcol;
- skip_para_end = saved_skip_para_end;
+ state = saved_state;
fflush(output);
slweb_cleanup();
@@ -1293,20 +1605,26 @@ process_incdir_subdir(FILE* output, const char* subdirname,
}
int
-process_incdir(FILE* output, const u8* token, const u8* link_prefix)
+process_incdir(FILE* output, const u8* token, const u8* link_prefix,
+ const int read_yaml_macros_and_links)
{
u8* saveptr = NULL;
/* skipping the first token (incdir) */
- u8* arg = (u8*)strtok_r((char*)token, " ", (char**)&saveptr);
- size_t arg_len = 0;
- long num = 5;
- u8* macro_body = NULL;
- int names_total = 0;
- int current_name = 0;
+ u8* arg = NULL;
+ size_t arg_len = 0;
+ long num = 5;
+ u8* macro_body = NULL;
+ int names_total = 0;
struct dirent** namelist;
+ struct dirent** pnamelist;
+ long names_output;
int details_open = 1;
- arg = (u8*)strtok_r((char*)NULL, " ", (char**)&saveptr);
+ if (read_yaml_macros_and_links)
+ return 0;
+
+ arg = (u8*)strtok_r((char*)token, " ", (char**)&saveptr);
+ arg = (u8*)strtok_r(NULL, " ", (char**)&saveptr);
if (!arg)
exit(error(1, (u8*)"incdir: Arguments required"));
@@ -1318,7 +1636,7 @@ process_incdir(FILE* output, const u8* token, const u8* link_prefix)
incdir = strdup((char*)(arg + 1));
*(incdir + strlen(incdir) - 1) = 0;
- arg = (u8*)strtok_r((char*)NULL, " ", (char**)&saveptr);
+ arg = (u8*)strtok_r(NULL, " ", (char**)&saveptr);
if (!arg)
exit(error(1, (u8*)"incdir: Second argument required"));
@@ -1334,11 +1652,12 @@ process_incdir(FILE* output, const u8* token, const u8* link_prefix)
(u8*)"incdir: Non-numeric argument"));
parg++;
}
- num = strtol((char*)arg, NULL, 10);
+ errno = 0;
+ num = strtol((char*)arg, NULL, 10);
if (errno)
exit(error(errno,
(u8*)"incdir: Invalid parameter 'num'"));
- arg = (u8*)strtok_r((char*)NULL, " ", (char**)&saveptr);
+ arg = (u8*)strtok_r(NULL, " ", (char**)&saveptr);
if (arg)
{
if (*arg != '=')
@@ -1361,16 +1680,15 @@ process_incdir(FILE* output, const u8* token, const u8* link_prefix)
exit(error(errno, (u8*)"incdir: scandir '%s' error", incdir));
}
- current_name = 0;
- /*print_output(output, "\n");*/
- if (names_total < num)
- num = names_total;
- while (current_name < num)
+ pnamelist = namelist;
+ names_output = 0;
+ while (names_output < MIN(names_total, num))
{
- process_incdir_subdir(output, namelist[current_name]->d_name,
- link_prefix, details_open, macro_body);
+ process_incdir_subdir(output, (*pnamelist)->d_name, link_prefix,
+ details_open, macro_body);
details_open = 0;
- current_name++;
+ pnamelist++;
+ names_output++;
}
/*print_output(output, "\n");*/
output_firstcol = 1;
@@ -1403,24 +1721,21 @@ process_timestamp(FILE* output, const u8* link_prefix, const char* link,
year = (u8*)strtok_r((char*)date, "-", (char**)&ptr);
if (!year)
goto process_timestamp_cleanup;
- month = (u8*)strtok_r((char*)NULL, "-", (char**)&ptr);
+ month = (u8*)strtok_r(NULL, "-", (char**)&ptr);
if (!month)
goto process_timestamp_cleanup;
- day = (u8*)strtok_r((char*)NULL, "T", (char**)&ptr);
+ day = (u8*)strtok_r(NULL, "T", (char**)&ptr);
if (!day)
goto process_timestamp_cleanup;
ptimestamp_format = timestamp_format;
while (*ptimestamp_format)
{
if (*ptimestamp_format == 'd' || *ptimestamp_format == 'D')
- strncat((char*)formatted_date, (char*)day,
- DATEBUFSIZE - strlen((char*)formatted_date) - 1);
+ strcat((char*)formatted_date, (char*)day);
else if (*ptimestamp_format == 'm' || *ptimestamp_format == 'M')
- strncat((char*)formatted_date, (char*)month,
- DATEBUFSIZE - strlen((char*)formatted_date) - 1);
+ strcat((char*)formatted_date, (char*)month);
else if (*ptimestamp_format == 'y' || *ptimestamp_format == 'Y')
- strncat((char*)formatted_date, (char*)year,
- DATEBUFSIZE - strlen((char*)formatted_date) - 1);
+ strcat((char*)formatted_date, (char*)year);
else
*(formatted_date + strlen((char*)formatted_date))
= *ptimestamp_format;
@@ -1511,8 +1826,7 @@ process_macro(FILE* output, const u8* token,
}
CALLOC(pmacros->key, u8, KEYSIZE);
pmacros->seen = 0;
- strncpy((char*)pmacros->key, (char*)token + 1,
- KEYSIZE - 1);
+ strcpy((char*)pmacros->key, (char*)token + 1);
pmacros->value = NULL;
pmacros->value_size = 0;
}
@@ -1551,9 +1865,9 @@ process_tag(FILE* output, const u8* token, const u8* link_prefix,
output_firstcol = 1;
}
else if (startswith((char*)token, "csv")) /* {csv} */
- {
process_csv(output, token, read_yaml_macros_and_links, end_tag);
- }
+ else if (startswith((char*)token, "tsv")) /* {csv} */
+ process_tsv(output, token, read_yaml_macros_and_links, end_tag);
else if (startswith((char*)token, "include")) /* {include} */
{
process_include(output, token, read_yaml_macros_and_links);
@@ -1562,7 +1876,8 @@ process_tag(FILE* output, const u8* token, const u8* link_prefix,
else if (startswith((char*)token, "incdir")
&& !read_yaml_macros_and_links) /* {incdir} */
{
- process_incdir(output, token, link_prefix);
+ process_incdir(output, token, link_prefix,
+ read_yaml_macros_and_links);
*skip_eol = 1;
}
else if (*token == '=') /* {=macro} */
@@ -1726,6 +2041,8 @@ process_paralinks(FILE* output, const u8* link_prefix)
{
if (pparalink->key)
{
+ if (!output_firstcol)
+ print_output(output, "\n");
print_output(output, "=> %s%s%s\t%s\n",
url_is_local((const char*)pparalink->key)
&& global_link_prefix
@@ -1955,8 +2272,7 @@ begin_article(FILE* output, const int add_article_header, const u8* author,
{
if (title)
{
- process_heading_start(output, 1, first_line_in_doc,
- *previous_line_blank);
+ process_heading_start(output, 1);
process_heading(output, title);
}
@@ -2025,6 +2341,85 @@ end_footnotes(FILE* output, const u8* link_prefix, const int add_footnote_div,
}
int
+simple_parse_yaml_line(const u8* line, KeyValue** vars, size_t* vars_count,
+ KeyValue** pvars)
+{
+ u8* token = NULL;
+ u8* ptoken = NULL;
+ u8* var_key = NULL;
+ const u8* pline = line;
+ int in_arg = 0;
+
+ if (!line || !vars || !vars_count || !pvars)
+ exit(error(EINVAL,
+ (u8*)"simple_parse_yaml_line: Invalid argument"));
+
+ CALLOC(token, u8, BUFSIZE);
+ ptoken = token;
+ *ptoken = 0;
+ while (*pline)
+ {
+ if (!in_arg && *pline == ':')
+ {
+ in_arg = 1;
+ *ptoken = 0;
+ var_key = (u8*)strdup((char*)token);
+ if (!var_key)
+ exit(error(ENOMEM,
+ (u8*)"Memory allocation failed (out of "
+ "memory?)"));
+ ptoken = token;
+ *ptoken = 0;
+ pline++;
+ }
+ else if (*pline == ' ' || *pline == '\t')
+ pline++;
+ else
+ *ptoken++ = *pline++;
+ }
+ if (*token)
+ *ptoken = 0;
+ if (var_key && *var_key && *token)
+ {
+ int found = 0;
+ KeyValue* cvar = NULL;
+
+ cvar = *vars;
+ while (!found && cvar != *vars + *vars_count)
+ {
+ if (!strcmp((const char*)cvar->key, (const char*)var_key)
+ && cvar->value_size
+ && !strcmp((const char*)cvar->value,
+ (const char*)token))
+ found = 1;
+ cvar++;
+ }
+ if (!found)
+ {
+ (*vars_count)++;
+ if (!*vars)
+ {
+ CALLOC(*vars, KeyValue, *vars_count);
+ *pvars = *vars;
+ }
+ else
+ {
+ REALLOCARRAY(*vars, KeyValue, *vars_count);
+ *pvars = *vars + *vars_count - 1;
+ }
+ CALLOC((*pvars)->key, u8, KEYSIZE);
+ strcpy((char*)(*pvars)->key, (char*)var_key);
+ (*pvars)->value_size = strlen((char*)token) + 1;
+ CALLOC((*pvars)->value, u8, (*pvars)->value_size);
+ strcpy((char*)(*pvars)->value, (char*)token);
+ }
+ }
+ free(var_key);
+ free(token);
+ return 0;
+}
+
+int
slweb_parse(FILE* output, const char* source_filename, const u8* buffer,
const int read_yaml_macros_and_links)
{
@@ -2103,6 +2498,7 @@ slweb_parse(FILE* output, const char* source_filename, const u8* buffer,
RESET_TOKEN(token, ptoken, token_size);
+ output_firstcol = 1;
do_buffer:;
u8* eol = (u8*)strchr((char*)pbuffer, '\n');
if (!eol)
@@ -2118,7 +2514,6 @@ do_buffer:;
lineno++;
colno = 1;
- output_firstcol = 1;
processed_start_of_line = 0;
skip_eol = 0;
list_para = 0;
@@ -2418,24 +2813,13 @@ do_line:
| ST_HTML_TAG | ST_IMAGE | ST_KBD
| ST_LINK_SECOND_ARG
| ST_LINK_SECOND_ARG_END | ST_MACRO_BODY
- | ST_PRE | ST_TAG | ST_YAML))
+ /*| ST_PRE*/ | ST_TAG | ST_YAML))
{
CHECKCOPY(token, ptoken, token_size, pline);
colno++;
}
else if (!IN(state, ST_ENT))
{
- /* Output existing text up to & */
- /**ptoken = 0;
- process_text_token(output, line, link_prefix,
- first_line_in_doc, previous_line_blank,
- processed_start_of_line,
- read_yaml_macros_and_links, list_para, &token,
- &ptoken, &token_size, 1);
- processed_start_of_line = 1;
-
- RESET_TOKEN(token, ptoken, token_size);*/
-
state |= ST_ENT;
pline++;
colno++;
@@ -2462,6 +2846,20 @@ do_line:
= 0;
strcat((char*)token, "&");
}
+ else if (endswith((char*)token, "lt"))
+ {
+ token[strlen((char*)token)
+ - strlen("lt")]
+ = 0;
+ strcat((char*)token, "<");
+ }
+ else if (endswith((char*)token, "gt"))
+ {
+ token[strlen((char*)token)
+ - strlen("gt")]
+ = 0;
+ strcat((char*)token, ">");
+ }
else if (endswith((char*)token, "quot"))
{
token[strlen((char*)token)
@@ -2818,8 +3216,7 @@ do_line:
if ((IN(state, ST_HEADING)) && !(IN(state, ST_HEADING_TEXT)))
{
if (!read_yaml_macros_and_links)
- process_heading_start(output, heading_level,
- first_line_in_doc, previous_line_blank);
+ process_heading_start(output, heading_level);
state |= ST_HEADING_TEXT;
pline++;
colno++;
diff --git a/slw2gmi.do b/slw2gmi.do
@@ -1,2 +1,8 @@
-redo-ifchange slw2gmi.o slw2gmi.c defs.h
-${SLW2GMI_CC:-gcc -g} -Wall -std=c99 -o $3 slw2gmi.o
+for f in *.h.in; do
+ echo $f | sed -e's/\.in$//g'
+done | xargs redo-ifchange
+for f in *.h *.c; do
+ echo $f
+ echo $f | sed -e's/\.c$/.o/g'
+done | xargs redo-ifchange
+${SLW2GMI_CC:-gcc -g} -Wall -std=c99 -o $3 slw2gmi.o utf8.o
diff --git a/version.do b/version.do
@@ -1,6 +1,5 @@
-if ! git describe >$3; then
- echo "$0: can't call git describe, falling back to 'unknown'" >&2
- echo 'unknown' >$3
-fi
+FALLBACKVER=${FALLBACKVER:-unknown}
+{ command -v git >/dev/null 2>&1 && git describe >/dev/null 2>&1; } && \
+ git describe 2>/dev/null | sed 's/^v//' >$3 || echo $FALLBACKVER >$3
redo-always
redo-stamp <$3
diff --git a/version.h b/version.h
@@ -0,0 +1,3 @@
+#define PROGRAMNAME "slw2gmi"
+#define DATE "18 Mar 2022"
+#define VERSION "0.1.5.1"
diff --git a/version.h.in b/version.h.in
@@ -0,0 +1,3 @@
+#define PROGRAMNAME "slw2gmi"
+#define DATE "%DATE%"
+#define VERSION "%VERSION%"