чување a8843eba5ea5615cc6b0f2eee24586f5b97bd705
родитељ 3a4ad5f662691b15244bcf9872b49bbddfb83677
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Sun, 11 Oct 2020 22:25:13 +0200
Merge branch 'wip-2020-10' into master
Diffstat:
измењених датотека: 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 && 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, ¤t_symbol_set);
+ result = set_symbol_set(arg, ¤t_symbol_set,
+ ¤t_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, ¤t_symbol_set);
+ result = set_symbol_set(arg, ¤t_symbol_set,
+ ¤t_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