чување 42c74d764d10f39de4c349c3fc2696c036a044ff
родитељ d5f1aa604fd9ff516d8dc61ed732a50f6c90bc49
Аутор: Страхиња Радић <sr@strahinja.org>
Датум: Thu, 12 Mar 2026 22:13:46 +0100
Implement more robust and organized error checking; wchar_t -> u32
Diffstat:
| M | TODO | | | 2 | -- |
| A | TODO.done | | | 9 | +++++++++ |
| M | defs.h | | | 149 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
| M | table.1.in | | | 20 | ++++++++++++++++++-- |
| M | table.c | | | 373 | +++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- |
измењених датотека: 5, додавања: 334(+), брисања: 219(-)
diff --git a/TODO b/TODO
@@ -1,8 +1,6 @@
TODO
====
-[x] Detect if the output is a terminal and turn off ANSI codes by default if it
- isn't
Legend
diff --git a/TODO.done b/TODO.done
@@ -0,0 +1,9 @@
+Done TODOs
+==========
+
+[x] Detect if the output is a terminal and turn off ANSI codes by default if it
+ isn't
+
+[x] Check data types
+
+[x] Implement more robust error checking for -c nn
diff --git a/defs.h b/defs.h
@@ -12,10 +12,16 @@
#define ANSI_SGR_BOLD_ON "\033[1m"
#define ANSI_SGR_BOLD_OFF "\033[0m"
-#define LEN(x) (sizeof(x) / sizeof(x[0]))
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define UNUSED(x) ((void)(x))
+#define CUSTOM_ERROR_START 200
+
+#define HASH(a, b) ((unsigned int)((a) << 8) | (b))
+#define LEN(x) (sizeof(x) / sizeof(x[0]))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define U32(c) ((u32)(0x00000000 | (c)))
+#define UNUSED(x) ((void)(x))
+
+#define TAB ((u32)0x00000009)
#define ENSURE_SIZE(to, temp, tosize, testsize, fromsize, type) \
do \
@@ -27,7 +33,7 @@
if (!temp) \
{ \
perror(PROGRAMNAME ": realloc"); \
- exit(1); \
+ exit(errno); \
} \
to = temp; \
} \
@@ -40,7 +46,18 @@
if (!ptr) \
{ \
perror(PROGRAMNAME ": calloc"); \
- exit(1); \
+ exit(errno); \
+ } \
+ } while (0)
+
+#define MALLOC(ptr, size) \
+ do \
+ { \
+ ptr = malloc(size); \
+ if (!ptr) \
+ { \
+ perror(PROGRAMNAME ": malloc"); \
+ exit(errno); \
} \
} while (0)
@@ -51,7 +68,7 @@
if (!newptr) \
{ \
perror(PROGRAMNAME ": realloc"); \
- exit(1); \
+ exit(errno); \
} \
ptr = newptr; \
} while (0)
@@ -84,13 +101,19 @@
*pformat++ = num; \
} while (0)
-#define TABLE_ERR_CODE(num) (200 + (num))
-
enum {
- ERR_NONE = 0,
- ERR_BAD_ALIGN = TABLE_ERR_CODE(1),
- ERR_BAD_CL_ARG = TABLE_ERR_CODE(2),
- ERR_UNMATCHED_QUOTE = TABLE_ERR_CODE(3),
+ ERR_NONE,
+ ERR_NO_CL_ARG_PARAM,
+ ERR_BAD_CL_ARG,
+ ERR_BAD_ALIGN,
+ ERR_BAD_NUMBER,
+ ERR_BAD_FORMAT_SPEC,
+ ERR_BAD_QUOTES_ARG,
+ ERR_BAD_SET_SPEC,
+ ERR_ISDIR,
+ ERR_NOTREG_FILE,
+ ERR_UNMATCHED_QUOTE,
+ ERR_STREAM_ERROR,
};
enum { Q_PROCESS, Q_IGNORE };
@@ -131,118 +154,118 @@ typedef enum {
typedef enum { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT } Alignment;
-static const u32* table_symbols[][9] =
+static const u32 table_symbols[][9] =
{
[TABLE_SYMBOLS_ASCII] = {
// ascii
- (u32*)L"+", (u32*)L"-", (u32*)L"+",
- (u32*)L"|", (u32*)L" ", (u32*)L"|",
- (u32*)L"+", (u32*)L"-", (u32*)L"+",
+ U32('+'), U32('-'), U32('+'),
+ U32('|'), U32(' '), U32('|'),
+ U32('+'), U32('-'), U32('+'),
},
[TABLE_SYMBOLS_SINGLE] = {
// single
- (u32*)L"\u250c", (u32*)L"\u2500", (u32*)L"\u2510",
- (u32*)L"\u2502", (u32*)L" ", (u32*)L"\u2502",
- (u32*)L"\u2514", (u32*)L"\u2500", (u32*)L"\u2518",
+ U32(0x250c), U32(0x2500), U32(0x2510),
+ U32(0x2502), U32(' '), U32(0x2502),
+ U32(0x2514), U32(0x2500), U32(0x2518),
},
[TABLE_SYMBOLS_DOUBLE] = {
// double
- (u32*)L"\u2554", (u32*)L"\u2550", (u32*)L"\u2557",
- (u32*)L"\u2551", (u32*)L" ", (u32*)L"\u2551",
- (u32*)L"\u255a", (u32*)L"\u2550", (u32*)L"\u255d",
+ U32(0x2554), U32(0x2550), U32(0x2557),
+ U32(0x2551), U32(' '), U32(0x2551),
+ U32(0x255a), U32(0x2550), U32(0x255d),
},
[TABLE_SYMBOLS_EMPTY] = {
// empty
- (u32*)L" ", (u32*)L" ", (u32*)L" ",
- (u32*)L" ", (u32*)L" ", (u32*)L" ",
- (u32*)L" ", (u32*)L" ", (u32*)L" ",
+ U32(' '), U32(' '), U32(' '),
+ U32(' '), U32(' '), U32(' '),
+ U32(' '), U32(' '), U32(' '),
}
};
-static const u32* table_inner_symbols[][3] =
+static const u32 table_inner_symbols[][3] =
{
[TABLE_INNER_ASCII_ASCII] = {
// ascii -> ascii
- (u32*)L"+",
- (u32*)L"|",
- (u32*)L"+",
+ U32('+'),
+ U32('|'),
+ U32('+'),
},
[TABLE_INNER_SINGLE_SINGLE] = {
// single -> single
- (u32*)L"\u252c",
- (u32*)L"\u2502",
- (u32*)L"\u2534",
+ U32(0x252c),
+ U32(0x2502),
+ U32(0x2534),
},
[TABLE_INNER_SINGLE_DOUBLE] = {
// single -> double
- (u32*)L"\u2565",
- (u32*)L"\u2551",
- (u32*)L"\u2568",
+ U32(0x2565),
+ U32(0x2551),
+ U32(0x2568),
},
[TABLE_INNER_DOUBLE_SINGLE] = {
// double -> single
- (u32*)L"\u2564",
- (u32*)L"\u2502",
- (u32*)L"\u2567",
+ U32(0x2564),
+ U32(0x2502),
+ U32(0x2567),
},
[TABLE_INNER_DOUBLE_DOUBLE] = {
// double -> double
- (u32*)L"\u2566",
- (u32*)L"\u2551",
- (u32*)L"\u2569",
+ U32(0x2566),
+ U32(0x2551),
+ U32(0x2569),
},
[TABLE_INNER_EMPTY_EMPTY] = {
// empty -> empty
- (u32*)L" ",
- (u32*)L" ",
- (u32*)L" ",
+ U32(' '),
+ U32(' '),
+ U32(' '),
},
[TABLE_INNER_ASCII_EMPTY] = {
// ascii -> empty
- (u32*)L"-",
- (u32*)L" ",
- (u32*)L"-",
+ U32('-'),
+ U32(' '),
+ U32('-'),
},
[TABLE_INNER_SINGLE_EMPTY] = {
// single -> empty
- (u32*)L"\u2500",
- (u32*)L" ",
- (u32*)L"\u2500",
+ U32(0x2500),
+ U32(' '),
+ U32(0x2500),
},
[TABLE_INNER_DOUBLE_EMPTY] = {
// double -> empty
- (u32*)L"\u2550",
- (u32*)L" ",
- (u32*)L"\u2550",
+ U32(0x2550),
+ U32(' '),
+ U32(0x2550),
},
[TABLE_INNER_EMPTY_ASCII] = {
// empty -> ascii
- (u32*)L" ",
- (u32*)L"|",
- (u32*)L" ",
+ U32(' '),
+ U32('|'),
+ U32(' '),
},
[TABLE_INNER_EMPTY_SINGLE] = {
// empty -> single
- (u32*)L" ",
- (u32*)L"\u2502",
- (u32*)L" ",
+ U32(' '),
+ U32(0x2502),
+ U32(' '),
},
[TABLE_INNER_EMPTY_DOUBLE] = {
// empty -> double
- (u32*)L" ",
- (u32*)L"\u2551",
- (u32*)L" ",
+ U32(' '),
+ U32(0x2551),
+ U32(' '),
}
};
diff --git a/table.1.in b/table.1.in
@@ -239,11 +239,27 @@ that value is returned as the exit status.
Otherwise, exit status is one of the following:
.Bl -tag -width Ds -offset indent -compact
.It Li 201
-Alignment specification is not valid.
+Command line option is missing a required argument.
.It Li 202
-Command line argument or its parameter are not recognized.
+Command line argument is invalid/unsupported.
.It Li 203
+Alignment specification is not valid.
+.It Li 204
+Numeric argument is not a valid integer.
+.It Li 205
+Format specification is not valid.
+.It Li 206
+Specified quotes literal is invalid.
+.It Li 207
+Set specification is invalid.
+.It Li 208
+File is a directory.
+.It Li 209
+File is not a regular file.
+.It Li 210
A quote is present without its corresponding closing quote.
+.It Li 211
+There has been an input stream error.
.El
.
.Sh EXAMPLES
diff --git a/table.c b/table.c
@@ -23,25 +23,26 @@
" See the file LICENSE for exact copyright and license " \
"details.")
-static int* format = NULL;
-static Alignment* align = NULL;
-static ssize_t line_size;
-static ssize_t outbuf_size;
+static int* format = NULL;
+static Alignment* align = NULL;
static size_t align_size = 0;
static size_t colno = 0;
static size_t current_rune_column = 0;
static size_t current_table_column = 0;
static size_t format_size = 0;
static size_t lineno = 0;
-static size_t rune_columns = 80;
static size_t tab_length = 8;
static size_t table_columns = 0;
-static u32 delimiter = L',';
+static ssize_t line_size;
+static ssize_t outbuf_size;
+static ssize_t rune_columns = 80;
+static u32 delimiter = U32(',');
static long line_max;
static int align_header = 0;
static int border_mode = 0;
static int current_inner_symbol_set = TABLE_INNER_DOUBLE_SINGLE;
static int current_symbol_set = TABLE_SYMBOLS_DOUBLE;
+static int error_code = ERR_NONE;
static int expand_tabs = 0;
static int format_value = 0;
static int in_sgr = 0;
@@ -57,7 +58,6 @@ static const int alignments[] = {
['c'] = ALIGN_CENTER,
['r'] = ALIGN_RIGHT
};
-#define HASH(a,b) ((unsigned int)((a) << 8) | (b))
static const struct {
int border;
int inner;
@@ -87,6 +87,20 @@ static const struct {
[HASH('s','s')] = { .border = TABLE_SYMBOLS_SINGLE,
.inner = TABLE_INNER_SINGLE_SINGLE }
};
+const char* errors[] = {
+ [ERR_NONE] = "",
+ [ERR_NO_CL_ARG_PARAM] = "Option requires an argument: %s",
+ [ERR_BAD_CL_ARG] = "Invalid argument: %s",
+ [ERR_BAD_ALIGN] = "Invalid alignment specification: %s",
+ [ERR_BAD_NUMBER] = "Invalid numeric argument: %s",
+ [ERR_BAD_FORMAT_SPEC] = "Invalid format specification: %s",
+ [ERR_BAD_QUOTES_ARG] = "Invalid quotes specification: %s",
+ [ERR_BAD_SET_SPEC] = "Invalid set specification: %s",
+ [ERR_ISDIR] = "'%s' is a directory",
+ [ERR_NOTREG_FILE] = "'%s' is not a regular file",
+ [ERR_UNMATCHED_QUOTE] = "Unmatched quote",
+ [ERR_STREAM_ERROR] = "Input stream error",
+};
/* clang-format on */
static int skip_while_sgr(const u8* s, size_t* char_delta, int also_print,
@@ -103,13 +117,15 @@ static int
error(const int code, const char* fmt, ...)
{
va_list args;
- char buf[line_max];
+ char* buf = NULL;
assert(fmt != NULL);
+ MALLOC(buf, line_max);
va_start(args, fmt);
- if (vsnprintf(buf, LEN(buf), fmt, args) >= (ssize_t)LEN(buf))
- buf[LEN(buf) - 1] = 0;
+ if (vsnprintf(buf, line_max, fmt, args) >= line_max)
+ buf[line_max - 1] = 0;
va_end(args);
fprintf(stderr, "%s: %s\n", PROGRAMNAME, buf);
+ free(buf);
return code;
}
@@ -124,7 +140,7 @@ number_of_columns(const u8* input, u32 delimiter)
assert(input != NULL);
pinput = input;
- while (pinput && *pinput)
+ while (*pinput)
{
if (u8_rune_to_u32(&uch, pinput, &ch_len))
warning("Malformed UTF-8 at position %td: "
@@ -156,13 +172,13 @@ print_aligned(const u8* s, size_t rune_length, size_t to_size, Alignment align,
if (align == ALIGN_CENTER)
for (i = 0; 2 * i + rune_length < to_size; i++)
{
- printf("%c", alignment_char);
+ fputc(alignment_char, stdout);
(*current_rune_column)++;
}
else if (align == ALIGN_RIGHT)
for (i = 0; i + rune_length < to_size; i++)
{
- printf("%c", alignment_char);
+ fputc(alignment_char, stdout);
(*current_rune_column)++;
}
if (align == ALIGN_LEFT)
@@ -174,13 +190,13 @@ print_aligned(const u8* s, size_t rune_length, size_t to_size, Alignment align,
ps += skipped_chars;
if (!no_ansi && lineno == 0)
- printf("%s", ANSI_SGR_BOLD_ON);
+ fputs(ANSI_SGR_BOLD_ON, stdout);
u8_rune_to_u32(&uch, ps, &ch_len);
output_chars = 0;
while (output_chars != ch_len)
{
- printf("%c", (char)*ps++);
+ fputc((char)*ps++, stdout);
output_chars++;
}
output_runes++;
@@ -207,13 +223,13 @@ print_aligned(const u8* s, size_t rune_length, size_t to_size, Alignment align,
ps += skipped_chars;
if (!no_ansi && lineno == 0)
- printf("%s", ANSI_SGR_BOLD_ON);
+ fputs(ANSI_SGR_BOLD_ON, stdout);
u8_rune_to_u32(&uch, ps, &ch_len);
output_chars = 0;
while (output_chars != ch_len)
{
- printf("%c", (char)*ps++);
+ fputc((char)*ps++, stdout);
output_chars++;
}
output_runes++;
@@ -239,13 +255,13 @@ print_aligned(const u8* s, size_t rune_length, size_t to_size, Alignment align,
ps += skipped_chars;
if (!no_ansi && lineno == 0)
- printf("%s", ANSI_SGR_BOLD_ON);
+ fputs(ANSI_SGR_BOLD_ON, stdout);
u8_rune_to_u32(&uch, ps, &ch_len);
output_chars = 0;
while (output_chars != ch_len)
{
- printf("%c", (char)*ps++);
+ fputc((char)*ps++, stdout);
output_chars++;
}
output_runes++;
@@ -289,29 +305,35 @@ set_align(const char* arg, Alignment** align, size_t* align_size)
}
static int
-set_columns(const char* arg, size_t* cols)
+set_columns(const char* arg, ssize_t* cols)
{
- size_t c;
+ ssize_t c;
+ int result;
assert((arg != NULL) && (cols != NULL));
errno = 0;
- c = strtol(arg, NULL, 10);
- if (errno == EINVAL || errno == ERANGE)
+ if (!*arg)
{
- perror(PROGRAMNAME ": strtol");
- return errno;
+ error_code = ERR_NO_CL_ARG_PARAM;
+ return 1;
+ }
+ result = sscanf(arg, "%zu", &c);
+ if (result == EOF || result < 1)
+ {
+ error_code = ERR_BAD_NUMBER;
+ return 1;
}
else
*cols = c;
- return ERR_NONE;
+ return 0;
}
static int
-set_delimiter(u8* arg, u32* delimiter)
+set_delimiter(const char* arg, u32* delimiter)
{
size_t delimiter_len = 0;
u32 uch;
assert((arg != NULL) && (delimiter != NULL));
- u8_rune_to_u32(&uch, arg, &delimiter_len);
+ u8_rune_to_u32(&uch, (u8*)arg, &delimiter_len);
*delimiter = uch;
return 0;
}
@@ -324,7 +346,7 @@ set_format(const char* arg, int** format, size_t* format_size)
char* token = NULL;
char* ptoken = NULL;
size_t token_size = BUF_DEFAULT;
- int num;
+ int num, result;
assert((arg != NULL) && (format != NULL) && (format_size != NULL));
CALLOC(token, char, token_size);
@@ -338,7 +360,8 @@ set_format(const char* arg, int** format, size_t* format_size)
{
free(token);
free(*format);
- *format = NULL;
+ *format = NULL;
+ error_code = ERR_BAD_FORMAT_SPEC;
return 1;
}
if (*parg == ':')
@@ -347,18 +370,19 @@ set_format(const char* arg, int** format, size_t* format_size)
{
free(token);
free(*format);
- *format = NULL;
+ *format = NULL;
+ error_code = ERR_BAD_FORMAT_SPEC;
return 2;
}
*ptoken = 0;
errno = 0;
- num = strtol(token, NULL, 10);
- if (errno)
+ result = sscanf(token, "%u", &num);
+ if (result == EOF || result < 1)
{
- perror(PROGRAMNAME ": strtol");
free(token);
free(*format);
- *format = NULL;
+ *format = NULL;
+ error_code = ERR_BAD_NUMBER;
return 3;
}
CHECKSET(*format, pformat, *format_size, num);
@@ -373,13 +397,13 @@ set_format(const char* arg, int** format, size_t* format_size)
{
*ptoken = 0;
errno = 0;
- num = strtol(token, NULL, 10);
- if (errno)
+ result = sscanf(token, "%u", &num);
+ if (result == EOF || result < 1)
{
- perror(PROGRAMNAME ": strtol");
free(token);
free(*format);
- *format = NULL;
+ *format = NULL;
+ error_code = ERR_BAD_NUMBER;
return 3;
}
CHECKSET(*format, pformat, *format_size, num);
@@ -397,7 +421,10 @@ set_quotes_behavior(const char* arg, int* quotes)
else if (!strcmp(arg, "ignore"))
*quotes = Q_IGNORE;
else
+ {
+ error_code = ERR_BAD_QUOTES_ARG;
return 1;
+ }
return 0;
}
@@ -408,14 +435,20 @@ set_symbol_set(char* arg, int* current_symbol_set, int* current_inner_symbol_set
&& (current_inner_symbol_set != NULL));
if (!arg[0] || !arg[1] || arg[2] || !strchr("ades", arg[0])
|| !strchr("ades", arg[1]))
+ {
+ error_code = ERR_BAD_SET_SPEC;
return 1;
+ }
assert((arg[0] == 'a') || (arg[0] == 'd') || (arg[0] == 'e')
|| (arg[0] == 's') || (arg[1] == 'a') || (arg[1] == 'd')
|| (arg[1] == 'e') || (arg[1] == 's'));
if (!strcmp(arg, "ad") || !strcmp(arg, "as") || !strcmp(arg, "ad")
|| !strcmp(arg, "as") || !strcmp(arg, "da")
|| !strcmp(arg, "sa"))
+ {
+ error_code = ERR_BAD_SET_SPEC;
return 1;
+ }
*current_symbol_set = symbol_sets[HASH(arg[0], arg[1])].border;
*current_inner_symbol_set = symbol_sets[HASH(arg[0], arg[1])].inner;
return 0;
@@ -442,8 +475,8 @@ skip_while_sgr(const u8* s, size_t* char_delta, int also_print, int whole_string
if (also_print)
{
- printf("%c", (char)*ps++);
- printf("%c", (char)*ps++);
+ fputc((char)*ps++, stdout);
+ fputc((char)*ps++, stdout);
}
else
ps += 2;
@@ -452,7 +485,7 @@ skip_while_sgr(const u8* s, size_t* char_delta, int also_print, int whole_string
while (*ps && *(ps - 1) != 'm')
{
if (also_print)
- printf("%c", (char)*ps++);
+ fputc((char)*ps++, stdout);
else
ps++;
(*char_delta)++;
@@ -464,16 +497,15 @@ skip_while_sgr(const u8* s, size_t* char_delta, int also_print, int whole_string
static int
startswith(const char* s, const char* what)
{
- const char* ps = s;
assert((s != NULL) && (what != NULL));
- while (*ps && *what)
+ while (*s && *s == *what)
{
- if (*what && *ps != *what)
+ if (*s != *what)
return 0;
- ps++;
+ s++;
what++;
}
- return 1;
+ return *what == 0;
}
static int
@@ -489,7 +521,7 @@ usage(void)
" [-s <set> | --symbols=<set>] [-t | --expand-tabs]"
" [-y | --yes-ansi] [pathname]\n",
PROGRAMNAME, PROGRAMNAME);
- return ERR_NONE;
+ return 0;
}
static int
@@ -498,20 +530,22 @@ version(const int full)
printf("%s %s, committed on %s\n", PROGRAMNAME, VERSION, DATE);
if (full)
puts(COPYRIGHT);
- return ERR_NONE;
+ return 0;
}
static void
warning(const char* fmt, ...)
{
va_list args;
- char buf[line_max];
+ char* buf = NULL;
assert(fmt != NULL);
+ MALLOC(buf, line_max);
va_start(args, fmt);
- if (vsnprintf(buf, LEN(buf), fmt, args) >= (ssize_t)LEN(buf))
- buf[LEN(buf) - 1] = 0;
+ if (vsnprintf(buf, line_max, fmt, args) >= line_max)
+ buf[line_max - 1] = 0;
va_end(args);
fprintf(stderr, "%s: %s\n", PROGRAMNAME, buf);
+ free(buf);
}
static int
@@ -553,7 +587,7 @@ main(int argc, char** argv)
if (pledge("stdio rpath unveil", NULL) < 0)
{
perror(PROGRAMNAME ": pledge");
- exit(1);
+ exit(errno);
}
#endif
@@ -564,7 +598,7 @@ main(int argc, char** argv)
if (!strcmp(progname, "tsvtable"))
{
- delimiter = L'\t';
+ delimiter = TAB;
quotes = Q_IGNORE;
}
else if (!strcmp(progname, "tablep"))
@@ -618,10 +652,7 @@ do_arg:
{
arg += strlen("align=");
if (set_align(arg, &align, &align_size))
- exit(error(ERR_BAD_ALIGN,
- "Invalid alignment "
- "specification: '%s'",
- arg));
+ goto main_done;
}
else if (!strcmp(arg, "border-mode"))
border_mode = 1;
@@ -629,26 +660,21 @@ do_arg:
{
arg += strlen("columns=");
if (set_columns(arg, &rune_columns))
- exit(error(ERR_BAD_CL_ARG,
- "Invalid argument: "
- "'%s'",
- arg));
+ goto main_done;
}
else if (startswith(arg, "delimiter="))
{
arg += strlen("delimiter=");
- if (set_delimiter((u8*)arg, &delimiter))
- exit(error(ERR_BAD_CL_ARG,
- "Invalid argument: "
- "'%s'",
- arg));
+ if (set_delimiter(arg, &delimiter))
+ goto main_done;
}
else if (!strcmp(arg, "expand-tabs"))
expand_tabs = 1;
else if (startswith(arg, "format="))
{
arg += strlen("format=");
- set_format(arg, &format, &format_size);
+ if (set_format(arg, &format, &format_size))
+ goto main_done;
}
else if (!strcmp(arg, "msdos"))
msdos = 1;
@@ -660,30 +686,27 @@ do_arg:
{
arg += strlen("quotes=");
if (set_quotes_behavior(arg, "es))
- exit(error(ERR_BAD_CL_ARG,
- "Invalid argument: "
- "'%s'",
- arg));
+ goto main_done;
}
else if (startswith(arg, "symbols="))
{
arg += strlen("symbols=");
if (set_symbol_set(arg, ¤t_symbol_set,
¤t_inner_symbol_set))
- exit(error(ERR_BAD_CL_ARG,
- "Invalid argument: "
- "'%s'",
- arg));
+ goto main_done;
}
else if (!strcmp(arg, "yes-ansi"))
no_ansi = 0;
else if (!strcmp(arg, "help"))
- return usage();
+ {
+ usage();
+ goto main_done;
+ }
else
{
(void)usage();
- exit(error(ERR_BAD_CL_ARG,
- "Invalid argument: --%s", arg));
+ error_code = ERR_BAD_CL_ARG;
+ goto main_done;
}
}
else
@@ -713,8 +736,7 @@ do_arg:
break;
case 'h':
usage();
- exit(ERR_NONE);
- break;
+ goto main_done;
case 'm':
msdos = 1;
break;
@@ -744,12 +766,19 @@ do_arg:
break;
default:
(void)usage();
- exit(error(ERR_BAD_CL_ARG,
- "Invalid argument: -%c", c));
+ error_code = ERR_BAD_CL_ARG;
+ goto main_done;
}
/* Gobble up the rest of the arg ("-d:" etc) */
if (*arg)
goto continue_current_arg;
+ else if (cmd == CMD_COLUMNS || cmd == CMD_DELIMITER
+ || cmd == CMD_FORMAT || cmd == CMD_SYMBOLS
+ || cmd == CMD_QUOTES)
+ {
+ error_code = ERR_NO_CL_ARG_PARAM;
+ goto main_done;
+ }
}
}
else
@@ -758,40 +787,33 @@ do_arg:
if (cmd == CMD_ALIGN)
{
if (set_align(arg, &align, &align_size))
- exit(error(ERR_BAD_ALIGN,
- "Invalid alignment specification: '%s'",
- arg));
+ goto main_done;
}
else if (cmd == CMD_COLUMNS)
{
if (set_columns(arg, &rune_columns))
- exit(error(ERR_BAD_CL_ARG,
- "Invalid argument: '%s'", arg));
+ goto main_done;
}
else if (cmd == CMD_DELIMITER)
{
- if (set_delimiter((u8*)arg, &delimiter))
- exit(error(ERR_BAD_CL_ARG,
- "Invalid argument: '%s'", arg));
+ if (set_delimiter(arg, &delimiter))
+ goto main_done;
}
else if (cmd == CMD_FORMAT)
{
if (set_format(arg, &format, &format_size))
- exit(error(ERR_BAD_CL_ARG,
- "Invalid argument: '%s'", arg));
+ goto main_done;
}
else if (cmd == CMD_QUOTES)
{
if (set_quotes_behavior(arg, "es))
- exit(error(ERR_BAD_CL_ARG,
- "Invalid argument: '%s'", arg));
+ goto main_done;
}
else if (cmd == CMD_SYMBOLS)
{
if (set_symbol_set(arg, ¤t_symbol_set,
¤t_inner_symbol_set))
- exit(error(ERR_BAD_CL_ARG,
- "Invalid argument: '%s'", arg));
+ goto main_done;
}
else if (filename)
warning("Additional argument ignored: '%s'", arg);
@@ -828,14 +850,19 @@ done_arg:
exit(errno);
}
if (S_ISDIR(st.st_mode))
- exit(error(EISDIR, "Is a directory: '%s'", filename));
+ {
+ error_code = ERR_ISDIR;
+ goto main_done;
+ }
+ if (!S_ISREG(st.st_mode))
+ {
+ error_code = ERR_NOTREG_FILE;
+ goto main_done;
+ }
errno = 0;
input = fopen(filename, "r");
if (!input)
- {
- perror(PROGRAMNAME ": fopen");
- exit(error(errno, "Cannot open '%s'", filename));
- }
+ goto main_done;
}
else
input = stdin;
@@ -851,7 +878,14 @@ do_input:
goto done_input;
if (!fgets((char*)pline, line_size - (pline - line), input))
+ {
+ if (ferror(input))
+ {
+ error_code = ERR_STREAM_ERROR;
+ goto main_done;
+ }
goto done_input;
+ }
eol = strchr((char*)pline, '\n');
if (eol)
@@ -890,8 +924,11 @@ do_input:
table_columns = 1;
/* Sanity check */
- if (rune_columns < table_columns + 2)
+ if (rune_columns < 0 || rune_columns < table_columns + 2)
+ {
+ warning("Columns adjusted to %u", table_columns + 2);
rune_columns = table_columns + 2;
+ }
assert(rune_columns >= table_columns + 2);
if (format && !border_mode)
@@ -923,9 +960,9 @@ do_column:
if (current_rune_column == 0)
{
u8len = u32_rune_to_u8(u8ch,
- *table_symbols[current_symbol_set][0]);
+ table_symbols[current_symbol_set][0]);
u8ch[u8len] = 0;
- printf("%s", u8ch);
+ fputs((const char*)u8ch, stdout);
column_start++;
}
else if (!within_column(column_start, current_rune_column))
@@ -933,18 +970,18 @@ do_column:
if (current_table_column == table_columns - 1)
{
u8len = u32_rune_to_u8(u8ch,
- *table_symbols[current_symbol_set][2]);
+ table_symbols[current_symbol_set][2]);
u8ch[u8len] = 0;
- printf("%s", u8ch);
+ fputs((const char*)u8ch, stdout);
}
else
{
/* clang-format off */
- u8len = u32_rune_to_u8(u8ch, *table_inner_symbols[
+ u8len = u32_rune_to_u8(u8ch, table_inner_symbols[
current_inner_symbol_set][0]);
/* clang-format on */
u8ch[u8len] = 0;
- printf("%s", u8ch);
+ fputs((const char*)u8ch, stdout);
column_start++;
if (format)
column_start
@@ -957,15 +994,15 @@ do_column:
else
{
u8len = u32_rune_to_u8(u8ch,
- *table_symbols[current_symbol_set][1]);
+ table_symbols[current_symbol_set][1]);
u8ch[u8len] = 0;
- printf("%s", u8ch);
+ fputs((const char*)u8ch, stdout);
}
current_rune_column++;
goto do_column;
done_columns:
- printf("\n");
+ puts("");
output_lines++;
goto not_first;
@@ -973,22 +1010,22 @@ empty_line:
current_table_column = 0;
current_rune_column = 0;
column_start = 0;
- u8len = u32_rune_to_u8(u8ch, *table_symbols[current_symbol_set][3]);
+ u8len = u32_rune_to_u8(u8ch, table_symbols[current_symbol_set][3]);
u8ch[u8len] = 0;
- printf("%s", u8ch);
+ fputs((const char*)u8ch, stdout);
while (current_table_column + 1 < table_columns)
{
while (within_column(column_start, current_rune_column))
{
- printf("%c", alignment_char);
+ fputc(alignment_char, stdout);
current_rune_column++;
}
/* clang-format off */
u8len = u32_rune_to_u8(u8ch,
- *table_inner_symbols[current_inner_symbol_set][1]);
+ table_inner_symbols[current_inner_symbol_set][1]);
/* clang-format on */
u8ch[u8len] = 0;
- printf("%s", u8ch);
+ fputs((const char*)u8ch, stdout);
column_start++;
if (format)
column_start += *(format + current_table_column);
@@ -999,12 +1036,12 @@ empty_line:
}
while (within_column(column_start, current_rune_column))
{
- printf("%c", alignment_char);
+ fputc(alignment_char, stdout);
current_rune_column++;
}
- u8len = u32_rune_to_u8(u8ch, *table_symbols[current_symbol_set][5]);
+ u8len = u32_rune_to_u8(u8ch, table_symbols[current_symbol_set][5]);
u8ch[u8len] = 0;
- printf("%s\n", u8ch);
+ puts((const char*)u8ch);
pline = line;
goto do_input;
@@ -1015,17 +1052,18 @@ not_first:
column_start = 0;
in_sgr = 0;
- u8len = u32_rune_to_u8(u8ch, *table_symbols[current_symbol_set][3]);
+ u8len = u32_rune_to_u8(u8ch, table_symbols[current_symbol_set][3]);
u8ch[u8len] = 0;
- printf("%s", u8ch);
+ fputs((const char*)u8ch, stdout);
do_line:
if (!pline || !*pline)
{
if (in_quote)
{
- printf("\n");
- exit(error(ERR_UNMATCHED_QUOTE, "Unmatched quote"));
+ puts("");
+ error_code = ERR_UNMATCHED_QUOTE;
+ goto main_done;
}
else
goto done_line;
@@ -1052,7 +1090,7 @@ continue_line:
(ssize_t)(outbuf_size + sizeof((u8*)ANSI_SGR_BOLD_OFF)), u8);
poutbuf = outbuf + outbuf_len;
u8_rune_to_u32(&uch, pline, &ch_len);
- if (uch == (u32)L'\033' && *(pline + 1) == '[')
+ if (uch == U32('\033') && *(pline + 1) == '[')
{
in_sgr = 1;
if (!no_ansi)
@@ -1063,7 +1101,7 @@ continue_line:
pline++;
colno++;
}
- else if (uch == (u32)L'm')
+ else if (uch == U32('m'))
{
if (!no_ansi || !in_sgr)
*poutbuf++ = *pline;
@@ -1101,13 +1139,13 @@ continue_line:
(lineno == 0 && !align_header)
? ALIGN_LEFT
: (current_table_column < align_size
- ? align[current_table_column]
- : ALIGN_LEFT),
+ ? align[current_table_column]
+ : ALIGN_LEFT),
¤t_rune_column);
while (within_column(column_start, current_rune_column))
{
- printf("%c", alignment_char);
+ fputc(alignment_char, stdout);
current_rune_column++;
}
@@ -1123,11 +1161,11 @@ continue_line:
if (current_table_column != table_columns - 1)
{
/* clang-format off */
- u8len = u32_rune_to_u8(u8ch, *table_inner_symbols[
+ u8len = u32_rune_to_u8(u8ch, table_inner_symbols[
current_inner_symbol_set][1]);
/* clang-format on */
u8ch[u8len] = 0;
- printf("%s", u8ch);
+ fputs((const char*)u8ch, stdout);
current_rune_column++;
current_table_column++;
}
@@ -1148,7 +1186,7 @@ continue_line:
pline++;
colno++;
}
- else if (uch == (u32)L'\t' && expand_tabs)
+ else if (uch == TAB && expand_tabs)
{
while ((current_rune_column + outbufrunelen) % tab_length != 0)
{
@@ -1174,7 +1212,7 @@ continue_line:
done_line:
if (!no_ansi && lineno == 0)
- printf("%s", ANSI_SGR_BOLD_OFF);
+ fputs(ANSI_SGR_BOLD_OFF, stdout);
if (*outbuf)
{
@@ -1189,8 +1227,8 @@ done_line:
(lineno == 0 && !align_header)
? ALIGN_LEFT
: (current_table_column < align_size
- ? align[current_table_column]
- : ALIGN_LEFT),
+ ? align[current_table_column]
+ : ALIGN_LEFT),
¤t_rune_column);
*outbuf = 0;
@@ -1199,13 +1237,13 @@ done_line:
{
while (within_column(column_start, current_rune_column))
{
- printf("%c", alignment_char);
+ fputc(alignment_char, stdout);
current_rune_column++;
}
u8len = u32_rune_to_u8(u8ch,
- *table_inner_symbols[current_inner_symbol_set][1]);
+ table_inner_symbols[current_inner_symbol_set][1]);
u8ch[u8len] = 0;
- printf("%s", u8ch);
+ fputs((const char*)u8ch, stdout);
column_start++;
if (format)
column_start += *(format + current_table_column);
@@ -1216,13 +1254,13 @@ done_line:
}
while (within_column(column_start, current_rune_column))
{
- printf("%c", alignment_char);
+ fputc(alignment_char, stdout);
current_rune_column++;
}
- u8len = u32_rune_to_u8(u8ch, *table_symbols[current_symbol_set][5]);
+ u8len = u32_rune_to_u8(u8ch, table_symbols[current_symbol_set][5]);
u8ch[u8len] = 0;
- printf("%s\n", u8ch);
+ puts((const char*)u8ch);
output_lines++;
lineno++;
@@ -1248,7 +1286,7 @@ do_bottom_border:
if (current_rune_column == 0)
{
u8len = u32_rune_to_u8(u8ch,
- *table_symbols[current_symbol_set][6]);
+ table_symbols[current_symbol_set][6]);
column_start++;
}
else if (!within_column(column_start, current_rune_column))
@@ -1256,14 +1294,13 @@ do_bottom_border:
if (current_table_column == table_columns - 1)
{
u8len = u32_rune_to_u8(u8ch,
- *table_symbols[current_symbol_set][8]);
+ table_symbols[current_symbol_set][8]);
current_table_column++;
}
else
{
u8len = u32_rune_to_u8(u8ch,
- *table_inner_symbols[current_inner_symbol_set]
- [2]);
+ table_inner_symbols[current_inner_symbol_set][2]);
column_start++;
if (format)
column_start
@@ -1275,28 +1312,60 @@ do_bottom_border:
}
else
u8len = u32_rune_to_u8(u8ch,
- *table_symbols[current_symbol_set][7]);
+ table_symbols[current_symbol_set][7]);
u8ch[u8len] = 0;
- printf("%s", u8ch);
+ fputs((const char*)u8ch, stdout);
current_rune_column++;
goto do_bottom_border;
done_bottom_border:
- printf("\n");
+ puts("");
output_lines++;
skip_bottom_border:
+main_done:
+ if (errno)
+ perror(PROGRAMNAME);
+
free(format);
free(align);
if (opause)
{
- char buf[line_max];
- printf("Press Enter to continue: ");
+ char* buf = NULL;
+ MALLOC(buf, line_max);
+ puts("Press Enter to continue: ");
fflush(stdout);
clearerr(stdin);
fgets(buf, line_max, stdin);
+ free(buf);
}
- fclose(input);
- return 0;
+ if (input)
+ fclose(input);
+
+ switch (error_code)
+ {
+ case ERR_NONE:
+ break;
+ case ERR_NO_CL_ARG_PARAM:
+ case ERR_BAD_CL_ARG:
+ case ERR_BAD_ALIGN:
+ error(error_code, errors[error_code], *argv);
+ break;
+ case ERR_ISDIR:
+ case ERR_NOTREG_FILE:
+ error(error_code, errors[error_code], filename);
+ break;
+ case ERR_BAD_NUMBER:
+ case ERR_BAD_FORMAT_SPEC:
+ case ERR_BAD_QUOTES_ARG:
+ case ERR_BAD_SET_SPEC:
+ error(error_code, errors[error_code], arg);
+ break;
+ default:
+ error(error_code, errors[error_code]);
+ break;
+ }
+ return errno ? errno
+ : (error_code ? CUSTOM_ERROR_START + error_code : 0);
}