Complete README.md
[tabular.git] / README.md
blob136feb4973d58a189656ccc56a00bf647630ad1a
1 # tabular
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 `','`.
7 ## Features
8 * Quality
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.
19 * Portable
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.
24 ## Limitations
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.
29 ## Build dependencies
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
34 following
36 ```
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 \
45     -Wcast-align=strict \
46     -D_FORTIFY_SOURCE=2 \
47     -fstack-protector-strong -fstack-clash-protection -fPIE
49 LDFLAGS = -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack \
50     -Wl,-z,separate-code
51 ```
53 Otherwise you can just remove the security flags and compile it with
54 ```
55 CFLAGS = -std=c99 -O2 -Wall -Wextra -Wpedantic
56 LDFLAGS =
57 ```
59 or pass your own flags to make
60 ```sh
61 make CC=gcc CFLAGS=... LDFLAGS=...
62 ```
64 ## Installation
65 Clone this repository then
67 ```sh
68 $ make PREFIX=/usr install
69 ```
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
74 ## Usage
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.
82 ### Examples
83 Example CSVs are taken from https://people.sc.fsu.edu/~jburkardt/data/csv/csv.html
85 ```sh
86 $ cat addresses.csv
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
103 ```sh
104 $ tabular tally_cab.csv - addresses.csv <<EOF
105 foo,bar,baz
106 a,b,c,
109 Distance (miles)   "Fare ($)"
110  4.5                 18.00
111 26.7                 73.75
112  6.7                 23.00
113 16.4                 56.00
114 32.7                 83.25
115  5.7                 17.50
116 77.0                190.50
117  8.3                 19.65
118 foo  bar  baz
119 a    b    c
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
128 ```sh
129 $ cat names.csv | tabular -s ';'
130 ID     NAME                  AGE
131 23434  Norris, Chuck         24
132 34343  Bond, James "master"  57
135 ### Static analysis
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):
141 * `alpha.security`
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`
149 * `alpha.unix`