Update license headers to conform to BSD 2-clause
[pp.git] / README.md
blob631d112dd73428637c8d3a74fd7ea9baf5ae797a
1 # pp (prepend)
3 The **pp** (prepend) utility takes the content of the file named by the *source* operand and inserts or prepends it
4 above the first line of the file named by the *target* operand. The file operands are processed in command-line order.
5 If the *source* file is a single dash (‘-’) or absent, **pp** reads from the standard input.
7 So, essentially, if I have a CSV file without a header and I want to quickly insert the header from a file, I
8 would run:
10 ```sh
11 $ pp header.txt spreadsheet.csv
12 ```
14 and it would be functionally equivalent to
16 ```sh
17 $ cat header.txt spreadsheet.csv > temp
18 $ mv temp spreadsheet.csv
19 ```
21 ## Features
22 * Quality
23     * Compiled with security hardening flags
24     * Static analysis integrated using clang's `scan-build` using checkers `alpha.security`, `alpha.core.CastSize`,
25     `alpha.core.CastToStruct`, `alpha.core.IdenticalExpr`, `alpha.core.PointerArithm`, `alpha.core.PointerSub`,
26     `alpha.core.SizeofPtr`, `alpha.core.TestAfterDivZero`, `alpha.unix`
27     * Test harness
28     * Follows [FreeBSD coding style](https://www.freebsd.org/cgi/man.cgi?query=style&sektion=9)
29 * Portable
30     * C99 compliant
31     * Self-contained, no external dependencies
32     * Easy to compile (needs clang >= 11.0) and uses POSIX make
34 ## Build dependencies
35 The only dependency is the toolchain needed to build the program using the Makefile, which is `clang` >= 11.0. That's
36 because the security flags used to build the executable are specific to clang.
38 If you want to build it with GCC and have equivalent security flags you can change the `CFLAGS` and `LDFLAGS` to the
39 following
41 ```
42 CFLAGS = -std=c99 -O2 -Wall -Wextra -Wpedantic \
43     -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 -Wformat-security \
44     -Wnull-dereference -Wstack-protector -Wtrampolines -Walloca -Wvla \
45     -Warray-bounds=2 -Wimplicit-fallthrough=3 -Wtraditional-conversion \
46     -Wshift-overflow=2 -Wcast-qual -Wstringop-overflow=4 -Wconversion \
47     -Warith-conversion -Wlogical-op -Wduplicated-cond -Wduplicated-branches \
48     -Wformat-signedness -Wshadow -Wstrict-overflow=4 -Wundef \
49     -Wstrict-prototypes -Wswitch-default -Wswitch-enum -Wstack-usage=1000000 \
50     -Wcast-align=strict \
51     -D_FORTIFY_SOURCE=2 \
52     -fstack-protector-strong -fstack-clash-protection -fPIE
54 LDFLAGS = -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack \
55     -Wl,-z,separate-code
56 ```
58 Otherwise you can just remove the security flags and compile it with
59 ```
60 CFLAGS = -std=c99 -O2 -Wall -Wextra -Wpedantic
61 LDFLAGS =
62 ```
64 or pass your own flags to make
65 ```sh
66 make CC=gcc CFLAGS=... LDFLAGS=...
67 ```
69 ## Installation
70 Clone this repository then
72 ```sh
73 $ make PREFIX=/usr install
74 ```
76 This will install the compiled binary under `PREFIX` (`/usr/bin`) in this case, if not specified `PREFIX` will default
77 to `/usr/local`. For staged installs, `DESTDIR` is also supported. As the binary does not have any dependency (other
78 than clang) it does not have to be installed before use.
80 ## Usage
81 Using **pp** is quite simple, you just specify the *source* file and *target* file
82 ```sh
83 $ pp source target
84 ```
85 The source file however, can be omitted, in this case the program takes the input from the standard input until `EOF` or
86 `^D` is reached
87 ```sh
88 $ pp target
89 ```
90 this behavior can also be achieved by using ‘-’ as *source* file
91 ```sh
92 $ pp - target
93 ```
95 ## Compilation
96 In order to build on any Unix-like system, simply run `make`. Since the binary does not have any dependencies, it can
97 just be copied into your `PATH`.
99 ### Test suite
100 The test suite consists of a POSIX shell script called `harness.sh` contained in the `test` folder. It's output is
101 similar to [googletest](https://github.com/google/googletest)'s and it can be invoked with `make test` which, if
102 everything is working should output something similar to
104 ./test/harness.sh
105 [----------] Test environment set-up.
106 [==========] Running 7 test cases.
107 [ RUN      ] empty_source
108 [       OK ] empty_source
109 [ RUN      ] empty_destination
110 [       OK ] empty_destination
111 [ RUN      ] trivial_test
112 [       OK ] trivial_test
113 [ RUN      ] stdin_source
114 [       OK ] stdin_source
115 [ RUN      ] utf8_source
116 [       OK ] utf8_source
117 [ RUN      ] filename_dash
118 [       OK ] filename_dash
119 [ RUN      ] opt_source
120 [       OK ] opt_source
121 [==========] 7 test cases ran.
122 [  PASSED  ] 7 tests.
123 [  FAILED  ] 0 tests.
124 [----------] Test environment teardown.
127 ### Static analysis
128 Static analysis on the code base is done by using clang's static analyzer run through `scan-build.sh` which wraps the
129 `scan-build` utility. The checkers used are part of the
130 [Experimental Checkers](https://releases.llvm.org/12.0.0/tools/clang/docs/analyzer/checkers.html#alpha-checkers)
131 (aka *alpha* checkers):
133 * `alpha.security`
134 * `alpha.core.CastSize`
135 * `alpha.core.CastToStruct`
136 * `alpha.core.IdenticalExpr`
137 * `alpha.core.PointerArithm`
138 * `alpha.core.PointerSub`
139 * `alpha.core.SizeofPtr`
140 * `alpha.core.TestAfterDivZero`
141 * `alpha.unix`