2 The **tabular** utility reads files containing tabular data sequentially and pretty prints them as a table.
3 The file operands are processed in command-line order. If the file is a single dash (‘-’) or absent, **tabular**
4 reads from the standard input. The separator character(s) of each column in the data set can be specified at run-time,
5 which defaults to `','`.
9 * Compiled with security hardening flags.
10 * Static analysis integrated using clang's `scan-build` using checkers `alpha.security`, `alpha.core.CastSize`,
11 `alpha.core.CastToStruct`, `alpha.core.IdenticalExpr`, `alpha.core.PointerArithm`, `alpha.core.PointerSub`,
12 `alpha.core.SizeofPtr`, `alpha.core.TestAfterDivZero`, `alpha.unix`.
13 * Follows [FreeBSD coding style](https://www.freebsd.org/cgi/man.cgi?query=style&sektion=9).
14 * [RFC4180](https://datatracker.ietf.org/doc/html/rfc4180) compliant:
15 * handles `\n`, `\r` and `\r\n` as new line
16 * if double-quotes are used to enclose fields it handles double quotes appearing inside a field only if
17 escaped by preceding it with another double quote. For example `"x""y"` is equivalent to `x"y`
18 * handles the precence of the separator character inside a quoted field.
20 * C99 compliant *and* may be built in an environment which provides POSIX.1-2001 system interfaces.
21 * Self-contained, no external dependencies
22 * Easy to compile (needs clang >= 11.0) and uses POSIX make.
25 * Input lines are limited to `LINE_MAX` bytes in lenght.
26 * Only single character separators are allowed for now.
27 * The program presumes the locale is UTF-8.
30 The only dependency is the toolchain needed to build the program using the Makefile, which is `clang` >= 11.0. That's
31 because the security flags used to build the executable are specific to clang.
33 If you want to build it with GCC and have equivalent security flags you can change the `CFLAGS` and `LDFLAGS` to the
37 CFLAGS = -std=c99 -O2 -Wall -Wextra -Wpedantic \
38 -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 -Wformat-security \
39 -Wnull-dereference -Wstack-protector -Wtrampolines -Walloca -Wvla \
40 -Warray-bounds=2 -Wimplicit-fallthrough=3 -Wtraditional-conversion \
41 -Wshift-overflow=2 -Wcast-qual -Wstringop-overflow=4 -Wconversion \
42 -Warith-conversion -Wlogical-op -Wduplicated-cond -Wduplicated-branches \
43 -Wformat-signedness -Wshadow -Wstrict-overflow=4 -Wundef \
44 -Wstrict-prototypes -Wswitch-default -Wswitch-enum -Wstack-usage=1000000 \
47 -fstack-protector-strong -fstack-clash-protection -fPIE
49 LDFLAGS = -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack \
53 Otherwise you can just remove the security flags and compile it with
55 CFLAGS = -std=c99 -O2 -Wall -Wextra -Wpedantic
59 or pass your own flags to make
61 make CC=gcc CFLAGS=... LDFLAGS=...
65 Clone this repository then
68 $ make PREFIX=/usr install
71 This will install the compiled binary under `PREFIX` (`/usr/bin`) in this case, if not specified `PREFIX` will default
72 to `/usr/local`. For staged installs, `DESTDIR` is also supported. As the binary does not have any dependency (other
75 **tabular** receives as input one or more files to print as a table. The files however, can be omitted, in this case
76 the program takes the input from the standard input until `EOF` or `^D` is reached. If a file is a single dash (‘-’),
77 **tabular** reads from standard input.
79 The options are as follows:
80 * **-s** Specify a character to be used to delimit the columns and each field. If omitted `','` is used.
83 Example CSVs are taken from https://people.sc.fsu.edu/~jburkardt/data/csv/csv.html
87 John,Doe,120 jefferson st.,Riverside, NJ, 08075
88 Jack,McGinnis,220 hobo Av.,Phila, PA,09119
89 "John ""Da Man""",Repici,120 Jefferson St.,Riverside, NJ,08075
90 Stephen,Tyler,"7452 Terrace ""At the Plaza"" road",SomeTown,SD, 91234
91 ,Blankman,,SomeTown, SD, 00298
92 "Joan ""the bone"", Anne",Jet,"9th, at Terrace plc",Desert City,CO,00123
94 $ tabular addresses.csv
95 John Doe 120 jefferson st. Riverside NJ 08075
96 Jack McGinnis 220 hobo Av. Phila PA 09119
97 John "Da Man" Repici 120 Jefferson St. Riverside NJ 08075
98 Stephen Tyler 7452 Terrace "At the Plaza" road SomeTown SD 91234
99 Blankman SomeTown SD 00298
100 Joan "the bone", Anne Jet 9th, at Terrace plc Desert City CO 00123
104 $ tabular tally_cab.csv - addresses.csv <<EOF
109 Distance (miles) "Fare ($)"
120 John Doe 120 jefferson st. Riverside NJ 08075
121 Jack McGinnis 220 hobo Av. Phila PA 09119
122 John "Da Man" Repici 120 Jefferson St. Riverside NJ 08075
123 Stephen Tyler 7452 Terrace "At the Plaza" road SomeTown SD 91234
124 Blankman SomeTown SD 00298
125 Joan "the bone", Anne Jet 9th, at Terrace plc Desert City CO 00123
129 $ cat names.csv | tabular -s ';'
131 23434 Norris, Chuck 24
132 34343 Bond, James "master" 57
136 Static analysis on the code base is done by using clang's static analyzer run through `scan-build.sh` which wraps the
137 `scan-build` utility. The checkers used are part of the
138 [Experimental Checkers](https://releases.llvm.org/12.0.0/tools/clang/docs/analyzer/checkers.html#alpha-checkers)
139 (aka *alpha* checkers):
142 * `alpha.core.CastSize`
143 * `alpha.core.CastToStruct`
144 * `alpha.core.IdenticalExpr`
145 * `alpha.core.PointerArithm`
146 * `alpha.core.PointerSub`
147 * `alpha.core.SizeofPtr`
148 * `alpha.core.TestAfterDivZero`