table

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

чување a8843eba5ea5615cc6b0f2eee24586f5b97bd705
родитељ 3a4ad5f662691b15244bcf9872b49bbddfb83677
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Sun, 11 Oct 2020 22:25:13 +0200

Merge branch 'wip-2020-10' into master

Diffstat:
M.gitignore | 2++
ACHANGES | 13+++++++++++++
MMakefile | 7++++++-
MTODO | 8+++++---
Mdefs.h | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Mindex.html | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Mtable.c | 532++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Atest/UTF-8-demo.txt | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/UTF-8-test.txt | 0
Atest/file.sh | 2++
Atest/ls-adv.sh | 2++
Mtest/sales.csv | 16+++++++++++-----
Mtest/sales.sc | 27+++++++++++++++++++++++----
измењених датотека: 13, додавања: 846(+), брисања: 118(-)

diff --git a/.gitignore b/.gitignore @@ -4,4 +4,6 @@ *.rej *.o *.swp +nohup.out +*.png table diff --git a/CHANGES b/CHANGES @@ -0,0 +1,13 @@ + Changelog + ========= + +* v0.1-alpha + + - Read and display columns + + - Use "T" connector chars; connector selection similar to -s + + - Handle tabs - unwrap to spaces at tab stops (test/lsb_release.sh) + + - Better UTF-8 substring code based on screen columns + diff --git a/Makefile b/Makefile @@ -1,9 +1,14 @@ BINDIR=/usr/local/bin +CFLAGS= +#CFLAGS=-g all: table +.o: .c + $(CC) $(CFLAGS) -o $@ -c $< + table: table.o - $(CC) -lunistring -o $@ $< + $(CC) $(CFLAGS) -lunistring -o $@ $< install: all cp table $(BINDIR) diff --git a/TODO b/TODO @@ -5,12 +5,14 @@ [ ] Handle tty ANSI codes (test/neofetch.sh) + [x] Ignore malformed UTF-8 sequences. Currently segmentation faults + (test/who-Huw.sh with LC_ALL=sr_RS.UTF8 and cyrillic user names) + [x] Handle tabs - unwrap to spaces at tab stops (test/lsb_release.sh) - [ ] Ignore malformed UTF-8 sequences. Currently segmentation faults - (test/who-Huw.sh with LC_ALL=sr_RS.UTF8 and cyrillic user names) + [x] Read and display columns - [ ] Read and display columns + [x] Use "T" connector chars; connector selection similar to -s [x] Better UTF-8 substring code based on screen columns diff --git a/defs.h b/defs.h @@ -1,5 +1,5 @@ /* - * Command line utility to format and display CSV. + * table - Command line utility to format and display CSV. * Copyright (C) 2020 Страхиња Радић * * This program is free software: you can redistribute it and/or modify it @@ -34,18 +34,19 @@ #define BUFSIZE 1024 -// Minimal table column width without the ending char +// Minimal table column width without the borders // | A | B | C | -// ^^^^--This -// [Max screen columns] -// [Max table columns] = -------------------- -// MIN_TABLE_COL_WIDTH -#define MIN_TABLE_COL_WIDTH 4 +// ^^^--This +// [Max screen columns] - [Table columns] - 1 +// [Max table columns] = ------------------------------------------ +// MIN_TABLE_COL_WIDTH +#define MIN_TABLE_COL_WIDTH 3 typedef enum { CMD_NONE, CMD_COLUMNS, + CMD_DELIMITER, CMD_SYMBOLS, CMD_VERSION } Command; @@ -57,6 +58,15 @@ enum TABLE_SYMBOLS_DOUBLE }; +enum +{ + TABLE_INNER_ASCII_ASCII, + TABLE_INNER_SINGLE_SINGLE, + TABLE_INNER_SINGLE_DOUBLE, + TABLE_INNER_DOUBLE_SINGLE, + TABLE_INNER_DOUBLE_DOUBLE +}; + static const uint8_t* table_symbols[][9] = { [TABLE_SYMBOLS_ASCII] = { @@ -67,9 +77,9 @@ static const uint8_t* table_symbols[][9] = }, [TABLE_SYMBOLS_SINGLE] = { // single - (uint8_t*)"\u250c", (uint8_t*)"\u2500", (uint8_t*)"\u2510", - (uint8_t*)"\u2502", (uint8_t*)" ", (uint8_t*)"\u2502", - (uint8_t*)"\u2514", (uint8_t*)"\u2500", (uint8_t*)"\u2518", + (uint8_t*)"\u250c", (uint8_t*)"\u2500", (uint8_t*)"\u2510", + (uint8_t*)"\u2502", (uint8_t*)" ", (uint8_t*)"\u2502", + (uint8_t*)"\u2514", (uint8_t*)"\u2500", (uint8_t*)"\u2518", }, [TABLE_SYMBOLS_DOUBLE] = { // double @@ -79,5 +89,43 @@ static const uint8_t* table_symbols[][9] = } }; +static const uint8_t* table_inner_symbols[][3] = +{ + [TABLE_INNER_ASCII_ASCII] = { + // ascii -> ascii + (uint8_t*)"+", + (uint8_t*)"|", + (uint8_t*)"+", + }, + + [TABLE_INNER_SINGLE_SINGLE] = { + // single -> single + (uint8_t*)"\u252c", + (uint8_t*)"\u2502", + (uint8_t*)"\u2534", + }, + + [TABLE_INNER_SINGLE_DOUBLE] = { + // single -> double + (uint8_t*)"\u2565", + (uint8_t*)"\u2551", + (uint8_t*)"\u2568", + }, + + [TABLE_INNER_DOUBLE_SINGLE] = { + // double -> single + (uint8_t*)"\u2564", + (uint8_t*)"\u2502", + (uint8_t*)"\u2567", + }, + + [TABLE_INNER_DOUBLE_DOUBLE] = { + // double -> double + (uint8_t*)"\u2566", + (uint8_t*)"\u2551", + (uint8_t*)"\u2569", + } +}; + #endif diff --git a/index.html b/index.html @@ -1,39 +1,94 @@ <!DOCTYPE html> <html> <head> - <title>table - Command line utility to format and display CSV</title> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>table - Command line utility to format and display CSV</title> + <style> + html, body, html * + { + font-family: "Noto Sans", "Helvetica", "Arial", sans-serif; + font-weight: normal; + font-size: 11pt; + } + + h1, h2, h3, h4, h5 + { + font-weight: bold; + } + + h1 + { + font-size: 2.25em; + } + + h2 + { + font-size: 1.5em; + font-variant: small-caps; + } + + h3 + { + font-size: 1.2em; + } + + pre, pre * + { + font-family: "Noto Mono", "Courier New", "Courier", monospace; + } + + pre + { + overflow-x: auto; + } + </style> </head> <body> <h1>table</h1> <p>Command line utility to format and display CSV.</p> - <h2>Install</h2> <pre> -$ make && sudo make install +$ git clone <a +href="https://github.com/Strahinja/table.git">https://github.com/Strahinja/table.git</a> +$ cd table +$ make &amp;&amp; sudo make install </pre> + <h2>Changelog</h2> + + <h3>v0.1-alpha</h3> + <ul> + <li>Read and display columns</li> + <li>Use "T" connector chars; connector selection similar to -s</li> + <li> + Handle tabs - unwrap to spaces at tab stops + (test/lsb_release.sh) + </li> + <li>Better UTF-8 substring code based on screen columns</li> + </ul> <h2>License</h2> <p>table - Command line utility to format and display CSV.<br /> - Copyright (C) 2020 Страхиња Радић</p> + Copyright (C) 2020 Страхиња Радић</p> - <p> This program is free software: you can redistribute it and/or modify + <p>This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</p> <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details.</p> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + Public License for more details.</p> - <p> You should have received a copy of the GNU General Public License - along with this program. If not, see <a -href="https://www.gnu.org/licenses/">https://www.gnu.org/licenses/</a>.</p> + <p>You should have received a copy of the GNU General Public License + along with this program. If not, see <a + href="https://www.gnu.org/licenses/">https://www.gnu.org/licenses/</a>.</p> </body> </html> diff --git a/table.c b/table.c @@ -1,5 +1,5 @@ /* - * Command line utility to format and display CSV. + * table - Command line utility to format and display CSV. * Copyright (C) 2020 Страхиња Радић * * This program is free software: you can redistribute it and/or modify it @@ -31,23 +31,36 @@ usage() { printf("Usage: %s [options] [filename]\n", PROGRAMNAME); printf(" Where [options] is one or more of the following:\n"); - printf(" -c [cols]\n"); - printf(" --columns=[cols]\n"); + printf(" -c <cols>\n"); + printf(" --columns=<cols>\n"); printf(" Set maximum table width in columns (default 80)\n"); printf("\n"); + printf(" -d <delim>\n"); + printf(" --delimiter=<delim>\n"); + printf(" Set field delimiter (default \",\"). First line\n"); + printf(" of the input determines the number of table\n"); + printf(" columns. Special characters, like \";\", need\n"); + printf(" to be quoted:\n"); + printf(" $ table -d \";\"\n"); + printf("\n"); printf(" -h\n"); printf(" --help\n"); - printf(" Prints this usage information screen\n"); + printf(" Print this usage information screen\n"); printf("\n"); - printf(" -s [set]\n"); - printf(" --symbols=[set]\n"); - printf(" Use table symbol set [set], where [set] is one\n"); - printf(" of the following:\n"); - printf(" ascii | single | double (default)\n"); + printf(" -s <set>\n"); + printf(" --symbols=<set>\n"); + printf(" Use table symbol set <set> for table lines,\n"); + printf(" where <set> is one of the following\n"); + printf(" (format: <border><inner border>):\n"); + printf(" aa = ascii-ascii\n"); + printf(" ss = single-single\n"); + printf(" sd = single-double\n"); + printf(" ds = double-single (default)\n"); + printf(" dd = double-double\n"); printf("\n"); printf(" -v\n"); printf(" --version\n"); - printf(" Prints program version and exits\n"); + printf(" Print program version and exit\n"); return 0; } @@ -63,6 +76,19 @@ error(int code, uint8_t* fmt, ...) return code; } +void +u32_print(char* name, uint32_t* src, size_t src_len); + +/* + A B C 0 + 0 1 2 3 + len = 3 --^ + start = 1 (B) + finish = len = 3 (0) + substr_len = finish-start = 2 (BC) + result = BC0 +*/ + char* substr(char* src, int start, int finish) { @@ -72,50 +98,84 @@ substr(char* src, int start, int finish) int substr_len = finish-start; if (substr_len < 0) substr_len = 0; - char* result = (char*) malloc(sizeof(char) * (substr_len+1)); + char* result = (char*) calloc(substr_len+1, sizeof(char)); + char* presult = result; for (int i = start; i < finish && *(src+i) != '\0'; i++) { - *result++ = *(src+i); + *presult++ = *(src+i); } - *result = '\0'; + *presult = '\0'; - return result-substr_len; + return result; } +/* + start = 1 + | finish = 3 + v v + A B C D 0 + ==== + 0 1 2 3 4 + src_len = 4 + normalized_start = 1 (B) + normalized_finish = 3 (0) + len = normalized_finish-normalized_start = 2 (BC) + dest = BC0 +*/ uint32_t* u32_substr(uint32_t* src, size_t src_len, size_t start, size_t finish, - uint32_t* dest, size_t* dest_len) + size_t* dest_len) { size_t normalized_finish = src_len; + uint32_t* dest = NULL; if (finish < normalized_finish) normalized_finish = finish; + if (normalized_finish < 0) + normalized_finish = 0; size_t normalized_start = 0; - if (start >= normalized_start) + if (start > normalized_start) normalized_start = start; if (normalized_start > normalized_finish) normalized_start = normalized_finish; size_t len = normalized_finish - normalized_start; - dest = u32_cpy(dest, src + normalized_start, len); + dest = (uint32_t*) calloc(len+1, sizeof(uint32_t)); + memcpy(dest, src + normalized_start, sizeof(uint32_t) * len); + dest[len] = (uint32_t)'\0'; *dest_len = len; + return dest; } int -set_symbol_set(char* arg, int* current_symbol_set) +set_symbol_set(char* arg, int* current_symbol_set, + int* current_inner_symbol_set) { - if (!strcmp(arg, "ascii")) + if (!strcmp(arg, "aa")) { *current_symbol_set = TABLE_SYMBOLS_ASCII; + *current_inner_symbol_set = TABLE_INNER_ASCII_ASCII; } - else if (!strcmp(arg, "single")) + else if (!strcmp(arg, "ss")) { *current_symbol_set = TABLE_SYMBOLS_SINGLE; + *current_inner_symbol_set = TABLE_INNER_SINGLE_SINGLE; + } + else if (!strcmp(arg, "sd")) + { + *current_symbol_set = TABLE_SYMBOLS_SINGLE; + *current_inner_symbol_set = TABLE_INNER_SINGLE_DOUBLE; + } + else if (!strcmp(arg, "ds")) + { + *current_symbol_set = TABLE_SYMBOLS_DOUBLE; + *current_inner_symbol_set = TABLE_INNER_DOUBLE_SINGLE; } - else if (!strcmp(arg, "double")) + else if (!strcmp(arg, "dd")) { *current_symbol_set = TABLE_SYMBOLS_DOUBLE; + *current_inner_symbol_set = TABLE_INNER_DOUBLE_DOUBLE; } else { @@ -125,12 +185,12 @@ set_symbol_set(char* arg, int* current_symbol_set) } int -set_columns(char* arg, int* cols) +set_columns(char* arg, size_t* cols) { - int c = strtol(arg, NULL, 10); + size_t c = strtol(arg, NULL, 10); if (errno == EINVAL || errno == ERANGE) { - return error(1, "Invalid numeric value: %s\n", arg); + return error(1, (uint8_t*)"Invalid numeric value: %s\n", arg); } else { @@ -139,13 +199,35 @@ set_columns(char* arg, int* cols) return 0; } +int +set_delimiter(char* arg, uint32_t* delimiter) +{ + size_t start = 0; + size_t len = strlen(arg); + size_t finish = len; + + if (arg[0] == '"') + start = 1; + if (arg[len-1] == '"') + finish = len-2; + + char* stripped_arg = substr(arg, start, finish); + uint32_t* delim = (uint32_t*) calloc(BUFSIZE, sizeof(uint32_t)); + size_t delim_len = BUFSIZE; + u8_to_u32(stripped_arg, len, delim, &delim_len); + *delimiter = delim[0]; + free(delim); + + return 0; +} + size_t -number_of_columns(const uint32_t* input, const size_t tempbuf_len, +number_of_columns(const uint32_t* input, const size_t input_len, uint32_t delimiter) { - size_t result = 0; + size_t result = 1; - for (size_t i = 0; i < tempbuf_len; i++) + for (size_t i = 0; i < input_len; i++) { if (input[i] == delimiter) { @@ -156,10 +238,11 @@ number_of_columns(const uint32_t* input, const size_t tempbuf_len, } uint32_t* -u32_tabs_to_spaces(uint32_t* src, size_t src_len, uint32_t* dest, +u32_tabs_to_spaces(const uint32_t* src, const size_t src_len, size_t* dest_len, size_t tab_length) { size_t rune_column = 0; + uint32_t* dest = (uint32_t*) calloc(BUFSIZE, sizeof(uint32_t)); for (size_t i = 0; i < src_len; i++) { @@ -175,9 +258,72 @@ u32_tabs_to_spaces(uint32_t* src, size_t src_len, uint32_t* dest, dest[rune_column++] = src[i]; } *dest_len = rune_column; + dest[*dest_len] = (uint32_t)'\0'; return dest; } +// | A | B | C | +// ^^^-^^^-^^^----This +size_t +get_max_table_column_width(size_t rune_columns, size_t table_columns) +{ + size_t result = (rune_columns-table_columns-1)/table_columns; + + return result < MIN_TABLE_COL_WIDTH + ? MIN_TABLE_COL_WIDTH + : result; +} + +size_t +get_max_last_table_column_width(size_t rune_columns, size_t table_columns) +{ + size_t result = get_max_table_column_width(rune_columns, table_columns); + return rune_columns - (table_columns-1) * (result+1) - 2; +} + +void +u32_print(char* name, uint32_t* src, size_t src_len) +{ + printf("%s [%lu] = \"", name, src_len); + for (size_t k = 0; k < src_len; k++) + { + uint8_t charbuf[7]; + size_t charbuf_len = 7; + u32_to_u8(src+k, 1, charbuf, &charbuf_len); + charbuf[charbuf_len] = (uint8_t)'\0'; + printf("%X='%s' ", src[k], charbuf); + } + printf("\"\n"); +} + +/* TODO: Column alignment? + *void + *write_column(uint32_t* src, size_t src_len, size_t column_width, + * size_t written_columns, size_t rune_columns, + * uint8_t* start_symbol, uint8_t* finish_symbol) + *{ + * uint8_t* buffer = NULL; + * size_t buffer_len = BUFSIZE; + * + * fprintf(stdout, "%s", start_symbol); + * + * buffer = (uint8_t*) calloc(BUFSIZE, sizeof(uint8_t)); + * u32_to_u8(src, src_len, buffer, &buffer_len); + * fprintf(stdout, "%s", buffer); + * + * size_t end_column; + * if (rune_columns - written_columns > 2 * column_width) + * end_column = written_columns + column_width + 1; + * else + * end_column = rune_columns - 1; + * + * for (size_t column = written_columns; column < end_column; column++) + * fprintf(stdout, " "); + * + * fprintf(stdout, "%s", finish_symbol); + *} + */ + int main(int argc, char** argv) { @@ -185,9 +331,13 @@ main(int argc, char** argv) Command cmd = CMD_NONE; char* filename = NULL; int current_symbol_set = TABLE_SYMBOLS_DOUBLE; - size_t max_table_columns = 0; - int rune_columns = 80; + int current_inner_symbol_set = TABLE_INNER_DOUBLE_SINGLE; + size_t table_columns = 0; + size_t max_table_column_width = MIN_TABLE_COL_WIDTH; + size_t max_last_table_column_width = MIN_TABLE_COL_WIDTH; + size_t rune_columns = 80; size_t tab_length = 8; + uint32_t delimiter = ','; while ((arg = *++argv)) { @@ -209,10 +359,18 @@ main(int argc, char** argv) if (result) return result; } + else if (!strcmp(substr(arg, 0, strlen("delimiter=")), "delimiter=")) + { + arg += strlen("delimiter="); + result = set_delimiter(arg, &delimiter); + if (result) + return result; + } else if (!strcmp(substr(arg, 0, strlen("symbols=")), "symbols=")) { arg += strlen("symbols="); - result = set_symbol_set(arg, &current_symbol_set); + result = set_symbol_set(arg, &current_symbol_set, + &current_inner_symbol_set); if (result) return result; @@ -234,6 +392,9 @@ main(int argc, char** argv) case 'c': cmd = CMD_COLUMNS; break; + case 'd': + cmd = CMD_DELIMITER; + break; case 'h': return usage(); break; @@ -254,22 +415,28 @@ main(int argc, char** argv) int result; if (cmd == CMD_SYMBOLS) { - result = set_symbol_set(arg, &current_symbol_set); + result = set_symbol_set(arg, &current_symbol_set, + &current_inner_symbol_set); if (result) return result; - cmd = CMD_NONE; } else if (cmd == CMD_COLUMNS) { result = set_columns(arg, &rune_columns); if (result) return result; - cmd = CMD_NONE; + } + else if (cmd == CMD_DELIMITER) + { + result = set_delimiter(arg, &delimiter); + if (result) + return result; } else { filename = arg; } + cmd = CMD_NONE; } } @@ -278,8 +445,6 @@ main(int argc, char** argv) return version(); } - uint8_t line[BUFSIZE]; - FILE* input = NULL; if (filename) { @@ -292,88 +457,285 @@ main(int argc, char** argv) else input = stdin; - fprintf(stdout, "%s", table_symbols[current_symbol_set][0]); - int col = 0; - while (col++ < rune_columns-2) - fprintf(stdout, "%s", table_symbols[current_symbol_set][1]); - fprintf(stdout, "%s\n", table_symbols[current_symbol_set][2]); + uint8_t* line = (uint8_t*) calloc(BUFSIZE, sizeof(uint8_t)); + size_t line_len = 0; uint32_t* unicode_line = NULL; size_t unicode_line_len = 0; - uint32_t* punicode_line = NULL; - uint32_t* expanded_line = NULL; - size_t expanded_line_len = 0; - uint32_t* pexpanded_line = NULL; + uint8_t* buffer = NULL; + size_t buffer_len = 0; + + uint32_t* unicode_buffer = NULL; + size_t unicode_buffer_len = 0; - uint8_t* cropped_line = NULL; - size_t cropped_line_len = 0; - uint8_t* pcropped_line = NULL; + size_t col; - uint32_t* unicode_cropped_line = NULL; - size_t unicode_cropped_line_len = 0; - uint32_t* punicode_cropped_line = NULL; do { - fgets(line, sizeof(line), input); + fgets(line, sizeof(uint8_t) * BUFSIZE, input); + line_len = u8_strlen(line); + if (!feof(input)) { uint8_t* eol = u8_strchr(line, (ucs4_t)'\n'); if (eol) *eol = (uint8_t)'\0'; - if (unicode_line) - unicode_line = (uint32_t*) realloc(unicode_line, sizeof(uint32_t) * BUFSIZE); + if (unicode_buffer) + unicode_buffer = (uint32_t*) realloc(unicode_buffer, sizeof(uint32_t) * BUFSIZE); else - unicode_line = (uint32_t*) malloc(sizeof(uint32_t) * BUFSIZE); - unicode_line_len = sizeof(uint32_t) * BUFSIZE; - punicode_line = u8_to_u32(line, u8_strlen(line), - unicode_line, &unicode_line_len); + unicode_buffer = (uint32_t*) calloc(BUFSIZE, sizeof(uint32_t)); + unicode_buffer_len = BUFSIZE; - fprintf(stdout, "%s", table_symbols[current_symbol_set][3]); - - if (expanded_line) - expanded_line = (uint32_t*) realloc(expanded_line, sizeof(uint32_t) * BUFSIZE); - else - expanded_line = (uint32_t*) malloc(sizeof(uint32_t) * BUFSIZE); - expanded_line_len = sizeof(uint32_t) * BUFSIZE; - pexpanded_line = u32_tabs_to_spaces(punicode_line, unicode_line_len, - expanded_line, &expanded_line_len, - tab_length); + unicode_line_len = BUFSIZE; + unicode_line = u8_to_u32(line, line_len, + NULL, &unicode_line_len); + if (!unicode_line) + { + fprintf(stdout, "%s", table_symbols[current_symbol_set][3]); + for (size_t i = 0; i < max_table_column_width; i++) + { + fprintf(stdout, " "); + } + fprintf(stdout, "%s\n", table_symbols[current_symbol_set][5]); + continue; + } - unicode_cropped_line = (uint32_t*) malloc(sizeof(uint32_t) * BUFSIZE); - unicode_cropped_line_len = sizeof(sizeof(uint32_t) * BUFSIZE); - punicode_cropped_line = u32_substr(pexpanded_line, expanded_line_len, - 0, rune_columns-2, - unicode_cropped_line, &unicode_cropped_line_len); + if (!table_columns) + { + table_columns = number_of_columns(unicode_line, + unicode_line_len, delimiter); + max_table_column_width = + get_max_table_column_width(rune_columns, table_columns); + max_last_table_column_width = + get_max_last_table_column_width(rune_columns, table_columns); + + fprintf(stdout, "%s", table_symbols[current_symbol_set][0]); + col = 0; + // |---|---|---|---|---| + // 01 4 8 12 16 20 + // + // max_w = 3 + // 8-1 = 7 % 3 = 1 + // 12-1 = 11 % 3 = 2 + // 8 % (max_w+1) = 0 + // 12 % (max_w+1) = 0 + size_t table_column = 0; + while (col++ < rune_columns-2) + if (table_column < table_columns-1 + && col % (max_table_column_width+1) == 0) + { + fprintf(stdout, "%s", + table_inner_symbols[current_inner_symbol_set][0]); + table_column++; + } + else + fprintf(stdout, "%s", table_symbols[current_symbol_set][1]); + fprintf(stdout, "%s\n", table_symbols[current_symbol_set][2]); + } - if (cropped_line) - free(cropped_line); - cropped_line = (uint8_t*) malloc(sizeof(uint8_t) * BUFSIZE); - cropped_line_len = sizeof(uint8_t) * BUFSIZE; - pcropped_line = u32_to_u8(punicode_cropped_line, unicode_cropped_line_len, - cropped_line, &cropped_line_len); + if (unicode_buffer) + free(unicode_buffer); + unicode_buffer = u32_tabs_to_spaces(unicode_line, + unicode_line_len, + &unicode_buffer_len, + tab_length); - if (pcropped_line) + if (unicode_line) + free(unicode_line); + unicode_line = (uint32_t*) calloc(BUFSIZE, sizeof(uint32_t)); + u32_strcpy(unicode_line, unicode_buffer); + unicode_line_len = unicode_buffer_len; + + size_t substr_start = 0; + size_t substr_finish = 0; + size_t rune_column; + size_t column_width = max_table_column_width; + size_t written_columns = 0; + size_t current_table_column = 0; + + + for (rune_column = 0; + rune_column < unicode_line_len; + rune_column++) { - pcropped_line[cropped_line_len] = (uint8_t)'\0'; - fprintf(stdout, "%s", pcropped_line); + if (table_columns>1 + && current_table_column < table_columns-1 + && unicode_line[rune_column] == delimiter) + { + char temp[255]; + column_width = max_table_column_width; + + fprintf(stdout, "%s", + current_table_column == 0 + ? table_symbols[current_symbol_set][3] + : table_inner_symbols[current_inner_symbol_set][1] + ); + written_columns++; + + substr_finish = rune_column; + if (unicode_buffer) + free(unicode_buffer); + unicode_buffer = u32_substr(unicode_line, + unicode_line_len, + substr_start, + substr_finish, + &unicode_buffer_len); + if (unicode_buffer_len < column_width) + column_width = unicode_buffer_len; + + if (buffer) + free(buffer); + buffer = (uint8_t*) calloc(BUFSIZE, sizeof(uint8_t)); + buffer_len = BUFSIZE; + u32_to_u8(unicode_buffer, column_width, + buffer, &buffer_len); + + if (buffer && buffer_len>0) + { + fprintf(stdout, "%s", buffer); + written_columns += column_width; + } + + for (size_t i = 0; i < max_table_column_width-column_width; i++) + { + fprintf(stdout, " "); + } + written_columns += max_table_column_width-column_width; + + substr_start = rune_column+1; + current_table_column++; + } } - for (int i = 0; i < rune_columns-2-u8_width(cropped_line, cropped_line_len, "utf-8"); i++) + // Leftovers + if (table_columns > 1) { - fprintf(stdout, " "); + column_width = max_table_column_width; + // Not the last column + if (current_table_column > table_columns-2) + column_width = max_last_table_column_width; + + fprintf(stdout, "%s", + current_table_column == 0 + ? table_symbols[current_symbol_set][3] + : table_inner_symbols[current_inner_symbol_set][1] + ); + written_columns++; + + substr_finish = substr_start + column_width; + if (unicode_buffer) + free(unicode_buffer); + unicode_buffer = u32_substr(unicode_line, + unicode_line_len, + substr_start, + substr_finish, + &unicode_buffer_len); + unicode_buffer_len = u32_strlen(unicode_buffer); + if (unicode_buffer_len < column_width) + column_width = unicode_buffer_len; + + if (buffer) + free(buffer); + buffer = (uint8_t*) calloc(BUFSIZE, sizeof(uint8_t)); + buffer_len = BUFSIZE; + u32_to_u8(unicode_buffer, column_width, + buffer, &buffer_len); + + if (buffer && buffer_len>0) + { + fprintf(stdout, "%s", buffer); + written_columns += column_width; + } + + // Not the last column + if (current_table_column < table_columns-1) + { + for (size_t i = 0; i < max_table_column_width-column_width; i++) + { + fprintf(stdout, " "); + } + written_columns += max_table_column_width - column_width; + + for (size_t leftover_column = 0; + leftover_column < table_columns-current_table_column-1; + leftover_column++) + { + fprintf(stdout, "%s", + table_inner_symbols[current_inner_symbol_set][1]); + + size_t table_column_width = max_table_column_width; + if (leftover_column == table_columns-current_table_column-2) + table_column_width = rune_columns - written_columns - 2; + for (size_t i = 0; i < table_column_width; i++) + fprintf(stdout, " "); + } + } + // Last one + else + { + for (size_t i = written_columns+1; i < rune_columns; i++) + { + fprintf(stdout, " "); + } + } + + written_columns = rune_columns; } + // Handle a line with no delimiter + else + { + column_width = max_table_column_width; + + fprintf(stdout, "%s", table_symbols[current_symbol_set][3]); + + substr_finish = unicode_line_len; + if (unicode_buffer) + free(unicode_buffer); + unicode_buffer = u32_substr(unicode_line, + unicode_line_len, + substr_start, + substr_finish, + &unicode_buffer_len); + if (unicode_buffer_len-1 < column_width) + column_width = unicode_buffer_len-1; + + if (buffer) + free(buffer); + buffer = (uint8_t*) calloc(BUFSIZE, sizeof(uint8_t)); + buffer_len = BUFSIZE; + u32_to_u8(unicode_buffer, column_width, + buffer, &buffer_len); + + if (buffer && buffer_len>0) + { + fprintf(stdout, "%s", buffer); + } + for (size_t i = 0; i < rune_columns-column_width-table_columns-1; i++) + { + fprintf(stdout, " "); + } + } fprintf(stdout, "%s\n", table_symbols[current_symbol_set][5]); } } while (!feof(input)); fprintf(stdout, "%s", table_symbols[current_symbol_set][6]); + size_t table_column = 0; col = 0; while (col++ < rune_columns-2) - fprintf(stdout, "%s", table_symbols[current_symbol_set][7]); + if (table_column < table_columns-1 + && col % (max_table_column_width+1) == 0) + { + fprintf(stdout, "%s", + table_inner_symbols[current_inner_symbol_set][2]); + table_column++; + } + else + fprintf(stdout, "%s", table_symbols[current_symbol_set][7]); fprintf(stdout, "%s\n", table_symbols[current_symbol_set][8]); return 0; diff --git a/test/UTF-8-demo.txt b/test/UTF-8-demo.txt @@ -0,0 +1,212 @@ + +UTF-8 encoded sample plain-text file +‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +Markus Kuhn [ˈmaʳkʊs kuːn] <http://www.cl.cam.ac.uk/~mgk25/> — 2002-07-25 CC BY + + +The ASCII compatible UTF-8 encoding used in this plain-text file +is defined in Unicode, ISO 10646-1, and RFC 2279. + + +Using Unicode/UTF-8, you can write in emails and source code things such as + +Mathematics and sciences: + + ∮ E⋅da = Q, n → ∞, ∑ f(i) = ∏ g(i), ⎧⎡⎛┌─────┐⎞⎤⎫ + ⎪⎢⎜│a²+b³ ⎟⎥⎪ + ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β), ⎪⎢⎜│───── ⎟⎥⎪ + ⎪⎢⎜⎷ c₈ ⎟⎥⎪ + ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ, ⎨⎢⎜ ⎟⎥⎬ + ⎪⎢⎜ ∞ ⎟⎥⎪ + ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫), ⎪⎢⎜ ⎲ ⎟⎥⎪ + ⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪ + 2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm ⎩⎣⎝i=1 ⎠⎦⎭ + +Linguistics and dictionaries: + + ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn + Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ] + +APL: + + ((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈ + +Nicer typography in plain text files: + + ╔══════════════════════════════════════════╗ + ║ ║ + ║ • ‘single’ and “double” quotes ║ + ║ ║ + ║ • Curly apostrophes: “We’ve been here” ║ + ║ ║ + ║ • Latin-1 apostrophe and accents: '´` ║ + ║ ║ + ║ • ‚deutsche‘ „Anführungszeichen“ ║ + ║ ║ + ║ • †, ‡, ‰, •, 3–4, —, −5/+5, ™, … ║ + ║ ║ + ║ • ASCII safety test: 1lI|, 0OD, 8B ║ + ║ ╭─────────╮ ║ + ║ • the euro symbol: │ 14.95 € │ ║ + ║ ╰─────────╯ ║ + ╚══════════════════════════════════════════╝ + +Combining characters: + + STARGΛ̊TE SG-1, a = v̇ = r̈, a⃑ ⊥ b⃑ + +Greek (in Polytonic): + + The Greek anthem: + + Σὲ γνωρίζω ἀπὸ τὴν κόψη + τοῦ σπαθιοῦ τὴν τρομερή, + σὲ γνωρίζω ἀπὸ τὴν ὄψη + ποὺ μὲ βία μετράει τὴ γῆ. + + ᾿Απ᾿ τὰ κόκκαλα βγαλμένη + τῶν ῾Ελλήνων τὰ ἱερά + καὶ σὰν πρῶτα ἀνδρειωμένη + χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά! + + From a speech of Demosthenes in the 4th century BC: + + Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι, + ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς + λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ + τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿ + εἰς τοῦτο προήκοντα, ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ + πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν + οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι, + οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν + ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον + τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι + γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν + προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους + σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ + τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ + τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς + τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον. + + Δημοσθένους, Γ´ ᾿Ολυνθιακὸς + +Georgian: + + From a Unicode conference invitation: + + გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო + კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს, + ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს + ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი, + ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება + ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში, + ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში. + +Russian: + + From a Unicode conference invitation: + + Зарегистрируйтесь сейчас на Десятую Международную Конференцию по + Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии. + Конференция соберет широкий круг экспертов по вопросам глобального + Интернета и Unicode, локализации и интернационализации, воплощению и + применению Unicode в различных операционных системах и программных + приложениях, шрифтах, верстке и многоязычных компьютерных системах. + +Thai (UCS Level 2): + + Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese + classic 'San Gua'): + + [----------------------------|------------------------] + ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่ + สิบสองกษัตริย์ก่อนหน้าแลถัดไป สององค์ไซร้โง่เขลาเบาปัญญา + ทรงนับถือขันทีเป็นที่พึ่ง บ้านเมืองจึงวิปริตเป็นนักหนา + โฮจิ๋นเรียกทัพทั่วหัวเมืองมา หมายจะฆ่ามดชั่วตัวสำคัญ + เหมือนขับไสไล่เสือจากเคหา รับหมาป่าเข้ามาเลยอาสัญ + ฝ่ายอ้องอุ้นยุแยกให้แตกกัน ใช้สาวนั้นเป็นชนวนชื่นชวนใจ + พลันลิฉุยกุยกีกลับก่อเหตุ ช่างอาเพศจริงหนาฟ้าร้องไห้ + ต้องรบราฆ่าฟันจนบรรลัย ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ + + (The above is a two-column text. If combining characters are handled + correctly, the lines of the second column should be aligned with the + | character above.) + +Ethiopian: + + Proverbs in the Amharic language: + + ሰማይ አይታረስ ንጉሥ አይከሰስ። + ብላ ካለኝ እንደአባቴ በቆመጠኝ። + ጌጥ ያለቤቱ ቁምጥና ነው። + ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው። + የአፍ ወለምታ በቅቤ አይታሽም። + አይጥ በበላ ዳዋ ተመታ። + ሲተረጉሙ ይደረግሙ። + ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል። + ድር ቢያብር አንበሳ ያስር። + ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም። + እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም። + የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ። + ሥራ ከመፍታት ልጄን ላፋታት። + ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል። + የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ። + ተንጋሎ ቢተፉ ተመልሶ ባፉ። + ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው። + እግርህን በፍራሽህ ልክ ዘርጋ። + +Runes: + + ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ + + (Old English, which transcribed into Latin reads 'He cwaeth that he + bude thaem lande northweardum with tha Westsae.' and means 'He said + that he lived in the northern land near the Western Sea.') + +Braille: + + ⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌ + + ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞ + ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎ + ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂ + ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙ + ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑ + ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲ + + ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ + + ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹ + ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞ + ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕ + ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹ + ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎ + ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎ + ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳ + ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞ + ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ + + (The first couple of paragraphs of "A Christmas Carol" by Dickens) + +Compact font selection example text: + + ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789 + abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ + –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд + ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა + +Greetings in various languages: + + Hello world, Καλημέρα κόσμε, コンニチハ + +Box drawing alignment tests: █ + ▉ + ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳ + ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳ + ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳ + ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳ + ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎ + ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏ + ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ ▗▄▖▛▀▜ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█ + ▝▀▘▙▄▟ diff --git a/test/UTF-8-test.txt b/test/UTF-8-test.txt Бинарне датотеке се разликују. diff --git a/test/file.sh b/test/file.sh @@ -0,0 +1,2 @@ +#!/bin/sh +file ~/Downloads/* | sed -e's/ \+/ /g' | table -d : -c 110 diff --git a/test/ls-adv.sh b/test/ls-adv.sh @@ -0,0 +1,2 @@ +#!/bin/sh +ls -l | tail -n 15 | sed -e's/ \+/ /g' -e's/\t/ /g' | table -d " " -c 120 -s ss diff --git a/test/sales.csv b/test/sales.csv @@ -1,5 +1,11 @@ -,January,February,March,, -Unit 1,23.45,10.13,8.46,, -Unit 2,18.22,45.00,11.78,, -Unit 3,4.57,30.41,19.22,, -Total,0.00,0.00,0.00,, +,January,February,March +Unit 1,23.45,10.13,8.46 +Unit 2,18.22,45.00,11.78 +Unit 3,4.57,30.41,19.22 +Total,46.24,85.54,39.46 +,,, +,Јануар,Фебруар,Март +Артикал 1,45000.00,5000.00,64300.00 +Артикал 2,12000.00,21500.00,9800.00 +Артикал 3,16000.00,13000.00,11430.00 +Просек,24333.33,13166.67,28510.00 diff --git a/test/sales.sc b/test/sales.sc @@ -17,7 +17,26 @@ let B3 = 4.567 let C3 = 30.41 let D3 = 19.22 leftstring A4 = "Total" -let B4 = @sum(D7:D9) -let C4 = @sum(E7:E9) -let D4 = @sum(F7:F9) -goto A0 +let B4 = @sum(B1:B3) +let C4 = @sum(C1:C3) +let D4 = @sum(D1:D3) +leftstring B6 = "Јануар" +leftstring C6 = "Фебруар" +leftstring D6 = "Март" +leftstring A7 = "Артикал 1" +let B7 = 45000 +let C7 = 5000 +let D7 = 64300 +leftstring A8 = "Артикал 2" +let B8 = 12000 +let C8 = 21500 +let D8 = 9800 +leftstring A9 = "Артикал 3" +let B9 = 16000 +let C9 = 13000 +let D9 = 11430 +leftstring A10 = "Просек" +let B10 = @avg(B7:B9) +let C10 = @avg(C7:C9) +let D10 = @avg(D7:D9) +goto A10