slw2gmi

Конвертор из slweb-а у Џемини
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување 63fe27d7488a401c47ad9911b7026c6fd5221b6a
родитељ a873fe3d22e59c34a01aea5346ee44aaacebb608
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Fri, 18 Mar 2022 23:06:34 +0100

Adjust for current slweb (0.4.5+)

Diffstat:
AAUTHORS | 1+
Mall.do | 3+--
Adefault.h.do | 12++++++++++++
Mdefs.h | 44++++++++++++++++++++++++--------------------
Mslw2gmi.c | 1145+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mslw2gmi.do | 10++++++++--
Mversion.do | 7+++----
Aversion.h | 3+++
Aversion.h.in | 3+++
измењених датотека: 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(&paralinks, paralinks_count); free_keyvalue(&links, links_count); free_keyvalue(&macros, 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%"