чување 0b2aee9da644525ff828cb4c0adaf545f4a843b9
родитељ 2d92894a36850f6e07d2ec1cc532d322ce8e0ce4
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Sat, 4 Sep 2021 12:33:31 +0200
Updated to match slweb v0.3.12
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
| M | TODO | | | 2 | +- |
| M | defs.h | | | 6 | +++++- |
| M | slw2gmi.c | | | 7949 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
измењених датотека: 3, додавања: 4103(+), брисања: 3854(-)
diff --git a/TODO b/TODO
@@ -11,7 +11,7 @@
[x] Remove libunistring as a dependency
- < > Remove realpath as a dependency?
+ <x> Remove realpath as a dependency?
[x] Fix leaks
[x] Fix leaks in slw2gmi
diff --git a/defs.h b/defs.h
@@ -21,7 +21,7 @@
#include "utf8.h"
#define PROGRAMNAME "slw2gmi"
-#define VERSION "0.1.2"
+#define VERSION "0.1.3"
#define COPYRIGHTYEAR "2021"
#define MADEBY_URL "https://strahinja.srht.site/slw2gmi/"
@@ -44,6 +44,10 @@ typedef enum
TRUE = 1
} BOOL;
+#define ALL(var, mask) (((var) & (mask)) == (mask))
+#define ANY(var, mask) (((var) & (mask)) != 0)
+#define IN(var, mask) ALL(var, mask)
+
typedef unsigned char UBYTE;
typedef unsigned long ULONG;
typedef unsigned long long ULLONG;
diff --git a/slw2gmi.c b/slw2gmi.c
@@ -2,4201 +2,4446 @@
#include "defs.h"
-static size_t lineno = 0;
-static size_t colno = 1;
-static BOOL output_firstcol = TRUE;
-static BOOL skip_para_end = FALSE;
-static char* input_filename = NULL;
-static char* input_dirname = NULL;
-static char* basedir = NULL;
-static size_t basedir_size = 0;
-static char* incdir = NULL;
-static char* global_link_prefix = NULL;
+static size_t lineno = 0;
+static size_t colno = 1;
+static BOOL output_firstcol = TRUE;
+static BOOL skip_para_end = FALSE;
+static const char* input_filename = NULL;
+static char* input_dirname = NULL;
+static char* basedir = NULL;
+static size_t basedir_size = 0;
+static char* incdir = NULL;
+static char* global_link_prefix = NULL;
static size_t global_link_prefix_size = 0;
-static KeyValue* vars = NULL;
-static KeyValue* pvars = NULL;
-static size_t vars_count = 0;
-static KeyValue* macros = NULL;
-static KeyValue* pmacros = NULL;
-static size_t macros_count = 0;
-static KeyValue* links = NULL;
-static KeyValue* plinks = NULL;
-static size_t links_count = 0;
-static KeyValue* paralinks = NULL;
-static KeyValue* pparalinks = NULL;
-static size_t paralinks_count = 0;
-static KeyValue* footnotes = NULL;
-static KeyValue* pfootnotes = NULL;
-static size_t footnote_count = 0;
-static size_t current_footnote = 0;
-static u8** inline_footnotes = NULL;
+static KeyValue* vars = NULL;
+static KeyValue* pvars = NULL;
+static size_t vars_count = 0;
+static KeyValue* macros = NULL;
+static KeyValue* pmacros = NULL;
+static size_t macros_count = 0;
+static KeyValue* links = NULL;
+static KeyValue* plinks = NULL;
+static size_t links_count = 0;
+static KeyValue* paralinks = NULL;
+static KeyValue* pparalinks = NULL;
+static size_t paralinks_count = 0;
+static KeyValue* footnotes = NULL;
+static KeyValue* pfootnotes = NULL;
+static size_t footnote_count = 0;
+static size_t current_footnote = 0;
+static u8** inline_footnotes = NULL;
static size_t inline_footnote_count = 0;
static size_t current_inline_footnote = 0;
-static u8* csv_template = NULL;
-static size_t csv_template_size = 0;
-static char* csv_filename = NULL;
-static long csv_iter = 0;
-static ULLONG state = ST_NONE;
-
-#define CHECKEXITNOMEM(ptr) do { if (!ptr) exit(error(ENOMEM, \
- (u8*)"Memory allocation failed (out of memory?)")); } while (0)
-
-#define CALLOC(ptr, ptrtype, nmemb) do { ptr = calloc(nmemb, sizeof(ptrtype)); \
- CHECKEXITNOMEM(ptr); } while (0)
-
-#define REALLOC(ptr, ptrtype, newsize) do { ptrtype* newptr = realloc(ptr, newsize); \
- CHECKEXITNOMEM(newptr); \
- ptr = newptr; } while (0)
+static u8* csv_template = NULL;
+static size_t csv_template_size = 0;
+static char* csv_filename = NULL;
+static long csv_iter = 0;
+static ULLONG state = ST_NONE;
+
+#define CHECKEXITNOMEM(ptr) \
+ do \
+ { \
+ if (!ptr) \
+ exit(error(ENOMEM, \
+ (u8*)"Memory allocation failed (out of " \
+ "memory?)")); \
+ } while (0)
+
+#define CALLOC(ptr, ptrtype, nmemb) \
+ do \
+ { \
+ ptr = calloc(nmemb, sizeof(ptrtype)); \
+ CHECKEXITNOMEM(ptr); \
+ } while (0)
+
+#define REALLOC(ptr, ptrtype, newsize) \
+ do \
+ { \
+ ptrtype* newptr = realloc(ptr, newsize); \
+ CHECKEXITNOMEM(newptr); \
+ ptr = newptr; \
+ } while (0)
#define REALLOCARRAY(ptr, membtype, newcount) \
- REALLOC(ptr, membtype, sizeof(membtype) * newcount);
-
-#define CHECKCOPY(token, ptoken, token_size, pline) do { \
- if (ptoken + 2 > token + token_size) \
- { \
- size_t old_size = token_size; \
- token_size += BUFSIZE; \
- REALLOC(token, u8, token_size); \
- ptoken = token + old_size - 1; \
- } \
- *ptoken++ = *pline++; } while (0)
-
-#define RESET_TOKEN(token, ptoken, token_size) do { \
- token_size = BUFSIZE; \
- REALLOC(token, u8, token_size); \
- *token = 0; ptoken = token; } while (0)
-
-#define ALL(var, mask) ( ((var) & (mask)) == (mask) )
-#define ANY(var, mask) ( (var) & (mask) )
+ REALLOC(ptr, membtype, sizeof(membtype) * newcount);
+
+#define CHECKCOPY(token, ptoken, token_size, pline) \
+ do \
+ { \
+ if (ptoken + 2 > token + token_size) \
+ { \
+ size_t old_size = token_size; \
+ token_size += BUFSIZE; \
+ REALLOC(token, u8, token_size); \
+ ptoken = token + old_size - 1; \
+ } \
+ *ptoken++ = *pline++; \
+ } while (0)
+
+#define RESET_TOKEN(token, ptoken, token_size) \
+ do \
+ { \
+ token_size = BUFSIZE; \
+ REALLOC(token, u8, token_size); \
+ *token = 0; \
+ ptoken = token; \
+ } while (0)
int
version()
{
- printf("%s v%s\n", PROGRAMNAME, VERSION);
- return 0;
+ printf("%s v%s\n", PROGRAMNAME, VERSION);
+ return 0;
}
int
usage()
{
- printf("Usage: %s [-b|--body-only] [-d|--basedir <dir>]"
- " [-p|--global-link-prefix <URL>] [-h|--help]"
- " [-v|--version] [filename]\n", PROGRAMNAME);
- return 0;
+ printf("Usage: %s [-d|--basedir <dir>]"
+ " [-p|--global-link-prefix <URL>] [-h|--help]"
+ " [-v|--version] [filename]\n",
+ PROGRAMNAME);
+ return 0;
}
int
-error(int code, u8* fmt, ...)
+error(const int code, const u8* fmt, ...)
{
- char buf[BUFSIZE];
- va_list args;
- va_start(args, fmt);
- vsnprintf(buf, sizeof(buf), (const char*)fmt, args);
- va_end(args);
- fprintf(stderr, "%s:%s:%lu:%lu: %s\n", PROGRAMNAME,
- input_filename ? input_filename : "(stdin)",
- lineno, colno, buf);
- return code;
+ char buf[BUFSIZE];
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), (const char*)fmt, args);
+ va_end(args);
+ fprintf(stderr, "%s:%s:%lu:%lu: %s\n", PROGRAMNAME,
+ input_filename ? input_filename : "(stdin)", lineno, colno,
+ buf);
+ return code;
}
int
-warning(int code, u8* fmt, ...)
+warning(const int code, const u8* fmt, ...)
{
- char buf[BUFSIZE];
- va_list args;
- va_start(args, fmt);
- vsnprintf(buf, sizeof(buf), (const char*)fmt, args);
- va_end(args);
- fprintf(stderr, "Warning: %s\n", buf);
- return code;
+ char buf[BUFSIZE];
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), (const char*)fmt, args);
+ va_end(args);
+ fprintf(stderr, "Warning: %s\n", buf);
+ return code;
}
int
-free_keyvalue(KeyValue** list, size_t list_count)
+free_keyvalue(KeyValue** list, const size_t list_count)
{
- if (!list || !*list)
- return 1;
-
- 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);
- }
- return 0;
+ if (!list || !*list)
+ return 1;
+
+ 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);
+ }
+ return 0;
}
int
-slweb_cleanup();
+slweb_cleanup()
+{
+ if (basedir)
+ free(basedir);
+ free(input_dirname);
+ while (inline_footnote_count--)
+ free(inline_footnotes[inline_footnote_count]);
+ if (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);
+
+ return 0;
+}
-int
-slweb_parse(u8* buffer, FILE* output, BOOL read_yaml_macros_and_links);
+int slweb_parse(FILE* output, const char* source_filename, const u8* buffer,
+ const BOOL read_yaml_macros_and_links);
BOOL
startswith(const char* s, const char* what)
{
- if (!s || !what)
- return FALSE;
+ if (!s || !what)
+ return FALSE;
- do
- {
- if (*s++ != *what++)
- return FALSE;
- }
- while (*s && *what);
+ do
+ {
+ if (*s++ != *what++)
+ return FALSE;
+ } while (*s && *what);
- return !*what;
+ return !*what;
}
u8*
-get_value(KeyValue* list, size_t list_count, u8* key, BOOL* seen)
+get_value(KeyValue* list, const size_t list_count, const u8* key, BOOL* seen)
{
- if (!list)
- return NULL;
- KeyValue* plist = list;
- while (plist < list + list_count)
- {
- if (!strcmp((char*)plist->key, (char*)key))
- {
- if (seen)
- {
- *seen = plist->seen;
- plist->seen = TRUE;
- }
- return plist->value;
- }
- plist++;
- }
- return NULL;
+ if (!list)
+ return NULL;
+ KeyValue* plist = list;
+ while (plist < list + list_count)
+ {
+ if (!strcmp((char*)plist->key, (char*)key))
+ {
+ if (seen)
+ {
+ *seen = plist->seen;
+ plist->seen = TRUE;
+ }
+ return plist->value;
+ }
+ plist++;
+ }
+ return NULL;
}
int
-set_basedir(char* arg, char** basedir, size_t* basedir_size)
+set_basedir(char** basedir, size_t* basedir_size, const char* arg)
{
- size_t basedir_len = 0;
- size_t arg_len = strlen(arg);
-
- if (arg_len < 1)
- exit(error(1, (u8*)"--basedir: Argument required"));
-
- if (arg_len + 1 > *basedir_size)
- {
- *basedir_size = arg_len+1;
- REALLOC(*basedir, char, *basedir_size);
- }
- strncpy(*basedir, arg, *basedir_size-1);
- *(*basedir + arg_len) = 0;
- basedir_len = strlen(*basedir);
- if (*(*basedir + basedir_len - 1) == '/')
- *(*basedir + basedir_len - 1) = 0;
-
- return 0;
+ size_t basedir_len = 0;
+ size_t arg_len = strlen(arg);
+
+ if (arg_len < 1)
+ exit(error(1, (u8*)"--basedir: Argument required"));
+
+ if (arg_len + 1 > *basedir_size)
+ {
+ *basedir_size = arg_len + 1;
+ REALLOC(*basedir, char, *basedir_size);
+ }
+ strncpy(*basedir, arg, *basedir_size - 1);
+ *(*basedir + arg_len) = 0;
+ basedir_len = strlen(*basedir);
+ if (*(*basedir + basedir_len - 1) == '/')
+ *(*basedir + basedir_len - 1) = 0;
+
+ return 0;
}
int
-set_global_link_prefix(char* arg, char** global_link_prefix,
- size_t* global_link_prefix_size)
+set_global_link_prefix(char** global_link_prefix,
+ size_t* global_link_prefix_size, const char* arg)
{
- size_t arg_len = strlen(arg);
+ size_t arg_len = strlen(arg);
- if (arg_len < 1)
- exit(error(1, (u8*)"--global-link-prefix: Argument required"));
+ if (arg_len < 1)
+ exit(error(1, (u8*)"--global-link-prefix: Argument required"));
- if (arg_len + 1 > *global_link_prefix_size)
- {
- *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);
- *(*global_link_prefix + arg_len) = 0;
+ if (arg_len + 1 > *global_link_prefix_size)
+ {
+ *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);
+ *(*global_link_prefix + arg_len) = 0;
- return 0;
+ return 0;
}
char*
strip_ext(const char* fn)
{
- char* newname = NULL;
- char* pnewname = NULL;
- const char* pfn = NULL;
- char* dot = NULL;
+ char* newname = NULL;
+ char* pnewname = NULL;
+ const char* pfn = NULL;
+ char* dot = NULL;
- dot = strrchr(fn, '.');
+ dot = strrchr(fn, '.');
- if (!dot)
- return NULL;
+ if (!dot)
+ return NULL;
- CALLOC(newname, char, strlen(fn)+1);
- pnewname = newname;
- pfn = fn;
+ CALLOC(newname, char, strlen(fn) + 1);
+ pnewname = newname;
+ pfn = fn;
- while (pfn != dot && *pfn)
- *pnewname++ = *pfn++;
+ while (pfn != dot && *pfn)
+ *pnewname++ = *pfn++;
- return newname;
+ return newname;
}
int
-print_output(FILE* output, char* fmt, ...)
+print_output(FILE* output, const char* fmt, ...)
{
- char buf[BUFSIZE];
- va_list args;
-
- if (!output || !fmt)
- exit(error(EINVAL, (u8*)"print_output: Invalid argument"));
-
- va_start(args, fmt);
- if (state & ST_CSV_BODY)
- {
- size_t buf_len = 0;
- vsnprintf((char*)buf, BUFSIZE, fmt, args);
- buf_len = strlen(buf);
- if (!csv_template)
- {
- csv_template_size = BUFSIZE;
- CALLOC(csv_template, u8, csv_template_size);
- strncpy((char*)csv_template, buf, BUFSIZE-1);
- *(csv_template + buf_len) = 0;
- }
- else
- {
- if (strlen((char*)csv_template) + buf_len > csv_template_size)
- {
- csv_template_size += BUFSIZE;
- REALLOC(csv_template, u8, csv_template_size);
- }
- strncat((char*)csv_template, buf, csv_template_size
- - strlen((char*)csv_template) - 1);
- }
- }
- else
- vfprintf(output, fmt, args);
- va_end(args);
- return 0;
+ char buf[BUFSIZE];
+ va_list args;
+
+ if (!output || !fmt)
+ exit(error(EINVAL, (u8*)"print_output: Invalid argument"));
+
+ va_start(args, fmt);
+ if (IN(state, ST_CSV_BODY))
+ {
+ size_t buf_len = 0;
+ vsnprintf((char*)buf, BUFSIZE, fmt, args);
+ buf_len = strlen(buf);
+ if (!csv_template)
+ {
+ csv_template_size = BUFSIZE;
+ CALLOC(csv_template, u8, csv_template_size);
+ strncpy((char*)csv_template, buf, BUFSIZE - 1);
+ *(csv_template + buf_len) = 0;
+ }
+ else
+ {
+ if (strlen((char*)csv_template) + buf_len
+ > csv_template_size)
+ {
+ csv_template_size += BUFSIZE;
+ REALLOC(csv_template, u8, csv_template_size);
+ }
+ strncat((char*)csv_template, buf,
+ csv_template_size - strlen((char*)csv_template)
+ - 1);
+ }
+ }
+ else
+ vfprintf(output, fmt, args);
+ va_end(args);
+ return 0;
}
-#define PIPE_READ_INDEX 0
+#define PIPE_READ_INDEX 0
#define PIPE_WRITE_INDEX 1
int
-print_command(const char* command,
- const u8* pass_arguments[], const u8* pipe_arguments[],
- FILE* output, BOOL strip_newlines)
+print_command(FILE* output, const char* command, const u8* pass_arguments[],
+ const u8* pipe_arguments[], const BOOL strip_newlines)
{
- if (!command || !pass_arguments)
- exit(error(EINVAL, (u8*)"print_command: Invalid argument"));
-
- pid_t pid = 0;
- int arg_pipe_fds[2];
- int output_pipe_fds[2];
- int pstatus = 0;
-
- pipe(arg_pipe_fds);
- pipe(output_pipe_fds);
- pid = fork();
- if (pid == 0)
- {
- close(arg_pipe_fds[PIPE_WRITE_INDEX]);
- close(output_pipe_fds[PIPE_READ_INDEX]);
-
- prctl(PR_SET_PDEATHSIG, SIGTERM);
-
- dup2(arg_pipe_fds[PIPE_READ_INDEX], STDIN_FILENO);
- dup2(output_pipe_fds[PIPE_WRITE_INDEX], STDOUT_FILENO);
-
- execvp(command, (char* const*)pass_arguments);
- exit(1);
- }
- else if (pid < 0)
- exit(error(errno, (u8*)"Fork failed"));
-
- /* Parent */
- close(arg_pipe_fds[PIPE_READ_INDEX]);
- close(output_pipe_fds[PIPE_WRITE_INDEX]);
- FILE* cmd_input = fdopen(arg_pipe_fds[PIPE_WRITE_INDEX], "w");
- FILE* cmd_output = fdopen(output_pipe_fds[PIPE_READ_INDEX], "r");
-
- if (!cmd_input || !cmd_output)
- exit(error(1, (u8*)"Cannot fdopen"));
-
- if (pipe_arguments)
- {
- const u8** ppipe_argument = pipe_arguments;
- while (ppipe_argument && *ppipe_argument)
- {
- fprintf(cmd_input, "%s\n", *ppipe_argument);
- ppipe_argument++;
- }
- }
- fclose(cmd_input);
-
- u8* cmd_output_line = NULL;
- CALLOC(cmd_output_line, u8, 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;
-
- print_output(output, "%s%s", cmd_output_line,
- strip_newlines ? "" : "\n");
- }
- if (!strip_newlines)
- output_firstcol = TRUE;
- free(cmd_output_line);
-
- fclose(cmd_output);
-
- kill(pid, SIGKILL);
- pid_t wpid = waitpid(pid, &pstatus, 0);
- if (wpid < 0)
- warning(pstatus, (u8*)"Child returned nonzero status, errno = %d",
- errno);
- if (WIFEXITED(pstatus))
- return WEXITSTATUS(pstatus);
-
- return wpid;
+ if (!command || !pass_arguments)
+ exit(error(EINVAL, (u8*)"print_command: Invalid argument"));
+
+ pid_t pid = 0;
+ int arg_pipe_fds[2];
+ int output_pipe_fds[2];
+ int pstatus = 0;
+
+ fflush(output);
+ pipe(arg_pipe_fds);
+ pipe(output_pipe_fds);
+ pid = fork();
+ if (pid == 0)
+ {
+ close(arg_pipe_fds[PIPE_WRITE_INDEX]);
+ close(output_pipe_fds[PIPE_READ_INDEX]);
+
+ prctl(PR_SET_PDEATHSIG, SIGTERM);
+
+ dup2(arg_pipe_fds[PIPE_READ_INDEX], STDIN_FILENO);
+ dup2(output_pipe_fds[PIPE_WRITE_INDEX], STDOUT_FILENO);
+
+ execvp(command, (char* const*)pass_arguments);
+ exit(1);
+ }
+ else if (pid < 0)
+ exit(error(errno, (u8*)"Fork failed"));
+
+ /* Parent */
+ close(arg_pipe_fds[PIPE_READ_INDEX]);
+ close(output_pipe_fds[PIPE_WRITE_INDEX]);
+ FILE* cmd_input = fdopen(arg_pipe_fds[PIPE_WRITE_INDEX], "w");
+ FILE* cmd_output = fdopen(output_pipe_fds[PIPE_READ_INDEX], "r");
+
+ if (!cmd_input || !cmd_output)
+ exit(error(1, (u8*)"Cannot fdopen"));
+
+ if (pipe_arguments)
+ {
+ const u8** ppipe_argument = pipe_arguments;
+ while (ppipe_argument && *ppipe_argument)
+ {
+ fprintf(cmd_input, "%s\n", *ppipe_argument);
+ ppipe_argument++;
+ }
+ }
+ fclose(cmd_input);
+
+ u8* cmd_output_line = NULL;
+ CALLOC(cmd_output_line, u8, 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;
+
+ print_output(output, "%s%s", cmd_output_line,
+ strip_newlines ? "" : "\n");
+ }
+ if (!strip_newlines)
+ output_firstcol = TRUE;
+ free(cmd_output_line);
+
+ fclose(cmd_output);
+
+ kill(pid, SIGKILL);
+ pid_t wpid = waitpid(pid, &pstatus, 0);
+ if (wpid < 0)
+ warning(pstatus,
+ (u8*)"Child returned nonzero status, errno = %d",
+ errno);
+ if (WIFEXITED(pstatus))
+ return WEXITSTATUS(pstatus);
+
+ return wpid;
}
int
-read_file_into_buffer(u8** buffer, size_t* buffer_size, char* input_filename,
- char** input_dirname, FILE** input)
+read_file_into_buffer(FILE** input, u8** buffer, size_t* buffer_size,
+ const char* input_filename, char** input_dirname)
{
- struct stat fs;
- char* slash = NULL;
-
- *input = fopen(input_filename, "r");
- if (!*input)
- return error(ENOENT, (u8*)"No such file: %s", input_filename);
-
- fstat(fileno(*input), &fs);
- if (*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);
-
- slash = strrchr(input_filename, '/');
- if (slash)
- {
- CALLOC(*input_dirname, char, strlen(input_filename)+1);
- char* pinput_dirname = *input_dirname;
- char* pinput_filename = input_filename;
- while (pinput_filename && *pinput_filename
- && pinput_filename != slash)
- *pinput_dirname++ = *pinput_filename++;
- }
- else
- {
- CALLOC(*input_dirname, char, 2);
- **input_dirname = '.';
- }
-
- fclose(*input);
-
- return 0;
+ struct stat fs;
+ char* slash = NULL;
+
+ *input = fopen(input_filename, "r");
+ if (!*input)
+ return error(ENOENT, (u8*)"No such file: %s", input_filename);
+
+ fstat(fileno(*input), &fs);
+ if (*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);
+
+ slash = strrchr(input_filename, '/');
+ if (slash)
+ {
+ CALLOC(*input_dirname, char, strlen(input_filename) + 1);
+ char* pinput_dirname = *input_dirname;
+ const char* pinput_filename = input_filename;
+ while (pinput_filename && *pinput_filename
+ && pinput_filename != slash)
+ *pinput_dirname++ = *pinput_filename++;
+ }
+ else
+ {
+ CALLOC(*input_dirname, char, 2);
+ **input_dirname = '.';
+ }
+
+ fclose(*input);
+
+ return 0;
}
-int
-read_csv(FILE* output, const char* filename, csv_callback_t callback);
+int read_csv(FILE* output, const char* filename, csv_callback_t callback);
int
-process_heading_start(FILE* output, UBYTE heading_level,
- BOOL first_line_in_doc, BOOL previous_line_blank)
+process_heading_start(FILE* output, const UBYTE heading_level,
+ BOOL first_line_in_doc, const BOOL previous_line_blank)
{
- 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, " ");
- output_firstcol = FALSE;
- return 0;
+ 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, " ");
+ output_firstcol = FALSE;
+ return 0;
}
int
-process_heading(const u8* token, FILE* output)
+process_heading(FILE* output, const u8* token)
{
- if (!token || strlen((char*)token) < 1)
- warning(1, (u8*)"Empty heading");
+ if (!token || strlen((char*)token) < 1)
+ warning(1, (u8*)"Empty heading");
- print_output(output, "%s\n\n", token ? (char*)token : "");
- output_firstcol = TRUE;
+ print_output(output, "%s\n\n", token ? (char*)token : "");
+ output_firstcol = TRUE;
- return 0;
+ return 0;
}
int
process_git_log(FILE* output)
{
- if (!input_filename)
- return warning(1, (u8*)"Cannot use 'git-log' in stdin");
+ if (!input_filename)
+ return warning(1, (u8*)"Cannot use 'git-log' in stdin");
- char* basename = NULL;
- size_t basename_size = strlen(input_filename)+1;
- CALLOC(basename, char, basename_size);
- char* slash = strrchr(input_filename, '/');
- pid_t result = 0;
+ char* basename = NULL;
+ size_t basename_size = BUFSIZE;
+ CALLOC(basename, char, basename_size);
+ char* slash = strrchr(input_filename, '/');
+ pid_t result = 0;
- if (slash)
- strncpy(basename, slash+1, basename_size-1);
- else
- strncpy(basename, input_filename, basename_size-1);
+ if (slash)
+ strncpy(basename, slash + 1, basename_size - 1);
+ else
+ strncpy(basename, input_filename, basename_size - 1);
- u8* pipe_args[] = { (u8*)basename, NULL };
+ u8* pipe_args[] = {(u8*)basename, NULL};
- print_output(output, "Previous commit: ");
- result = print_command(CMD_GIT_LOG,
- (const u8**)CMD_GIT_LOG_ARGS,
- (const u8**)pipe_args, output, FALSE);
- print_output(output, "\n");
- output_firstcol = TRUE;
+ print_output(output, "Previous commit: ");
+ result = print_command(output, CMD_GIT_LOG,
+ (const u8**)CMD_GIT_LOG_ARGS, (const u8**)pipe_args, FALSE);
+ print_output(output, "\n");
+ output_firstcol = TRUE;
- free(basename);
+ free(basename);
- return result ? warning(result, (u8*)"git-log: Cannot run git") : 0;
+ return result ? warning(result, (u8*)"git-log: Cannot run git") : 0;
}
-#define PRINTIF(format, arg) { \
- if ((ALL(csv_state, ST_CS_COND_NONEMPTY) \
- && *csv_register[conditional_index-1]) \
- || (ALL(csv_state, ST_CS_COND_EMPTY) \
- && !*csv_register[conditional_index-1]) \
- || !ANY(csv_state, ST_CS_COND_EMPTY | ST_CS_COND_NONEMPTY)) \
- { fprintf(output, format, arg); } }
+#define PRINTIF(format, arg) \
+ do \
+ { \
+ if ((ALL(csv_state, ST_CS_COND_NONEMPTY) \
+ && *csv_register[conditional_index - 1]) \
+ || (ALL(csv_state, ST_CS_COND_EMPTY) \
+ && !*csv_register[conditional_index - 1]) \
+ || !ANY(csv_state, \
+ ST_CS_COND_EMPTY | ST_CS_COND_NONEMPTY)) \
+ { \
+ fprintf(output, format, arg); \
+ } \
+ } while (0)
int
print_csv_row(FILE* output, u8** csv_header, u8** csv_register)
{
- u8* pcsv_template = csv_template;
- UBYTE csv_state = ST_CS_NONE;
- UBYTE num = 0;
- UBYTE conditional_index = 0;
-
- while (*pcsv_template)
- {
- if (csv_state & ST_CS_ESCAPE)
- {
- PRINTIF("%c", *pcsv_template)
- csv_state &= ~ST_CS_ESCAPE;
- pcsv_template++;
- continue;
- }
-
- switch (*pcsv_template)
- {
- case '\\':
- csv_state |= ST_CS_ESCAPE;
- pcsv_template++;
- break;
- case '$':
- if (csv_state & ST_CS_REGISTER)
- {
- PRINTIF("%c", '$')
- csv_state &= ~ST_CS_REGISTER;
- }
- else
- csv_state |= ST_CS_REGISTER;
- pcsv_template++;
- break;
- case '#':
- if (csv_state & ST_CS_HEADER)
- {
- error(1, (u8*)"csv: Invalid header register mark");
- csv_state &= ~(ST_CS_REGISTER | ST_CS_HEADER);
- }
- else if (csv_state & ST_CS_REGISTER)
- {
- csv_state &= ~ST_CS_REGISTER;
- csv_state |= ST_CS_HEADER;
- }
- else
- PRINTIF("%c", '#')
- pcsv_template++;
- break;
- case '?':
- if (csv_state & ST_CS_COND)
- {
- error(1, (u8*)"csv: Invalid conditional mark");
- csv_state &= ~ST_CS_COND;
- }
- else if (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 (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 (csv_state & ST_CS_COND)
- {
- conditional_index = *pcsv_template - '0';
- csv_state &= ~ST_CS_COND;
- csv_state |= ST_CS_COND_NONEMPTY;
- }
- else if (csv_state & ST_CS_HEADER)
- {
- num = *pcsv_template - '0';
- PRINTIF("%s", csv_header[num-1])
- csv_state &= ~ST_CS_HEADER;
- }
- else if (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 (csv_state & ST_CS_HEADER)
- {
- error(1, (u8*)"csv: Invalid header register mark");
- csv_state &= ~ST_CS_HEADER;
- }
- else if (csv_state & ST_CS_REGISTER)
- {
- error(1, (u8*)"csv: Invalid register mark");
- csv_state &= ~ST_CS_REGISTER;
- }
- else
- PRINTIF("%c", *pcsv_template)
- pcsv_template++;
- }
- }
- return 0;
+ u8* pcsv_template = csv_template;
+ UBYTE csv_state = ST_CS_NONE;
+ UBYTE num = 0;
+ UBYTE conditional_index = 0;
+
+ while (*pcsv_template)
+ {
+ if (csv_state & ST_CS_ESCAPE)
+ {
+ PRINTIF("%c", *pcsv_template);
+ csv_state &= ~ST_CS_ESCAPE;
+ pcsv_template++;
+ continue;
+ }
+
+ switch (*pcsv_template)
+ {
+ case '\\':
+ csv_state |= ST_CS_ESCAPE;
+ pcsv_template++;
+ break;
+ case '$':
+ if (csv_state & ST_CS_REGISTER)
+ {
+ PRINTIF("%c", '$');
+ csv_state &= ~ST_CS_REGISTER;
+ }
+ else
+ csv_state |= ST_CS_REGISTER;
+ pcsv_template++;
+ break;
+ case '#':
+ if (csv_state & ST_CS_HEADER)
+ {
+ error(1,
+ (u8*)"csv: Invalid header "
+ "register mark");
+ csv_state &= ~(ST_CS_REGISTER | ST_CS_HEADER);
+ }
+ else if (csv_state & ST_CS_REGISTER)
+ {
+ csv_state &= ~ST_CS_REGISTER;
+ csv_state |= ST_CS_HEADER;
+ }
+ else
+ PRINTIF("%c", '#');
+ pcsv_template++;
+ break;
+ case '?':
+ if (csv_state & ST_CS_COND)
+ {
+ error(1, (u8*)"csv: Invalid conditional mark");
+ csv_state &= ~ST_CS_COND;
+ }
+ else if (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 (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 (csv_state & ST_CS_COND)
+ {
+ conditional_index = *pcsv_template - '0';
+ csv_state &= ~ST_CS_COND;
+ csv_state |= ST_CS_COND_NONEMPTY;
+ }
+ else if (csv_state & ST_CS_HEADER)
+ {
+ num = *pcsv_template - '0';
+ PRINTIF("%s", csv_header[num - 1]);
+ csv_state &= ~ST_CS_HEADER;
+ }
+ else if (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 (csv_state & ST_CS_HEADER)
+ {
+ error(1,
+ (u8*)"csv: Invalid header "
+ "register mark");
+ csv_state &= ~ST_CS_HEADER;
+ }
+ else if (csv_state & ST_CS_REGISTER)
+ {
+ error(1, (u8*)"csv: Invalid register mark");
+ csv_state &= ~ST_CS_REGISTER;
+ }
+ else
+ PRINTIF("%c", *pcsv_template);
+ pcsv_template++;
+ }
+ }
+ return 0;
}
int
read_csv(FILE* output, const char* filename, csv_callback_t callback)
{
- if (!callback)
- exit(error(EINVAL, (u8*)"read_csv: Invalid callback argument"));
-
- FILE* csv = NULL;
- size_t csv_lineno = 0;
- u8* bufline = NULL;
- u8* pbufline = NULL;
- u8* token = NULL;
- u8* ptoken = NULL;
- size_t token_size = 0;
- UBYTE csv_state = ST_CS_NONE;
- u8* csv_header[MAX_CSV_REGISTERS];
- UBYTE current_header = 0;
- u8* csv_register[MAX_CSV_REGISTERS];
- UBYTE current_register = 0;
- u8* csv_delimiter = get_value(vars, vars_count,
- (u8*)"csv-delimiter", NULL);
-
- if (!(csv = fopen(filename, "rt")))
- exit(error(ENOENT, (u8*)"csv: No such file: %s", filename));
-
- CALLOC(bufline, u8, BUFSIZE);
- token_size = BUFSIZE;
- CALLOC(token, u8, token_size);
- for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
- CALLOC(csv_header[i], u8, BUFSIZE);
- for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
- CALLOC(csv_register[i], u8, BUFSIZE);
-
- while (!feof(csv) && (!csv_iter || csv_lineno <= csv_iter))
- {
- u8* eol = NULL;
- if (!fgets((char*)bufline, BUFSIZE, csv))
- break;
- eol = (u8*)strchr((char*)bufline, '\n');
- if (eol)
- *eol = 0;
-
- pbufline = bufline;
- RESET_TOKEN(token, ptoken, token_size);
- current_register = 0;
- while (*pbufline)
- {
- switch (*pbufline)
- {
- case '"':
- if (csv_state & ST_CS_QUOTE)
- csv_state &= ~ST_CS_QUOTE;
- else
- csv_state |= ST_CS_QUOTE;
- pbufline++;
- break;
- case ';':
- case ',':
- if (csv_state & ST_CS_QUOTE)
- CHECKCOPY(token, ptoken, token_size, pbufline);
- else
- {
- *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 (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)
+ if (!callback)
+ exit(error(EINVAL, (u8*)"read_csv: Invalid callback argument"));
+
+ FILE* csv = NULL;
+ size_t csv_lineno = 0;
+ u8* bufline = NULL;
+ u8* pbufline = NULL;
+ u8* token = NULL;
+ u8* ptoken = NULL;
+ size_t token_size = 0;
+ UBYTE csv_state = ST_CS_NONE;
+ u8* csv_header[MAX_CSV_REGISTERS];
+ UBYTE current_header = 0;
+ u8* csv_register[MAX_CSV_REGISTERS];
+ UBYTE current_register = 0;
+ u8* csv_delimiter
+ = get_value(vars, vars_count, (u8*)"csv-delimiter", NULL);
+
+ if (!(csv = fopen(filename, "rt")))
+ exit(error(ENOENT, (u8*)"csv: No such file: %s", filename));
+
+ CALLOC(bufline, u8, BUFSIZE);
+ token_size = BUFSIZE;
+ CALLOC(token, u8, token_size);
+ for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
+ CALLOC(csv_header[i], u8, BUFSIZE);
+ for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
+ CALLOC(csv_register[i], u8, BUFSIZE);
+
+ while (!feof(csv) && (!csv_iter || csv_lineno <= csv_iter))
+ {
+ u8* eol = NULL;
+ if (!fgets((char*)bufline, BUFSIZE, csv))
+ break;
+ eol = (u8*)strchr((char*)bufline, '\n');
+ if (eol)
+ *eol = 0;
+
+ pbufline = bufline;
+ RESET_TOKEN(token, ptoken, token_size);
+ current_register = 0;
+ while (*pbufline)
+ {
+ switch (*pbufline)
+ {
+ case '"':
+ if (csv_state & ST_CS_QUOTE)
+ csv_state &= ~ST_CS_QUOTE;
+ else
+ csv_state |= ST_CS_QUOTE;
+ pbufline++;
+ break;
+ case ';':
+ case ',':
+ if (csv_state & ST_CS_QUOTE)
+ CHECKCOPY(token, ptoken, token_size,
+ pbufline);
+ else
+ {
+ *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 (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);
+ }
+ }
+ }
+ *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);
- }
- }
- }
- *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);
-
- if (csv_lineno > 0 && pbufline != bufline)
- (*callback)(output, csv_header, csv_register);
-
- for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
- *csv_register[i] = 0;
- csv_lineno++;
- }
- fclose(csv);
- for (UBYTE i = MAX_CSV_REGISTERS; i > 0; i--)
- free(csv_register[i-1]);
- for (UBYTE i = MAX_CSV_REGISTERS; i > 0; i--)
- free(csv_header[i-1]);
- free(token);
- free(bufline);
-
- return 0;
+ (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);
+
+ if (csv_lineno > 0 && pbufline != bufline)
+ (*callback)(output, csv_header, csv_register);
+
+ for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
+ *csv_register[i] = 0;
+ csv_lineno++;
+ }
+ fclose(csv);
+ for (UBYTE i = MAX_CSV_REGISTERS; i > 0; i--)
+ free(csv_register[i - 1]);
+ for (UBYTE i = MAX_CSV_REGISTERS; i > 0; i--)
+ free(csv_header[i - 1]);
+ free(token);
+ free(bufline);
+
+ return 0;
}
int
-process_csv(u8* arg_token, FILE* output, BOOL read_yaml_macros_and_links,
- BOOL end_tag)
+process_csv(FILE* output, const u8* arg_token,
+ const BOOL read_yaml_macros_and_links, const BOOL end_tag)
{
- if (end_tag)
- {
- state &= ~ST_CSV_BODY;
-
- if (read_yaml_macros_and_links)
- return 0;
-
- read_csv(output, csv_filename, &print_csv_row);
-
- free(csv_filename);
- csv_filename = NULL;
- free(csv_template);
- csv_template = NULL;
- csv_template_size = 0;
- }
- else
- {
- if (state & ST_CSV_BODY)
- exit(error(1, (u8*)"Can't nest csv directives"));
-
- state |= ST_CSV_BODY;
-
- if (read_yaml_macros_and_links)
- return 0;
-
- csv_iter = 0;
- u8* saveptr = NULL;
- u8* args = (u8*)strtok_r((char*)arg_token, " ", (char**)&saveptr);
- args = (u8*)strtok_r((char*)NULL, " ", (char**)&saveptr);
- if (!args)
- exit(error(EINVAL, (u8*)"csv: Arguments required"));
- size_t args_len = strlen((char*)args);
- if (*args != '"' || *(args + args_len - 1) != '"')
- exit(error(EINVAL, (u8*)"csv: First argument must be a string"));
- if (!csv_filename)
- CALLOC(csv_filename, u8, BUFSIZE);
- u8* args_base = (u8*)strdup((char*)args+1);
- *(args_base + strlen((char*)args_base) - 1) = 0;
- snprintf(csv_filename, BUFSIZE, "%s/%s.csv", input_dirname, (char*)args_base);
- free(args_base);
- args = (u8*)strtok_r((char*)NULL, " ", (char**)&saveptr);
- if (args)
- {
- errno = 0;
- csv_iter = strtol((char*)args, NULL, 10);
- if (errno)
- exit(error(errno, (u8*)"csv: Invalid argument '%s'", args));
- }
- }
-
- return 0;
+ if (end_tag)
+ {
+ state &= ~ST_CSV_BODY;
+
+ if (read_yaml_macros_and_links)
+ return 0;
+
+ read_csv(output, csv_filename, &print_csv_row);
+
+ free(csv_filename);
+ csv_filename = NULL;
+ free(csv_template);
+ csv_template = NULL;
+ csv_template_size = 0;
+ }
+ else
+ {
+ if (IN(state, ST_CSV_BODY))
+ exit(error(1, (u8*)"Can't nest csv directives"));
+
+ state |= ST_CSV_BODY;
+
+ if (read_yaml_macros_and_links)
+ return 0;
+
+ csv_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*)"csv: Arguments required"));
+ size_t args_len = strlen((char*)args);
+ if (*args != '"' || *(args + args_len - 1) != '"')
+ exit(error(EINVAL,
+ (u8*)"csv: First argument must be a string"));
+ if (!csv_filename)
+ CALLOC(csv_filename, u8, BUFSIZE);
+ u8* args_base = (u8*)strdup((char*)args + 1);
+ *(args_base + strlen((char*)args_base) - 1) = 0;
+ snprintf(csv_filename, BUFSIZE, "%s/%s.csv", input_dirname,
+ (char*)args_base);
+ free(args_base);
+ args = (u8*)strtok_r((char*)NULL, " ", (char**)&saveptr);
+ if (args)
+ {
+ errno = 0;
+ csv_iter = strtol((char*)args, NULL, 10);
+ if (errno)
+ exit(error(errno,
+ (u8*)"csv: Invalid argument '%s'",
+ args));
+ }
+ }
+
+ return 0;
}
int
-process_include(u8* token, FILE* output, BOOL read_yaml_macros_and_links)
+process_include(FILE* output, const u8* token,
+ const BOOL 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;
-
- if (!ptoken)
- exit(error(1, (u8*)"Directive 'include' requires"
- " an argument"));
-
- fflush(output);
- pid_t pid = fork();
- int pstatus = 0;
-
- if (pid > 0)
- wait(&pstatus);
- else if (pid == 0)
- {
- prctl(PR_SET_PDEATHSIG, SIGTERM);
-
- CALLOC(include_filename, char, BUFSIZE);
- pinclude_filename = include_filename;
- ptoken++;
- while (ptoken && *ptoken)
- if (*ptoken != '"')
- *pinclude_filename++ = *ptoken++;
- else
- ptoken++;
-
- if (!strcmp(basedir, "."))
- set_basedir(input_dirname, &basedir, &basedir_size);
-
- CALLOC(input_filename, char, BUFSIZE);
- snprintf(input_filename, BUFSIZE, "%s/%s.slw", basedir, include_filename);
- free(include_filename);
-
- FILE* input = NULL;
- FILE* output = stdout;
- u8* buffer = NULL;
- size_t buffer_size = 0;
- int result = 0;
- ULONG saved_state = ST_NONE;
- BOOL saved_output_firstcol = TRUE;
- BOOL saved_skip_para_end = FALSE;
-
- read_file_into_buffer(&buffer, &buffer_size, input_filename,
- &input_dirname, &input);
-
- free_keyvalue(&links, links_count);
- free(links);
- links = NULL;
- links_count = 0;
-
- free_keyvalue(¶links, paralinks_count);
- free(paralinks);
- paralinks = NULL;
- paralinks_count = 0;
-
- free_keyvalue(&footnotes, footnote_count);
- free(footnotes);
- footnotes = NULL;
- footnote_count = 0;
- current_footnote = 0;
-
- while (inline_footnote_count--)
- free(inline_footnotes[inline_footnote_count]);
- if (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 = TRUE;
- skip_para_end = FALSE;
-
- /* First pass: read YAML, macros and links */
- result = slweb_parse(buffer, output, TRUE);
-
- if (result)
- {
- slweb_cleanup();
- free(buffer);
- return result;
- }
- state = ST_NONE;
- output_firstcol = TRUE;
- skip_para_end = FALSE;
- current_footnote = 0;
- current_inline_footnote = 0;
-
- /* Second pass: parse and output */
- result = slweb_parse(buffer, output, FALSE);
-
- state = saved_state;
- output_firstcol = saved_output_firstcol;
- skip_para_end = saved_skip_para_end;
-
- slweb_cleanup();
- free(buffer);
- exit(result);
- }
- else
- exit(error(1, (u8*)"Fork failed"));
-
- return 0;
+ 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;
+
+ if (!ptoken)
+ exit(error(1,
+ (u8*)"Directive 'include' requires"
+ " an argument"));
+
+ fflush(output);
+ pid_t pid = fork();
+ int pstatus = 0;
+
+ if (pid > 0)
+ wait(&pstatus);
+ else if (pid == 0)
+ {
+ char* filename = NULL;
+ prctl(PR_SET_PDEATHSIG, SIGTERM);
+
+ CALLOC(include_filename, char, BUFSIZE);
+ pinclude_filename = include_filename;
+ ptoken++;
+ while (ptoken && *ptoken)
+ if (*ptoken != '"')
+ *pinclude_filename++ = *ptoken++;
+ else
+ ptoken++;
+
+ if (!strcmp(basedir, "."))
+ set_basedir(&basedir, &basedir_size, input_dirname);
+
+ CALLOC(filename, char, BUFSIZE);
+ snprintf(filename, BUFSIZE, "%s/%s.slw", basedir,
+ 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;
+ BOOL saved_output_firstcol = TRUE;
+ BOOL saved_skip_para_end = FALSE;
+
+ read_file_into_buffer(&input, &buffer, &buffer_size,
+ input_filename, &input_dirname);
+
+ free_keyvalue(&links, links_count);
+ free(links);
+ links = NULL;
+ links_count = 0;
+
+ free_keyvalue(¶links, paralinks_count);
+ free(paralinks);
+ paralinks = NULL;
+ paralinks_count = 0;
+
+ free_keyvalue(&footnotes, footnote_count);
+ free(footnotes);
+ footnotes = NULL;
+ footnote_count = 0;
+ current_footnote = 0;
+
+ while (inline_footnote_count--)
+ free(inline_footnotes[inline_footnote_count]);
+ if (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 = TRUE;
+ skip_para_end = FALSE;
+
+ /* First pass: read YAML, macros and links */
+ result = slweb_parse(output, input_filename, buffer, TRUE);
+
+ if (result)
+ {
+ slweb_cleanup();
+ free(filename);
+ free(buffer);
+ return result;
+ }
+ state = ST_NONE;
+ output_firstcol = TRUE;
+ skip_para_end = FALSE;
+ current_footnote = 0;
+ current_inline_footnote = 0;
+
+ /* Second pass: parse and output */
+ result = slweb_parse(output, input_filename, buffer, FALSE);
+
+ state = saved_state;
+ output_firstcol = saved_output_firstcol;
+ skip_para_end = saved_skip_para_end;
+
+ slweb_cleanup();
+ free(filename);
+ free(buffer);
+ exit(result);
+ }
+ else
+ exit(error(1, (u8*)"Fork failed"));
+
+ return 0;
}
int
process_list_start(FILE* output)
{
- return 0;
+ return 0;
}
int
process_list_item_start(FILE* output)
{
- fprintf(output, "%s* ", output_firstcol ? "" : "\n");
- state |= ST_PARA_OPEN;
- return 0;
+ fprintf(output, "%s* ", output_firstcol ? "" : "\n");
+ state |= ST_PARA_OPEN;
+ return 0;
}
-int
-process_paralinks(const u8* link_prefix, FILE* output);
+int process_paralinks(FILE* output, const u8* link_prefix);
int
-process_list_item_end(const u8* link_prefix, FILE* output)
+process_list_item_end(FILE* output, const u8* link_prefix)
{
- if (state & ST_PARA_OPEN)
- {
- state &= ~ST_PARA_OPEN;
- print_output(output, "\n\n");
- output_firstcol = TRUE;
- process_paralinks(link_prefix, output);
- }
- return 0;
+ if (IN(state, ST_PARA_OPEN))
+ {
+ state &= ~ST_PARA_OPEN;
+ print_output(output, "\n\n");
+ output_firstcol = TRUE;
+ process_paralinks(output, link_prefix);
+ }
+ return 0;
}
int
process_list_end(FILE* output)
{
- return 0;
+ return 0;
}
int
process_numlist_start(FILE* output)
{
- return 0;
+ return 0;
}
int
process_numlist_end(FILE* output)
{
- return 0;
+ return 0;
}
int
filter_subdirs(const struct dirent* node)
{
- if (!node || ((*node->d_name == '.')
- && (!*(node->d_name+1)
- || ((*(node->d_name+1) == '.')
- && !(*(node->d_name+2))))))
- return 0;
-
- struct stat st;
- char* nodename = NULL;
-
- CALLOC(nodename, char, BUFSIZE);
- snprintf(nodename, BUFSIZE, "%s/%s", incdir, node->d_name);
-
- if (lstat(nodename, &st) < 0 || !S_ISDIR(st.st_mode))
- {
- free(nodename);
- return 0;
- }
-
- free(nodename);
-
- return 1;
+ if (!node
+ || ((*node->d_name == '.')
+ && (!*(node->d_name + 1)
+ || ((*(node->d_name + 1) == '.')
+ && !(*(node->d_name + 2))))))
+ return 0;
+
+ struct stat st;
+ char* nodename = NULL;
+
+ CALLOC(nodename, char, BUFSIZE);
+ snprintf(nodename, BUFSIZE, "%s/%s", incdir, node->d_name);
+
+ if (lstat(nodename, &st) < 0 || !S_ISDIR(st.st_mode))
+ {
+ free(nodename);
+ return 0;
+ }
+
+ free(nodename);
+
+ return 1;
}
int
filter_slw(const struct dirent* node)
{
- if (!node || ((*node->d_name == '.')
- && (!*(node->d_name+1)
- || ((*(node->d_name+1) == '.')
- && !(*(node->d_name+2))))))
- return 0;
-
- size_t node_len = strlen(node->d_name);
- size_t slw_len = strlen(".slw");
-
- if (slw_len >= node_len)
- return 0;
- return !strcmp(node->d_name + strlen(node->d_name) - slw_len, ".slw");
+ if (!node
+ || ((*node->d_name == '.')
+ && (!*(node->d_name + 1)
+ || ((*(node->d_name + 1) == '.')
+ && !(*(node->d_name + 2))))))
+ return 0;
+
+ size_t node_len = strlen(node->d_name);
+ size_t slw_len = strlen(".slw");
+
+ if (slw_len >= node_len)
+ return 0;
+ return !strcmp(node->d_name + strlen(node->d_name) - slw_len, ".slw");
}
-int
+int
reverse_alphacompare(const struct dirent** a, const struct dirent** b)
{
- if (!a || !b)
- return 0;
+ if (!a || !b)
+ return 0;
- return -1 * strcmp((*a)->d_name, (*b)->d_name);
+ return -1 * strcmp((*a)->d_name, (*b)->d_name);
}
-int
-process_timestamp(FILE* output, const u8* link_prefix, const char* link,
- u8* permalink_macro, u8* date, u8* title);
+int process_timestamp(FILE* output, const u8* link_prefix, const char* link,
+ const u8* permalink_macro, const u8* date, const u8* title);
int
-process_incdir_subdir(const char* subdirname, const u8* link_prefix,
- FILE* output, BOOL details_open, u8* macro_body)
+process_incdir_subdir(FILE* output, const char* subdirname,
+ const u8* link_prefix, BOOL details_open, u8* macro_body)
{
- struct dirent** namelist;
- struct dirent** pnamelist;
- long names_total = 0;
- long names_output;
- char* abs_subdirname = NULL;
-
- 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)
- {
- perror("scandir");
- exit(error(errno, (u8*)"incdir_subdir: scandir '%s' error",
- abs_subdirname));
- }
-
- pnamelist = namelist;
- names_output = 0;
- while (names_output < names_total && pnamelist && *pnamelist)
- {
- int pstatus = 0;
- char* basename = strip_ext((*pnamelist)->d_name);
- char* link = NULL;
- CALLOC(link, char, BUFSIZE);
-
- snprintf(link, BUFSIZE, "%s/%s", subdirname, basename);
-
- fflush(output);
- pid_t pid = fork();
-
- if (pid > 0)
- wait(&pstatus);
- else if (pid == 0)
- {
- set_basedir(abs_subdirname, &basedir, &basedir_size);
- snprintf(input_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;
- BOOL saved_output_firstcol = TRUE;
- BOOL saved_skip_para_end = FALSE;
-
- read_file_into_buffer(&buffer, &buffer_size, input_filename,
- &input_dirname, &input);
-
- free_keyvalue(&links, links_count);
- free(links);
- links = NULL;
- links_count = 0;
-
- free_keyvalue(¶links, paralinks_count);
- free(paralinks);
- paralinks = 0;
- paralinks_count = 0;
-
- free_keyvalue(&footnotes, footnote_count);
- free(footnotes);
- footnotes = 0;
- footnote_count = 0;
- current_footnote = 0;
-
- while (inline_footnote_count--)
- free(inline_footnotes[inline_footnote_count]);
- if (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 = TRUE;
- skip_para_end = FALSE;
-
- /* Read YAML, macros and links */
- result = slweb_parse(buffer, output, TRUE);
-
- if (result)
- {
- slweb_cleanup();
- free(buffer);
- free(link);
- free(basename);
- free(abs_subdirname);
- while (names_total--)
- free(namelist[names_total]);
- free(namelist);
- return result;
- }
-
- u8* date = get_value(vars, vars_count, (u8*)"date", NULL);
- u8* title = get_value(vars, vars_count, (u8*)"title",
- NULL);
- if (title && date)
- process_timestamp(output, link_prefix, link, NULL, date, title);
-
- state = saved_state;
- output_firstcol = saved_output_firstcol;
- skip_para_end = saved_skip_para_end;
-
- fflush(output);
- slweb_cleanup();
- free(buffer);
- free(link);
- free(basename);
- free(abs_subdirname);
- while (names_total--)
- free(namelist[names_total]);
- free(namelist);
- exit(result);
- }
- else
- exit(error(1, (u8*)"Fork failed"));
-
- free(link);
- free(basename);
- pnamelist++;
- names_output++;
- }
-
- while (names_total--)
- free(namelist[names_total]);
- free(namelist);
- free(abs_subdirname);
-
- return 0;
+ struct dirent** namelist;
+ struct dirent** pnamelist;
+ long names_total = 0;
+ long names_output;
+ char* abs_subdirname = NULL;
+
+ 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)
+ {
+ perror("scandir");
+ exit(error(errno, (u8*)"incdir_subdir: scandir '%s' error",
+ abs_subdirname));
+ }
+
+ pnamelist = namelist;
+ names_output = 0;
+ while (names_output < names_total && pnamelist && *pnamelist)
+ {
+ int pstatus = 0;
+ char* basename = strip_ext((*pnamelist)->d_name);
+ char* link = NULL;
+ CALLOC(link, char, BUFSIZE);
+
+ snprintf(link, BUFSIZE, "%s/%s", subdirname, basename);
+
+ fflush(output);
+ pid_t pid = fork();
+
+ if (pid > 0)
+ wait(&pstatus);
+ else if (pid == 0)
+ {
+ char* filename = NULL;
+ set_basedir(&basedir, &basedir_size, abs_subdirname);
+ CALLOC(filename, char, BUFSIZE);
+ 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;
+ BOOL saved_output_firstcol = TRUE;
+ BOOL saved_skip_para_end = FALSE;
+
+ read_file_into_buffer(&input, &buffer, &buffer_size,
+ filename, &input_dirname);
+
+ free_keyvalue(&links, links_count);
+ free(links);
+ links = NULL;
+ links_count = 0;
+
+ free_keyvalue(¶links, paralinks_count);
+ free(paralinks);
+ paralinks = 0;
+ paralinks_count = 0;
+
+ free_keyvalue(&footnotes, footnote_count);
+ free(footnotes);
+ footnotes = 0;
+ footnote_count = 0;
+ current_footnote = 0;
+
+ while (inline_footnote_count--)
+ free(inline_footnotes[inline_footnote_count]);
+ if (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 = TRUE;
+ skip_para_end = FALSE;
+
+ /* Read YAML, macros and links */
+ result = slweb_parse(output, filename, buffer, TRUE);
+
+ if (result)
+ {
+ slweb_cleanup();
+ free(filename);
+ free(buffer);
+ free(link);
+ free(basename);
+ free(abs_subdirname);
+ while (names_total--)
+ free(namelist[names_total]);
+ free(namelist);
+ return result;
+ }
+
+ u8* date = get_value(vars, vars_count, (u8*)"date",
+ NULL);
+ u8* title = get_value(vars, vars_count, (u8*)"title",
+ NULL);
+ if (title && date)
+ process_timestamp(output, link_prefix, link,
+ NULL, date, title);
+
+ state = saved_state;
+ output_firstcol = saved_output_firstcol;
+ skip_para_end = saved_skip_para_end;
+
+ fflush(output);
+ slweb_cleanup();
+ free(filename);
+ free(buffer);
+ free(link);
+ free(basename);
+ free(abs_subdirname);
+ while (names_total--)
+ free(namelist[names_total]);
+ free(namelist);
+ exit(result);
+ }
+ else
+ exit(error(1, (u8*)"Fork failed"));
+
+ free(link);
+ free(basename);
+ pnamelist++;
+ names_output++;
+ }
+
+ while (names_total--)
+ free(namelist[names_total]);
+ free(namelist);
+ free(abs_subdirname);
+
+ return 0;
}
int
-process_incdir(u8* token, const u8* link_prefix, FILE* output,
- BOOL read_yaml_macros_and_links)
+process_incdir(FILE* output, const u8* token, const u8* link_prefix,
+ const BOOL read_yaml_macros_and_links)
{
- if (read_yaml_macros_and_links)
- return 0;
-
- 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;
- struct dirent** namelist;
- BOOL details_open = TRUE;
-
-
- arg = (u8*)strtok_r((char*)NULL, " ", (char**)&saveptr);
- if (!arg)
- exit(error(1, (u8*)"incdir: Arguments required"));
-
- arg_len = strlen((char*)arg);
-
- if (*arg != '"' || *(arg + arg_len - 1) != '"')
- exit(error(1, (u8*)"incdir: First argument not string"));
-
- incdir = strdup((char*)(arg+1));
- *(incdir + strlen(incdir) - 1) = 0;
-
- arg = (u8*)strtok_r((char*)NULL, " ", (char**)&saveptr);
- if (!arg)
- exit(error(1, (u8*)"incdir: Second argument required"));
-
- if (*arg == '=')
- macro_body = get_value(macros, macros_count, arg+1, NULL);
- else
- {
- u8* parg = arg;
- while (parg && *parg)
- {
- if (*parg < '0' || *parg > '9')
- exit(error(1, (u8*)"incdir: Non-numeric argument"));
- parg++;
- }
- num = strtol((char*)arg, NULL, 10);
- if (errno)
- exit(error(errno, (u8*)"incdir: Invalid parameter 'num'"));
- arg = (u8*)strtok_r((char*)NULL, " ", (char**)&saveptr);
- if (arg)
- {
- if (*arg != '=')
- {
- free(incdir);
- exit(error(1, (u8*)"incdir: Third argument not macro"));
- }
- macro_body = get_value(macros, macros_count, arg+1, NULL);
- }
- }
-
- if ((names_total = scandir(incdir, &namelist, &filter_subdirs,
- &reverse_alphacompare)) < 0)
- {
- perror("scandir");
- 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)
- {
- process_incdir_subdir(namelist[current_name]->d_name, link_prefix,
- output, details_open, macro_body);
- details_open = FALSE;
- current_name++;
- }
- print_output(output, "\n");
- output_firstcol = TRUE;
-
- while (names_total--)
- free(namelist[names_total]);
- free(namelist);
- free(incdir);
-
- return 0;
+ if (read_yaml_macros_and_links)
+ return 0;
+
+ 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;
+ struct dirent** namelist;
+ BOOL details_open = TRUE;
+
+ arg = (u8*)strtok_r((char*)NULL, " ", (char**)&saveptr);
+ if (!arg)
+ exit(error(1, (u8*)"incdir: Arguments required"));
+
+ arg_len = strlen((char*)arg);
+
+ if (*arg != '"' || *(arg + arg_len - 1) != '"')
+ exit(error(1, (u8*)"incdir: First argument not string"));
+
+ incdir = strdup((char*)(arg + 1));
+ *(incdir + strlen(incdir) - 1) = 0;
+
+ arg = (u8*)strtok_r((char*)NULL, " ", (char**)&saveptr);
+ if (!arg)
+ exit(error(1, (u8*)"incdir: Second argument required"));
+
+ if (*arg == '=')
+ macro_body = get_value(macros, macros_count, arg + 1, NULL);
+ else
+ {
+ u8* parg = arg;
+ while (parg && *parg)
+ {
+ if (*parg < '0' || *parg > '9')
+ exit(error(1,
+ (u8*)"incdir: Non-numeric argument"));
+ parg++;
+ }
+ num = strtol((char*)arg, NULL, 10);
+ if (errno)
+ exit(error(errno,
+ (u8*)"incdir: Invalid parameter 'num'"));
+ arg = (u8*)strtok_r((char*)NULL, " ", (char**)&saveptr);
+ if (arg)
+ {
+ if (*arg != '=')
+ {
+ free(incdir);
+ exit(error(1,
+ (u8*)"incdir: Third argument not "
+ "macro"));
+ }
+ macro_body = get_value(macros, macros_count, arg + 1,
+ NULL);
+ }
+ }
+
+ if ((names_total = scandir(incdir, &namelist, &filter_subdirs,
+ &reverse_alphacompare))
+ < 0)
+ {
+ perror("scandir");
+ 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)
+ {
+ process_incdir_subdir(output, namelist[current_name]->d_name,
+ link_prefix, details_open, macro_body);
+ details_open = FALSE;
+ current_name++;
+ }
+ print_output(output, "\n");
+ output_firstcol = TRUE;
+
+ while (names_total--)
+ free(namelist[names_total]);
+ free(namelist);
+ free(incdir);
+
+ return 0;
}
-BOOL
-url_is_local(const char* url);
+BOOL url_is_local(const char* url);
int
-process_timestamp(FILE* output, const u8* link_prefix, const char* link,
- u8* permalink_macro, u8* date, u8* title)
+process_timestamp(FILE* output, const u8* link_prefix, const char* link,
+ const u8* permalink_macro, const u8* date, const u8* title)
{
- u8* day = NULL;
- u8* month = NULL;
- u8* year = NULL;
- u8* formatted_date = NULL;
- u8* ptr = NULL;
- const char* ptimestamp_format = NULL;
- char* in_filename = NULL;
- char* in_line = NULL;
-
- CALLOC(formatted_date, u8, DATEBUFSIZE);
- ptr = NULL;
- year = (u8*)strtok_r((char*)date, "-", (char**)&ptr);
- if (year)
- {
- month = (u8*)strtok_r((char*)NULL, "-", (char**)&ptr);
- if (month)
- {
- day = (u8*)strtok_r((char*)NULL, "T", (char**)&ptr);
- if (day)
- {
- 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);
- else if (*ptimestamp_format == 'm'
- || *ptimestamp_format == 'M')
- strncat((char*)formatted_date, (char*)month,
- DATEBUFSIZE-strlen((char*)formatted_date)-1);
- else if (*ptimestamp_format == 'y'
- || *ptimestamp_format == 'Y')
- strncat((char*)formatted_date, (char*)year,
- DATEBUFSIZE-strlen((char*)formatted_date)-1);
- else
- *(formatted_date + strlen((char*)formatted_date))
- = *ptimestamp_format;
-
- ptimestamp_format++;
- }
- if (title)
- print_output(output, "=> %s%s%s.gmi\t%s %s\n",
- url_is_local(link) && global_link_prefix
- ? (const char*)global_link_prefix : "",
- url_is_local(link) && link_prefix
- ? (const char*)link_prefix : "",
- link, formatted_date, title);
- else
- print_output(output, "=> %s%s%s.gmi\t%s\n",
- url_is_local(link) && global_link_prefix
- ? (const char*)global_link_prefix : "",
- url_is_local(link) && link_prefix
- ? (const char*)link_prefix : "",
- link, formatted_date);
- output_firstcol = TRUE;
- }
- }
- }
-
- free(formatted_date);
- free(in_line);
- free(in_filename);
-
- return 0;
+ u8* day = NULL;
+ u8* month = NULL;
+ u8* year = NULL;
+ u8* formatted_date = NULL;
+ u8* ptr = NULL;
+ const char* ptimestamp_format = NULL;
+ char* in_filename = NULL;
+ char* in_line = NULL;
+
+ CALLOC(formatted_date, u8, DATEBUFSIZE);
+ ptr = NULL;
+ year = (u8*)strtok_r((char*)date, "-", (char**)&ptr);
+ if (year)
+ {
+ month = (u8*)strtok_r((char*)NULL, "-", (char**)&ptr);
+ if (month)
+ {
+ day = (u8*)strtok_r((char*)NULL, "T", (char**)&ptr);
+ if (day)
+ {
+ 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);
+ else if (*ptimestamp_format == 'm'
+ || *ptimestamp_format == 'M')
+ strncat((char*)formatted_date,
+ (char*)month,
+ DATEBUFSIZE
+ - strlen((
+ char*)formatted_date)
+ - 1);
+ else if (*ptimestamp_format == 'y'
+ || *ptimestamp_format == 'Y')
+ strncat((char*)formatted_date,
+ (char*)year,
+ DATEBUFSIZE
+ - strlen((
+ char*)formatted_date)
+ - 1);
+ else
+ *(formatted_date
+ + strlen((
+ char*)formatted_date))
+ = *ptimestamp_format;
+
+ ptimestamp_format++;
+ }
+ if (title)
+ print_output(output,
+ "=> %s%s%s.gmi\t%s %s\n",
+ url_is_local(
+ link) && global_link_prefix
+ ? (const char*)
+ global_link_prefix
+ : "",
+ url_is_local(link) && link_prefix
+ ? (const char*)link_prefix
+ : "",
+ link, formatted_date, title);
+ else
+ print_output(output,
+ "=> %s%s%s.gmi\t%s\n",
+ url_is_local(
+ link) && global_link_prefix
+ ? (const char*)
+ global_link_prefix
+ : "",
+ url_is_local(link) && link_prefix
+ ? (const char*)link_prefix
+ : "",
+ link, formatted_date);
+ output_firstcol = TRUE;
+ }
+ }
+ }
+
+ free(formatted_date);
+ free(in_line);
+ free(in_filename);
+
+ return 0;
}
int
-process_macro(u8* token, FILE* output, BOOL read_yaml_macros_and_links,
- BOOL end_tag)
+process_macro(FILE* output, const u8* token,
+ const BOOL read_yaml_macros_and_links, const BOOL end_tag)
{
- if (!end_tag)
- {
- if (state & ST_MACRO_BODY)
- exit(error(1, (u8*)"Macro undefined or nested"));
-
- BOOL seen = FALSE;
- u8* 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)
- {
- u8* eol = (u8*)strrchr((char*)macro_body, '\n');
- size_t macro_body_len = strlen((char*)macro_body);
- if (eol)
- output_firstcol = macro_body + macro_body_len -
- (u8*)strrchr((char*)macro_body, '\n') > 0;
- else
- output_firstcol = !*macro_body
- || *(macro_body+macro_body_len-1) == '\n';
- print_output(output, "%s", macro_body);
- }
- else
- state |= ST_MACRO_BODY;
- }
- }
- else
- {
- if (read_yaml_macros_and_links)
- {
- macros_count++;
-
- if (!macros)
- {
- CALLOC(macros, KeyValue, macros_count);
- pmacros = macros;
- }
- else
- {
- REALLOC(macros, KeyValue, macros_count * sizeof(KeyValue));
- pmacros = macros + macros_count - 1;
- }
- CALLOC(pmacros->key, u8, KEYSIZE);
- pmacros->seen = FALSE;
- strncpy((char*)pmacros->key, (char*)token+1, KEYSIZE-1);
- pmacros->value = NULL;
- pmacros->value_size = 0;
- }
- state |= ST_MACRO_BODY;
- }
- }
- else
- state &= ~ST_MACRO_BODY;
-
- return 0;
+ if (!end_tag)
+ {
+ if (IN(state, ST_MACRO_BODY))
+ exit(error(1, (u8*)"Macro undefined or nested"));
+
+ BOOL seen = FALSE;
+ u8* macro_body = get_value(macros, macros_count, token + 1,
+ read_yaml_macros_and_links ? NULL : &seen);
+
+ if (macro_body && !read_yaml_macros_and_links)
+ {
+ if (seen)
+ {
+ u8* eol = (u8*)strrchr((char*)macro_body, '\n');
+ size_t macro_body_len
+ = strlen((char*)macro_body);
+ if (eol)
+ output_firstcol = macro_body
+ + macro_body_len
+ - (u8*)strrchr(
+ (char*)macro_body,
+ '\n')
+ > 0;
+ else
+ output_firstcol = !*macro_body
+ || *(macro_body + macro_body_len
+ - 1)
+ == '\n';
+ print_output(output, "%s", macro_body);
+ }
+ else
+ state |= ST_MACRO_BODY;
+ }
+ else if (!macro_body)
+ {
+ if (read_yaml_macros_and_links)
+ {
+ macros_count++;
+
+ if (!macros)
+ {
+ CALLOC(macros, KeyValue, macros_count);
+ pmacros = macros;
+ }
+ else
+ {
+ REALLOC(macros, KeyValue,
+ macros_count * sizeof(KeyValue));
+ pmacros = macros + macros_count - 1;
+ }
+ CALLOC(pmacros->key, u8, KEYSIZE);
+ pmacros->seen = FALSE;
+ strncpy((char*)pmacros->key, (char*)token + 1,
+ KEYSIZE - 1);
+ pmacros->value = NULL;
+ pmacros->value_size = 0;
+ }
+ state |= ST_MACRO_BODY;
+ }
+ }
+ else
+ state &= ~ST_MACRO_BODY;
+
+ return 0;
}
-int
-process_para_end(const u8* link_prefix, BOOL previous_line_blank, FILE* output);
+int process_para_end(FILE* output, const u8* link_prefix,
+ const BOOL previous_line_blank);
int
-process_tag(u8* token, const u8* link_prefix, FILE* output,
- BOOL previous_line_blank, BOOL read_yaml_macros_and_links,
- BOOL* skip_eol, BOOL end_tag)
+process_tag(FILE* output, const u8* token, const u8* link_prefix,
+ const BOOL previous_line_blank, const BOOL read_yaml_macros_and_links,
+ BOOL* skip_eol, const BOOL end_tag)
{
- if (!token || strlen((char*)token) < 1)
- return warning(1, (u8*)"%s:%ld:%ld: Empty tag name",
- input_filename, lineno, colno);
-
- 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} */
- {
- print_output(output, "Generated by slw2gmi © %s Strahinya Radich.\n",
- COPYRIGHTYEAR);
- output_firstcol = TRUE;
- }
- else if (startswith((char*)token, "csv")) /* {csv} */
- {
- process_csv(token, output, read_yaml_macros_and_links, end_tag);
- }
- else if (startswith((char*)token, "include")) /* {include} */
- {
- process_include(token, output, read_yaml_macros_and_links);
- *skip_eol = TRUE;
- }
- else if (startswith((char*)token, "incdir")) /* {incdir} */
- {
- process_incdir(token, link_prefix, output, read_yaml_macros_and_links);
- *skip_eol = TRUE;
- }
- else if (*token == '=') /* {=macro} */
- {
- process_macro(token, output, read_yaml_macros_and_links, end_tag);
- *skip_eol = TRUE;
- }
- else if (startswith((char*)token, "p") && !read_yaml_macros_and_links)
- {
- skip_para_end = TRUE;
- *skip_eol = TRUE;
- if (end_tag)
- {
- process_para_end(link_prefix, previous_line_blank, output);
- output_firstcol = TRUE;
- }
- }
-
- return 0;
+ if (!token || strlen((char*)token) < 1)
+ return warning(1, (u8*)"%s:%ld:%ld: Empty tag name",
+ input_filename, lineno, colno);
+
+ 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} */
+ {
+ print_output(output,
+ "Generated by slw2gmi © %s Strahinya Radich.\n",
+ COPYRIGHTYEAR);
+ output_firstcol = TRUE;
+ }
+ else if (startswith((char*)token, "csv")) /* {csv} */
+ {
+ process_csv(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);
+ *skip_eol = TRUE;
+ }
+ else if (startswith((char*)token, "incdir")) /* {incdir} */
+ {
+ process_incdir(output, token, link_prefix,
+ read_yaml_macros_and_links);
+ *skip_eol = TRUE;
+ }
+ else if (*token == '=') /* {=macro} */
+ {
+ process_macro(output, token, read_yaml_macros_and_links,
+ end_tag);
+ *skip_eol = TRUE;
+ }
+ else if (startswith((char*)token, "p") && !read_yaml_macros_and_links)
+ {
+ skip_para_end = TRUE;
+ *skip_eol = TRUE;
+ if (end_tag)
+ {
+ process_para_end(output, link_prefix,
+ previous_line_blank);
+ output_firstcol = TRUE;
+ }
+ }
+
+ return 0;
}
int
process_bold(FILE* output, BOOL end_tag)
{
- return 0;
+ return 0;
}
int
process_italic(FILE* output, BOOL end_tag)
{
- return 0;
+ return 0;
}
int
process_code(FILE* output, BOOL end_tag)
{
- return 0;
+ return 0;
}
int
process_blockquote(FILE* output, BOOL end_tag)
{
- if (end_tag)
- print_output(output, "\n\n");
- else
- print_output(output, "%s>", output_firstcol ? "" : "\n");
- return 0;
+ if (end_tag)
+ print_output(output, "\n\n");
+ else
+ print_output(output, "%s>", output_firstcol ? "" : "\n");
+ return 0;
}
int
process_kbd(FILE* output, BOOL end_tag)
{
- return 0;
+ return 0;
}
int
process_strike(FILE* output, BOOL end_tag)
{
- print_output(output, "~");
- return 0;
+ print_output(output, "~");
+ return 0;
}
int
process_table_start(FILE* output)
{
- return 0;
+ return 0;
}
int
process_table_header_cell(FILE* output)
{
- return 0;
+ return 0;
}
-int
+int
process_table_header_end(FILE* output)
{
- return 0;
+ return 0;
}
int
process_table_body_start(FILE* output, BOOL start_row)
{
- return 0;
+ return 0;
}
int
process_table_body_row_start(FILE* output)
{
- return 0;
+ return 0;
}
int
process_table_body_cell(FILE* output)
{
- return 0;
+ return 0;
}
int
process_table_body_row_end(FILE* output)
{
- return 0;
+ return 0;
}
int
process_table_end(FILE* output)
{
- return 0;
+ return 0;
}
BOOL
url_is_local(const char* url)
{
- return !(startswith(url, "http://")
- || startswith(url, "https://")
- || startswith(url, "gemini://")
- || startswith(url, "ftp://")
- || startswith(url, "ftps://")
- || startswith(url, "mailto://"));
+ return !(startswith(url, "http://") || startswith(url, "https://")
+ || startswith(url, "gemini://") || startswith(url, "ftp://")
+ || startswith(url, "ftps://") || startswith(url, "mailto://"));
}
int
-get_realpath(char** realpath, char* relativeto, char* path)
+process_inline_link(FILE* output, const u8* link_text)
{
- u8* command = NULL;
- FILE* cmd_output = NULL;
-
- CALLOC(command, u8, BUFSIZE);
- strncpy(*realpath, ".", BUFSIZE-1);
- snprintf((char*)command, BUFSIZE-1, "realpath --relative-to=%s %s",
- relativeto, path);
-
- cmd_output = popen((char*)command, "r");
- if (cmd_output)
- {
- u8* cmd_output_line = NULL;
- CALLOC(cmd_output_line, u8, 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;
-
- strncpy(*realpath, (char*)cmd_output_line, BUFSIZE-1);
- }
- pclose(cmd_output);
- free(cmd_output_line);
- }
- else
- warning(1, (u8*)"get_realpath: Cannot popen");
-
- free(command);
-
- return 0;
+ print_output(output, "%s", link_text);
+ return 0;
}
int
-process_inline_link(u8* link_text, u8* link_macro_body,
- u8* link_url, FILE* output)
+process_link(FILE* output, const u8* link_text)
{
- print_output(output, "%s", link_text);
- return 0;
+ return process_inline_link(output, link_text);
}
int
-process_link(u8* link_text, u8* link_macro_body, u8* link_id,
- FILE* output)
+process_inline_image(FILE* output, const u8* image_text)
{
- u8* url = get_value(links, links_count, link_id, NULL);
- return process_inline_link(link_text, link_macro_body,
- url, output);
+ print_output(output, "%s ", image_text);
+ return 0;
}
int
-process_inline_image(u8* image_text, u8* image_url, FILE* output,
- BOOL add_link, BOOL add_figcaption)
+process_image(FILE* output, const u8* image_text)
{
- print_output(output, "%s ", image_text);
- return 0;
+ return process_inline_image(output, image_text);
}
int
-process_image(u8* image_text, u8* image_id, FILE* output,
- BOOL add_link, BOOL add_figcaption)
+process_paralinks(FILE* output, const u8* link_prefix)
{
- u8* url = get_value(links, links_count, image_id, NULL);
- return process_inline_image(image_text, url, output, add_link,
- add_figcaption);
+ KeyValue* pparalink = paralinks;
+ if (!skip_para_end)
+ {
+ /*
+ *if (!output_firstcol && (paralinks_count > 0))
+ * print_output(output, "\n");
+ */
+
+ /*print_output(output, "\n");*/
+ }
+ while (pparalink < paralinks + paralinks_count)
+ {
+ if (pparalink->key)
+ {
+ print_output(output, "=> %s%s%s\t%s\n",
+ url_is_local((const char*)pparalink->key)
+ && global_link_prefix
+ ? (const char*)global_link_prefix
+ : "",
+ url_is_local((const char*)pparalink->key)
+ && link_prefix
+ ? (const char*)link_prefix
+ : "",
+ pparalink->key, pparalink->value);
+ output_firstcol = TRUE;
+ }
+ pparalink++;
+ }
+ if (paralinks_count > 0)
+ print_output(output, "\n");
+
+ free_keyvalue(¶links, paralinks_count);
+ free(paralinks);
+ paralinks = NULL;
+ paralinks_count = 0;
+ pparalinks = paralinks;
+
+ return 0;
}
int
-process_paralinks(const u8* link_prefix, FILE* output)
+process_para_end(FILE* output, const u8* link_prefix,
+ const BOOL previous_line_blank)
{
- KeyValue* pparalink = paralinks;
- if (!skip_para_end)
- {
- /*
- *if (!output_firstcol && (paralinks_count > 0))
- * print_output(output, "\n");
- */
- print_output(output, "\n");
- }
- while (pparalink < paralinks + paralinks_count)
- {
- if (pparalink->key)
- {
- print_output(output, "=> %s%s%s\t%s\n",
- url_is_local((const char*)pparalink->key) && global_link_prefix
- ? (const char*)global_link_prefix : "",
- url_is_local((const char*)pparalink->key) && link_prefix
- ? (const char*)link_prefix : "",
- pparalink->key, pparalink->value);
- output_firstcol = TRUE;
- }
- pparalink++;
- }
- if (paralinks_count > 0)
- print_output(output, "\n");
-
- free_keyvalue(¶links, paralinks_count);
- free(paralinks);
- paralinks = NULL;
- paralinks_count = 0;
- pparalinks = paralinks;
-
- return 0;
+ if (!skip_para_end)
+ print_output(output, "\n");
+ process_paralinks(output, link_prefix);
+
+ return 0;
}
int
-process_para_end(const u8* link_prefix, BOOL previous_line_blank, FILE* output)
+process_line_start(FILE* output, const u8* line, const u8* link_prefix,
+ const BOOL first_line_in_doc, const BOOL previous_line_blank,
+ const BOOL read_yaml_macros_and_links, const BOOL list_para, u8** token,
+ u8** ptoken)
{
- if (!skip_para_end)
- print_output(output, "\n");
- process_paralinks(link_prefix, output);
+ if ((first_line_in_doc || previous_line_blank)
+ && !(ANY(state, ST_BLOCKQUOTE | ST_PRE)))
+ {
+ if (!list_para)
+ {
+ if (state & ST_LIST)
+ {
+ state &= ~ST_LIST;
+ if (!read_yaml_macros_and_links)
+ {
+ process_list_item_end(output,
+ link_prefix);
+ process_list_end(output);
+ }
+ }
- return 0;
-}
+ if (state & ST_NUMLIST)
+ {
+ state &= ~ST_NUMLIST;
+ if (!read_yaml_macros_and_links)
+ {
+ process_list_item_end(output,
+ link_prefix);
+ process_numlist_end(output);
+ }
+ }
-int
-process_line_start(u8* line, const u8* link_prefix,
- BOOL first_line_in_doc, BOOL previous_line_blank,
- BOOL read_yaml_macros_and_links, BOOL skip_eol, BOOL list_para,
- FILE* output, u8** token, u8** ptoken)
-{
- if ((first_line_in_doc || previous_line_blank)
- && !(ANY(state, ST_BLOCKQUOTE | ST_PRE)))
- {
- if (!list_para)
- {
- if (state & ST_LIST)
- {
- state &= ~ST_LIST;
- if (!read_yaml_macros_and_links)
- {
- process_list_item_end(link_prefix, output);
- process_list_end(output);
- }
- }
-
- if (state & ST_NUMLIST)
- {
- state &= ~ST_NUMLIST;
- if (!read_yaml_macros_and_links)
- {
- process_list_item_end(link_prefix, output);
- process_numlist_end(output);
- }
- }
-
- if (state & ST_FOOTNOTE_TEXT)
- {
- if (!read_yaml_macros_and_links && (state & ST_PARA_OPEN))
- {
- process_para_end(link_prefix, previous_line_blank, output);
- output_firstcol = TRUE;
- }
- state &= ~(ST_FOOTNOTE_TEXT | ST_PARA_OPEN);
- }
- }
- if (!ANY(state, ST_TABLE | ST_TABLE_HEADER | ST_TABLE_LINE))
- {
- if (!read_yaml_macros_and_links)
- print_output(output, "%s",
- output_firstcol && previous_line_blank ? "" : "\n");
- output_firstcol = TRUE;
- skip_para_end = FALSE;
- state |= ST_PARA_OPEN;
- }
- }
- return 0;
+ if (state & ST_FOOTNOTE_TEXT)
+ {
+ if (!read_yaml_macros_and_links
+ && (state & ST_PARA_OPEN))
+ {
+ process_para_end(output, link_prefix,
+ previous_line_blank);
+ output_firstcol = TRUE;
+ }
+ state &= ~(ST_FOOTNOTE_TEXT | ST_PARA_OPEN);
+ }
+ }
+ if (!ANY(state, ST_TABLE | ST_TABLE_HEADER | ST_TABLE_LINE))
+ {
+ if (!read_yaml_macros_and_links)
+ print_output(output, "%s",
+ output_firstcol && previous_line_blank
+ ? ""
+ : "\n");
+ output_firstcol = TRUE;
+ skip_para_end = FALSE;
+ state |= ST_PARA_OPEN;
+ }
+ }
+ return 0;
}
int
-process_text_token(u8* line, const u8* link_prefix,
- BOOL first_line_in_doc, BOOL previous_line_blank,
- BOOL processed_start_of_line, BOOL skip_eol,
- BOOL read_yaml_macros_and_links, BOOL list_para, FILE* output,
- u8** token, u8** ptoken, size_t* token_size,
- BOOL add_enclosing_paragraph)
+process_text_token(FILE* output, const u8* line, const u8* link_prefix,
+ const BOOL first_line_in_doc, const BOOL previous_line_blank,
+ const BOOL processed_start_of_line,
+ const BOOL read_yaml_macros_and_links, const BOOL list_para, u8** token,
+ u8** ptoken, size_t* token_size, const BOOL add_enclosing_paragraph)
{
- if (!(state & ST_YAML))
- {
- if (add_enclosing_paragraph && !processed_start_of_line)
- process_line_start(line, link_prefix, first_line_in_doc,
- previous_line_blank, read_yaml_macros_and_links, skip_eol,
- list_para, output, token, ptoken);
- **ptoken = 0;
- if (**token && !read_yaml_macros_and_links
- && !(state & ST_MACRO_BODY))
- {
- print_output(output, "%s", *token);
- u8* eol = (u8*)strrchr((char*)*token, '\n');
- if (eol)
- output_firstcol = *token + strlen((char*)*token) - eol > 0;
- else
- output_firstcol = FALSE;
- }
- }
- RESET_TOKEN(*token, *ptoken, *token_size);
- return 0;
+ if (!IN(state, ST_YAML))
+ {
+ if (add_enclosing_paragraph && !processed_start_of_line)
+ process_line_start(output, line, link_prefix,
+ first_line_in_doc, previous_line_blank,
+ read_yaml_macros_and_links, list_para, token,
+ ptoken);
+ **ptoken = 0;
+ if (**token && !read_yaml_macros_and_links
+ && !IN(state, ST_MACRO_BODY))
+ {
+ print_output(output, "%s", *token);
+ u8* eol = (u8*)strrchr((char*)*token, '\n');
+ if (eol)
+ output_firstcol
+ = *token + strlen((char*)*token) - eol
+ > 0;
+ else
+ output_firstcol = FALSE;
+ }
+ }
+ RESET_TOKEN(*token, *ptoken, *token_size);
+ return 0;
}
int
-process_inline_footnote(u8* token, BOOL read_yaml_macros_and_links,
- FILE* output)
+process_inline_footnote(u8* token, BOOL read_yaml_macros_and_links, FILE* output)
{
- current_inline_footnote++;
-
- if (read_yaml_macros_and_links)
- {
- size_t token_len = strlen((char*)token);
-
- inline_footnote_count++;
- if (inline_footnote_count == 1 && footnote_count > 0)
- warning(1, (u8*)"Both inline and regular footnotes present");
- else if (!inline_footnotes)
- {
- inline_footnote_count = 1;
- CALLOC(inline_footnotes, u8*, inline_footnote_count);
- }
- else
- REALLOC(inline_footnotes, u8*, sizeof(u8*) * inline_footnote_count);
- CALLOC(inline_footnotes[inline_footnote_count-1], u8, token_len+1);
-
- strncpy((char*)inline_footnotes[inline_footnote_count-1], (char*)token,
- token_len);
- *(inline_footnotes[inline_footnote_count-1] + token_len) = 0;
- }
- else
- {
- print_output(output, "(%d)", current_inline_footnote);
- output_firstcol = FALSE;
- }
-
- return 0;
+ current_inline_footnote++;
+
+ if (read_yaml_macros_and_links)
+ {
+ size_t token_len = strlen((char*)token);
+
+ inline_footnote_count++;
+ if (inline_footnote_count == 1 && footnote_count > 0)
+ warning(1, (u8*)"Both inline and regular footnotes present");
+ else if (!inline_footnotes)
+ {
+ inline_footnote_count = 1;
+ CALLOC(inline_footnotes, u8*, inline_footnote_count);
+ }
+ else
+ REALLOC(inline_footnotes, u8*,
+ sizeof(u8*) * inline_footnote_count);
+ CALLOC(inline_footnotes[inline_footnote_count - 1], u8,
+ token_len + 1);
+
+ strncpy((char*)inline_footnotes[inline_footnote_count - 1],
+ (char*)token, token_len);
+ *(inline_footnotes[inline_footnote_count - 1] + token_len) = 0;
+ }
+ else
+ {
+ print_output(output, "(%d)", current_inline_footnote);
+ output_firstcol = FALSE;
+ }
+
+ return 0;
}
int
-process_footnote(u8* token, BOOL footnote_definition, BOOL footnote_output,
- FILE* output)
+process_footnote(FILE* output, const u8* token, const BOOL footnote_definition,
+ const BOOL footnote_output)
{
- current_footnote++;
-
- if (footnote_definition)
- {
- footnote_count++;
- if (footnote_count == 1 && inline_footnote_count > 0)
- warning(1, (u8*)"Both inline and regular footnotes present");
- else if (!footnotes)
- {
- CALLOC(footnotes, KeyValue, footnote_count);
- pfootnotes = footnotes;
- }
- else
- {
- REALLOCARRAY(footnotes, KeyValue, footnote_count);
- pfootnotes = footnotes + footnote_count - 1;
- }
- CALLOC(pfootnotes->key, u8, KEYSIZE);
- strncpy((char*)pfootnotes->key, (char*)token, KEYSIZE-1);
- pfootnotes->value = NULL;
- pfootnotes->value_size = 0;
- }
-
- if (footnote_output)
- {
- print_output(output, "(%d)", current_footnote);
- output_firstcol = FALSE;
- }
-
- return 0;
+ current_footnote++;
+
+ if (footnote_definition)
+ {
+ footnote_count++;
+ if (footnote_count == 1 && inline_footnote_count > 0)
+ warning(1, (u8*)"Both inline and regular footnotes present");
+ else if (!footnotes)
+ {
+ CALLOC(footnotes, KeyValue, footnote_count);
+ pfootnotes = footnotes;
+ }
+ else
+ {
+ REALLOCARRAY(footnotes, KeyValue, footnote_count);
+ pfootnotes = footnotes + footnote_count - 1;
+ }
+ CALLOC(pfootnotes->key, u8, KEYSIZE);
+ strncpy((char*)pfootnotes->key, (char*)token, KEYSIZE - 1);
+ pfootnotes->value = NULL;
+ pfootnotes->value_size = 0;
+ }
+
+ if (footnote_output)
+ {
+ print_output(output, "(%d)", current_footnote);
+ output_firstcol = FALSE;
+ }
+
+ return 0;
}
int
-process_horizontal_rule(const u8* link_prefix, BOOL previous_line_blank,
- FILE* output)
+process_horizontal_rule(const u8* link_prefix, BOOL previous_line_blank,
+ FILE* output)
{
- /* Temporarily break paragraph as hr is para-level */
- if (state & ST_PARA_OPEN)
- process_para_end(link_prefix, previous_line_blank, output);
- print_output(output, "————————————————————\n");
- if (state & ST_PARA_OPEN)
- print_output(output, "\n");
- return 0;
+ /* Temporarily break paragraph as hr is para-level */
+ if (state & ST_PARA_OPEN)
+ process_para_end(output, link_prefix, previous_line_blank);
+ print_output(output, "————————————————————\n");
+ if (state & ST_PARA_OPEN)
+ print_output(output, "\n");
+ return 0;
}
int
process_formula(FILE* output, const u8* token, BOOL display_formula)
{
- return 0;
+ return 0;
}
int
-begin_article(FILE* output, const BOOL add_article_header,
- const u8* author, const u8* title,
- const u8* header_text, const char* title_heading_level,
- u8* date, const BOOL ext_in_permalink, BOOL first_line_in_doc,
- BOOL* previous_line_blank, const char* permalink_url)
+begin_article(FILE* output, const BOOL add_article_header, const u8* author,
+ const u8* title, const u8* header_text, const char* title_heading_level,
+ u8* date, const BOOL ext_in_permalink, BOOL first_line_in_doc,
+ BOOL* previous_line_blank, const char* permalink_url)
{
- if (title)
- {
- process_heading_start(output, 1, first_line_in_doc,
- *previous_line_blank);
- process_heading(title, output);
- }
+ if (title)
+ {
+ process_heading_start(output, 1, first_line_in_doc,
+ *previous_line_blank);
+ process_heading(output, title);
+ }
- if (header_text)
- print_output(output, "%s\n\n", (char*)header_text);
+ if (header_text)
+ print_output(output, "%s\n\n", (char*)header_text);
- if (author)
- print_output(output, "%s\n\n", author);
+ if (author)
+ print_output(output, "%s\n\n", author);
- if (date && input_filename)
- {
- char* link = strip_ext(input_filename);
- char* real_link = NULL;
- CALLOC(real_link, char, BUFSIZE);
+ if (date && input_filename)
+ {
+ char* link = strip_ext(input_filename);
+ char* real_link = NULL;
+ CALLOC(real_link, char, BUFSIZE);
- if (ext_in_permalink)
- strncat(link, timestamp_output_ext, BUFSIZE-strlen(link)-1);
+ if (ext_in_permalink)
+ strncat(link, timestamp_output_ext,
+ BUFSIZE - strlen(link) - 1);
- free(real_link);
- free(link);
- }
+ free(real_link);
+ free(link);
+ }
- output_firstcol = author || date || header_text || title;
- *previous_line_blank = author || header_text || title ;
+ output_firstcol = author || date || header_text || title;
+ *previous_line_blank = author || header_text || title;
- return 0;
+ return 0;
}
int
end_footnotes(FILE* output, const u8* link_prefix, BOOL add_footnote_div,
- BOOL previous_line_blank)
+ BOOL previous_line_blank)
{
- size_t footnote = 0;
-
- if (state & ST_PARA_OPEN)
- {
- output_firstcol = TRUE;
- state &= ~ST_PARA_OPEN;
- if (paralinks_count > 0)
- process_paralinks(link_prefix, output);
- }
-
- process_horizontal_rule(link_prefix, previous_line_blank, output);
- output_firstcol = TRUE;
-
- for (footnote = 0; footnote < inline_footnote_count; footnote++)
- {
- print_output(output, "%d. %s\n\n", footnote+1,
- (char*)inline_footnotes[footnote]);
- output_firstcol = TRUE;
- }
-
- KeyValue* pfootnote = footnotes;
- footnote = 0;
- while (pfootnote && footnote < footnote_count)
- {
- print_output(output, "%d. %s\n\n", footnote+1, (char*)pfootnote->value);
- output_firstcol = TRUE;
- pfootnote++;
- footnote++;
- }
-
- return 0;
+ size_t footnote = 0;
+
+ if (state & ST_PARA_OPEN)
+ {
+ output_firstcol = TRUE;
+ state &= ~ST_PARA_OPEN;
+ if (paralinks_count > 0)
+ process_paralinks(output, link_prefix);
+ }
+
+ process_horizontal_rule(link_prefix, previous_line_blank, output);
+ output_firstcol = TRUE;
+
+ for (footnote = 0; footnote < inline_footnote_count; footnote++)
+ {
+ print_output(output, "%d. %s\n\n", footnote + 1,
+ (char*)inline_footnotes[footnote]);
+ output_firstcol = TRUE;
+ }
+
+ KeyValue* pfootnote = footnotes;
+ footnote = 0;
+ while (pfootnote && footnote < footnote_count)
+ {
+ print_output(output, "%d. %s\n\n", footnote + 1,
+ (char*)pfootnote->value);
+ output_firstcol = TRUE;
+ pfootnote++;
+ footnote++;
+ }
+
+ return 0;
}
int
-slweb_parse(u8* buffer, FILE* output, BOOL read_yaml_macros_and_links)
+slweb_parse(FILE* output, const char* source_filename, const u8* buffer,
+ const BOOL read_yaml_macros_and_links)
{
- u8* title = NULL;
- u8* title_heading_level = NULL;
- u8* header_text = NULL;
- u8* author = NULL;
- u8* date = NULL;
- u8* permalink_url = NULL;
- u8* ext_in_permalink = NULL;
- u8* var_add_article_header = NULL;
- u8* var_add_image_links = NULL;
- u8* var_add_figcaption = NULL;
- u8* var_add_footnote_div = NULL;
- u8* link_prefix = NULL;
- u8* pbuffer = NULL;
- u8* line = NULL;
- u8* pline = NULL;
- size_t line_len = 0;
- u8* token = NULL;
- u8* ptoken = NULL;
- size_t token_size = 0;
- u8* link_text = NULL;
- size_t link_size = 0;
- u8* link_macro = NULL;
- UBYTE heading_level = 0;
- BOOL end_tag = FALSE;
- BOOL first_line_in_doc = TRUE;
- BOOL skip_change_first_line_in_doc = FALSE;
- BOOL skip_eol = FALSE;
- BOOL keep_token = FALSE;
- BOOL previous_line_blank = FALSE;
- BOOL processed_start_of_line = FALSE;
- BOOL add_image_links = TRUE;
- BOOL add_figcaption = TRUE;
- BOOL add_footnote_div = FALSE;
- BOOL list_para = FALSE;
- BOOL footnote_at_line_start = FALSE;
- size_t pline_len = 0;
-
- if (!buffer)
- exit(error(1, (u8*)"Empty buffer"));
-
- title = get_value(vars, vars_count, (u8*)"title", NULL);
- title_heading_level = get_value(vars, vars_count,
- (u8*)"title-heading-level", NULL);
- header_text = get_value(vars, vars_count, (u8*)"header-text", NULL);
- author = get_value(vars, vars_count, (u8*)"author", NULL);
- date = get_value(vars, vars_count, (u8*)"date", NULL);
- permalink_url = get_value(vars, vars_count, (u8*)"permalink-url", NULL);
- ext_in_permalink = get_value(vars, vars_count, (u8*)"ext-in-permalink", NULL);
- var_add_article_header = get_value(vars, vars_count, (u8*)"add-article-header", NULL);
- var_add_image_links = get_value(vars, vars_count, (u8*)"add-image-links", NULL);
- add_image_links = !(var_add_image_links && *var_add_image_links == '0');
- var_add_figcaption = get_value(vars, vars_count, (u8*)"add-figcaption", NULL);
- add_figcaption = !(var_add_figcaption && *var_add_figcaption == '0');
- var_add_footnote_div = get_value(vars, vars_count, (u8*)"add-footnote-div", NULL);
- add_footnote_div = var_add_footnote_div && *var_add_footnote_div == '1';
- link_prefix = get_value(vars, vars_count, (u8*)"link-prefix", NULL);
-
- CALLOC(line, u8, BUFSIZE);
- token_size = BUFSIZE;
- CALLOC(token, u8, BUFSIZE);
- CALLOC(link_macro, u8, BUFSIZE);
-
- pbuffer = buffer;
- pvars = vars;
- pmacros = macros;
- plinks = links;
- pparalinks = paralinks;
- pfootnotes = footnotes;
- lineno = 0;
-
- if (!read_yaml_macros_and_links)
- begin_article(output,
- var_add_article_header && *var_add_article_header == '1',
- author, title, header_text, (char*)title_heading_level, date,
- ext_in_permalink && *ext_in_permalink != '0',
- first_line_in_doc, &previous_line_blank, (char*)permalink_url);
-
- RESET_TOKEN(token, ptoken, token_size);
-
- do
- {
- u8* eol = (u8*)strchr((char*)pbuffer, '\n');
- if (!eol)
- break;
-
- pline = line;
- while (pbuffer != eol)
- *pline++ = *pbuffer++;
- pbuffer++;
- *pline = 0;
- pline = line;
- line_len = strlen((char*)line);
-
- lineno++;
- colno = 1;
- output_firstcol = TRUE;
- processed_start_of_line = FALSE;
- skip_eol = FALSE;
- /*list_item = FALSE;*/
- list_para = FALSE;
-
- while (pline && *pline)
- {
- switch (*pline)
- {
- case '-':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_MACRO_BODY | ST_PRE | ST_YAML_VAL))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
- else if (colno == 1
- && strlen((char*)pline) > 2
- && startswith((char*)pline, "---"))
- {
- skip_eol = TRUE;
-
- if (!(state & ST_YAML) && lineno > 1
- && !read_yaml_macros_and_links)
- {
- process_horizontal_rule(link_prefix, previous_line_blank,
- output);
- output_firstcol = TRUE;
- }
- else
- {
- if (lineno == 1)
- state |= ST_YAML;
- else
- state &= ~ST_YAML;
-
- skip_change_first_line_in_doc = TRUE;
- }
- pline = NULL;
- }
- else if (colno == 1
- && strlen((char*)pline) > 1
- && *(pline+1) == ' ')
- {
- if (state & ST_NUMLIST)
- {
- state &= ~ST_NUMLIST;
- if (!read_yaml_macros_and_links)
- {
- process_list_item_end(link_prefix, output);
- process_numlist_end(output);
- }
- }
- if (!read_yaml_macros_and_links)
- {
- if (!(state & ST_LIST))
- process_list_start(output);
- else
- process_list_item_end(link_prefix, output);
- process_list_item_start(output);
- }
-
- processed_start_of_line = TRUE;
- skip_eol = FALSE;
-
- state |= ST_LIST;
-
- pline += 2;
- colno += 2;
- }
- else
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- break;
-
- case ':':
- if (state & ST_YAML
- && !(ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_HEADING | ST_IMAGE | ST_MACRO_BODY
- | ST_PRE | ST_TAG | ST_YAML_VAL))
- && read_yaml_macros_and_links)
- {
- *ptoken = 0;
-
- 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);
- strncpy((char*)pvars->key, (char*)token, KEYSIZE-1);
- pvars->value = NULL;
- pvars->value_size = 0;
-
- state |= ST_YAML_VAL;
- RESET_TOKEN(token, ptoken, token_size);
- pline++;
- colno++;
-
- while (pline && (*pline == ' ' || *pline == '\t'))
- {
- pline++;
- colno++;
- }
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
- else {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- break;
-
- case '~':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_HTML_TAG | ST_IMAGE | ST_LINK_SECOND_ARG
- | ST_LINK_SECOND_ARG_END | ST_MACRO_BODY
- | ST_PRE | ST_TAG | ST_YAML))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
-
- if (strlen((char*)pline) > 1 && *(pline+1) == '~')
- {
- /* Handle ~~ within footnotes, headings and link text specially */
- if (ANY(state, ST_INLINE_FOOTNOTE | ST_HEADING
- | ST_FOOTNOTE_TEXT | ST_LINK))
- {
- u8* entity = (u8*)" ";
- size_t entity_len = strlen((char*)entity);
- size_t token_len = 0;
-
- *ptoken = 0;
- token_len = strlen((char*)token);
-
- if (token_len + entity_len < BUFSIZE)
- {
- strncat((char*)token, (char*)entity,
- BUFSIZE-token_len-1);
- ptoken += entity_len;
- }
- }
- else
- {
- /* Output existing text up to ~~ */
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links, list_para,
- output, &token, &ptoken, &token_size, TRUE);
- processed_start_of_line = TRUE;
-
- if (!read_yaml_macros_and_links
- && !(ANY(state, ST_PRE | ST_CODE | ST_HEADING)))
- print_output(output, " ");
- }
-
- pline += 2;
- colno += 2;
- }
- else
- {
- /* Handle ~ within footnotes, headings and link text specially */
- if (ANY(state, ST_INLINE_FOOTNOTE | ST_HEADING
- | ST_FOOTNOTE_TEXT | ST_LINK))
- {
- u8* tag = state & ST_STRIKE
- ? (u8*)"~"
- : (u8*)"~";
- size_t tag_len = strlen((char*)tag);
- size_t token_len = 0;
-
- *ptoken = 0;
- token_len = strlen((char*)token);
-
- if (token_len + tag_len < BUFSIZE)
- {
- strncat((char*)token, (char*)tag,
- BUFSIZE-token_len-1);
- ptoken += tag_len;
- }
- }
- else
- {
- /* Output existing text up to ~ */
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links, list_para,
- output, &token, &ptoken, &token_size, TRUE);
- processed_start_of_line = TRUE;
-
- if (!read_yaml_macros_and_links
- && !(ANY(state, ST_PRE | ST_CODE | ST_HEADING)))
- process_strike(output, state & ST_STRIKE);
- }
-
- state ^= ST_STRIKE;
- pline++;
- colno++;
- }
- break;
-
- case '`':
- if (ANY(state, ST_DISPLAY_FORMULA | ST_FORMULA | ST_IMAGE
- | ST_MACRO_BODY))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- if (colno == 1
- && strlen((char*)pline) > 2
- && startswith((char*)pline, "```"))
- {
- state ^= ST_PRE;
-
- if (!read_yaml_macros_and_links)
- {
- print_output(output, "```%s", (state & ST_PRE) ? "" : "\n\n");
- output_firstcol = TRUE;
- output_firstcol = !(state & ST_PRE);
- }
-
- /* Skip the rest of the line (language) */
- pline = NULL;
- }
- else if (!ANY(state, ST_PRE | ST_TAG | ST_YAML))
- {
- if (!ANY(state, ST_INLINE_FOOTNOTE | ST_HEADING
- | ST_FOOTNOTE_TEXT | ST_LINK))
- {
- /* Output existing text up to ` */
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- processed_start_of_line = TRUE;
- }
-
- state ^= ST_CODE;
-
- pline++;
- colno++;
- }
- else
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- break;
-
- case '#':
- if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
- if (colno == 1
- && !(ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_MACRO_BODY | ST_PRE | ST_YAML)))
- {
- if (state & ST_LIST)
- {
- state &= ~ST_LIST;
- if (!read_yaml_macros_and_links)
- {
- process_list_item_end(link_prefix, output);
- process_list_end(output);
- }
- }
-
- if (state & ST_NUMLIST)
- {
- state &= ~ST_NUMLIST;
- if (!read_yaml_macros_and_links)
- {
- process_list_item_end(link_prefix, output);
- process_numlist_end(output);
- }
- }
-
- state |= ST_HEADING;
- heading_level = 1;
- pline++;
- colno++;
- }
- else if (state & ST_HEADING && *(pline-1) == '#')
- {
- if (heading_level < MAX_HEADING_LEVEL)
- heading_level++;
- pline++;
- colno++;
- }
- else
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- break;
-
- case '_':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- /*| ST_HTML_TAG */| ST_IMAGE | ST_LINK_SECOND_ARG
- | ST_LINK_SECOND_ARG_END | ST_MACRO_BODY | ST_PRE
- | ST_TAG | ST_YAML))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- if (strlen((char*)pline) > 1 && *(pline+1) == '_')
- {
- /* Handle __ within footnotes, headings and link text specially */
- if (!ANY(state, ST_INLINE_FOOTNOTE | ST_HEADING
- | ST_FOOTNOTE_TEXT | ST_LINK))
- {
- /* Output existing text up to __ */
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- processed_start_of_line = TRUE;
-
- if (!read_yaml_macros_and_links
- && !(ANY(state, ST_PRE | ST_CODE | ST_HEADING)))
- process_bold(output, state & ST_BOLD);
- }
-
- state ^= ST_BOLD;
- pline += 2;
- colno += 2;
- }
- else
- {
- /* Handle _ within footnotes, headings and link text specially */
- if (!ANY(state, ST_INLINE_FOOTNOTE | ST_HEADING
- | ST_FOOTNOTE_TEXT | ST_LINK))
- {
- /* Output existing text up to _ */
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- processed_start_of_line = TRUE;
-
- if (!read_yaml_macros_and_links
- && !(ANY(state, ST_PRE | ST_CODE | ST_HEADING)))
- process_italic(output, state & ST_ITALIC);
- }
-
- state ^= ST_ITALIC;
- pline++;
- colno++;
- }
- break;
-
- case 'o':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- /*| ST_HTML_TAG */| ST_IMAGE | ST_MACRO_BODY | ST_PRE
- | ST_YAML))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- if (colno == 1
- && strlen((char*)pline) > 1
- && *(pline+1) == ' ')
- {
- if (state & ST_NUMLIST)
- {
- state &= ~ST_NUMLIST;
- if (!read_yaml_macros_and_links)
- {
- process_list_item_end(link_prefix, output);
- process_numlist_end(output);
- }
- }
- if (!read_yaml_macros_and_links)
- {
- if (!(state & ST_LIST))
- process_list_start(output);
- else
- process_list_item_end(link_prefix, output);
- process_list_item_start(output);
- }
-
- processed_start_of_line = TRUE;
- skip_eol = FALSE;
-
- state |= ST_LIST;
-
- pline += 2;
- colno += 2;
- }
- else
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- break;
-
- case '*':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- /*| ST_HTML_TAG */| ST_IMAGE | ST_MACRO_BODY | ST_PRE
- | ST_YAML))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- pline_len = strlen((char*)pline);
- if (colno == 1
- && pline_len > 1 && *(pline+1) == '[')
- {
- process_line_start(line, link_prefix, first_line_in_doc,
- previous_line_blank, read_yaml_macros_and_links,
- skip_eol, list_para, output, &token, &ptoken);
-
- /* Ignore abbreviations (for now) */
- pline = NULL;
- }
- else if (colno == 1
- && pline_len > 2 && startswith((char*)pline, "***"))
- {
- skip_eol = TRUE;
- if (!read_yaml_macros_and_links)
- {
- process_horizontal_rule(link_prefix, previous_line_blank,
- output);
- output_firstcol = TRUE;
- }
- pline = NULL;
- }
- else if (colno == 1
- && strlen((char*)pline) > 1
- && *(pline+1) == ' ')
- {
- if (state & ST_NUMLIST)
- {
- state &= ~ST_NUMLIST;
- if (!read_yaml_macros_and_links)
- {
- process_list_item_end(link_prefix, output);
- process_numlist_end(output);
- }
- }
- if (!read_yaml_macros_and_links)
- {
- if (!(state & ST_LIST))
- process_list_start(output);
- else
- process_list_item_end(link_prefix, output);
- process_list_item_start(output);
- }
-
- processed_start_of_line = TRUE;
- skip_eol = FALSE;
-
- state |= ST_LIST;
-
- pline += 2;
- colno += 2;
- }
- else if (pline_len > 1 && *(pline+1) == '*')
- {
- /* Handle ** within footnotes, headings and link text specially */
- if (!ANY(state, ST_INLINE_FOOTNOTE | ST_HEADING
- | ST_FOOTNOTE_TEXT | ST_LINK))
- {
- /* Output existing text up to * */
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- processed_start_of_line = TRUE;
-
- if (!read_yaml_macros_and_links
- && !(ANY(state, ST_PRE | ST_CODE | ST_HEADING)))
- process_bold(output, state & ST_BOLD);
- }
-
- state ^= ST_BOLD;
- pline += 2;
- colno += 2;
- }
- else
- {
- /* Handle * within footnotes, headings and link text specially */
- if (!ANY(state, ST_INLINE_FOOTNOTE | ST_HEADING
- | ST_FOOTNOTE_TEXT | ST_LINK))
-
- {
- /* Output existing text up to * */
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- processed_start_of_line = TRUE;
-
- if (!read_yaml_macros_and_links
- && !(ANY(state, ST_PRE | ST_CODE | ST_HEADING)))
- process_italic(output, state & ST_ITALIC);
- }
-
- state ^= ST_ITALIC;
- pline++;
- colno++;
- }
- break;
-
- case ' ':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_IMAGE | ST_MACRO_BODY | ST_PRE | ST_YAML_VAL))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
-
- if ((state & ST_HEADING) && !(state & ST_HEADING_TEXT))
- {
- if (!read_yaml_macros_and_links)
- process_heading_start(output, heading_level,
- first_line_in_doc, previous_line_blank);
- state |= ST_HEADING_TEXT;
- pline++;
- colno++;
- break;
- }
-
- if (colno == 1
- && strlen((char*)pline) > 1
- && startswith((char*)pline, " "))
- {
- list_para = TRUE;
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- processed_start_of_line = TRUE;
- while (*pline == ' ' || *pline == '\t')
- {
- pline++;
- colno++;
- }
- break;
- }
-
- if (strlen((char*)pline) == 2
- && *(pline+1) == ' ')
- {
- *ptoken = 0;
- strncat((char*)ptoken, "\n",
- BUFSIZE-strlen((char*)token)-1);
- ptoken += strlen("\n");
- output_firstcol = TRUE;
- pline++;
- colno++;
- }
- else if (state & ST_LINK_MACRO)
- {
- *ptoken = 0;
- strncpy((char*)link_macro, (char*)token, BUFSIZE-1);
- *(link_macro + strlen((char*)token)) = 0;
- RESET_TOKEN(token, ptoken, token_size);
- state &= ~ST_LINK_MACRO;
- }
- else if (!(state & ST_HEADING
- && *(pline-1) == '#'))
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
-
- case '{':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- /*| ST_HTML_TAG*/ | ST_PRE | ST_YAML | ST_YAML_VAL))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- if (state & ST_MACRO_BODY)
- {
- *ptoken = 0;
- size_t token_len = strlen((char*)token);
-
- skip_eol = TRUE;
- if (read_yaml_macros_and_links)
- {
- if (!macros)
- {
- macros_count = 1;
- CALLOC(macros, KeyValue, macros_count);
- pmacros = macros;
- }
- if (pmacros->value)
- {
- size_t value_len = strlen((char*)pmacros->value);
-
- if (pmacros->value_size < value_len + token_len + 1)
- {
- pmacros->value_size += token_len;
- REALLOC(pmacros->value, u8, pmacros->value_size);
- }
- strncat((char*)pmacros->value, (char*)token,
- pmacros->value_size-1);
- }
- else
- {
- pmacros->value_size = token_len+1;
- CALLOC(pmacros->value, u8, pmacros->value_size);
- strncpy((char*)pmacros->value, (char*)token,
- pmacros->value_size-1);
- }
- }
- }
- else
- {
- /* Output existing text up to { */
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- processed_start_of_line = TRUE;
- }
-
- state |= ST_TAG;
- RESET_TOKEN(token, ptoken, token_size);
-
- pline++;
- colno++;
- break;
-
- case '/':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_IMAGE | ST_PRE | ST_HEADING | ST_YAML_VAL))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- if ((state & ST_TAG) && pline-1 && *(pline-1) == '{')
- {
- end_tag = TRUE;
- pline++;
- }
- else
- CHECKCOPY(token, ptoken, token_size, pline);
-
- colno++;
- break;
-
- case '}':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_IMAGE | ST_PRE | ST_YAML | ST_YAML_VAL))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
-
- if (state & ST_TAG)
- {
- state &= ~ST_TAG;
- *ptoken = 0;
-
- process_tag(token, link_prefix, output, previous_line_blank,
- read_yaml_macros_and_links, &skip_eol, end_tag);
-
- RESET_TOKEN(token, ptoken, token_size);
- end_tag = FALSE;
- }
-
- pline++;
- colno++;
- break;
-
- case '|':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- /*| ST_HTML_TAG*/ | ST_IMAGE | ST_PRE | ST_TAG
- | ST_YAML))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- if (strlen((char*)pline) > 1 && *(pline+1) == '|')
- {
- if (!ANY(state, ST_INLINE_FOOTNOTE | ST_HEADING
- | ST_FOOTNOTE_TEXT | ST_LINK))
- {
- /* Output existing text up to || */
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- processed_start_of_line = TRUE;
- }
-
- state ^= ST_KBD;
-
- pline += 2;
- colno += 2;
- }
- /* Partial tables (for templating) */
- else if (!(state & ST_PRE) && colno == 1
- && strlen((char*)pline) > 1
- && *(pline+1) == '@')
- {
- skip_eol = TRUE;
-
- pline += 2;
- colno += 2;
-
- switch (*pline)
- {
- case '\\':
- if (!read_yaml_macros_and_links)
- process_table_start(output);
- pline = NULL;
- break;
-
- case '#':
- state |= ST_TABLE_HEADER;
- pline++;
- colno++;
- break;
-
- case '-':
- state &= ~ST_TABLE_HEADER;
- if (!read_yaml_macros_and_links)
- process_table_body_start(output, FALSE);
- pline = NULL;
- break;
-
- case ' ':
- state |= ST_TABLE;
- if (!read_yaml_macros_and_links)
- process_table_body_row_start(output);
- break;
-
- case '/':
- state &= ~ST_TABLE;
- process_table_end(output);
- pline = NULL;
- break;
-
- default:
- warning(1, (u8*)"Invalid partial table line");
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- }
- else if (!(state & ST_PRE) && colno == 1)
- {
- skip_eol = TRUE;
-
- if (state & ST_TABLE_HEADER)
- {
- state &= ~ST_TABLE_HEADER;
- state |= ST_TABLE_LINE;
- pline = NULL;
- break;
- }
-
- if (state & ST_TABLE_LINE)
- {
- state &= ~ST_TABLE_LINE;
- state |= ST_TABLE;
- if (!read_yaml_macros_and_links)
- process_table_body_start(output, TRUE);
- }
- else if (state & ST_TABLE)
- {
- if (!read_yaml_macros_and_links)
- process_table_body_row_start(output);
- }
- else
- {
- state |= ST_TABLE_HEADER;
- if (!read_yaml_macros_and_links)
- process_table_start(output);
- }
-
- pline++;
- colno++;
- }
- else if (state & ST_TABLE_HEADER)
- {
- *ptoken = 0;
- if (!read_yaml_macros_and_links)
- {
- print_output(output, "%s", token);
- if (*token)
- output_firstcol = FALSE;
- if (strlen((char*)pline) > 1)
- process_table_header_cell(output);
- else
- process_table_header_end(output);
- }
- RESET_TOKEN(token, ptoken, token_size);
- pline++;
- colno++;
- }
- else if (state & ST_TABLE)
- {
- *ptoken = 0;
- if (!read_yaml_macros_and_links)
- {
- print_output(output, "%s", token);
- if (*token)
- output_firstcol = FALSE;
- if (strlen((char*)pline) > 1)
- process_table_body_cell(output);
- else
- process_table_body_row_end(output);
- }
- RESET_TOKEN(token, ptoken, token_size);
- pline++;
- colno++;
- }
- else
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- break;
-
- case '<':
- if (read_yaml_macros_and_links
- || ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_IMAGE | ST_PRE))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
-
- state |= ST_HTML_TAG;
- pline++;
- colno++;
- break;
-
- case '>':
- if (state & ST_HTML_TAG)
- {
- state &= ~ST_HTML_TAG;
- pline++;
- colno++;
- break;
- }
-
- if (ANY(state, ST_DISPLAY_FORMULA | ST_FORMULA | ST_IMAGE
- | ST_MACRO_BODY))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
-
- if (!read_yaml_macros_and_links
- && !ANY(state, ST_CODE | ST_HEADING | ST_PRE)
- && colno == 1)
- {
- if (!read_yaml_macros_and_links
- && !(state & ST_BLOCKQUOTE))
- {
- process_blockquote(output, FALSE);
- output_firstcol = FALSE;
- }
-
- state |= ST_BLOCKQUOTE;
-
- pline++;
- colno++;
- }
- else
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- break;
-
- case '!':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_FOOTNOTE_TEXT | ST_HEADING | ST_IMAGE
- | ST_INLINE_FOOTNOTE | ST_LINK | ST_MACRO_BODY
- | ST_PRE))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- if (strlen((char*)pline) > 1 && *(pline+1) == '[')
- {
- /* Output existing text up to ! */
- *ptoken = 0;
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- processed_start_of_line = TRUE;
-
- RESET_TOKEN(token, ptoken, token_size);
-
- state |= ST_IMAGE;
- keep_token = TRUE;
- pline += 2;
- colno += 2;
- }
- else
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
-
- break;
-
- case '=':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_MACRO_BODY | ST_PRE | ST_TAG))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- if (colno != 1 && *(pline-1) == '[')
- {
- state |= ST_LINK_MACRO;
- pline++;
- colno++;
- }
- else
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- break;
-
- case '[':
- pline_len = strlen((char*)pline);
-
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_HEADING | ST_IMAGE | ST_MACRO_BODY | ST_PRE))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- if (state & ST_FOOTNOTE_TEXT)
- {
- if (!read_yaml_macros_and_links && (state & ST_PARA_OPEN))
- {
- process_para_end(link_prefix, previous_line_blank, output);
- output_firstcol = TRUE;
- }
- state &= ~(ST_FOOTNOTE_TEXT | ST_PARA_OPEN);
- }
-
- if (pline_len > 1 && *(pline+1) == '^')
- {
- footnote_at_line_start = colno == 1;
- if (*token)
- {
- /* Output existing text up to [^ */
- *ptoken = 0;
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- }
- processed_start_of_line = TRUE;
-
- RESET_TOKEN(token, ptoken, token_size);
- state |= ST_FOOTNOTE;
- pline += 2;
- colno += 2;
- break;
- }
-
- if (*token)
- {
- /* Output existing text up to [ */
- *ptoken = 0;
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- }
- processed_start_of_line = TRUE;
-
- RESET_TOKEN(token, ptoken, token_size);
- state |= ST_LINK;
- keep_token = TRUE;
- *link_macro = 0;
- pline++;
- colno++;
+ u8* title = NULL;
+ u8* title_heading_level = NULL;
+ u8* header_text = NULL;
+ u8* author = NULL;
+ u8* date = NULL;
+ u8* permalink_url = NULL;
+ u8* ext_in_permalink = NULL;
+ u8* var_add_article_header = NULL;
+ u8* var_add_footnote_div = NULL;
+ u8* link_prefix = NULL;
+ const u8* pbuffer = NULL;
+ u8* line = NULL;
+ u8* pline = NULL;
+ size_t line_len = 0;
+ u8* token = NULL;
+ u8* ptoken = NULL;
+ size_t token_size = 0;
+ u8* link_text = NULL;
+ size_t link_size = 0;
+ u8* link_macro = NULL;
+ UBYTE heading_level = 0;
+ BOOL end_tag = FALSE;
+ BOOL first_line_in_doc = TRUE;
+ BOOL skip_change_first_line_in_doc = FALSE;
+ BOOL skip_eol = FALSE;
+ BOOL keep_token = FALSE;
+ BOOL previous_line_blank = FALSE;
+ BOOL processed_start_of_line = FALSE;
+ BOOL add_footnote_div = FALSE;
+ BOOL list_para = FALSE;
+ BOOL footnote_at_line_start = FALSE;
+ size_t pline_len = 0;
+
+ if (!buffer)
+ exit(error(1, (u8*)"Empty buffer"));
+
+ title = get_value(vars, vars_count, (u8*)"title", NULL);
+ title_heading_level
+ = get_value(vars, vars_count, (u8*)"title-heading-level", NULL);
+ header_text = get_value(vars, vars_count, (u8*)"header-text", NULL);
+ author = get_value(vars, vars_count, (u8*)"author", NULL);
+ date = get_value(vars, vars_count, (u8*)"date", NULL);
+ permalink_url = get_value(vars, vars_count, (u8*)"permalink-url", NULL);
+ ext_in_permalink
+ = get_value(vars, vars_count, (u8*)"ext-in-permalink", NULL);
+ var_add_article_header
+ = get_value(vars, vars_count, (u8*)"add-article-header", NULL);
+ var_add_footnote_div
+ = get_value(vars, vars_count, (u8*)"add-footnote-div", NULL);
+ add_footnote_div = var_add_footnote_div && *var_add_footnote_div == '1';
+ link_prefix = get_value(vars, vars_count, (u8*)"link-prefix", NULL);
+
+ CALLOC(line, u8, BUFSIZE);
+ token_size = BUFSIZE;
+ CALLOC(token, u8, BUFSIZE);
+ CALLOC(link_macro, u8, BUFSIZE);
+
+ pbuffer = buffer;
+ pvars = vars;
+ pmacros = macros;
+ plinks = links;
+ pparalinks = paralinks;
+ pfootnotes = footnotes;
+ lineno = 0;
+
+ if (!read_yaml_macros_and_links)
+ begin_article(output,
+ var_add_article_header && *var_add_article_header == '1',
+ author, title, header_text, (char*)title_heading_level,
+ date, ext_in_permalink && *ext_in_permalink != '0',
+ first_line_in_doc, &previous_line_blank,
+ (char*)permalink_url);
+
+ RESET_TOKEN(token, ptoken, token_size);
+
+do_buffer:;
+ u8* eol = (u8*)strchr((char*)pbuffer, '\n');
+ if (!eol)
+ goto done_buffer;
+
+ pline = line;
+ while (pbuffer != eol)
+ *pline++ = *pbuffer++;
+ pbuffer++;
+ *pline = 0;
+ pline = line;
+ line_len = strlen((char*)line);
+
+ lineno++;
+ colno = 1;
+ output_firstcol = TRUE;
+ processed_start_of_line = FALSE;
+ skip_eol = FALSE;
+ list_para = FALSE;
+
+do_line:
+ if (!pline || !*pline)
+ goto done_line;
+ switch (*pline)
+ {
+ case '-':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_MACRO_BODY | ST_PRE | ST_YAML_VAL))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+ else if (colno == 1 && strlen((char*)pline) > 2
+ && startswith((char*)pline, "---"))
+ {
+ skip_eol = TRUE;
- if (*pline == '(')
+ if (!(IN(state, ST_YAML)) && lineno > 1
+ && !read_yaml_macros_and_links)
+ {
+ process_horizontal_rule(link_prefix,
+ previous_line_blank, output);
+ output_firstcol = TRUE;
+ }
+ else
+ {
+ if (lineno == 1)
+ state |= ST_YAML;
+ else
+ state &= ~ST_YAML;
+
+ skip_change_first_line_in_doc = TRUE;
+ }
+ pline = NULL;
+ }
+ else if (colno == 1 && strlen((char*)pline) > 1
+ && *(pline + 1) == ' ')
+ {
+ if (IN(state, ST_NUMLIST))
+ {
+ state &= ~ST_NUMLIST;
+ if (!read_yaml_macros_and_links)
+ {
+ process_list_item_end(output,
+ link_prefix);
+ process_numlist_end(output);
+ }
+ }
+ if (!read_yaml_macros_and_links)
+ {
+ if (!(IN(state, ST_LIST)))
+ process_list_start(output);
+ else
+ process_list_item_end(output,
+ link_prefix);
+ process_list_item_start(output);
+ }
+
+ processed_start_of_line = TRUE;
+ skip_eol = FALSE;
+
+ state |= ST_LIST;
+
+ pline += 2;
+ colno += 2;
+ }
+ else
{
- *ptoken = 0;
- state |= ST_LINK_SPAN;
- pline++;
- colno++;
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
}
+ break;
+
+ case ':':
+ if (IN(state, ST_YAML)
+ && !(ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_HEADING | ST_IMAGE | ST_MACRO_BODY
+ | ST_PRE | ST_TAG | ST_YAML_VAL))
+ && read_yaml_macros_and_links)
+ {
+ *ptoken = 0;
- break;
+ vars_count++;
- case '(':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_FOOTNOTE_TEXT | ST_HEADING
- | ST_INLINE_FOOTNOTE | ST_LINK_SECOND_ARG_END
- | ST_MACRO_BODY | ST_PRE))
- CHECKCOPY(token, ptoken, token_size, pline);
- else if (*link_macro && (state & ST_LINK))
+ 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);
+ strncpy((char*)pvars->key, (char*)token, KEYSIZE - 1);
+ pvars->value = NULL;
+ pvars->value_size = 0;
+
+ state |= ST_YAML_VAL;
+ RESET_TOKEN(token, ptoken, token_size);
+ pline++;
+ colno++;
+
+ while (pline && (*pline == ' ' || *pline == '\t'))
{
-/*
- * u8* tag = (u8*)"<span>";
- * size_t tag_len = strlen(tag);
- * size_t token_len = 0;
- *
- * *ptoken = 0;
- * token_len = strlen(token);
- *
- * if (token_len + tag_len < BUFSIZE)
- * {
- * strncat((char*)token, tag, BUFSIZE-token_len-1);
- * ptoken += tag_len;
- * }
- */
-
- state |= ST_LINK_SPAN;
pline++;
+ colno++;
+ }
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+ else
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+ break;
+
+ case '~':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | 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))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+
+ if (strlen((char*)pline) > 1 && *(pline + 1) == '~')
+ {
+ u8* entity = (u8*)" ";
+ /* Handle ~~ within footnotes, headings
+ * and link text specially */
+ if (ANY(state,
+ ST_INLINE_FOOTNOTE | ST_HEADING
+ | ST_FOOTNOTE_TEXT | ST_LINK))
+ {
+ size_t entity_len = strlen((char*)entity);
+ size_t token_len = 0;
+
+ *ptoken = 0;
+ token_len = strlen((char*)token);
+
+ if (token_len + entity_len < BUFSIZE)
+ {
+ strncat((char*)token, (char*)entity,
+ BUFSIZE - token_len - 1);
+ ptoken += entity_len;
+ }
}
else
- CHECKCOPY(token, ptoken, token_size, pline);
+ {
+ /* Output existing text up to ~~ */
+ 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, TRUE);
+ processed_start_of_line = TRUE;
+
+ if (!read_yaml_macros_and_links
+ && !(ANY(state,
+ ST_PRE | ST_CODE | ST_HEADING)))
+ print_output(output, " ");
+ }
+
+ pline += 2;
+ colno += 2;
+ }
+ else
+ {
+ /* Handle ~ within footnotes, headings
+ * and link text specially */
+ if (ANY(state,
+ ST_INLINE_FOOTNOTE | ST_HEADING
+ | ST_FOOTNOTE_TEXT | ST_LINK))
+ {
+ u8* tag = IN(state, ST_STRIKE) ? (u8*)"</s>"
+ : (u8*)"<s>";
+ size_t tag_len = strlen((char*)tag);
+ size_t token_len = 0;
+
+ *ptoken = 0;
+ token_len = strlen((char*)token);
+
+ if (token_len + tag_len < BUFSIZE)
+ {
+ strncat((char*)token, (char*)tag,
+ BUFSIZE - token_len - 1);
+ ptoken += tag_len;
+ }
+ }
+ else
+ {
+ /* Output existing text up to ~ */
+ 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, TRUE);
+ processed_start_of_line = TRUE;
+
+ if (!read_yaml_macros_and_links
+ && !(ANY(state,
+ ST_PRE | ST_CODE | ST_HEADING)))
+ process_strike(output,
+ (IN(state, ST_STRIKE)));
+ }
+
+ state ^= ST_STRIKE;
+ pline++;
+ colno++;
+ }
+ break;
+
+ case '`':
+ if (ANY(state,
+ ST_DISPLAY_FORMULA | ST_FORMULA | ST_IMAGE
+ | ST_MACRO_BODY))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
colno++;
break;
+ }
- case ')':
- if (ANY(state, ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_LINK_SECOND_ARG_END))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- if (state & ST_LINK_SPAN)
- {
- state &= ~ST_LINK_SPAN;
- pline++;
- }
- else if (ANY(state, ST_LINK_SECOND_ARG | ST_IMAGE_SECOND_ARG))
- {
- *ptoken = 0;
- if (!read_yaml_macros_and_links)
- {
- paralinks_count++;
- if (!paralinks)
- {
- CALLOC(paralinks, KeyValue, paralinks_count);
- pparalinks = paralinks;
- }
- else
- {
- REALLOCARRAY(paralinks, KeyValue, paralinks_count);
- pparalinks = paralinks + paralinks_count - 1;
- }
- pparalinks->key = (u8*)strdup((char*)token);
- pparalinks->value_size = strlen((char*)link_text)+1;
- pparalinks->value = (u8*)strdup((char*)link_text);
-
- if (output_firstcol
- && ((*(line+line_len-1) == ']')
- || *(line+line_len-1) == ')'))
- {
- skip_eol = TRUE;
- skip_para_end = TRUE;
- pline = NULL;
- }
- else
- {
- if (state & ST_LINK_SECOND_ARG)
- process_inline_link(link_text,
- get_value(macros, macros_count,
- link_macro, NULL),
- token, output);
- else
- process_inline_image(link_text, token, output,
- add_image_links, add_figcaption);
- output_firstcol = !*link_text;
- }
- }
- RESET_TOKEN(token, ptoken, token_size);
- state &= ~(ST_LINK | ST_LINK_SECOND_ARG
- | ST_IMAGE | ST_IMAGE_SECOND_ARG);
- if (pline)
- pline++;
- }
- else
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
-
- case ']':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_HEADING | ST_MACRO_BODY | ST_PRE))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- *ptoken = 0;
- if (state & ST_INLINE_FOOTNOTE)
- {
- process_inline_footnote(token, read_yaml_macros_and_links,
- output);
-
- keep_token = FALSE;
- RESET_TOKEN(token, ptoken, token_size);
- state &= ~ST_INLINE_FOOTNOTE;
- pline++;
- colno++;
- }
- else if (state & ST_FOOTNOTE)
- {
- BOOL footnote_definition = (strlen((char*)pline) > 1)
- && (*(pline+1) == ':') && footnote_at_line_start;
-
- process_footnote(token,
- footnote_definition && read_yaml_macros_and_links,
- !footnote_definition && !read_yaml_macros_and_links,
- output);
-
- RESET_TOKEN(token, ptoken, token_size);
- state &= ~ST_FOOTNOTE;
- footnote_at_line_start = FALSE;
- pline++;
- colno++;
- if (footnote_definition)
- {
- pline++;
- colno++;
- while (*pline == ' ' || *pline == '\t')
- {
- pline++;
- colno++;
- }
- state |= ST_FOOTNOTE_TEXT;
- }
- }
- else if (state & ST_LINK_SECOND_ARG)
- {
- if (!read_yaml_macros_and_links)
- {
- u8* url = get_value(links, links_count, token, NULL);
- if (!url)
- exit(error(EINVAL, (u8*)"get_value: Invalid argument"));
- paralinks_count++;
- if (!paralinks)
- {
- CALLOC(paralinks, KeyValue, paralinks_count);
- pparalinks = paralinks;
- }
- else
- {
- REALLOCARRAY(paralinks, KeyValue, paralinks_count);
- pparalinks = paralinks + paralinks_count - 1;
- }
- pparalinks->key = (u8*)strdup((char*)url);
- pparalinks->value_size = strlen((char*)link_text)+1;
- pparalinks->value = (u8*)strdup((char*)link_text);
-
- if (output_firstcol
- && ((*(line+line_len-1) == ']')
- || *(line+line_len-1) == ')'))
- {
- skip_eol = TRUE;
- pline = NULL;
- }
- else
- {
- process_link(link_text,
- get_value(macros, macros_count,
- link_macro, NULL),
- token, output);
- output_firstcol = !*link_text;
- }
- }
- RESET_TOKEN(token, ptoken, token_size);
- state &= ~(ST_LINK | ST_LINK_SECOND_ARG);
- if (pline)
- {
- pline++;
- colno++;
- }
- }
- else if (state & ST_IMAGE_SECOND_ARG)
- {
- if (!read_yaml_macros_and_links)
- {
- u8* url = get_value(links, links_count, token, NULL);
- if (!url)
- exit(error(EINVAL, (u8*)"get_value: Invalid argument"));
- paralinks_count++;
- if (!paralinks)
- {
- CALLOC(paralinks, KeyValue, paralinks_count);
- pparalinks = paralinks;
- }
- else
- {
- REALLOCARRAY(paralinks, KeyValue, paralinks_count);
- pparalinks = paralinks + paralinks_count - 1;
- }
- pparalinks->key = (u8*)strdup((char*)url);
- pparalinks->value_size = strlen((char*)link_text)+1;
- pparalinks->value = (u8*)strdup((char*)link_text);
-
- if (output_firstcol
- && ((*(line+line_len-1) == ']')
- || *(line+line_len-1) == ')'))
- {
- skip_eol = TRUE;
- pline = NULL;
- }
- else
- {
- process_image(link_text, token, output,
- add_image_links, add_figcaption);
- output_firstcol = !*link_text;
- }
- }
- RESET_TOKEN(token, ptoken, token_size);
- state &= ~(ST_IMAGE | ST_IMAGE_SECOND_ARG);
- if (pline)
- {
- pline++;
- colno++;
- }
- }
- else if (strlen((char*)pline) > 1)
- {
- size_t token_len = 0;
- switch (*(pline+1))
- {
- case ':':
- links_count++;
-
- if (!links)
- {
- CALLOC(links, KeyValue, links_count);
- plinks = links;
- }
- else
- {
- REALLOCARRAY(links, KeyValue, links_count);
- plinks = links + links_count - 1;
- }
- CALLOC(plinks->key, u8, KEYSIZE);
- strncpy((char*)plinks->key, (char*)token, KEYSIZE-1);
- plinks->value = NULL;
- plinks->value_size = 0;
- pline += 2;
- colno += 2;
- while (pline && (*pline == ' ' || *pline == '\t'))
- {
- pline++;
- colno++;
- }
- RESET_TOKEN(token, ptoken, token_size);
- keep_token = FALSE;
- state |= ST_LINK_SECOND_ARG_END;
- break;
-
- case '[':
- case '(':
- token_len = strlen((char*)token);
- if (link_text)
- {
- if (token_len + 1 > link_size)
- {
- link_size = token_len+1;
- REALLOC(link_text, u8, link_size);
- }
- }
- else
- {
- link_size = token_len+1;
- CALLOC(link_text, u8, link_size);
- }
- strncpy((char*)link_text, (char*)token, link_size-1);
- *(link_text + token_len) = 0;
- pline += 2;
- colno += 2;
- RESET_TOKEN(token, ptoken, token_size);
- keep_token = FALSE;
- if (state & ST_LINK)
- state |= ST_LINK_SECOND_ARG;
- else
- state |= ST_IMAGE_SECOND_ARG;
- break;
- default:
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- state &= ~(ST_LINK | ST_IMAGE);
- break;
- }
- }
- else
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- break;
-
- case '^':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_FOOTNOTE_TEXT | ST_IMAGE | ST_INLINE_FOOTNOTE
- | ST_PRE | ST_YAML))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- if (strlen((char*)pline) > 1 && *(pline+1) == '[')
- {
- /* Output existing text up to ^[ */
- *ptoken = 0;
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- processed_start_of_line = TRUE;
-
- RESET_TOKEN(token, ptoken, token_size);
- state |= ST_INLINE_FOOTNOTE;
- keep_token = TRUE;
- pline += 2;
- colno += 2;
- break;
- }
-
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
-
- case '\\':
- *ptoken = 0;
- if (ANY(state, ST_DISPLAY_FORMULA | ST_FORMULA
- /*| ST_HTML_TAG*/ | ST_IMAGE | ST_LINK
- | ST_MACRO_BODY))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- if (strlen((char*)pline) > 1)
- {
- pline++;
- colno++;
-
- CHECKCOPY(token, ptoken, token_size, pline);
- }
- else
- {
- pline = NULL;
- break;
- }
-
- colno++;
- break;
-
- case '$':
- if (ANY(state, ST_CODE | ST_CSV_BODY | ST_IMAGE | ST_PRE
- | ST_YAML))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- break;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
-
- if (strlen((char*)pline) > 1
- && *(pline+1) == '$')
- {
- if (state & ST_FORMULA)
- exit(error(1, (u8*)"Display formula within an"
- " open formula"));
-
- if (!(state & ST_DISPLAY_FORMULA))
- {
- /* Output existing text up to $$ */
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- }
- processed_start_of_line = TRUE;
-
- state ^= ST_DISPLAY_FORMULA;
-
- if (state & ST_DISPLAY_FORMULA)
- keep_token = TRUE;
- else
- {
- *ptoken = 0;
-
- if (!read_yaml_macros_and_links)
- process_formula(output, token, TRUE);
-
- keep_token = FALSE;
- RESET_TOKEN(token, ptoken, token_size);
- }
-
- pline += 2;
- colno += 2;
- }
- else
- {
- if (state & ST_DISPLAY_FORMULA)
- exit(error(1, (u8*)"Formula within an open"
- " display formula"));
-
- if (!(state & ST_FORMULA))
- {
- /* Output existing text up to $ */
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- }
- processed_start_of_line = TRUE;
-
- state ^= ST_FORMULA;
-
- if (state & ST_FORMULA)
- keep_token = TRUE;
- else
- {
- *ptoken = 0;
-
- if (!read_yaml_macros_and_links)
- process_formula(output, token, FALSE);
-
- keep_token = FALSE;
- RESET_TOKEN(token, ptoken, token_size);
- }
-
- pline++;
- colno++;
- }
- break;
-
- case '1': case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9': case '0':
- if (ANY(state, ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_MACRO_BODY | ST_PRE | ST_YAML_VAL))
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- else if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- break;
- }
- else if (colno == 1
- && strlen((char*)pline) > 1
- && (*(pline+1) == '.' || *(pline+1) == ')'))
- {
- if (state & ST_LIST)
- {
- state &= ~ST_LIST;
- if (!read_yaml_macros_and_links)
- {
- process_list_item_end(link_prefix, output);
- process_list_end(output);
- }
- }
- if (!read_yaml_macros_and_links)
- {
- if (!(state & ST_NUMLIST))
- process_numlist_start(output);
- else
- process_list_item_end(link_prefix, output);
- process_list_item_start(output);
- }
-
- processed_start_of_line = TRUE;
- skip_eol = FALSE;
-
- state |= ST_NUMLIST;
-
- pline += 2;
- colno += 2;
- }
- else
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- break;
-
- default:
- if (state & ST_HTML_TAG)
- {
- pline++;
- colno++;
- }
- else
- {
- CHECKCOPY(token, ptoken, token_size, pline);
- colno++;
- }
- }
- }
-
- *ptoken = 0;
-
- if (*token && read_yaml_macros_and_links
- && (state & ST_YAML_VAL))
- {
- *ptoken = 0;
- if (!vars)
- {
- vars_count = 1;
- CALLOC(vars, KeyValue, vars_count);
- pvars = vars;
- }
- pvars->value_size = strlen((char*)token)+1;
- CALLOC(pvars->value, u8, pvars->value_size);
- strncpy((char*)pvars->value, (char*)token, pvars->value_size-1);
- }
- else if (keep_token)
- {
- size_t token_len = strlen((char*)token);
-
- if (ptoken + 2 > token + token_size)
- {
- size_t old_size = token_size;
- token_size += BUFSIZE;
- REALLOC(token, u8, token_size);
- ptoken = token + old_size - 1;
- }
- strncat((char*)token, " ",
- token_size - token_len - 1);
- ptoken++;
- *ptoken = 0;
- }
- else
- {
- if (*token)
- {
- *ptoken = 0;
- size_t token_len = strlen((char*)token);
- if (state & ST_MACRO_BODY)
- {
- skip_eol = TRUE;
- if (read_yaml_macros_and_links)
- {
- if (!macros)
- {
- macros_count = 1;
- CALLOC(macros, KeyValue, macros_count);
- pmacros = macros;
- }
- if (pmacros->value)
- {
- size_t value_len = strlen((char*)pmacros->value);
-
- if (pmacros->value_size < value_len + token_len + 1)
- {
- pmacros->value_size += BUFSIZE;
- REALLOC(pmacros->value, u8, pmacros->value_size);
- }
- strncat((char*)pmacros->value, (char*)token,
- pmacros->value_size-value_len-1);
- strncat((char*)pmacros->value, " ",
- pmacros->value_size
- -strlen((char*)pmacros->value)-1);
- }
- else
- {
- pmacros->value_size = BUFSIZE;
- CALLOC(pmacros->value, u8, pmacros->value_size);
- strncpy((char*)pmacros->value, (char*)token,
- pmacros->value_size-1);
- strncat((char*)pmacros->value, " ",
- pmacros->value_size
- -strlen((char*)pmacros->value)-1);
- }
- }
- }
- else if (state & ST_FOOTNOTE_TEXT)
- {
- skip_eol = TRUE;
- if (read_yaml_macros_and_links)
- {
- if (!footnotes)
- {
- footnote_count = 1;
- CALLOC(footnotes, KeyValue, footnote_count);
- pfootnotes = footnotes;
- }
- if (pfootnotes->value)
- {
- size_t value_len = strlen((char*)pfootnotes->value);
-
- if (pfootnotes->value_size < value_len + token_len + 1)
- {
- pfootnotes->value_size += BUFSIZE;
- REALLOC(pfootnotes->value, u8, pfootnotes->value_size);
- }
- strncat((char*)pfootnotes->value, (char*)token,
- pfootnotes->value_size-value_len-1);
- strncat((char*)pfootnotes->value, " ",
- pfootnotes->value_size
- -strlen((char*)pfootnotes->value)-1);
- }
- else
- {
- pfootnotes->value_size = BUFSIZE;
- CALLOC(pfootnotes->value, u8, pfootnotes->value_size);
- strncpy((char*)pfootnotes->value, (char*)token,
- pfootnotes->value_size-1);
- strncat((char*)pfootnotes->value, " ",
- pfootnotes->value_size
- -strlen((char*)pfootnotes->value)-1);
- }
- }
- }
- else if (ANY(state, ST_LINK_SECOND_ARG | ST_LINK_SECOND_ARG_END))
- {
- if (read_yaml_macros_and_links)
- {
- if (!links)
- {
- links_count = 1;
- CALLOC(links, KeyValue, links_count);
- plinks = links;
- }
- plinks->value_size = strlen((char*)token)+1;
- CALLOC(plinks->value, u8, plinks->value_size);
- strncpy((char*)plinks->value, (char*)token,
- plinks->value_size-1);
- }
- }
- else if (state & ST_HEADING)
- {
- state &= ~(ST_HEADING | ST_HEADING_TEXT);
- if (!read_yaml_macros_and_links)
- process_heading(token, output);
- first_line_in_doc = FALSE;
- RESET_TOKEN(token, ptoken, token_size);
- heading_level = 0;
- }
- else if (!ANY(state, ST_DISPLAY_FORMULA | ST_FORMULA
- | ST_IMAGE | ST_LINK))
- process_text_token(line, link_prefix, first_line_in_doc,
- previous_line_blank, processed_start_of_line,
- skip_eol, read_yaml_macros_and_links,
- list_para, output, &token, &ptoken,
- &token_size, TRUE);
- }
-
- if (!ANY(state, ST_PRE | ST_IMAGE_SECOND_ARG | ST_LINK_SECOND_ARG
- | ST_LINK_SECOND_ARG_END)
- && (!*pbuffer || (*pbuffer == '\n')))
- {
- if (!*pbuffer && (state & ST_LIST))
- {
- if (!read_yaml_macros_and_links)
- {
- process_list_item_end(link_prefix, output);
- process_list_end(output);
- }
- state &= ~ST_LIST;
- }
-
- if (!*pbuffer && (state & ST_NUMLIST))
- {
- if (!read_yaml_macros_and_links)
- {
- process_list_item_end(link_prefix, output);
- process_numlist_end(output);
- }
- state &= ~ST_NUMLIST;
- }
-
- if (state & ST_PARA_OPEN)
- {
- /*
- *if (skip_para_end) print_output(output, "SPE");
- *else print_output(output, "!SPE!");
- */
- if (!read_yaml_macros_and_links)
- {
- process_para_end(link_prefix, previous_line_blank, output);
- output_firstcol = TRUE;
- }
-
- if (state & ST_LIST)
- skip_eol = TRUE;
-
- state &= ~ST_PARA_OPEN;
- }
-
- if (!*pbuffer && (state & ST_FOOTNOTE_TEXT))
- {
- state &= ~ST_FOOTNOTE_TEXT;
-
- *ptoken = 0;
- size_t token_len = strlen((char*)token);
-
- skip_eol = TRUE;
- if (read_yaml_macros_and_links)
- {
- if (!footnotes)
- {
- footnote_count = 1;
- CALLOC(footnotes, KeyValue, footnote_count);
- pfootnotes = footnotes;
- }
- if (pfootnotes->value)
- {
- size_t value_len = strlen((char*)pfootnotes->value);
-
- if (pfootnotes->value_size < value_len + token_len + 1)
- {
- pfootnotes->value_size
- = value_len + token_len + 1;
- REALLOC(pfootnotes->value, u8, pfootnotes->value_size);
- }
- strncat((char*)pfootnotes->value, (char*)token,
- pfootnotes->value_size-1);
- }
- else
- {
- pfootnotes->value_size = token_len + 1;
- CALLOC(pfootnotes->value, u8, pfootnotes->value_size);
- strncpy((char*)pfootnotes->value, (char*)token,
- pfootnotes->value_size-1);
- }
- }
- }
- }
-
- if (state & ST_BLOCKQUOTE
- && (!*pbuffer || *pbuffer != '>'))
- {
- state &= ~ST_BLOCKQUOTE;
- process_blockquote(output, TRUE);
- output_firstcol = TRUE;
- }
-
- if (ANY(state, ST_TABLE_HEADER | ST_TABLE_LINE)
- && (!line_len || !*pbuffer))
- {
- if (!read_yaml_macros_and_links)
- {
- warning(1, (u8*)"Malformed table");
- process_table_end(output);
- }
- state &= ~(ST_TABLE_HEADER | ST_TABLE_LINE);
- }
-
- if ((state & ST_TABLE) && (!line_len || !*pbuffer))
- {
- if (!read_yaml_macros_and_links)
- process_table_end(output);
- state &= ~ST_TABLE;
- }
- }
-
- if (!skip_eol && !keep_token && !read_yaml_macros_and_links
- && !ANY(state, ST_YAML | ST_YAML_VAL | ST_LINK_SECOND_ARG
- | ST_LINK_SECOND_ARG_END))
- {
- print_output(output, "%s", state & ST_PRE ? "\n"
- : (output_firstcol ? "" : " "));
- output_firstcol = (state & ST_PRE) || output_firstcol;
- }
-
- if (!keep_token)
- RESET_TOKEN(token, ptoken, token_size);
-
- if (!skip_change_first_line_in_doc
- && !(state & ST_YAML))
- first_line_in_doc = FALSE;
-
- skip_change_first_line_in_doc = FALSE;
- if (line_len == 0)
- {
- if (!previous_line_blank)
- {
- if (!read_yaml_macros_and_links
- && (state & ST_PARA_OPEN))
- {
- if (state & ST_LIST)
- process_list_item_end(link_prefix, output);
- else
- {
- process_para_end(link_prefix, previous_line_blank, output);
- output_firstcol = TRUE;
- }
- }
- previous_line_blank = TRUE;
- }
- }
- else
- previous_line_blank = FALSE;
-
- /* Lasts until the end of line */
- state &= ~(ST_YAML_VAL | ST_IMAGE_SECOND_ARG | ST_LINK_SECOND_ARG
- | ST_LINK_SECOND_ARG_END);
- }
- while (pbuffer && *pbuffer);
-
- if (!read_yaml_macros_and_links)
- {
- if (footnote_count > 0 || inline_footnote_count > 0)
- end_footnotes(output, link_prefix, add_footnote_div, previous_line_blank);
-
- if (paralinks_count > 0)
- process_paralinks(link_prefix, output);
-
- print_output(output, "\n");
- output_firstcol = TRUE;
- }
-
- if (link_text)
- free(link_text);
-
- free(link_macro);
- free(token);
- free(line);
-
- return 0;
-}
+ if (colno == 1 && strlen((char*)pline) > 2
+ && startswith((char*)pline, "```"))
+ {
+ state ^= ST_PRE;
-int
-slweb_cleanup()
-{
- free(basedir);
- free(input_dirname);
- while (inline_footnote_count--)
- free(inline_footnotes[inline_footnote_count]);
- if (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);
-
- return 0;
-}
+ if (!read_yaml_macros_and_links)
+ {
+ print_output(output, "```%s",
+ IN(state, ST_PRE) ? "" : "\n\n");
+ output_firstcol = !IN(state, ST_PRE);
+ }
-int
-main(int argc, char** argv)
-{
- char* arg;
- Command cmd = CMD_NONE;
- int result = 0;
-
- basedir_size = 2;
- CALLOC(basedir, char, basedir_size);
- *basedir = '.';
-
- while ((arg = *++argv))
- {
- if (*arg == '-')
- {
- arg++;
- char c = *arg++;
- int result;
-
- if (c == '-')
- {
- if (!strcmp(arg, "version"))
- cmd = CMD_VERSION;
- else if (startswith(arg, "basedir"))
- {
- arg += strlen("basedir");
- result = set_basedir(arg, &basedir, &basedir_size);
- if (result)
- return result;
- }
- else if (startswith(arg, "global-link-prefix"))
- {
- arg += strlen("global-link-prefix");
- result = set_global_link_prefix(arg, &global_link_prefix,
- &global_link_prefix_size);
- if (result)
- return result;
- }
- else if (!strcmp(arg, "help"))
- return usage();
- else
- {
- error(EINVAL, (u8*)"Invalid argument: --%s", arg);
- return usage();
- }
- }
- else
- {
- switch (c)
- {
- case 'd':
- cmd = CMD_BASEDIR;
- break;
- case 'h':
- return usage();
- break;
- case 'p':
- cmd = CMD_LINK_PREFIX;
- break;
- case 'v':
- cmd = CMD_VERSION;
- break;
- default:
- error(EINVAL, (u8*)"Invalid argument: -%c", c);
- return usage();
- }
- }
- }
- else
- {
- int result;
-
- if (cmd == CMD_BASEDIR)
- {
- result = set_basedir(arg, &basedir, &basedir_size);
- if (result)
- return result;
- }
- else if (cmd == CMD_LINK_PREFIX)
- {
- result = set_global_link_prefix(arg, &global_link_prefix,
- &global_link_prefix_size);
- if (result)
- return result;
- }
- else
- input_filename = arg;
- cmd = CMD_NONE;
- }
- }
-
- if (cmd == CMD_BASEDIR)
- return error(1, (u8*)"-d: Argument required");
-
- if (cmd == CMD_VERSION)
- return version();
-
- FILE* input = NULL;
- FILE* output = stdout;
- u8* buffer = NULL;
- size_t buffer_size = 0;
-
- if (input_filename)
- read_file_into_buffer(&buffer, &buffer_size, input_filename, &input_dirname, &input);
- else
- {
- u8* bufline = NULL;
- size_t buffer_len = 0;
- size_t buffer_size = 0;
- size_t bufline_len = 0;
-
- input = stdin;
-
- CALLOC(bufline, u8, BUFSIZE);
- buffer_size = BUFSIZE;
- CALLOC(buffer, u8, buffer_size);
-
- while (!feof(input))
- {
- u8* eol = NULL;
- if (!fgets((char*)bufline, BUFSIZE-1, input))
- break;
- eol = (u8*)strchr((char*)bufline, '\n');
- if (eol)
- *(eol+1) = 0;
- bufline_len = strlen((char*)bufline);
- if (buffer_len + bufline_len + 1 > buffer_size)
- {
- buffer_size += BUFSIZE;
- REALLOC(buffer, u8, buffer_size);
- }
- strncat((char*)buffer, (char*)bufline, buffer_size-buffer_len-1);
- buffer_len += bufline_len;
- }
- free(bufline);
- }
-
- vars = NULL;
- vars_count = 0;
- macros = NULL;
- macros_count = 0;
- links = NULL;
- links_count = 0;
- paralinks = NULL;
- paralinks_count = 0;
- footnotes = NULL;
- footnote_count = 0;
- inline_footnotes = NULL;
- inline_footnote_count = 0;
-
- /* First pass: read YAML, macros and links */
- result = slweb_parse(buffer, output, TRUE);
-
- if (result)
- {
- slweb_cleanup();
- free(buffer);
- return result;
- }
-
- state = ST_NONE;
- current_footnote = 0;
- current_inline_footnote = 0;
-
- /* Second pass: parse and output */
- result = slweb_parse(buffer, output, FALSE);
-
- slweb_cleanup();
- free(buffer);
-
- return result;
+ /* Skip the rest of the line (language) */
+ pline = NULL;
+ }
+ else if (!ANY(state, ST_PRE | ST_TAG | ST_YAML))
+ {
+ if (!ANY(state,
+ ST_INLINE_FOOTNOTE | ST_HEADING
+ | ST_FOOTNOTE_TEXT | ST_LINK))
+ {
+ /* Output existing text up to ` */
+ 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, TRUE);
+ processed_start_of_line = TRUE;
+ }
+
+ state ^= ST_CODE;
+
+ pline++;
+ colno++;
+ }
+ else
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+ break;
+
+ case '#':
+ if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+ if (colno == 1
+ && !(ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_MACRO_BODY | ST_PRE | ST_YAML)))
+ {
+ if (IN(state, ST_LIST))
+ {
+ state &= ~ST_LIST;
+ if (!read_yaml_macros_and_links)
+ {
+ process_list_item_end(output,
+ link_prefix);
+ process_list_end(output);
+ }
+ }
+
+ if (IN(state, ST_NUMLIST))
+ {
+ state &= ~ST_NUMLIST;
+ if (!read_yaml_macros_and_links)
+ {
+ process_list_item_end(output,
+ link_prefix);
+ process_numlist_end(output);
+ }
+ }
+
+ state |= ST_HEADING;
+ heading_level = 1;
+ pline++;
+ colno++;
+ }
+ else if (IN(state, ST_HEADING) && *(pline - 1) == '#')
+ {
+ if (heading_level < MAX_HEADING_LEVEL)
+ heading_level++;
+ pline++;
+ colno++;
+ }
+ else
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+ break;
+
+ case '_':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_HTML_TAG | ST_IMAGE | ST_LINK_SECOND_ARG
+ | ST_LINK_SECOND_ARG_END | ST_MACRO_BODY
+ | ST_PRE | ST_TAG | ST_YAML))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ if (strlen((char*)pline) > 1 && *(pline + 1) == '_')
+ {
+ /* Handle __ within footnotes, headings
+ * and link text specially */
+ if (!ANY(state,
+ ST_INLINE_FOOTNOTE | ST_HEADING
+ | ST_FOOTNOTE_TEXT | ST_LINK))
+ {
+ /* Output existing text up to __ */
+ 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, TRUE);
+ processed_start_of_line = TRUE;
+
+ if (!read_yaml_macros_and_links
+ && !(ANY(state,
+ ST_PRE | ST_CODE | ST_HEADING)))
+ process_bold(output, IN(state, ST_BOLD));
+ }
+
+ state ^= ST_BOLD;
+ pline += 2;
+ colno += 2;
+ }
+ else
+ {
+ /* Handle _ within footnotes, headings
+ * and link text specially */
+ if (!ANY(state,
+ ST_INLINE_FOOTNOTE | ST_HEADING
+ | ST_FOOTNOTE_TEXT | ST_LINK))
+ {
+ /* Output existing text up to _ */
+ 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, TRUE);
+ processed_start_of_line = TRUE;
+
+ if (!read_yaml_macros_and_links
+ && !(ANY(state,
+ ST_PRE | ST_CODE | ST_HEADING)))
+ process_italic(output,
+ IN(state, ST_ITALIC));
+ }
+
+ state ^= ST_ITALIC;
+ pline++;
+ colno++;
+ }
+ break;
+
+ case 'o':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_HTML_TAG | ST_IMAGE | ST_MACRO_BODY
+ | ST_PRE | ST_YAML))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ if (colno == 1 && strlen((char*)pline) > 1
+ && *(pline + 1) == ' ')
+ {
+ if (IN(state, ST_NUMLIST))
+ {
+ state &= ~ST_NUMLIST;
+ if (!read_yaml_macros_and_links)
+ {
+ process_list_item_end(output,
+ link_prefix);
+ process_numlist_end(output);
+ }
+ }
+ if (!read_yaml_macros_and_links)
+ {
+ if (!(IN(state, ST_LIST)))
+ process_list_start(output);
+ else
+ process_list_item_end(output,
+ link_prefix);
+ process_list_item_start(output);
+ }
+
+ processed_start_of_line = TRUE;
+ skip_eol = FALSE;
+
+ state |= ST_LIST;
+
+ pline += 2;
+ colno += 2;
+ }
+ else
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+ break;
+
+ case '*':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA
+ | ST_FORMULA
+ /*| ST_HTML_TAG */
+ | ST_IMAGE | ST_MACRO_BODY | ST_PRE
+ | ST_YAML))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ pline_len = strlen((char*)pline);
+ if (colno == 1 && pline_len > 1 && *(pline + 1) == '[')
+ {
+ process_line_start(output, line, link_prefix,
+ first_line_in_doc, previous_line_blank,
+ read_yaml_macros_and_links, list_para, &token,
+ &ptoken);
+
+ /* Ignore abbreviations (for now) */
+ pline = NULL;
+ }
+ else if (colno == 1 && pline_len > 2
+ && startswith((char*)pline, "***"))
+ {
+ skip_eol = TRUE;
+ if (!read_yaml_macros_and_links)
+ {
+ process_horizontal_rule(link_prefix,
+ previous_line_blank, output);
+ output_firstcol = TRUE;
+ }
+ pline = NULL;
+ }
+ else if (colno == 1 && strlen((char*)pline) > 1
+ && *(pline + 1) == ' ')
+ {
+ if (IN(state, ST_NUMLIST))
+ {
+ state &= ~ST_NUMLIST;
+ if (!read_yaml_macros_and_links)
+ {
+ process_list_item_end(output,
+ link_prefix);
+ process_numlist_end(output);
+ }
+ }
+ if (!read_yaml_macros_and_links)
+ {
+ if (!(IN(state, ST_LIST)))
+ process_list_start(output);
+ else
+ process_list_item_end(output,
+ link_prefix);
+ process_list_item_start(output);
+ }
+
+ processed_start_of_line = TRUE;
+ skip_eol = FALSE;
+
+ state |= ST_LIST;
+
+ pline += 2;
+ colno += 2;
+ }
+ else if (pline_len > 1 && *(pline + 1) == '*')
+ {
+ /* Handle ** within footnotes, headings
+ * and link text specially */
+ if (!ANY(state,
+ ST_INLINE_FOOTNOTE | ST_HEADING
+ | ST_FOOTNOTE_TEXT | ST_LINK))
+ {
+ /* Output existing text up to * */
+ 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, TRUE);
+ processed_start_of_line = TRUE;
+
+ if (!read_yaml_macros_and_links
+ && !(ANY(state,
+ ST_PRE | ST_CODE | ST_HEADING)))
+ process_bold(output, IN(state, ST_BOLD));
+ }
+
+ state ^= ST_BOLD;
+ pline += 2;
+ colno += 2;
+ }
+ else
+ {
+ /* Handle * within footnotes, headings
+ * and link text specially */
+ if (!ANY(state,
+ ST_INLINE_FOOTNOTE | ST_HEADING
+ | ST_FOOTNOTE_TEXT | ST_LINK))
+
+ {
+ /* Output existing text up to * */
+ 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, TRUE);
+ processed_start_of_line = TRUE;
+
+ if (!read_yaml_macros_and_links
+ && !(ANY(state,
+ ST_PRE | ST_CODE | ST_HEADING)))
+ process_italic(output,
+ IN(state, ST_ITALIC));
+ }
+
+ state ^= ST_ITALIC;
+ pline++;
+ colno++;
+ }
+ break;
+
+ case ' ':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA | ST_IMAGE
+ | ST_MACRO_BODY | ST_PRE | ST_YAML_VAL))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+
+ 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);
+ state |= ST_HEADING_TEXT;
+ pline++;
+ colno++;
+ break;
+ }
+
+ if (colno == 1 && strlen((char*)pline) > 1
+ && startswith((char*)pline, " "))
+ {
+ list_para = TRUE;
+ 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, TRUE);
+ processed_start_of_line = TRUE;
+ while (*pline == ' ' || *pline == '\t')
+ {
+ pline++;
+ colno++;
+ }
+ break;
+ }
+
+ if (strlen((char*)pline) == 2 && *(pline + 1) == ' ')
+ {
+ *ptoken = 0;
+ strncat((char*)ptoken, "\n",
+ BUFSIZE - strlen((char*)token) - 1);
+ ptoken += strlen("\n");
+ output_firstcol = TRUE;
+ pline++;
+ colno++;
+ }
+ else if (IN(state, ST_LINK_MACRO))
+ {
+ *ptoken = 0;
+ strncpy((char*)link_macro, (char*)token, BUFSIZE - 1);
+ *(link_macro + strlen((char*)token)) = 0;
+ RESET_TOKEN(token, ptoken, token_size);
+ state &= ~ST_LINK_MACRO;
+ }
+ else if (!(IN(state, ST_HEADING) && *(pline - 1) == '#'))
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+
+ case '{':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA
+ | ST_FORMULA
+ /*| ST_HTML_TAG*/
+ | ST_PRE | ST_YAML | ST_YAML_VAL))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ if (IN(state, ST_MACRO_BODY))
+ {
+ *ptoken = 0;
+ size_t token_len = strlen((char*)token);
+
+ skip_eol = TRUE;
+ if (read_yaml_macros_and_links)
+ {
+ if (!macros)
+ {
+ macros_count = 1;
+ CALLOC(macros, KeyValue, macros_count);
+ pmacros = macros;
+ }
+ if (pmacros->value)
+ {
+ size_t value_len
+ = strlen((char*)pmacros->value);
+
+ if (pmacros->value_size
+ < value_len + token_len + 1)
+ {
+ pmacros->value_size
+ += token_len;
+ REALLOC(pmacros->value, u8,
+ pmacros->value_size);
+ }
+ strncat((char*)pmacros->value,
+ (char*)token,
+ pmacros->value_size - 1);
+ }
+ else
+ {
+ pmacros->value_size = token_len + 1;
+ CALLOC(pmacros->value, u8,
+ pmacros->value_size);
+ strncpy((char*)pmacros->value,
+ (char*)token,
+ pmacros->value_size - 1);
+ }
+ }
+ }
+ else
+ {
+ /* Output existing text up to { */
+ 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, TRUE);
+ processed_start_of_line = TRUE;
+ }
+
+ state |= ST_TAG;
+ RESET_TOKEN(token, ptoken, token_size);
+
+ pline++;
+ colno++;
+ break;
+
+ case '/':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA | ST_IMAGE
+ | ST_PRE | ST_HEADING | ST_YAML_VAL))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ if ((IN(state, ST_TAG)) && pline - 1 && *(pline - 1) == '{')
+ {
+ end_tag = TRUE;
+ pline++;
+ }
+ else
+ CHECKCOPY(token, ptoken, token_size, pline);
+
+ colno++;
+ break;
+
+ case '}':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA | ST_IMAGE
+ | ST_PRE | ST_YAML | ST_YAML_VAL))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+
+ if (IN(state, ST_TAG))
+ {
+ state &= ~ST_TAG;
+ *ptoken = 0;
+
+ process_tag(output, token, link_prefix,
+ previous_line_blank, read_yaml_macros_and_links,
+ &skip_eol, end_tag);
+
+ RESET_TOKEN(token, ptoken, token_size);
+ end_tag = FALSE;
+ }
+
+ pline++;
+ colno++;
+ break;
+
+ case '|':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA
+ | ST_FORMULA
+ /*| ST_HTML_TAG*/
+ | ST_IMAGE | ST_PRE | ST_TAG | ST_YAML))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ if (strlen((char*)pline) > 1 && *(pline + 1) == '|')
+ {
+ if (!ANY(state,
+ ST_INLINE_FOOTNOTE | ST_HEADING
+ | ST_FOOTNOTE_TEXT | ST_LINK))
+ {
+ /* Output existing text up to || */
+ 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, TRUE);
+ processed_start_of_line = TRUE;
+ }
+
+ state ^= ST_KBD;
+
+ pline += 2;
+ colno += 2;
+ }
+ /* Partial tables (for templating) */
+ else if (!(IN(state, ST_PRE)) && colno == 1
+ && strlen((char*)pline) > 1 && *(pline + 1) == '@')
+ {
+ skip_eol = TRUE;
+
+ pline += 2;
+ colno += 2;
+
+ switch (*pline)
+ {
+ case '\\':
+ if (!read_yaml_macros_and_links)
+ process_table_start(output);
+ pline = NULL;
+ break;
+
+ case '#':
+ state |= ST_TABLE_HEADER;
+ pline++;
+ colno++;
+ break;
+
+ case '-':
+ state &= ~ST_TABLE_HEADER;
+ if (!read_yaml_macros_and_links)
+ process_table_body_start(output, FALSE);
+ pline = NULL;
+ break;
+
+ case ' ':
+ state |= ST_TABLE;
+ if (!read_yaml_macros_and_links)
+ process_table_body_row_start(output);
+ break;
+
+ case '/':
+ state &= ~ST_TABLE;
+ process_table_end(output);
+ pline = NULL;
+ break;
+
+ default:
+ warning(1, (u8*)"Invalid partial table line");
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+ }
+ else if (!(IN(state, ST_PRE)) && colno == 1)
+ {
+ skip_eol = TRUE;
+
+ if (IN(state, ST_TABLE_HEADER))
+ {
+ state &= ~ST_TABLE_HEADER;
+ state |= ST_TABLE_LINE;
+ pline = NULL;
+ break;
+ }
+
+ if (IN(state, ST_TABLE_LINE))
+ {
+ state &= ~ST_TABLE_LINE;
+ state |= ST_TABLE;
+ if (!read_yaml_macros_and_links)
+ process_table_body_start(output, TRUE);
+ }
+ else if (IN(state, ST_TABLE))
+ {
+ if (!read_yaml_macros_and_links)
+ process_table_body_row_start(output);
+ }
+ else
+ {
+ state |= ST_TABLE_HEADER;
+ if (!read_yaml_macros_and_links)
+ process_table_start(output);
+ }
+
+ pline++;
+ colno++;
+ }
+ else if (IN(state, ST_TABLE_HEADER))
+ {
+ *ptoken = 0;
+ if (!read_yaml_macros_and_links)
+ {
+ print_output(output, "%s", token);
+ if (*token)
+ output_firstcol = FALSE;
+ if (strlen((char*)pline) > 1)
+ process_table_header_cell(output);
+ else
+ process_table_header_end(output);
+ }
+ RESET_TOKEN(token, ptoken, token_size);
+ pline++;
+ colno++;
+ }
+ else if (IN(state, ST_TABLE))
+ {
+ *ptoken = 0;
+ if (!read_yaml_macros_and_links)
+ {
+ print_output(output, "%s", token);
+ if (*token)
+ output_firstcol = FALSE;
+ if (strlen((char*)pline) > 1)
+ process_table_body_cell(output);
+ else
+ process_table_body_row_end(output);
+ }
+ RESET_TOKEN(token, ptoken, token_size);
+ pline++;
+ colno++;
+ }
+ else
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+ break;
+
+ case '<':
+ if (read_yaml_macros_and_links
+ || ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_IMAGE | ST_PRE))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+
+ state |= ST_HTML_TAG;
+ pline++;
+ colno++;
+ break;
+
+ case '>':
+ if (IN(state, ST_HTML_TAG))
+ {
+ state &= ~ST_HTML_TAG;
+ pline++;
+ colno++;
+ break;
+ }
+
+ if (ANY(state,
+ ST_DISPLAY_FORMULA | ST_FORMULA | ST_IMAGE
+ | ST_MACRO_BODY))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+
+ if (!read_yaml_macros_and_links
+ && !ANY(state, ST_CODE | ST_HEADING | ST_PRE)
+ && colno == 1)
+ {
+ if (!read_yaml_macros_and_links
+ && !(IN(state, ST_BLOCKQUOTE)))
+ {
+ process_blockquote(output, FALSE);
+ output_firstcol = FALSE;
+ }
+
+ state |= ST_BLOCKQUOTE;
+
+ pline++;
+ colno++;
+ }
+ else
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+ break;
+
+ case '!':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_FOOTNOTE_TEXT | ST_HEADING | ST_IMAGE
+ | ST_INLINE_FOOTNOTE | ST_LINK
+ | ST_MACRO_BODY | ST_PRE))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ if (strlen((char*)pline) > 1 && *(pline + 1) == '[')
+ {
+ /* 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, TRUE);
+ processed_start_of_line = TRUE;
+
+ RESET_TOKEN(token, ptoken, token_size);
+
+ state |= ST_IMAGE;
+ keep_token = TRUE;
+ pline += 2;
+ colno += 2;
+ }
+ else
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+
+ break;
+
+ case '=':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_MACRO_BODY | ST_PRE | ST_TAG))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ if (colno != 1 && *(pline - 1) == '[')
+ {
+ state |= ST_LINK_MACRO;
+ pline++;
+ colno++;
+ }
+ else
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+ break;
+
+ case '[':
+ pline_len = strlen((char*)pline);
+
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_HEADING | ST_IMAGE | ST_MACRO_BODY
+ | ST_PRE))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ if (IN(state, ST_FOOTNOTE_TEXT))
+ {
+ if (!read_yaml_macros_and_links
+ && (IN(state, ST_PARA_OPEN)))
+ {
+ process_para_end(output, link_prefix,
+ previous_line_blank);
+ output_firstcol = TRUE;
+ }
+ state &= ~(ST_FOOTNOTE_TEXT | ST_PARA_OPEN);
+ }
+
+ if (pline_len > 1 && *(pline + 1) == '^')
+ {
+ footnote_at_line_start = colno == 1;
+ if (*token)
+ {
+ /* 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, TRUE);
+ }
+ processed_start_of_line = TRUE;
+
+ RESET_TOKEN(token, ptoken, token_size);
+ state |= ST_FOOTNOTE;
+ pline += 2;
+ colno += 2;
+ break;
+ }
+
+ if (*token)
+ {
+ /* 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, TRUE);
+ }
+ processed_start_of_line = TRUE;
+
+ RESET_TOKEN(token, ptoken, token_size);
+ state |= ST_LINK;
+ keep_token = TRUE;
+ *link_macro = 0;
+ pline++;
+ colno++;
+
+ if (*pline == '(')
+ {
+ *ptoken = 0;
+ state |= ST_LINK_SPAN;
+ pline++;
+ colno++;
+ }
+
+ break;
+
+ case '(':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_FOOTNOTE_TEXT | ST_HEADING
+ | ST_INLINE_FOOTNOTE | ST_LINK_SECOND_ARG_END
+ | ST_MACRO_BODY | ST_PRE))
+ CHECKCOPY(token, ptoken, token_size, pline);
+ else if (*link_macro && (IN(state, ST_LINK)))
+ {
+ /*
+ * u8*
+ * tag = (u8*)"<span>"; size_t tag_len =
+ * strlen(tag); size_t token_len = 0;
+ *
+ * *ptoken
+ * = 0; token_len = strlen(token);
+ *
+ * if
+ * (token_len + tag_len < BUFSIZE)
+ * {
+ * strncat((char*)token,
+ * tag, BUFSIZE-token_len-1); ptoken +=
+ * tag_len;
+ * }
+ */
+
+ state |= ST_LINK_SPAN;
+ pline++;
+ }
+ else
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+
+ case ')':
+ if (ANY(state,
+ ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_LINK_SECOND_ARG_END))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ pline_len = strlen((char*)pline);
+
+ if (IN(state, ST_LINK_SPAN) && pline_len > 1
+ && *(pline + 1) == ']')
+ {
+ state &= ~ST_LINK_SPAN;
+ pline++;
+ }
+ else if (ANY(state, ST_LINK_SECOND_ARG | ST_IMAGE_SECOND_ARG))
+ {
+ *ptoken = 0;
+ if (!read_yaml_macros_and_links)
+ {
+ paralinks_count++;
+ if (!paralinks)
+ {
+ CALLOC(paralinks, KeyValue,
+ paralinks_count);
+ pparalinks = paralinks;
+ }
+ else
+ {
+ REALLOCARRAY(paralinks, KeyValue,
+ paralinks_count);
+ pparalinks = paralinks + paralinks_count
+ - 1;
+ }
+ pparalinks->key = (u8*)strdup((char*)token);
+ pparalinks->value_size
+ = strlen((char*)link_text) + 1;
+ pparalinks->value
+ = (u8*)strdup((char*)link_text);
+
+ if (output_firstcol
+ && ((*(line + line_len - 1) == ']')
+ || *(line + line_len - 1)
+ == ')'))
+ {
+ skip_eol = TRUE;
+ skip_para_end = TRUE;
+ pline = NULL;
+ }
+ else
+ {
+ if (IN(state, ST_LINK_SECOND_ARG))
+ process_inline_link(output,
+ link_text);
+ else
+ process_inline_image(output,
+ link_text);
+ output_firstcol = !*link_text;
+ }
+ }
+ RESET_TOKEN(token, ptoken, token_size);
+ state &= ~(ST_LINK | ST_LINK_SECOND_ARG | ST_IMAGE
+ | ST_IMAGE_SECOND_ARG);
+ if (pline)
+ pline++;
+ }
+ else
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+
+ case ']':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_HEADING | ST_MACRO_BODY | ST_PRE))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ *ptoken = 0;
+ if (IN(state, ST_INLINE_FOOTNOTE))
+ {
+ process_inline_footnote(token,
+ read_yaml_macros_and_links, output);
+
+ keep_token = FALSE;
+ RESET_TOKEN(token, ptoken, token_size);
+ state &= ~ST_INLINE_FOOTNOTE;
+ pline++;
+ colno++;
+ }
+ else if (IN(state, ST_FOOTNOTE))
+ {
+ BOOL footnote_definition = (strlen((char*)pline) > 1)
+ && (*(pline + 1) == ':')
+ && footnote_at_line_start;
+
+ process_footnote(output, token,
+ footnote_definition
+ && read_yaml_macros_and_links,
+ !footnote_definition
+ && !read_yaml_macros_and_links);
+
+ RESET_TOKEN(token, ptoken, token_size);
+ state &= ~ST_FOOTNOTE;
+ footnote_at_line_start = FALSE;
+ pline++;
+ colno++;
+ if (footnote_definition)
+ {
+ pline++;
+ colno++;
+ while (*pline == ' ' || *pline == '\t')
+ {
+ pline++;
+ colno++;
+ }
+ state |= ST_FOOTNOTE_TEXT;
+ }
+ }
+ else if (IN(state, ST_LINK_SECOND_ARG))
+ {
+ if (!read_yaml_macros_and_links)
+ {
+ u8* url = get_value(links, links_count, token,
+ NULL);
+ if (!url)
+ exit(error(EINVAL,
+ (u8*)"get_"
+ "value: "
+ "Invalid "
+ "argumen"
+ "t"));
+ paralinks_count++;
+ if (!paralinks)
+ {
+ CALLOC(paralinks, KeyValue,
+ paralinks_count);
+ pparalinks = paralinks;
+ }
+ else
+ {
+ REALLOCARRAY(paralinks, KeyValue,
+ paralinks_count);
+ pparalinks = paralinks + paralinks_count
+ - 1;
+ }
+ pparalinks->key = (u8*)strdup((char*)url);
+ pparalinks->value_size
+ = strlen((char*)link_text) + 1;
+ pparalinks->value
+ = (u8*)strdup((char*)link_text);
+
+ if (output_firstcol
+ && ((*(line + line_len - 1) == ']')
+ || *(line + line_len - 1)
+ == ')'))
+ {
+ skip_eol = TRUE;
+ pline = NULL;
+ }
+ else
+ {
+ process_link(output, link_text);
+ output_firstcol = !*link_text;
+ }
+ }
+ RESET_TOKEN(token, ptoken, token_size);
+ state &= ~(ST_LINK | ST_LINK_SECOND_ARG);
+ if (pline)
+ {
+ pline++;
+ colno++;
+ }
+ }
+ else if (IN(state, ST_IMAGE_SECOND_ARG))
+ {
+ if (!read_yaml_macros_and_links)
+ {
+ u8* url = get_value(links, links_count, token,
+ NULL);
+ if (!url)
+ exit(error(EINVAL,
+ (u8*)"get_"
+ "value: "
+ "Invalid "
+ "argumen"
+ "t"));
+ paralinks_count++;
+ if (!paralinks)
+ {
+ CALLOC(paralinks, KeyValue,
+ paralinks_count);
+ pparalinks = paralinks;
+ }
+ else
+ {
+ REALLOCARRAY(paralinks, KeyValue,
+ paralinks_count);
+ pparalinks = paralinks + paralinks_count
+ - 1;
+ }
+ pparalinks->key = (u8*)strdup((char*)url);
+ pparalinks->value_size
+ = strlen((char*)link_text) + 1;
+ pparalinks->value
+ = (u8*)strdup((char*)link_text);
+
+ if (output_firstcol
+ && ((*(line + line_len - 1) == ']')
+ || *(line + line_len - 1)
+ == ')'))
+ {
+ skip_eol = TRUE;
+ pline = NULL;
+ }
+ else
+ {
+ process_image(output, link_text);
+ output_firstcol = !*link_text;
+ }
+ }
+ RESET_TOKEN(token, ptoken, token_size);
+ state &= ~(ST_IMAGE | ST_IMAGE_SECOND_ARG);
+ if (pline)
+ {
+ pline++;
+ colno++;
+ }
+ }
+ else if (strlen((char*)pline) > 1)
+ {
+ size_t token_len = 0;
+ switch (*(pline + 1))
+ {
+ case ':':
+ links_count++;
+
+ if (!links)
+ {
+ CALLOC(links, KeyValue, links_count);
+ plinks = links;
+ }
+ else
+ {
+ REALLOCARRAY(links, KeyValue,
+ links_count);
+ plinks = links + links_count - 1;
+ }
+ CALLOC(plinks->key, u8, KEYSIZE);
+ strncpy((char*)plinks->key, (char*)token,
+ KEYSIZE - 1);
+ plinks->value = NULL;
+ plinks->value_size = 0;
+ pline += 2;
+ colno += 2;
+ while (pline
+ && (*pline == ' ' || *pline == '\t'))
+ {
+ pline++;
+ colno++;
+ }
+ RESET_TOKEN(token, ptoken, token_size);
+ keep_token = FALSE;
+ state |= ST_LINK_SECOND_ARG_END;
+ break;
+
+ case '[':
+ case '(':
+ token_len = strlen((char*)token);
+ if (link_text && token_len + 1 > link_size)
+ {
+ link_size = token_len + 1;
+ REALLOC(link_text, u8, link_size);
+ }
+ else if (!link_text)
+ {
+ link_size = token_len + 1;
+ CALLOC(link_text, u8, link_size);
+ }
+ strncpy((char*)link_text, (char*)token,
+ link_size - 1);
+ *(link_text + token_len) = 0;
+ pline += 2;
+ colno += 2;
+ RESET_TOKEN(token, ptoken, token_size);
+ keep_token = FALSE;
+ if (IN(state, ST_LINK))
+ state |= ST_LINK_SECOND_ARG;
+ else
+ state |= ST_IMAGE_SECOND_ARG;
+ break;
+ default:
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ state &= ~(ST_LINK | ST_IMAGE);
+ break;
+ }
+ }
+ else
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+ break;
+
+ case '^':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_FOOTNOTE_TEXT | ST_IMAGE
+ | ST_INLINE_FOOTNOTE | ST_PRE | ST_YAML))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ if (strlen((char*)pline) > 1 && *(pline + 1) == '[')
+ {
+ /* 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, TRUE);
+ processed_start_of_line = TRUE;
+
+ RESET_TOKEN(token, ptoken, token_size);
+ state |= ST_INLINE_FOOTNOTE;
+ keep_token = TRUE;
+ pline += 2;
+ colno += 2;
+ break;
+ }
+
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+
+ case '\\':
+ *ptoken = 0;
+ if (ANY(state,
+ ST_DISPLAY_FORMULA
+ | ST_FORMULA
+ /*| ST_HTML_TAG*/
+ | ST_IMAGE | ST_LINK | ST_MACRO_BODY))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ if (strlen((char*)pline) > 1)
+ {
+ pline++;
+ colno++;
+
+ CHECKCOPY(token, ptoken, token_size, pline);
+ }
+ else
+ {
+ pline = NULL;
+ break;
+ }
+
+ colno++;
+ break;
+
+ case '$':
+ if (ANY(state,
+ ST_CODE | ST_CSV_BODY | ST_IMAGE | ST_PRE | ST_YAML))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ break;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+
+ if (strlen((char*)pline) > 1 && *(pline + 1) == '$')
+ {
+ if (IN(state, ST_FORMULA))
+ exit(error(1,
+ (u8*)"Display formula within an"
+ " open formula"));
+
+ if (!(IN(state, ST_DISPLAY_FORMULA)))
+ {
+ /* Output existing text up to $$ */
+ 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, TRUE);
+ }
+ processed_start_of_line = TRUE;
+
+ state ^= ST_DISPLAY_FORMULA;
+
+ if (IN(state, ST_DISPLAY_FORMULA))
+ keep_token = TRUE;
+ else
+ {
+ *ptoken = 0;
+
+ if (!read_yaml_macros_and_links)
+ process_formula(output, token, TRUE);
+
+ keep_token = FALSE;
+ RESET_TOKEN(token, ptoken, token_size);
+ }
+
+ pline += 2;
+ colno += 2;
+ }
+ else
+ {
+ if (IN(state, ST_DISPLAY_FORMULA))
+ exit(error(1,
+ (u8*)"Formula within an open"
+ " display formula"));
+
+ if (!(IN(state, ST_FORMULA)))
+ {
+ /* Output existing text up to $ */
+ 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, TRUE);
+ }
+ processed_start_of_line = TRUE;
+
+ state ^= ST_FORMULA;
+
+ if (IN(state, ST_FORMULA))
+ keep_token = TRUE;
+ else
+ {
+ *ptoken = 0;
+
+ if (!read_yaml_macros_and_links)
+ process_formula(output, token, FALSE);
+
+ keep_token = FALSE;
+ RESET_TOKEN(token, ptoken, token_size);
+ }
+
+ pline++;
+ colno++;
+ }
+ break;
+
+ case '1': /* FALLTHROUGH */
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '0':
+ if (ANY(state,
+ ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_MACRO_BODY | ST_PRE | ST_YAML_VAL))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+ else if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ break;
+ }
+ else if (colno == 1 && strlen((char*)pline) > 1
+ && (*(pline + 1) == '.' || *(pline + 1) == ')'))
+ {
+ if (IN(state, ST_LIST))
+ {
+ state &= ~ST_LIST;
+ if (!read_yaml_macros_and_links)
+ {
+ process_list_item_end(output,
+ link_prefix);
+ process_list_end(output);
+ }
+ }
+ if (!read_yaml_macros_and_links)
+ {
+ if (!(IN(state, ST_NUMLIST)))
+ process_numlist_start(output);
+ else
+ process_list_item_end(output,
+ link_prefix);
+ process_list_item_start(output);
+ }
+
+ processed_start_of_line = TRUE;
+ skip_eol = FALSE;
+
+ state |= ST_NUMLIST;
+
+ pline += 2;
+ colno += 2;
+ }
+ else
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+ break;
+
+ default:
+ if (state & ST_HTML_TAG)
+ {
+ pline++;
+ colno++;
+ }
+ else
+ {
+ CHECKCOPY(token, ptoken, token_size, pline);
+ colno++;
+ }
+ }
+ goto do_line;
+
+done_line:
+ *ptoken = 0;
+
+ if (*token && read_yaml_macros_and_links && (IN(state, ST_YAML_VAL)))
+ {
+ *ptoken = 0;
+ if (!vars)
+ {
+ vars_count = 1;
+ CALLOC(vars, KeyValue, vars_count);
+ pvars = vars;
+ }
+ pvars->value_size = strlen((char*)token) + 1;
+ CALLOC(pvars->value, u8, pvars->value_size);
+ strncpy((char*)pvars->value, (char*)token,
+ pvars->value_size - 1);
+ }
+ else if (keep_token)
+ {
+ size_t token_len = strlen((char*)token);
+
+ if (ptoken + 2 > token + token_size)
+ {
+ size_t old_size = token_size;
+ token_size += BUFSIZE;
+ REALLOC(token, u8, token_size);
+ ptoken = token + old_size - 1;
+ }
+ strncat((char*)token, " ", token_size - token_len - 1);
+ ptoken++;
+ *ptoken = 0;
+ }
+ else
+ {
+ if (*token)
+ {
+ *ptoken = 0;
+ size_t token_len = strlen((char*)token);
+ if (IN(state, ST_MACRO_BODY))
+ {
+ skip_eol = TRUE;
+ if (!read_yaml_macros_and_links)
+ goto skip_macro_read;
+ if (!macros)
+ {
+ macros_count = 1;
+ CALLOC(macros, KeyValue, macros_count);
+ pmacros = macros;
+ }
+ if (pmacros->value)
+ {
+ size_t value_len
+ = strlen((char*)pmacros->value);
+
+ if (pmacros->value_size
+ < value_len + token_len + 1)
+ {
+ pmacros->value_size += BUFSIZE;
+ REALLOC(pmacros->value, u8,
+ pmacros->value_size);
+ }
+ strncat((char*)pmacros->value,
+ (char*)token,
+ pmacros->value_size - value_len
+ - 1);
+ strncat((char*)pmacros->value, " ",
+ pmacros->value_size
+ - strlen((char*)pmacros
+ ->value)
+ - 1);
+ }
+ else
+ {
+ pmacros->value_size = BUFSIZE;
+ CALLOC(pmacros->value, u8,
+ pmacros->value_size);
+ strncpy((char*)pmacros->value,
+ (char*)token,
+ pmacros->value_size - 1);
+ strncat((char*)pmacros->value, " ",
+ pmacros->value_size
+ - strlen((char*)pmacros
+ ->value)
+ - 1);
+ }
+ skip_macro_read:;
+ }
+ else if (IN(state, ST_FOOTNOTE_TEXT))
+ {
+ skip_eol = TRUE;
+ if (!read_yaml_macros_and_links)
+ goto skip_footnote_read;
+ if (!footnotes)
+ {
+ footnote_count = 1;
+ CALLOC(footnotes, KeyValue,
+ footnote_count);
+ pfootnotes = footnotes;
+ }
+ if (pfootnotes->value)
+ {
+ size_t value_len = strlen(
+ (char*)pfootnotes->value);
+
+ if (pfootnotes->value_size
+ < value_len + token_len + 1)
+ {
+ pfootnotes->value_size
+ += BUFSIZE;
+ REALLOC(pfootnotes->value, u8,
+ pfootnotes->value_size);
+ }
+ strncat((char*)pfootnotes->value,
+ (char*)token,
+ pfootnotes->value_size
+ - value_len - 1);
+ strncat((char*)pfootnotes->value, " ",
+ pfootnotes->value_size
+ - strlen(
+ (char*)pfootnotes
+ ->value)
+ - 1);
+ }
+ else
+ {
+ pfootnotes->value_size = BUFSIZE;
+ CALLOC(pfootnotes->value, u8,
+ pfootnotes->value_size);
+ strncpy((char*)pfootnotes->value,
+ (char*)token,
+ pfootnotes->value_size - 1);
+ strncat((char*)pfootnotes->value, " ",
+ pfootnotes->value_size
+ - strlen(
+ (char*)pfootnotes
+ ->value)
+ - 1);
+ }
+ skip_footnote_read:;
+ }
+ else if (ANY(state,
+ ST_LINK_SECOND_ARG
+ | ST_LINK_SECOND_ARG_END))
+ {
+ if (read_yaml_macros_and_links)
+ {
+ if (!links)
+ {
+ links_count = 1;
+ CALLOC(links, KeyValue,
+ links_count);
+ plinks = links;
+ }
+ plinks->value_size
+ = strlen((char*)token) + 1;
+ CALLOC(plinks->value, u8,
+ plinks->value_size);
+ strncpy((char*)plinks->value,
+ (char*)token,
+ plinks->value_size - 1);
+ }
+ }
+ else if (IN(state, ST_HEADING))
+ {
+ state &= ~(ST_HEADING | ST_HEADING_TEXT);
+ if (!read_yaml_macros_and_links)
+ process_heading(output, token);
+ first_line_in_doc = FALSE;
+ RESET_TOKEN(token, ptoken, token_size);
+ heading_level = 0;
+ }
+ else if (!ANY(state,
+ ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_IMAGE | ST_LINK))
+ 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, TRUE);
+ }
+
+ if (!ANY(state,
+ ST_PRE | ST_IMAGE_SECOND_ARG | ST_LINK_SECOND_ARG
+ | ST_LINK_SECOND_ARG_END)
+ && (!*pbuffer || (*pbuffer == '\n')))
+ {
+ if (IN(state, ST_PARA_OPEN))
+ {
+ if (!read_yaml_macros_and_links)
+ {
+ process_list_item_end(output,
+ link_prefix);
+ process_list_end(output);
+ }
+ state &= ~ST_LIST;
+ }
+
+ if (!*pbuffer && (state & ST_NUMLIST))
+ {
+ if (!read_yaml_macros_and_links)
+ {
+ process_list_item_end(output,
+ link_prefix);
+ process_numlist_end(output);
+ }
+ state &= ~ST_NUMLIST;
+ }
+
+ if (IN(state, ST_PARA_OPEN))
+ {
+ /*
+ *if (skip_para_end)
+ *print_output(output, "SPE"); else
+ *print_output(output, "!SPE!");
+ */
+ if (!read_yaml_macros_and_links)
+ {
+ process_para_end(output, link_prefix,
+ previous_line_blank);
+ output_firstcol = TRUE;
+ }
+
+ if (IN(state, ST_LIST))
+ skip_eol = TRUE;
+
+ state &= ~ST_PARA_OPEN;
+ }
+
+ if (!*pbuffer && (IN(state, ST_FOOTNOTE_TEXT)))
+ {
+ state &= ~ST_FOOTNOTE_TEXT;
+
+ *ptoken = 0;
+ size_t token_len = strlen((char*)token);
+
+ skip_eol = TRUE;
+ if (read_yaml_macros_and_links)
+ {
+ if (!footnotes)
+ {
+ footnote_count = 1;
+ CALLOC(footnotes, KeyValue,
+ footnote_count);
+ pfootnotes = footnotes;
+ }
+ if (pfootnotes->value)
+ {
+ size_t value_len = strlen((
+ char*)pfootnotes->value);
+
+ if (pfootnotes->value_size
+ < value_len + token_len
+ + 1)
+ {
+ pfootnotes->value_size
+ = value_len
+ + token_len + 1;
+ REALLOC(pfootnotes->value,
+ u8,
+ pfootnotes
+ ->value_size);
+ }
+ strncat((char*)pfootnotes->value,
+ (char*)token,
+ pfootnotes->value_size
+ - 1);
+ }
+ else
+ {
+ pfootnotes->value_size
+ = token_len + 1;
+ CALLOC(pfootnotes->value, u8,
+ pfootnotes->value_size);
+ strncpy((char*)pfootnotes->value,
+ (char*)token,
+ pfootnotes->value_size
+ - 1);
+ }
+ }
+ }
+ }
+
+ if (state & ST_BLOCKQUOTE && (!*pbuffer || *pbuffer != '>'))
+ {
+ state &= ~ST_BLOCKQUOTE;
+ process_blockquote(output, TRUE);
+ output_firstcol = TRUE;
+ }
+
+ if (ANY(state, ST_TABLE_HEADER | ST_TABLE_LINE)
+ && (!line_len || !*pbuffer))
+ {
+ if (!read_yaml_macros_and_links)
+ {
+ warning(1, (u8*)"Malformed table");
+ process_table_end(output);
+ }
+ state &= ~(ST_TABLE_HEADER | ST_TABLE_LINE);
+ }
+
+ if ((state & ST_TABLE) && (!line_len || !*pbuffer))
+ {
+ if (!read_yaml_macros_and_links)
+ process_table_end(output);
+ state &= ~ST_TABLE;
+ }
+ }
+
+ if (!skip_eol && !keep_token && !read_yaml_macros_and_links
+ && !ANY(state,
+ ST_YAML | ST_YAML_VAL | ST_LINK_SECOND_ARG
+ | ST_LINK_SECOND_ARG_END))
+ {
+ print_output(output, "%s",
+ state & ST_PRE ? "\n" : (output_firstcol ? "" : " "));
+ output_firstcol = (state & ST_PRE) || output_firstcol;
+ }
+
+ if (!keep_token)
+ RESET_TOKEN(token, ptoken, token_size);
+
+ if (!skip_change_first_line_in_doc && !(state & ST_YAML))
+ first_line_in_doc = FALSE;
+
+ skip_change_first_line_in_doc = FALSE;
+ if (line_len == 0)
+ {
+ if (!previous_line_blank)
+ {
+ if (!read_yaml_macros_and_links
+ && (state & ST_PARA_OPEN))
+ {
+ if (state & ST_LIST)
+ process_list_item_end(output,
+ link_prefix);
+ else
+ {
+ process_para_end(output, link_prefix,
+ previous_line_blank);
+ output_firstcol = TRUE;
+ }
+ }
+ previous_line_blank = TRUE;
+ }
+ }
+ else
+ previous_line_blank = FALSE;
+
+ /* Lasts until the end of line */
+ state &= ~(ST_YAML_VAL | ST_IMAGE_SECOND_ARG | ST_LINK_SECOND_ARG
+ | ST_LINK_SECOND_ARG_END);
+
+ if (pbuffer && *pbuffer)
+ goto do_buffer;
+done_buffer:
+ if (!read_yaml_macros_and_links
+ && (footnote_count > 0 || inline_footnote_count > 0))
+ end_footnotes(output, link_prefix, add_footnote_div,
+ previous_line_blank);
+
+ if (paralinks_count > 0)
+ process_paralinks(output, link_prefix);
+
+ print_output(output, "\n");
+ output_firstcol = TRUE;
+
+ if (link_text)
+ free(link_text);
+
+ free(link_macro);
+ free(token);
+ free(line);
+
+ return 0;
+}
+
+int
+main(int argc, char** argv)
+{
+ char* arg;
+ Command cmd = CMD_NONE;
+ int result = 0;
+
+ basedir_size = 2;
+ CALLOC(basedir, char, basedir_size);
+ *basedir = '.';
+
+ while ((arg = *++argv))
+ {
+ if (*arg == '-')
+ {
+ arg++;
+ char c = *arg++;
+ int result;
+
+ if (c == '-')
+ {
+ if (!strcmp(arg, "version"))
+ cmd = CMD_VERSION;
+ else if (startswith(arg, "basedir"))
+ {
+ arg += strlen("basedir");
+ result = set_basedir(&basedir,
+ &basedir_size, arg);
+ if (result)
+ return result;
+ }
+ else if (startswith(arg, "global-link-prefix"))
+ {
+ arg += strlen("global-link-prefix");
+ result = set_global_link_prefix(
+ &global_link_prefix,
+ &global_link_prefix_size, arg);
+ if (result)
+ return result;
+ }
+ else if (!strcmp(arg, "help"))
+ return usage();
+ else
+ {
+ error(EINVAL,
+ (u8*)"Invalid argument: --%s",
+ arg);
+ return usage();
+ }
+ }
+ else
+ {
+ switch (c)
+ {
+ case 'd':
+ cmd = CMD_BASEDIR;
+ break;
+ case 'h':
+ return usage();
+ break;
+ case 'p':
+ cmd = CMD_LINK_PREFIX;
+ break;
+ case 'v':
+ cmd = CMD_VERSION;
+ break;
+ default:
+ error(EINVAL,
+ (u8*)"Invalid argument: -%c",
+ c);
+ return usage();
+ }
+ }
+ }
+ else
+ {
+ int result;
+
+ if (cmd == CMD_BASEDIR)
+ {
+ result = set_basedir(&basedir, &basedir_size,
+ arg);
+ if (result)
+ return result;
+ }
+ else if (cmd == CMD_LINK_PREFIX)
+ {
+ result = set_global_link_prefix(&global_link_prefix,
+ &global_link_prefix_size, arg);
+ if (result)
+ return result;
+ }
+ else
+ input_filename = arg;
+ cmd = CMD_NONE;
+ }
+ }
+
+ if (cmd == CMD_BASEDIR)
+ return error(1, (u8*)"-d: Argument required");
+
+ if (cmd == CMD_VERSION)
+ return version();
+
+ FILE* input = NULL;
+ FILE* output = stdout;
+ u8* buffer = NULL;
+ size_t buffer_size = 0;
+
+ if (input_filename)
+ read_file_into_buffer(&input, &buffer, &buffer_size,
+ input_filename, &input_dirname);
+ else
+ {
+ u8* bufline = NULL;
+ size_t buffer_len = 0;
+ size_t buffer_size = 0;
+ size_t bufline_len = 0;
+
+ input = stdin;
+
+ CALLOC(bufline, u8, BUFSIZE);
+ buffer_size = BUFSIZE;
+ CALLOC(buffer, u8, buffer_size);
+
+ while (!feof(input))
+ {
+ u8* eol = NULL;
+ if (!fgets((char*)bufline, BUFSIZE - 1, input))
+ break;
+ eol = (u8*)strchr((char*)bufline, '\n');
+ if (eol)
+ *(eol + 1) = 0;
+ bufline_len = strlen((char*)bufline);
+ if (buffer_len + bufline_len + 1 > buffer_size)
+ {
+ buffer_size += BUFSIZE;
+ REALLOC(buffer, u8, buffer_size);
+ }
+ strncat((char*)buffer, (char*)bufline,
+ buffer_size - buffer_len - 1);
+ buffer_len += bufline_len;
+ }
+ free(bufline);
+ }
+
+ vars = NULL;
+ vars_count = 0;
+ macros = NULL;
+ macros_count = 0;
+ links = NULL;
+ links_count = 0;
+ paralinks = NULL;
+ paralinks_count = 0;
+ footnotes = NULL;
+ footnote_count = 0;
+ inline_footnotes = NULL;
+ inline_footnote_count = 0;
+
+ /* First pass: read YAML, macros and links */
+ result = slweb_parse(output, input_filename, buffer, TRUE);
+
+ if (result)
+ {
+ slweb_cleanup();
+ free(buffer);
+ return result;
+ }
+
+ state = ST_NONE;
+ current_footnote = 0;
+ current_inline_footnote = 0;
+
+ /* Second pass: parse and output */
+ result = slweb_parse(output, input_filename, buffer, FALSE);
+
+ slweb_cleanup();
+ free(buffer);
+
+ return result;
}