чување 0d0724789508e45b2fbf6b206e7ae6d3d28b3cb6
родитељ 2be3b25e469dff8e2007e07b42b9cb202d090613
Аутор: Страхиња Радић <sr@strahinja.org>
Датум: Tue, 23 Jul 2024 20:24:42 +0200
Add table-specific exit status codes; table.c: Sort functions, add
more assert calls
Diffstat:
| M | defs.h | | | 35 | ++++++++++++++++++++++------------- |
| M | table.1.in | | | 15 | ++++++++++++++- |
| M | table.c | | | 593 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
измењених датотека: 3, додавања: 339(+), брисања: 304(-)
diff --git a/defs.h b/defs.h
@@ -84,21 +84,16 @@
*pformat++ = num; \
} while (0)
-typedef enum {
- CMD_NONE,
- CMD_ALIGN,
- CMD_COLUMNS,
- CMD_DELIMITER,
- CMD_FORMAT,
- CMD_QUOTES,
- CMD_SYMBOLS,
- CMD_VERSION,
- CMD_FULL_VERSION
-} Command;
+#define TABLE_ERR_CODE(num) (200 + (num))
-enum { Q_PROCESS, Q_IGNORE };
+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),
+};
-typedef enum { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT } Alignment;
+enum { Q_PROCESS, Q_IGNORE };
enum {
TABLE_SYMBOLS_ASCII,
@@ -122,6 +117,20 @@ enum {
TABLE_INNER_EMPTY_DOUBLE,
};
+typedef enum {
+ CMD_NONE,
+ CMD_ALIGN,
+ CMD_COLUMNS,
+ CMD_DELIMITER,
+ CMD_FORMAT,
+ CMD_QUOTES,
+ CMD_SYMBOLS,
+ CMD_VERSION,
+ CMD_FULL_VERSION
+} Command;
+
+typedef enum { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT } Alignment;
+
static const u32* table_symbols[][9] =
{
[TABLE_SYMBOLS_ASCII] = {
diff --git a/table.1.in b/table.1.in
@@ -29,7 +29,7 @@
.Sh COMMAND ALIASES
.Bl -column -offset 1m "123456"
.It Nm tablep Ta is a synonym for Ql "table -p" .
-.It Nm tsvtable Ta is a synonym for Ql "table -d \(dq$(printf '\et')\(dq -q ignore" .
+.It Nm tsvtable Ta is a synonym for Ql table -d Qo $(printf '\et') Qc -q ignore .
.El
.
.Sh DESCRIPTION
@@ -232,6 +232,19 @@ This switch enforces the output of ANSI SGR codes, even in that case.
.
.Sh EXIT STATUS
.Ex -std
+.Pp
+For errors caused by unsuccessful calls to libc functions setting
+.Va errno ,
+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.
+.It Li 202
+Command line argument or its parameter are not recognized.
+.It Li 203
+A quote is present without its corresponding closing quote.
+.El
.
.Sh EXAMPLES
.Bl -bullet -width 0
diff --git a/table.c b/table.c
@@ -2,8 +2,6 @@
* any later version. Copyright (C) 2020-2024 Страхиња Радић.
* See the file LICENSE for exact copyright and license details. */
-#define NDEBUG
-
#include <assert.h>
#include <errno.h>
#include <limits.h>
@@ -12,6 +10,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
#include <unistd.h>
#include "defs.h"
@@ -24,33 +23,33 @@
" See the file LICENSE for exact copyright and license " \
"details.")
-long line_max;
-ssize_t line_size;
-ssize_t outbuf_size;
-size_t colno = 0;
-size_t lineno = 0;
-int current_symbol_set = TABLE_SYMBOLS_DOUBLE;
-int current_inner_symbol_set = TABLE_INNER_DOUBLE_SINGLE;
-size_t current_table_column = 0;
-size_t current_rune_column = 0;
-size_t table_columns = 0;
-size_t rune_columns = 80;
-size_t tab_length = 8;
-u32 delimiter = L',';
-int* format = NULL;
-size_t format_size = 0;
-int format_value = 0;
-Alignment* align = NULL;
-int align_header = 0;
-size_t align_size = 0;
-int border_mode = 0;
-int no_ansi = 0;
-int in_sgr = 0;
-int msdos = 0;
-int opause = 0;
-int expand_tabs = 0;
-int quotes = Q_PROCESS;
-char alignment_char = ' ';
+static int* format = NULL;
+static Alignment* align = NULL;
+static ssize_t line_size;
+static ssize_t outbuf_size;
+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 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 expand_tabs = 0;
+static int format_value = 0;
+static int in_sgr = 0;
+static int msdos = 0;
+static int no_ansi = 0;
+static int opause = 0;
+static int quotes = Q_PROCESS;
+static char alignment_char = ' ';
/* clang-format off */
static const int alignments[] = {
@@ -90,36 +89,22 @@ static const struct {
};
/* clang-format on */
-int
-version(const int full)
-{
- printf("%s %s, committed on %s\n", PROGRAMNAME, VERSION, DATE);
- if (full)
- puts(COPYRIGHT);
- return 0;
-}
+static int skip_while_sgr(const u8* s, size_t* char_delta, int also_print,
+ int whole_string);
+static void warning(const char* fmt, ...);
-int
-usage(void)
+static size_t
+current_column_width(void)
{
- printf("Usage:\t%s -h | --help | -V | --full-version | -v | --version\n"
- "\t%s [-a <alignment> | --align=<alignment>]"
- " [-b | --border-mode] [-c <cols> | --columns=<cols>]"
- " [-D | --align-dot] [-d <delim> | --delimiter=<delim>]"
- " [-f <format> | --format=<format>] [-H | --align-header]"
- " [-m | --msdos] [-n | --no-ansi] [-p | --pause]"
- " [-q <behavior> | --quotes=<behavior>]"
- " [-s <set> | --symbols=<set>] [-t | --expand-tabs]"
- " [-y | --yes-ansi] [pathname]\n",
- PROGRAMNAME, PROGRAMNAME);
- return 0;
+ return format ? format[current_table_column] : format_value;
}
-int
+static int
error(const int code, const char* fmt, ...)
{
va_list args;
char buf[line_max];
+ assert(fmt != NULL);
va_start(args, fmt);
if (vsnprintf(buf, LEN(buf), fmt, args) >= (ssize_t)LEN(buf))
buf[LEN(buf) - 1] = 0;
@@ -128,77 +113,166 @@ error(const int code, const char* fmt, ...)
return code;
}
-void
-warning(const char* fmt, ...)
+/* Return number of columns based on the input line */
+static size_t
+number_of_columns(const u8* input, u32 delimiter)
{
- va_list args;
- char buf[line_max];
- va_start(args, fmt);
- if (vsnprintf(buf, LEN(buf), fmt, args) >= (ssize_t)LEN(buf))
- buf[LEN(buf) - 1] = 0;
- va_end(args);
- fprintf(stderr, "%s: %s\n", PROGRAMNAME, buf);
+ const u8* pinput = NULL;
+ u32 uch;
+ size_t ch_len = 0;
+ size_t result = 1;
+
+ assert(input != NULL);
+ pinput = input;
+ while (pinput && *pinput)
+ {
+ if (u8_rune_to_u32(&uch, pinput, &ch_len))
+ warning("Malformed UTF-8 at position %td: "
+ "uch=%02X, "
+ "pinput=%02X",
+ pinput - input, uch, *pinput);
+ if (uch == delimiter)
+ result++;
+ pinput += ch_len;
+ }
+ return result;
}
-int
-startswith(const char* s, const char* what)
+static int
+print_aligned(const u8* s, size_t rune_length, size_t to_size, Alignment align,
+ size_t* current_rune_column)
{
- const char* ps = s;
+ const u8* ps = s;
+ u32 uch;
+ size_t i;
+ size_t ch_len;
+ size_t colwidth = current_column_width();
+ size_t output_runes = 0;
+ size_t skipped_runes = 0;
+ size_t output_chars = 0;
+ size_t skipped_chars = 0;
- if (!ps || !what)
- return 0;
+ assert((s != NULL) && (current_rune_column != NULL));
+ if (align == ALIGN_CENTER)
+ for (i = 0; 2 * i + rune_length < to_size; i++)
+ {
+ printf("%c", alignment_char);
+ (*current_rune_column)++;
+ }
+ else if (align == ALIGN_RIGHT)
+ for (i = 0; i + rune_length < to_size; i++)
+ {
+ printf("%c", alignment_char);
+ (*current_rune_column)++;
+ }
+ if (align == ALIGN_LEFT)
+ {
+ output_runes = 0;
+ while (output_runes != MIN(rune_length, colwidth))
+ {
+ skip_while_sgr(ps, &skipped_chars, 1, 0);
+ ps += skipped_chars;
- while (*ps && *what)
+ if (!no_ansi && lineno == 0)
+ printf("%s", ANSI_SGR_BOLD_ON);
+
+ u8_rune_to_u32(&uch, ps, &ch_len);
+ output_chars = 0;
+ while (output_chars != ch_len)
+ {
+ printf("%c", (char)*ps++);
+ output_chars++;
+ }
+ output_runes++;
+ }
+ skip_while_sgr(ps, &skipped_chars, 1, 1);
+ }
+ else if (align == ALIGN_CENTER)
{
- if (*what && *ps != *what)
- return 0;
- ps++;
- what++;
+ skipped_runes = 0;
+ while (2 * skipped_runes + to_size < rune_length)
+ {
+ skip_while_sgr(ps, &skipped_chars, 1, 0);
+ ps += skipped_chars;
+
+ u8_rune_to_u32(&uch, ps, &ch_len);
+ ps += ch_len;
+ skipped_runes++;
+ }
+
+ output_runes = 0;
+ while (output_runes != MIN(rune_length, colwidth))
+ {
+ skip_while_sgr(ps, &skipped_chars, 1, 0);
+ ps += skipped_chars;
+
+ if (!no_ansi && lineno == 0)
+ printf("%s", ANSI_SGR_BOLD_ON);
+
+ u8_rune_to_u32(&uch, ps, &ch_len);
+ output_chars = 0;
+ while (output_chars != ch_len)
+ {
+ printf("%c", (char)*ps++);
+ output_chars++;
+ }
+ output_runes++;
+ }
+ skip_while_sgr(ps, &skipped_chars, 1, 1);
}
+ else if (align == ALIGN_RIGHT)
+ {
+ skipped_runes = 0;
+ while (skipped_runes + to_size < rune_length)
+ {
+ skip_while_sgr(ps, &skipped_chars, 1, 0);
+ ps += skipped_chars;
- return 1;
-}
+ u8_rune_to_u32(&uch, ps, &ch_len);
+ ps += ch_len;
+ skipped_runes++;
+ }
+ output_runes = 0;
+ while (output_runes != MIN(rune_length, colwidth))
+ {
+ skip_while_sgr(ps, &skipped_chars, 1, 0);
+ ps += skipped_chars;
-size_t
-current_column_width(void)
-{
- return format ? format[current_table_column] : format_value;
-}
+ if (!no_ansi && lineno == 0)
+ printf("%s", ANSI_SGR_BOLD_ON);
-int
-within_column(size_t column_start, size_t current_rune_column)
-{
- return current_rune_column < column_start + current_column_width();
+ u8_rune_to_u32(&uch, ps, &ch_len);
+ output_chars = 0;
+ while (output_chars != ch_len)
+ {
+ printf("%c", (char)*ps++);
+ output_chars++;
+ }
+ output_runes++;
+ }
+ skip_while_sgr(ps, &skipped_chars, 1, 1);
+ }
+ (*current_rune_column) += output_runes;
+ return 0;
}
-int
-set_symbol_set(char* arg, int* current_symbol_set, int* current_inner_symbol_set)
+static unsigned int
+round_div(unsigned int a, unsigned int b)
{
- if (!arg[0] || !arg[1] || arg[2] || !strchr("ades", arg[0])
- || !strchr("ades", arg[1]))
- 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"))
- 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;
+ assert(b != 0);
+ return (a + (b / 2)) / b;
}
-int
+static int
set_align(const char* arg, Alignment** align, size_t* align_size)
{
- const char* parg = arg;
Alignment* palign = NULL;
+ const char* parg = arg;
+ assert((arg != NULL) && (align != NULL) && (align_size != NULL));
*align_size = strlen(arg);
CALLOC(*align, Alignment, *align_size);
palign = *align;
-
while (*parg)
{
if (!strchr("lcr", *parg))
@@ -208,56 +282,56 @@ set_align(const char* arg, Alignment** align, size_t* align_size)
*align_size = 0;
return 1;
}
-
assert((*parg == 'l') || (*parg == 'c') || (*parg == 'r'));
-
*palign++ = alignments[(int)*parg++];
}
-
return 0;
}
-int
+static int
set_columns(const char* arg, size_t* cols)
{
size_t c;
+ assert((arg != NULL) && (cols != NULL));
errno = 0;
c = strtol(arg, NULL, 10);
if (errno == EINVAL || errno == ERANGE)
- return error(1, "Invalid numeric value: %s", arg);
+ {
+ perror(PROGRAMNAME ": strtol");
+ return errno;
+ }
else
*cols = c;
- return 0;
+ return ERR_NONE;
}
-int
+static int
set_delimiter(u8* arg, u32* delimiter)
{
size_t delimiter_len = 0;
u32 uch;
-
+ assert((arg != NULL) && (delimiter != NULL));
u8_rune_to_u32(&uch, arg, &delimiter_len);
*delimiter = uch;
-
return 0;
}
-int
+static int
set_format(const char* arg, int** format, size_t* format_size)
{
- const char* parg = arg;
int* pformat = NULL;
+ const char* parg = arg;
char* token = NULL;
- size_t token_size = BUF_DEFAULT;
char* ptoken = NULL;
+ size_t token_size = BUF_DEFAULT;
int num;
+ assert((arg != NULL) && (format != NULL) && (format_size != NULL));
CALLOC(token, char, token_size);
ptoken = token;
*format_size = FORMAT_DEFAULT;
CALLOC(*format, int, *format_size);
pformat = *format;
-
while (*parg)
{
if (!((*parg >= '0' && *parg <= '9') || *parg == ':'))
@@ -310,15 +384,14 @@ set_format(const char* arg, int** format, size_t* format_size)
}
CHECKSET(*format, pformat, *format_size, num);
}
-
free(token);
-
return 0;
}
-int
+static int
set_quotes_behavior(const char* arg, int* quotes)
{
+ assert((arg != NULL) && (quotes != NULL));
if (!strcmp(arg, "process"))
*quotes = Q_PROCESS;
else if (!strcmp(arg, "ignore"))
@@ -328,11 +401,31 @@ set_quotes_behavior(const char* arg, int* quotes)
return 0;
}
-int
+static int
+set_symbol_set(char* arg, int* current_symbol_set, int* current_inner_symbol_set)
+{
+ assert((arg != NULL) && (current_symbol_set != NULL)
+ && (current_inner_symbol_set != NULL));
+ if (!arg[0] || !arg[1] || arg[2] || !strchr("ades", arg[0])
+ || !strchr("ades", arg[1]))
+ 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"))
+ 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;
+}
+
+static int
skip_while_sgr(const u8* s, size_t* char_delta, int also_print, int whole_string)
{
const u8* ps = s;
-
+ assert((s != NULL) && (char_delta != NULL));
*char_delta = 0;
while (*ps)
{
@@ -368,162 +461,70 @@ skip_while_sgr(const u8* s, size_t* char_delta, int also_print, int whole_string
return 0;
}
-int
-print_aligned(const u8* s, size_t rune_length, size_t to_size, Alignment align,
- size_t* current_rune_column)
+static int
+startswith(const char* s, const char* what)
{
- size_t i;
- const u8* ps = s;
- u32 uch;
- size_t ch_len;
- size_t colwidth = current_column_width();
- size_t output_runes = 0;
- size_t skipped_runes = 0;
- size_t output_chars = 0;
- size_t skipped_chars = 0;
-
- if (align == ALIGN_CENTER)
- for (i = 0; 2 * i + rune_length < to_size; i++)
- {
- printf("%c", alignment_char);
- (*current_rune_column)++;
- }
- else if (align == ALIGN_RIGHT)
- for (i = 0; i + rune_length < to_size; i++)
- {
- printf("%c", alignment_char);
- (*current_rune_column)++;
- }
- if (align == ALIGN_LEFT)
- {
- output_runes = 0;
- while (output_runes != MIN(rune_length, colwidth))
- {
- skip_while_sgr(ps, &skipped_chars, 1, 0);
- ps += skipped_chars;
-
- if (!no_ansi && lineno == 0)
- printf("%s", ANSI_SGR_BOLD_ON);
-
- u8_rune_to_u32(&uch, ps, &ch_len);
- output_chars = 0;
- while (output_chars != ch_len)
- {
- printf("%c", (char)*ps++);
- output_chars++;
- }
- output_runes++;
- }
- skip_while_sgr(ps, &skipped_chars, 1, 1);
- }
- else if (align == ALIGN_CENTER)
- {
- skipped_runes = 0;
- while (2 * skipped_runes + to_size < rune_length)
- {
- skip_while_sgr(ps, &skipped_chars, 1, 0);
- ps += skipped_chars;
-
- u8_rune_to_u32(&uch, ps, &ch_len);
- ps += ch_len;
- skipped_runes++;
- }
-
- output_runes = 0;
- while (output_runes != MIN(rune_length, colwidth))
- {
- skip_while_sgr(ps, &skipped_chars, 1, 0);
- ps += skipped_chars;
-
- if (!no_ansi && lineno == 0)
- printf("%s", ANSI_SGR_BOLD_ON);
-
- u8_rune_to_u32(&uch, ps, &ch_len);
- output_chars = 0;
- while (output_chars != ch_len)
- {
- printf("%c", (char)*ps++);
- output_chars++;
- }
- output_runes++;
- }
- skip_while_sgr(ps, &skipped_chars, 1, 1);
- }
- else if (align == ALIGN_RIGHT)
+ const char* ps = s;
+ assert((s != NULL) && (what != NULL));
+ while (*ps && *what)
{
- skipped_runes = 0;
- while (skipped_runes + to_size < rune_length)
- {
- skip_while_sgr(ps, &skipped_chars, 1, 0);
- ps += skipped_chars;
-
- u8_rune_to_u32(&uch, ps, &ch_len);
- ps += ch_len;
- skipped_runes++;
- }
- output_runes = 0;
- while (output_runes != MIN(rune_length, colwidth))
- {
- skip_while_sgr(ps, &skipped_chars, 1, 0);
- ps += skipped_chars;
-
- if (!no_ansi && lineno == 0)
- printf("%s", ANSI_SGR_BOLD_ON);
-
- u8_rune_to_u32(&uch, ps, &ch_len);
- output_chars = 0;
- while (output_chars != ch_len)
- {
- printf("%c", (char)*ps++);
- output_chars++;
- }
- output_runes++;
- }
- skip_while_sgr(ps, &skipped_chars, 1, 1);
+ if (*what && *ps != *what)
+ return 0;
+ ps++;
+ what++;
}
- (*current_rune_column) += output_runes;
- return 0;
+ return 1;
}
-/* Return number of columns based on the input line */
-size_t
-number_of_columns(const u8* input, u32 delimiter)
+static int
+usage(void)
{
- u32 uch;
- size_t ch_len = 0;
- size_t result = 1;
- const u8* pinput = NULL;
-
- pinput = input;
-
- if (!input)
- return result;
+ printf("Usage:\t%s -h | --help | -V | --full-version | -v | --version\n"
+ "\t%s [-a <alignment> | --align=<alignment>]"
+ " [-b | --border-mode] [-c <cols> | --columns=<cols>]"
+ " [-D | --align-dot] [-d <delim> | --delimiter=<delim>]"
+ " [-f <format> | --format=<format>] [-H | --align-header]"
+ " [-m | --msdos] [-n | --no-ansi] [-p | --pause]"
+ " [-q <behavior> | --quotes=<behavior>]"
+ " [-s <set> | --symbols=<set>] [-t | --expand-tabs]"
+ " [-y | --yes-ansi] [pathname]\n",
+ PROGRAMNAME, PROGRAMNAME);
+ return ERR_NONE;
+}
- while (pinput && *pinput)
- {
- if (u8_rune_to_u32(&uch, pinput, &ch_len))
- warning("Malformed UTF-8 at position %td: "
- "uch=%02X, "
- "pinput=%02X",
- pinput - input, uch, *pinput);
- if (uch == delimiter)
- result++;
- pinput += ch_len;
- }
+static int
+version(const int full)
+{
+ printf("%s %s, committed on %s\n", PROGRAMNAME, VERSION, DATE);
+ if (full)
+ puts(COPYRIGHT);
+ return ERR_NONE;
+}
- return result;
+static void
+warning(const char* fmt, ...)
+{
+ va_list args;
+ char buf[line_max];
+ assert(fmt != NULL);
+ va_start(args, fmt);
+ if (vsnprintf(buf, LEN(buf), fmt, args) >= (ssize_t)LEN(buf))
+ buf[LEN(buf) - 1] = 0;
+ va_end(args);
+ fprintf(stderr, "%s: %s\n", PROGRAMNAME, buf);
}
-unsigned int
-round_div(unsigned int a, unsigned int b)
+static int
+within_column(size_t column_start, size_t current_rune_column)
{
- return (a + (b / 2)) / b;
+ return current_rune_column < column_start + current_column_width();
}
int
main(int argc, char** argv)
{
FILE* input = NULL;
+ struct stat st;
Command cmd = CMD_NONE;
u32 uch;
u8* line = NULL;
@@ -577,18 +578,18 @@ main(int argc, char** argv)
else if (errno)
{
perror(PROGRAMNAME ": isatty");
- exit(1);
+ exit(errno);
}
}
- errno = 0;
+ errno = 0;
line_max = sysconf(_SC_LINE_MAX);
if (line_max == -1)
{
if (errno)
{
perror(PROGRAMNAME ": sysconf");
- exit(1);
+ exit(errno);
}
line_max = _POSIX2_LINE_MAX;
}
@@ -617,9 +618,10 @@ do_arg:
{
arg += strlen("align=");
if (set_align(arg, &align, &align_size))
- exit(error(1,
+ exit(error(ERR_BAD_ALIGN,
"Invalid alignment "
- "specification"));
+ "specification: '%s'",
+ arg));
}
else if (!strcmp(arg, "border-mode"))
border_mode = 1;
@@ -627,7 +629,7 @@ do_arg:
{
arg += strlen("columns=");
if (set_columns(arg, &rune_columns))
- exit(error(EINVAL,
+ exit(error(ERR_BAD_CL_ARG,
"Invalid argument: "
"'%s'",
arg));
@@ -636,7 +638,7 @@ do_arg:
{
arg += strlen("delimiter=");
if (set_delimiter((u8*)arg, &delimiter))
- exit(error(EINVAL,
+ exit(error(ERR_BAD_CL_ARG,
"Invalid argument: "
"'%s'",
arg));
@@ -658,7 +660,7 @@ do_arg:
{
arg += strlen("quotes=");
if (set_quotes_behavior(arg, "es))
- exit(error(EINVAL,
+ exit(error(ERR_BAD_CL_ARG,
"Invalid argument: "
"'%s'",
arg));
@@ -668,7 +670,7 @@ do_arg:
arg += strlen("symbols=");
if (set_symbol_set(arg, ¤t_symbol_set,
¤t_inner_symbol_set))
- exit(error(EINVAL,
+ exit(error(ERR_BAD_CL_ARG,
"Invalid argument: "
"'%s'",
arg));
@@ -679,9 +681,9 @@ do_arg:
return usage();
else
{
- error(EINVAL, "Invalid argument: --%s", arg);
- usage();
- exit(EINVAL);
+ (void)usage();
+ exit(error(ERR_BAD_CL_ARG,
+ "Invalid argument: --%s", arg));
}
}
else
@@ -710,7 +712,8 @@ do_arg:
align_header = 1;
break;
case 'h':
- return usage();
+ usage();
+ exit(ERR_NONE);
break;
case 'm':
msdos = 1;
@@ -740,9 +743,9 @@ do_arg:
no_ansi = 0;
break;
default:
- error(EINVAL, "Invalid argument: -%c", c);
- usage();
- exit(EINVAL);
+ (void)usage();
+ exit(error(ERR_BAD_CL_ARG,
+ "Invalid argument: -%c", c));
}
/* Gobble up the rest of the arg ("-d:" etc) */
if (*arg)
@@ -755,39 +758,40 @@ do_arg:
if (cmd == CMD_ALIGN)
{
if (set_align(arg, &align, &align_size))
- exit(error(EINVAL, "Invalid argument: '%s'",
+ exit(error(ERR_BAD_ALIGN,
+ "Invalid alignment specification: '%s'",
arg));
}
else if (cmd == CMD_COLUMNS)
{
if (set_columns(arg, &rune_columns))
- exit(error(EINVAL, "Invalid argument: '%s'",
- arg));
+ exit(error(ERR_BAD_CL_ARG,
+ "Invalid argument: '%s'", arg));
}
else if (cmd == CMD_DELIMITER)
{
if (set_delimiter((u8*)arg, &delimiter))
- exit(error(EINVAL, "Invalid argument: '%s'",
- arg));
+ exit(error(ERR_BAD_CL_ARG,
+ "Invalid argument: '%s'", arg));
}
else if (cmd == CMD_FORMAT)
{
if (set_format(arg, &format, &format_size))
- exit(error(EINVAL, "Invalid argument: '%s'",
- arg));
+ exit(error(ERR_BAD_CL_ARG,
+ "Invalid argument: '%s'", arg));
}
else if (cmd == CMD_QUOTES)
{
if (set_quotes_behavior(arg, "es))
- exit(error(EINVAL, "Invalid argument: '%s'",
- arg));
+ exit(error(ERR_BAD_CL_ARG,
+ "Invalid argument: '%s'", arg));
}
else if (cmd == CMD_SYMBOLS)
{
if (set_symbol_set(arg, ¤t_symbol_set,
¤t_inner_symbol_set))
- exit(error(EINVAL, "Invalid argument: '%s'",
- arg));
+ exit(error(ERR_BAD_CL_ARG,
+ "Invalid argument: '%s'", arg));
}
else if (filename)
warning("Additional argument ignored: '%s'", arg);
@@ -809,17 +813,29 @@ done_arg:
if (unveil(filename, "r") < 0)
{
perror(PROGRAMNAME ": unveil");
- exit(1);
+ exit(errno);
}
if (unveil(NULL, NULL) < 0)
{
perror(PROGRAMNAME ": unveil");
- exit(1);
+ exit(errno);
}
#endif
+ errno = 0;
+ if (stat(filename, &st) < 0)
+ {
+ perror(PROGRAMNAME ": stat");
+ exit(errno);
+ }
+ if (S_ISDIR(st.st_mode))
+ exit(error(EISDIR, "Is a directory: '%s'", filename));
+ errno = 0;
input = fopen(filename, "r");
if (!input)
- exit(error(ENOENT, "File not found: %s", filename));
+ {
+ perror(PROGRAMNAME ": fopen");
+ exit(error(errno, "Cannot open '%s'", filename));
+ }
}
else
input = stdin;
@@ -1009,7 +1025,7 @@ do_line:
if (in_quote)
{
printf("\n");
- exit(error(EINVAL, "Unmatched quote"));
+ exit(error(ERR_UNMATCHED_QUOTE, "Unmatched quote"));
}
else
goto done_line;
@@ -1210,7 +1226,6 @@ done_line:
output_lines++;
lineno++;
-
pline = line;
goto do_input;
@@ -1274,7 +1289,6 @@ done_bottom_border:
skip_bottom_border:
free(format);
free(align);
-
if (opause)
{
char buf[line_max];
@@ -1284,6 +1298,5 @@ skip_bottom_border:
fgets(buf, line_max, stdin);
}
fclose(input);
-
return 0;
}