table

Помоћни програм из командне линије за форматирање и приказ CSV-а
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување 87a587014e2ac983134f36fde443c965723d74da
родитељ 66eea0abf2b8886d89ce550a87d083bd000a8188
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Wed, 10 May 2023 21:27:56 +0200

Add -q

Signed-off-by: Страхиња Радић <contact@strahinja.org>

Diffstat:
MTODO | 2+-
Mdefs.h | 62+++++++++++++++++++++++++++++++-------------------------------
Mtable.1.in | 24+++++++++++++++++++++++-
Mtable.c | 210++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
измењених датотека: 4, додавања: 184(+), брисања: 114(-)

diff --git a/TODO b/TODO @@ -3,7 +3,7 @@ TODO [ ] Add column alignment -< > Add switch to turn off processing of quotes; have tsvtable use it +<x> Add switch to turn off processing of quotes; have tsvtable use it automatically diff --git a/defs.h b/defs.h @@ -4,49 +4,49 @@ #include "utf8.h" -#define BUFSIZE 4096 +#define BUFSIZE 4096 #define SMALL_BUFSIZE 256 -//#define ANSI_SGR_RESET "\e[0m\e[?25h" +// #define ANSI_SGR_RESET "\e[0m\e[?25h" #define ANSI_SGR_BOLD_ON "\e[1m" #define ANSI_SGR_BOLD_OFF "\e[0m" typedef unsigned char UBYTE; -typedef unsigned int UINT; +typedef unsigned int UINT; typedef unsigned long ULONG; -typedef enum -{ - CMD_NONE, - CMD_COLUMNS, - CMD_DELIMITER, - CMD_FORMAT, - CMD_SYMBOLS, - CMD_VERSION +typedef enum { + CMD_NONE, + CMD_COLUMNS, + CMD_DELIMITER, + CMD_FORMAT, + CMD_QUOTES, + CMD_SYMBOLS, + CMD_VERSION } Command; -enum -{ - TABLE_SYMBOLS_ASCII, - TABLE_SYMBOLS_SINGLE, - TABLE_SYMBOLS_DOUBLE, - TABLE_SYMBOLS_EMPTY +enum { Q_PROCESS, Q_IGNORE }; + +enum { + TABLE_SYMBOLS_ASCII, + TABLE_SYMBOLS_SINGLE, + TABLE_SYMBOLS_DOUBLE, + TABLE_SYMBOLS_EMPTY }; -enum -{ - TABLE_INNER_ASCII_ASCII, - TABLE_INNER_SINGLE_SINGLE, - TABLE_INNER_SINGLE_DOUBLE, - TABLE_INNER_DOUBLE_SINGLE, - TABLE_INNER_DOUBLE_DOUBLE, - TABLE_INNER_EMPTY_EMPTY, - TABLE_INNER_ASCII_EMPTY, - TABLE_INNER_SINGLE_EMPTY, - TABLE_INNER_DOUBLE_EMPTY, - TABLE_INNER_EMPTY_ASCII, - TABLE_INNER_EMPTY_SINGLE, - TABLE_INNER_EMPTY_DOUBLE, +enum { + TABLE_INNER_ASCII_ASCII, + TABLE_INNER_SINGLE_SINGLE, + TABLE_INNER_SINGLE_DOUBLE, + TABLE_INNER_DOUBLE_SINGLE, + TABLE_INNER_DOUBLE_DOUBLE, + TABLE_INNER_EMPTY_EMPTY, + TABLE_INNER_ASCII_EMPTY, + TABLE_INNER_SINGLE_EMPTY, + TABLE_INNER_DOUBLE_EMPTY, + TABLE_INNER_EMPTY_ASCII, + TABLE_INNER_EMPTY_SINGLE, + TABLE_INNER_EMPTY_DOUBLE, }; static const u32* table_symbols[][9] = diff --git a/table.1.in b/table.1.in @@ -34,7 +34,7 @@ is a synonym for .br .B tsvtable is a synonym for -.BR "table -d \(dq$(printf '\et')\(dq" . +.BR "table -d \(dq$(printf '\et')\(dq -q ignore" . . .SH SYNOPSIS . @@ -54,6 +54,7 @@ is a synonym for .OP "\-m \fR|\fP \-\-msdos" .OP "\-n \fR|\fP \-\-no\-ansi" .OP "\-p \fR|\fP \-\-pause" +.OP "\-q \fR|\fP \-\-quotes=" behavior .OP "\-s \fR|\fP \-\-symbols=" set .OP "\-t \fR|\fP \-\-expand-tabs" .YS @@ -191,6 +192,27 @@ from file managers which don't pause after executing programs or as a single command from terminal emulators. . .TP +.BI \-q " behavior" +.TQ +.BI \-\-quotes= behavior +.br +.I behavior +can be one of the following: +. +.RS +.IP \fBprocess\fP +Treats everything between the quotes as a single column. +Treats consequtive quotes within the quoted text as literal quotes. +This is the default. +.IP \fBignore\fP +Ignores the special meaning of quotes (like TSV). +This is the default if +.B table +is called as +.BR tsvtable . +.RE +. +.TP .BI \-s " set" .TQ .BI \-\-symbols= set diff --git a/table.c b/table.c @@ -81,6 +81,7 @@ int handle_ansi = 1; int msdos = 0; int pause = 0; int expand_tabs = 0; +int quotes = Q_PROCESS; int version() @@ -95,8 +96,9 @@ usage() printf("Usage: %s [-b|--border-mode] [-c <cols>|--columns=<cols>] [-d" " <delim>|--delimiter=<delim>] [-f <format>|--format=<format>]" " [-h|--help] [-m|--msdos] [-n|--no-ansi]" - " [-p|--pause] [-s <set>|--symbols=<set>] [-t|--expand-tabs] " - "[-v|--version]\n", + " [-p|--pause] [-q <behavior>|--quotes=<behavior>]" + " [-s <set>|--symbols=<set>] [-t|--expand-tabs]" + " [-v|--version]\n", PROGRAMNAME); return 0; } @@ -311,6 +313,18 @@ set_format(const char* arg, ULONG** format, size_t* format_size) return 0; } +int +set_quotes_behavior(const char* arg, int* quotes) +{ + if (!strcmp(arg, "process")) + *quotes = Q_PROCESS; + else if (!strcmp(arg, "ignore")) + *quotes = Q_IGNORE; + else + return 1; + return 0; +} + /* Return number of columns based on the input line */ size_t number_of_columns(const u8* input, u32 delimiter) @@ -365,7 +379,10 @@ main(int argc, char** argv) progname = sep + 1; if (!strcmp(progname, "tsvtable")) + { delimiter = L'\t'; + quotes = Q_IGNORE; + } else if (!strcmp(progname, "tablep")) pause = 1; @@ -431,6 +448,15 @@ do_arg: arg += strlen("pause"); pause = 1; } + else if (startswith(arg, "quotes=")) + { + arg += strlen("quotes="); + if (set_quotes_behavior(arg, &quotes)) + return error(EINVAL, + "Invalid argument: " + "'%s'", + arg); + } else if (startswith(arg, "symbols=")) { arg += strlen("symbols="); @@ -477,6 +503,9 @@ do_arg: case 'p': pause = 1; break; + case 'q': + cmd = CMD_QUOTES; + break; case 's': cmd = CMD_SYMBOLS; break; @@ -516,6 +545,12 @@ do_arg: return error(EINVAL, "Invalid argument: '%s'", arg); } + else if (cmd == CMD_QUOTES) + { + if (set_quotes_behavior(arg, &quotes)) + return error(EINVAL, "Invalid argument: '%s'", + arg); + } else if (cmd == CMD_SYMBOLS) { if (set_symbol_set(arg, &current_symbol_set, @@ -543,15 +578,16 @@ done_arg: else input = stdin; - u8* line = NULL; - u8* pline = NULL; - int quote = 0; + u8* line = NULL; + u8* pline = NULL; + int in_quote = 0; u32 uch; u8 u8ch[7]; size_t u8len = 0; size_t ch_len = 0; size_t output_lines = 0; size_t column_start = 0; + u8* pch_end; CALLOC(line, u8, BUFSIZE); @@ -574,7 +610,7 @@ do_input: if (!*line && lineno != 0) goto empty_line; - quote = 0; + in_quote = 0; pline = line; colno = 0; current_rune_column = 0; @@ -718,97 +754,109 @@ not_first: do_line: if (!pline || !*pline) - goto done_line; + { + if (in_quote) + { + printf("\n"); + return error(EINVAL, "Unmatched quote"); + } + else + goto done_line; + } - if (*pline == '"') + if (in_quote && *pline == '"' && *(pline + 1) == '"') { - quote = !quote; pline++; colno++; + goto continue_line; } - else + else if (quotes == Q_PROCESS && *pline == '"') + { + in_quote = !in_quote; + pline++; + colno++; + goto do_line; + } + +continue_line: + u8_char_to_u32(&uch, pline, &ch_len); + if (uch == delimiter && !in_quote + && current_table_column < table_columns - 1) { - u8* pch_end; - u8_char_to_u32(&uch, pline, &ch_len); - if (ch_len <= 0) + if (handle_ansi && lineno == 0) + printf("%s", ANSI_SGR_BOLD_OFF); + + while (within_column(column_start)) { - if (within_column(column_start)) - { - printf("%c", *pline++); - current_rune_column++; - } - colno++; + printf(" "); + current_rune_column++; } - else if (uch == (u32)L'\t' && expand_tabs) + column_start++; + if (format) + column_start += *(format + current_table_column); + else + column_start += format_value; + if (current_table_column != table_columns - 1) { - while (within_column(column_start)) - { - printf(" "); - current_rune_column++; - if (current_rune_column % tab_length == 0) - break; - } - pline++; - colno++; + u8len = u32_char_to_u8(u8ch, + *table_inner_symbols[current_inner_symbol_set] + [1]); + u8ch[u8len] = 0; + printf("%s", u8ch); + current_rune_column++; + current_table_column++; } - else if (border_mode) + + if (handle_ansi && lineno == 0) + printf("%s", ANSI_SGR_BOLD_ON); + + pline += ch_len; + colno += ch_len; + } + else if (ch_len <= 0) + { + if (within_column(column_start)) { - pch_end = pline + ch_len; - if (within_column(column_start)) - { - while (pline != pch_end) - printf("%c", *pline++); - current_rune_column++; - } - pline = pch_end; - colno += ch_len; + printf("%c", *pline++); + current_rune_column++; } - else if (uch == delimiter && !quote - && current_table_column < table_columns - 1) + colno++; + } + else if (uch == (u32)L'\t' && expand_tabs) + { + while (within_column(column_start)) { - if (handle_ansi && lineno == 0) - printf("%s", ANSI_SGR_BOLD_OFF); - - while (within_column(column_start)) - { - printf(" "); - current_rune_column++; - } - column_start++; - if (format) - column_start - += *(format + current_table_column); - else - column_start += format_value; - if (current_table_column != table_columns - 1) - { - u8len = u32_char_to_u8(u8ch, - *table_inner_symbols - [current_inner_symbol_set][1]); - u8ch[u8len] = 0; - printf("%s", u8ch); - current_rune_column++; - current_table_column++; - } - - if (handle_ansi && lineno == 0) - printf("%s", ANSI_SGR_BOLD_ON); - - pline += ch_len; - colno += ch_len; + printf(" "); + current_rune_column++; + if (current_rune_column % tab_length == 0) + break; } - else + pline++; + colno++; + } + else if (border_mode) + { + pch_end = pline + ch_len; + if (within_column(column_start)) { - pch_end = pline + ch_len; - if (within_column(column_start)) - { - while (pline != pch_end) - printf("%c", *pline++); - current_rune_column++; - } - pline = pch_end; - colno += ch_len; + while (pline != pch_end) + printf("%c", *pline++); + current_rune_column++; + } + pline = pch_end; + colno += ch_len; + } + else + { + pch_end = pline + ch_len; + if (within_column(column_start)) + { + while (pline != pch_end) + printf("%c", *pline++); + current_rune_column++; } + pline = pch_end; + colno += ch_len; } goto do_line;