чување 5e6983bbb3d9e72efcc1fbaa83ce52d6a429f2db
родитељ f798b7975018cbe191e2234280256a1aa2bbd5f9
Аутор: Страхиња Радић <sr@strahinja.org>
Датум: Tue, 23 Jul 2024 10:17:45 +0200
Add exact exit codes for errors not related to errno; error reporting cleanup
Diffstat:
| M | defs.h | | | 69 | ++++++++++++++++++++++++++++++++++++++++++++++----------------------- |
| M | slweb.1.in | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | slweb.c | | | 292 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
измењених датотека: 3, додавања: 251(+), брисања: 158(-)
diff --git a/defs.h b/defs.h
@@ -11,6 +11,46 @@
#define SMALL_ARGSIZE 256
#define DATEBUFSIZE 12
+#define SLWEB_ERR_CODE(num) (200 + (num))
+
+enum {
+ ERR_NONE = 0,
+ ERR_ARG_NOTNUM = SLWEB_ERR_CODE(1),
+ ERR_ARG_NOTSTR = SLWEB_ERR_CODE(2),
+ ERR_BAD_CL_ARG = SLWEB_ERR_CODE(3),
+ ERR_BAD_CND_MARK = SLWEB_ERR_CODE(4),
+ ERR_BAD_EMPTY_CND = SLWEB_ERR_CODE(5),
+ ERR_BAD_HR_MARK = SLWEB_ERR_CODE(6),
+ ERR_BAD_REG_MARK = SLWEB_ERR_CODE(7),
+ ERR_FORMAT_DATE_FAIL = SLWEB_ERR_CODE(8),
+ ERR_MACRO_UNDEF = SLWEB_ERR_CODE(9),
+ ERR_NEST_CSV = SLWEB_ERR_CODE(10),
+ ERR_NEST_MACRO = SLWEB_ERR_CODE(11),
+ ERR_NEST_MATH = SLWEB_ERR_CODE(12),
+ ERR_NO_ARG = SLWEB_ERR_CODE(13),
+ ERR_POPEN_FAIL = SLWEB_ERR_CODE(14),
+ ERR_SCANDIR_FAIL = SLWEB_ERR_CODE(15),
+};
+
+typedef enum {
+ CMD_NONE,
+ CMD_BODY_ONLY,
+ CMD_BASEDIR,
+ CMD_HELP,
+ CMD_LINK_PREFIX,
+ CMD_VERSION,
+ CMD_FULL_VERSION
+} Command;
+
+typedef struct {
+ u8* key;
+ u8* value;
+ size_t value_size;
+} KeyValue;
+
+typedef void (*csv_callback_t)(FILE* output, u8** csv_header, u8** csv_register);
+typedef void (*tsv_callback_t)(FILE* output, u8** tsv_header, u8** tsv_register);
+
static const char article_timestamp_format[] = "d.m.y";
static const char list_timestamp_format[] = "y-m-d";
static const char timestamp_output_ext[] = ".html";
@@ -59,7 +99,8 @@ static const char* CMD_IDENTIFY
#define CALLOC(ptr, ptrtype, nmemb) \
do \
{ \
- ptr = calloc(nmemb, sizeof(ptrtype)); \
+ errno = 0; \
+ ptr = calloc(nmemb, sizeof(ptrtype)); \
if (!ptr) \
{ \
perror(PROGRAMNAME ": calloc"); \
@@ -71,7 +112,9 @@ static const char* CMD_IDENTIFY
#define REALLOC(ptr, ptrtype, newsize) \
do \
{ \
- ptrtype* newptr = realloc(ptr, newsize); \
+ ptrtype* newptr = NULL; \
+ errno = 0; \
+ newptr = realloc(ptr, newsize); \
if (!newptr) \
{ \
perror(PROGRAMNAME ": realloc"); \
@@ -128,6 +171,7 @@ static const char* CMD_IDENTIFY
if (!(to) || (tosize) < (testsize)) \
{ \
(tosize) = fromsize; \
+ errno = 0; \
temp = realloc(to, (tosize) * sizeof(type)); \
if (!temp) \
{ \
@@ -138,27 +182,6 @@ static const char* CMD_IDENTIFY
} \
} while (0)
-typedef unsigned long ULONG;
-
-typedef enum {
- CMD_NONE,
- CMD_BODY_ONLY,
- CMD_BASEDIR,
- CMD_HELP,
- CMD_LINK_PREFIX,
- CMD_VERSION,
- CMD_FULL_VERSION
-} Command;
-
-typedef struct {
- u8* key;
- u8* value;
- size_t value_size;
-} KeyValue;
-
-typedef int (*csv_callback_t)(FILE* output, u8** csv_header, u8** csv_register);
-typedef int (*tsv_callback_t)(FILE* output, u8** tsv_header, u8** tsv_register);
-
#define MAX_HEADING_LEVEL 4
#define MAX_CSV_REGISTERS 9
#define MAX_TSV_REGISTERS 9
diff --git a/slweb.1.in b/slweb.1.in
@@ -1313,6 +1313,54 @@ directive, similar to the macro\-form of links.
.
.Sh EXIT STATUS
.Ex -std
+.Pp
+For errors caused by the unsuccessful calls to libc functions setting
+.Va errno ,
+that value is returned as the exit status.
+Otherwise, the exit status is one of the following:
+.Bl -tag -width Ds -offset indent -compact
+.It Li 201
+Argument to a function is not numeric.
+.It Li 202
+Argument to a function is not beginning and ending with double quotes (not a
+.Do string Dc Ns ).
+.It Li 203
+Command line argument is not recognized.
+.It Li 204
+Conditional mark is not recognized.
+.It Li 205
+Empty conditional mark is before or without the corresponding nonempty
+conditional.
+.It Li 206
+Header register mark is not recognized.
+.It Li 207
+Register mark is not recognized.
+.It Li 208
+Parsing arguments failed when formatting date.
+.It Li 209
+Macro is not defined.
+.It Li 210
+There are nested CSV/TSV directives.
+.It Li 211
+There are nested macro definitions.
+.It Li 212
+There are nested formulas.
+.It Li 213
+No arguments are supplied to a directive or to a command line argument which
+requires at least one.
+.It Li 214
+The function
+.Xr popen 3
+(which doesn't set
+.Va errno )
+failed.
+.It Li 215
+The function
+.Xr scandir 3
+(which doesn't set
+.Va errno )
+failed.
+.El
.
.Sh EXAMPLES
Given the file
diff --git a/slweb.c b/slweb.c
@@ -65,10 +65,10 @@ static int add_css(FILE* output, int output_yaml);
static int error(const int code, const char* file, const char* func,
const int line, const char* fmt, ...);
static u8* format_date(const u8* date_arg, const char* timestamp_format);
-static int free_keyvalue(KeyValue** list, const size_t list_count);
+static void free_keyvalue(KeyValue** list, const size_t list_count);
static u8* get_value(KeyValue* list, const size_t list_count, const u8* key,
KeyValue** cursor);
-static int print_meta_var(FILE* output, u8** tsv_header, u8** tsv_register);
+static void print_meta_var(FILE* output, u8** tsv_header, u8** tsv_register);
static int print_output(FILE* output, const char* fmt, ...);
static void process_horizontal_rule(FILE* output);
static void process_incdir_subdir(FILE* output, const char* subdirname,
@@ -342,7 +342,7 @@ end_footnotes(FILE* output, int add_footnote_div)
}
pfootnote = footnotes;
- footnote = 0;
+ footnote = 0;
while (pfootnote && footnote < footnote_count)
{
print_output(output,
@@ -400,10 +400,10 @@ filter_slw(const struct dirent* node)
&& !(*(node->d_name + 2))))))
return 0;
node_len = strlen(node->d_name);
- slw_len = strlen(".slw");
+ slw_len = sizeof(".slw");
if (slw_len >= node_len)
return 0;
- return !strcmp(node->d_name + strlen(node->d_name) - slw_len, ".slw");
+ return !strcmp(node->d_name + node_len - slw_len, ".slw");
}
static int
@@ -418,18 +418,14 @@ filter_subdirs(const struct dirent* node)
|| ((*(node->d_name + 1) == '.')
&& !(*(node->d_name + 2))))))
return 0;
-
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;
}
@@ -447,9 +443,14 @@ format_date(const u8* date_arg, const char* timestamp_format)
size_t formatted_date_len;
assert((date_arg != NULL) && (timestamp_format != NULL));
- date = (u8*)strdup((const char*)date_arg);
+ errno = 0;
+ date = (u8*)strdup((const char*)date_arg);
if (!date)
- goto format_date_cleanup;
+ {
+ perror(PROGRAMNAME ": strdup");
+ exit(error(errno, __FILE__, __func__, __LINE__,
+ "Allocation error"));
+ }
CALLOC(formatted_date, u8, DATEBUFSIZE);
ptr = NULL;
year = (u8*)strtok_r((char*)date, "-", (char**)&ptr);
@@ -496,19 +497,19 @@ format_date_cleanup:
return NULL;
}
-static int
+static void
free_keyvalue(KeyValue** list, const size_t list_count)
{
- if (!list || !*list)
- return 1;
-
+ assert(list != NULL);
+ if (!*list)
+ return;
for (size_t index = 0; index < list_count; index++)
{
KeyValue* current = *list + index;
free(current->value);
free(current->key);
}
- return 0;
+ return;
}
static u8*
@@ -559,7 +560,8 @@ print_command(FILE* output, const char* command, const u8* pass_arguments[],
fflush(output);
pipe(arg_pipe_fds);
pipe(output_pipe_fds);
- pid = fork();
+ errno = 0;
+ pid = fork();
if (pid == 0)
{
close(arg_pipe_fds[PIPE_WRITE_INDEX]);
@@ -572,19 +574,23 @@ print_command(FILE* output, const char* command, const u8* pass_arguments[],
exit(1);
}
else if (pid < 0)
+ {
+ perror(PROGRAMNAME ": fork");
exit(error(errno, __FILE__, __func__, __LINE__, "fork failed"));
+ }
/* Parent */
close(arg_pipe_fds[PIPE_READ_INDEX]);
close(output_pipe_fds[PIPE_WRITE_INDEX]);
- errno = 0;
- cmd_input = fdopen(arg_pipe_fds[PIPE_WRITE_INDEX], "w");
+ errno = 0;
+ cmd_input = fdopen(arg_pipe_fds[PIPE_WRITE_INDEX], "w");
if (cmd_input)
cmd_output = fdopen(output_pipe_fds[PIPE_READ_INDEX], "r");
if (!cmd_input || !cmd_output)
{
perror(PROGRAMNAME ": fdopen");
- exit(error(errno, __FILE__, __func__, __LINE__, "fdopen failed"));
+ exit(error(errno, __FILE__, __func__, __LINE__,
+ "fdopen failed"));
}
if (pipe_arguments)
@@ -638,7 +644,7 @@ print_command(FILE* output, const char* command, const u8* pass_arguments[],
} \
} while (0)
-static int
+static void
print_csv_row(FILE* output, u8** csv_header, u8** csv_register)
{
u8* pcsv_template = csv_template;
@@ -649,7 +655,7 @@ print_csv_row(FILE* output, u8** csv_header, u8** csv_register)
&& (csv_register != NULL));
csv_template_start:
if (!*pcsv_template)
- goto csv_template_done;
+ return;
if (IN(csv_state, ST_CS_ESCAPE))
{
PRINTCSVIF("%c", *pcsv_template);
@@ -677,7 +683,7 @@ csv_template_start:
case '#':
if (IN(csv_state, ST_CS_HEADER))
{
- error(1, __FILE__, __func__, __LINE__,
+ error(ERR_BAD_HR_MARK, __FILE__, __func__, __LINE__,
"Invalid header register mark");
CLEAR(csv_state, ST_CS_REGISTER | ST_CS_HEADER);
}
@@ -693,7 +699,7 @@ csv_template_start:
case '?':
if (IN(csv_state, ST_CS_COND))
{
- error(1, __FILE__, __func__, __LINE__,
+ error(ERR_BAD_CND_MARK, __FILE__, __func__, __LINE__,
"Invalid conditional mark");
CLEAR(csv_state, ST_CS_COND);
}
@@ -714,7 +720,7 @@ csv_template_start:
}
else if (IN(csv_state, ST_CS_COND))
{
- error(1, __FILE__, __func__, __LINE__,
+ error(ERR_BAD_EMPTY_CND, __FILE__, __func__, __LINE__,
"Empty conditional before/without nonempty "
"conditional");
CLEAR(csv_state, ST_CS_COND | ST_CS_COND_EMPTY);
@@ -766,13 +772,13 @@ csv_template_start:
default:
if (IN(csv_state, ST_CS_HEADER))
{
- error(1, __FILE__, __func__, __LINE__,
+ error(ERR_BAD_HR_MARK, __FILE__, __func__, __LINE__,
"Invalid header register mark");
CLEAR(csv_state, ST_CS_HEADER);
}
else if (IN(csv_state, ST_CS_REGISTER))
{
- error(1, __FILE__, __func__, __LINE__,
+ error(ERR_BAD_REG_MARK, __FILE__, __func__, __LINE__,
"Invalid register mark");
CLEAR(csv_state, ST_CS_REGISTER);
}
@@ -781,8 +787,6 @@ csv_template_start:
pcsv_template++;
}
goto csv_template_start;
-csv_template_done:
- return 0;
}
static int
@@ -811,7 +815,7 @@ print_image_dimensions(FILE* output, const u8* image_file_prefix, const u8* path
cmd_output = popen(command, "r");
/* popen(3): "The popen() function does not reliably set errno." */
if (!cmd_output)
- return error(1, __FILE__, __func__, __LINE__,
+ return error(ERR_POPEN_FAIL, __FILE__, __func__, __LINE__,
"popen failed");
if (!fgets(cmd_output_line, BUFSIZE, cmd_output))
goto print_dimensions_cleanup;
@@ -827,7 +831,7 @@ print_dimensions_cleanup:
return 0;
}
-static int
+static void
print_meta_var(FILE* output, u8** tsv_header, u8** tsv_register)
{
u8* pvalue;
@@ -837,7 +841,7 @@ print_meta_var(FILE* output, u8** tsv_header, u8** tsv_register)
assert((output != NULL) && (tsv_header != NULL)
&& (tsv_register != NULL));
if (!*tsv_register || !*(tsv_register + 1))
- return 0;
+ return;
pvalue = *(tsv_register + 1);
value_len = strlen((char*)pvalue);
if (*pvalue == '%' && *(pvalue + value_len - 1) == '%')
@@ -854,7 +858,6 @@ print_meta_var(FILE* output, u8** tsv_header, u8** tsv_register)
else
print_output(output, "<meta name=\"%s\" content=\"%s\">\n",
*tsv_register, *(tsv_register + 1));
- return 0;
}
#define PRINTTSVIF(format, arg) \
@@ -869,7 +872,7 @@ print_meta_var(FILE* output, u8** tsv_header, u8** tsv_register)
fprintf(output, format, arg); \
} while (0)
-static int
+static void
print_tsv_row(FILE* output, u8** tsv_header, u8** tsv_register)
{
u8* ptsv_template = tsv_template;
@@ -881,7 +884,7 @@ print_tsv_row(FILE* output, u8** tsv_header, u8** tsv_register)
&& (tsv_register != NULL));
tsv_template_start:
if (!*ptsv_template)
- goto tsv_template_done;
+ return;
if (IN(tsv_state, ST_CS_ESCAPE))
{
PRINTTSVIF("%c", *ptsv_template);
@@ -909,7 +912,7 @@ tsv_template_start:
case '#':
if (IN(tsv_state, ST_CS_HEADER))
{
- error(1, __FILE__, __func__, __LINE__,
+ error(ERR_BAD_HR_MARK, __FILE__, __func__, __LINE__,
"Invalid header register mark");
CLEAR(tsv_state, ST_CS_REGISTER | ST_CS_HEADER);
}
@@ -925,7 +928,7 @@ tsv_template_start:
case '?':
if (IN(tsv_state, ST_CS_COND))
{
- error(1, __FILE__, __func__, __LINE__,
+ error(ERR_BAD_CND_MARK, __FILE__, __func__, __LINE__,
"Invalid conditional mark");
CLEAR(tsv_state, ST_CS_COND);
}
@@ -946,7 +949,7 @@ tsv_template_start:
}
else if (IN(tsv_state, ST_CS_COND))
{
- error(1, __FILE__, __func__, __LINE__,
+ error(ERR_BAD_EMPTY_CND, __FILE__, __func__, __LINE__,
"Empty conditional before/without nonempty "
"conditional");
CLEAR(tsv_state, ST_CS_COND | ST_CS_COND_EMPTY);
@@ -998,13 +1001,13 @@ tsv_template_start:
default:
if (IN(tsv_state, ST_CS_HEADER))
{
- error(1, __FILE__, __func__, __LINE__,
+ error(ERR_BAD_HR_MARK, __FILE__, __func__, __LINE__,
"Invalid header register mark");
CLEAR(tsv_state, ST_CS_HEADER);
}
else if (IN(tsv_state, ST_CS_REGISTER))
{
- error(1, __FILE__, __func__, __LINE__,
+ error(ERR_BAD_REG_MARK, __FILE__, __func__, __LINE__,
"Invalid register mark");
CLEAR(tsv_state, ST_CS_REGISTER);
}
@@ -1013,8 +1016,6 @@ tsv_template_start:
ptsv_template++;
}
goto tsv_template_start;
-tsv_template_done:
- return 0;
}
static int
@@ -1133,7 +1134,7 @@ process_csv(FILE* output, const u8* arg_token,
else
{
if (ANY(state, ST_CSV_BODY | ST_TSV_BODY))
- exit(error(1, __FILE__, __func__, __LINE__,
+ exit(error(ERR_NEST_CSV, __FILE__, __func__, __LINE__,
"Can't nest csv/tsv directives"));
SET(state, ST_CSV_BODY);
if (read_yaml_macros_and_links)
@@ -1142,11 +1143,11 @@ process_csv(FILE* output, const u8* arg_token,
(void)strtok_r((char*)arg_token, " ", (char**)&saveptr);
args = (u8*)strtok_r(NULL, " ", (char**)&saveptr);
if (!args)
- exit(error(EINVAL, __FILE__, __func__, __LINE__,
+ exit(error(ERR_NO_ARG, __FILE__, __func__, __LINE__,
"Arguments required"));
args_len = strlen((char*)args);
if (*args != '"' || *(args + args_len - 1) != '"')
- exit(error(EINVAL, __FILE__, __func__, __LINE__,
+ exit(error(ERR_ARG_NOTSTR, __FILE__, __func__, __LINE__,
"First argument must be a string"));
if (!csv_filename)
CALLOC(csv_filename, char, BUFSIZE);
@@ -1161,8 +1162,11 @@ process_csv(FILE* output, const u8* arg_token,
errno = 0;
csv_iter = (size_t)strtol((char*)args, NULL, 10);
if (errno)
+ {
+ perror(PROGRAMNAME ": strtol");
exit(error(errno, __FILE__, __func__, __LINE__,
"Invalid argument '%s'", args));
+ }
}
}
return 0;
@@ -1294,8 +1298,8 @@ process_image(FILE* output, const u8* image_text, const u8* image_file_prefix,
const int add_figcaption)
{
u8* url = get_value(links, links_count, image_id, NULL);
- process_inline_image(output, image_text, image_file_prefix,
- link_prefix, url, add_link, add_figcaption);
+ process_inline_image(output, image_text, image_file_prefix, link_prefix,
+ url, add_link, add_figcaption);
}
static int
@@ -1324,11 +1328,11 @@ process_incdir(FILE* output, const u8* token, const u8* link_prefix,
(void)strtok_r((char*)token, " ", (char**)&saveptr);
arg = (u8*)strtok_r(NULL, " ", (char**)&saveptr);
if (!arg)
- exit(error(1, __FILE__, __func__, __LINE__,
+ exit(error(ERR_NO_ARG, __FILE__, __func__, __LINE__,
"Arguments required"));
arg_len = strlen((char*)arg);
if (*arg != '"' || *(arg + arg_len - 1) != '"')
- exit(error(1, __FILE__, __func__, __LINE__,
+ exit(error(ERR_ARG_NOTSTR, __FILE__, __func__, __LINE__,
"First argument not string"));
incdir = strdup((char*)(arg + 1));
@@ -1349,15 +1353,18 @@ incdir_next_arg:
while (parg && *parg)
{
if (*parg < '0' || *parg > '9')
- exit(error(1, __FILE__, __func__, __LINE__,
- "Invalid argument"));
+ exit(error(ERR_ARG_NOTNUM, __FILE__, __func__,
+ __LINE__, "Argument not a number"));
parg++;
}
errno = 0;
num = strtol((char*)arg, NULL, 10);
if (errno)
+ {
+ perror(PROGRAMNAME ": strtol");
exit(error(errno, __FILE__, __func__, __LINE__,
"Invalid parameter 'num'"));
+ }
}
pass++;
if (pass < 3)
@@ -1369,7 +1376,7 @@ incdir_done_args:
if ((names_total = scandir(incdir, &namelist, &filter_subdirs,
&reverse_alphacompare))
< 0)
- exit(error(1, __FILE__, __func__, __LINE__,
+ exit(error(ERR_SCANDIR_FAIL, __FILE__, __func__, __LINE__,
"scandir '%s' failed", incdir));
pnamelist = namelist;
names_output = 0;
@@ -1446,7 +1453,7 @@ process_incdir_subdir(FILE* output, const char* subdirname,
&reverse_alphacompare))
< 0)
{
- exit(error(1, __FILE__, __func__, __LINE__,
+ exit(error(ERR_SCANDIR_FAIL, __FILE__, __func__, __LINE__,
"scandir '%s' failed", abs_subdirname));
}
@@ -1458,7 +1465,8 @@ process_incdir_subdir(FILE* output, const char* subdirname,
if (!list_only)
print_output(output, "<article>\n");
fflush(output);
- pid = fork();
+ errno = 0;
+ pid = fork();
if (pid > 0)
wait(&pstatus);
else if (pid == 0)
@@ -1511,7 +1519,8 @@ process_incdir_subdir(FILE* output, const char* subdirname,
formatted_date
= format_date(date, list_timestamp_format);
if (!formatted_date)
- exit(error(1, __FILE__, __func__, __LINE__,
+ exit(error(ERR_FORMAT_DATE_FAIL, __FILE__,
+ __func__, __LINE__,
"format_date error"));
/* Have to temporarily reset this because of potential
@@ -1599,8 +1608,11 @@ process_incdir_subdir(FILE* output, const char* subdirname,
exit(result);
}
else
- exit(error(1, __FILE__, __func__, __LINE__,
+ {
+ perror(PROGRAMNAME ": fork");
+ exit(error(errno, __FILE__, __func__, __LINE__,
"fork failed"));
+ }
if (!list_only)
print_output(output, "</article>\n");
@@ -1622,7 +1634,7 @@ process_incdir_subdir(FILE* output, const char* subdirname,
output_firstcol = 0;
}
-static int
+static void
process_include(FILE* output, const u8* token,
const int read_yaml_macros_and_links)
{
@@ -1645,15 +1657,19 @@ process_include(FILE* output, const u8* token,
assert((output != NULL) && (token != NULL));
ptoken = (u8*)strchr((char*)token, ' ');
if (!input_filename)
- return warning(1,
+ {
+ warning(1,
(u8*)"process_include: Cannot use 'include' in stdin");
+ return;
+ }
if (!ptoken)
- exit(error(1, __FILE__, __func__, __LINE__,
+ exit(error(ERR_NO_ARG, __FILE__, __func__, __LINE__,
"Directive 'include' requires an argument"));
fflush(output);
pipe(arg_pipe_fds);
pipe(output_pipe_fds);
- pid = fork();
+ errno = 0;
+ pid = fork();
if (pid > 0) /* parent */
{
child_output = NULL;
@@ -1760,8 +1776,10 @@ process_include(FILE* output, const u8* token,
exit(result);
}
else
- exit(error(1, __FILE__, __func__, __LINE__, "fork failed"));
- return 0;
+ {
+ perror(PROGRAMNAME ": fork");
+ exit(error(errno, __FILE__, __func__, __LINE__, "fork failed"));
+ }
}
static int
@@ -2010,7 +2028,7 @@ process_macro(FILE* output, const u8* token, const int end_tag)
assert((output != NULL) && (token != NULL));
macro_body = get_value(macros, macros_count, token + 1, NULL);
if (!macro_body)
- exit(error(1, __FILE__, __func__, __LINE__,
+ exit(error(ERR_MACRO_UNDEF, __FILE__, __func__, __LINE__,
"Macro '%s' undefined", token + 1));
eol = (u8*)strrchr((char*)macro_body, '\n');
@@ -2039,7 +2057,7 @@ process_macro_def(FILE* output, const u8* token,
return 0;
}
if (IN(state, ST_MACRO_BODY))
- exit(error(1, __FILE__, __func__, __LINE__,
+ exit(error(ERR_NEST_MACRO, __FILE__, __func__, __LINE__,
"Cannot nest definitions"));
if (read_yaml_macros_and_links)
@@ -2351,7 +2369,7 @@ process_tsv(FILE* output, const u8* arg_token,
else
{
if (ANY(state, ST_CSV_BODY | ST_TSV_BODY))
- exit(error(1, __FILE__, __func__, __LINE__,
+ exit(error(ERR_NEST_CSV, __FILE__, __func__, __LINE__,
"Can't nest csv/tsv directives"));
SET(state, ST_TSV_BODY);
if (read_yaml_macros_and_links)
@@ -2360,11 +2378,11 @@ process_tsv(FILE* output, const u8* arg_token,
(void)strtok_r((char*)arg_token, " ", (char**)&saveptr);
args = (u8*)strtok_r(NULL, " ", (char**)&saveptr);
if (!args)
- exit(error(EINVAL, __FILE__, __func__, __LINE__,
+ exit(error(ERR_NO_ARG, __FILE__, __func__, __LINE__,
"Arguments required"));
args_len = strlen((char*)args);
if (*args != '"' || *(args + args_len - 1) != '"')
- exit(error(EINVAL, __FILE__, __func__, __LINE__,
+ exit(error(ERR_ARG_NOTSTR, __FILE__, __func__, __LINE__,
"First argument must be a string"));
if (!tsv_filename)
CALLOC(tsv_filename, char, BUFSIZE);
@@ -2379,8 +2397,11 @@ process_tsv(FILE* output, const u8* arg_token,
errno = 0;
tsv_iter = (size_t)strtol((char*)args, NULL, 10);
if (errno)
+ {
+ perror(PROGRAMNAME ": strtol");
exit(error(errno, __FILE__, __func__, __LINE__,
"Invalid argument '%s'", args));
+ }
}
}
}
@@ -2405,11 +2426,11 @@ process_tsv_count(FILE* output, const u8* arg_token,
(void)strtok_r((char*)arg_token, " ", (char**)&saveptr);
args = (u8*)strtok_r(NULL, " ", (char**)&saveptr);
if (!args)
- exit(error(EINVAL, __FILE__, __func__, __LINE__,
+ exit(error(ERR_NO_ARG, __FILE__, __func__, __LINE__,
"Arguments required"));
args_len = strlen((char*)args);
if (*args != '"' || *(args + args_len - 1) != '"')
- exit(error(EINVAL, __FILE__, __func__, __LINE__,
+ exit(error(ERR_ARG_NOTSTR, __FILE__, __func__, __LINE__,
"First argument must be a string"));
if (!tsv_filename)
CALLOC(tsv_filename, char, BUFSIZE);
@@ -2470,7 +2491,7 @@ read_csv(FILE* output, const char* filename, csv_callback_t callback)
assert((output != NULL) && (filename != NULL) && (callback != NULL));
csv_delimiter = get_value(vars, vars_count, (u8*)"csv-delimiter", NULL);
- errno = 0;
+ errno = 0;
if (!(csv = fopen(filename, "rt")))
{
perror(PROGRAMNAME ": fopen");
@@ -2910,7 +2931,7 @@ strip_ext(const char* fn, const size_t fn_size)
dot = strrchr(fn, '.');
if (!dot)
return NULL;
- errno = 0;
+ errno = 0;
newname = strndup(fn, fn_size);
if (!newname)
{
@@ -2981,60 +3002,59 @@ slweb_parse(FILE* output, const char* source_filename, const size_t sfn_size,
const u8* buffer, const int body_only,
const int 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* footer_permalink_text = NULL;
- u8* var_incdir_only_summary = NULL;
- u8* image_file_prefix = NULL;
- u8* link_prefix = NULL;
- const u8* pbuffer = NULL;
- u8* line = NULL;
- u8* pline = NULL;
- u8* token = NULL;
- u8* ptoken = NULL;
- u8* link_text = NULL;
- u8* link_macro = NULL;
- u8* temp = NULL;
- u8* temp2 = NULL;
- u8* eol = NULL;
- size_t line_len = 0;
- size_t line_size = 0;
- size_t entity_len = 0;
- size_t token_size = 0;
- size_t token_len = 0;
- size_t value_len = 0;
- size_t link_size = 0;
- size_t heading_count = 0;
- size_t pline_len = 0;
- int break_mark = 0;
- int end_tag = 0;
- int first_line_in_doc = 1;
+ const u8* pbuffer = NULL;
+ u8* author = NULL;
+ u8* date = NULL;
+ u8* eol = NULL;
+ u8* ext_in_permalink = NULL;
+ u8* footer_permalink_text = NULL;
+ u8* header_text = NULL;
+ u8* image_file_prefix = NULL;
+ u8* line = NULL;
+ u8* link_macro = NULL;
+ u8* link_prefix = NULL;
+ u8* link_text = NULL;
+ u8* permalink_url = NULL;
+ u8* pline = NULL;
+ u8* ptoken = NULL;
+ u8* temp = NULL;
+ u8* temp2 = NULL;
+ u8* title = NULL;
+ u8* title_heading_level = NULL;
+ u8* token = NULL;
+ u8* var_add_article_header = NULL;
+ u8* var_add_figcaption = NULL;
+ u8* var_add_footnote_div = NULL;
+ u8* var_add_image_links = NULL;
+ u8* var_incdir_only_summary = NULL;
+ size_t entity_len = 0;
+ size_t heading_count = 0;
+ size_t line_len = 0;
+ size_t line_size = 0;
+ size_t link_size = 0;
+ size_t pline_len = 0;
+ size_t token_len = 0;
+ size_t token_size = 0;
+ size_t value_len = 0;
+ int add_figcaption = 1;
+ int add_footnote_div = 0;
+ int add_image_links = 1;
+ int break_mark = 0;
+ int end_tag = 0;
+ int first_line_in_doc = 1;
+ int footnote_at_line_start = 0;
+ int keep_token = 0;
+ int list_para = 0;
+ int madeby_present = 0;
+ int previous_line_blank = 0;
+ int previous_line_block = 0;
+ int processed_start_of_line = 0;
+ int save_errno;
int skip_change_first_line_in_doc = 0;
int skip_eol = 0;
- int keep_token = 0;
- int previous_line_blank = 0;
- int previous_line_block = 0;
- int processed_start_of_line = 0;
- int add_image_links = 1;
- int add_figcaption = 1;
- int add_footnote_div = 0;
- int list_para = 0;
- int footnote_at_line_start = 0;
- int madeby_present = 0;
unsigned char heading_level = 0;
- if (!buffer)
- exit(error(1, __FILE__, __func__, __LINE__, "Empty buffer"));
-
+ assert((output != NULL) && (buffer != NULL));
title = get_value(vars, vars_count, (u8*)"title", NULL);
title_heading_level
= get_value(vars, vars_count, (u8*)"title-heading-level", NULL);
@@ -4699,7 +4719,8 @@ do_line:
if (strlen((char*)pline) > 1 && *(pline + 1) == '$')
{
if (IN(state, ST_FORMULA))
- exit(error(1, __FILE__, __func__, __LINE__,
+ exit(error(ERR_NEST_MATH, __FILE__, __func__,
+ __LINE__,
"Display formula within an open "
"formula"));
@@ -4731,7 +4752,8 @@ do_line:
else
{
if (IN(state, ST_DISPLAY_FORMULA))
- exit(error(1, __FILE__, __func__, __LINE__,
+ exit(error(ERR_NEST_MATH, __FILE__, __func__,
+ __LINE__,
"Formula within an open display "
"formula"));
if (!(IN(state, ST_FORMULA)))
@@ -5189,14 +5211,15 @@ done_buffer:
free(link_macro);
free(token);
free(line);
- return 0;
+ return ERR_NONE;
parse_alloc_error:
+ save_errno = errno;
free(link_text);
free(link_macro);
free(token);
free(line);
- return 1;
+ return save_errno;
}
int
@@ -5211,7 +5234,7 @@ main(const int argc, const char** argv)
Command cmd = CMD_NONE;
size_t buffer_size = 0;
int body_only = 0;
- int result = 0;
+ int result = ERR_NONE;
UNUSED(argc);
basedir_size = 2;
@@ -5222,9 +5245,9 @@ main(const int argc, const char** argv)
{
if (*arg == '-')
{
+ char c;
arg++;
- char c = *arg++;
- int result;
+ c = *arg++;
if (c == '-')
{
@@ -5256,8 +5279,8 @@ main(const int argc, const char** argv)
exit(usage());
else
{
- error(EINVAL, __FILE__, __func__,
- __LINE__,
+ error(ERR_BAD_CL_ARG, __FILE__,
+ __func__, __LINE__,
"Invalid argument: --%s", arg);
exit(usage());
}
@@ -5285,16 +5308,15 @@ main(const int argc, const char** argv)
cmd = CMD_VERSION;
break;
default:
- error(EINVAL, __FILE__, __func__,
- __LINE__,
+ usage();
+ return error(ERR_BAD_CL_ARG, __FILE__,
+ __func__, __LINE__,
"Invalid argument: -%c", c);
- return usage();
}
}
}
else
{
- int result;
switch (cmd)
{
case CMD_BASEDIR:
@@ -5321,7 +5343,7 @@ main(const int argc, const char** argv)
switch (cmd)
{
case CMD_BASEDIR:
- exit(error(1, __FILE__, __func__, __LINE__,
+ exit(error(ERR_NO_ARG, __FILE__, __func__, __LINE__,
"Argument required"));
case CMD_FULL_VERSION:
version(1);