~q3cpma/csv-view

b889fdb42c8cf7d11b4c7d2adadd23f0841a4eef — q3cpma 2 years ago 58e5cc2
Change the min/max functionality to work on columns and some general cleanup
12 files changed, 172 insertions(+), 155 deletions(-)

M GNUmakefile
A README
D README.adoc
M include/opt.h
M src/cell.c
M src/opt.c
M src/table.c
M test/1.output
M test/2.csv
M test/2.output
M test/4.output
M test/test.sh
M GNUmakefile => GNUmakefile +6 -5
@@ 1,5 1,5 @@
BIN := csv_viewer
PREFIX := $$HOME
BIN := csv_view
PREFIX := /usr/local
CONFIG := Release

MAKEFLAGS := $(MAKEFLAGS) -r


@@ 60,10 60,11 @@ clean:

install: $(BIN)
	mkdir -p -- $(DESTDIR)$(PREFIX)/bin
	cp -f -- $^ $(DESTDIR)$(PREFIX)/bin
	cp -f -- $(BIN) $(DESTDIR)$(PREFIX)/bin
	chmod 755 -- $(addprefix $(DESTDIR)$(PREFIX)/bin/, $(BIN))

uninstall:
	rm -f -- $(addprefix $(DESTDIR)$(PREFIX)/bin/, $(BIN))
uninstall: | $(SUBMAKE)
	rm -- $(addprefix $(DESTDIR)$(PREFIX)/bin/, $(BIN))

lint: clean
	@command -v scan-build >/dev/null && scan-build -analyze-headers \

A README => README +56 -0
@@ 0,0 1,56 @@
    Description
    -----------

Simple CSV/DSV visualiser with some useful options. Follows rfc4180 except that:
  * Lines starting with '#' and empty lines are ignored.
  * End of row is '\n' (not CLRF).
  * Double quotes can be put inside quoted fields if escaped by another double quote.

+---------------------------------------------------------------------------------+
| NAME                                                                            |
|     csv_view - Simple CSV/DSV viewer                                            |
|                                                                                 |
| SYNOPSIS                                                                        |
|     csv_view [-hlmM] [-f FORMAT] [-r NROWS] [-d DELIMITER] FILE                 |
|                                                                                 |
| DESCRIPTION                                                                     |
|     Print FILE as a table to standard output.                                   |
|     If FILE is -, read standard input instead.                                  |
|                                                                                 |
|     -d DELIMITER                                                                |
|         Use a different delimiter than comma.                                   |
|                                                                                 |
|     -r NROWS                                                                    |
|         Ignore NROWS before searching for the column's min/max when using -m or |
|         -M. Defaults to 0.                                                      |
|                                                                                 |
|     -f FORMAT                                                                   |
|         Use FORMAT as printf(3) format for floating point values.               |
|         Defaults to "%g".                                                       |
|                                                                                 |
|     -h                                                                          |
|         Print this help message and exit.                                       |
|                                                                                 |
|     -l                                                                          |
|         Use line-drawing characters for printing.                               |
|                                                                                 |
|     -m                                                                          |
|         For each row, highlight the minimum numeric value in dim.               |
|                                                                                 |
|     -M                                                                          |
|         Same as -m, but highlight the maximum in bold.                          |
|                                                                                 |
|     -t                                                                          |
|         Trim whitespace around cell content.                                    |
|                                                                                 |
|     -v                                                                          |
|         Print the version and exit.                                             |
+---------------------------------------------------------------------------------+


    Dependencies
    ------------

* C11 compiler (tested with clang and gcc)
* ncurses
* GNU make

D README.adoc => README.adoc +0 -49
@@ 1,49 0,0 @@
....................................................................................................................
NAME
    csv_viewer - Simple csv/dsv viewer

SYNOPSIS
    csv_viewer [-hlmM] [-F format] [-f field] [-d delimiter] FILE

DESCRIPTION
    Print a csv file as a table to standard output.
    If FILE is -, read standard input.

    -d delimiter
            Use a different delimiter than comma.

    -f field
            Ignore the fields before field when using -m or -M. Defaults to 0.

    -F format
            Use as the printf(3) format for floating point values. Defaults to ".1f".

    -h
            Print this help message and exit.

    -l
            Use line-drawing characters for printing.

    -m
            For each row, highlight the minimum numeric value in dim.

    -M
            Same as -m, but highlight the maximum in bold.

    -t
            Trim whitespace around cell content.

....................................................................................................................

Follows rfc4180 except that:

* Lines starting with '#' and empty lines are ignored.
* End of row is '\n' (not CLRF).
* Double quotes can be put inside quoted fields if escaped by another double quote.


Dependencies
------------
* c11 compiler (tested with clang and gcc)
* ncurses
* GNU make
\ No newline at end of file

M include/opt.h => include/opt.h +1 -1
@@ 8,7 8,7 @@
typedef struct
{
	char *float_fmt;
	size_t find_field;
	size_t row_skip;
	uint32_t delim; /* UCS codepoint for the field separator */
	bool find_max : 1;
	bool find_min : 1;

M src/cell.c => src/cell.c +3 -0
@@ 15,6 15,9 @@ void cell_free(Cell *c)
	if(!c)
		return;
	if(c->tag == STRING)
	{
		PTR_ARRAY_FREE(c->lines, free);
		ARRAY_FREE(c->line_width);
	}
	free(c);
}

M src/opt.c => src/opt.c +32 -31
@@ 9,25 9,26 @@

static const char *usage =
	"NAME\n"
	"    %s - Simple csv/dsv viewer\n"
	"    %s - Simple CSV/DSV viewer\n"
	"\n"
	"SYNOPSIS\n"
	"    %s [-hlmM] [-F format] [-f field] [-d delimiter] FILE\n"
	"    %s [-hlmM] [-f FORMAT] [-r NROWS] [-d DELIMITER] FILE\n"
	"\n"
	"DESCRIPTION\n"
	"    Print a csv file as a table to standard output.\n"
	"    If FILE is -, read standard input.\n"
	"    Print FILE as a table to standard output.\n"
	"    If FILE is -, read standard input instead.\n"
	"\n"
	"    -d delimiter\n"
	"    -d DELIMITER\n"
	"        Use a different delimiter than comma.\n"
	"\n"
	"    -f field\n"
	"        Ignore the fields before field when using -m or -M. Defaults"
	" to 0.\n"
	"    -r NROWS\n"
	"        Ignore NROWS before searching for the column's min/max when using"
	" -m or\n"
	"        -M. Defaults to 0.\n"
	"\n"
	"    -F format\n"
	"        Use as the printf(3) format for floating point values. Defaults"
	" to \"%% g\".\n"
	"    -f FORMAT\n"
	"        Use FORMAT as printf(3) format for floating point values.\n"
	"        Defaults to \"%%g\".\n"
	"\n"
	"    -h\n"
	"        Print this help message and exit.\n"


@@ 57,47 58,35 @@ Options getopt_wrap(int argc, char **argv)
	Options ret = {0};
	const char *p = optarg;

	ret.float_fmt = "% g";
	ret.float_fmt = "%g";
	ret.delim = ',';

	for(int opt; (opt = getopt(argc, argv, "f:F:d:hlmMtv")) != -1; )
	for(int opt; (opt = getopt(argc, argv, "f:d:hlmMr:tv")) != -1; )
	{
		switch(opt)
		{
			case 'f':
				if(!strtoul_wrap(&(ret.find_field), optarg))
			case 'd':
				ret.delim = xutf8_step(&p);
				if(*p)
				{
					die("%s: the -f option requires an unsigned integer",
					die("%s: the delimiter must be a single UTF-8 character",
						optarg);
				}
				break;

			case 'F':
			case 'f':
				ret.float_fmt = optarg;
				errchk(regmatch(optarg, float_fmt_regexp),
					"%s: invalid float format", optarg);
				const char *fnd = strchr(optarg, '%');
				if(!fnd || (fnd && strchr(fnd + 1, '%')))
					die("%s: wrong format argument to -F option", optarg);
				break;

			case 'd':
				ret.delim = xutf8_step(&p);
				if(*p)
				{
					die("%s: the delimiter must be a single UTF-8 character",
						optarg);
				}
					die("%s: wrong format argument to -f option", optarg);
				break;

			case 'h':
				printf(usage, PROG_NAME, PROG_NAME);
				exit(EXIT_SUCCESS);

			case 'v':
				printf("%s version: %s\n", PROG_NAME, PROG_VERSION);
				exit(EXIT_SUCCESS);

			case 'l':
				ret.linedraw = true;
				break;


@@ 110,10 99,22 @@ Options getopt_wrap(int argc, char **argv)
				ret.find_max = true;
				break;

			case 'r':
				if(!strtoul_wrap(&(ret.row_skip), optarg))
				{
					die("%s: the -r option requires an unsigned integer",
						optarg);
				}
				break;

			case 't':
				ret.trim_whitespace = true;
				break;

			case 'v':
				printf("%s version: %s\n", PROG_NAME, PROG_VERSION);
				exit(EXIT_SUCCESS);

			default:
				printf(usage, PROG_NAME, PROG_NAME);
				exit(EXIT_FAILURE);

M src/table.c => src/table.c +31 -14
@@ 1,4 1,5 @@
#include <float.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <wchar.h>


@@ 120,6 121,7 @@ void table_print(FILE *stream, Table *t, const Options *opt)
{
	const size_t nrow = ARRAY_LENGTH(t), ncol = ARRAY_LENGTH(t[0]);

	struct {size_t pos; double val;} *colmin = NULL, *colmax = NULL;
	size_t *colw = xcalloc(ncol, sizeof(size_t)),
		*rowh = xcalloc(nrow, sizeof(size_t));
	uint8_t **attrs = xmalloc(nrow * sizeof(uint8_t *));


@@ 127,36 129,49 @@ void table_print(FILE *stream, Table *t, const Options *opt)
		attrs[row] = xcalloc(ncol, sizeof(uint8_t));

	if(opt->find_min || opt->find_max)
	{
		term_init();
		colmin = xmalloc(ncol * sizeof(struct {size_t pos; double val;}));
		colmax = xmalloc(ncol * sizeof(struct {size_t pos; double val;}));
		for(size_t col = 0; col < ncol; ++col)
		{
			colmin[col].val = DBL_MAX;
			colmax[col].val = -DBL_MAX;
		}
	}

	/*Compute table cell dimensions and find row min/max*/
	for(size_t row = 0; row < nrow; ++row)
	{
		double min = DBL_MAX, max = -DBL_MAX;
		ssize_t mincol = -1, maxcol = -1;
		for(size_t col = 0; col < ncol; ++col)
		{
			const Cell *c = t[row][col]; /*For readability*/
			const Cell *const c = t[row][col]; /*For readability*/
			colw[col] = u64max(colw[col], c->width);
			rowh[row] = u64max(rowh[row], c->height);
			if(col >= opt->find_field && (c->tag == INTEGER || c->tag == FLOAT))
			if(row >= opt->row_skip && (c->tag == INTEGER || c->tag == FLOAT))
			{
				if(opt->find_min && CELL_NVAL(c) < min)
				if(opt->find_min && CELL_NVAL(c) < colmin[col].val)
				{
					min = CELL_NVAL(c);
					mincol = col;
					colmin[col].val = CELL_NVAL(c);
					colmin[col].pos = row;
				}
				if(opt->find_max && CELL_NVAL(c) > max)
				if(opt->find_max && CELL_NVAL(c) > colmax[col].val)
				{
					max = CELL_NVAL(c);
					maxcol = col;
					colmax[col].val = CELL_NVAL(c);
					colmax[col].pos = row;
				}
			}
		}
		if(mincol != -1)
			attrs[row][mincol] |= TERMATTR_DIM;
		if(maxcol != -1)
			attrs[row][maxcol] |= TERMATTR_BOLD;
	}
	if(opt->find_min || opt->find_max)
	{
		for(size_t col = 0; col < ncol; ++col)
		{
			if(colmin[col].val != DBL_MAX)
				attrs[colmin[col].pos][col] |= TERMATTR_DIM;
			if(colmax[col].val != -DBL_MAX)
				attrs[colmax[col].pos][col] |= TERMATTR_BOLD;
		}
	}

	for(size_t row = 0; row < nrow; ++row)


@@ 177,6 192,8 @@ void table_print(FILE *stream, Table *t, const Options *opt)

	free(colw);
	free(rowh);
	free(colmin);
	free(colmax);
	for(size_t row = 0; row < nrow; ++row)
		free(attrs[row]);
	free(attrs);

M test/1.output => test/1.output +6 -6
@@ 1,18 1,18 @@
+------+----------------+----------------------------------------+------------------------+-----------+
| Year | Make           | Model                                  | Description            | Price     |
+------+----------------+----------------------------------------+------------------------+-----------+
| 1997 | Ford           | E350                                   | ac, abs, moon          | 3000.0000 |
| 1997 | Ford           | E350                                   | ac, abs, moon          | 3000.0000 |
+------+----------------+----------------------------------------+------------------------+-----------+
| 1999 | Chevy          | Venture "Extended Edition"             |                        | 4900.0000 |
| 1999 | Chevy          | Venture "Extended Edition"             |                        | 4900.0000 |
+------+----------------+----------------------------------------+------------------------+-----------+
| 1999 | Chevy          | Venture "Extended Edition, Very Large" |                        | 5000.0000 |
| 1999 | Chevy          | Venture "Extended Edition, Very Large" |                        | 5000.0000 |
+------+----------------+----------------------------------------+------------------------+-----------+
| 1991 | マツダ株式会社 | RX-7 FC, Turbocharged!                 |                        | 7000.0000 |
| 1991 | マツダ株式会社 | RX-7 FC, Turbocharged!                 |                        | 7000.0000 |
+------+----------------+----------------------------------------+------------------------+-----------+
| 1996 | Jeep           | Grand Cherokee                         | MUST SELL!             | 4799.0000 |
| 1996 | Jeep           | Grand Cherokee                         | MUST SELL!             | 4799.0000 |
|      |                |                                        | air, moon roof, loaded |           |
+------+----------------+----------------------------------------+------------------------+-----------+
| 2000 | Toyota         | Corolla                                | line1                  | 8000.5679 |
| 2000 | Toyota         | Corolla                                | line1                  | 8000.5679 |
|      |                |                                        | line2                  |           |
|      |                |                                        | line3                  |           |
|      |                |                                        | line4                  |           |

M test/2.csv => test/2.csv +10 -14
@@ 1,14 1,10 @@
Degree,kara(thresh=1),kara(thresh=2),kara(thresh=4),kara(thresh=8),kara(thresh=16),kara(thresh=32),kara(thresh=64),kara(thresh=128),naive
8,0.000070,0.000016,0.000011,0.000010,0.000008,0.000008,0.000007,0.000008,0.000007
16,0.000077,0.000037,0.000024,0.000022,0.000027,0.000014,0.000014,0.000013,0.000013
32,0.000202,0.000160,0.000071,0.000068,0.000075,0.000099,0.000049,0.000048,0.000047
64,0.000587,0.000332,0.000210,0.000202,0.000224,0.000280,0.000377,0.000185,0.000179
128,0.001184,0.000298,0.000215,0.000200,0.000229,0.000296,0.000375,0.000509,0.000244
256,0.001754,0.000937,0.000660,0.000603,0.000710,0.000851,0.001098,0.001438,0.000903
512,0.005142,0.002813,0.001826,0.001754,0.002032,0.002554,0.003286,0.004363,0.003557
1024,0.015735,0.008772,0.005581,0.005294,0.006092,0.007695,0.009872,0.013065,0.014152
2048,0.046491,0.029617,0.016532,0.015859,0.018326,0.023108,0.029691,0.039217,0.056363
4096,0.141647,0.073605,0.049661,0.047745,0.055027,0.069509,0.089445,0.118070,0.225694
8192,0.460367,0.230238,0.148449,0.142034,0.166336,0.211032,0.268572,0.354294,0.909226
16384,1.307833,0.809571,0.456097,0.434285,0.502572,0.626099,0.808081,1.062579,3.610455
32768,3.829337,2.139101,1.403984,1.289114,1.482390,1.867964,2.407981,3.160550,14.410283
Degree,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768
kara(thresh=1),0.000070,0.000077,0.000202,0.000587,0.001184,0.001754,0.005142,0.015735,0.046491,0.141647,0.460367,1.307833,3.829337
kara(thresh=2),0.000016,0.000037,0.000160,0.000332,0.000298,0.000937,0.002813,0.008772,0.029617,0.073605,0.230238,0.809571,2.139101
kara(thresh=4),0.000011,0.000024,0.000071,0.000210,0.000215,0.000660,0.001826,0.005581,0.016532,0.049661,0.148449,0.456097,1.403984
kara(thresh=8),0.000010,0.000022,0.000068,0.000202,0.000200,0.000603,0.001754,0.005294,0.015859,0.047745,0.142034,0.434285,1.289114
kara(thresh=16),0.000008,0.000027,0.000075,0.000224,0.000229,0.000710,0.002032,0.006092,0.018326,0.055027,0.166336,0.502572,1.482390
kara(thresh=32),0.000008,0.000014,0.000099,0.000280,0.000296,0.000851,0.002554,0.007695,0.023108,0.069509,0.211032,0.626099,1.867964
kara(thresh=64),0.000007,0.000014,0.000049,0.000377,0.000375,0.001098,0.003286,0.009872,0.029691,0.089445,0.268572,0.808081,2.407981
kara(thresh=128),0.000008,0.000013,0.000048,0.000185,0.000509,0.001438,0.004363,0.013065,0.039217,0.118070,0.354294,1.062579,3.160550
naive,0.000007,0.000013,0.000047,0.000179,0.000244,0.000903,0.003557,0.014152,0.056363,0.225694,0.909226,3.610455,14.410283

M test/2.output => test/2.output +21 -29
@@ 1,29 1,21 @@
┌────────┬────────────────┬────────────────┬────────────────┬────────────────┬─────────────────┬─────────────────┬─────────────────┬──────────────────┬─────────┐
│ Degree │ kara(thresh=1) │ kara(thresh=2) │ kara(thresh=4) │ kara(thresh=8) │ kara(thresh=16) │ kara(thresh=32) │ kara(thresh=64) │ kara(thresh=128) │ naive   │
├────────┼────────────────┼────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┼─────────────────┼──────────────────┼─────────┤
│ 8      │ 0.0001         │ 0.0000         │ 0.0000         │ 0.0000         │ 0.0000          │ 0.0000          │ 0.0000          │ 0.0000           │ 0.0000  │
├────────┼────────────────┼────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┼─────────────────┼──────────────────┼─────────┤
│ 16     │ 0.0001         │ 0.0000         │ 0.0000         │ 0.0000         │ 0.0000          │ 0.0000          │ 0.0000          │ 0.0000           │ 0.0000  │
├────────┼────────────────┼────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┼─────────────────┼──────────────────┼─────────┤
│ 32     │ 0.0002         │ 0.0002         │ 0.0001         │ 0.0001         │ 0.0001          │ 0.0001          │ 0.0000          │ 0.0000           │ 0.0000  │
├────────┼────────────────┼────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┼─────────────────┼──────────────────┼─────────┤
│ 64     │ 0.0006         │ 0.0003         │ 0.0002         │ 0.0002         │ 0.0002          │ 0.0003          │ 0.0004          │ 0.0002           │ 0.0002  │
├────────┼────────────────┼────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┼─────────────────┼──────────────────┼─────────┤
│ 128    │ 0.0012         │ 0.0003         │ 0.0002         │ 0.0002         │ 0.0002          │ 0.0003          │ 0.0004          │ 0.0005           │ 0.0002  │
├────────┼────────────────┼────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┼─────────────────┼──────────────────┼─────────┤
│ 256    │ 0.0018         │ 0.0009         │ 0.0007         │ 0.0006         │ 0.0007          │ 0.0009          │ 0.0011          │ 0.0014           │ 0.0009  │
├────────┼────────────────┼────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┼─────────────────┼──────────────────┼─────────┤
│ 512    │ 0.0051         │ 0.0028         │ 0.0018         │ 0.0018         │ 0.0020          │ 0.0026          │ 0.0033          │ 0.0044           │ 0.0036  │
├────────┼────────────────┼────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┼─────────────────┼──────────────────┼─────────┤
│ 1024   │ 0.0157         │ 0.0088         │ 0.0056         │ 0.0053         │ 0.0061          │ 0.0077          │ 0.0099          │ 0.0131           │ 0.0142  │
├────────┼────────────────┼────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┼─────────────────┼──────────────────┼─────────┤
│ 2048   │ 0.0465         │ 0.0296         │ 0.0165         │ 0.0159         │ 0.0183          │ 0.0231          │ 0.0297          │ 0.0392           │ 0.0564  │
├────────┼────────────────┼────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┼─────────────────┼──────────────────┼─────────┤
│ 4096   │ 0.1416         │ 0.0736         │ 0.0497         │ 0.0477         │ 0.0550          │ 0.0695          │ 0.0894          │ 0.1181           │ 0.2257  │
├────────┼────────────────┼────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┼─────────────────┼──────────────────┼─────────┤
│ 8192   │ 0.4604         │ 0.2302         │ 0.1484         │ 0.1420         │ 0.1663          │ 0.2110          │ 0.2686          │ 0.3543           │ 0.9092  │
├────────┼────────────────┼────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┼─────────────────┼──────────────────┼─────────┤
│ 16384  │ 1.3078         │ 0.8096         │ 0.4561         │ 0.4343         │ 0.5026          │ 0.6261          │ 0.8081          │ 1.0626           │ 3.6105  │
├────────┼────────────────┼────────────────┼────────────────┼────────────────┼─────────────────┼─────────────────┼─────────────────┼──────────────────┼─────────┤
│ 32768  │ 3.8293         │ 2.1391         │ 1.4040         │ 1.2891         │ 1.4824          │ 1.8680          │ 2.4080          │ 3.1606           │ 14.4103 │
└────────┴────────────────┴────────────────┴────────────────┴────────────────┴─────────────────┴─────────────────┴─────────────────┴──────────────────┴─────────┘
┌──────────────────┬─────────┬─────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬─────────┐
│ Degree           │ 8       │ 16      │ 32       │ 64       │ 128      │ 256      │ 512      │ 1024     │ 2048     │ 4096     │ 8192     │ 16384    │ 32768   │
├──────────────────┼─────────┼─────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤
│ kara(thresh=1)   │ 7e-05   │ 7.7e-05 │ 0.000202 │ 0.000587 │ 0.001184 │ 0.001754 │ 0.005142 │ 0.015735 │ 0.046491 │ 0.141647 │ 0.460367 │ 1.30783  │ 3.82934 │
├──────────────────┼─────────┼─────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤
│ kara(thresh=2)   │ 1.6e-05 │ 3.7e-05 │ 0.00016  │ 0.000332 │ 0.000298 │ 0.000937 │ 0.002813 │ 0.008772 │ 0.029617 │ 0.073605 │ 0.230238 │ 0.809571 │ 2.1391  │
├──────────────────┼─────────┼─────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤
│ kara(thresh=4)   │ 1.1e-05 │ 2.4e-05 │ 7.1e-05  │ 0.00021  │ 0.000215 │ 0.00066  │ 0.001826 │ 0.005581 │ 0.016532 │ 0.049661 │ 0.148449 │ 0.456097 │ 1.40398 │
├──────────────────┼─────────┼─────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤
│ kara(thresh=8)   │ 1e-05   │ 2.2e-05 │ 6.8e-05  │ 0.000202 │ 0.0002   │ 0.000603 │ 0.001754 │ 0.005294 │ 0.015859 │ 0.047745 │ 0.142034 │ 0.434285 │ 1.28911 │
├──────────────────┼─────────┼─────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤
│ kara(thresh=16)  │ 8e-06   │ 2.7e-05 │ 7.5e-05  │ 0.000224 │ 0.000229 │ 0.00071  │ 0.002032 │ 0.006092 │ 0.018326 │ 0.055027 │ 0.166336 │ 0.502572 │ 1.48239 │
├──────────────────┼─────────┼─────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤
│ kara(thresh=32)  │ 8e-06   │ 1.4e-05 │ 9.9e-05  │ 0.00028  │ 0.000296 │ 0.000851 │ 0.002554 │ 0.007695 │ 0.023108 │ 0.069509 │ 0.211032 │ 0.626099 │ 1.86796 │
├──────────────────┼─────────┼─────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤
│ kara(thresh=64)  │ 7e-06   │ 1.4e-05 │ 4.9e-05  │ 0.000377 │ 0.000375 │ 0.001098 │ 0.003286 │ 0.009872 │ 0.029691 │ 0.089445 │ 0.268572 │ 0.808081 │ 2.40798 │
├──────────────────┼─────────┼─────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤
│ kara(thresh=128) │ 8e-06   │ 1.3e-05 │ 4.8e-05  │ 0.000185 │ 0.000509 │ 0.001438 │ 0.004363 │ 0.013065 │ 0.039217 │ 0.11807  │ 0.354294 │ 1.06258  │ 3.16055 │
├──────────────────┼─────────┼─────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤
│ naive            │ 7e-06   │ 1.3e-05 │ 4.7e-05  │ 0.000179 │ 0.000244 │ 0.000903 │ 0.003557 │ 0.014152 │ 0.056363 │ 0.225694 │ 0.909226 │ 3.61045  │ 14.4103 │
└──────────────────┴─────────┴─────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴─────────┘

M test/4.output => test/4.output +1 -1
@@ 1,1 1,1 @@
csv_viewer: Error row 1, field 2, character 2: missing matching double quote
csv_view: Error row 1, field 2, character 2: missing matching double quote

M test/test.sh => test/test.sh +5 -5
@@ 4,23 4,23 @@ set -u
[ $# -lt 1 ] && echo "Usage: $0 test..." && exit 1
[ $# -eq 1 ] && [ "$1" = "all" ] && set -- 1 2 3 4

cd "$(dirname -- "$0")"
bin=../csv_viewer
cd -- "$(dirname -- "$0")"
bin=../csv_view

for i
do
	case "$i" in
		1)
			"$bin" -F %.4f -f0 -m -M 1.csv | diff - 1.output
			"$bin" -f %.4f -r2 -m -M 1.csv | diff - 1.output
			;;
		2)
			"$bin" -l -F %.4f -f1 -m -M 2.csv | diff - 2.output
			"$bin" -l -r1 -m -M 2.csv | diff - 2.output
			;;
		3)
			"$bin" -l 3.csv | diff - 3.output
			;;
		4)
			"$bin" -F %.4f 4.csv 2>&1 | diff - 4.output
			"$bin" -f %.4f 4.csv 2>&1 | diff - 4.output
			;;
		*)
			echo "$i: unknown test"