commit d85bb07

Antonio  ·  2026-06-08 08:55:17 +0000 UTC
parent d85bb07
First commit

Signed-off-by: Antonio <anto@shackles.my.domain>
259 files changed,  +34485, -0
A README
+77, -0
 1@@ -0,0 +1,77 @@
 2+Language: Cpp
 3+BasedOnStyle: LLVM
 4+AlignAfterOpenBracket: Align
 5+AlignConsecutiveMacros: false
 6+AlignConsecutiveAssignments: false
 7+AlignConsecutiveDeclarations: false
 8+AlignEscapedNewlines: Right
 9+AlignOperands: Align
10+AlignTrailingComments: true
11+AllowAllArgumentsOnNextLine: true
12+AllowAllParametersOfDeclarationOnNextLine: true
13+AllowShortBlocksOnASingleLine: false
14+AllowShortCaseLabelsOnASingleLine: false
15+AllowShortFunctionsOnASingleLine: false
16+AllowShortIfStatementsOnASingleLine: false
17+AllowShortLoopsOnASingleLine: false
18+AlwaysBreakAfterDefinitionReturnType: TopLevel
19+AlwaysBreakAfterReturnType: TopLevelDefinitions
20+AlwaysBreakBeforeMultilineStrings: false
21+BinPackArguments: true
22+BinPackParameters: true
23+BraceWrapping:
24+  AfterCaseLabel: false
25+  AfterClass: false
26+  AfterControlStatement: Never
27+  AfterEnum: false
28+  AfterFunction: true
29+  AfterNamespace: false
30+  AfterObjCDeclaration: false
31+  AfterStruct: false
32+  AfterUnion: false
33+  AfterExternBlock: false
34+  BeforeCatch: false
35+  BeforeElse: false
36+  IndentBraces: false
37+  SplitEmptyFunction: true
38+  SplitEmptyRecord: true
39+  SplitEmptyNamespace: true
40+BreakBeforeBinaryOperators: None
41+BreakBeforeBraces: Custom
42+BreakBeforeTernaryOperators: true
43+BreakStringLiterals: true
44+ColumnLimit: 80
45+ContinuationIndentWidth: 8
46+DerivePointerAlignment: false
47+DisableFormat: false
48+FixNamespaceComments: true
49+IncludeBlocks: Preserve
50+IncludeCategories:
51+  - Regex: '^".*"'
52+    Priority: 1
53+  - Regex: '^<.*>'
54+    Priority: 2
55+IndentCaseLabels: false
56+IndentPPDirectives: None
57+IndentWidth: 8
58+IndentWrappedFunctionNames: false
59+KeepEmptyLinesAtTheStartOfBlocks: false
60+MaxEmptyLinesToKeep: 1
61+NamespaceIndentation: None
62+PointerAlignment: Right
63+ReflowComments: true
64+SortIncludes: true
65+SortUsingDeclarations: true
66+SpaceAfterCStyleCast: false
67+SpaceBeforeAssignmentOperators: true
68+SpaceBeforeParens: ControlStatements
69+SpaceInEmptyParentheses: false
70+SpacesBeforeTrailingComments: 1
71+SpacesInAngles: false
72+SpacesInContainerLiterals: false
73+SpacesInCStyleCastParentheses: false
74+SpacesInParentheses: false
75+SpacesInSquareBrackets: false
76+Standard: c++03
77+TabWidth: 8
78+UseTab: Always
+68, -0
 1@@ -0,0 +1,68 @@
 2+Copyright (C) 2006, 2019 Rob Landley [rob@landley.net](mailto:rob@landley.net)
 3+Copyright (c) 2011 Connor Lane Smith [cls@lubutu.com](mailto:cls@lubutu.com)
 4+Copyright (c) 2011-2016 Dimitris Papastamos [sin@2f30.org](mailto:sin@2f30.org)
 5+Copyright (c) 2011 Hiltjo Posthuma [hiltjo@codemadness.org](mailto:hiltjo@codemadness.org)
 6+Copyright (c) 2011 Kamil CholewiƄski [harry666t@gmail.com](mailto:harry666t@gmail.com)
 7+Copyright (c) 2011 pancake [pancake@youterm.com](mailto:pancake@youterm.com)
 8+Copyright (c) 2011 Random832 [random832@fastmail.us](mailto:random832@fastmail.us)
 9+Copyright (c) 2011 Rob Pilling [robpilling@gmail.com](mailto:robpilling@gmail.com)
10+Copyright (c) 2012 Christoph Lohmann [20h@r-36.net](mailto:20h@r-36.net)
11+Copyright (c) 2012 David Galos [galosd83@students.rowan.edu](mailto:galosd83@students.rowan.edu)
12+Copyright (c) 2012 Kurt H. Maier [khm@sciops.net](mailto:khm@sciops.net)
13+Copyright (c) 2012 Robert Ransom [rransom.8774@gmail.com](mailto:rransom.8774@gmail.com)
14+Copyright (c) 2012 William Haddon [william@haddonthethird.net](mailto:william@haddonthethird.net)
15+Copyright (c) 2013 Anselm R Garbe [anselm@garbe.us](mailto:anselm@garbe.us)
16+Copyright (c) 2013 Christian Hesse [mail@eworm.de](mailto:mail@eworm.de)
17+Copyright (c) 2013 David Galos [galosd83@students.rowan.edu](mailto:galosd83@students.rowan.edu)
18+Copyright (c) 2013-2016 Dimitris Papapastamos [sin@2f30.org](mailto:sin@2f30.org)
19+Copyright (c) 2013 dsp [dsp@2f30.org](mailto:dsp@2f30.org)
20+Copyright (c) 2013 Federico G. Benavento [benavento@gmail.com](mailto:benavento@gmail.com)
21+Copyright (c) 2013 Jakob Kramer [jakob.kramer@gmx.de](mailto:jakob.kramer@gmx.de)
22+Copyright (c) 2013 Jesse Ogle [jesse.p.ogle@gmail.com](mailto:jesse.p.ogle@gmail.com)
23+Copyright (c) 2013 Lorenzo Cogotti [miciamail@hotmail.it](mailto:miciamail@hotmail.it)
24+Copyright (c) 2013 Markus Teich [markus.teich@stusta.mhn.de](mailto:markus.teich@stusta.mhn.de)
25+Copyright (c) 2013 Markus Wichmann [nullplan@gmx.net](mailto:nullplan@gmx.net)
26+Copyright (c) 2013 oblique [psyberbits@gmail.com](mailto:psyberbits@gmail.com)
27+Copyright (c) 2013 Roberto E. Vargas Caballero [k0ga@shike2.com](mailto:k0ga@shike2.com)
28+Copyright (c) 2013 s-p-k [mr.dwts@gmail.com](mailto:mr.dwts@gmail.com)
29+Copyright (c) 2013 Truls Becken [truls.becken@gmail.com](mailto:truls.becken@gmail.com)
30+Copyright (c) 2014 Adria Garriga [rhaps0dy@installgentoo.com](mailto:rhaps0dy@installgentoo.com)
31+Copyright (c) 2014 Ari Malinen [ari.malinen@gmail.com](mailto:ari.malinen@gmail.com)
32+Copyright (c) 2014 Brandon Mulcahy [brandon@jangler.info](mailto:brandon@jangler.info)
33+Copyright (c) 2014 Carlos J. Torres [vlaadbrain@gmail.com](mailto:vlaadbrain@gmail.com)
34+Copyright (c) 2014 Daniel Bainton [dpb@driftaway.org](mailto:dpb@driftaway.org)
35+Copyright (c) 2014 Evan Gates [evan.gates@gmail.com](mailto:evan.gates@gmail.com)
36+Copyright (c) 2014-2015 Greg Reagle [greg.reagle@umbc.edu](mailto:greg.reagle@umbc.edu)
37+Copyright (c) 2014-2016 Hiltjo Posthuma [hiltjo@codemadness.org](mailto:hiltjo@codemadness.org)
38+Copyright (c) 2014 Jan Tatje [jan@jnt.io](mailto:jan@jnt.io)
39+Copyright (c) 2014 Jeffrey Picard [jeff@jeffreypicard.com](mailto:jeff@jeffreypicard.com)
40+Copyright (c) 2014-2016 Laslo Hunhold [dev@frign.de](mailto:dev@frign.de)
41+Copyright (c) 2014 Michael Forney [mforney@mforney.org](mailto:mforney@mforney.org)
42+Copyright (c) 2014 Roberto E. Vargas Caballero [k0ga@shike2.com](mailto:k0ga@shike2.com)
43+Copyright (c) 2014 Silvan Jegen [s.jegen@gmail.com](mailto:s.jegen@gmail.com)
44+Copyright (c) 2014 Tuukka Kataja [stuge@xor.fi](mailto:stuge@xor.fi)
45+Copyright (c) 2015 Dionysis Grigoropoulos [info@erethon.com](mailto:info@erethon.com)
46+Copyright (c) 2015 Quentin Rameau [quinq@fifth.space](mailto:quinq@fifth.space)
47+Copyright (c) 2015 Risto Salminen [ripejcp@gmail.com](mailto:ripejcp@gmail.com)
48+Copyright (c) 2015 Tai Chi Minh Ralph Eastwood [tcmreastwood@gmail.com](mailto:tcmreastwood@gmail.com)
49+Copyright (c) 2015 Wolfgang Corcoran-Mathe [wcm@sigwinch.xyz](mailto:wcm@sigwinch.xyz)
50+Copyright (c) 2016 Eivind Uggedal [eivind@uggedal.com](mailto:eivind@uggedal.com)
51+Copyright (c) 2016 Mattias Andrée [m@maandree.se](mailto:m@maandree.se)
52+Copyright (c) 2026 xplshn [anto@xplshn.com.ar](mailto:anto@xplshn.com.ar) (https://github.com/xplshn)
53+
54+Permission to use, copy, modify, and/or distribute this software for any
55+purpose with or without fee is hereby granted, provided that the above
56+copyright notice and this permission notice appear in all copies.
57+
58+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
59+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
60+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
61+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
62+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
63+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
64+OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
65+SOFTWARE.
66+
67+Portions of this software (specifically utils under net/) are partially
68+based on code written by Rob Landley
69+The rest are based on SBASE/UBASE source code
+321, -0
  1@@ -0,0 +1,321 @@
  2+.POSIX:
  3+include config.mk
  4+
  5+.SUFFIXES:
  6+.SUFFIXES: .y .o .c
  7+
  8+HDR =\
  9+	shared/arg.h\
 10+	shared/compat.h\
 11+	shared/config.h\
 12+	shared/crypt.h\
 13+	shared/fs.h\
 14+	shared/md5.h\
 15+	shared/queue.h\
 16+	shared/sha1.h\
 17+	shared/sha224.h\
 18+	shared/sha256.h\
 19+	shared/sha384.h\
 20+	shared/sha512.h\
 21+	shared/sha512-224.h\
 22+	shared/sha512-256.h\
 23+	shared/text.h\
 24+	shared/utf.h\
 25+	shared/util.h\
 26+	shared/passwd.h\
 27+	shared/reboot.h\
 28+	shared/rtc.h\
 29+	shared/proc.h
 30+
 31+LIBUTFOBJ =\
 32+	shared/libutf/fgetrune.o\
 33+	shared/libutf/fputrune.o\
 34+	shared/libutf/isalnumrune.o\
 35+	shared/libutf/isalpharune.o\
 36+	shared/libutf/isblankrune.o\
 37+	shared/libutf/iscntrlrune.o\
 38+	shared/libutf/isdigitrune.o\
 39+	shared/libutf/isgraphrune.o\
 40+	shared/libutf/isprintrune.o\
 41+	shared/libutf/ispunctrune.o\
 42+	shared/libutf/isspacerune.o\
 43+	shared/libutf/istitlerune.o\
 44+	shared/libutf/isxdigitrune.o\
 45+	shared/libutf/lowerrune.o\
 46+	shared/libutf/rune.o\
 47+	shared/libutf/runetype.o\
 48+	shared/libutf/upperrune.o\
 49+	shared/libutf/utf.o\
 50+	shared/libutf/utftorunestr.o
 51+
 52+LIBUTILOBJ =\
 53+	shared/libutil/concat.o\
 54+	shared/libutil/cp.o\
 55+	shared/libutil/crypt.o\
 56+	shared/libutil/confirm.o\
 57+	shared/libutil/ealloc.o\
 58+	shared/libutil/enmasse.o\
 59+	shared/libutil/eprintf.o\
 60+	shared/libutil/eregcomp.o\
 61+	shared/libutil/estrtod.o\
 62+	shared/libutil/fnck.o\
 63+	shared/libutil/fshut.o\
 64+	shared/libutil/getlines.o\
 65+	shared/libutil/human.o\
 66+	shared/libutil/linecmp.o\
 67+	shared/libutil/md5.o\
 68+	shared/libutil/memmem.o\
 69+	shared/libutil/mkdirp.o\
 70+	shared/libutil/mode.o\
 71+	shared/libutil/parseoffset.o\
 72+	shared/libutil/putword.o\
 73+	shared/libutil/reallocarray.o\
 74+	shared/libutil/recurse.o\
 75+	shared/libutil/rm.o\
 76+	shared/libutil/sha1.o\
 77+	shared/libutil/sha224.o\
 78+	shared/libutil/sha256.o\
 79+	shared/libutil/sha384.o\
 80+	shared/libutil/sha512.o\
 81+	shared/libutil/sha512-224.o\
 82+	shared/libutil/sha512-256.o\
 83+	shared/libutil/strcasestr.o\
 84+	shared/libutil/strlcat.o\
 85+	shared/libutil/strlcpy.o\
 86+	shared/libutil/strsep.o\
 87+	shared/libutil/strnsubst.o\
 88+	shared/libutil/strtonum.o\
 89+	shared/libutil/writeall.o\
 90+	shared/libutil/unescape.o\
 91+	shared/libutil/agetcwd.o\
 92+	shared/libutil/agetline.o\
 93+	shared/libutil/apathmax.o\
 94+	shared/libutil/estrtol.o\
 95+	shared/libutil/estrtoul.o\
 96+	shared/libutil/explicit_bzero.o\
 97+	shared/libutil/passwd.o\
 98+	shared/libutil/proc.o\
 99+	shared/libutil/tty.o\
100+	shared/libutil/fconcat.o\
101+	shared/libutil/recurse_dir.o
102+
103+LIB = shared/libutf/libutf.a shared/libutil/libutil.a
104+
105+POSIX_BIN =\
106+	cmd/posix/basename\
107+	cmd/posix/cal\
108+	cmd/posix/cat\
109+	cmd/posix/chgrp\
110+	cmd/posix/chmod\
111+	cmd/posix/chown\
112+	cmd/posix/cksum\
113+	cmd/posix/cmp\
114+	cmd/posix/comm\
115+	cmd/posix/cp\
116+	cmd/posix/cut\
117+	cmd/posix/date\
118+	cmd/posix/dd\
119+	cmd/posix/df\
120+	cmd/posix/dirname\
121+	cmd/posix/du\
122+	cmd/posix/echo\
123+	cmd/posix/ed\
124+	cmd/posix/env\
125+	cmd/posix/expand\
126+	cmd/posix/expr\
127+	cmd/posix/false\
128+	cmd/posix/find\
129+	cmd/posix/fold\
130+	cmd/posix/getconf\
131+	cmd/posix/grep\
132+	cmd/posix/head\
133+	cmd/posix/id\
134+	cmd/posix/join\
135+	cmd/posix/kill\
136+	cmd/posix/link\
137+	cmd/posix/ln\
138+	cmd/posix/logger\
139+	cmd/posix/logname\
140+	cmd/posix/ls\
141+	cmd/posix/mesg\
142+	cmd/posix/mkdir\
143+	cmd/posix/mkfifo\
144+	cmd/posix/mv\
145+	cmd/posix/nice\
146+	cmd/posix/nl\
147+	cmd/posix/nohup\
148+	cmd/posix/od\
149+	cmd/posix/paste\
150+	cmd/posix/pathchk\
151+	cmd/posix/printf\
152+	cmd/posix/ps\
153+	cmd/posix/pwd\
154+	cmd/posix/readlink\
155+	cmd/posix/renice\
156+	cmd/posix/rm\
157+	cmd/posix/rmdir\
158+	cmd/posix/sed\
159+	cmd/posix/sleep\
160+	cmd/posix/sort\
161+	cmd/posix/split\
162+	cmd/posix/tail\
163+	cmd/posix/tee\
164+	cmd/posix/test\
165+	cmd/posix/time\
166+	cmd/posix/touch\
167+	cmd/posix/tr\
168+	cmd/posix/true\
169+	cmd/posix/tsort\
170+	cmd/posix/tty\
171+	cmd/posix/uname\
172+	cmd/posix/unexpand\
173+	cmd/posix/uniq\
174+	cmd/posix/unlink\
175+	cmd/posix/uudecode\
176+	cmd/posix/uuencode\
177+	cmd/posix/wc\
178+	cmd/posix/who\
179+	cmd/posix/xargs
180+
181+LINUX_BIN =\
182+	cmd/linux/blkdiscard\
183+	cmd/linux/chvt\
184+	cmd/linux/ctrlaltdel\
185+	cmd/linux/dmesg\
186+	cmd/linux/eject\
187+	cmd/linux/fallocate\
188+	cmd/linux/free\
189+	cmd/linux/freeramdisk\
190+	cmd/linux/fsfreeze\
191+	cmd/linux/hwclock\
192+	cmd/linux/insmod\
193+	cmd/linux/lsmod\
194+	cmd/linux/mkswap\
195+	cmd/linux/mount\
196+	cmd/linux/mountpoint\
197+	cmd/linux/pidof\
198+	cmd/linux/pivot_root\
199+	cmd/linux/pwdx\
200+	cmd/linux/readahead\
201+	cmd/linux/rmmod\
202+	cmd/linux/swaplabel\
203+	cmd/linux/swapoff\
204+	cmd/linux/swapon\
205+	cmd/linux/switch_root\
206+	cmd/linux/umount\
207+	cmd/linux/unshare\
208+	cmd/linux/uptime\
209+	cmd/linux/vtallow
210+
211+NET_BIN =\
212+	cmd/net/netcat\
213+	cmd/net/tftp\
214+	cmd/net/tunctl\
215+	cmd/net/wget\
216+	cmd/net/ping\
217+	cmd/net/ifconfig\
218+	cmd/net/host\
219+	cmd/net/httpd
220+
221+XSI_BIN =\
222+	cmd/xsi/mknod\
223+	cmd/xsi/passwd\
224+	cmd/xsi/su
225+
226+PSEUDO_BIN =\
227+	cmd/pseudo/chroot\
228+	cmd/pseudo/clear\
229+	cmd/pseudo/cols\
230+	cmd/pseudo/cron\
231+	cmd/pseudo/flock\
232+	cmd/pseudo/getty\
233+	cmd/pseudo/halt\
234+	cmd/pseudo/hostname\
235+	cmd/pseudo/killall5\
236+	cmd/pseudo/last\
237+	cmd/pseudo/lastlog\
238+	cmd/pseudo/login\
239+	cmd/pseudo/md5sum\
240+	cmd/pseudo/mktemp\
241+	cmd/pseudo/nologin\
242+	cmd/pseudo/pagesize\
243+	cmd/pseudo/printenv\
244+	cmd/pseudo/respawn\
245+	cmd/pseudo/rev\
246+	cmd/pseudo/seq\
247+	cmd/pseudo/setsid\
248+	cmd/pseudo/sha1sum\
249+	cmd/pseudo/sha224sum\
250+	cmd/pseudo/sha256sum\
251+	cmd/pseudo/sha384sum\
252+	cmd/pseudo/sha512sum\
253+	cmd/pseudo/sha512-224sum\
254+	cmd/pseudo/sha512-256sum\
255+	cmd/pseudo/sponge\
256+	cmd/pseudo/stat\
257+	cmd/pseudo/tar\
258+	cmd/pseudo/truncate\
259+	cmd/pseudo/watch\
260+	cmd/pseudo/which\
261+	cmd/pseudo/whoami\
262+	cmd/pseudo/xinstall\
263+	cmd/pseudo/yes
264+
265+MAKEOBJ =\
266+	cmd/posix/make/defaults.o\
267+	cmd/posix/make/main.o\
268+	cmd/posix/make/parser.o\
269+	cmd/posix/make/posix.o\
270+	cmd/posix/make/rules.o
271+
272+OBJ = $(LIBUTFOBJ) $(LIBUTILOBJ) $(MAKEOBJ)
273+
274+all: $(LIB) $(POSIX_BIN) $(LINUX_BIN) $(NET_BIN) $(XSI_BIN) $(PSEUDO_BIN) cmd/posix/make/make
275+
276+$(POSIX_BIN) $(LINUX_BIN) $(NET_BIN) $(XSI_BIN) $(PSEUDO_BIN): $(LIB)
277+
278+$(OBJ) $(POSIX_BIN) $(LINUX_BIN) $(NET_BIN) $(XSI_BIN) $(PSEUDO_BIN): $(HDR)
279+
280+.o:
281+	$(CC) $(LDFLAGS) -o $@ $< $(LIB) $(LDLIBS)
282+
283+.c.o:
284+	$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
285+
286+.c:
287+	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIB) $(LDLIBS)
288+
289+cmd/posix/bc.c: cmd/posix/bc.y
290+	$(YACC) -d -o $@ $<
291+
292+cmd/posix/bc: cmd/posix/bc.c
293+	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ cmd/posix/bc.c $(LIB) $(LDLIBS)
294+
295+$(MAKEOBJ): cmd/posix/make/make.h
296+
297+cmd/posix/make/make: $(MAKEOBJ) $(LIB)
298+	$(CC) $(LDFLAGS) -o $@ $(MAKEOBJ) $(LIB) $(LDLIBS)
299+
300+shared/libutf/libutf.a: $(LIBUTFOBJ)
301+	$(AR) $(ARFLAGS) $@ $?
302+	$(RANLIB) $@
303+
304+shared/libutil/libutil.a: $(LIBUTILOBJ)
305+	$(AR) $(ARFLAGS) $@ $?
306+	$(RANLIB) $@
307+
308+cmd/posix/getconf: cmd/posix/getconf.h
309+
310+cmd/posix/getconf.h:
311+	scripts/getconf.sh > $@ || { rm -f $@; exit 1; }
312+
313+box: $(LIB)
314+	CC='$(CC)' CPPFLAGS='$(CPPFLAGS)' CFLAGS='$(CFLAGS)' \
315+	LDFLAGS='$(LDFLAGS)' LDLIBS='$(LDLIBS)' OBJCOPY='$(OBJCOPY)' \
316+	scripts/mkbox
317+
318+clean:
319+	rm -f shared/libutf/*.o shared/libutil/*.o cmd/posix/make/*.o
320+	rm -f $(POSIX_BIN) $(LINUX_BIN) $(NET_BIN) $(XSI_BIN) $(PSEUDO_BIN) $(LIB)
321+	rm -f cmd/posix/make/make cmd/posix/getconf.h cmd/posix/bc.c
322+	rm -rf aruu-box .box
A README
+181, -0
  1@@ -0,0 +1,181 @@
  2+Argentino Roca Unix Utilities
  3+=============================
  4+
  5+ARUU is a unified fork of sbase and ubase, it is an effort trying to
  6+complete SBASE & UBASE., new utils partially based on toybox have
  7+been added, specifically, the utils under cmd/net are partially based
  8+on their toybox applet equivalent.
  9+
 10+OVERVIEW
 11+========
 12+
 13+aruu builds two things:
 14+
 15+  1. individual tool binaries (default 'make all')
 16+  2. aruu-box: a multi-call binary containing every tool ('make box')
 17+
 18+The multi-call binary is built by scripts/mkbox. It uses objcopy to
 19+rename each tool's 'main' symbol, generates a C dispatch table, then
 20+links everything into a single statically-dispatched binary. Invoke
 21+tools by symlinking aruu-box to the tool name, or by running:
 22+
 23+    aruu-box <command> [args...]
 24+
 25+To install symlinks into a directory:
 26+
 27+    aruu-box -i /usr/local/bin
 28+
 29+REQUIREMENTS
 30+============
 31+
 32+  cc       POSIX.1-2008-compliant C compiler (pcc, etc)
 33+  make     POSIX make (pdpmake, gmake, bmake)
 34+  ar       archive tool
 35+  ranlib   archive indexer
 36+  objcopy  for 'make box' only
 37+
 38+Optional:
 39+
 40+  yacc     only needed if rebuilding bc from bc.y
 41+
 42+BUILDING
 43+========
 44+
 45+Build all individual tools:
 46+
 47+    make
 48+
 49+Build the multi-call binary:
 50+
 51+    make box
 52+
 53+Both targets can be combined:
 54+
 55+    make all box
 56+
 57+Configuration is in config.mk. Override compiler and flags:
 58+
 59+    make CC=musl-gcc CFLAGS='-Os -static'
 60+
 61+Override install prefix:
 62+
 63+    make PREFIX=/usr install
 64+
 65+INSTALL
 66+=======
 67+
 68+    make install           installs individual tools to $(PREFIX)/bin
 69+    aruu-box -i /usr/bin   installs symlinks for the box binary
 70+
 71+SOURCE LAYOUT
 72+=============
 73+
 74+    config.mk              build configuration
 75+    Makefile               pdpmake-compatible build rules
 76+    scripts/
 77+      mkbox                builds aruu-box from compiled tool objects
 78+      getconf.sh           generates cmd/posix/getconf.h at build time
 79+    shared/
 80+      *.h                  project headers (util.h, arg.h, utf.h, ...)
 81+      libutil/             utility library (eprintf, ealloc, recurse, ...)
 82+      libutf/              UTF-8/rune library
 83+    cmd/
 84+      posix/               POSIX.1-2008 tools (cat, ls, grep, sed, ...)
 85+      posix/make/          POSIX make implementation
 86+      linux/               Linux-specific tools (mount, dmesg, insmod, ...)
 87+      net/                 networking tools (wget, ping, nc, ifconfig, ...)
 88+      pseudo/              widely-used non-POSIX tools (tar, stat, seq, ...)
 89+      xsi/                 XSI-extension tools (mknod, su, passwd)
 90+
 91+TOOLS
 92+=====
 93+
 94+posix: [, basename, cal, cat, chgrp, chmod, chown, cksum, cmp, comm,
 95+       cp, cut, date, dd, df, dirname, du, echo, ed, env, expand,
 96+       expr, false, find, fold, getconf, grep, head, id, join, kill,
 97+       link, ln, logger, logname, ls, mesg, mkdir, mkfifo, mv, nice,
 98+       nl, nohup, od, paste, pathchk, printf, ps, pwd, readlink,
 99+       renice, rm, rmdir, sed, sleep, sort, split, tail, tee, test,
100+       time, touch, tr, true, tsort, tty, uname, unexpand, uniq,
101+       unlink, uudecode, uuencode, wc, who, xargs
102+
103+posix/make: make
104+
105+linux: blkdiscard, chvt, ctrlaltdel, dmesg, eject, fallocate, free,
106+       freeramdisk, fsfreeze, hwclock, insmod, lsmod, lsusb, mkswap,
107+       mount, mountpoint, pidof, pivot_root, pwdx, readahead, rmmod,
108+       swaplabel, swapoff, swapon, switch_root, sysctl, umount,
109+       unshare, uptime, vtallow
110+
111+net:   host, httpd, ifconfig, netcat, ping, tftp, tunctl, wget
112+
113+pseudo: chroot, clear, cols, cron, flock, getty, halt, hostname,
114+        install, killall5, last, lastlog, login, md5sum, mktemp,
115+        nologin, pagesize, printenv, respawn, rev, seq, setsid,
116+        sha1sum, sha224sum, sha256sum, sha384sum, sha512sum,
117+        sha512-224sum, sha512-256sum, sponge, stat, tar, truncate,
118+        watch, which, whoami, yes
119+
120+xsi:   mknod, passwd, su
121+
122+LICENSE
123+=======
124+
125+ISC, see ./LICENSE for details. Credits:
126+Copyright (C) 2006, 2019 Rob Landley [rob@landley.net](mailto:rob@landley.net)
127+Copyright (c) 2011 Connor Lane Smith [cls@lubutu.com](mailto:cls@lubutu.com)
128+Copyright (c) 2011-2016 Dimitris Papastamos [sin@2f30.org](mailto:sin@2f30.org)
129+Copyright (c) 2011 Hiltjo Posthuma [hiltjo@codemadness.org](mailto:hiltjo@codemadness.org)
130+Copyright (c) 2011 Kamil CholewiƄski [harry666t@gmail.com](mailto:harry666t@gmail.com)
131+Copyright (c) 2011 pancake [pancake@youterm.com](mailto:pancake@youterm.com)
132+Copyright (c) 2011 Random832 [random832@fastmail.us](mailto:random832@fastmail.us)
133+Copyright (c) 2011 Rob Pilling [robpilling@gmail.com](mailto:robpilling@gmail.com)
134+Copyright (c) 2012 Christoph Lohmann [20h@r-36.net](mailto:20h@r-36.net)
135+Copyright (c) 2012 David Galos [galosd83@students.rowan.edu](mailto:galosd83@students.rowan.edu)
136+Copyright (c) 2012 Kurt H. Maier [khm@sciops.net](mailto:khm@sciops.net)
137+Copyright (c) 2012 Robert Ransom [rransom.8774@gmail.com](mailto:rransom.8774@gmail.com)
138+Copyright (c) 2012 William Haddon [william@haddonthethird.net](mailto:william@haddonthethird.net)
139+Copyright (c) 2013 Anselm R Garbe [anselm@garbe.us](mailto:anselm@garbe.us)
140+Copyright (c) 2013 Christian Hesse [mail@eworm.de](mailto:mail@eworm.de)
141+Copyright (c) 2013 David Galos [galosd83@students.rowan.edu](mailto:galosd83@students.rowan.edu)
142+Copyright (c) 2013-2016 Dimitris Papapastamos [sin@2f30.org](mailto:sin@2f30.org)
143+Copyright (c) 2013 dsp [dsp@2f30.org](mailto:dsp@2f30.org)
144+Copyright (c) 2013 Federico G. Benavento [benavento@gmail.com](mailto:benavento@gmail.com)
145+Copyright (c) 2013 Jakob Kramer [jakob.kramer@gmx.de](mailto:jakob.kramer@gmx.de)
146+Copyright (c) 2013 Jesse Ogle [jesse.p.ogle@gmail.com](mailto:jesse.p.ogle@gmail.com)
147+Copyright (c) 2013 Lorenzo Cogotti [miciamail@hotmail.it](mailto:miciamail@hotmail.it)
148+Copyright (c) 2013 Markus Teich [markus.teich@stusta.mhn.de](mailto:markus.teich@stusta.mhn.de)
149+Copyright (c) 2013 Markus Wichmann [nullplan@gmx.net](mailto:nullplan@gmx.net)
150+Copyright (c) 2013 oblique [psyberbits@gmail.com](mailto:psyberbits@gmail.com)
151+Copyright (c) 2013 Roberto E. Vargas Caballero [k0ga@shike2.com](mailto:k0ga@shike2.com)
152+Copyright (c) 2013 s-p-k [mr.dwts@gmail.com](mailto:mr.dwts@gmail.com)
153+Copyright (c) 2013 Truls Becken [truls.becken@gmail.com](mailto:truls.becken@gmail.com)
154+Copyright (c) 2014 Adria Garriga [rhaps0dy@installgentoo.com](mailto:rhaps0dy@installgentoo.com)
155+Copyright (c) 2014 Ari Malinen [ari.malinen@gmail.com](mailto:ari.malinen@gmail.com)
156+Copyright (c) 2014 Brandon Mulcahy [brandon@jangler.info](mailto:brandon@jangler.info)
157+Copyright (c) 2014 Carlos J. Torres [vlaadbrain@gmail.com](mailto:vlaadbrain@gmail.com)
158+Copyright (c) 2014 Daniel Bainton [dpb@driftaway.org](mailto:dpb@driftaway.org)
159+Copyright (c) 2014 Evan Gates [evan.gates@gmail.com](mailto:evan.gates@gmail.com)
160+Copyright (c) 2014-2015 Greg Reagle [greg.reagle@umbc.edu](mailto:greg.reagle@umbc.edu)
161+Copyright (c) 2014-2016 Hiltjo Posthuma [hiltjo@codemadness.org](mailto:hiltjo@codemadness.org)
162+Copyright (c) 2014 Jan Tatje [jan@jnt.io](mailto:jan@jnt.io)
163+Copyright (c) 2014 Jeffrey Picard [jeff@jeffreypicard.com](mailto:jeff@jeffreypicard.com)
164+Copyright (c) 2014-2016 Laslo Hunhold [dev@frign.de](mailto:dev@frign.de)
165+Copyright (c) 2014 Michael Forney [mforney@mforney.org](mailto:mforney@mforney.org)
166+Copyright (c) 2014 Roberto E. Vargas Caballero [k0ga@shike2.com](mailto:k0ga@shike2.com)
167+Copyright (c) 2014 Silvan Jegen [s.jegen@gmail.com](mailto:s.jegen@gmail.com)
168+Copyright (c) 2014 Tuukka Kataja [stuge@xor.fi](mailto:stuge@xor.fi)
169+Copyright (c) 2015 Dionysis Grigoropoulos [info@erethon.com](mailto:info@erethon.com)
170+Copyright (c) 2015 Quentin Rameau [quinq@fifth.space](mailto:quinq@fifth.space)
171+Copyright (c) 2015 Risto Salminen [ripejcp@gmail.com](mailto:ripejcp@gmail.com)
172+Copyright (c) 2015 Tai Chi Minh Ralph Eastwood [tcmreastwood@gmail.com](mailto:tcmreastwood@gmail.com)
173+Copyright (c) 2015 Wolfgang Corcoran-Mathe [wcm@sigwinch.xyz](mailto:wcm@sigwinch.xyz)
174+Copyright (c) 2016 Eivind Uggedal [eivind@uggedal.com](mailto:eivind@uggedal.com)
175+Copyright (c) 2016 Mattias Andrée [m@maandree.se](mailto:m@maandree.se)
176+Copyright (c) 2026 xplshn [anto@xplshn.com.ar](mailto:anto@xplshn.com.ar) (https://github.com/xplshn)
177+
178+Portions of this software (specifically utils under net/) are partially
179+based on code written by Rob Landley
180+The rest are based on SBASE/UBASE source code
181+
182+=~= Argentino Roca Unix Utilities =~= https://github.com/xplshn/aruu =~=
+48, -0
 1@@ -0,0 +1,48 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/ioctl.h>
 4+#include <sys/mount.h>
 5+#include <sys/stat.h>
 6+#include <sys/types.h>
 7+
 8+#include <fcntl.h>
 9+#include <stdint.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+#define OFFSET_IDX	0
15+#define LENGTH_IDX	1
16+
17+#define BLKDISCARD	_IO(0x12, 119)
18+
19+static void
20+usage(void)
21+{
22+	eprintf("usage: %s device\n", argv0);
23+}
24+
25+int
26+main(int argc, char *argv[])
27+{
28+	uint64_t range[2];
29+	int fd;
30+
31+	ARGBEGIN {
32+	default:
33+		usage();
34+	} ARGEND
35+
36+	if (argc != 1)
37+		usage();
38+
39+	fd = open(argv[0], O_RDWR);
40+	if (fd < 0)
41+		eprintf("open: %s:", argv[0]);
42+	range[OFFSET_IDX] = 0;
43+	if (ioctl(fd, BLKGETSIZE64, &range[LENGTH_IDX]) < 0)
44+		eprintf("BLKGETSIZE64: %s:", argv[0]);
45+	if (ioctl(fd, BLKDISCARD, range) < 0)
46+		eprintf("BLKDISCARD: %s:", argv[0]);
47+	close(fd);
48+	return 0;
49+}
+67, -0
 1@@ -0,0 +1,67 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/ioctl.h>
 4+#include <sys/types.h>
 5+
 6+#include <fcntl.h>
 7+#include <limits.h>
 8+#include <stdio.h>
 9+#include <string.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+#define KDGKBTYPE	0x4B33	/* get keyboard type */
15+
16+#define VT_ACTIVATE	0x5606	/* make vt active */
17+#define VT_WAITACTIVE	0x5607	/* wait for vt active */
18+
19+static char *vt[] = {
20+	"/proc/self/fd/0",
21+	"/dev/console",
22+	"/dev/tty",
23+	"/dev/tty0",
24+};
25+
26+static void
27+usage(void)
28+{
29+	eprintf("usage: %s num\n", argv0);
30+}
31+
32+int
33+main(int argc, char *argv[])
34+{
35+	unsigned int n, i;
36+	int fd;
37+	char c;
38+
39+	ARGBEGIN {
40+	default:
41+		usage();
42+	} ARGEND;
43+
44+	if (argc != 1)
45+		usage();
46+
47+	n = estrtonum(argv[0], 0, UINT_MAX);
48+	for (i = 0; i < LEN(vt); i++) {
49+		if ((fd = open(vt[i], O_RDONLY)) < 0)
50+			continue;
51+		c = 0;
52+		if (ioctl(fd, KDGKBTYPE, &c) == 0)
53+			goto found;
54+		if (close(fd) < 0)
55+			eprintf("close %s:", vt[i]);
56+	}
57+	eprintf("no console found\n");
58+
59+found:
60+	if (ioctl(fd, VT_ACTIVATE, n) == -1)
61+		eprintf("VT_ACTIVATE %u:", n);
62+	if (ioctl(fd, VT_WAITACTIVE, n) == -1)
63+		eprintf("VT_WAITACTIVE %u:", n);
64+	if (close(fd) < 0)
65+		eprintf("close %s:", vt[i]);
66+
67+	return 0;
68+}
+42, -0
 1@@ -0,0 +1,42 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/syscall.h>
 4+
 5+#include <stdio.h>
 6+#include <unistd.h>
 7+
 8+#include "reboot.h"
 9+#include "util.h"
10+
11+static void
12+usage(void)
13+{
14+	eprintf("usage: %s -h | -s\n", argv0);
15+}
16+
17+int
18+main(int argc, char *argv[])
19+{
20+	int hflag = 0, sflag = 0, cmd;
21+
22+	ARGBEGIN {
23+	case 'h':
24+		hflag = 1;
25+		break;
26+	case 's':
27+		sflag = 1;
28+		break;
29+	default:
30+		usage();
31+	} ARGEND;
32+
33+	if (argc || !(hflag ^ sflag))
34+		usage();
35+
36+	cmd = hflag ? LINUX_REBOOT_CMD_CAD_ON : LINUX_REBOOT_CMD_CAD_OFF;
37+
38+	if (syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
39+	            cmd, NULL) < 0)
40+		eprintf("reboot:");
41+
42+	return 0;
43+}
+81, -0
 1@@ -0,0 +1,81 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/klog.h>
 4+
 5+#include <stdio.h>
 6+#include <stdlib.h>
 7+#include <string.h>
 8+#include <unistd.h>
 9+
10+#include "util.h"
11+
12+enum {
13+	SYSLOG_ACTION_READ_ALL = 3,
14+	SYSLOG_ACTION_CLEAR = 5,
15+	SYSLOG_ACTION_CONSOLE_LEVEL = 8,
16+	SYSLOG_ACTION_SIZE_BUFFER = 10
17+};
18+
19+static void
20+dmesg_show(const void *buf, size_t n)
21+{
22+	const char *p = buf;
23+	ssize_t r;
24+
25+	r = write(1, p, n);
26+	if (r < 0)
27+		eprintf("write:");
28+	if (r > 0 && p[r - 1] != '\n')
29+		putchar('\n');
30+}
31+
32+static void
33+usage(void)
34+{
35+	eprintf("usage: %s [-Ccr] [-n level]\n", argv0);
36+}
37+
38+int
39+main(int argc, char *argv[])
40+{
41+	int n;
42+	char *buf;
43+	int cflag = 0;
44+	long level;
45+
46+	ARGBEGIN {
47+	case 'C':
48+		if (klogctl(SYSLOG_ACTION_CLEAR, NULL, 0) < 0)
49+			eprintf("klogctl:");
50+		return 0;
51+	case 'c':
52+		cflag = 1;
53+		break;
54+	case 'r':
55+		break;
56+	case 'n':
57+		level = estrtol(EARGF(usage()), 10);
58+		if (klogctl(SYSLOG_ACTION_CONSOLE_LEVEL, NULL, level) < 0)
59+			eprintf("klogctl:");
60+		return 0;
61+	default:
62+		usage();
63+	} ARGEND;
64+
65+	n = klogctl(SYSLOG_ACTION_SIZE_BUFFER, NULL, 0);
66+	if (n < 0)
67+		eprintf("klogctl:");
68+
69+	buf = emalloc(n);
70+
71+	n = klogctl(SYSLOG_ACTION_READ_ALL, buf, n);
72+	if (n < 0)
73+		eprintf("klogctl:");
74+
75+	dmesg_show(buf, n);
76+
77+	if (cflag && klogctl(SYSLOG_ACTION_CLEAR, NULL, 0) < 0)
78+		eprintf("klogctl:");
79+
80+	free(buf);
81+	return 0;
82+}
+68, -0
 1@@ -0,0 +1,68 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/ioctl.h>
 4+#include <sys/stat.h>
 5+#include <sys/types.h>
 6+
 7+#include <fcntl.h>
 8+#include <stdio.h>
 9+#include <unistd.h>
10+
11+#include "util.h"
12+
13+enum {
14+	OPEN_TRAY = 0x5309,
15+	CLOSE_TRAY = 0x5319,
16+};
17+
18+static int tflag = 0;
19+static int ret = 0;
20+
21+static void
22+eject(const char *devname)
23+{
24+	int fd, out;
25+
26+	if ((fd = open(devname, O_RDONLY | O_NONBLOCK)) < 0) {
27+		weprintf("open %s:", devname);
28+		ret = 1;
29+	} else if (tflag && ioctl(fd, CLOSE_TRAY, &out) < 0) {
30+		weprintf("ioctl %s:", devname);
31+		ret = 1;
32+	} else if (!tflag && ioctl(fd, OPEN_TRAY, &out) < 0) {
33+		weprintf("ioctl %s:", devname);
34+		ret = 1;
35+	}
36+
37+	if (fd >= 0 && close(fd) < 0) {
38+		weprintf("close %s:", devname);
39+		ret = 1;
40+	}
41+}
42+
43+
44+static void
45+usage(void)
46+{
47+	eprintf("usage: %s [-t] [device ...]\n", argv0);
48+}
49+
50+int
51+main(int argc, char *argv[])
52+{
53+	ARGBEGIN {
54+	case 't':
55+		tflag = 1;
56+		break;
57+	default:
58+		usage();
59+	} ARGEND;
60+
61+	if (!argc) {
62+		eject("/dev/sr0");
63+	} else {
64+		for (; *argv; argc--, argv++)
65+			eject(*argv);
66+	}
67+
68+	return ret;
69+}
+55, -0
 1@@ -0,0 +1,55 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+
 5+#include <fcntl.h>
 6+#include <limits.h>
 7+#include <stdint.h>
 8+#include <stdio.h>
 9+#include <stdlib.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+static void
15+usage(void)
16+{
17+	eprintf("usage: %s [-o num] -l num file ...\n", argv0);
18+}
19+
20+int
21+main(int argc, char *argv[])
22+{
23+	int fd, ret = 0;
24+	off_t size = 0, offset = 0;
25+
26+	ARGBEGIN {
27+	case 'l':
28+		size = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
29+		break;
30+	case 'o':
31+		offset = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
32+		break;
33+	default:
34+		usage();
35+	} ARGEND;
36+
37+	if (!argc || !size)
38+		usage();
39+
40+	for (; *argv; argc--, argv++) {
41+		if ((fd = open(*argv, O_RDWR | O_CREAT, 0644)) < 0) {
42+			weprintf("open %s:", *argv);
43+			ret = 1;
44+		} else if (posix_fallocate(fd, offset, size) < 0) {
45+			weprintf("posix_fallocate %s:", *argv);
46+			ret = 1;
47+		}
48+
49+		if (fd >= 0 && close(fd) < 0) {
50+			weprintf("close %s:", *argv);
51+			ret = 1;
52+		}
53+	}
54+
55+	return ret;
56+}
+72, -0
 1@@ -0,0 +1,72 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/sysinfo.h>
 4+
 5+#include <stdio.h>
 6+#include <stdlib.h>
 7+
 8+#include "util.h"
 9+
10+static unsigned int mem_unit = 1;
11+static unsigned int unit_shift;
12+
13+static unsigned long long
14+scale(unsigned long long v)
15+{
16+	return (v * mem_unit) >> unit_shift;
17+}
18+
19+static void
20+usage(void)
21+{
22+	eprintf("usage: %s [-bkmg]\n", argv0);
23+}
24+
25+int
26+main(int argc, char *argv[])
27+{
28+	struct sysinfo info;
29+
30+	if (sysinfo(&info) < 0)
31+		eprintf("sysinfo:");
32+	mem_unit = info.mem_unit ? info.mem_unit : 1;
33+
34+	ARGBEGIN {
35+	case 'b':
36+		unit_shift = 0;
37+		break;
38+	case 'k':
39+		unit_shift = 10;
40+		break;
41+	case 'm':
42+		unit_shift = 20;
43+		break;
44+	case 'g':
45+		unit_shift = 30;
46+		break;
47+	default:
48+		usage();
49+	} ARGEND;
50+
51+	printf("     %13s%13s%13s%13s%13s\n",
52+	       "total",
53+	       "used",
54+	       "free",
55+	       "shared", "buffers");
56+	printf("Mem: ");
57+	printf("%13llu%13llu%13llu%13llu%13llu\n",
58+	       scale(info.totalram),
59+	       scale(info.totalram - info.freeram),
60+	       scale(info.freeram),
61+	       scale(info.sharedram),
62+	       scale(info.bufferram));
63+	printf("-/+ buffers/cache:");
64+	printf("%13llu%13llu\n",
65+	       scale(info.totalram - info.freeram - info.bufferram),
66+	       scale(info.freeram + info.bufferram));
67+	printf("Swap:");
68+	printf("%13llu%13llu%13llu\n",
69+	       scale(info.totalswap),
70+	       scale(info.totalswap - info.freeswap),
71+	       scale(info.freeswap));
72+	return 0;
73+}
+39, -0
 1@@ -0,0 +1,39 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/ioctl.h>
 4+#include <sys/mount.h>
 5+#include <sys/types.h>
 6+
 7+#include <fcntl.h>
 8+#include <stdio.h>
 9+#include <stdlib.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+static void
15+usage(void)
16+{
17+	eprintf("usage: %s\n", argv0);
18+}
19+
20+int
21+main(int argc, char *argv[])
22+{
23+	char *dev = "/dev/ram";
24+	int fd;
25+
26+	ARGBEGIN {
27+	default:
28+		usage();
29+	} ARGEND;
30+
31+	if (argc != 0)
32+		usage();
33+
34+	if ((fd = open(dev, O_RDWR)) < 0)
35+		eprintf("open: %s:", dev);
36+	if (ioctl(fd, BLKFLSBUF, dev) < 0)
37+		eprintf("BLKFLSBUF %s:", dev);
38+	close(fd);
39+	return 0;
40+}
+54, -0
 1@@ -0,0 +1,54 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/ioctl.h>
 4+#include <sys/stat.h>
 5+#include <sys/types.h>
 6+
 7+#include <fcntl.h>
 8+#include <stdio.h>
 9+#include <stdlib.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+#define FIFREEZE	_IOWR('X', 119, int)	/* Freeze */
15+#define FITHAW		_IOWR('X', 120, int)	/* Thaw */
16+
17+static void
18+usage(void)
19+{
20+	eprintf("usage: %s (-f | -u) mountpoint\n", argv0);
21+}
22+
23+int
24+main(int argc, char *argv[])
25+{
26+	int fflag = 0;
27+	int uflag = 0;
28+	long p = 1;
29+	int fd;
30+
31+	ARGBEGIN {
32+	case 'f':
33+		fflag = 1;
34+		break;
35+	case 'u':
36+		uflag = 1;
37+		break;
38+	default:
39+		usage();
40+	} ARGEND;
41+
42+	if (argc != 1)
43+		usage();
44+
45+	if ((fflag ^ uflag) == 0)
46+		usage();
47+
48+	fd = open(argv[0], O_RDONLY);
49+	if (fd < 0)
50+		eprintf("open: %s:", argv[0]);
51+	if (ioctl(fd, fflag == 1 ? FIFREEZE : FITHAW, &p) < 0)
52+		eprintf("%s %s:", fflag == 1 ? "FIFREEZE" : "FITHAW", argv[0]);
53+	close(fd);
54+	return 0;
55+}
+159, -0
  1@@ -0,0 +1,159 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/ioctl.h>
  4+#include <sys/stat.h>
  5+#include <sys/time.h>
  6+#include <sys/types.h>
  7+
  8+#include <fcntl.h>
  9+#include <stdio.h>
 10+#include <stdlib.h>
 11+#include <string.h>
 12+#include <time.h>
 13+#include <unistd.h>
 14+
 15+#include "rtc.h"
 16+#include "util.h"
 17+
 18+static void
 19+readrtctm(struct tm *tm, int fd)
 20+{
 21+	struct rtc_time rt;
 22+
 23+	memset(&rt, 0, sizeof(rt));
 24+	if (ioctl(fd, RTC_RD_TIME, &rt) < 0)
 25+		eprintf("RTC_RD_TIME:");
 26+	tm->tm_sec = rt.tm_sec;
 27+	tm->tm_min = rt.tm_min;
 28+	tm->tm_hour = rt.tm_hour;
 29+	tm->tm_mday = rt.tm_mday;
 30+	tm->tm_mon = rt.tm_mon;
 31+	tm->tm_year = rt.tm_year;
 32+	tm->tm_wday = rt.tm_wday;
 33+	tm->tm_yday = rt.tm_yday;
 34+	tm->tm_isdst = rt.tm_isdst;
 35+}
 36+
 37+static void
 38+writertctm(struct tm *tm, int fd)
 39+{
 40+	struct rtc_time rt;
 41+
 42+	rt.tm_sec = tm->tm_sec;
 43+	rt.tm_min = tm->tm_min;
 44+	rt.tm_hour = tm->tm_hour;
 45+	rt.tm_mday = tm->tm_mday;
 46+	rt.tm_mon = tm->tm_mon;
 47+	rt.tm_year = tm->tm_year;
 48+	rt.tm_wday = tm->tm_wday;
 49+	rt.tm_yday = tm->tm_yday;
 50+	rt.tm_isdst = tm->tm_isdst;
 51+	if (ioctl(fd, RTC_SET_TIME, &rt) < 0)
 52+		eprintf("RTC_SET_TIME:");
 53+}
 54+
 55+static void
 56+show(char *dev)
 57+{
 58+	struct tm tm;
 59+	time_t t;
 60+	int fd;
 61+
 62+	fd = open(dev, O_RDONLY);
 63+	if (fd < 0)
 64+		eprintf("open %s:", dev);
 65+	readrtctm(&tm, fd);
 66+	t = mktime(&tm);
 67+	printf("%s", asctime(localtime(&t)));
 68+	close(fd);
 69+}
 70+
 71+static void
 72+hctosys(char *dev)
 73+{
 74+	struct timeval tv;
 75+	struct tm tm;
 76+	int r;
 77+	int fd;
 78+
 79+	fd = open(dev, O_RDONLY);
 80+	if (fd < 0)
 81+		eprintf("open %s:", dev);
 82+	readrtctm(&tm, fd);
 83+	tv.tv_sec = mktime(&tm);
 84+	tv.tv_usec = 0;
 85+	r = settimeofday(&tv, NULL);
 86+	if (r < 0)
 87+		eprintf("settimeofday:");
 88+	close(fd);
 89+}
 90+
 91+static void
 92+systohc(char *dev)
 93+{
 94+	struct timeval tv;
 95+	struct tm *tm;
 96+	time_t t;
 97+	int fd;
 98+
 99+	fd = open(dev, O_WRONLY);
100+	if (fd < 0)
101+		eprintf("open %s:", dev);
102+	gettimeofday(&tv, NULL);
103+	t = tv.tv_sec;
104+	tm = gmtime(&t);
105+	weprintf("warning: assuming UTC for systohc\n");
106+	writertctm(tm, fd);
107+	close(fd);
108+}
109+
110+static void
111+usage(void)
112+{
113+	eprintf("usage: %s [-rsw] [-u] [dev]\n", argv0);
114+}
115+
116+int
117+main(int argc, char *argv[])
118+{
119+	char *dev = "/dev/rtc";
120+	int rflag = 0;
121+	int sflag = 0;
122+	int wflag = 0;
123+
124+	ARGBEGIN {
125+	case 'r':
126+		rflag = 1;
127+		break;
128+	case 's':
129+		sflag = 1;
130+		break;
131+	case 'w':
132+		wflag = 1;
133+		break;
134+	case 'u':
135+		break;
136+	default:
137+		usage();
138+	} ARGEND;
139+
140+	if (argc > 1)
141+		usage();
142+	else if (argc == 1)
143+		dev = argv[0];
144+
145+	if ((rflag ^ sflag ^ wflag) == 0)
146+		eprintf("missing or incompatible function\n");
147+
148+	/* Only UTC support at the moment */
149+	setenv("TZ", "UTC0", 1);
150+	tzset();
151+
152+	if (rflag == 1)
153+		show(dev);
154+	else if (sflag == 1)
155+		hctosys(dev);
156+	else if (wflag == 1)
157+		systohc(dev);
158+
159+	return 0;
160+}
+69, -0
 1@@ -0,0 +1,69 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+#include <sys/syscall.h>
 5+
 6+#include <fcntl.h>
 7+#include <stdio.h>
 8+#include <stdlib.h>
 9+#include <string.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+static void
15+usage(void)
16+{
17+	eprintf("usage: %s filename [args...]\n", argv0);
18+}
19+
20+int
21+main(int argc, char *argv[])
22+{
23+	char *buf = NULL, *opts = NULL;
24+	size_t blen, plen = 0;
25+	int i, fd;
26+	ssize_t n;
27+	struct stat sb;
28+
29+	ARGBEGIN {
30+	default:
31+		usage();
32+	} ARGEND;
33+
34+	if (argc < 1)
35+		usage();
36+
37+	fd = open(argv[0], O_RDONLY);
38+	if (fd < 0)
39+		eprintf("open %s:", argv[0]);
40+	if (fstat(fd, &sb) < 0)
41+		eprintf("stat %s:", argv[0]);
42+	blen = sb.st_size;
43+	buf = emalloc(blen);
44+
45+	n = read(fd, buf, blen);
46+	if (n < 0 || (size_t)n != blen)
47+		eprintf("read:");
48+
49+	argc--;
50+	argv++;
51+
52+	for (i = 0; i < argc; i++)
53+		plen += strlen(argv[i]);
54+	if (plen > 0) {
55+		plen += argc;
56+		opts = ecalloc(1, plen);
57+		for (i = 0; i < argc; i++) {
58+			strcat(opts, argv[i]);
59+			if (i + 1 < argc)
60+				strcat(opts, " ");
61+		}
62+	}
63+
64+	if (syscall(__NR_init_module, buf, blen, !opts ? "" : opts) < 0)
65+		eprintf("init_module:");
66+
67+	free(opts);
68+	free(buf);
69+	return 0;
70+}
+67, -0
 1@@ -0,0 +1,67 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <stdlib.h>
 5+#include <string.h>
 6+
 7+#include "text.h"
 8+#include "util.h"
 9+
10+static void parse_modline(char *buf, char **name, char **size,
11+			  char **refcount, char **users);
12+
13+static void
14+usage(void)
15+{
16+	eprintf("usage: %s\n", argv0);
17+}
18+
19+int
20+main(int argc, char *argv[])
21+{
22+	const char *modfile = "/proc/modules";
23+	FILE *fp;
24+	char *buf = NULL;
25+	char *name, *size, *refcount, *users;
26+	size_t bufsize = 0;
27+	size_t len;
28+
29+	ARGBEGIN {
30+	default:
31+		usage();
32+	} ARGEND;
33+
34+	if (argc > 0)
35+		usage();
36+
37+	fp = fopen(modfile, "r");
38+	if (!fp)
39+		eprintf("fopen %s:", modfile);
40+
41+	printf("%-23s Size  Used by\n", "Module");
42+
43+	while (agetline(&buf, &bufsize, fp) != -1) {
44+		parse_modline(buf, &name, &size, &refcount, &users);
45+		if (!name || !size || !refcount || !users)
46+			eprintf("invalid format: %s\n", modfile);
47+		len = strlen(users) - 1;
48+		if (users[len] == ',' || users[len] == '-')
49+			users[len] = '\0';
50+		printf("%-20s%8s%3s %s\n", name, size, refcount,
51+		       users);
52+	}
53+	if (ferror(fp))
54+		eprintf("%s: read error:", modfile);
55+	free(buf);
56+	fclose(fp);
57+	return 0;
58+}
59+
60+static void
61+parse_modline(char *buf, char **name, char **size,
62+	      char **refcount, char **users)
63+{
64+	*name = strtok(buf, " ");
65+	*size = strtok(NULL, " ");
66+	*refcount = strtok(NULL, " ");
67+	*users = strtok(NULL, " ");
68+}
+58, -0
 1@@ -0,0 +1,58 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <limits.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+
 7+#include "text.h"
 8+#include "util.h"
 9+
10+static void
11+lsusb(const char *file)
12+{
13+	FILE *fp;
14+	char path[PATH_MAX];
15+	char *buf = NULL;
16+	size_t size = 0;
17+	unsigned int i = 0, busnum = 0, devnum = 0, pid = 0, vid = 0;
18+
19+	if (strlcpy(path, file, sizeof(path)) >= sizeof(path))
20+		eprintf("path too long\n");
21+	if (strlcat(path, "/uevent", sizeof(path)) >= sizeof(path))
22+		eprintf("path too long\n");
23+
24+	if (!(fp = fopen(path, "r")))
25+		return;
26+	while (agetline(&buf, &size, fp) != -1) {
27+		if (sscanf(buf, "BUSNUM=%u\n", &busnum) ||
28+		    sscanf(buf, "DEVNUM=%u\n", &devnum) ||
29+		    sscanf(buf, "PRODUCT=%x/%x/", &pid, &vid))
30+			i++;
31+		if (i == 3) {
32+			printf("Bus %03d Device %03d: ID %04x:%04x\n", busnum, devnum,
33+			       pid, vid);
34+			break;
35+		}
36+	}
37+	if (ferror(fp))
38+		eprintf("%s: read error:", path);
39+	free(buf);
40+	fclose(fp);
41+}
42+
43+static void
44+usage(void)
45+{
46+	eprintf("usage: %s\n", argv0);
47+}
48+
49+int
50+main(int argc, char *argv[])
51+{
52+	ARGBEGIN {
53+	default:
54+		usage();
55+	} ARGEND;
56+
57+	recurse_dir("/sys/bus/usb/devices", lsusb);
58+	return 0;
59+}
+89, -0
 1@@ -0,0 +1,89 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+
 5+#include <fcntl.h>
 6+#include <stdio.h>
 7+#include <stdlib.h>
 8+#include <string.h>
 9+#include <unistd.h>
10+
11+#include "util.h"
12+
13+#define SWAP_UUID_LENGTH 16
14+#define SWAP_LABEL_LENGTH 16
15+#define SWAP_MIN_PAGES 10
16+
17+struct swap_hdr {
18+	char	      bootbits[1024];
19+	unsigned int  version;
20+	unsigned int  last_page;
21+	unsigned int  nr_badpages;
22+	unsigned char uuid[SWAP_UUID_LENGTH];
23+	char	      volume_name[SWAP_LABEL_LENGTH];
24+	unsigned int  padding[117];
25+	unsigned int  badpages[1];
26+};
27+
28+static void
29+usage(void)
30+{
31+	eprintf("usage: %s device\n", argv0);
32+}
33+
34+int
35+main(int argc, char *argv[])
36+{
37+	int fd;
38+	unsigned int pages;
39+	long pagesize;
40+	struct stat sb;
41+	char *buf;
42+	struct swap_hdr *hdr;
43+
44+	ARGBEGIN {
45+	default:
46+		usage();
47+	} ARGEND;
48+
49+	if (argc < 1)
50+		usage();
51+
52+	pagesize = sysconf(_SC_PAGESIZE);
53+	if (pagesize <= 0) {
54+		pagesize = sysconf(_SC_PAGE_SIZE);
55+		if (pagesize <= 0)
56+			eprintf("can't determine pagesize\n");
57+	}
58+
59+	fd = open(argv[0], O_RDWR);
60+	if (fd < 0)
61+		eprintf("open %s:", argv[0]);
62+	if (fstat(fd, &sb) < 0)
63+		eprintf("stat %s:", argv[0]);
64+
65+	buf = ecalloc(1, pagesize);
66+
67+	pages = sb.st_size / pagesize;
68+	if (pages < SWAP_MIN_PAGES)
69+		eprintf("swap space needs to be at least %ldKiB\n",
70+			SWAP_MIN_PAGES * pagesize / 1024);
71+
72+	/* Fill up the swap header */
73+	hdr = (struct swap_hdr *)buf;
74+	hdr->version = 1;
75+	hdr->last_page = pages - 1;
76+	strncpy(buf + pagesize - 10, "SWAPSPACE2", 10);
77+
78+	printf("Setting up swapspace version 1, size = %luKiB\n",
79+	       (pages - 1) * pagesize / 1024);
80+
81+	/* Write out the signature page */
82+	if (write(fd, buf, pagesize) != pagesize)
83+		eprintf("unable to write signature page\n");
84+
85+	fsync(fd);
86+	close(fd);
87+	free(buf);
88+
89+	return 0;
90+}
+328, -0
  1@@ -0,0 +1,328 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/mount.h>
  4+#include <sys/stat.h>
  5+#include <sys/types.h>
  6+#include <sys/wait.h>
  7+
  8+#include <errno.h>
  9+#include <limits.h>
 10+#include <mntent.h>
 11+#include <stdio.h>
 12+#include <stdlib.h>
 13+#include <string.h>
 14+#include <unistd.h>
 15+
 16+#include "text.h"
 17+#include "util.h"
 18+
 19+#define FSOPTS_MAXLEN 512
 20+
 21+struct {
 22+	const char *opt;
 23+	const char *notopt;
 24+	unsigned long v;
 25+} optnames[] = {
 26+	{ "defaults",   NULL,           0              },
 27+	{ "remount",    NULL,           MS_REMOUNT     },
 28+	{ "ro",         "rw",           MS_RDONLY      },
 29+	{ "sync",       "async",        MS_SYNCHRONOUS },
 30+	{ "dirsync",    NULL,           MS_DIRSYNC     },
 31+	{ "nodev",      "dev",          MS_NODEV       },
 32+	{ "noatime",    "atime",        MS_NOATIME     },
 33+	{ "noauto",     "auto",         0              },
 34+	{ "nodiratime", "diratime",     MS_NODIRATIME  },
 35+	{ "noexec",     "exec",         MS_NOEXEC      },
 36+	{ "nosuid",     "suid",         MS_NOSUID      },
 37+	{ "mand",       "nomand",       MS_MANDLOCK    },
 38+	{ "relatime",   "norelatime",   MS_RELATIME    },
 39+	{ "bind",       NULL,           MS_BIND        },
 40+	{ NULL,         NULL,           0              }
 41+};
 42+
 43+static unsigned long argflags = 0;
 44+static char fsopts[FSOPTS_MAXLEN] = "";
 45+
 46+static char *
 47+findtype(const char *types, const char *t)
 48+{
 49+	const char *p;
 50+	size_t len;
 51+
 52+	for (len = strlen(t); (p = strstr(types, t)); types = p + len) {
 53+		if (!strncmp(p, t, len) && (p[len] == '\0' || p[len] == ','))
 54+			return (char *)p;
 55+	}
 56+	return NULL;
 57+}
 58+
 59+static void
 60+parseopts(const char *popts, unsigned long *flags, char *data, size_t datasiz)
 61+{
 62+	unsigned int i, validopt;
 63+	size_t optlen, dlen = 0;
 64+	const char *name, *e;
 65+
 66+	name = popts;
 67+	data[0] = '\0';
 68+	do {
 69+		if ((e = strstr(name, ",")))
 70+			optlen = e - name;
 71+		else
 72+			optlen = strlen(name);
 73+
 74+		validopt = 0;
 75+		for (i = 0; optnames[i].opt; i++) {
 76+			if (optnames[i].opt &&
 77+			    !strncmp(name, optnames[i].opt, optlen)) {
 78+				*flags |= optnames[i].v;
 79+				validopt = 1;
 80+				break;
 81+			}
 82+			if (optnames[i].notopt &&
 83+			    !strncmp(name, optnames[i].notopt, optlen)) {
 84+				*flags &= ~optnames[i].v;
 85+				validopt = 1;
 86+				break;
 87+			}
 88+		}
 89+
 90+		if (!validopt && optlen > 0) {
 91+			/* unknown option, pass as data option to mount() */
 92+			if (dlen + optlen + 2 >= datasiz)
 93+				return; /* prevent overflow */
 94+			if (dlen)
 95+				data[dlen++] = ',';
 96+			memcpy(&data[dlen], name, optlen);
 97+			dlen += optlen;
 98+			data[dlen] = '\0';
 99+		}
100+		name = e + 1;
101+	} while (e);
102+}
103+
104+static int
105+mounthelper(const char *fsname, const char *dir, const char *fstype)
106+{
107+	pid_t pid;
108+	char eprog[PATH_MAX];
109+	char const *eargv[10];
110+	int status, i;
111+
112+	pid = fork();
113+	switch(pid) {
114+	case -1:
115+		break;
116+	case 0:
117+		snprintf(eprog, sizeof(eprog), "mount.%s", fstype);
118+
119+		i = 0;
120+		eargv[i++] = eprog;
121+		if (argflags & MS_BIND)
122+			eargv[i++] = "-B";
123+		if (argflags & MS_MOVE)
124+			eargv[i++] = "-M";
125+		if (argflags & MS_REC)
126+			eargv[i++] = "-R";
127+
128+		if (fsopts[0]) {
129+			eargv[i++] = "-o";
130+			eargv[i++] = fsopts;
131+		}
132+		eargv[i++] = fsname;
133+		eargv[i++] = dir;
134+		eargv[i] = NULL;
135+
136+		execvp(eprog, (char * const *)eargv);
137+		if (errno == ENOENT)
138+			_exit(1);
139+		weprintf("execvp:");
140+		_exit(1);
141+		break;
142+	default:
143+		if (waitpid(pid, &status, 0) < 0) {
144+			weprintf("waitpid:");
145+			return -1;
146+		}
147+		if (WIFEXITED(status))
148+			return WEXITSTATUS(status);
149+		else if (WIFSIGNALED(status))
150+			return 1;
151+		break;
152+	}
153+	return 0;
154+}
155+
156+static int
157+mounted(const char *dir)
158+{
159+	FILE *fp;
160+	struct mntent *me, mebuf;
161+	struct stat st1, st2;
162+	char linebuf[256];
163+
164+	if (stat(dir, &st1) < 0) {
165+		weprintf("stat %s:", dir);
166+		return 0;
167+	}
168+	if (!(fp = setmntent("/proc/mounts", "r")))
169+		eprintf("setmntent %s:", "/proc/mounts");
170+
171+	while ((me = getmntent_r(fp, &mebuf, linebuf, sizeof(linebuf)))) {
172+		if (stat(me->mnt_dir, &st2) < 0) {
173+			weprintf("stat %s:", me->mnt_dir);
174+			continue;
175+		}
176+		if (st1.st_dev == st2.st_dev &&
177+		    st1.st_ino == st2.st_ino)
178+			return 1;
179+	}
180+	endmntent(fp);
181+
182+	return 0;
183+}
184+
185+static void
186+usage(void)
187+{
188+	eprintf("usage: %s [-BMRan] [-t fstype] [-o options] [source] [target]\n",
189+	        argv0);
190+}
191+
192+int
193+main(int argc, char *argv[])
194+{
195+	char *types = NULL, data[FSOPTS_MAXLEN] = "", *resolvpath = NULL;
196+	char *files[] = { "/proc/mounts", "/etc/fstab", NULL };
197+	const char *source, *target;
198+	struct mntent *me = NULL;
199+	int aflag = 0, status = 0, i, r;
200+	unsigned long flags = 0;
201+	FILE *fp;
202+
203+	ARGBEGIN {
204+	case 'B':
205+		argflags |= MS_BIND;
206+		break;
207+	case 'M':
208+		argflags |= MS_MOVE;
209+		break;
210+	case 'R':
211+		argflags |= MS_REC;
212+		break;
213+	case 'a':
214+		aflag = 1;
215+		break;
216+	case 'o':
217+		estrlcat(fsopts, EARGF(usage()), sizeof(fsopts));
218+		parseopts(fsopts, &flags, data, sizeof(data));
219+		break;
220+	case 't':
221+		types = EARGF(usage());
222+		break;
223+	case 'n':
224+		break;
225+	default:
226+		usage();
227+	} ARGEND;
228+
229+	if (argc < 1 && aflag == 0) {
230+		if (!(fp = fopen(files[0], "r")))
231+			eprintf("fopen %s:", files[0]);
232+		fconcat(fp, files[0], stdout, "<stdout>");
233+		fclose(fp);
234+		return 0;
235+	}
236+
237+	if (aflag == 1)
238+		goto mountall;
239+
240+	source = argv[0];
241+	target = argv[1];
242+
243+	if (!target) {
244+		target = argv[0];
245+		source = NULL;
246+		if (strcmp(target, "/") != 0) {
247+			if (!(resolvpath = realpath(target, NULL)))
248+				eprintf("realpath %s:", target);
249+			target = resolvpath;
250+		}
251+	}
252+
253+	for (i = 0; files[i]; i++) {
254+		if (!(fp = setmntent(files[i], "r"))) {
255+			if (strcmp(files[i], "/proc/mounts") != 0)
256+				weprintf("setmntent %s:", files[i]);
257+			continue;
258+		}
259+		while ((me = getmntent(fp))) {
260+			if (strcmp(me->mnt_dir, target) == 0 ||
261+			   strcmp(me->mnt_fsname, target) == 0 ||
262+			   (source && strcmp(me->mnt_dir, source) == 0) ||
263+			   (source && strcmp(me->mnt_fsname, source) == 0)) {
264+				if (!source) {
265+					target = me->mnt_dir;
266+					source = me->mnt_fsname;
267+				}
268+				if (!fsopts[0])
269+					estrlcat(fsopts, me->mnt_opts, sizeof(fsopts));
270+					parseopts(fsopts, &flags, data, sizeof(data));
271+				if (!types)
272+					types = me->mnt_type;
273+				goto mountsingle;
274+			}
275+		}
276+		endmntent(fp);
277+		fp = NULL;
278+	}
279+	if (!source)
280+		eprintf("can't find %s in /etc/fstab\n", target);
281+
282+mountsingle:
283+	r = mounthelper(source, target, types);
284+	if (r == -1)
285+		status = 1;
286+	if (r > 0 && mount(source, target, types, argflags | flags, data) < 0) {
287+		weprintf("mount: %s:", source);
288+		status = 1;
289+	}
290+	if (fp)
291+		endmntent(fp);
292+	free(resolvpath);
293+	return status;
294+
295+mountall:
296+	if (!(fp = setmntent("/etc/fstab", "r")))
297+		eprintf("setmntent %s:", "/etc/fstab");
298+	while ((me = getmntent(fp))) {
299+		/* has "noauto" option or already mounted: skip */
300+		if (hasmntopt(me, MNTOPT_NOAUTO) || mounted(me->mnt_dir))
301+			continue;
302+		flags = 0;
303+		fsopts[0] = '\0';
304+		if (strlcat(fsopts, me->mnt_opts, sizeof(fsopts)) >= sizeof(fsopts)) {
305+			weprintf("%s: option string too long\n", me->mnt_dir);
306+			status = 1;
307+			continue;
308+		}
309+		parseopts(fsopts, &flags, data, sizeof(data));
310+		/* if -t types specified:
311+		 * if non-match, skip
312+		 * if match and prefixed with "no", skip */
313+		if (types &&
314+		    ((types[0] == 'n' && types[1] == 'o' &&
315+		     findtype(types + 2, me->mnt_type)) ||
316+		     (!findtype(types, me->mnt_type))))
317+			continue;
318+
319+		r = mounthelper(me->mnt_fsname, me->mnt_dir, me->mnt_type);
320+		if (r > 0 && mount(me->mnt_fsname, me->mnt_dir, me->mnt_type,
321+		                   argflags | flags, data) < 0) {
322+			weprintf("mount: %s:", me->mnt_fsname);
323+			status = 1;
324+		}
325+	}
326+	endmntent(fp);
327+
328+	return status;
329+}
+102, -0
  1@@ -0,0 +1,102 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+#include <sys/sysmacros.h>
  5+#include <sys/types.h>
  6+
  7+#include <mntent.h>
  8+#include <stdio.h>
  9+#include <stdlib.h>
 10+#include <string.h>
 11+#include <unistd.h>
 12+
 13+#include "util.h"
 14+
 15+static void
 16+usage(void)
 17+{
 18+	eprintf("usage: %s [-dqx] target\n", argv0);
 19+}
 20+
 21+int
 22+main(int argc, char *argv[])
 23+{
 24+	int dflag = 0, qflag = 0, xflag = 0;
 25+	int ret = 0;
 26+	struct mntent *me = NULL;
 27+	FILE *fp;
 28+	struct stat st1, st2;
 29+
 30+	ARGBEGIN {
 31+	case 'd':
 32+		dflag = 1;
 33+		break;
 34+	case 'q':
 35+		qflag = 1;
 36+		break;
 37+	case 'x':
 38+		xflag = 1;
 39+		break;
 40+	default:
 41+		usage();
 42+	} ARGEND;
 43+
 44+	if (argc < 1)
 45+		usage();
 46+
 47+	if (stat(argv[0], &st1) < 0) {
 48+		if (qflag)
 49+			return 1;
 50+		eprintf("stat %s:", argv[0]);
 51+	}
 52+
 53+	if (xflag) {
 54+		if (!S_ISBLK(st1.st_mode)) {
 55+			if (qflag)
 56+				return 1;
 57+			eprintf("stat: %s: not a block device\n",
 58+				argv[0]);
 59+		}
 60+		printf("%u:%u\n", major(st1.st_rdev),
 61+		       minor(st1.st_rdev));
 62+		return 0;
 63+	}
 64+
 65+	if (!S_ISDIR(st1.st_mode)) {
 66+		if (qflag)
 67+			return 1;
 68+		eprintf("stat %s: not a directory\n", argv[0]);
 69+	}
 70+
 71+	if (dflag) {
 72+		printf("%u:%u\n", major(st1.st_dev),
 73+		       minor(st1.st_dev));
 74+		return 0;
 75+	}
 76+
 77+	fp = setmntent("/proc/mounts", "r");
 78+	if (!fp) {
 79+		if (qflag)
 80+			return 1;
 81+		eprintf("setmntent %s:", "/proc/mounts");
 82+	}
 83+	while ((me = getmntent(fp)) != NULL) {
 84+		if (stat(me->mnt_dir, &st2) < 0) {
 85+			if (qflag)
 86+				return 1;
 87+			eprintf("stat %s:", me->mnt_dir);
 88+		}
 89+		if (st1.st_dev == st2.st_dev &&
 90+		    st1.st_ino == st2.st_ino)
 91+			break;
 92+	}
 93+	endmntent(fp);
 94+
 95+	if (me == NULL)
 96+		ret = 1;
 97+
 98+	if (!qflag)
 99+		printf("%s %s a mountpoint\n", argv[0],
100+		       !ret ? "is" : "is not");
101+
102+	return ret;
103+}
+116, -0
  1@@ -0,0 +1,116 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/types.h>
  4+
  5+#include <dirent.h>
  6+#include <libgen.h>
  7+#include <limits.h>
  8+#include <stdio.h>
  9+#include <stdlib.h>
 10+#include <string.h>
 11+#include <unistd.h>
 12+
 13+#include "proc.h"
 14+#include "queue.h"
 15+#include "util.h"
 16+
 17+struct pidentry {
 18+	pid_t pid;
 19+	SLIST_ENTRY(pidentry) entry;
 20+};
 21+
 22+static SLIST_HEAD(, pidentry) omitpid_head;
 23+
 24+static void
 25+usage(void)
 26+{
 27+	eprintf("usage: %s [-o pid1,pid2,...pidN] [-s] [program...]\n", argv0);
 28+}
 29+
 30+int
 31+main(int argc, char *argv[])
 32+{
 33+	DIR *dp;
 34+	struct dirent *entry;
 35+	pid_t pid;
 36+	struct procstat ps;
 37+	char cmdline[BUFSIZ], *cmd, *cmdbase = NULL, *p, *arg = NULL;
 38+	int i, found = 0;
 39+	int sflag = 0, oflag = 0;
 40+	struct pidentry *pe;
 41+
 42+	ARGBEGIN {
 43+	case 's':
 44+		sflag = 1;
 45+		break;
 46+	case 'o':
 47+		oflag = 1;
 48+		arg = EARGF(usage());
 49+		break;
 50+	default:
 51+		usage();
 52+	} ARGEND;
 53+
 54+	if (!argc)
 55+		return 1;
 56+
 57+	SLIST_INIT(&omitpid_head);
 58+
 59+	if (oflag) {
 60+		for (p = strtok(arg, ","); p; p = strtok(NULL, ",")) {
 61+			pe = emalloc(sizeof(*pe));
 62+			if (strcmp(p, "%PPID") == 0)
 63+				pe->pid = getppid();
 64+			else
 65+				pe->pid = estrtol(p, 10);
 66+			SLIST_INSERT_HEAD(&omitpid_head, pe, entry);
 67+		}
 68+	}
 69+
 70+	if (!(dp = opendir("/proc")))
 71+		eprintf("opendir /proc:");
 72+
 73+	while ((entry = readdir(dp))) {
 74+		if (!pidfile(entry->d_name))
 75+			continue;
 76+		pid = estrtol(entry->d_name, 10);
 77+		if (oflag) {
 78+			SLIST_FOREACH(pe, &omitpid_head, entry)
 79+				if (pe->pid == pid)
 80+					break;
 81+			if (pe)
 82+				continue;
 83+		}
 84+		if (parsestat(pid, &ps) < 0)
 85+			continue;
 86+		if (parsecmdline(ps.pid, cmdline,
 87+				 sizeof(cmdline)) < 0) {
 88+			cmd = ps.comm;
 89+			cmdbase = cmd;
 90+		} else {
 91+			if ((p = strchr(cmdline, ' ')))
 92+				*p = '\0';
 93+			cmd = cmdline;
 94+			cmdbase = basename(cmdline);
 95+		}
 96+		/* Workaround for login shells */
 97+		if (cmd[0] == '-')
 98+			cmd++;
 99+		for (i = 0; i < argc; i++) {
100+			if (strcmp(cmd, argv[i]) == 0 ||
101+			    strcmp(cmdbase, argv[i]) == 0) {
102+				putword(stdout, entry->d_name);
103+				found++;
104+				if (sflag)
105+					goto out;
106+			}
107+		}
108+	}
109+
110+out:
111+	if (found)
112+		putchar('\n');
113+
114+	closedir(dp);
115+
116+	return found ? 0 : 1;
117+}
+31, -0
 1@@ -0,0 +1,31 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/syscall.h>
 4+
 5+#include <stdio.h>
 6+#include <stdlib.h>
 7+#include <unistd.h>
 8+
 9+#include "util.h"
10+
11+static void
12+usage(void)
13+{
14+	eprintf("usage: %s new-root put-old\n", argv0);
15+}
16+
17+int
18+main(int argc, char *argv[])
19+{
20+	ARGBEGIN {
21+	default:
22+		usage();
23+	} ARGEND;
24+
25+	if (argc < 2)
26+		usage();
27+
28+	if (syscall(SYS_pivot_root, argv[0], argv[1]) < 0)
29+		eprintf("pivot_root:");
30+
31+	return 0;
32+}
+51, -0
 1@@ -0,0 +1,51 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <limits.h>
 5+#include <stdio.h>
 6+#include <string.h>
 7+#include <unistd.h>
 8+
 9+#include "util.h"
10+
11+static void
12+usage(void)
13+{
14+	eprintf("usage: %s pid...\n", argv0);
15+}
16+
17+int
18+main(int argc, char *argv[])
19+{
20+	int ret = 0;
21+	char path[PATH_MAX];
22+	char target[PATH_MAX + sizeof(" (deleted)")];
23+	ssize_t n;
24+
25+	ARGBEGIN {
26+	default:
27+		usage();
28+	} ARGEND;
29+
30+	if (argc == 0)
31+		usage();
32+
33+	for (; argc > 0; argc--, argv++) {
34+		n = snprintf(path, sizeof(path), "/proc/%s/cwd", *argv);
35+		if (n < 0 || n >= sizeof(path)) {
36+			errno = ESRCH;
37+		} else {
38+			n = readlink(path, target, sizeof(target) - 1);
39+			if (n >= 0) {
40+				target[n] = '\0';
41+				printf("%s: %s\n", *argv, target);
42+				continue;
43+			}
44+		}
45+		if (errno == ENOENT)
46+			errno = ESRCH;
47+		weprintf("%s:", *argv);
48+		ret = 1;
49+	}
50+
51+	return ret;
52+}
+38, -0
 1@@ -0,0 +1,38 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <fcntl.h>
 4+#include <limits.h>
 5+#include <stdio.h>
 6+#include <stdlib.h>
 7+
 8+#include "util.h"
 9+
10+static void
11+usage(void)
12+{
13+	eprintf("usage: %s file...\n", argv0);
14+}
15+
16+int
17+main(int argc, char *argv[])
18+{
19+	FILE *fp;
20+
21+	ARGBEGIN {
22+	default:
23+		usage();
24+	} ARGEND;
25+
26+	if (argc == 0)
27+		usage();
28+
29+	for (; argc > 0; argc--, argv++) {
30+		if (!(fp = fopen(argv[0], "r"))) {
31+			weprintf("fopen %s:", argv[0]);
32+			continue;
33+		}
34+		if (readahead(fileno(fp), 0, -1) < 0)
35+			weprintf("readahead %s:", argv[0]);
36+		fclose(fp);
37+	}
38+	return 0;
39+}
+50, -0
 1@@ -0,0 +1,50 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/syscall.h>
 4+
 5+#include <fcntl.h>
 6+#include <libgen.h>
 7+#include <stdio.h>
 8+#include <stdlib.h>
 9+#include <string.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+static void
15+usage(void)
16+{
17+	eprintf("usage: %s [-fw] module...\n", argv0);
18+}
19+
20+int
21+main(int argc, char *argv[])
22+{
23+	char *mod, *p;
24+	int i;
25+	int flags = O_NONBLOCK;
26+
27+	ARGBEGIN {
28+	case 'f':
29+		flags |= O_TRUNC;
30+		break;
31+	case 'w':
32+		flags &= ~O_NONBLOCK;
33+		break;
34+	default:
35+		usage();
36+	} ARGEND;
37+
38+	if (argc < 1)
39+		usage();
40+
41+	for (i = 0; i < argc; i++) {
42+		mod = argv[i];
43+		p = strrchr(mod, '.');
44+		if (p && !strcmp(p, ".ko"))
45+			*p = '\0';
46+		if (syscall(__NR_delete_module, mod, flags) < 0)
47+			eprintf("delete_module:");
48+	}
49+
50+	return 0;
51+}
+80, -0
 1@@ -0,0 +1,80 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/types.h>
 4+
 5+#include <fcntl.h>
 6+#include <stdio.h>
 7+#include <stdlib.h>
 8+#include <string.h>
 9+#include <unistd.h>
10+
11+#include "util.h"
12+
13+#define SWAP_MAGIC1 "SWAPSPACE2"
14+#define SWAP_MAGIC2 "SWAP-SPACE"
15+#define SWAP_MAGIC_LENGTH (10)
16+#define SWAP_MAGIC_OFFSET (sysconf(_SC_PAGESIZE) - SWAP_MAGIC_LENGTH)
17+#define SWAP_LABEL_LENGTH (16)
18+#define SWAP_LABEL_OFFSET (1024 + 4 + 4 + 4 + 16)
19+
20+static void
21+usage(void)
22+{
23+	eprintf("usage: %s [-L label] device\n", argv0);
24+}
25+
26+int
27+main(int argc, char *argv[])
28+{
29+	int setlabel = 0;
30+	int fd;
31+	char magic[SWAP_MAGIC_LENGTH];
32+	char *label;
33+	char *device;
34+	int i;
35+
36+	ARGBEGIN {
37+	case 'L':
38+		setlabel = 1;
39+		label = EARGF(usage());
40+		break;
41+	default:
42+		usage();
43+	} ARGEND;
44+
45+	if (argc < 1)
46+		usage();
47+	device = argv[0];
48+
49+	fd = open(device, O_RDWR);
50+	if (fd < 0)
51+		eprintf("open %s:", device);
52+
53+	if (lseek(fd, SWAP_MAGIC_OFFSET, SEEK_SET) != SWAP_MAGIC_OFFSET)
54+		eprintf("failed seeking to magic position:");
55+	if (read(fd, magic, SWAP_MAGIC_LENGTH) != SWAP_MAGIC_LENGTH)
56+		eprintf("reading magic failed:");
57+	if (memcmp(magic, SWAP_MAGIC1, 10) && memcmp(magic, SWAP_MAGIC2, 10))
58+		eprintf("%s: is not a swap partition\n", device);
59+	if (lseek(fd, SWAP_LABEL_OFFSET, SEEK_SET) != SWAP_LABEL_OFFSET)
60+		eprintf("failed seeking to label position:");
61+
62+	if (!setlabel) {
63+		label = emalloc(SWAP_LABEL_LENGTH);
64+		if (read(fd, label, SWAP_LABEL_LENGTH) != SWAP_LABEL_LENGTH)
65+			eprintf("reading label failed:");
66+		for (i = 0; i < SWAP_LABEL_LENGTH && label[i] != '\0'; i++)
67+			if (i == (SWAP_LABEL_LENGTH - 1) && label[i] != '\0')
68+				eprintf("invalid label\n");
69+		printf("label: %s\n", label);
70+		free(label);
71+	} else {
72+		if (strlen(label) + 1 > SWAP_LABEL_LENGTH)
73+			eprintf("label too long\n");
74+		if (write(fd, label, strlen(label) + 1) != (ssize_t)strlen(label) + 1)
75+			eprintf("writing label failed:");
76+	}
77+
78+	fsync(fd);
79+	close(fd);
80+	return 0;
81+}
+59, -0
 1@@ -0,0 +1,59 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/swap.h>
 4+
 5+#include <mntent.h>
 6+#include <stdio.h>
 7+#include <stdlib.h>
 8+#include <string.h>
 9+
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+	eprintf("usage: %s -a | device\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+	int i;
22+	int ret = 0;
23+	int all = 0;
24+	struct mntent *me;
25+	FILE *fp;
26+
27+	ARGBEGIN {
28+	case 'a':
29+		all = 1;
30+		break;
31+	default:
32+		usage();
33+	} ARGEND;
34+
35+	if ((!all && argc < 1) || (all && argc > 0))
36+		usage();
37+
38+	if (all) {
39+		fp = setmntent("/etc/fstab", "r");
40+		if (!fp)
41+			eprintf("setmntent %s:", "/etc/fstab");
42+		while ((me = getmntent(fp)) != NULL) {
43+			if (strcmp(me->mnt_type, MNTTYPE_SWAP) == 0) {
44+				if (swapoff(me->mnt_fsname) < 0) {
45+					weprintf("swapoff %s:", me->mnt_fsname);
46+					ret = 1;
47+				}
48+			}
49+		}
50+		endmntent(fp);
51+	} else {
52+		for (i = 0; i < argc; i++) {
53+			if (swapoff(argv[i]) < 0) {
54+				weprintf("swapoff %s:", argv[i]);
55+				ret = 1;
56+			}
57+		}
58+	}
59+	return ret;
60+}
+67, -0
 1@@ -0,0 +1,67 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/swap.h>
 4+
 5+#include <mntent.h>
 6+#include <stdio.h>
 7+#include <stdlib.h>
 8+#include <string.h>
 9+
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+	eprintf("usage: %s [-dp] -a | device\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+	int i;
22+	int ret = 0;
23+	int flags = 0;
24+	int all = 0;
25+	struct mntent *me;
26+	FILE *fp;
27+
28+	ARGBEGIN {
29+	case 'a':
30+		all = 1;
31+		break;
32+	case 'd':
33+		flags |= SWAP_FLAG_DISCARD;
34+		break;
35+	case 'p':
36+		flags |= SWAP_FLAG_PREFER;
37+		break;
38+	default:
39+		usage();
40+	} ARGEND;
41+
42+	if ((!all && argc < 1) || (all && argc > 0))
43+		usage();
44+
45+	if (all) {
46+		fp = setmntent("/etc/fstab", "r");
47+		if (!fp)
48+			eprintf("setmntent %s:", "/etc/fstab");
49+		while ((me = getmntent(fp)) != NULL) {
50+			if (strcmp(me->mnt_type, MNTTYPE_SWAP) == 0
51+			    && (hasmntopt(me, MNTOPT_NOAUTO) == NULL)) {
52+				if (swapon(me->mnt_fsname, flags) < 0) {
53+					weprintf("swapon %s:", me->mnt_fsname);
54+					ret = 1;
55+				}
56+			}
57+		}
58+		endmntent(fp);
59+	} else {
60+		for (i = 0; i < argc; i++) {
61+			if (swapon(argv[i], flags) < 0) {
62+				weprintf("swapon %s:", argv[i]);
63+				ret = 1;
64+			}
65+		}
66+	}
67+	return ret;
68+}
+131, -0
  1@@ -0,0 +1,131 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/mount.h>
  4+#include <sys/stat.h>
  5+#include <sys/vfs.h>
  6+
  7+#include <dirent.h>
  8+#include <fcntl.h>
  9+#include <limits.h>
 10+#include <stdio.h>
 11+#include <stdlib.h>
 12+#include <string.h>
 13+#include <unistd.h>
 14+
 15+#include "util.h"
 16+
 17+#define RAMFS_MAGIC		0x858458f6	/* some random number */
 18+#define TMPFS_MAGIC		0x01021994
 19+
 20+static void
 21+delete_content(const char *dir, dev_t curdevice)
 22+{
 23+	char path[PATH_MAX];
 24+	DIR *d;
 25+	struct stat st;
 26+	struct dirent *dent;
 27+
 28+	/* don't dive into other filesystems */
 29+	if (lstat(dir, &st) < 0 || st.st_dev != curdevice)
 30+		return;
 31+	if (!(d = opendir(dir)))
 32+		return;
 33+	while ((dent = readdir(d))) {
 34+		if (strcmp(dent->d_name, ".") == 0 ||
 35+		    strcmp(dent->d_name, "..") == 0)
 36+			continue;
 37+
 38+		/* build path and dive deeper */
 39+		if (strlcpy(path, dir, sizeof(path)) >= sizeof(path))
 40+			eprintf("path too long\n");
 41+		if (path[strlen(path) - 1] != '/')
 42+			if (strlcat(path, "/", sizeof(path)) >= sizeof(path))
 43+				eprintf("path too long\n");
 44+		if (strlcat(path, dent->d_name, sizeof(path)) >= sizeof(path))
 45+			eprintf("path too long\n");
 46+
 47+		if (lstat(path, &st) < 0)
 48+			weprintf("lstat %s:", path);
 49+
 50+		if (S_ISDIR(st.st_mode)) {
 51+			delete_content(path, curdevice);
 52+			if (rmdir(path) < 0)
 53+				weprintf("rmdir %s:", path);
 54+		} else {
 55+			if (unlink(path) < 0)
 56+				weprintf("unlink %s:", path);
 57+		}
 58+	}
 59+	closedir(d);
 60+}
 61+
 62+static void
 63+usage(void)
 64+{
 65+	eprintf("usage: %s [-c console] [newroot] [init] (PID 1)\n", argv0);
 66+}
 67+
 68+int
 69+main(int argc, char *argv[])
 70+{
 71+	char *console = NULL;
 72+	dev_t curdev;
 73+	struct stat st;
 74+	struct statfs stfs;
 75+
 76+	ARGBEGIN {
 77+	case 'c':
 78+		console = EARGF(usage());
 79+		break;
 80+	default:
 81+		usage();
 82+	} ARGEND;
 83+
 84+	/* check number of args and if we are PID 1 */
 85+	if (argc != 2 || getpid() != 1)
 86+		usage();
 87+
 88+	/* chdir to newroot and make sure it's a different fs */
 89+	if (chdir(argv[0]))
 90+		eprintf("chdir %s:", argv[0]);
 91+
 92+	if (stat("/", &st))
 93+		eprintf("stat %s:", "/");
 94+
 95+	curdev = st.st_dev;
 96+	if (stat(".", &st))
 97+		eprintf("stat %s:", ".");
 98+	if (st.st_dev == curdev)
 99+		usage();
100+
101+	/* avoids trouble with real filesystems */
102+	if (stat("/init", &st) || !S_ISREG(st.st_mode))
103+		eprintf("/init is not a regular file\n");
104+
105+	statfs("/", &stfs);
106+	if ((unsigned)stfs.f_type != RAMFS_MAGIC && (unsigned)stfs.f_type != TMPFS_MAGIC)
107+		eprintf("current filesystem is not a RAMFS or TMPFS\n");
108+
109+	/* wipe / */
110+	delete_content("/", curdev);
111+
112+	/* overmount / with newroot and chroot into it */
113+	if (mount(".", "/", NULL, MS_MOVE, NULL))
114+		eprintf("mount %s:", ".");
115+
116+	if (chroot("."))
117+		eprintf("chroot failed\n");
118+
119+	/* if -c is set, redirect stdin/stdout/stderr to console */
120+	if (console) {
121+		close(0);
122+		if (open(console, O_RDWR) == -1)
123+			eprintf("open %s:", console);
124+		dup2(0, 1);
125+		dup2(0, 2);
126+	}
127+
128+	/* execute init */
129+	execv(argv[1], argv);
130+	eprintf("can't execute '%s':", argv[1]);
131+	return 1;
132+}
+213, -0
  1@@ -0,0 +1,213 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <fcntl.h>
  4+#include <limits.h>
  5+#include <stdio.h>
  6+#include <stdlib.h>
  7+#include <string.h>
  8+#include <unistd.h>
  9+
 10+#include "text.h"
 11+#include "util.h"
 12+
 13+static void
 14+replacestr(char *s, int a, int b)
 15+{
 16+	for (; *s; s++)
 17+		if (*s == a)
 18+			*s = b;
 19+}
 20+
 21+static int
 22+getsysctl(char *variable, char **value)
 23+{
 24+	char path[PATH_MAX];
 25+	char *p;
 26+	char *buf, *tmp, c;
 27+	int fd;
 28+	ssize_t n;
 29+	size_t sz, i;
 30+
 31+	replacestr(variable, '.', '/');
 32+
 33+	strlcpy(path, "/proc/sys/", sizeof(path));
 34+	if (strlcat(path, variable, sizeof(path)) >= sizeof(path)) {
 35+		replacestr(variable, '/', '.');
 36+		return -1;
 37+	}
 38+
 39+	replacestr(variable, '/', '.');
 40+
 41+	fd = open(path, O_RDONLY);
 42+	if (fd < 0)
 43+		return -1;
 44+
 45+	i = 0;
 46+	sz = 1;
 47+	buf = NULL;
 48+	while (1) {
 49+		n = read(fd, &c, 1);
 50+		if (n < 0) {
 51+			close(fd);
 52+			free(buf);
 53+			return -1;
 54+		}
 55+		if (n == 0)
 56+			break;
 57+		if (i == sz - 1) {
 58+			sz *= 2;
 59+			tmp = realloc(buf, sz);
 60+			if (!tmp) {
 61+				close(fd);
 62+				free(buf);
 63+				return -1;
 64+			}
 65+			buf = tmp;
 66+		}
 67+		buf[i++] = c;
 68+	}
 69+	buf[i] = '\0';
 70+
 71+	p = strrchr(buf, '\n');
 72+	if (p)
 73+		*p = '\0';
 74+
 75+	*value = buf;
 76+
 77+	close(fd);
 78+
 79+	return 0;
 80+}
 81+
 82+static int
 83+setsysctl(char *variable, char *value)
 84+{
 85+	char path[PATH_MAX];
 86+	int fd;
 87+	ssize_t n;
 88+
 89+	replacestr(variable, '.', '/');
 90+
 91+	strlcpy(path, "/proc/sys/", sizeof(path));
 92+	if (strlcat(path, variable, sizeof(path)) >= sizeof(path)) {
 93+		replacestr(variable, '/', '.');
 94+		return -1;
 95+	}
 96+
 97+	replacestr(variable, '/', '.');
 98+
 99+	fd = open(path, O_WRONLY);
100+	if (fd < 0)
101+		return -1;
102+
103+	n = write(fd, value, strlen(value));
104+	if ((size_t)n != strlen(value)) {
105+		close(fd);
106+		return -1;
107+	}
108+
109+	close(fd);
110+
111+	return 0;
112+}
113+
114+static int
115+parsepair(char *pair)
116+{
117+	char *p;
118+	char *variable;
119+	char *value;
120+
121+	for (p = pair; *p; p++) {
122+		if (p[0] == '.' && p[1] == '.') {
123+			weprintf("malformed input: %s\n", pair);
124+			return -1;
125+		}
126+	}
127+	p = strchr(pair, '=');
128+	if (p) {
129+		if (p[1] == '\0') {
130+			weprintf("malformed input: %s\n", pair);
131+			return -1;
132+		}
133+		*p = '\0';
134+		value = &p[1];
135+	} else {
136+		value = NULL;
137+	}
138+	variable = pair;
139+	if (value) {
140+		if (setsysctl(variable, value) < 0) {
141+			weprintf("failed to set sysctl for %s\n", variable);
142+			return -1;
143+		}
144+	} else {
145+		if (getsysctl(variable, &value) < 0) {
146+			weprintf("failed to get sysctl for %s\n", variable);
147+			return -1;
148+		}
149+		printf("%s = %s\n", variable, value);
150+		free(value);
151+	}
152+
153+	return 0;
154+}
155+
156+static void
157+usage(void)
158+{
159+	eprintf("usage: %s [-p file] variable[=value]...\n", argv0);
160+}
161+
162+int
163+main(int argc, char *argv[])
164+{
165+	FILE *fp;
166+	char *buf = NULL, *p;
167+	char *file = NULL;
168+	size_t size = 0;
169+	int i;
170+	int r = 0;
171+
172+	ARGBEGIN {
173+	case 'p':
174+		file = EARGF(usage());
175+		break;
176+	default:
177+		usage();
178+	} ARGEND;
179+
180+	if (!file && argc < 1)
181+		usage();
182+
183+	if (!file) {
184+		for (i = 0; i < argc; i++)
185+			if (parsepair(argv[i]) < 0)
186+				r = 1;
187+	} else {
188+		fp = fopen(file, "r");
189+		if (!fp)
190+			eprintf("fopen %s:", file);
191+		while (agetline(&buf, &size, fp) != -1) {
192+			p = buf;
193+			for (p = buf; *p == ' ' || *p == '\t'; p++)
194+				;
195+			if (*p == '#' || *p == '\n')
196+				continue;
197+			for (p = buf; *p; p++) {
198+				if (*p == '\n') {
199+					*p = '\0';
200+					break;
201+				}
202+			}
203+			p = buf;
204+			if (parsepair(p) < 0)
205+				r = 1;
206+		}
207+		if (ferror(fp))
208+			eprintf("%s: read error:", file);
209+		free(buf);
210+		fclose(fp);
211+	}
212+
213+	return r;
214+}
+180, -0
  1@@ -0,0 +1,180 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/mount.h>
  4+
  5+#include <mntent.h>
  6+#include <stdio.h>
  7+#include <stdlib.h>
  8+#include <string.h>
  9+
 10+#include "util.h"
 11+
 12+#ifdef STD_NON_POSIX
 13+static int
 14+fsopt_matches(const char *opts_list, const char *opt, size_t optlen)
 15+{
 16+	int match = 1;
 17+
 18+	if (optlen >= 2 && opt[0] == 'n' && opt[1] == 'o') {
 19+		match--;
 20+		opt += 2;
 21+		optlen -= 2;
 22+	}
 23+
 24+	if (optlen == 0)
 25+		return 0;
 26+
 27+	if (match && optlen > 1 && *opt == '+') {
 28+		opt++;
 29+		optlen--;
 30+	}
 31+
 32+	while (1) {
 33+		if (strncmp(opts_list, opt, optlen) == 0) {
 34+			const char *after_opt = opts_list + optlen;
 35+			if (*after_opt == '\0' || *after_opt == ',')
 36+				return match;
 37+		}
 38+
 39+		opts_list = strchr(opts_list, ',');
 40+		if (!opts_list)
 41+			break;
 42+		opts_list++;
 43+	}
 44+
 45+	return !match;
 46+}
 47+
 48+static int
 49+fsopts_matches(const char *opts_list, const char *reqopts_list)
 50+{
 51+	const char *comma;
 52+	size_t len;
 53+
 54+	if (!reqopts_list)
 55+		return 1;
 56+
 57+	while (1) {
 58+		comma = strchr(reqopts_list, ',');
 59+		if (!comma)
 60+			len = strlen(reqopts_list);
 61+		else
 62+			len = comma - reqopts_list;
 63+
 64+		if (len && !fsopt_matches(opts_list, reqopts_list, len))
 65+			return 0;
 66+
 67+		if (!comma)
 68+			break;
 69+		reqopts_list = ++comma;
 70+	}
 71+
 72+	return 1;
 73+}
 74+#endif
 75+
 76+static int
 77+umountall(int flags
 78+#ifdef STD_NON_POSIX
 79+          , const char *oflag
 80+#endif
 81+)
 82+{
 83+	FILE *fp;
 84+	struct mntent *me;
 85+	int ret = 0;
 86+	char **mntdirs = NULL;
 87+	int len = 0;
 88+
 89+	fp = setmntent("/proc/mounts", "r");
 90+	if (!fp)
 91+		eprintf("setmntent %s:", "/proc/mounts");
 92+	while ((me = getmntent(fp))) {
 93+		if (strcmp(me->mnt_type, "proc") == 0)
 94+			continue;
 95+#ifdef STD_NON_POSIX
 96+		if (oflag && !fsopts_matches(me->mnt_opts, oflag))
 97+			continue;
 98+#endif
 99+		mntdirs = erealloc(mntdirs, ++len * sizeof(*mntdirs));
100+		mntdirs[len - 1] = estrdup(me->mnt_dir);
101+	}
102+	endmntent(fp);
103+	while (--len >= 0) {
104+		if (umount2(mntdirs[len], flags) < 0) {
105+			weprintf("umount2 %s:", mntdirs[len]);
106+			ret = 1;
107+		}
108+		free(mntdirs[len]);
109+	}
110+	free(mntdirs);
111+	return ret;
112+}
113+
114+static void
115+usage(void)
116+{
117+#ifdef STD_NON_POSIX
118+	weprintf("usage: %s [-lfn] [-O options] target...\n", argv0);
119+	weprintf("usage: %s -a [-lfn] [-O options]\n", argv0);
120+#else
121+	weprintf("usage: %s [-lfn] target...\n", argv0);
122+	weprintf("usage: %s -a [-lfn]\n", argv0);
123+#endif
124+	exit(1);
125+}
126+
127+int
128+main(int argc, char *argv[])
129+{
130+	int i;
131+	int aflag = 0;
132+	int flags = 0;
133+	int ret = 0;
134+#ifdef STD_NON_POSIX
135+	char *oflag = NULL;
136+#endif
137+
138+	ARGBEGIN {
139+	case 'a':
140+		aflag = 1;
141+		break;
142+	case 'f':
143+		flags |= MNT_FORCE;
144+		break;
145+	case 'l':
146+		flags |= MNT_DETACH;
147+		break;
148+	case 'n':
149+		break;
150+#ifdef STD_NON_POSIX
151+	case 'O':
152+		oflag = EARGF(usage());
153+		break;
154+#endif
155+	default:
156+		usage();
157+	} ARGEND;
158+
159+	if (argc < 1 && aflag == 0)
160+		usage();
161+
162+#ifdef STD_NON_POSIX
163+	if (oflag && aflag == 0)
164+		usage();
165+#endif
166+
167+	if (aflag == 1)
168+		return umountall(flags
169+#ifdef STD_NON_POSIX
170+		                 , oflag
171+#endif
172+		);
173+
174+	for (i = 0; i < argc; i++) {
175+		if (umount2(argv[i], flags) < 0) {
176+			weprintf("umount2 %s:", argv[i]);
177+			ret = 1;
178+		}
179+	}
180+	return ret;
181+}
+54, -0
 1@@ -0,0 +1,54 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sched.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <string.h>
 7+#include <unistd.h>
 8+
 9+#include "util.h"
10+
11+static void
12+usage(void)
13+{
14+	eprintf("usage: %s [-muinpU] cmd [args...]\n", argv0);
15+}
16+
17+int
18+main(int argc, char *argv[])
19+{
20+	int flags = 0;
21+
22+	ARGBEGIN {
23+	case 'm':
24+		flags |= CLONE_NEWNS;
25+		break;
26+	case 'u':
27+		flags |= CLONE_NEWUTS;
28+		break;
29+	case 'i':
30+		flags |= CLONE_NEWIPC;
31+		break;
32+	case 'n':
33+		flags |= CLONE_NEWNET;
34+		break;
35+	case 'p':
36+		flags |= CLONE_NEWPID;
37+		break;
38+	case 'U':
39+		flags |= CLONE_NEWUSER;
40+		break;
41+	default:
42+		usage();
43+	} ARGEND;
44+
45+	if (argc < 1)
46+		usage();
47+
48+	if (unshare(flags) < 0)
49+		eprintf("unshare:");
50+
51+	if (execvp(argv[0], argv) < 0)
52+		eprintf("execvp:");
53+
54+	return 0;
55+}
+73, -0
 1@@ -0,0 +1,73 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/sysinfo.h>
 4+
 5+#include <stdio.h>
 6+#include <stdlib.h>
 7+#include <string.h>
 8+#include <time.h>
 9+#include <utmpx.h>
10+
11+#include "config.h"
12+#include "util.h"
13+
14+static void
15+usage(void)
16+{
17+	eprintf("usage: %s\n", argv0);
18+}
19+
20+int
21+main(int argc, char *argv[])
22+{
23+	struct utmpx utx;
24+	FILE *ufp;
25+	struct sysinfo info;
26+	time_t tmptime;
27+	struct tm *now;
28+	unsigned int days, hours, minutes;
29+	int nusers = 0;
30+	size_t n;
31+
32+	ARGBEGIN {
33+	default:
34+		usage();
35+	} ARGEND;
36+
37+	if (sysinfo(&info) < 0)
38+		eprintf("sysinfo:");
39+	time(&tmptime);
40+	now = localtime(&tmptime);
41+	printf(" %02d:%02d:%02d up ", now->tm_hour, now->tm_min, now->tm_sec);
42+	info.uptime /= 60;
43+	minutes = info.uptime % 60;
44+	info.uptime /= 60;
45+	hours = info.uptime % 24;
46+	days = info.uptime / 24;
47+	if (days)
48+		printf("%d day%s, ", days, days != 1 ? "s" : "");
49+	if (hours)
50+		printf("%2d:%02d, ", hours, minutes);
51+	else
52+		printf("%d min, ", minutes);
53+
54+	if ((ufp = fopen(UTMP_PATH, "r"))) {
55+		while ((n = fread(&utx, sizeof(utx), 1, ufp)) > 0) {
56+			if (!utx.ut_user[0])
57+				continue;
58+			if (utx.ut_type != USER_PROCESS)
59+				continue;
60+			nusers++;
61+		}
62+		if (ferror(ufp))
63+			eprintf("%s: read error:", UTMP_PATH);
64+		fclose(ufp);
65+		printf(" %d user%s, ", nusers, nusers != 1 ? "s" : "");
66+	}
67+
68+	printf(" load average: %.02f, %.02f, %.02f\n",
69+	       info.loads[0] / 65536.0f,
70+	       info.loads[1] / 65536.0f,
71+	       info.loads[2] / 65536.0f);
72+
73+	return 0;
74+}
+52, -0
 1@@ -0,0 +1,52 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/types.h>
 4+#include <sys/stat.h>
 5+#include <sys/ioctl.h>
 6+
 7+#include <fcntl.h>
 8+#include <stdio.h>
 9+#include <string.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+#define CONSOLE "/dev/console"
15+
16+#define VT_LOCKSWITCH   0x560B  /* disallow vt switching */
17+#define VT_UNLOCKSWITCH 0x560C  /* allow vt switching */
18+
19+static void
20+usage(void)
21+{
22+	eprintf("usage: %s n | y\n", argv0);
23+}
24+
25+int
26+main(int argc, char *argv[])
27+{
28+	int fd;
29+	int allow;
30+
31+	ARGBEGIN {
32+	default:
33+		usage();
34+	} ARGEND;
35+
36+	if (argc != 1)
37+		usage();
38+
39+	if (!strcmp(argv[0], "y"))
40+		allow = 1;
41+	else if (!strcmp(argv[0], "n"))
42+		allow = 0;
43+	else
44+		usage();
45+
46+	if ((fd = open(CONSOLE, O_WRONLY)) < 0)
47+		eprintf("open %s:", CONSOLE);
48+	if (ioctl(fd, allow ? VT_UNLOCKSWITCH : VT_LOCKSWITCH) < 0)
49+		eprintf("cannot %s VT switch:",
50+			allow ? "unlock" : "lock");
51+	close(fd);
52+	return 0;
53+}
+329, -0
  1@@ -0,0 +1,329 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include "util.h"
  4+#include "arg.h"
  5+
  6+#include <arpa/inet.h>
  7+#include <ctype.h>
  8+#include <errno.h>
  9+#include <netdb.h>
 10+#include <netinet/in.h>
 11+#include <resolv.h>
 12+#include <stdio.h>
 13+#include <stdlib.h>
 14+#include <string.h>
 15+#include <sys/socket.h>
 16+#include <sys/time.h>
 17+#include <sys/types.h>
 18+#include <unistd.h>
 19+
 20+struct RRType {
 21+	const char *name;
 22+	const char *msg;
 23+	int type;
 24+};
 25+
 26+static const struct RRType rrtypes[] = {
 27+	{ "A", "has address", 1 },
 28+	{ "NS", "name server", 2 },
 29+	{ "CNAME", "is a nickname for", 5 },
 30+	{ "SOA", "start of authority", 6 },
 31+	{ "PTR", "domain name pointer", 12 },
 32+	{ "MX", "mail is handled by", 15 },
 33+	{ "TXT", "descriptive text", 16 },
 34+	{ "AAAA", "has IPv6 address", 28 },
 35+	{ "SRV", "has SRV record", 33 },
 36+	{ "ANY", "has ANY record", 255 }
 37+};
 38+
 39+static void
 40+usage(void)
 41+{
 42+	eprintf("usage: %s [-t type] name [server]\n", argv0);
 43+}
 44+
 45+static int
 46+load_nameservers(char **ns, int max_ns)
 47+{
 48+	FILE *fp = fopen("/etc/resolv.conf", "r");
 49+	char line[256];
 50+	char *p, *end;
 51+	int count = 0;
 52+
 53+	if (!fp)
 54+		return 0;
 55+
 56+	while (fgets(line, sizeof(line), fp) && count < max_ns) {
 57+		if (strncmp(line, "nameserver", 10) == 0 && isspace(line[10])) {
 58+			p = line + 11;
 59+			while (isspace(*p))
 60+				p++;
 61+			end = p;
 62+			while (*end && !isspace(*end) && *end != '#')
 63+				end++;
 64+			*end = '\0';
 65+			if (*p) {
 66+				ns[count++] = estrdup(p);
 67+			}
 68+		}
 69+	}
 70+	fclose(fp);
 71+	return count;
 72+}
 73+
 74+static char *
 75+reverse_ip(const char *ip_str, int *type)
 76+{
 77+	struct in_addr addr4;
 78+	struct in6_addr addr6;
 79+	unsigned char *p;
 80+	char *buf = emalloc(256);
 81+	int i, j;
 82+
 83+	if (inet_pton(AF_INET, ip_str, &addr4) > 0) {
 84+		p = (unsigned char *)&addr4.s_addr;
 85+		sprintf(buf, "%d.%d.%d.%d.in-addr.arpa", p[3], p[2], p[1], p[0]);
 86+		*type = 12;
 87+		return buf;
 88+	} else if (inet_pton(AF_INET6, ip_str, &addr6) > 0) {
 89+		p = (unsigned char *)&addr6.s6_addr;
 90+		j = 0;
 91+		for (i = 15; i >= 0; i--) {
 92+			j += sprintf(buf + j, "%x.%x.", p[i] & 15, p[i] >> 4);
 93+		}
 94+		strcpy(buf + j, "ip6.arpa");
 95+		*type = 12;
 96+		return buf;
 97+	}
 98+
 99+	free(buf);
100+	return NULL;
101+}
102+
103+static int
104+send_query(const char *ns, const char *name, int type, unsigned char *resp, int resp_len)
105+{
106+	struct addrinfo hints, *res;
107+	unsigned char query[512];
108+	struct timeval tv;
109+	int qlen;
110+	int sock = -1;
111+	int r;
112+
113+	qlen = res_mkquery(0, name, 1, type, NULL, 0, NULL, query, sizeof(query));
114+	if (qlen < 0) {
115+		weprintf("res_mkquery failed for %s\n", name);
116+		return -1;
117+	}
118+
119+	memset(&hints, 0, sizeof(hints));
120+	hints.ai_family = AF_UNSPEC;
121+	hints.ai_socktype = SOCK_DGRAM;
122+
123+	r = getaddrinfo(ns, "53", &hints, &res);
124+	if (r != 0) {
125+		weprintf("getaddrinfo %s: %s\n", ns, gai_strerror(r));
126+		return -1;
127+	}
128+
129+	sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
130+	if (sock < 0) {
131+		freeaddrinfo(res);
132+		return -1;
133+	}
134+
135+	tv.tv_sec = 5;
136+	tv.tv_usec = 0;
137+	setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
138+
139+	if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
140+		close(sock);
141+		freeaddrinfo(res);
142+		return -1;
143+	}
144+
145+	if (send(sock, query, qlen, 0) < 0) {
146+		close(sock);
147+		freeaddrinfo(res);
148+		return -1;
149+	}
150+
151+	r = recv(sock, resp, resp_len, 0);
152+	close(sock);
153+	freeaddrinfo(res);
154+
155+	return r;
156+}
157+
158+static unsigned short
159+peek_be(const unsigned char *p)
160+{
161+	return (p[0] << 8) | p[1];
162+}
163+
164+static int
165+parse_response(const unsigned char *resp, int resp_len, const char *query_name)
166+{
167+	const unsigned char *p;
168+	char name[256];
169+	char target[256];
170+	char ipv6[64];
171+	char mname[256], rname[256];
172+	const char *err;
173+	const char *msg;
174+	struct in_addr a;
175+	int rcode, qdcount, ancount;
176+	int i, n, type, rdlen, pref, n1, n2;
177+	unsigned int ttl;
178+
179+	if (resp_len < 12) {
180+		weprintf("response too short: %d\n", resp_len);
181+		return -1;
182+	}
183+
184+	rcode = resp[3] & 0x0f;
185+	if (rcode != 0) {
186+		err = "Unknown error";
187+		switch (rcode) {
188+		case 1: err = "Format error"; break;
189+		case 2: err = "Server failure"; break;
190+		case 3: err = "Non-existent domain"; break;
191+		case 4: err = "Not implemented"; break;
192+		case 5: err = "Refused"; break;
193+		}
194+		eprintf("Host not found: %s\n", err);
195+	}
196+
197+	qdcount = peek_be(resp + 4);
198+	ancount = peek_be(resp + 6);
199+
200+	p = resp + 12;
201+	for (i = 0; i < qdcount; i++) {
202+		n = dn_expand(resp, resp + resp_len, p, name, sizeof(name));
203+		if (n < 0)
204+			return -1;
205+		p += n + 4;
206+	}
207+
208+	if (ancount == 0) {
209+		printf("%s has no records\n", query_name);
210+		return 0;
211+	}
212+
213+	for (i = 0; i < ancount; i++) {
214+		n = dn_expand(resp, resp + resp_len, p, name, sizeof(name));
215+		if (n < 0)
216+			return -1;
217+		p += n;
218+		type = peek_be(p);
219+		ttl = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7];
220+		rdlen = peek_be(p + 8);
221+		p += 10;
222+
223+		(void)ttl;
224+
225+		if (type == 1) {
226+			memcpy(&a, p, 4);
227+			printf("%s has address %s\n", name, inet_ntoa(a));
228+		} else if (type == 28) {
229+			inet_ntop(AF_INET6, p, ipv6, sizeof(ipv6));
230+			printf("%s has IPv6 address %s\n", name, ipv6);
231+		} else if (type == 2 || type == 5 || type == 12) {
232+			dn_expand(resp, resp + resp_len, p, target, sizeof(target));
233+			msg = "has record";
234+			if (type == 2) msg = "name server";
235+			else if (type == 5) msg = "is a nickname for";
236+			else if (type == 12) msg = "domain name pointer";
237+			printf("%s %s %s\n", name, msg, target);
238+		} else if (type == 15) {
239+			pref = peek_be(p);
240+			dn_expand(resp, resp + resp_len, p + 2, target, sizeof(target));
241+			printf("%s mail is handled by %d %s\n", name, pref, target);
242+		} else if (type == 16) {
243+			printf("%s descriptive text \"%.*s\"\n", name, (int)p[0], (char *)(p + 1));
244+		} else if (type == 6) {
245+			n1 = dn_expand(resp, resp + resp_len, p, mname, sizeof(mname));
246+			n2 = dn_expand(resp, resp + resp_len, p + n1, rname, sizeof(rname));
247+			(void)n2;
248+			printf("%s start of authority %s %s\n", name, mname, rname);
249+		} else {
250+			printf("%s has unsupported record type %d\n", name, type);
251+		}
252+
253+		p += rdlen;
254+	}
255+
256+	return 0;
257+}
258+
259+int
260+main(int argc, char *argv[])
261+{
262+	unsigned char resp[65536];
263+	char *ns[8];
264+	char *tflag = NULL;
265+	char *name;
266+	char *query_name;
267+	char *rev;
268+	int ns_count = 0;
269+	int type = 1;
270+	int i, r;
271+
272+	ARGBEGIN {
273+	case 't':
274+		tflag = EARGF(usage());
275+		break;
276+	default:
277+		usage();
278+	} ARGEND
279+
280+	if (argc < 1)
281+		usage();
282+
283+	query_name = argv[0];
284+
285+	if (argc > 1) {
286+		ns[0] = argv[1];
287+		ns_count = 1;
288+	} else {
289+		ns_count = load_nameservers(ns, 8);
290+		if (ns_count == 0)
291+			eprintf("no nameservers found in /etc/resolv.conf\n");
292+	}
293+
294+	rev = reverse_ip(query_name, &type);
295+	if (rev) {
296+		name = rev;
297+	} else {
298+		name = query_name;
299+		if (tflag) {
300+			type = -1;
301+			for (i = 0; i < (int)LEN(rrtypes); i++) {
302+				if (strcasecmp(tflag, rrtypes[i].name) == 0) {
303+					type = rrtypes[i].type;
304+					break;
305+				}
306+			}
307+			if (type == -1)
308+				eprintf("invalid record type: %s\n", tflag);
309+		}
310+	}
311+
312+	for (i = 0; i < ns_count; i++) {
313+		r = send_query(ns[i], name, type, resp, sizeof(resp));
314+		if (r > 0) {
315+			parse_response(resp, r, query_name);
316+			break;
317+		}
318+	}
319+
320+	if (rev)
321+		free(rev);
322+
323+	if (argc == 1) {
324+		for (i = 0; i < ns_count; i++) {
325+			free(ns[i]);
326+		}
327+	}
328+
329+	return r > 0 ? 0 : 1;
330+}
+291, -0
  1@@ -0,0 +1,291 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include "util.h"
  4+#include "arg.h"
  5+
  6+#include <arpa/inet.h>
  7+#include <ctype.h>
  8+#include <dirent.h>
  9+#include <errno.h>
 10+#include <fcntl.h>
 11+#include <netdb.h>
 12+#include <netinet/in.h>
 13+#include <stdio.h>
 14+#include <stdlib.h>
 15+#include <string.h>
 16+#include <sys/socket.h>
 17+#include <sys/stat.h>
 18+#include <sys/types.h>
 19+#include <time.h>
 20+#include <unistd.h>
 21+
 22+static void
 23+usage(void)
 24+{
 25+	eprintf("usage: %s [-e string] [-d string] [-v] [dir]\n", argv0);
 26+}
 27+
 28+static char *
 29+url_decode(char *s)
 30+{
 31+	char *r, *w;
 32+	unsigned int val;
 33+
 34+	for (r = w = s; *r; ) {
 35+		if (*r == '%' && isxdigit((unsigned char)r[1]) && isxdigit((unsigned char)r[2])) {
 36+			sscanf(r + 1, "%2x", &val);
 37+			*w++ = val;
 38+			r += 3;
 39+		} else if (*r == '+') {
 40+			*w++ = ' ';
 41+			r++;
 42+		} else {
 43+			*w++ = *r++;
 44+		}
 45+	}
 46+	*w = '\0';
 47+	return s;
 48+}
 49+
 50+static char *
 51+url_encode(const char *s)
 52+{
 53+	char *buf = emalloc(strlen(s) * 3 + 1);
 54+	char *w = buf;
 55+	const char *r = s;
 56+
 57+	while (*r) {
 58+		if (isalnum((unsigned char)*r) || strchr("-._~", *r)) {
 59+			*w++ = *r++;
 60+		} else {
 61+			w += sprintf(w, "%%%02X", (unsigned char)*r);
 62+			r++;
 63+		}
 64+	}
 65+	*w = '\0';
 66+	return buf;
 67+}
 68+
 69+static void
 70+send_error(int status, const char *msg)
 71+{
 72+	printf("HTTP/1.1 %d %s\r\n"
 73+	       "Content-Type: text/html; charset=UTF-8\r\n"
 74+	       "Connection: close\r\n\r\n", status, msg);
 75+	printf("<html><head><title>%d %s</title></head>"
 76+	       "<body><h3>%d %s</h3></body></html>\n", status, msg, status, msg);
 77+}
 78+
 79+static int
 80+is_under(const char *file, const char *dir)
 81+{
 82+	char *rfile = realpath(file, NULL);
 83+	char *rdir = realpath(dir, NULL);
 84+	int rc = 0;
 85+	size_t len;
 86+
 87+	if (rfile && rdir) {
 88+		len = strlen(rdir);
 89+		if (strncmp(rfile, rdir, len) == 0) {
 90+			if (rfile[len] == '\0' || rfile[len] == '/' || (len > 0 && rdir[len - 1] == '/'))
 91+				rc = 1;
 92+		}
 93+	}
 94+	free(rfile);
 95+	free(rdir);
 96+	return rc;
 97+}
 98+
 99+static const char *
100+get_mime_type(const char *file)
101+{
102+	const char *ext = strrchr(file, '.');
103+	if (!ext)
104+		return "application/octet-stream";
105+	ext++;
106+
107+	if (strcasecmp(ext, "html") == 0 || strcasecmp(ext, "htm") == 0)
108+		return "text/html; charset=UTF-8";
109+	if (strcasecmp(ext, "css") == 0)
110+		return "text/css";
111+	if (strcasecmp(ext, "js") == 0)
112+		return "application/javascript";
113+	if (strcasecmp(ext, "png") == 0)
114+		return "image/png";
115+	if (strcasecmp(ext, "jpg") == 0 || strcasecmp(ext, "jpeg") == 0)
116+		return "image/jpeg";
117+	if (strcasecmp(ext, "gif") == 0)
118+		return "image/gif";
119+	if (strcasecmp(ext, "txt") == 0)
120+		return "text/plain; charset=UTF-8";
121+	if (strcasecmp(ext, "pdf") == 0)
122+		return "application/pdf";
123+	if (strcasecmp(ext, "zip") == 0)
124+		return "application/zip";
125+
126+	return "application/octet-stream";
127+}
128+
129+static void
130+handle_connection(void)
131+{
132+	struct stat st, st_idx;
133+	struct dirent *de;
134+	DIR *dir;
135+	char line[4096];
136+	char method[32], path[2048], proto[32];
137+	char index_path[sizeof(path) + 32];
138+	char file_buf[8192];
139+	char date_buf[64];
140+	const char *mime_type;
141+	char *query, *p, *enc;
142+	ssize_t n_read;
143+	size_t len;
144+	int fd;
145+
146+	if (!fgets(line, sizeof(line), stdin))
147+		return;
148+
149+	if (sscanf(line, "%31s %2047s %31s", method, path, proto) != 3) {
150+		send_error(400, "Bad Request");
151+		return;
152+	}
153+
154+	while (fgets(line, sizeof(line), stdin)) {
155+		if (line[0] == '\r' || line[0] == '\n')
156+			break;
157+	}
158+
159+	if (strcasecmp(method, "GET") != 0) {
160+		send_error(501, "Not Implemented");
161+		return;
162+	}
163+
164+	url_decode(path);
165+
166+	query = strchr(path, '?');
167+	if (query) {
168+		*query = '\0';
169+		setenv("QUERY_STRING", query + 1, 1);
170+	} else {
171+		unsetenv("QUERY_STRING");
172+	}
173+
174+	p = path;
175+	while (*p == '/')
176+		p++;
177+	if (*p == '\0')
178+		p = ".";
179+
180+	if (stat(p, &st) < 0) {
181+		send_error(404, "Not Found");
182+		return;
183+	}
184+
185+	if (!is_under(p, ".")) {
186+		send_error(403, "Forbidden");
187+		return;
188+	}
189+
190+	if (S_ISDIR(st.st_mode)) {
191+		len = strlen(path);
192+		if (len > 0 && path[len - 1] != '/') {
193+			printf("HTTP/1.1 302 Found\r\n"
194+			       "Location: %s/\r\n"
195+			       "Connection: close\r\n\r\n", path);
196+			return;
197+		}
198+
199+		snprintf(index_path, sizeof(index_path), "%s/index.html", p);
200+		if (stat(index_path, &st_idx) == 0 && S_ISREG(st_idx.st_mode)) {
201+			p = index_path;
202+			st = st_idx;
203+			goto serve_file;
204+		}
205+
206+		dir = opendir(p);
207+		if (!dir) {
208+			send_error(403, "Forbidden");
209+			return;
210+		}
211+
212+		printf("HTTP/1.1 200 OK\r\n"
213+		       "Content-Type: text/html; charset=UTF-8\r\n"
214+		       "Connection: close\r\n\r\n");
215+		printf("<html><head><title>Index of %s</title></head><body>\n", path);
216+		printf("<h3>Index of %s</h3><hr><pre>\n", path);
217+
218+		while ((de = readdir(dir))) {
219+			if (strcmp(de->d_name, ".") == 0)
220+				continue;
221+			enc = url_encode(de->d_name);
222+			printf("<a href=\"%s\">%s</a>\n", enc, de->d_name);
223+			free(enc);
224+		}
225+		printf("</pre><hr></body></html>\n");
226+		closedir(dir);
227+		return;
228+	}
229+
230+serve_file:
231+	fd = open(p, O_RDONLY);
232+	if (fd < 0) {
233+		send_error(403, "Forbidden");
234+		return;
235+	}
236+
237+	mime_type = get_mime_type(p);
238+	strftime(date_buf, sizeof(date_buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&st.st_mtime));
239+
240+	printf("HTTP/1.1 200 OK\r\n"
241+	       "Content-Type: %s\r\n"
242+	       "Content-Length: %lld\r\n"
243+	       "Last-Modified: %s\r\n"
244+	       "Connection: close\r\n\r\n",
245+	       mime_type, (long long)st.st_size, date_buf);
246+
247+	while ((n_read = read(fd, file_buf, sizeof(file_buf))) > 0) {
248+		writeall(1, file_buf, n_read);
249+	}
250+	close(fd);
251+}
252+
253+int
254+main(int argc, char *argv[])
255+{
256+	char *eflag = NULL;
257+	char *dflag = NULL;
258+	char *enc;
259+
260+	ARGBEGIN {
261+	case 'e':
262+		eflag = EARGF(usage());
263+		break;
264+	case 'd':
265+		dflag = EARGF(usage());
266+		break;
267+	case 'v':
268+		break;
269+	default:
270+		usage();
271+	} ARGEND
272+
273+	if (eflag) {
274+		enc = url_encode(eflag);
275+		printf("%s\n", enc);
276+		free(enc);
277+		return 0;
278+	}
279+
280+	if (dflag) {
281+		printf("%s\n", url_decode(dflag));
282+		return 0;
283+	}
284+
285+	if (argc > 0) {
286+		if (chdir(argv[0]) < 0)
287+			eprintf("chdir %s:\n", argv[0]);
288+	}
289+
290+	handle_connection();
291+	return 0;
292+}
+392, -0
  1@@ -0,0 +1,392 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include "util.h"
  4+#include "arg.h"
  5+
  6+#include <arpa/inet.h>
  7+#include <ctype.h>
  8+#include <errno.h>
  9+#include <net/if.h>
 10+#include <net/if_arp.h>
 11+#include <netinet/in.h>
 12+#include <stdio.h>
 13+#include <stdlib.h>
 14+#include <string.h>
 15+#include <sys/ioctl.h>
 16+#include <sys/socket.h>
 17+#include <sys/types.h>
 18+#include <unistd.h>
 19+
 20+static void
 21+usage(void)
 22+{
 23+	eprintf("usage: %s [-a] [interface [action ...]]\n", argv0);
 24+}
 25+
 26+static void
 27+print_ipv6(const char *name)
 28+{
 29+	FILE *fp = fopen("/proc/net/if_inet6", "r");
 30+	char line[256];
 31+	char addr_hex[40];
 32+	char ifname[IFNAMSIZ];
 33+	unsigned int ifindex, plen, scope, flags;
 34+	int i, j;
 35+	char ipv6_str[40];
 36+	const char *scope_str;
 37+
 38+	if (!fp)
 39+		return;
 40+
 41+	while (fgets(line, sizeof(line), fp)) {
 42+		if (sscanf(line, "%32s %x %x %x %x %15s", addr_hex, &ifindex, &plen, &scope, &flags, ifname) == 6) {
 43+			if (strcmp(name, ifname) == 0) {
 44+				j = 0;
 45+				for (i = 0; i < 32; i++) {
 46+					ipv6_str[j++] = addr_hex[i];
 47+					if (i > 0 && i < 31 && (i % 4 == 3))
 48+						ipv6_str[j++] = ':';
 49+				}
 50+				ipv6_str[j] = '\0';
 51+
 52+				scope_str = "Unknown";
 53+				switch (scope) {
 54+				case 0x00: scope_str = "Global"; break;
 55+				case 0x10: scope_str = "Host"; break;
 56+				case 0x20: scope_str = "Link"; break;
 57+				case 0x40: scope_str = "Site"; break;
 58+				case 0x80: scope_str = "Compat"; break;
 59+				}
 60+				printf("        inet6 addr: %s/%d Scope:%s\n", ipv6_str, plen, scope_str);
 61+			}
 62+		}
 63+	}
 64+	fclose(fp);
 65+}
 66+
 67+static void
 68+display_interface(int sock, const char *name)
 69+{
 70+	struct ifreq ifr;
 71+	struct sockaddr_in *sin;
 72+	unsigned char *hwaddr;
 73+	FILE *fp;
 74+	char line[256];
 75+	char *p, *ifname;
 76+	short flags;
 77+	int mtu = 0;
 78+	int metric = 0;
 79+	unsigned long long rx_bytes, rx_packets, rx_errs, rx_drop;
 80+	unsigned long long tx_bytes, tx_packets, tx_errs, tx_drop;
 81+
 82+	memset(&ifr, 0, sizeof(ifr));
 83+	strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
 84+
 85+	if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
 86+		weprintf("ioctl SIOCGIFFLAGS %s:\n", name);
 87+		return;
 88+	}
 89+	flags = ifr.ifr_flags;
 90+
 91+	printf("%-9s ", name);
 92+
 93+	if (ioctl(sock, SIOCGIFHWADDR, &ifr) >= 0) {
 94+		hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data;
 95+		printf("Link encap:");
 96+		switch (ifr.ifr_hwaddr.sa_family) {
 97+		case ARPHRD_ETHER:
 98+			printf("Ethernet  HWaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
 99+			       hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
100+			break;
101+		case ARPHRD_LOOPBACK:
102+			printf("Local Loopback\n");
103+			break;
104+		default:
105+			printf("UNSPEC\n");
106+			break;
107+		}
108+	} else {
109+		printf("Link encap:UNSPEC\n");
110+	}
111+
112+	memset(&ifr, 0, sizeof(ifr));
113+	strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
114+	if (ioctl(sock, SIOCGIFADDR, &ifr) >= 0) {
115+		sin = (struct sockaddr_in *)&ifr.ifr_addr;
116+		printf("        inet addr:%s", inet_ntoa(sin->sin_addr));
117+
118+		memset(&ifr, 0, sizeof(ifr));
119+		strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
120+		if (ioctl(sock, SIOCGIFBRDADDR, &ifr) >= 0) {
121+			sin = (struct sockaddr_in *)&ifr.ifr_broadaddr;
122+			printf("  Bcast:%s", inet_ntoa(sin->sin_addr));
123+		}
124+
125+		memset(&ifr, 0, sizeof(ifr));
126+		strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
127+		if (ioctl(sock, SIOCGIFNETMASK, &ifr) >= 0) {
128+			sin = (struct sockaddr_in *)&ifr.ifr_netmask;
129+			printf("  Mask:%s", inet_ntoa(sin->sin_addr));
130+		}
131+		printf("\n");
132+	}
133+
134+	print_ipv6(name);
135+
136+	printf("        ");
137+	if (flags & IFF_UP) printf("UP ");
138+	if (flags & IFF_BROADCAST) printf("BROADCAST ");
139+	if (flags & IFF_DEBUG) printf("DEBUG ");
140+	if (flags & IFF_LOOPBACK) printf("LOOPBACK ");
141+	if (flags & IFF_POINTOPOINT) printf("POINTOPOINT ");
142+	if (flags & IFF_RUNNING) printf("RUNNING ");
143+	if (flags & IFF_NOARP) printf("NOARP ");
144+	if (flags & IFF_PROMISC) printf("PROMISC ");
145+	if (flags & IFF_ALLMULTI) printf("ALLMULTI ");
146+	if (flags & IFF_MULTICAST) printf("MULTICAST ");
147+
148+	memset(&ifr, 0, sizeof(ifr));
149+	strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
150+	if (ioctl(sock, SIOCGIFMTU, &ifr) >= 0)
151+		mtu = ifr.ifr_mtu;
152+	if (ioctl(sock, SIOCGIFMETRIC, &ifr) >= 0)
153+		metric = ifr.ifr_metric;
154+	printf(" MTU:%d  Metric:%d\n", mtu, metric);
155+
156+	fp = fopen("/proc/net/dev", "r");
157+	if (fp) {
158+		while (fgets(line, sizeof(line), fp)) {
159+			p = strchr(line, ':');
160+			if (p) {
161+				*p = '\0';
162+				ifname = line;
163+				while (isspace(*ifname))
164+					ifname++;
165+				if (strcmp(ifname, name) == 0) {
166+					if (sscanf(p + 1, "%llu %llu %llu %llu %*u %*u %*u %*u %llu %llu %llu %llu",
167+					           &rx_bytes, &rx_packets, &rx_errs, &rx_drop,
168+					           &tx_bytes, &tx_packets, &tx_errs, &tx_drop) == 8) {
169+						printf("        RX packets:%llu errors:%llu dropped:%llu overruns:0 frame:0\n",
170+						       rx_packets, rx_errs, rx_drop);
171+						printf("        TX packets:%llu errors:%llu dropped:%llu overruns:0 carrier:0\n",
172+						       tx_packets, tx_errs, tx_drop);
173+						printf("        RX bytes:%llu  TX bytes:%llu\n", rx_bytes, tx_bytes);
174+					}
175+					break;
176+				}
177+			}
178+		}
179+		fclose(fp);
180+	}
181+	printf("\n");
182+}
183+
184+static void
185+list_interfaces(int sock, int all)
186+{
187+	FILE *fp = fopen("/proc/net/dev", "r");
188+	struct ifreq ifr;
189+	char line[256];
190+	char *p, *name;
191+	int line_num = 0;
192+
193+	if (!fp)
194+		eprintf("fopen /proc/net/dev:\n");
195+
196+	while (fgets(line, sizeof(line), fp)) {
197+		line_num++;
198+		if (line_num <= 2)
199+			continue;
200+		p = strchr(line, ':');
201+		if (p) {
202+			*p = '\0';
203+			name = line;
204+			while (isspace(*name))
205+				name++;
206+			memset(&ifr, 0, sizeof(ifr));
207+			strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
208+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) >= 0) {
209+				if (all || (ifr.ifr_flags & IFF_UP)) {
210+					display_interface(sock, name);
211+				}
212+			}
213+		}
214+	}
215+	fclose(fp);
216+}
217+
218+int
219+main(int argc, char *argv[])
220+{
221+	struct ifreq ifr;
222+	struct sockaddr_in *sin;
223+	char *name;
224+	char *arg;
225+	char *slash;
226+	int aflag = 0;
227+	int sock = -1;
228+	int i = 1;
229+	int prefix;
230+	unsigned int mask;
231+
232+	ARGBEGIN {
233+	case 'a':
234+		aflag = 1;
235+		break;
236+	default:
237+		usage();
238+	} ARGEND
239+
240+	sock = socket(AF_INET, SOCK_DGRAM, 0);
241+	if (sock < 0)
242+		eprintf("socket:\n");
243+
244+	if (argc == 0) {
245+		list_interfaces(sock, aflag);
246+		close(sock);
247+		return 0;
248+	}
249+
250+	name = argv[0];
251+
252+	if (argc == 1) {
253+		display_interface(sock, name);
254+		close(sock);
255+		return 0;
256+	}
257+
258+	memset(&ifr, 0, sizeof(ifr));
259+	strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
260+
261+	while (i < argc) {
262+		arg = argv[i];
263+
264+		if (strcmp(arg, "up") == 0) {
265+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
266+			ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
267+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
268+			i++;
269+		} else if (strcmp(arg, "down") == 0) {
270+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
271+			ifr.ifr_flags &= ~IFF_UP;
272+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
273+			i++;
274+		} else if (strcmp(arg, "netmask") == 0) {
275+			if (i + 1 >= argc) eprintf("netmask needs an address\n");
276+			sin = (struct sockaddr_in *)&ifr.ifr_netmask;
277+			sin->sin_family = AF_INET;
278+			if (inet_pton(AF_INET, argv[i + 1], &sin->sin_addr) <= 0)
279+				eprintf("invalid address: %s\n", argv[i + 1]);
280+			if (ioctl(sock, SIOCSIFNETMASK, &ifr) < 0) eprintf("ioctl SIOCSIFNETMASK:");
281+			i += 2;
282+		} else if (strcmp(arg, "broadcast") == 0) {
283+			if (i + 1 >= argc) eprintf("broadcast needs an address\n");
284+			sin = (struct sockaddr_in *)&ifr.ifr_broadaddr;
285+			sin->sin_family = AF_INET;
286+			if (inet_pton(AF_INET, argv[i + 1], &sin->sin_addr) <= 0)
287+				eprintf("invalid address: %s\n", argv[i + 1]);
288+			if (ioctl(sock, SIOCSIFBRDADDR, &ifr) < 0) eprintf("ioctl SIOCSIFBRDADDR:");
289+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
290+			ifr.ifr_flags |= IFF_BROADCAST;
291+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
292+			i += 2;
293+		} else if (strcmp(arg, "mtu") == 0) {
294+			if (i + 1 >= argc) eprintf("mtu needs a value\n");
295+			ifr.ifr_mtu = atoi(argv[i + 1]);
296+			if (ioctl(sock, SIOCSIFMTU, &ifr) < 0) eprintf("ioctl SIOCSIFMTU:");
297+			i += 2;
298+		} else if (strcmp(arg, "metric") == 0) {
299+			if (i + 1 >= argc) eprintf("metric needs a value\n");
300+			ifr.ifr_metric = atoi(argv[i + 1]);
301+			if (ioctl(sock, SIOCSIFMETRIC, &ifr) < 0) eprintf("ioctl SIOCSIFMETRIC:");
302+			i += 2;
303+		} else if (strcmp(arg, "txqueuelen") == 0) {
304+			if (i + 1 >= argc) eprintf("txqueuelen needs a value\n");
305+			ifr.ifr_qlen = atoi(argv[i + 1]);
306+			if (ioctl(sock, SIOCSIFTXQLEN, &ifr) < 0) eprintf("ioctl SIOCSIFTXQLEN:");
307+			i += 2;
308+		} else if (strcmp(arg, "dstaddr") == 0 || strcmp(arg, "pointopoint") == 0) {
309+			if (i + 1 >= argc) eprintf("%s needs an address\n", arg);
310+			sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
311+			sin->sin_family = AF_INET;
312+			if (inet_pton(AF_INET, argv[i + 1], &sin->sin_addr) <= 0)
313+				eprintf("invalid address: %s\n", argv[i + 1]);
314+			if (ioctl(sock, SIOCSIFDSTADDR, &ifr) < 0) eprintf("ioctl SIOCSIFDSTADDR:");
315+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
316+			ifr.ifr_flags |= IFF_POINTOPOINT;
317+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
318+			i += 2;
319+		} else if (strcmp(arg, "arp") == 0) {
320+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
321+			ifr.ifr_flags &= ~IFF_NOARP;
322+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
323+			i++;
324+		} else if (strcmp(arg, "-arp") == 0) {
325+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
326+			ifr.ifr_flags |= IFF_NOARP;
327+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
328+			i++;
329+		} else if (strcmp(arg, "promisc") == 0) {
330+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
331+			ifr.ifr_flags |= IFF_PROMISC;
332+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
333+			i++;
334+		} else if (strcmp(arg, "-promisc") == 0) {
335+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
336+			ifr.ifr_flags &= ~IFF_PROMISC;
337+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
338+			i++;
339+		} else if (strcmp(arg, "allmulti") == 0) {
340+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
341+			ifr.ifr_flags |= IFF_ALLMULTI;
342+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
343+			i++;
344+		} else if (strcmp(arg, "-allmulti") == 0) {
345+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
346+			ifr.ifr_flags &= ~IFF_ALLMULTI;
347+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
348+			i++;
349+		} else if (strcmp(arg, "multicast") == 0) {
350+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
351+			ifr.ifr_flags |= IFF_MULTICAST;
352+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
353+			i++;
354+		} else if (strcmp(arg, "-multicast") == 0) {
355+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
356+			ifr.ifr_flags &= ~IFF_MULTICAST;
357+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
358+			i++;
359+		} else {
360+			sin = (struct sockaddr_in *)&ifr.ifr_addr;
361+			sin->sin_family = AF_INET;
362+			slash = strchr(arg, '/');
363+			prefix = -1;
364+			if (slash) {
365+				*slash = '\0';
366+				prefix = atoi(slash + 1);
367+			}
368+			if (inet_pton(AF_INET, arg, &sin->sin_addr) <= 0) {
369+				eprintf("unknown action or invalid address: %s\n", arg);
370+			}
371+			if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) eprintf("ioctl SIOCSIFADDR:");
372+
373+			if (prefix >= 0) {
374+				mask = 0;
375+				if (prefix > 0)
376+					mask = htonl(~0U << (32 - prefix));
377+				sin = (struct sockaddr_in *)&ifr.ifr_netmask;
378+				sin->sin_family = AF_INET;
379+				sin->sin_addr.s_addr = mask;
380+				if (ioctl(sock, SIOCSIFNETMASK, &ifr) < 0) eprintf("ioctl SIOCSIFNETMASK:");
381+			}
382+
383+			if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
384+			ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
385+			if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
386+
387+			i++;
388+		}
389+	}
390+
391+	close(sock);
392+	return 0;
393+}
+222, -0
  1@@ -0,0 +1,222 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/socket.h>
  4+#include <sys/types.h>
  5+
  6+#include <arpa/inet.h>
  7+#include <netinet/in.h>
  8+
  9+#include <errno.h>
 10+#include <fcntl.h>
 11+#include <netdb.h>
 12+#include <poll.h>
 13+#include <stdio.h>
 14+#include <stdlib.h>
 15+#include <string.h>
 16+#include <unistd.h>
 17+
 18+#include "util.h"
 19+
 20+static void
 21+usage(void)
 22+{
 23+	eprintf("usage: %s [-lu] [-p localport] [host] [port]\n", argv0);
 24+}
 25+
 26+static int
 27+resolve(const char *host, const char *port, int family, int socktype,
 28+	int passive, struct sockaddr_storage *addr, socklen_t *addrlen)
 29+{
 30+	struct addrinfo hints, *res;
 31+	int r;
 32+
 33+	memset(&hints, 0, sizeof(hints));
 34+	hints.ai_family = family;
 35+	hints.ai_socktype = socktype;
 36+	if (passive)
 37+		hints.ai_flags = AI_PASSIVE;
 38+
 39+	if ((r = getaddrinfo(host, port, &hints, &res)) != 0) {
 40+		weprintf("getaddrinfo: %s\n", gai_strerror(r));
 41+		return -1;
 42+	}
 43+
 44+	memcpy(addr, res->ai_addr, res->ai_addrlen);
 45+	*addrlen = res->ai_addrlen;
 46+	freeaddrinfo(res);
 47+	return 0;
 48+}
 49+
 50+int
 51+main(int argc, char *argv[])
 52+{
 53+	struct sockaddr_storage local_addr, remote_addr;
 54+	socklen_t local_len = sizeof(local_addr),
 55+		  remote_len = sizeof(remote_addr);
 56+	struct pollfd fds[2];
 57+	int listenfd = -1, sockfd = -1;
 58+	int lflag = 0;
 59+	int uflag = 0;
 60+	char *port = NULL;
 61+	char *host = NULL;
 62+	char *local_port = NULL;
 63+	int socktype;
 64+	int n, opt;
 65+	char buf[BUFSIZ];
 66+
 67+	ARGBEGIN
 68+	{
 69+	case 'l':
 70+		lflag = 1;
 71+		break;
 72+	case 'p':
 73+		local_port = EARGF(usage());
 74+		break;
 75+	case 'u':
 76+		uflag = 1;
 77+		break;
 78+	default:
 79+		usage();
 80+	}
 81+	ARGEND
 82+
 83+	socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
 84+
 85+	if (lflag) {
 86+		/* server mode */
 87+		if (!local_port) {
 88+			if (argc == 1) {
 89+				local_port = argv[0];
 90+				argc = 0;
 91+			} else {
 92+				usage();
 93+			}
 94+		}
 95+		memset(&local_addr, 0, sizeof(local_addr));
 96+		if (resolve(NULL, local_port, AF_UNSPEC, socktype, 1,
 97+			    &local_addr, &local_len) < 0)
 98+			return 1;
 99+
100+		listenfd = socket(local_addr.ss_family, socktype, 0);
101+		if (listenfd < 0)
102+			eprintf("socket:");
103+
104+		opt = 1;
105+		setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt,
106+			   sizeof(opt));
107+
108+		if (bind(listenfd, (struct sockaddr *)&local_addr, local_len) <
109+		    0)
110+			eprintf("bind:");
111+
112+		if (!uflag) {
113+			if (listen(listenfd, 5) < 0)
114+				eprintf("listen:");
115+			sockfd = accept(listenfd,
116+					(struct sockaddr *)&remote_addr,
117+					&remote_len);
118+			if (sockfd < 0)
119+				eprintf("accept:");
120+			close(listenfd);
121+		} else {
122+			sockfd = listenfd;
123+			n = recvfrom(sockfd, buf, sizeof(buf), MSG_PEEK,
124+				     (struct sockaddr *)&remote_addr,
125+				     &remote_len);
126+			if (n < 0)
127+				eprintf("recvfrom:");
128+			if (connect(sockfd, (struct sockaddr *)&remote_addr,
129+				    remote_len) < 0)
130+				eprintf("connect:");
131+		}
132+	} else {
133+		/* client mode */
134+		if (argc != 2)
135+			usage();
136+		host = argv[0];
137+		port = argv[1];
138+
139+		memset(&remote_addr, 0, sizeof(remote_addr));
140+		if (resolve(host, port, AF_UNSPEC, socktype, 0, &remote_addr,
141+			    &remote_len) < 0)
142+			return 1;
143+
144+		sockfd = socket(remote_addr.ss_family, socktype, 0);
145+		if (sockfd < 0)
146+			eprintf("socket:");
147+
148+		if (local_port) {
149+			memset(&local_addr, 0, sizeof(local_addr));
150+			if (resolve(NULL, local_port, remote_addr.ss_family,
151+				    socktype, 1, &local_addr, &local_len) < 0)
152+				return 1;
153+			opt = 1;
154+			setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt,
155+				   sizeof(opt));
156+			if (bind(sockfd, (struct sockaddr *)&local_addr,
157+				 local_len) < 0)
158+				eprintf("bind:");
159+		}
160+
161+		if (connect(sockfd, (struct sockaddr *)&remote_addr,
162+			    remote_len) < 0)
163+			eprintf("connect:");
164+	}
165+
166+	fds[0].fd = 0;
167+	fds[0].events = POLLIN;
168+	fds[1].fd = sockfd;
169+	fds[1].events = POLLIN;
170+
171+	while (1) {
172+		if (poll(fds, 2, -1) < 0) {
173+			if (errno == EINTR)
174+				continue;
175+			eprintf("poll:");
176+		}
177+
178+		if (fds[0].revents & POLLIN) {
179+			n = read(0, buf, sizeof(buf));
180+			if (n < 0) {
181+				weprintf("read stdin:");
182+				break;
183+			}
184+			if (n == 0) {
185+				if (!uflag) {
186+					shutdown(sockfd, SHUT_WR);
187+					fds[0].fd = -1;
188+				} else {
189+					break;
190+				}
191+			} else {
192+				if (writeall(sockfd, buf, n) < 0) {
193+					weprintf("write socket:");
194+					break;
195+				}
196+			}
197+		}
198+
199+		if (fds[1].revents & POLLIN) {
200+			n = read(sockfd, buf, sizeof(buf));
201+			if (n < 0) {
202+				weprintf("read socket:");
203+				break;
204+			}
205+			if (n == 0) {
206+				break;
207+			} else {
208+				if (writeall(1, buf, n) < 0) {
209+					weprintf("write stdout:");
210+					break;
211+				}
212+			}
213+		}
214+
215+		if ((fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) ||
216+		    (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL))) {
217+			break;
218+		}
219+	}
220+
221+	close(sockfd);
222+	return 0;
223+}
+311, -0
  1@@ -0,0 +1,311 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include "util.h"
  4+#include "arg.h"
  5+
  6+#include <arpa/inet.h>
  7+#include <errno.h>
  8+#include <netdb.h>
  9+#include <netinet/in.h>
 10+#include <netinet/ip.h>
 11+#include <netinet/ip_icmp.h>
 12+#include <poll.h>
 13+#include <signal.h>
 14+#include <stdio.h>
 15+#include <stdlib.h>
 16+#include <string.h>
 17+#include <sys/socket.h>
 18+#include <sys/time.h>
 19+#include <sys/types.h>
 20+#include <unistd.h>
 21+
 22+static int keep_running = 1;
 23+
 24+static void
 25+usage(void)
 26+{
 27+	eprintf("usage: %s [-c count] [-i interval] [-s size] [-t ttl] [-w deadline] [-q] host\n", argv0);
 28+}
 29+
 30+static void
 31+sigint_handler(int sig)
 32+{
 33+	(void)sig;
 34+	keep_running = 0;
 35+}
 36+
 37+static unsigned short
 38+checksum(unsigned short *addr, int len)
 39+{
 40+	unsigned long sum = 0;
 41+
 42+	while (len > 1) {
 43+		sum += *addr++;
 44+		len -= 2;
 45+	}
 46+	if (len > 0)
 47+		sum += *(unsigned char *)addr;
 48+	while (sum >> 16)
 49+		sum = (sum & 0xffff) + (sum >> 16);
 50+	return ~sum;
 51+}
 52+
 53+static void
 54+send_ping(int sock, struct sockaddr_in *dst, int seq, int size)
 55+{
 56+	struct icmphdr *icmp;
 57+	char *packet;
 58+	struct timeval tv;
 59+	int packlen = sizeof(*icmp) + size;
 60+
 61+	packet = emalloc(packlen);
 62+	memset(packet, 0, packlen);
 63+
 64+	icmp = (struct icmphdr *)packet;
 65+	icmp->type = ICMP_ECHO;
 66+	icmp->code = 0;
 67+	icmp->un.echo.id = htons(getpid() & 0xffff);
 68+	icmp->un.echo.sequence = htons(seq);
 69+
 70+	/* store timestamp in payload if size is large enough */
 71+	if (size >= (int)sizeof(struct timeval)) {
 72+		gettimeofday(&tv, NULL);
 73+		memcpy(packet + sizeof(*icmp), &tv, sizeof(tv));
 74+	}
 75+
 76+	icmp->checksum = checksum((unsigned short *)packet, packlen);
 77+
 78+	if (sendto(sock, packet, packlen, 0, (struct sockaddr *)dst, sizeof(*dst)) < 0)
 79+		eprintf("sendto:");
 80+
 81+	free(packet);
 82+}
 83+
 84+static double
 85+get_time_ms(void)
 86+{
 87+	struct timeval tv;
 88+	gettimeofday(&tv, NULL);
 89+	return (double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0;
 90+}
 91+
 92+static void
 93+print_stats(const char *host, int sent, int received, double min_rtt, double max_rtt, double sum_rtt)
 94+{
 95+	printf("\n--- %s ping statistics ---\n", host);
 96+	printf("%d packets transmitted, %d received, %d%% packet loss\n",
 97+	       sent, received, sent > 0 ? (sent - received) * 100 / sent : 0);
 98+	if (received > 0) {
 99+		printf("rtt min/avg/max = %.3f/%.3f/%.3f ms\n",
100+		       min_rtt, sum_rtt / received, max_rtt);
101+	}
102+}
103+
104+int
105+main(int argc, char *argv[])
106+{
107+	struct addrinfo hints, *res;
108+	struct sockaddr_in dst;
109+	struct sockaddr_in from;
110+	struct pollfd pfd;
111+	struct timeval sent_tv;
112+	struct icmphdr *icmp;
113+	char *cflag = NULL;
114+	char *iflag = NULL;
115+	char *sflag = NULL;
116+	char *tflag = NULL;
117+	char *wflag = NULL;
118+	char *host;
119+	char *rxbuf;
120+	int qflag = 0;
121+	int count = 0;
122+	int size = 56;
123+	int ttl = 0;
124+	int deadline = 0;
125+	int sock = -1;
126+	int is_raw = 1;
127+	int seq = 1;
128+	int sent = 0;
129+	int received = 0;
130+	int r, optval, p_res, hlen;
131+	double interval = 1.0;
132+	double min_rtt = 999999.0;
133+	double max_rtt = 0.0;
134+	double sum_rtt = 0.0;
135+	double start_time, deadline_ms, next_send_ms, now, timeout_ms, time_to_deadline, rtt, sent_ms;
136+	ssize_t n;
137+	socklen_t fromlen;
138+
139+	ARGBEGIN {
140+	case 'c':
141+		cflag = EARGF(usage());
142+		break;
143+	case 'i':
144+		iflag = EARGF(usage());
145+		break;
146+	case 's':
147+		sflag = EARGF(usage());
148+		break;
149+	case 't':
150+		tflag = EARGF(usage());
151+		break;
152+	case 'w':
153+		wflag = EARGF(usage());
154+		break;
155+	case 'q':
156+		qflag = 1;
157+		break;
158+	default:
159+		usage();
160+	} ARGEND
161+
162+	if (argc < 1)
163+		usage();
164+
165+	host = argv[0];
166+
167+	if (cflag)
168+		count = estrtonum(cflag, 1, 1000000);
169+	if (iflag)
170+		interval = estrtod(iflag);
171+	if (sflag)
172+		size = estrtonum(sflag, 0, 65507);
173+	if (tflag)
174+		ttl = estrtonum(tflag, 1, 255);
175+	if (wflag)
176+		deadline = estrtonum(wflag, 1, 1000000);
177+
178+	memset(&hints, 0, sizeof(hints));
179+	hints.ai_family = AF_INET;
180+	hints.ai_socktype = SOCK_RAW;
181+
182+	r = getaddrinfo(host, NULL, &hints, &res);
183+	if (r != 0)
184+		eprintf("getaddrinfo %s: %s\n", host, gai_strerror(r));
185+
186+	memcpy(&dst, res->ai_addr, sizeof(dst));
187+	freeaddrinfo(res);
188+
189+	/* try opening raw icmp socket first, fallback to dgram */
190+	sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
191+	if (sock < 0) {
192+		sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
193+		if (sock < 0)
194+			eprintf("socket:");
195+		is_raw = 0;
196+	}
197+
198+	if (ttl > 0) {
199+		if (setsockopt(sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0)
200+			eprintf("setsockopt IP_TTL:");
201+	}
202+
203+	/* request that recvfrom returns the ttl value */
204+	optval = 1;
205+	if (is_raw) {
206+		setsockopt(sock, IPPROTO_IP, IP_RECVTTL, &optval, sizeof(optval));
207+	}
208+
209+	if (!qflag) {
210+		printf("PING %s (%s) %d bytes of data.\n",
211+		       host, inet_ntoa(dst.sin_addr), size);
212+	}
213+
214+	signal(SIGINT, sigint_handler);
215+
216+	pfd.fd = sock;
217+	pfd.events = POLLIN;
218+
219+	start_time = get_time_ms();
220+	deadline_ms = deadline > 0 ? start_time + deadline * 1000.0 : 0.0;
221+	next_send_ms = start_time;
222+
223+	rxbuf = emalloc(size + 1024);
224+
225+	while (keep_running) {
226+		now = get_time_ms();
227+
228+		if (deadline > 0 && now >= deadline_ms)
229+			break;
230+
231+		if (count > 0 && sent >= count && received >= sent)
232+			break;
233+
234+		if (now >= next_send_ms && (count == 0 || sent < count)) {
235+			send_ping(sock, &dst, seq++, size);
236+			sent++;
237+			next_send_ms = now + interval * 1000.0;
238+		}
239+
240+		timeout_ms = next_send_ms - now;
241+		if (deadline > 0) {
242+			time_to_deadline = deadline_ms - now;
243+			if (time_to_deadline < timeout_ms)
244+				timeout_ms = time_to_deadline;
245+		}
246+		if (timeout_ms < 0)
247+			timeout_ms = 0;
248+
249+		if (count > 0 && sent >= count)
250+			timeout_ms = 2000.0;
251+
252+		p_res = poll(&pfd, 1, (int)timeout_ms);
253+		if (p_res < 0) {
254+			if (errno == EINTR)
255+				continue;
256+			eprintf("poll:\n");
257+		}
258+
259+		if (p_res > 0 && (pfd.revents & POLLIN)) {
260+			fromlen = sizeof(from);
261+			n = recvfrom(sock, rxbuf, size + 1024, 0, (struct sockaddr *)&from, &fromlen);
262+			if (n < 0) {
263+				if (errno == EINTR || errno == EAGAIN)
264+					continue;
265+				eprintf("recvfrom:\n");
266+			}
267+
268+			hlen = 0;
269+			if (is_raw) {
270+				struct ip *ip = (struct ip *)rxbuf;
271+				hlen = ip->ip_hl << 2;
272+				if (n < hlen + (int)sizeof(*icmp))
273+					continue;
274+			}
275+			icmp = (struct icmphdr *)(rxbuf + hlen);
276+
277+			if (icmp->type == ICMP_ECHOREPLY &&
278+			    (!is_raw || ntohs(icmp->un.echo.id) == (getpid() & 0xffff))) {
279+				received++;
280+				rtt = get_time_ms();
281+				if (n - hlen - (int)sizeof(*icmp) >= (int)sizeof(struct timeval)) {
282+					memcpy(&sent_tv, rxbuf + hlen + sizeof(*icmp), sizeof(sent_tv));
283+					sent_ms = (double)sent_tv.tv_sec * 1000.0 + (double)sent_tv.tv_usec / 1000.0;
284+					rtt -= sent_ms;
285+					if (rtt < min_rtt)
286+						min_rtt = rtt;
287+					if (rtt > max_rtt)
288+						max_rtt = rtt;
289+					sum_rtt += rtt;
290+					if (!qflag) {
291+						printf("%d bytes from %s: icmp_seq=%d ttl=%d time=%.3f ms\n",
292+						       (int)n, inet_ntoa(from.sin_addr), ntohs(icmp->un.echo.sequence),
293+						       is_raw ? ((struct ip *)rxbuf)->ip_ttl : 64, rtt);
294+					}
295+				} else {
296+					if (!qflag) {
297+						printf("%d bytes from %s: icmp_seq=%d ttl=%d\n",
298+						       (int)n, inet_ntoa(from.sin_addr), ntohs(icmp->un.echo.sequence),
299+						       is_raw ? ((struct ip *)rxbuf)->ip_ttl : 64);
300+					}
301+				}
302+			}
303+		}
304+	}
305+
306+	free(rxbuf);
307+	close(sock);
308+
309+	print_stats(host, sent, received, min_rtt, max_rtt, sum_rtt);
310+
311+	return received > 0 ? 0 : 1;
312+}
+309, -0
  1@@ -0,0 +1,309 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/time.h>
  4+#include <sys/types.h>
  5+#include <sys/socket.h>
  6+
  7+#include <netdb.h>
  8+#include <netinet/in.h>
  9+
 10+#include <errno.h>
 11+#include <stdio.h>
 12+#include <stdlib.h>
 13+#include <string.h>
 14+#include <unistd.h>
 15+
 16+#include "util.h"
 17+
 18+#define BLKSIZE 512
 19+#define HDRSIZE 4
 20+#define PKTSIZE (BLKSIZE + HDRSIZE)
 21+
 22+#define TIMEOUT_SEC 5
 23+/* transfer will time out after NRETRIES * TIMEOUT_SEC */
 24+#define NRETRIES 5
 25+
 26+#define RRQ  1
 27+#define WWQ  2
 28+#define DATA 3
 29+#define ACK  4
 30+#define ERR  5
 31+
 32+static char *errtext[] = {
 33+	"Undefined",
 34+	"File not found",
 35+	"Access violation",
 36+	"Disk full or allocation exceeded",
 37+	"Illegal TFTP operation",
 38+	"Unknown transfer ID",
 39+	"File already exists",
 40+	"No such user"
 41+};
 42+
 43+static struct sockaddr_storage to;
 44+static socklen_t tolen;
 45+static int timeout;
 46+static int state;
 47+static int s;
 48+
 49+static int
 50+packreq(unsigned char *buf, int op, char *path, char *mode)
 51+{
 52+	unsigned char *p = buf;
 53+
 54+	*p++ = op >> 8;
 55+	*p++ = op & 0xff;
 56+	if (strlen(path) + 1 > 256)
 57+		eprintf("filename too long\n");
 58+	memcpy(p, path, strlen(path) + 1);
 59+	p += strlen(path) + 1;
 60+	memcpy(p, mode, strlen(mode) + 1);
 61+	p += strlen(mode) + 1;
 62+	return p - buf;
 63+}
 64+
 65+static int
 66+packack(unsigned char *buf, int blkno)
 67+{
 68+	buf[0] = ACK >> 8;
 69+	buf[1] = ACK & 0xff;
 70+	buf[2] = blkno >> 8;
 71+	buf[3] = blkno & 0xff;
 72+	return 4;
 73+}
 74+
 75+static int
 76+packdata(unsigned char *buf, int blkno)
 77+{
 78+	buf[0] = DATA >> 8;
 79+	buf[1] = DATA & 0xff;
 80+	buf[2] = blkno >> 8;
 81+	buf[3] = blkno & 0xff;
 82+	return 4;
 83+}
 84+
 85+static int
 86+unpackop(unsigned char *buf)
 87+{
 88+	return (buf[0] << 8) | (buf[1] & 0xff);
 89+}
 90+
 91+static int
 92+unpackblkno(unsigned char *buf)
 93+{
 94+	return (buf[2] << 8) | (buf[3] & 0xff);
 95+}
 96+
 97+static int
 98+unpackerrc(unsigned char *buf)
 99+{
100+	int errc;
101+
102+	errc = (buf[2] << 8) | (buf[3] & 0xff);
103+	if (errc < 0 || errc >= LEN(errtext))
104+		eprintf("bad error code: %d\n", errc);
105+	return errc;
106+}
107+
108+static int
109+writepkt(unsigned char *buf, int len)
110+{
111+	int n;
112+
113+	n = sendto(s, buf, len, 0, (struct sockaddr *)&to,
114+	           tolen);
115+	if (n < 0)
116+		if (errno != EINTR)
117+			eprintf("sendto:");
118+	return n;
119+}
120+
121+static int
122+readpkt(unsigned char *buf, int len)
123+{
124+	int n;
125+
126+	n = recvfrom(s, buf, len, 0, (struct sockaddr *)&to,
127+	             &tolen);
128+	if (n < 0) {
129+		if (errno != EINTR && errno != EWOULDBLOCK)
130+			eprintf("recvfrom:");
131+		timeout++;
132+		if (timeout == NRETRIES)
133+			eprintf("transfer timed out\n");
134+	} else {
135+		timeout = 0;
136+	}
137+	return n;
138+}
139+
140+static void
141+getfile(char *file)
142+{
143+	unsigned char buf[PKTSIZE];
144+	int n, op, blkno, nextblkno = 1, done = 0;
145+
146+	state = RRQ;
147+	for (;;) {
148+		switch (state) {
149+		case RRQ:
150+			n = packreq(buf, RRQ, file, "octet");
151+			writepkt(buf, n);
152+			n = readpkt(buf, sizeof(buf));
153+			if (n > 0) {
154+				op = unpackop(buf);
155+				if (op != DATA && op != ERR)
156+					eprintf("bad opcode: %d\n", op);
157+				state = op;
158+			}
159+			break;
160+		case DATA:
161+			n -= HDRSIZE;
162+			if (n < 0)
163+				eprintf("truncated packet\n");
164+			blkno = unpackblkno(buf);
165+			if (blkno == nextblkno) {
166+				nextblkno++;
167+				write(1, &buf[HDRSIZE], n);
168+			}
169+			if (n < BLKSIZE)
170+				done = 1;
171+			state = ACK;
172+			break;
173+		case ACK:
174+			n = packack(buf, blkno);
175+			writepkt(buf, n);
176+			if (done)
177+				return;
178+			n = readpkt(buf, sizeof(buf));
179+			if (n > 0) {
180+				op = unpackop(buf);
181+				if (op != DATA && op != ERR)
182+					eprintf("bad opcode: %d\n", op);
183+				state = op;
184+			}
185+			break;
186+		case ERR:
187+			eprintf("error: %s\n", errtext[unpackerrc(buf)]);
188+		}
189+	}
190+}
191+
192+static void
193+putfile(char *file)
194+{
195+	unsigned char inbuf[PKTSIZE], outbuf[PKTSIZE];
196+	int inb, outb, op, blkno, nextblkno = 0, done = 0;
197+
198+	state = WWQ;
199+	for (;;) {
200+		switch (state) {
201+		case WWQ:
202+			outb = packreq(outbuf, WWQ, file, "octet");
203+			writepkt(outbuf, outb);
204+			inb = readpkt(inbuf, sizeof(inbuf));
205+			if (inb > 0) {
206+				op = unpackop(inbuf);
207+				if (op != ACK && op != ERR)
208+					eprintf("bad opcode: %d\n", op);
209+				state = op;
210+			}
211+			break;
212+		case DATA:
213+			if (blkno == nextblkno) {
214+				nextblkno++;
215+				packdata(outbuf, nextblkno);
216+				outb = read(0, &outbuf[HDRSIZE], BLKSIZE);
217+				if (outb < BLKSIZE)
218+					done = 1;
219+			}
220+			writepkt(outbuf, outb + HDRSIZE);
221+			inb = readpkt(inbuf, sizeof(inbuf));
222+			if (inb > 0) {
223+				op = unpackop(inbuf);
224+				if (op != ACK && op != ERR)
225+					eprintf("bad opcode: %d\n", op);
226+				state = op;
227+			}
228+			break;
229+		case ACK:
230+			if (inb < HDRSIZE)
231+				eprintf("truncated packet\n");
232+			blkno = unpackblkno(inbuf);
233+			if (blkno == nextblkno)
234+				if (done)
235+					return;
236+			state = DATA;
237+			break;
238+		case ERR:
239+			eprintf("error: %s\n", errtext[unpackerrc(inbuf)]);
240+		}
241+	}
242+}
243+
244+static void
245+usage(void)
246+{
247+	eprintf("usage: %s -h host [-p port] [-x | -c] file\n", argv0);
248+}
249+
250+int
251+main(int argc, char *argv[])
252+{
253+	struct addrinfo hints, *res, *r;
254+	struct timeval tv;
255+	char *host = NULL, *port = "tftp";
256+	void (*fn)(char *) = getfile;
257+	int ret;
258+
259+	ARGBEGIN {
260+	case 'h':
261+		host = EARGF(usage());
262+		break;
263+	case 'p':
264+		port = EARGF(usage());
265+		break;
266+	case 'x':
267+		fn = getfile;
268+		break;
269+	case 'c':
270+		fn = putfile;
271+		break;
272+	default:
273+		usage();
274+	} ARGEND
275+
276+	if (!host || !argc)
277+		usage();
278+
279+	memset(&hints, 0, sizeof(hints));
280+	hints.ai_family = AF_UNSPEC;
281+	hints.ai_socktype = SOCK_DGRAM;
282+	hints.ai_protocol = IPPROTO_UDP;
283+	ret = getaddrinfo(host, port, &hints, &res);
284+	if (ret)
285+		eprintf("getaddrinfo: %s\n", gai_strerror(ret));
286+
287+	for (r = res; r; r = r->ai_next) {
288+		if (r->ai_family != AF_INET &&
289+		    r->ai_family != AF_INET6)
290+			continue;
291+		s = socket(r->ai_family, r->ai_socktype,
292+		           r->ai_protocol);
293+		if (s < 0)
294+			continue;
295+		break;
296+	}
297+	if (!r)
298+		eprintf("cannot create socket\n");
299+	memcpy(&to, r->ai_addr, r->ai_addrlen);
300+	tolen = r->ai_addrlen;
301+	freeaddrinfo(res);
302+
303+	tv.tv_sec = TIMEOUT_SEC;
304+	tv.tv_usec = 0;
305+	if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
306+		eprintf("setsockopt:");
307+
308+	fn(argv[0]);
309+	return 0;
310+}
+98, -0
 1@@ -0,0 +1,98 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/ioctl.h>
 4+#include <sys/socket.h>
 5+#include <sys/stat.h>
 6+#include <sys/types.h>
 7+
 8+#include <fcntl.h>
 9+#include <limits.h>
10+#include <pwd.h>
11+#include <stdio.h>
12+#include <stdlib.h>
13+#include <string.h>
14+#include <unistd.h>
15+
16+#include <linux/if.h>
17+#include <linux/if_tun.h>
18+
19+#include "util.h"
20+
21+static int dflag;
22+static int tflag = 1;
23+static int Tflag;
24+static char *owner;
25+
26+static void
27+usage(void)
28+{
29+	eprintf("usage: %s [-dtT] [-u owner] [device]\n", argv0);
30+}
31+
32+int
33+main(int argc, char *argv[])
34+{
35+	struct ifreq ifr;
36+	struct passwd *pw;
37+	uid_t owner_uid = 0;
38+	int fd;
39+
40+	ARGBEGIN
41+	{
42+	case 'd':
43+		dflag = 1;
44+		tflag = 0;
45+		break;
46+	case 't':
47+		tflag = 1;
48+		dflag = 0;
49+		break;
50+	case 'T':
51+		Tflag = 1;
52+		break;
53+	case 'u':
54+		owner = EARGF(usage());
55+		break;
56+	default:
57+		usage();
58+	}
59+	ARGEND
60+
61+	if (owner) {
62+		pw = getpwnam(owner);
63+		if (!pw)
64+			owner_uid = estrtonum(owner, 0, UINT_MAX);
65+		else
66+			owner_uid = pw->pw_uid;
67+	}
68+
69+	fd = open("/dev/net/tun", O_RDWR);
70+	if (fd < 0)
71+		eprintf("open /dev/net/tun:");
72+
73+	memset(&ifr, 0, sizeof(ifr));
74+	ifr.ifr_flags = (Tflag ? IFF_TAP : IFF_TUN) | IFF_NO_PI;
75+
76+	if (argc > 0)
77+		estrlcpy(ifr.ifr_name, argv[0], sizeof(ifr.ifr_name));
78+
79+	if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0)
80+		eprintf("ioctl TUNSETIFF:");
81+
82+	if (tflag) {
83+		if (ioctl(fd, TUNSETPERSIST, (void *)1) < 0)
84+			eprintf("ioctl TUNSETPERSIST:");
85+		if (owner) {
86+			if (ioctl(fd, TUNSETOWNER, (void *)(long)owner_uid) < 0)
87+				eprintf("ioctl TUNSETOWNER:");
88+		}
89+		printf("Set '%s' persistent and owned by %u\n", ifr.ifr_name,
90+		       owner_uid);
91+	} else if (dflag) {
92+		if (ioctl(fd, TUNSETPERSIST, (void *)0) < 0)
93+			eprintf("ioctl TUNSETPERSIST:");
94+		printf("Set '%s' non-persistent\n", ifr.ifr_name);
95+	}
96+
97+	close(fd);
98+	return 0;
99+}
+440, -0
  1@@ -0,0 +1,440 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include "util.h"
  4+#include "arg.h"
  5+
  6+#include <arpa/inet.h>
  7+#include <ctype.h>
  8+#include <errno.h>
  9+#include <fcntl.h>
 10+#include <netdb.h>
 11+#include <netinet/in.h>
 12+#include <stdio.h>
 13+#include <stdlib.h>
 14+#include <string.h>
 15+#include <sys/socket.h>
 16+#include <sys/types.h>
 17+#include <unistd.h>
 18+
 19+struct Stream {
 20+	int fd;
 21+	char buf[8192];
 22+	size_t len;
 23+	size_t idx;
 24+};
 25+
 26+static void
 27+usage(void)
 28+{
 29+	eprintf("usage: %s [-O file] [-p post_data] [-r limit] url\n", argv0);
 30+}
 31+
 32+static int
 33+dial(const char *host, const char *port)
 34+{
 35+	struct addrinfo hints, *res, *rp;
 36+	int fd = -1, r;
 37+
 38+	memset(&hints, 0, sizeof(hints));
 39+	hints.ai_family = AF_UNSPEC;
 40+	hints.ai_socktype = SOCK_STREAM;
 41+
 42+	r = getaddrinfo(host, port, &hints, &res);
 43+	if (r != 0) {
 44+		weprintf("getaddrinfo %s:%s: %s\n", host, port, gai_strerror(r));
 45+		return -1;
 46+	}
 47+
 48+	for (rp = res; rp; rp = rp->ai_next) {
 49+		fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
 50+		if (fd < 0)
 51+			continue;
 52+		if (connect(fd, rp->ai_addr, rp->ai_addrlen) == 0)
 53+			break;
 54+		close(fd);
 55+		fd = -1;
 56+	}
 57+
 58+	freeaddrinfo(res);
 59+	return fd;
 60+}
 61+
 62+static void
 63+parse_url(char *url, char **host, char **port, char **path)
 64+{
 65+	char *p, *ss;
 66+
 67+	if (strncasecmp(url, "http://", 7) == 0) {
 68+		url += 7;
 69+	} else if (strncasecmp(url, "https://", 8) == 0) {
 70+		url += 8;
 71+	} else {
 72+		eprintf("unsupported protocol or invalid url: %s\n", url);
 73+	}
 74+
 75+	*host = url;
 76+	p = strchr(url, '/');
 77+	if (p) {
 78+		*p = '\0';
 79+		*path = p + 1;
 80+	} else {
 81+		*path = "";
 82+	}
 83+
 84+	/* handle ipv6 brackets or host:port */
 85+	if (**host == '[') {
 86+		(*host)++;
 87+		ss = strchr(*host, ']');
 88+		if (ss) {
 89+			*ss = '\0';
 90+			ss++;
 91+			if (*ss == ':')
 92+				*port = ss + 1;
 93+			else
 94+				*port = "80";
 95+		} else {
 96+			eprintf("invalid ipv6 literal: %s\n", *host);
 97+		}
 98+	} else {
 99+		p = strrchr(*host, ':');
100+		if (p) {
101+			*p = '\0';
102+			*port = p + 1;
103+		} else {
104+			*port = "80";
105+		}
106+	}
107+}
108+
109+static char *
110+find_header(const char *headers, const char *name)
111+{
112+	const char *p;
113+	size_t len = strlen(name);
114+
115+	p = headers;
116+	while (p && *p) {
117+		if (strncasecmp(p, name, len) == 0) {
118+			p += len;
119+			while (*p == ' ' || *p == '\t')
120+				p++;
121+			len = strcspn(p, "\r\n");
122+			return estrndup(p, len);
123+		}
124+		p = strchr(p, '\n');
125+		if (p)
126+			p++;
127+	}
128+	return NULL;
129+}
130+
131+static int
132+stream_getc(struct Stream *s)
133+{
134+	if (s->idx < s->len) {
135+		return (unsigned char)s->buf[s->idx++];
136+	}
137+	s->idx = 0;
138+	s->len = read(s->fd, s->buf, sizeof(s->buf));
139+	if (s->len <= 0)
140+		return EOF;
141+	return (unsigned char)s->buf[s->idx++];
142+}
143+
144+static size_t
145+stream_read(struct Stream *s, void *ptr, size_t size)
146+{
147+	size_t total = 0;
148+	size_t n;
149+	char *p = ptr;
150+
151+	while (total < size) {
152+		if (s->idx < s->len) {
153+			n = MIN(size - total, s->len - s->idx);
154+			memcpy(p + total, s->buf + s->idx, n);
155+			s->idx += n;
156+			total += n;
157+		} else {
158+			s->idx = 0;
159+			s->len = read(s->fd, s->buf, sizeof(s->buf));
160+			if (s->len <= 0)
161+				break;
162+		}
163+	}
164+	return total;
165+}
166+
167+static void
168+read_chunked(struct Stream *s, int out_fd)
169+{
170+	char line[128];
171+	char chunk_buf[8192];
172+	size_t line_len, n;
173+	long long chunk_size, remaining;
174+	int c;
175+
176+	for (;;) {
177+		line_len = 0;
178+		for (;;) {
179+			c = stream_getc(s);
180+			if (c == EOF)
181+				eprintf("unexpected end of file reading chunk size\n");
182+			if (c == '\n') {
183+				line[line_len] = '\0';
184+				break;
185+			}
186+			if (c != '\r' && line_len < sizeof(line) - 1) {
187+				line[line_len++] = c;
188+			}
189+		}
190+
191+		chunk_size = strtoll(line, NULL, 16);
192+		if (chunk_size == 0) {
193+			stream_getc(s);
194+			stream_getc(s);
195+			break;
196+		}
197+
198+		remaining = chunk_size;
199+		while (remaining > 0) {
200+			n = stream_read(s, chunk_buf, MIN(remaining, (long long)sizeof(chunk_buf)));
201+			if (n == 0)
202+				eprintf("unexpected end of file in chunk data\n");
203+			if (writeall(out_fd, chunk_buf, n) < 0)
204+				eprintf("write output:\n");
205+			remaining -= n;
206+		}
207+
208+		stream_getc(s);
209+		stream_getc(s);
210+	}
211+}
212+
213+static void
214+read_non_chunked(struct Stream *s, int out_fd, long long content_len)
215+{
216+	char chunk_buf[8192];
217+	long long remaining = content_len;
218+	size_t n, to_read;
219+
220+	while (content_len < 0 || remaining > 0) {
221+		to_read = sizeof(chunk_buf);
222+		if (content_len >= 0)
223+			to_read = (size_t)MIN(remaining, (long long)sizeof(chunk_buf));
224+		n = stream_read(s, chunk_buf, to_read);
225+		if (n == 0) {
226+			if (content_len >= 0)
227+				eprintf("unexpected end of file\n");
228+			break;
229+		}
230+		if (writeall(out_fd, chunk_buf, n) < 0)
231+			eprintf("write output:\n");
232+		if (content_len >= 0)
233+			remaining -= n;
234+	}
235+}
236+
237+int
238+main(int argc, char *argv[])
239+{
240+	struct Stream s;
241+	char *Oflag = NULL;
242+	char *pflag = NULL;
243+	char *rflag = NULL;
244+	char *url, *host, *port, *path, *loc;
245+	char *curr_host, *curr_port, *curr_path;
246+	char *new_url;
247+	char *cl_str;
248+	char *te_str;
249+	char *header_end;
250+	char *out_name;
251+	int redirects = 0;
252+	int max_redirects = 20;
253+	int sock = -1;
254+	int out_fd = 1;
255+	int chunked;
256+	int status;
257+	long long content_len;
258+	size_t total_read;
259+	ssize_t n;
260+	size_t dir_len;
261+	char *last_slash;
262+
263+	ARGBEGIN {
264+	case 'O':
265+		Oflag = EARGF(usage());
266+		break;
267+	case 'p':
268+		pflag = EARGF(usage());
269+		break;
270+	case 'r':
271+		rflag = EARGF(usage());
272+		break;
273+	default:
274+		usage();
275+	} ARGEND
276+
277+	if (argc < 1)
278+		usage();
279+
280+	if (rflag)
281+		max_redirects = estrtonum(rflag, 0, 1000);
282+
283+	url = estrdup(argv[0]);
284+
285+	while (sock < 0) {
286+		if (redirects > max_redirects)
287+			eprintf("too many redirects\n");
288+
289+		/* parse url and backup original parts for relative redirect resolves */
290+		curr_host = curr_port = curr_path = NULL;
291+		parse_url(url, &curr_host, &curr_port, &curr_path);
292+
293+		host = estrdup(curr_host);
294+		port = estrdup(curr_port);
295+		path = estrdup(curr_path);
296+
297+		sock = dial(host, port);
298+		if (sock < 0)
299+			eprintf("failed to connect to %s:%s\n", host, port);
300+
301+		if (pflag) {
302+			dprintf(sock, "POST /%s HTTP/1.1\r\n"
303+			              "Host: %s\r\n"
304+			              "User-Agent: wget/aruu\r\n"
305+#ifdef STD_NON_POSIX
306+			              "Accept: */*\r\n"
307+#endif
308+			              "Content-Length: %zu\r\n"
309+			              "Connection: close\r\n\r\n",
310+			              path, host, strlen(pflag));
311+			writeall(sock, pflag, strlen(pflag));
312+		} else {
313+			dprintf(sock, "GET /%s HTTP/1.1\r\n"
314+			              "Host: %s\r\n"
315+			              "User-Agent: wget/aruu\r\n"
316+#ifdef STD_NON_POSIX
317+			              "Accept: */*\r\n"
318+#endif
319+			              "Connection: close\r\n\r\n",
320+			              path, host);
321+		}
322+
323+		/* read headers */
324+		total_read = 0;
325+		header_end = NULL;
326+		memset(s.buf, 0, sizeof(s.buf));
327+		while (total_read < sizeof(s.buf) - 1) {
328+			n = read(sock, s.buf + total_read, sizeof(s.buf) - 1 - total_read);
329+			if (n <= 0) {
330+				if (n < 0)
331+					eprintf("read socket:\n");
332+				else
333+					eprintf("connection closed by server\n");
334+			}
335+			total_read += n;
336+			s.buf[total_read] = '\0';
337+			header_end = strstr(s.buf, "\r\n\r\n");
338+			if (header_end)
339+				break;
340+		}
341+
342+		if (!header_end)
343+			eprintf("http header too large or not found\n");
344+
345+		*header_end = '\0';
346+		s.fd = sock;
347+		s.len = total_read;
348+		s.idx = (header_end + 4) - s.buf;
349+
350+		/* parse HTTP status code */
351+		if (strncasecmp(s.buf, "HTTP/1.1 ", 9) != 0 &&
352+		    strncasecmp(s.buf, "HTTP/1.0 ", 9) != 0) {
353+			eprintf("invalid http response: %s\n", s.buf);
354+		}
355+		status = atoi(s.buf + 9);
356+
357+		if (status >= 300 && status < 400) {
358+			loc = find_header(s.buf, "Location:");
359+			if (!loc)
360+				eprintf("redirect response without location header\n");
361+
362+			if (strncasecmp(loc, "http://", 7) == 0 ||
363+			    strncasecmp(loc, "https://", 8) == 0) {
364+				new_url = estrdup(loc);
365+			} else if (loc[0] == '/') {
366+				new_url = emalloc(8 + strlen(host) + strlen(port) + strlen(loc) + 2);
367+				sprintf(new_url, "http://%s:%s%s", host, port, loc);
368+			} else {
369+				last_slash = strrchr(path, '/');
370+				dir_len = 0;
371+				if (last_slash)
372+					dir_len = last_slash - path + 1;
373+				new_url = emalloc(8 + strlen(host) + strlen(port) + 1 + dir_len + strlen(loc) + 2);
374+				sprintf(new_url, "http://%s:%s/", host, port);
375+				if (dir_len > 0)
376+					strncat(new_url, path, dir_len);
377+				strcat(new_url, loc);
378+			}
379+
380+			free(loc);
381+			free(url);
382+			url = new_url;
383+			close(sock);
384+			sock = -1;
385+			redirects++;
386+		} else if (status != 200) {
387+			eprintf("server returned status: %d\n", status);
388+		}
389+
390+		free(host);
391+		free(port);
392+		free(path);
393+	}
394+
395+	/* parse headers for content length and chunked encoding */
396+	cl_str = find_header(s.buf, "Content-Length:");
397+	content_len = -1;
398+	if (cl_str) {
399+		content_len = strtoll(cl_str, NULL, 10);
400+		free(cl_str);
401+	}
402+
403+	te_str = find_header(s.buf, "Transfer-Encoding:");
404+	chunked = 0;
405+	if (te_str) {
406+		if (strcasecmp(te_str, "chunked") == 0)
407+			chunked = 1;
408+		free(te_str);
409+	}
410+
411+	/* open output file */
412+	out_name = NULL;
413+	if (Oflag) {
414+		out_name = Oflag;
415+	} else {
416+		last_slash = strrchr(url, '/');
417+		if (last_slash && *(last_slash + 1))
418+			out_name = last_slash + 1;
419+		else
420+			out_name = "index.html";
421+	}
422+
423+	if (strcmp(out_name, "-") != 0) {
424+		out_fd = open(out_name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
425+		if (out_fd < 0)
426+			eprintf("open %s:\n", out_name);
427+	}
428+
429+	/* read and write body */
430+	if (chunked)
431+		read_chunked(&s, out_fd);
432+	else
433+		read_non_chunked(&s, out_fd, content_len);
434+
435+	close(sock);
436+	if (out_fd != 1)
437+		close(out_fd);
438+	free(url);
439+
440+	return 0;
441+}
+39, -0
 1@@ -0,0 +1,39 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <libgen.h>
 4+#include <stdio.h>
 5+#include <string.h>
 6+
 7+#include "util.h"
 8+
 9+static void
10+usage(void)
11+{
12+	eprintf("usage: %s path [suffix]\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+	ssize_t off;
19+	size_t slen;
20+	char *p = "";
21+
22+	ARGBEGIN {
23+	default:
24+		usage();
25+	} ARGEND
26+
27+	if (argc != 1 && argc != 2)
28+		usage();
29+
30+	if (argv[0][0])
31+		p = basename(argv[0]);
32+	if (argc == 2 && (slen = strlen(argv[1])) > 0) {
33+		off = strlen(p) - slen;
34+		if (off > 0 && !strcmp(p + off, argv[1]))
35+			p[off] = '\0';
36+	}
37+	puts(p);
38+
39+	return fshut(stdout, "<stdout>");
40+}
+233, -0
  1@@ -0,0 +1,233 @@
  2+/*
  3+ * Copyright (C) Caldera International Inc.  2001-2002.
  4+ * All rights reserved.
  5+ *
  6+ * Redistribution and use in source and binary forms, with or without
  7+ * modification, are permitted provided that the following conditions
  8+ * are met:
  9+ * 1. Redistributions of source code and documentation must retain the above
 10+ *    copyright notice, this list of conditions and the following disclaimer.
 11+ * 2. Redistributions in binary form must reproduce the above copyright
 12+ *    notice, this list of conditions and the following disclaimer in the
 13+ *    documentation and/or other materials provided with the distribution.
 14+ * 3. All advertising materials mentioning features or use of this software
 15+ *    must display the following acknowledgement:
 16+ *      This product includes software developed or owned by Caldera
 17+ *      International, Inc.
 18+ * 4. Neither the name of Caldera International, Inc. nor the names of other
 19+ *    contributors may be used to endorse or promote products derived from
 20+ *    this software without specific prior written permission.
 21+ *
 22+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
 23+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
 24+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 25+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 26+ * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
 27+ * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 28+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 29+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 30+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 31+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 32+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 33+ * POSSIBILITY OF SUCH DAMAGE.
 34+ */
 35+
 36+/*
 37+ *
 38+ *	@(#)bc.library	8.1 (Berkeley) 6/6/93
 39+ */
 40+
 41+scale = 20
 42+define e(x){
 43+	auto a, b, c, d, e, g, t, w, y
 44+
 45+	t = scale
 46+	scale = t + .434*x + 1
 47+
 48+	w = 0
 49+	if(x<0){
 50+		x = -x
 51+		w = 1
 52+	}
 53+	y = 0
 54+	while(x>2){
 55+		x = x/2
 56+		y = y + 1
 57+	}
 58+
 59+	a=1
 60+	b=1
 61+	c=b
 62+	d=1
 63+	e=1
 64+	for(a=1;1==1;a++){
 65+		b=b*x
 66+		c=c*a+b
 67+		d=d*a
 68+		g = c/d
 69+		if(g == e){
 70+			g = g/1
 71+			while(y--){
 72+				g = g*g
 73+			}
 74+			scale = t
 75+			if(w==1) return(1/g)
 76+			return(g/1)
 77+		}
 78+		e=g
 79+	}
 80+}
 81+
 82+define l(x){
 83+	auto a, b, c, d, e, f, g, u, s, t
 84+	if(x <=0) return(1-10^scale)
 85+	t = scale
 86+
 87+	f=1
 88+	scale = scale + scale(x) - length(x) + 1
 89+	s=scale
 90+	while(x > 2){
 91+		s = s + (length(x)-scale(x))/2 + 1
 92+		if(s>0) scale = s
 93+		x = sqrt(x)
 94+		f=f*2
 95+	}
 96+	while(x < .5){
 97+		s = s + (length(x)-scale(x))/2 + 1
 98+		if(s>0) scale = s
 99+		x = sqrt(x)
100+		f=f*2
101+	}
102+
103+	scale = t + length(f) - scale(f) + 1
104+	u = (x-1)/(x+1)
105+
106+	scale = scale + 1.1*length(t) - 1.1*scale(t)
107+	s = u*u
108+	b = 2*f
109+	c = b
110+	d = 1
111+	e = 1
112+	for(a=3;1==1;a=a+2){
113+		b=b*s
114+		c=c*a+d*b
115+		d=d*a
116+		g=c/d
117+		if(g==e){
118+			scale = t
119+			return(u*c/d)
120+		}
121+		e=g
122+	}
123+}
124+
125+define s(x){
126+	auto a, b, c, s, t, y, p, n, i
127+	t = scale
128+	y = x/.7853
129+	s = t + length(y) - scale(y)
130+	if(s<t) s=t
131+	scale = s
132+	p = a(1)
133+
134+	scale = 0
135+	if(x>=0) n = (x/(2*p)+1)/2
136+	if(x<0) n = (x/(2*p)-1)/2
137+	x = x - 4*n*p
138+	if(n%2!=0) x = -x
139+
140+	scale = t + length(1.2*t) - scale(1.2*t)
141+	y = -x*x
142+	a = x
143+	b = 1
144+	s = x
145+	for(i=3; 1==1; i=i+2){
146+		a = a*y
147+		b = b*i*(i-1)
148+		c = a/b
149+		if(c==0){scale=t; return(s/1)}
150+		s = s+c
151+	}
152+}
153+
154+define c(x){
155+	auto t
156+	t = scale
157+	scale = scale+1
158+	x = s(x+2*a(1))
159+	scale = t
160+	return(x/1)
161+}
162+
163+define a(x){
164+	auto a, b, c, d, e, f, g, s, t
165+	if(x==0) return(0)
166+	if(x==1) {
167+		if(scale<52) {
168+			return(.7853981633974483096156608458198757210492923498437764/1)
169+		}
170+	}
171+	t = scale
172+	f=1
173+	while(x > .5){
174+		scale = scale + 1
175+		x= -(1-sqrt(1.+x*x))/x
176+		f=f*2
177+	}
178+	while(x < -.5){
179+		scale = scale + 1
180+		x = -(1-sqrt(1.+x*x))/x
181+		f=f*2
182+	}
183+	s = -x*x
184+	b = f
185+	c = f
186+	d = 1
187+	e = 1
188+	for(a=3;1==1;a=a+2){
189+		b=b*s
190+		c=c*a+d*b
191+		d=d*a
192+		g=c/d
193+		if(g==e){
194+			scale = t
195+			return(x*c/d)
196+		}
197+		e=g
198+	}
199+}
200+
201+define j(n,x){
202+	auto a,b,c,d,e,g,i,s,k,t
203+
204+	t = scale
205+	k = 1.36*x + 1.16*t - n
206+	k = length(k) - scale(k)
207+	if(k>0) scale = scale + k
208+
209+	s= -x*x/4
210+	if(n<0){
211+		n= -n
212+		x= -x
213+	}
214+	a=1
215+	c=1
216+	for(i=1;i<=n;i++){
217+		a=a*x
218+		c = c*2*i
219+	}
220+	b=a
221+	d=1
222+	e=1
223+	for(i=1;1;i++){
224+		a=a*s
225+		b=b*i*(n+i) + a
226+		c=c*i*(n+i)
227+		g=b/c
228+		if(g==e){
229+			scale = t
230+			return(g/1)
231+		}
232+	e=g
233+	}
234+}
+922, -0
  1@@ -0,0 +1,922 @@
  2+%{
  3+#include <libgen.h>
  4+#include <unistd.h>
  5+
  6+#include <assert.h>
  7+#include <ctype.h>
  8+#include <errno.h>
  9+#include <setjmp.h>
 10+#include <stdarg.h>
 11+#include <stdio.h>
 12+#include <stdlib.h>
 13+#include <string.h>
 14+
 15+#include "arg.h"
 16+#include "util.h"
 17+
 18+#define DIGITS   "0123456789ABCDEF"
 19+#define NESTED_MAX 32
 20+
 21+#define funid(f) ((f)[0] - 'a' + 1)
 22+
 23+int yydebug;
 24+
 25+typedef struct macro Macro;
 26+
 27+struct macro {
 28+	int op;
 29+	int id;
 30+	char *name;
 31+	int flowid;
 32+	int nested;
 33+};
 34+
 35+static int yyerror(char *);
 36+static int yylex(void);
 37+
 38+static void quit(void);
 39+static char *code(char *, ...);
 40+static char *forcode(Macro *, char *, char *, char *, char *);
 41+static char *whilecode(Macro *, char *, char *);
 42+static char *ifcode(Macro *, char *, char *);
 43+static char *funcode(Macro *, char *, char *, char *);
 44+static char *param(char *, char *), *local(char *, char *);
 45+static Macro *define(char *, char *);
 46+static char *retcode(char *);
 47+static char *brkcode(void);
 48+static Macro *macro(int);
 49+
 50+static char *ftn(char *);
 51+static char *var(char *);
 52+static char *ary(char *);
 53+static void writeout(char *);
 54+
 55+static char *yytext, *buff, *unwind;
 56+static char *filename;
 57+static FILE *filep;
 58+static int lineno, nerr, flowid;
 59+static jmp_buf recover;
 60+static int nested, inhome;
 61+static Macro macros[NESTED_MAX];
 62+int cflag, dflag, lflag, sflag;
 63+
 64+static char *dcprog = "dc";
 65+
 66+%}
 67+
 68+%union {
 69+	char *str;
 70+	char id[2];
 71+	Macro *macro;
 72+}
 73+
 74+%token <id> ID
 75+%token <str> STRING NUMBER
 76+%token <str> EQOP '+' '-' '*' '/' '%' '^' INCDEC
 77+%token HOME LOOP
 78+%token DOT
 79+%token EQ
 80+%token LE
 81+%token GE
 82+%token NE
 83+%token DEF
 84+%token BREAK
 85+%token QUIT
 86+%token LENGTH
 87+%token RETURN
 88+%token FOR
 89+%token IF
 90+%token WHILE
 91+%token SQRT
 92+%token SCALE
 93+%token IBASE
 94+%token OBASE
 95+%token AUTO PARAM
 96+%token PRINT
 97+
 98+%type <str> item statlst scolonlst
 99+%type <str> function assign nexpr expr exprstat rel stat ary cond
100+%type <str> autolst arglst parlst
101+%type <str> params param locals local
102+%type <macro> def if for while
103+
104+%right	'=' EQOP
105+%left	'+' '-'
106+%left	'*' '/' '%'
107+%right	'^'
108+
109+%start    program
110+
111+%%
112+
113+program  :
114+         | item program
115+         ;
116+
117+item     : scolonlst '\n'       {writeout($1);}
118+         | function             {writeout($1);}
119+         ;
120+
121+function : def parlst '{' '\n' autolst statlst '}' {$$ = funcode($1, $2, $5, $6);}
122+         ;
123+
124+scolonlst:                      {$$ = code("");}
125+         | stat
126+         | scolonlst ';' stat   {$$ = code("%s%s", $1, $3);}
127+         | scolonlst ';'
128+         ;
129+
130+statlst :                       {$$ = code("");}
131+        | stat
132+        | statlst '\n' stat     {$$ = code("%s%s", $1, $3);}
133+        | statlst ';' stat      {$$ = code("%s%s", $1, $3);}
134+        | statlst '\n'
135+        | statlst ';'
136+        ;
137+
138+stat    : exprstat
139+        | PRINT expr            {$$ = code("%sps.", $2);}
140+        | PRINT STRING          {$$ = code("[%s]P", $2);}
141+        | PRINT STRING ',' expr {$$ = code("[%s]P%sps.", $2, $4);}
142+        | STRING                {$$ = code("[%s]P", $1);}
143+        | BREAK                 {$$ = brkcode();}
144+        | QUIT                  {quit();}
145+        | RETURN                {$$ = retcode(code(" 0"));}
146+        | RETURN '(' expr ')'   {$$ = retcode($3);}
147+        | RETURN '(' ')'        {$$ = retcode(code(" 0"));}
148+        | while cond stat       {$$ = whilecode($1, $2, $3);}
149+        | if cond stat          {$$ = ifcode($1, $2, $3);}
150+        | '{' statlst '}'       {$$ = $2;}
151+        | for '(' expr ';' rel ';' expr ')' stat  {$$ = forcode($1, $3, $5, $7, $9);}
152+        ;
153+
154+while   : WHILE                 {$$ = macro(LOOP);}
155+        ;
156+
157+if      : IF                    {$$ = macro(IF);}
158+        ;
159+
160+for     : FOR                   {$$ = macro(LOOP);}
161+        ;
162+
163+def     : DEF ID                {$$ = macro(DEF);}
164+        ;
165+
166+parlst  : '(' ')'               {$$ = code("");}
167+        | '(' params ')'        {$$ = $2;}
168+        ;
169+
170+params  : param                 {$$ = param(NULL, $1);}
171+        | params ',' param      {$$ = param($1, $3);}
172+        ;
173+
174+param   : ID                    {$$ = var($1);}
175+        | ID '[' ']'            {$$ = ary($1);}
176+        ;
177+
178+autolst :                       {$$ = code("");}
179+        | AUTO locals '\n'      {$$ = $2;}
180+        | AUTO locals ';'       {$$ = $2;}
181+        ;
182+
183+locals  : local                 {$$ = local(NULL, $1);}
184+        | locals ',' local      {$$ = local($1, $3);}
185+        ;
186+
187+local   : ID                    {$$ = var($1);}
188+        | ID '[' ']'            {$$ = ary($1);}
189+        ;
190+
191+arglst  : expr
192+        | ID '[' ']'            {$$ = code("%s", ary($1));}
193+        | expr ',' arglst       {$$ = code("%s%s", $1, $3);}
194+        | ID '[' ']' ',' arglst {$$ = code("%s%s", ary($1), $5);}
195+        ;
196+
197+cond    : '(' rel ')'           {$$ = $2;}
198+        ;
199+
200+rel     : expr                  {$$ = code("%s 0!=", $1);}
201+        | expr EQ expr          {$$ = code("%s%s=", $1, $3);}
202+        | expr LE expr          {$$ = code("%s%s!<", $1, $3);}
203+        | expr GE expr          {$$ = code("%s%s!>", $1, $3);}
204+        | expr NE expr          {$$ = code("%s%s!=", $1, $3);}
205+        | expr '<' expr         {$$ = code("%s%s>", $1, $3);}
206+        | expr '>' expr         {$$ = code("%s%s<", $1, $3);}
207+        ;
208+
209+exprstat: nexpr                 {$$ = code("%s%ss.", $1, code(sflag ? "" : "p"));}
210+        | assign                {$$ = code("%ss.", $1);}
211+        ;
212+
213+expr    : nexpr
214+        | assign
215+        ;
216+
217+nexpr   : NUMBER                {$$ = code(" %s", code($1));}
218+        | ID                    {$$ = code("l%s", var($1));}
219+        | DOT                   {$$ = code("l.");}
220+        | SCALE                 {$$ = code("K");}
221+        | IBASE                 {$$ = code("I");}
222+        | OBASE                 {$$ = code("O");}
223+        | ID ary                {$$ = code("%s;%s", $2, ary($1));}
224+        | '(' expr ')'          {$$ = $2;}
225+        | ID '(' arglst ')'     {$$ = code("%sl%sx", $3, ftn($1));}
226+        | ID '(' ')'            {$$ = code("l%sx", ftn($1));}
227+        | '-' expr              {$$ = code("0%s-", $2);}
228+        | expr '+' expr         {$$ = code("%s%s+", $1, $3);}
229+        | expr '-' expr         {$$ = code("%s%s-", $1, $3);}
230+        | expr '*' expr         {$$ = code("%s%s*", $1, $3);}
231+        | expr '/' expr         {$$ = code("%s%s/", $1, $3);}
232+        | expr '%' expr         {$$ = code("%s%s%%", $1, $3);}
233+        | expr '^' expr         {$$ = code("%s%s^", $1, $3);}
234+        | LENGTH '(' expr ')'   {$$ = code("%sZ", $3);}
235+        | SQRT '(' expr ')'     {$$ = code("%sv", $3);}
236+        | SCALE '(' expr ')'    {$$ = code("%sX", $3);}
237+        | INCDEC ID             {$$ = code("l%s1%sds%s", var($2), code($1), var($2));}
238+        | INCDEC SCALE          {$$ = code("K1%sk", code($1));}
239+        | INCDEC IBASE          {$$ = code("I1%sdi", code($1));}
240+        | INCDEC OBASE          {$$ = code("O1%sdo", code($1));}
241+        | INCDEC ID ary         {$$ = code("%sdS_;%s1%sdL_:%s", $3, ary($2), code($1), ary($2));}
242+        | ID INCDEC             {$$ = code("l%sd1%ss%s", var($1), code($2), var($1));}
243+        | SCALE INCDEC          {$$ = code("Kd1%sk", code($2));}
244+        | IBASE INCDEC          {$$ = code("Id1%si", code($2));}
245+        | OBASE INCDEC          {$$ = code("Od1%so", code($2));}
246+        | ID ary INCDEC         {$$ = code("%sds.;%sd1%sl.:%s", $2, ary($1), code($3), ary($1));}
247+        ;
248+
249+assign  : ID '=' expr           {$$ = code("%sds%s", $3, var($1));}
250+        | SCALE '=' expr        {$$ = code("%sdk", $3);}
251+        | IBASE '=' expr        {$$ = code("%sdi", $3);}
252+        | OBASE '=' expr        {$$ = code("%sdo", $3);}
253+        | ID ary '=' expr       {$$ = code("%sd%s:%s", $4, $2, ary($1));}
254+        | ID EQOP expr          {$$ = code("%sl%s%sds%s", $3, var($1), code($2), var($1));}
255+        | SCALE EQOP expr       {$$ = code("%sK%sdk", $3, code($2));}
256+        | IBASE EQOP expr       {$$ = code("%sI%sdi", $3, code($2));}
257+        | OBASE EQOP expr       {$$ = code("%sO%sdo", $3, code($2));}
258+        | ID ary EQOP expr      {$$ = code("%s%sds.;%s%sdl.:s", $4, $2, ary($1), code($3), ary($1));}
259+        ;
260+
261+ary     : '[' expr ']'          {$$ = $2;}
262+        ;
263+
264+%%
265+static int
266+yyerror(char *s)
267+{
268+	fprintf(stderr, "bc: %s:%d: %s\n", filename, lineno, s);
269+	nerr++;
270+	longjmp(recover, 1);
271+}
272+
273+static void
274+writeout(char *s)
275+{
276+	if (write(1, s, strlen(s)) < 0)
277+		goto err;
278+	if (write(1, "\n", 1) < 0)
279+		goto err;
280+	free(s);
281+	return;
282+	
283+err:
284+	eprintf("writing to dc:");
285+}
286+
287+static char *
288+code(char *fmt, ...)
289+{
290+	char *s, *t;
291+	va_list ap;
292+	int c, len, room;
293+
294+	va_start(ap, fmt);
295+	room = BUFSIZ;
296+	for (s = buff; *fmt; s += len) {
297+		len = 1;
298+		if ((c = *fmt++) != '%')
299+			goto append;
300+
301+		switch (*fmt++) {
302+		case 'd':
303+			c = va_arg(ap, int);
304+			len = snprintf(s, room, "%d", c);
305+			if (len < 0 || len >= room)
306+				goto err;
307+			break;
308+		case 'c':
309+			c = va_arg(ap, int);
310+			goto append;
311+		case 's':
312+			t = va_arg(ap, void *);
313+			len = strlen(t);
314+			if (len >= room)
315+				goto err;
316+			memcpy(s, t, len);
317+			free(t);
318+			break;
319+		case '%':
320+		append:
321+			if (room <= 1)
322+				goto err;
323+			*s = c;
324+			break;
325+		default:
326+			abort();
327+		}
328+
329+		room -= len;
330+	}
331+	va_end(ap);
332+
333+	*s = '\0';
334+	return estrdup(buff);
335+
336+err:
337+	eprintf("unable to code requested operation\n");
338+	return NULL;
339+}
340+
341+static Macro *
342+macro(int op)
343+{
344+	int preop;
345+	Macro *d, *p;
346+
347+	if (nested == NESTED_MAX)
348+		yyerror("too much nesting");
349+
350+	d = &macros[nested];
351+	d->op = op;
352+	d->nested = nested++;
353+	d->name = NULL;
354+
355+	switch (op) {
356+	case HOME:
357+		d->id = 0;
358+		d->flowid = flowid;
359+		inhome = 1;
360+		break;
361+	case DEF:
362+		unwind = estrdup("");
363+		inhome = 0;
364+		d->id = funid(yytext);
365+		d->name = estrdup(yytext);
366+		d->flowid = macros[0].flowid;
367+		break;
368+	default:
369+		assert(nested > 1);
370+		preop = d[-1].op;
371+		d->flowid = d[-1].flowid;
372+		if (preop != HOME && preop != DEF) {
373+			if (d->flowid == 255)
374+				eprintf("too many control flow structures");
375+			d->flowid++;
376+		}
377+		d->id = d->flowid;
378+		if (!inhome) {
379+			/* populate reserved id */
380+			flowid = d->flowid;
381+			for (p = d; p != macros; --p)
382+				p[-1].flowid++;
383+		}
384+		break;
385+	}
386+
387+	return d;
388+}
389+
390+static char *
391+decl(int type, char *list, char *id)
392+{
393+	char *i1, *i2;
394+
395+	i1 = estrdup(id);
396+	i2 = estrdup(id);
397+	free(id);
398+
399+	if (!list)
400+		list = estrdup("");
401+
402+	unwind = code("%sL%ss.", unwind, i1);
403+
404+	return code((type == AUTO) ? "0S%s%s" : "S%s%s", i2, list);
405+}
406+
407+static char *
408+param(char *list, char *id)
409+{
410+	return decl(PARAM, list, id);
411+}
412+
413+static char *
414+local(char *list, char *id)
415+{
416+	return decl(AUTO, list, id);
417+}
418+
419+static char *
420+funcode(Macro *d, char *params, char *vars, char *body)
421+{
422+	char *s;
423+
424+	if (strlen(d->name) > 1) {
425+		s = code("[%s%s%s%s]s\"()%s\"",
426+			 vars, params,
427+			 body,
428+			 retcode(code(" 0")),
429+			 d->name);
430+	} else {
431+		s = code(sflag ? "[%s%s%s%s]s<%d>" : "[%s%s%s%s]s%c",
432+			 vars, params,
433+			 body,
434+			 retcode(code(" 0")),
435+			 d->id);
436+		free(d->name);
437+	}
438+
439+	free(unwind);
440+	unwind = NULL;
441+	nested--;
442+	inhome = 0;
443+
444+	return s;
445+}
446+
447+static char *
448+brkcode(void)
449+{
450+	Macro *d;
451+
452+	for (d = &macros[nested-1]; d->op != HOME && d->op != LOOP; --d)
453+		;
454+	if (d->op == HOME)
455+		yyerror("break not in for or while");
456+	return code(" %dQ", nested  - d->nested);
457+}
458+
459+static char *
460+forcode(Macro *d, char *init, char *cmp, char *inc, char *body)
461+{
462+	char *s;
463+
464+	s = code(sflag ? "[%s%ss.%s<%d>]s<%d>" : "[%s%ss.%s%c]s%c",
465+	         body,
466+	         inc,
467+	         estrdup(cmp),
468+	         d->id, d->id);
469+	writeout(s);
470+
471+	s = code(sflag ? "%ss.%s<%d> " : "%ss.%s%c ",
472+	         init,
473+	         cmp,
474+	         d->id);
475+	nested--;
476+
477+	return s;
478+}
479+
480+static char *
481+whilecode(Macro *d, char *cmp, char *body)
482+{
483+	char *s;
484+
485+	s = code(sflag ? "[%s%s<%d>]s<%d>" : "[%s%s%c]s%c",
486+	         body,
487+	         estrdup(cmp),
488+	         d->id, d->id);
489+	writeout(s);
490+
491+	s = code(sflag ? "%s<%d> " : "%s%c ",
492+	         cmp, d->id);
493+	nested--;
494+
495+	return s;
496+}
497+
498+static char *
499+ifcode(Macro *d, char *cmp, char *body)
500+{
501+	char *s;
502+
503+	s = code(sflag ? "[%s]s<%d>" : "[%s]s%c",
504+	         body, d->id);
505+	writeout(s);
506+
507+	s = code(sflag ? "%s<%d> " : "%s%c ",
508+	         cmp, d->id);
509+	nested--;
510+
511+	return s;
512+}
513+
514+static char *
515+retcode(char *expr)
516+{
517+	char *s;
518+
519+	if (nested < 2 || macros[1].op != DEF)
520+		yyerror("return must be in a function");
521+	return code("%s %s %dQ", expr, estrdup(unwind), nested - 1);
522+}
523+
524+static char *
525+ary(char *s)
526+{
527+	if (strlen(s) == 1)
528+		return code("%c", toupper(s[0]));
529+	return code("\"[]%s\"", estrdup(s));
530+}
531+
532+static char *
533+ftn(char *s)
534+{
535+	if (strlen(s) == 1)
536+		return code(sflag ? "<%d>" : "%c", funid(s));
537+	return code("\"()%s\"", estrdup(s));
538+}
539+
540+static char *
541+var(char *s)
542+{
543+	if (strlen(s) == 1)
544+		return code(s);
545+	return code("\"%s\"", estrdup(s));
546+}
547+
548+static void
549+quit(void)
550+{
551+	exit(nerr > 0 ? 1 : 0);
552+}
553+
554+static void
555+skipspaces(void)
556+{
557+	int ch;
558+
559+	while (isascii(ch = getc(filep)) && isspace(ch)) {
560+		if (ch == '\n') {
561+			lineno++;
562+			break;
563+		}
564+	}
565+	ungetc(ch, filep);
566+}
567+
568+static int
569+iden(int ch)
570+{
571+	static struct keyword {
572+		char *str;
573+		int token;
574+	} keywords[] = {
575+		{"define", DEF},
576+		{"break", BREAK},
577+		{"quit", QUIT},
578+		{"length", LENGTH},
579+		{"return", RETURN},
580+		{"for", FOR},
581+		{"if", IF},
582+		{"while", WHILE},
583+		{"sqrt", SQRT},
584+		{"scale", SCALE},
585+		{"ibase", IBASE},
586+		{"obase", OBASE},
587+		{"auto", AUTO},
588+		{"print", PRINT},
589+		{NULL}
590+	};
591+	struct keyword *p;
592+	char *bp;
593+
594+	ungetc(ch, filep);
595+	for (bp = yytext; bp < &yytext[BUFSIZ]; ++bp) {
596+		ch = getc(filep);
597+		if (!isascii(ch) || !islower(ch))
598+			break;
599+		*bp = ch;
600+	}
601+
602+	if (bp == &yytext[BUFSIZ])
603+		yyerror("too long token");
604+	*bp = '\0';
605+	ungetc(ch, filep);
606+
607+	if (strlen(yytext) == 1) {
608+		strcpy(yylval.id, yytext);
609+		return ID;
610+	}
611+
612+	for (p = keywords; p->str && strcmp(p->str, yytext); ++p)
613+		;
614+	if (p->str)
615+		return p->token;
616+
617+	if (!sflag)
618+		yyerror("invalid keyword");
619+	strcpy(yylval.id, yytext);
620+	return ID;
621+}
622+
623+static char *
624+digits(char *bp)
625+{
626+	int ch;
627+	char *digits = DIGITS, *p;
628+
629+	while (bp < &yytext[BUFSIZ]) {
630+		ch = getc(filep);
631+		p = strchr(digits, ch);
632+		if (!p)
633+			break;
634+		*bp++ = ch;
635+	}
636+
637+	if (bp == &yytext[BUFSIZ])
638+		return NULL;
639+	ungetc(ch, filep);
640+
641+	return bp;
642+}
643+
644+static int
645+number(int ch)
646+{
647+	int d;
648+	char *bp;
649+
650+	ungetc(ch, filep);
651+	if ((bp = digits(yytext)) == NULL)
652+		goto toolong;
653+
654+	if ((ch = getc(filep)) != '.') {
655+		ungetc(ch, filep);
656+		goto end;
657+	}
658+	*bp++ = '.';
659+
660+	if ((bp = digits(bp)) == NULL)
661+		goto toolong;
662+
663+end:
664+	if (bp ==  &yytext[BUFSIZ])
665+		goto toolong;
666+	*bp = '\0';
667+	yylval.str = yytext;
668+
669+	return NUMBER;
670+
671+toolong:
672+	yyerror("too long number");
673+	return 0;
674+}
675+
676+static int
677+string(int ch)
678+{
679+	char *bp;
680+
681+	for (bp = yytext; bp < &yytext[BUFSIZ]; ++bp) {
682+		if ((ch = getc(filep)) == '"')
683+			break;
684+		*bp = ch;
685+	}
686+
687+	if (bp == &yytext[BUFSIZ])
688+		yyerror("too long string");
689+	*bp = '\0';
690+	yylval.str = estrdup(yytext);
691+
692+	return STRING;
693+}
694+
695+static int
696+follow(int next, int yes, int no)
697+{
698+	int ch;
699+
700+	ch = getc(filep);
701+	if (ch == next)
702+		return yes;
703+	ungetc(ch, filep);
704+	return no;
705+}
706+
707+static int
708+operand(int ch)
709+{
710+	int peekc;
711+
712+	switch (ch) {
713+	case '\n':
714+	case '{':
715+	case '}':
716+	case '[':
717+	case ']':
718+	case '(':
719+	case ')':
720+	case ',':
721+	case ';':
722+		return ch;
723+	case '.':
724+		peekc = ungetc(getc(filep), filep);
725+		if (strchr(DIGITS, peekc))
726+			return number(ch);
727+		return DOT;
728+	case '"':
729+		return string(ch);
730+	case '*':
731+		yylval.str = "*";
732+		return follow('=', EQOP, '*');
733+	case '/':
734+		yylval.str = "/";
735+		return follow('=', EQOP, '/');
736+	case '%':
737+		yylval.str = "%";
738+		return follow('=', EQOP, '%');
739+	case '=':
740+		return follow('=', EQ, '=');
741+	case '+':
742+	case '-':
743+		yylval.str = (ch == '+') ? "+" : "-";
744+		if (follow('=', EQOP, ch) != ch)
745+			return EQOP;
746+		return follow(ch, INCDEC, ch);
747+	case '^':
748+		yylval.str = "^";
749+		return follow('=', EQOP, '^');
750+	case '<':
751+		return follow('=', LE, '<');
752+	case '>':
753+		return follow('=', GE, '>');
754+	case '!':
755+		if (getc(filep) == '=')
756+			return NE;
757+	default:
758+		yyerror("invalid operand");
759+		return 0;
760+	}
761+}
762+
763+static void
764+comment(void)
765+{
766+	int c;
767+
768+	for (;;) {
769+		while ((c = getc(filep)) != '*') {
770+			if (c == '\n')
771+				lineno++;
772+		}
773+		if ((c = getc(filep)) == '/')
774+			break;
775+		ungetc(c, filep);
776+	}
777+}
778+
779+static int
780+yylex(void)
781+{
782+	int peekc, ch;
783+
784+repeat:
785+	skipspaces();
786+
787+	ch = getc(filep);
788+	if (ch == EOF) {
789+		return EOF;
790+	} else if (!isascii(ch)) {
791+		yyerror("invalid input character");
792+	} else if (islower(ch)) {
793+		return iden(ch);
794+	} else if (strchr(DIGITS, ch)) {
795+		return number(ch);
796+	} else {
797+		if (ch == '/') {
798+			peekc = getc(filep);
799+			if (peekc == '*') {
800+				comment();
801+				goto repeat;
802+			}
803+			ungetc(peekc, filep);
804+		}
805+		return operand(ch);
806+	}
807+
808+	return 0;
809+}
810+
811+static void
812+spawn(void)
813+{
814+	int fds[2];
815+	char *par = sflag ? "-i" : NULL;
816+	char errmsg[] = "bc:error execing dc\n";
817+
818+	if (pipe(fds) < 0)
819+		eprintf("creating pipe:");
820+
821+	switch (fork()) {
822+	case -1:
823+		eprintf("forking dc:");
824+	case 0:
825+		close(1);
826+		dup(fds[1]);
827+		close(fds[0]);
828+		close(fds[1]);
829+		break;
830+	default:
831+		close(0);
832+		dup(fds[0]);
833+		close(fds[0]);
834+		close(fds[1]);
835+		execlp(dcprog, "dc", par, (char *) NULL);
836+
837+		/* it shouldn't happen */
838+		write(3, errmsg, sizeof(errmsg)-1);
839+		_Exit(2);
840+	}
841+}
842+
843+static void
844+run(void)
845+{
846+	if (setjmp(recover)) {
847+		if (ferror(filep))
848+			eprintf("%s:", filename);
849+		if (feof(filep))
850+			return;
851+	}
852+	yyparse();
853+}
854+
855+static void
856+bc(char *fname)
857+{
858+	Macro *d;
859+
860+	lineno = 1;
861+	nested = 0;
862+
863+	macro(HOME);
864+	if (!fname) {
865+		filename = "<stdin>";
866+		filep = stdin;
867+	} else {
868+		filename = fname;
869+		if ((filep = fopen(fname, "r")) == NULL)
870+			eprintf("%s:", fname);
871+	}
872+
873+	run();
874+	fclose(filep);
875+}
876+
877+static void
878+usage(void)
879+{
880+	eprintf("usage: %s [-p dc][-cdls]\n", argv0);
881+}
882+
883+int
884+main(int argc, char *argv[])
885+{
886+	ARGBEGIN {
887+	case 'p':
888+		dcprog = EARGF(usage());
889+		break;
890+	case 'c':
891+		cflag = 1;
892+		break;
893+	case 'd':
894+		dflag = 1;
895+		yydebug = 3;
896+		break;
897+	case 'l':
898+		lflag = 1;
899+		break;
900+	case 's':
901+		sflag = 1;
902+		break;
903+	default:
904+		usage();
905+	} ARGEND
906+
907+	yytext = malloc(BUFSIZ);
908+	buff = malloc(BUFSIZ);
909+	if (!yytext || !buff)
910+		eprintf("out of memory\n");
911+	flowid = 128;
912+
913+	if (!cflag)
914+		spawn();
915+	if (lflag)
916+		bc(PREFIX "/share/misc/bc.library");
917+
918+	while (*argv)
919+		bc(*argv++);
920+	bc(NULL);
921+
922+	quit();
923+}
+226, -0
  1@@ -0,0 +1,226 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <limits.h>
  4+#include <stdint.h>
  5+#include <stdio.h>
  6+#include <stdlib.h>
  7+#include <string.h>
  8+#include <time.h>
  9+#include <unistd.h>
 10+
 11+#include "util.h"
 12+
 13+enum { JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };
 14+enum caltype { JULIAN, GREGORIAN };
 15+enum { TRANS_YEAR = 1752, TRANS_MONTH = SEP, TRANS_DAY = 2 };
 16+
 17+static struct tm *ltime;
 18+
 19+static int
 20+isleap(size_t year, enum caltype cal)
 21+{
 22+	if (cal == GREGORIAN) {
 23+		if (year % 400 == 0)
 24+			return 1;
 25+		if (year % 100 == 0)
 26+			return 0;
 27+		return (year % 4 == 0);
 28+	}
 29+	else { /* cal == Julian */
 30+		return (year % 4 == 0);
 31+	}
 32+}
 33+
 34+static int
 35+monthlength(size_t year, int month, enum caltype cal)
 36+{
 37+	int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
 38+
 39+	return (month == FEB && isleap(year, cal)) ? 29 : mdays[month];
 40+}
 41+
 42+/* From http://www.tondering.dk/claus/cal/chrweek.php#calcdow */
 43+static int
 44+dayofweek(size_t year, int month, int dom, enum caltype cal)
 45+{
 46+	size_t y;
 47+	int m, a;
 48+
 49+	a = (13 - month) / 12;
 50+	y = year - a;
 51+	m = month + 12 * a - 1;
 52+
 53+	if (cal == GREGORIAN)
 54+		return (dom + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12) % 7;
 55+	else  /* cal == Julian */
 56+		return (5 + dom + y + y / 4 + (31 * m) / 12) % 7;
 57+}
 58+
 59+static void
 60+printgrid(size_t year, int month, int fday, int line)
 61+{
 62+	enum caltype cal;
 63+	int offset, dom, d = 0, trans; /* are we in the transition from Julian to Gregorian? */
 64+	int today = 0;
 65+
 66+	cal = (year < TRANS_YEAR || (year == TRANS_YEAR && month <= TRANS_MONTH)) ? JULIAN : GREGORIAN;
 67+	trans = (year == TRANS_YEAR && month == TRANS_MONTH);
 68+	offset = dayofweek(year, month, 1, cal) - fday;
 69+
 70+	if (offset < 0)
 71+		offset += 7;
 72+	if (line == 1) {
 73+		for (; d < offset; ++d)
 74+			printf("   ");
 75+		dom = 1;
 76+	} else {
 77+		dom = 8 - offset + (line - 2) * 7;
 78+		if (trans && !(line == 2 && fday == 3))
 79+			dom += 11;
 80+	}
 81+	if (ltime && year == ltime->tm_year + 1900 && month == ltime->tm_mon)
 82+		today = ltime->tm_mday;
 83+	for (; d < 7 && dom <= monthlength(year, month, cal); ++d, ++dom) {
 84+		if (dom == today)
 85+			printf("\x1b[7m%2d\x1b[0m ", dom); /* highlight today's date */
 86+		else
 87+			printf("%2d ", dom);
 88+		if (trans && dom == TRANS_DAY)
 89+			dom += 11;
 90+	}
 91+	for (; d < 7; ++d)
 92+		printf("   ");
 93+}
 94+
 95+static void
 96+drawcal(size_t year, int month, size_t ncols, size_t nmons, int fday)
 97+{
 98+	char *smon[] = { "January", "February", "March", "April",
 99+	                 "May", "June", "July", "August",
100+	                 "September", "October", "November", "December" };
101+	char *days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", };
102+	size_t m, n, col, cur_year, cur_month, dow;
103+	int line, pad;
104+	char month_year[sizeof("Su Mo Tu We Th Fr Sa")];
105+
106+	for (m = 0; m < nmons; ) {
107+		n = m;
108+		for (col = 0; m < nmons && col < ncols; ++col, ++m) {
109+			cur_year = year + m / 12;
110+			cur_month = month + m % 12;
111+			if (cur_month > 11) {
112+				cur_month -= 12;
113+				cur_year += 1;
114+			}
115+			snprintf(month_year, sizeof(month_year), "%s %zu", smon[cur_month], cur_year);
116+			pad = sizeof(month_year) - 1 - strlen(month_year);
117+			printf("%*s%s%*s   ", pad / 2 + pad % 2, "", month_year, pad / 2, "");
118+		}
119+		putchar('\n');
120+		for (col = 0, m = n; m < nmons && col < ncols; ++col, ++m) {
121+			for (dow = fday; dow < (fday + 7); ++dow)
122+				printf("%s ", days[dow % 7]);
123+			printf("  ");
124+		}
125+		putchar('\n');
126+		for (line = 1; line <= 6; ++line) {
127+			for (col = 0, m = n; m < nmons && col < ncols; ++col, ++m) {
128+				cur_year = year + m / 12;
129+				cur_month = month + m % 12;
130+				if (cur_month > 11) {
131+					cur_month -= 12;
132+					cur_year += 1;
133+				}
134+				printgrid(cur_year, cur_month, fday, line);
135+				printf("  ");
136+			}
137+			putchar('\n');
138+		}
139+	}
140+}
141+
142+static void
143+usage(void)
144+{
145+	eprintf("usage: %s [-1 | -3 | -y | -n num] "
146+	        "[-s | -m | -f num] [-c num] [[month] year]\n", argv0);
147+}
148+
149+int
150+main(int argc, char *argv[])
151+{
152+	time_t now;
153+	size_t year, ncols, nmons;
154+	int fday, month;
155+
156+	now   = time(NULL);
157+	ltime = localtime(&now);
158+	year  = ltime->tm_year + 1900;
159+	month = ltime->tm_mon + 1;
160+	fday  = 0;
161+
162+	if (!isatty(STDOUT_FILENO))
163+		ltime = NULL; /* don't highlight today's date */
164+
165+	ncols = 3;
166+	nmons = 0;
167+
168+	ARGBEGIN {
169+	case '1':
170+		nmons = 1;
171+		break;
172+	case '3':
173+		nmons = 3;
174+		if (--month == 0) {
175+			month = 12;
176+			year--;
177+		}
178+		break;
179+	case 'c':
180+		ncols = estrtonum(EARGF(usage()), 0, MIN(SIZE_MAX, LLONG_MAX));
181+		break;
182+	case 'f':
183+		fday = estrtonum(EARGF(usage()), 0, 6);
184+		break;
185+	case 'm': /* Monday */
186+		fday = 1;
187+		break;
188+	case 'n':
189+		nmons = estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG_MAX));
190+		break;
191+	case 's': /* Sunday */
192+		fday = 0;
193+		break;
194+	case 'y':
195+		month = 1;
196+		nmons = 12;
197+		break;
198+	default:
199+		usage();
200+	} ARGEND
201+
202+	if (nmons == 0) {
203+		if (argc == 1) {
204+			month = 1;
205+			nmons = 12;
206+		} else {
207+			nmons = 1;
208+		}
209+	}
210+
211+	switch (argc) {
212+	case 2:
213+		month = estrtonum(argv[0], 1, 12);
214+		argv++;
215+	case 1: /* fallthrough */
216+		year = estrtonum(argv[0], 0, INT_MAX);
217+		break;
218+	case 0:
219+		break;
220+	default:
221+		usage();
222+	}
223+
224+	drawcal(year, month - 1, ncols, nmons, fday);
225+
226+	return fshut(stdout, "<stdout>");
227+}
+52, -0
 1@@ -0,0 +1,52 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <fcntl.h>
 4+#include <string.h>
 5+#include <unistd.h>
 6+
 7+#include "util.h"
 8+
 9+static void
10+usage(void)
11+{
12+	eprintf("usage: %s [-u] [file ...]\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+	int fd, ret = 0;
19+
20+	ARGBEGIN {
21+	case 'u':
22+		break;
23+	default:
24+		usage();
25+	} ARGEND
26+
27+	if (!argc) {
28+		if (concat(0, "<stdin>", 1, "<stdout>") < 0)
29+			ret = 1;
30+	} else {
31+		for (; *argv; argc--, argv++) {
32+			if (!strcmp(*argv, "-")) {
33+				*argv = "<stdin>";
34+				fd = 0;
35+			} else if ((fd = open(*argv, O_RDONLY)) < 0) {
36+				weprintf("open %s:", *argv);
37+				ret = 1;
38+				continue;
39+			}
40+			switch (concat(fd, *argv, 1, "<stdout>")) {
41+			case -1:
42+				ret = 1;
43+				break;
44+			case -2:
45+				return 1;  /* exit on write error */
46+			}
47+			if (fd != 0)
48+				close(fd);
49+		}
50+	}
51+
52+	return ret;
53+}
+75, -0
 1@@ -0,0 +1,75 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+
 5+#include <errno.h>
 6+#include <fcntl.h>
 7+#include <grp.h>
 8+#include <unistd.h>
 9+
10+#include "fs.h"
11+#include "util.h"
12+
13+static int   hflag = 0;
14+static gid_t gid = -1;
15+static int   ret = 0;
16+
17+static void
18+chgrp(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
19+{
20+	int flags = 0;
21+
22+	if ((r->maxdepth == 0 && r->follow == 'P') || (r->follow == 'H' && r->depth) || (hflag && !(r->depth)))
23+		flags |= AT_SYMLINK_NOFOLLOW;
24+	if (fchownat(dirfd, name, -1, gid, flags) < 0) {
25+		weprintf("chown %s:", r->path);
26+		ret = 1;
27+	} else if (S_ISDIR(st->st_mode)) {
28+		recurse(dirfd, name, NULL, r);
29+	}
30+}
31+
32+static void
33+usage(void)
34+{
35+	eprintf("usage: %s [-h] [-R [-H | -L | -P]] group file ...\n", argv0);
36+}
37+
38+int
39+main(int argc, char *argv[])
40+{
41+	struct group *gr;
42+	struct recursor r = { .fn = chgrp, .maxdepth = 1, .follow = 'P' };
43+
44+	ARGBEGIN {
45+	case 'h':
46+		hflag = 1;
47+		break;
48+	case 'R':
49+		r.maxdepth = 0;
50+		break;
51+	case 'H':
52+	case 'L':
53+	case 'P':
54+		r.follow = ARGC();
55+		break;
56+	default:
57+		usage();
58+	} ARGEND
59+
60+	if (argc < 2)
61+		usage();
62+
63+	errno = 0;
64+	if ((gr = getgrnam(argv[0]))) {
65+		gid = gr->gr_gid;
66+	} else {
67+		if (errno)
68+			eprintf("getgrnam %s:", argv[0]);
69+		gid = estrtonum(argv[0], 0, UINT_MAX);
70+	}
71+
72+	for (argc--, argv++; *argv; argc--, argv++)
73+		recurse(AT_FDCWD, *argv, NULL, &r);
74+
75+	return ret || recurse_status;
76+}
+77, -0
 1@@ -0,0 +1,77 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <fcntl.h>
 4+#include <sys/stat.h>
 5+
 6+#include "fs.h"
 7+#include "util.h"
 8+
 9+static char  *modestr = "";
10+static mode_t mask    = 0;
11+static int    ret     = 0;
12+
13+static void
14+chmodr(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
15+{
16+	mode_t m;
17+
18+	m = parsemode(modestr, st->st_mode, mask);
19+	if (!S_ISLNK(st->st_mode) && fchmodat(dirfd, name, m, 0) < 0) {
20+		weprintf("chmod %s:", r->path);
21+		ret = 1;
22+	} else if (S_ISDIR(st->st_mode)) {
23+		recurse(dirfd, name, NULL, r);
24+	}
25+}
26+
27+static void
28+usage(void)
29+{
30+	eprintf("usage: %s [-R] mode file ...\n", argv0);
31+}
32+
33+int
34+main(int argc, char *argv[])
35+{
36+	struct recursor r = { .fn = chmodr, .maxdepth = 1, .follow = 'H', .flags = DIRFIRST };
37+	size_t i;
38+
39+	argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
40+
41+	for (; *argv && (*argv)[0] == '-'; argc--, argv++) {
42+		if (!(*argv)[1])
43+			usage();
44+		for (i = 1; (*argv)[i]; i++) {
45+			switch ((*argv)[i]) {
46+			case 'R':
47+				r.maxdepth = 0;
48+				break;
49+			case 'r': case 'w': case 'x': case 'X': case 's': case 't':
50+				/* -[rwxXst] are valid modes, so we're done */
51+				if (i == 1)
52+					goto done;
53+				/* fallthrough */
54+			case '-':
55+				/* -- terminator */
56+				if (i == 1 && !(*argv)[i + 1]) {
57+					argv++;
58+					argc--;
59+					goto done;
60+				}
61+				/* fallthrough */
62+			default:
63+				usage();
64+			}
65+		}
66+	}
67+done:
68+	mask = getumask();
69+	modestr = *argv;
70+
71+	if (argc < 2)
72+		usage();
73+
74+	for (--argc, ++argv; *argv; argc--, argv++)
75+		recurse(AT_FDCWD, *argv, NULL, &r);
76+
77+	return ret || recurse_status;
78+}
+104, -0
  1@@ -0,0 +1,104 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <errno.h>
  4+#include <fcntl.h>
  5+#include <grp.h>
  6+#include <limits.h>
  7+#include <pwd.h>
  8+#include <stdlib.h>
  9+#include <string.h>
 10+#include <unistd.h>
 11+
 12+#include "fs.h"
 13+#include "util.h"
 14+
 15+static int   hflag = 0;
 16+static uid_t uid = -1;
 17+static gid_t gid = -1;
 18+static int   ret = 0;
 19+
 20+static void
 21+chownpwgr(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
 22+{
 23+	int flags = 0;
 24+
 25+	if ((r->maxdepth == 0 && r->follow == 'P') || (r->follow == 'H' && r->depth) || (hflag && !(r->depth)))
 26+		flags |= AT_SYMLINK_NOFOLLOW;
 27+
 28+	if (fchownat(dirfd, name, uid, gid, flags) < 0) {
 29+		weprintf("chown %s:", r->path);
 30+		ret = 1;
 31+	} else if (S_ISDIR(st->st_mode)) {
 32+		recurse(dirfd, name, NULL, r);
 33+	}
 34+}
 35+
 36+static void
 37+usage(void)
 38+{
 39+	eprintf("usage: %s [-h] [-R [-H | -L | -P]] owner[:[group]] file ...\n"
 40+	        "       %s [-h] [-R [-H | -L | -P]] :group file ...\n",
 41+	        argv0, argv0);
 42+}
 43+
 44+int
 45+main(int argc, char *argv[])
 46+{
 47+	struct group *gr;
 48+	struct passwd *pw;
 49+	struct recursor r = { .fn = chownpwgr, .maxdepth = 1, .follow = 'P' };
 50+	char *owner, *group;
 51+
 52+	ARGBEGIN {
 53+	case 'h':
 54+		hflag = 1;
 55+		break;
 56+	case 'r':
 57+	case 'R':
 58+		r.maxdepth = 0;
 59+		break;
 60+	case 'H':
 61+	case 'L':
 62+	case 'P':
 63+		r.follow = ARGC();
 64+		break;
 65+	default:
 66+		usage();
 67+	} ARGEND
 68+
 69+	if (argc < 2)
 70+		usage();
 71+
 72+	owner = argv[0];
 73+	if ((group = strchr(owner, ':')))
 74+		*group++ = '\0';
 75+
 76+	if (owner && *owner) {
 77+		errno = 0;
 78+		pw = getpwnam(owner);
 79+		if (pw) {
 80+			uid = pw->pw_uid;
 81+		} else {
 82+			if (errno)
 83+				eprintf("getpwnam %s:", owner);
 84+			uid = estrtonum(owner, 0, UINT_MAX);
 85+		}
 86+	}
 87+	if (group && *group) {
 88+		errno = 0;
 89+		gr = getgrnam(group);
 90+		if (gr) {
 91+			gid = gr->gr_gid;
 92+		} else {
 93+			if (errno)
 94+				eprintf("getgrnam %s:", group);
 95+			gid = estrtonum(group, 0, UINT_MAX);
 96+		}
 97+	}
 98+	if (uid == (uid_t)-1 && gid == (gid_t)-1)
 99+		usage();
100+
101+	for (argc--, argv++; *argv; argc--, argv++)
102+		recurse(AT_FDCWD, *argv, NULL, &r);
103+
104+	return ret || recurse_status;
105+}
+132, -0
  1@@ -0,0 +1,132 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <fcntl.h>
  4+#include <inttypes.h>
  5+#include <stdio.h>
  6+#include <string.h>
  7+#include <unistd.h>
  8+
  9+#include "util.h"
 10+
 11+static int ret = 0;
 12+static const unsigned long crctab[] = {         0x00000000,
 13+0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
 14+0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
 15+0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
 16+0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
 17+0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
 18+0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
 19+0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
 20+0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
 21+0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
 22+0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
 23+0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
 24+0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
 25+0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
 26+0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
 27+0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
 28+0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
 29+0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
 30+0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
 31+0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
 32+0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
 33+0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
 34+0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
 35+0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
 36+0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
 37+0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
 38+0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
 39+0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
 40+0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
 41+0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
 42+0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
 43+0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
 44+0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
 45+0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
 46+0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
 47+0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
 48+0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
 49+0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
 50+0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
 51+0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
 52+0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
 53+0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
 54+0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
 55+0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
 56+0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
 57+0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
 58+0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
 59+0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
 60+0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
 61+0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
 62+0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
 63+0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
 64+};
 65+
 66+static void
 67+cksum(int fd, const char *s)
 68+{
 69+	ssize_t n;
 70+	size_t len = 0, i;
 71+	uint32_t ck = 0;
 72+	unsigned char buf[BUFSIZ];
 73+
 74+	while ((n = read(fd, buf, sizeof(buf))) > 0) {
 75+		for (i = 0; i < n; i++)
 76+			ck = (ck << 8) ^ crctab[(ck >> 24) ^ buf[i]];
 77+		len += n;
 78+	}
 79+	if (n < 0) {
 80+		weprintf("read %s:", s ? s : "<stdin>");
 81+		ret = 1;
 82+		return;
 83+	}
 84+
 85+	for (i = len; i; i >>= 8)
 86+		ck = (ck << 8) ^ crctab[(ck >> 24) ^ (i & 0xFF)];
 87+
 88+	printf("%"PRIu32" %zu", ~ck, len);
 89+	if (s) {
 90+		putchar(' ');
 91+		fputs(s, stdout);
 92+	}
 93+	putchar('\n');
 94+}
 95+
 96+static void
 97+usage(void)
 98+{
 99+	eprintf("usage: %s [file ...]\n", argv0);
100+}
101+
102+int
103+main(int argc, char *argv[])
104+{
105+	int fd;
106+
107+	ARGBEGIN {
108+	default:
109+		usage();
110+	} ARGEND
111+
112+	if (!argc) {
113+		cksum(0, NULL);
114+	} else {
115+		for (; *argv; argc--, argv++) {
116+			if (!strcmp(*argv, "-")) {
117+				*argv = "<stdin>";
118+				fd = 0;
119+			} else if ((fd = open(*argv, O_RDONLY)) < 0) {
120+				weprintf("open %s:", *argv);
121+				ret = 1;
122+				continue;
123+			}
124+			cksum(fd, *argv);
125+			if (fd != 0)
126+				close(fd);
127+		}
128+	}
129+
130+	ret |= fshut(stdout, "<stdout>");
131+
132+	return ret;
133+}
+82, -0
 1@@ -0,0 +1,82 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <stdlib.h>
 5+#include <string.h>
 6+
 7+#include "util.h"
 8+
 9+static void
10+usage(void)
11+{
12+	enprintf(2, "usage: %s [-l | -s] file1 file2\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+	FILE *fp[2];
19+	size_t line = 1, n;
20+	int ret = 0, lflag = 0, sflag = 0, same = 1, b[2];
21+
22+	ARGBEGIN {
23+	case 'l':
24+		lflag = 1;
25+		break;
26+	case 's':
27+		sflag = 1;
28+		break;
29+	default:
30+		usage();
31+	} ARGEND
32+
33+	if (argc != 2 || (lflag && sflag))
34+		usage();
35+
36+	for (n = 0; n < 2; n++) {
37+		if (!strcmp(argv[n], "-")) {
38+			argv[n] = "<stdin>";
39+			fp[n] = stdin;
40+		} else {
41+			if (!(fp[n] = fopen(argv[n], "r"))) {
42+				if (!sflag)
43+					weprintf("fopen %s:", argv[n]);
44+				return 2;
45+			}
46+		}
47+	}
48+
49+	for (n = 1; ; n++) {
50+		b[0] = getc(fp[0]);
51+		b[1] = getc(fp[1]);
52+
53+		if (b[0] == b[1]) {
54+			if (b[0] == EOF)
55+				break;
56+			else if (b[0] == '\n')
57+				line++;
58+			continue;
59+		} else if (b[0] == EOF || b[1] == EOF) {
60+			if (!sflag)
61+				weprintf("EOF on %s\n", argv[(b[0] != EOF)]);
62+			same = 0;
63+			break;
64+		} else if (!lflag) {
65+			if (!sflag)
66+				printf("%s %s differ: byte %zu, line %zu\n",
67+				       argv[0], argv[1], n, line);
68+			same = 0;
69+			break;
70+		} else {
71+			printf("%zu %o %o\n", n, b[0], b[1]);
72+			same = 0;
73+		}
74+	}
75+
76+	if (!ret)
77+		ret = !same;
78+	if (fshut(fp[0], argv[0]) | (fp[0] != fp[1] && fshut(fp[1], argv[1])) |
79+	    fshut(stdout, "<stdout>"))
80+		ret = 2;
81+
82+	return ret;
83+}
+97, -0
 1@@ -0,0 +1,97 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <stdlib.h>
 5+#include <string.h>
 6+
 7+#include "text.h"
 8+#include "util.h"
 9+
10+static int show = 0x07;
11+
12+static void
13+printline(int pos, struct line *line)
14+{
15+	int i;
16+
17+	if (!(show & (0x1 << pos)))
18+		return;
19+
20+	for (i = 0; i < pos; i++) {
21+		if (show & (0x1 << i))
22+			putchar('\t');
23+	}
24+	fwrite(line->data, 1, line->len, stdout);
25+}
26+
27+static void
28+usage(void)
29+{
30+	eprintf("usage: %s [-123] file1 file2\n", argv0);
31+}
32+
33+int
34+main(int argc, char *argv[])
35+{
36+	FILE *fp[2];
37+	static struct line line[2];
38+	size_t linecap[2] = { 0, 0 };
39+	ssize_t len;
40+	int ret = 0, i, diff = 0, seenline = 0;
41+
42+	ARGBEGIN {
43+	case '1':
44+	case '2':
45+	case '3':
46+		show &= 0x07 ^ (1 << (ARGC() - '1'));
47+		break;
48+	default:
49+		usage();
50+	} ARGEND
51+
52+	if (argc != 2)
53+		usage();
54+
55+	for (i = 0; i < 2; i++) {
56+		if (!strcmp(argv[i], "-")) {
57+			argv[i] = "<stdin>";
58+			fp[i] = stdin;
59+		} else if (!(fp[i] = fopen(argv[i], "r"))) {
60+			eprintf("fopen %s:", argv[i]);
61+		}
62+	}
63+
64+	for (;;) {
65+		for (i = 0; i < 2; i++) {
66+			if (diff && i == (diff < 0))
67+				continue;
68+			if ((len = getline(&(line[i].data), &linecap[i],
69+			                   fp[i])) > 0) {
70+				line[i].len = len;
71+				seenline = 1;
72+				continue;
73+			}
74+			if (ferror(fp[i]))
75+				eprintf("getline %s:", argv[i]);
76+			if ((diff || seenline) && line[!i].data[0])
77+				printline(!i, &line[!i]);
78+			while ((len = getline(&(line[!i].data), &linecap[!i],
79+			                      fp[!i])) > 0) {
80+				line[!i].len = len;
81+				printline(!i, &line[!i]);
82+			}
83+			if (ferror(fp[!i]))
84+				eprintf("getline %s:", argv[!i]);
85+			goto end;
86+		}
87+		diff = linecmp(&line[0], &line[1]);
88+		LIMIT(diff, -1, 1);
89+		seenline = 0;
90+		printline((2 - diff) % 3, &line[MAX(0, diff)]);
91+	}
92+end:
93+	ret |= fshut(fp[0], argv[0]);
94+	ret |= (fp[0] != fp[1]) && fshut(fp[1], argv[1]);
95+	ret |= fshut(stdout, "<stdout>");
96+
97+	return ret;
98+}
+63, -0
 1@@ -0,0 +1,63 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+
 5+#include "fs.h"
 6+#include "util.h"
 7+
 8+static void
 9+usage(void)
10+{
11+	eprintf("usage: %s [-afipv] [-R [-H | -L | -P]] source ... dest\n", argv0);
12+}
13+
14+int
15+main(int argc, char *argv[])
16+{
17+	struct stat st;
18+
19+	ARGBEGIN {
20+	case 'i':
21+		cp_iflag = 1;
22+		break;
23+	case 'a':
24+		cp_follow = 'P';
25+		cp_aflag = cp_pflag = cp_rflag = 1;
26+		break;
27+	case 'f':
28+		cp_fflag = 1;
29+		break;
30+	case 'p':
31+		cp_pflag = 1;
32+		break;
33+	case 'r':
34+	case 'R':
35+		cp_rflag = 1;
36+		break;
37+	case 'v':
38+		cp_vflag = 1;
39+		break;
40+	case 'H':
41+	case 'L':
42+	case 'P':
43+		cp_follow = ARGC();
44+		break;
45+	default:
46+		usage();
47+	} ARGEND
48+
49+	if (argc < 2)
50+		usage();
51+
52+	if (!cp_follow)
53+		cp_follow = cp_rflag ? 'P' : 'L';
54+
55+	if (argc > 2) {
56+		if (stat(argv[argc - 1], &st) < 0)
57+			eprintf("stat %s:", argv[argc - 1]);
58+		if (!S_ISDIR(st.st_mode))
59+			eprintf("%s: not a directory\n", argv[argc - 1]);
60+	}
61+	enmasse(argc, argv, cp);
62+
63+	return fshut(stdout, "<stdout>") || cp_status;
64+}
+215, -0
  1@@ -0,0 +1,215 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <stdio.h>
  4+#include <stdlib.h>
  5+#include <string.h>
  6+
  7+#include "text.h"
  8+#include "utf.h"
  9+#include "util.h"
 10+
 11+typedef struct Range {
 12+	size_t min, max;
 13+	struct Range *next;
 14+} Range;
 15+
 16+static Range *list     = NULL;
 17+static char   mode     = 0;
 18+static char  *delim    = "\t";
 19+static size_t delimlen = 1;
 20+static int    nflag    = 0;
 21+static int    sflag    = 0;
 22+
 23+static void
 24+insert(Range *r)
 25+{
 26+	Range *l, *p, *t;
 27+
 28+	for (p = NULL, l = list; l; p = l, l = l->next) {
 29+		if (r->max && r->max + 1 < l->min) {
 30+			r->next = l;
 31+			break;
 32+		} else if (!l->max || r->min < l->max + 2) {
 33+			l->min = MIN(r->min, l->min);
 34+			for (p = l, t = l->next; t; p = t, t = t->next)
 35+				if (r->max && r->max + 1 < t->min)
 36+					break;
 37+			l->max = (p->max && r->max) ? MAX(p->max, r->max) : 0;
 38+			l->next = t;
 39+			return;
 40+		}
 41+	}
 42+	if (p)
 43+		p->next = r;
 44+	else
 45+		list = r;
 46+}
 47+
 48+static void
 49+parselist(char *str)
 50+{
 51+	char *s;
 52+	size_t n = 1;
 53+	Range *r;
 54+
 55+	if (!*str)
 56+		eprintf("empty list\n");
 57+	for (s = str; *s; s++) {
 58+		if (*s == ' ')
 59+			*s = ',';
 60+		if (*s == ',')
 61+			n++;
 62+	}
 63+	r = ereallocarray(NULL, n, sizeof(*r));
 64+	for (s = str; n; n--, s++) {
 65+		r->min = (*s == '-') ? 1 : strtoul(s, &s, 10);
 66+		r->max = (*s == '-') ? strtoul(s + 1, &s, 10) : r->min;
 67+		r->next = NULL;
 68+		if (!r->min || (r->max && r->max < r->min) || (*s && *s != ','))
 69+			eprintf("bad list value\n");
 70+		insert(r++);
 71+	}
 72+}
 73+
 74+static size_t
 75+seek(struct line *s, size_t pos, size_t *prev, size_t count)
 76+{
 77+	size_t n = pos - *prev, i, j;
 78+
 79+	if (mode == 'b') {
 80+		if (n >= s->len)
 81+			return s->len;
 82+		if (nflag)
 83+			while (n && !UTF8_POINT(s->data[n]))
 84+				n--;
 85+		*prev += n;
 86+		return n;
 87+	} else if (mode == 'c') {
 88+		for (n++, i = 0; i < s->len; i++)
 89+			if (UTF8_POINT(s->data[i]) && !--n)
 90+				break;
 91+	} else {
 92+		for (i = (count < delimlen + 1) ? 0 : delimlen; n && i < s->len; ) {
 93+			if ((s->len - i) >= delimlen &&
 94+			    !memcmp(s->data + i, delim, delimlen)) {
 95+				if (!--n && count)
 96+					break;
 97+				i += delimlen;
 98+				continue;
 99+			}
100+			for (j = 1; j + i <= s->len && !fullrune(s->data + i, j); j++);
101+			i += j;
102+		}
103+	}
104+	*prev = pos;
105+
106+	return i;
107+}
108+
109+static void
110+cut(FILE *fp, const char *fname)
111+{
112+	Range *r;
113+	struct line s;
114+	static struct line line;
115+	static size_t size;
116+	size_t i, n, p;
117+	ssize_t len;
118+
119+	while ((len = getline(&line.data, &size, fp)) > 0) {
120+		line.len = len;
121+		if (line.data[line.len - 1] == '\n')
122+			line.data[--line.len] = '\0';
123+		if (mode == 'f' && !memmem(line.data, line.len, delim, delimlen)) {
124+			if (!sflag) {
125+				fwrite(line.data, 1, line.len, stdout);
126+				fputc('\n', stdout);
127+			}
128+			continue;
129+		}
130+		for (i = 0, p = 1, s = line, r = list; r; r = r->next) {
131+			n = seek(&s, r->min, &p, i);
132+			s.data += n;
133+			s.len -= n;
134+			i += (mode == 'f') ? delimlen : 1;
135+			if (!s.len)
136+				break;
137+			if (!r->max) {
138+				fwrite(s.data, 1, s.len, stdout);
139+				break;
140+			}
141+			n = seek(&s, r->max + 1, &p, i);
142+			i += (mode == 'f') ? delimlen : 1;
143+			if (fwrite(s.data, 1, n, stdout) != n)
144+				eprintf("fwrite <stdout>:");
145+			s.data += n;
146+			s.len -= n;
147+		}
148+		putchar('\n');
149+	}
150+	if (ferror(fp))
151+		eprintf("getline %s:", fname);
152+}
153+
154+static void
155+usage(void)
156+{
157+	eprintf("usage: %s -b list [-n] [file ...]\n"
158+	        "       %s -c list [file ...]\n"
159+	        "       %s -f list [-d delim] [-s] [file ...]\n",
160+		argv0, argv0, argv0);
161+}
162+
163+int
164+main(int argc, char *argv[])
165+{
166+	FILE *fp;
167+	int ret = 0;
168+
169+	ARGBEGIN {
170+	case 'b':
171+	case 'c':
172+	case 'f':
173+		mode = ARGC();
174+		parselist(EARGF(usage()));
175+		break;
176+	case 'd':
177+		delim = EARGF(usage());
178+		if (!*delim)
179+			eprintf("empty delimiter\n");
180+		delimlen = unescape(delim);
181+		break;
182+	case 'n':
183+		nflag = 1;
184+		break;
185+	case 's':
186+		sflag = 1;
187+		break;
188+	default:
189+		usage();
190+	} ARGEND
191+
192+	if (!mode)
193+		usage();
194+
195+	if (!argc)
196+		cut(stdin, "<stdin>");
197+	else {
198+		for (; *argv; argc--, argv++) {
199+			if (!strcmp(*argv, "-")) {
200+				*argv = "<stdin>";
201+				fp = stdin;
202+			} else if (!(fp = fopen(*argv, "r"))) {
203+				weprintf("fopen %s:", *argv);
204+				ret = 1;
205+				continue;
206+			}
207+			cut(fp, *argv);
208+			if (fp != stdin && fshut(fp, *argv))
209+				ret = 1;
210+		}
211+	}
212+
213+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
214+
215+	return ret;
216+}
+103, -0
  1@@ -0,0 +1,103 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <ctype.h>
  4+#include <stdio.h>
  5+#include <stdlib.h>
  6+#include <string.h>
  7+#include <time.h>
  8+
  9+#include "util.h"
 10+
 11+static void
 12+usage(void)
 13+{
 14+	eprintf("usage: %s [-u] [-d time] [+format | mmddHHMM[[CC]yy]]\n", argv0);
 15+}
 16+
 17+static int
 18+datefield(const char *s, size_t i)
 19+{
 20+	if (!isdigit(s[i]) || !isdigit(s[i+1]))
 21+		eprintf("invalid date format: %s\n", s);
 22+
 23+	return (s[i] - '0') * 10 + (s[i+1] - '0');
 24+}
 25+
 26+static void
 27+setdate(const char *s, struct tm *now)
 28+{
 29+	struct tm date;
 30+	struct timespec ts;
 31+
 32+	switch (strlen(s)) {
 33+	case 8:
 34+		date.tm_year = now->tm_year;
 35+		break;
 36+	case 10:
 37+		date.tm_year = datefield(s, 8);
 38+		if (date.tm_year < 69)
 39+			date.tm_year += 100;
 40+		break;
 41+	case 12:
 42+		date.tm_year = ((datefield(s, 8) - 19) * 100) + datefield(s, 10);
 43+		break;
 44+	default:
 45+		eprintf("invalid date format: %s\n", s);
 46+		break;
 47+	}
 48+
 49+	date.tm_mon = datefield(s, 0) - 1;
 50+	date.tm_mday = datefield(s, 2);
 51+	date.tm_hour = datefield(s, 4);
 52+	date.tm_min = datefield(s, 6);
 53+	date.tm_sec = 0;
 54+	date.tm_isdst = -1;
 55+
 56+	ts.tv_sec = mktime(&date);
 57+	if (ts.tv_sec == -1)
 58+		eprintf("mktime:");
 59+	ts.tv_nsec = 0;
 60+
 61+	if (clock_settime(CLOCK_REALTIME, &ts) == -1)
 62+		eprintf("clock_settime:");
 63+}
 64+
 65+int
 66+main(int argc, char *argv[])
 67+{
 68+	struct tm *now;
 69+	time_t t;
 70+	char buf[BUFSIZ], *fmt = "%a %b %e %H:%M:%S %Z %Y";
 71+
 72+	t = time(NULL);
 73+	if (t == -1)
 74+		eprintf("time:");
 75+
 76+	ARGBEGIN {
 77+	case 'd':
 78+		t = estrtonum(EARGF(usage()), 0, LLONG_MAX);
 79+		break;
 80+	case 'u':
 81+		if (setenv("TZ", "UTC0", 1) < 0)
 82+			eprintf("setenv:");
 83+		break;
 84+	default:
 85+		usage();
 86+	} ARGEND
 87+
 88+	if (!(now = localtime(&t)))
 89+		eprintf("localtime:");
 90+	if (argc) {
 91+		if (argc != 1)
 92+			usage();
 93+		if (argv[0][0] != '+') {
 94+			setdate(argv[0], now);
 95+			return 0;
 96+		}
 97+		fmt = &argv[0][1];
 98+	}
 99+
100+	strftime(buf, sizeof(buf), fmt, now);
101+	puts(buf);
102+
103+	return fshut(stdout, "<stdout>");
104+}
+237, -0
  1@@ -0,0 +1,237 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <ctype.h>
  4+#include <fcntl.h>
  5+#include <inttypes.h>
  6+#include <stdint.h>
  7+#include <string.h>
  8+#include <unistd.h>
  9+
 10+#include "util.h"
 11+
 12+static off_t ifull, ofull, ipart, opart;
 13+
 14+static void
 15+usage(void)
 16+{
 17+	eprintf("usage: %s [operand...]\n", argv0);
 18+}
 19+
 20+static size_t
 21+parsesize(char *expr)
 22+{
 23+	char *s = expr;
 24+	size_t n = 1;
 25+
 26+	for (;;) {
 27+		n *= strtoumax(s, &s, 10);
 28+		switch (*s) {
 29+		case 'k': n <<= 10; s++; break;
 30+		case 'b': n <<= 9; s++; break;
 31+		}
 32+		if (*s != 'x' || !s[1])
 33+			break;
 34+		s++;
 35+	}
 36+	if (*s || n == 0)
 37+		eprintf("invalid block size expression '%s'\n", expr);
 38+
 39+	return n;
 40+}
 41+
 42+static void
 43+bswap(unsigned char *buf, size_t len)
 44+{
 45+	int c;
 46+
 47+	for (len &= ~1; len > 0; buf += 2, len -= 2) {
 48+		c = buf[0];
 49+		buf[0] = buf[1];
 50+		buf[1] = c;
 51+	}
 52+}
 53+
 54+static void
 55+lcase(unsigned char *buf, size_t len)
 56+{
 57+	for (; len > 0; buf++, len--)
 58+		buf[0] = tolower(buf[0]);
 59+}
 60+
 61+static void
 62+ucase(unsigned char *buf, size_t len)
 63+{
 64+	for (; len > 0; buf++, len--)
 65+		buf[0] = toupper(buf[0]);
 66+}
 67+
 68+static void
 69+summary(void)
 70+{
 71+	fprintf(stderr, "%"PRIdMAX"+%"PRIdMAX" records in\n", (intmax_t)ifull, (intmax_t)ipart);
 72+	fprintf(stderr, "%"PRIdMAX"+%"PRIdMAX" records out\n", (intmax_t)ofull, (intmax_t)opart);
 73+}
 74+
 75+int
 76+main(int argc, char *argv[])
 77+{
 78+	enum {
 79+		LCASE   = 1 << 0,
 80+		UCASE   = 1 << 1,
 81+		SWAB    = 1 << 2,
 82+		NOERROR = 1 << 3,
 83+		NOTRUNC = 1 << 4,
 84+		SYNC    = 1 << 5,
 85+	} conv = 0;
 86+	char *arg, *val, *end;
 87+	const char *iname = "-", *oname = "-";
 88+	int ifd = 0, ofd = 1, eof = 0;
 89+	size_t len, bs = 0, ibs = 512, obs = 512, ipos = 0, opos = 0;
 90+	off_t skip = 0, seek = 0, count = -1;
 91+	ssize_t ret;
 92+	unsigned char *buf;
 93+
 94+	argv0 = argc ? (argc--, *argv++) : "dd";
 95+	for (; argc > 0; argc--, argv++) {
 96+		arg = *argv;
 97+		val = strchr(arg, '=');
 98+		if (!val)
 99+			usage();
100+		*val++ = '\0';
101+		if (strcmp(arg, "if") == 0) {
102+			iname = val;
103+		} else if (strcmp(arg, "of") == 0) {
104+			oname = val;
105+		} else if (strcmp(arg, "ibs") == 0) {
106+			ibs = parsesize(val);
107+		} else if (strcmp(arg, "obs") == 0) {
108+			obs = parsesize(val);
109+		} else if (strcmp(arg, "bs") == 0) {
110+			bs = parsesize(val);
111+		} else if (strcmp(arg, "skip") == 0) {
112+			skip = estrtonum(val, 0, LLONG_MAX);
113+		} else if (strcmp(arg, "seek") == 0) {
114+			seek = estrtonum(val, 0, LLONG_MAX);
115+		} else if (strcmp(arg, "count") == 0) {
116+			count = estrtonum(val, 0, LLONG_MAX);
117+		} else if (strcmp(arg, "conv") == 0) {
118+			do {
119+				end = strchr(val, ',');
120+				if (end)
121+					*end++ = '\0';
122+				if (strcmp(val, "lcase") == 0)
123+					conv |= LCASE;
124+				else if (strcmp(val, "ucase") == 0)
125+					conv |= UCASE;
126+				else if (strcmp(val, "swab") == 0)
127+					conv |= SWAB;
128+				else if (strcmp(val, "noerror") == 0)
129+					conv |= NOERROR;
130+				else if (strcmp(val, "notrunc") == 0)
131+					conv |= NOTRUNC;
132+				else if (strcmp(val, "sync") == 0)
133+					conv |= SYNC;
134+				else
135+					eprintf("unknown conv flag '%s'\n", val);
136+				val = end;
137+			} while (val);
138+		} else {
139+			weprintf("unknown operand '%s'\n", arg);
140+			usage();
141+		}
142+	}
143+
144+	if (bs)
145+		ibs = obs = bs;
146+	if (strcmp(iname, "-") != 0) {
147+		ifd = open(iname, O_RDONLY);
148+		if (ifd < 0)
149+			eprintf("open %s:", iname);
150+	}
151+	if (strcmp(oname, "-") != 0) {
152+		ofd = open(oname, O_WRONLY | O_CREAT | (conv & NOTRUNC || seek ? 0 : O_TRUNC), 0666);
153+		if (ofd < 0)
154+			eprintf("open %s:", oname);
155+	}
156+
157+	len = MAX(ibs, obs) + ibs;
158+	buf = emalloc(len);
159+	if (skip && lseek(ifd, skip * ibs, SEEK_SET) < 0) {
160+		while (skip--) {
161+			ret = read(ifd, buf, ibs);
162+			if (ret < 0)
163+				eprintf("read:");
164+			if (ret == 0) {
165+				eof = 1;
166+				break;
167+			}
168+		}
169+	}
170+	if (seek) {
171+		if (!(conv & NOTRUNC) && ftruncate(ofd, seek * ibs) != 0)
172+			eprintf("ftruncate:");
173+		if (lseek(ofd, seek * ibs, SEEK_SET) < 0)
174+			eprintf("lseek:");
175+		/* XXX: handle non-seekable files */
176+	}
177+	while (!eof) {
178+		while (ipos - opos < obs) {
179+			if (ifull + ipart == count) {
180+				eof = 1;
181+				break;
182+			}
183+			ret = read(ifd, buf + ipos, ibs);
184+			if (ret == 0) {
185+				eof = 1;
186+				break;
187+			}
188+			if (ret < 0) {
189+				weprintf("read:");
190+				if (!(conv & NOERROR))
191+					return 1;
192+				summary();
193+				if (!(conv & SYNC))
194+					continue;
195+				ret = 0;
196+			}
197+			if (ret < ibs) {
198+				ipart++;
199+				if (conv & SYNC) {
200+					memset(buf + ipos + ret, 0, ibs - ret);
201+					ret = ibs;
202+				}
203+			} else {
204+				ifull++;
205+			}
206+			if (conv & SWAB)
207+				bswap(buf + ipos, ret);
208+			if (conv & LCASE)
209+				lcase(buf + ipos, ret);
210+			if (conv & UCASE)
211+				ucase(buf + ipos, ret);
212+			ipos += ret;
213+			if (bs && !(conv & (SWAB | LCASE | UCASE)))
214+				break;
215+		}
216+		if (ipos == opos)
217+			break;
218+		do {
219+			ret = write(ofd, buf + opos, MIN(obs, ipos - opos));
220+			if (ret < 0)
221+				eprintf("write:");
222+			if (ret == 0)
223+				eprintf("write returned 0\n");
224+			if (ret < obs)
225+				opart++;
226+			else
227+				ofull++;
228+			opos += ret;
229+		} while (ipos - opos >= (eof ? 1 : obs));
230+		if (opos < ipos)
231+			memmove(buf, buf + opos, ipos - opos);
232+		ipos -= opos;
233+		opos = 0;
234+	}
235+	summary();
236+
237+	return 0;
238+}
+139, -0
  1@@ -0,0 +1,139 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/statvfs.h>
  4+
  5+#include <mntent.h>
  6+#include <stdio.h>
  7+#include <stdlib.h>
  8+#include <string.h>
  9+
 10+#include "util.h"
 11+
 12+static long blksize = 512;
 13+static int aflag = 0;
 14+static int hflag = 0;
 15+static int kflag = 0;
 16+
 17+#define CALC_POWER(n, power, base, i) do { \
 18+	while (n > power) {                \
 19+		power = power * base;      \
 20+		i++;                       \
 21+	}                                  \
 22+} while(0)
 23+
 24+static void
 25+print_human(
 26+	const char         *fsname,
 27+	unsigned long long total,
 28+	unsigned long long used,
 29+	unsigned long long avail,
 30+	int                capacity,
 31+	const char         *dir)
 32+{
 33+	long base = 1024;
 34+	unsigned long long power_total = base;
 35+	unsigned long long power_used = base;
 36+	unsigned long long power_avail = base;
 37+	char postfixes[] = {'B', 'K', 'M', 'G', 'T', 'P', 'E'};
 38+	int i = 0, j = 0, k = 0;
 39+
 40+	total = total * blksize;
 41+	used = used * blksize;
 42+	avail = avail * blksize;
 43+
 44+	CALC_POWER(total, power_total, base, i);
 45+	CALC_POWER(used, power_used, base, j);
 46+	CALC_POWER(avail, power_avail, base, k);
 47+
 48+	total = i ? total / (power_total / base) : total;
 49+	used = j ? used / (power_used / base) : used;
 50+	avail = k ? avail / (power_avail / base) : avail;
 51+	printf("%-12s %9llu%c %9llu%c %9llu%c %7d%%  %s\n",
 52+	       fsname, total, postfixes[i], used, postfixes[j],
 53+	       avail, postfixes[k], capacity, dir);
 54+}
 55+
 56+static int
 57+mnt_show(const char *fsname, const char *dir)
 58+{
 59+	struct statvfs s;
 60+	unsigned long long total, used, avail;
 61+	int capacity = 0;
 62+	int bs;
 63+
 64+	if (statvfs(dir, &s) < 0)
 65+		return -1;
 66+
 67+	bs = s.f_frsize / blksize;
 68+	total = s.f_blocks * bs;
 69+	avail = s.f_bfree * bs;
 70+	used = total - avail;
 71+
 72+	if (used + avail) {
 73+		capacity = (used * 100) / (used + avail);
 74+		if (used * 100 != capacity * (used + avail))
 75+			capacity++;
 76+	}
 77+
 78+	if (hflag)
 79+		print_human(fsname, total, used, avail, capacity, dir);
 80+	else
 81+		printf("%-12s %9llu %9llu %9llu %7d%%  %s\n",
 82+		       fsname, total, used, avail, capacity, dir);
 83+
 84+	return 0;
 85+}
 86+
 87+static void
 88+usage(void)
 89+{
 90+	eprintf("usage: %s [-a]\n", argv0);
 91+}
 92+
 93+int
 94+main(int argc, char *argv[])
 95+{
 96+	struct mntent *me = NULL;
 97+	FILE *fp;
 98+	int ret = 0;
 99+
100+	ARGBEGIN {
101+	case 'a':
102+		aflag = 1;
103+		break;
104+	case 'h':
105+		hflag = 1;
106+		kflag = 0;
107+		break;
108+	case 'k':
109+		kflag = 1;
110+		hflag = 0;
111+		blksize = 1024;
112+		break;
113+	case 's':
114+	case 'i':
115+		eprintf("not implemented\n");
116+	default:
117+		usage();
118+	} ARGEND;
119+
120+	if (hflag)
121+		printf("Filesystem         Size       Used      "
122+		       "Avail Capacity   Mounted on\n");
123+	else
124+		printf("Filesystem  %ld-blocks      Used     "
125+		       "Avail Capacity  Mounted on\n", blksize);
126+
127+	fp = setmntent("/proc/mounts", "r");
128+	if (!fp)
129+		eprintf("setmntent %s:", "/proc/mounts");
130+	while ((me = getmntent(fp)) != NULL) {
131+		if (aflag == 0)
132+			if (strcmp(me->mnt_type, "rootfs") == 0)
133+				continue;
134+		if (mnt_show(me->mnt_fsname, me->mnt_dir) < 0)
135+			ret = 1;
136+	}
137+	endmntent(fp);
138+
139+	return ret;
140+}
+27, -0
 1@@ -0,0 +1,27 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <libgen.h>
 4+#include <stdio.h>
 5+
 6+#include "util.h"
 7+
 8+static void
 9+usage(void)
10+{
11+	eprintf("usage: %s path\n", argv0);
12+}
13+
14+int
15+main(int argc, char *argv[])
16+{
17+	ARGBEGIN {
18+	default:
19+		usage();
20+	} ARGEND
21+
22+	if (argc != 1)
23+		usage();
24+
25+	puts(dirname(argv[0]));
26+
27+	return fshut(stdout, "<stdout>");
28+}
+167, -0
  1@@ -0,0 +1,167 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+#include <sys/types.h>
  5+
  6+#include <errno.h>
  7+#include <fcntl.h>
  8+#include <limits.h>
  9+#include <search.h>
 10+#include <stdint.h>
 11+#include <stdlib.h>
 12+#include <stdio.h>
 13+#include <unistd.h>
 14+
 15+#include "fs.h"
 16+#include "util.h"
 17+
 18+static size_t maxdepth = SIZE_MAX;
 19+static size_t blksize  = 512;
 20+
 21+static int aflag = 0;
 22+static int sflag = 0;
 23+static int hflag = 0;
 24+
 25+struct file {
 26+	dev_t devno;
 27+	ino_t inode;
 28+};
 29+
 30+static void
 31+printpath(off_t n, const char *path)
 32+{
 33+	if (hflag)
 34+		printf("%s\t%s\n", humansize(n * blksize), path);
 35+	else
 36+		printf("%jd\t%s\n", (intmax_t)n, path);
 37+}
 38+
 39+static off_t
 40+nblks(blkcnt_t blocks)
 41+{
 42+	return (512 * blocks + blksize - 1) / blksize;
 43+}
 44+
 45+static int
 46+cmp(const void *p1, const void *p2)
 47+{
 48+	const struct file *f1 = p1, *f2 = p2;
 49+
 50+	if (f1->devno > f2->devno)
 51+		return -1;
 52+	if (f1->devno < f2->devno)
 53+		return 1;
 54+
 55+	/* f1->devno == f2->devno */
 56+	if (f1->inode < f2->inode)
 57+		return -1;
 58+	if (f1->inode > f2->inode)
 59+		return 1;
 60+
 61+	return 0;
 62+}
 63+
 64+static int
 65+duplicated(dev_t dev, ino_t ino)
 66+{
 67+	static void *tree;
 68+	struct file **fpp, *fp, file = {dev, ino};
 69+
 70+	if ((fpp = tsearch(&file, &tree, cmp)) == NULL)
 71+		eprintf("%s:", argv0);
 72+
 73+	if (*fpp != &file)
 74+		return 1;
 75+
 76+	/* new file added */
 77+	fp = emalloc(sizeof(*fp));
 78+	*fp = file;
 79+	*fpp = fp;
 80+
 81+	return 0;
 82+}
 83+
 84+static void
 85+du(int dirfd, const char *path, struct stat *st, void *data, struct recursor *r)
 86+{
 87+	off_t *total = data, subtotal;
 88+
 89+	subtotal = nblks(st->st_blocks);
 90+	if (S_ISDIR(st->st_mode)) {
 91+		recurse(dirfd, path, &subtotal, r);
 92+	} else if (r->follow != 'P' || st->st_nlink > 1) {
 93+		if (duplicated(st->st_dev, st->st_ino))
 94+			goto print;
 95+	}
 96+
 97+	*total += subtotal;
 98+
 99+print:
100+	if (!r->depth)
101+		printpath(*total, r->path);
102+	else if (!sflag && r->depth <= maxdepth && (S_ISDIR(st->st_mode) || aflag))
103+		printpath(subtotal, r->path);
104+}
105+
106+static void
107+usage(void)
108+{
109+	eprintf("usage: %s [-a | -s] [-d depth] [-h] [-k] [-H | -L | -P] [-x] [file ...]\n", argv0);
110+}
111+
112+int
113+main(int argc, char *argv[])
114+{
115+	struct recursor r = { .fn = du, .follow = 'P' };
116+	off_t n = 0;
117+	int kflag = 0, dflag = 0;
118+	char *bsize;
119+
120+	ARGBEGIN {
121+	case 'a':
122+		aflag = 1;
123+		break;
124+	case 'd':
125+		dflag = 1;
126+		maxdepth = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
127+		break;
128+	case 'h':
129+		hflag = 1;
130+		break;
131+	case 'k':
132+		kflag = 1;
133+		break;
134+	case 's':
135+		sflag = 1;
136+		break;
137+	case 'x':
138+		r.flags |= SAMEDEV;
139+		break;
140+	case 'H':
141+	case 'L':
142+	case 'P':
143+		r.follow = ARGC();
144+		break;
145+	default:
146+		usage();
147+	} ARGEND
148+
149+	if ((aflag && sflag) || (dflag && sflag))
150+		usage();
151+
152+	bsize = getenv("BLOCKSIZE");
153+	if (bsize)
154+		blksize = estrtonum(bsize, 1, MIN(LLONG_MAX, SIZE_MAX));
155+	if (kflag)
156+		blksize = 1024;
157+
158+	if (!argc) {
159+		recurse(AT_FDCWD, ".", &n, &r);
160+	} else {
161+		for (; *argv; argc--, argv++) {
162+			n = 0;
163+			recurse(AT_FDCWD, *argv, &n, &r);
164+		}
165+	}
166+
167+	return fshut(stdout, "<stdout>") || recurse_status;
168+}
+24, -0
 1@@ -0,0 +1,24 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <string.h>
 5+#include "util.h"
 6+
 7+int
 8+main(int argc, char *argv[])
 9+{
10+	int nflag = 0;
11+
12+	argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
13+
14+	if (*argv && !strcmp(*argv, "-n")) {
15+		nflag = 1;
16+		argc--, argv++;
17+	}
18+
19+	for (; *argv; argc--, argv++)
20+		putword(stdout, *argv);
21+	if (!nflag)
22+		putchar('\n');
23+
24+	return fshut(stdout, "<stdout>");
25+}
+1722, -0
   1@@ -0,0 +1,1722 @@
   2+/* See LICENSE file for copyright and license details. */
   3+#include <sys/stat.h>
   4+#include <fcntl.h>
   5+#include <regex.h>
   6+#include <unistd.h>
   7+
   8+#include <ctype.h>
   9+#include <limits.h>
  10+#include <setjmp.h>
  11+#include <signal.h>
  12+#include <stdint.h>
  13+#include <stdio.h>
  14+#include <stdlib.h>
  15+#include <string.h>
  16+
  17+#include "util.h"
  18+
  19+#define REGEXSIZE  100
  20+#define LINESIZE    80
  21+#define NUMLINES    32
  22+#define CACHESIZ  4096
  23+#define AFTER     0
  24+#define BEFORE    1
  25+
  26+typedef struct {
  27+	char *str;
  28+	size_t cap;
  29+	size_t siz;
  30+} String;
  31+
  32+struct hline {
  33+	off_t seek;
  34+	char  global;
  35+	int   next, prev;
  36+};
  37+
  38+struct undo {
  39+	int curln, lastln;
  40+	size_t nr, cap;
  41+	struct link {
  42+		int to1, from1;
  43+		int to2, from2;
  44+	} *vec;
  45+};
  46+
  47+static char *prompt = "*";
  48+static regex_t *pattern;
  49+static regmatch_t matchs[10];
  50+static String lastre;
  51+
  52+static int optverbose, optprompt, exstatus, optdiag = 1;
  53+static int marks['z' - 'a' + 1];
  54+static int nlines, line1, line2;
  55+static int curln, lastln, ocurln, olastln;
  56+static jmp_buf savesp;
  57+static char *lasterr;
  58+static size_t idxsize, lastidx;
  59+static struct hline *zero;
  60+static String text;
  61+static char savfname[FILENAME_MAX];
  62+static char tmpname[FILENAME_MAX];
  63+static int scratch;
  64+static int pflag, modflag, uflag, gflag;
  65+static size_t csize;
  66+static String cmdline;
  67+static char *ocmdline;
  68+static int inputidx;
  69+static char *rhs;
  70+static char *lastmatch;
  71+static struct undo udata;
  72+static int newcmd;
  73+
  74+static sig_atomic_t intr, hup;
  75+
  76+static void undo(void);
  77+
  78+static void
  79+error(char *msg)
  80+{
  81+	exstatus = 1;
  82+	lasterr = msg;
  83+	puts("?");
  84+
  85+	if (optverbose)
  86+		puts(msg);
  87+	if (!newcmd)
  88+		undo();
  89+
  90+	curln = ocurln;
  91+	longjmp(savesp, 1);
  92+}
  93+
  94+static int
  95+nextln(int line)
  96+{
  97+	++line;
  98+	return (line > lastln) ? 0 : line;
  99+}
 100+
 101+static int
 102+prevln(int line)
 103+{
 104+	--line;
 105+	return (line < 0) ? lastln : line;
 106+}
 107+
 108+static String *
 109+copystring(String *s, char *from)
 110+{
 111+	size_t len;
 112+	char *t;
 113+
 114+	if ((t = strdup(from)) == NULL)
 115+		error("out of memory");
 116+	len = strlen(t);
 117+
 118+	free(s->str);
 119+	s->str = t;
 120+	s->siz = len;
 121+	s->cap = len;
 122+
 123+	return s;
 124+}
 125+
 126+static String *
 127+string(String *s)
 128+{
 129+	free(s->str);
 130+	s->str = NULL;
 131+	s->siz = 0;
 132+	s->cap = 0;
 133+
 134+	return s;
 135+}
 136+
 137+static char *
 138+addchar(char c, String *s)
 139+{
 140+	size_t cap = s->cap, siz = s->siz;
 141+	char *t = s->str;
 142+
 143+	if (siz >= cap &&
 144+	    (cap > SIZE_MAX - LINESIZE ||
 145+	     (t = realloc(t, cap += LINESIZE)) == NULL))
 146+			error("out of memory");
 147+	t[siz++] = c;
 148+	s->siz = siz;
 149+	s->cap = cap;
 150+	s->str = t;
 151+	return t;
 152+}
 153+
 154+static void chksignals(void);
 155+
 156+static int
 157+input(void)
 158+{
 159+	int ch;
 160+
 161+	chksignals();
 162+
 163+	ch = cmdline.str[inputidx];
 164+	if (ch != '\0')
 165+		inputidx++;
 166+	return ch;
 167+}
 168+
 169+static int
 170+back(int c)
 171+{
 172+	if (c == '\0')
 173+		return c;
 174+	return cmdline.str[--inputidx] = c;
 175+}
 176+
 177+static int
 178+makeline(char *s, int *off)
 179+{
 180+	struct hline *lp;
 181+	size_t len;
 182+	char *begin = s;
 183+	int c;
 184+
 185+	if (lastidx >= idxsize) {
 186+		lp = NULL;
 187+		if (idxsize <= SIZE_MAX - NUMLINES)
 188+			lp = reallocarray(zero, idxsize + NUMLINES, sizeof(*lp));
 189+		if (!lp)
 190+			error("out of memory");
 191+		idxsize += NUMLINES;
 192+		zero = lp;
 193+	}
 194+	lp = zero + lastidx;
 195+	lp->global = 0;
 196+
 197+	if (!s) {
 198+		lp->seek = -1;
 199+		len = 0;
 200+	} else {
 201+		while ((c = *s++) && c != '\n')
 202+			;
 203+		len = s - begin;
 204+		if ((lp->seek = lseek(scratch, 0, SEEK_END)) < 0 ||
 205+		    write(scratch, begin, len) < 0) {
 206+			error("input/output error");
 207+		}
 208+	}
 209+	if (off)
 210+		*off = len;
 211+	++lastidx;
 212+	return lp - zero;
 213+}
 214+
 215+static int
 216+getindex(int line)
 217+{
 218+	struct hline *lp;
 219+	int n;
 220+
 221+	if (line == -1)
 222+		line = 0;
 223+	for (n = 0, lp = zero; n != line; n++)
 224+		lp = zero + lp->next;
 225+
 226+	return lp - zero;
 227+}
 228+
 229+static char *
 230+gettxt(int line)
 231+{
 232+	static char buf[CACHESIZ];
 233+	static off_t lasto;
 234+	struct hline *lp;
 235+	off_t off, block;
 236+	ssize_t n;
 237+	char *p;
 238+
 239+	lp = zero + getindex(line);
 240+	text.siz = 0;
 241+	off = lp->seek;
 242+
 243+	if (off == (off_t) -1)
 244+		return addchar('\0', &text);
 245+
 246+repeat:
 247+	chksignals();
 248+	if (!csize || off < lasto || off - lasto >= csize) {
 249+		block = off & ~(CACHESIZ-1);
 250+		if (lseek(scratch, block, SEEK_SET) < 0 ||
 251+		    (n = read(scratch, buf, CACHESIZ)) < 0) {
 252+			error("input/output error");
 253+		}
 254+		csize = n;
 255+		lasto = block;
 256+	}
 257+	for (p = buf + off - lasto; p < buf + csize && *p != '\n'; ++p) {
 258+		++off;
 259+		addchar(*p, &text);
 260+	}
 261+	if (csize == CACHESIZ && p == buf + csize)
 262+		goto repeat;
 263+
 264+	addchar('\n', &text);
 265+	addchar('\0', &text);
 266+	return text.str;
 267+}
 268+
 269+static void
 270+setglobal(int i, int v)
 271+{
 272+	zero[getindex(i)].global = v;
 273+}
 274+
 275+static void
 276+clearundo(void)
 277+{
 278+	free(udata.vec);
 279+	udata.vec = NULL;
 280+	newcmd = udata.nr = udata.cap = 0;
 281+	modflag = 0;
 282+}
 283+
 284+static void
 285+newundo(int from1, int from2)
 286+{
 287+	struct link *p;
 288+
 289+	if (newcmd) {
 290+		clearundo();
 291+		udata.curln = ocurln;
 292+		udata.lastln = olastln;
 293+	}
 294+	if (udata.nr >= udata.cap) {
 295+		size_t siz = (udata.cap + 10) * sizeof(struct link);
 296+		if ((p = realloc(udata.vec, siz)) == NULL)
 297+			error("out of memory");
 298+		udata.vec = p;
 299+		udata.cap = udata.cap + 10;
 300+	}
 301+	p = &udata.vec[udata.nr++];
 302+	p->from1 = from1;
 303+	p->to1 = zero[from1].next;
 304+	p->from2 = from2;
 305+	p->to2 = zero[from2].prev;
 306+}
 307+
 308+/*
 309+ * relink: to1   <- from1
 310+ *         from2 -> to2
 311+ */
 312+static void
 313+relink(int to1, int from1, int from2, int to2)
 314+{
 315+	newundo(from1, from2);
 316+	zero[from1].next = to1;
 317+	zero[from2].prev = to2;
 318+	modflag = 1;
 319+}
 320+
 321+static void
 322+undo(void)
 323+{
 324+	struct link *p;
 325+
 326+	if (udata.nr == 0)
 327+		return;
 328+	for (p = &udata.vec[udata.nr-1]; udata.nr > 0; --p) {
 329+		--udata.nr;
 330+		zero[p->from1].next = p->to1;
 331+		zero[p->from2].prev = p->to2;
 332+	}
 333+	free(udata.vec);
 334+	udata.vec = NULL;
 335+	udata.cap = 0;
 336+	curln = udata.curln;
 337+	lastln = udata.lastln;
 338+}
 339+
 340+static void
 341+inject(char *s, int where)
 342+{
 343+	int off, k, begin, end;
 344+
 345+	if (where == BEFORE) {
 346+		begin = getindex(curln-1);
 347+		end = getindex(nextln(curln-1));
 348+	} else {
 349+		begin = getindex(curln);
 350+		end = getindex(nextln(curln));
 351+	}
 352+	while (*s) {
 353+		k = makeline(s, &off);
 354+		s += off;
 355+		relink(k, begin, k, begin);
 356+		relink(end, k, end, k);
 357+		++lastln;
 358+		++curln;
 359+		begin = k;
 360+	}
 361+}
 362+
 363+static void
 364+clearbuf(void)
 365+{
 366+	if (scratch)
 367+		close(scratch);
 368+	remove(tmpname);
 369+	free(zero);
 370+	zero = NULL;
 371+	scratch = csize = idxsize = lastidx = curln = lastln = 0;
 372+	modflag = lastln = curln = 0;
 373+}
 374+
 375+static void
 376+setscratch(void)
 377+{
 378+	int r, k;
 379+	char *dir;
 380+
 381+	clearbuf();
 382+	clearundo();
 383+	if ((dir = getenv("TMPDIR")) == NULL)
 384+		dir = "/tmp";
 385+	r = snprintf(tmpname, sizeof(tmpname), "%s/%s",
 386+	             dir, "ed.XXXXXX");
 387+	if (r < 0 || (size_t)r >= sizeof(tmpname))
 388+		error("scratch filename too long");
 389+	if ((scratch = mkstemp(tmpname)) < 0)
 390+		error("failed to create scratch file");
 391+	if ((k = makeline(NULL, NULL)))
 392+		error("input/output error in scratch file");
 393+	relink(k, k, k, k);
 394+	clearundo();
 395+}
 396+
 397+static void
 398+compile(int delim)
 399+{
 400+	int n, ret, c,bracket;
 401+	static char buf[BUFSIZ];
 402+
 403+	if (!isgraph(delim))
 404+		error("invalid pattern delimiter");
 405+
 406+	bracket = lastre.siz = 0;
 407+	for (n = 0;; ++n) {
 408+		c = input();
 409+		if (c == delim && !bracket || c == '\0') {
 410+			break;
 411+		} else if (c == '\\') {
 412+			addchar(c, &lastre);
 413+			c = input();
 414+		} else if (c == '[') {
 415+			bracket = 1;
 416+		} else if (c == ']') {
 417+			bracket = 0;
 418+		}
 419+		addchar(c, &lastre);
 420+	}
 421+	if (n == 0) {
 422+		if (!pattern)
 423+			error("no previous pattern");
 424+		return;
 425+	}
 426+	addchar('\0', &lastre);
 427+
 428+	if (pattern)
 429+		regfree(pattern);
 430+	if (!pattern && (!(pattern = malloc(sizeof(*pattern)))))
 431+		error("out of memory");
 432+	if ((ret = regcomp(pattern, lastre.str, 0))) {
 433+		regerror(ret, pattern, buf, sizeof(buf));
 434+		error(buf);
 435+	}
 436+}
 437+
 438+static int
 439+match(int num)
 440+{
 441+	int r;
 442+
 443+	lastmatch = gettxt(num);
 444+	text.str[text.siz - 2] = '\0';
 445+	r = !regexec(pattern, lastmatch, 10, matchs, 0);
 446+	text.str[text.siz - 2] = '\n';
 447+
 448+	return r;
 449+}
 450+
 451+static int
 452+rematch(int num)
 453+{
 454+	regoff_t off = matchs[0].rm_eo;
 455+	regmatch_t *m;
 456+	int r;
 457+
 458+	text.str[text.siz - 2] = '\0';
 459+	r = !regexec(pattern, lastmatch + off, 10, matchs, REG_NOTBOL);
 460+	text.str[text.siz - 2] = '\n';
 461+
 462+	if (!r)
 463+		return 0;
 464+
 465+	if (matchs[0].rm_eo > 0) {
 466+		lastmatch += off;
 467+		return 1;
 468+	}
 469+
 470+	/* Zero width match was found at the end of the input, done */
 471+	if (lastmatch[off] == '\n') {
 472+		lastmatch += off;
 473+		return 0;
 474+	}
 475+
 476+	/* Zero width match at the current posiion, find the next one */
 477+	text.str[text.siz - 2] = '\0';
 478+	r = !regexec(pattern, lastmatch + off + 1, 10, matchs, REG_NOTBOL);
 479+	text.str[text.siz - 2] = '\n';
 480+
 481+	if (!r)
 482+		return 0;
 483+
 484+	/* Re-adjust matches to account for +1 in regexec */
 485+	for (m = matchs; m < &matchs[10]; m++) {
 486+		m->rm_so += 1;
 487+		m->rm_eo += 1;
 488+	}
 489+	lastmatch += off;
 490+
 491+	return 1;
 492+}
 493+
 494+static int
 495+search(int way)
 496+{
 497+	int i;
 498+
 499+	i = curln;
 500+	do {
 501+		chksignals();
 502+
 503+		i = (way == '?') ? prevln(i) : nextln(i);
 504+		if (i > 0 && match(i))
 505+			return i;
 506+	} while (i != curln);
 507+
 508+	error("invalid address");
 509+	return -1; /* not reached */
 510+}
 511+
 512+static void
 513+skipblank(void)
 514+{
 515+	char c;
 516+
 517+	while ((c = input()) == ' ' || c == '\t')
 518+		;
 519+	back(c);
 520+}
 521+
 522+static void
 523+ensureblank(void)
 524+{
 525+	char c;
 526+
 527+	switch ((c = input())) {
 528+	case ' ':
 529+	case '\t':
 530+		skipblank();
 531+	case '\0':
 532+		back(c);
 533+		break;
 534+	default:
 535+		error("unknown command");
 536+	}
 537+}
 538+
 539+static int
 540+getnum(void)
 541+{
 542+	int ln, n, c;
 543+
 544+	for (ln = 0; isdigit(c = input()); ln += n) {
 545+		if (ln > INT_MAX/10)
 546+			goto invalid;
 547+		n = c - '0';
 548+		ln *= 10;
 549+		if (INT_MAX - ln < n)
 550+			goto invalid;
 551+	}
 552+	back(c);
 553+	return ln;
 554+
 555+invalid:
 556+	error("invalid address");
 557+	return -1; /* not reached */
 558+}
 559+
 560+static int
 561+linenum(int *line)
 562+{
 563+	int ln, c;
 564+
 565+	skipblank();
 566+
 567+	switch (c = input()) {
 568+	case '.':
 569+		ln = curln;
 570+		break;
 571+	case '\'':
 572+		skipblank();
 573+		if (!islower(c = input()))
 574+			error("invalid mark character");
 575+		if (!(ln = marks[c - 'a']))
 576+			error("invalid address");
 577+		break;
 578+	case '$':
 579+		ln = lastln;
 580+		break;
 581+	case '?':
 582+	case '/':
 583+		compile(c);
 584+		ln = search(c);
 585+		break;
 586+	case '^':
 587+	case '-':
 588+	case '+':
 589+		ln = curln;
 590+		back(c);
 591+		break;
 592+	default:
 593+		back(c);
 594+		if (isdigit(c))
 595+			ln = getnum();
 596+		else
 597+			return 0;
 598+		break;
 599+	}
 600+	*line = ln;
 601+	return 1;
 602+}
 603+
 604+static int
 605+address(int *line)
 606+{
 607+	int ln, sign, c, num;
 608+
 609+	if (!linenum(&ln))
 610+		return 0;
 611+
 612+	for (;;) {
 613+		skipblank();
 614+		if ((c = input()) != '+' && c != '-' && c != '^')
 615+			break;
 616+		sign = c == '+' ? 1 : -1;
 617+		num = isdigit(back(input())) ? getnum() : 1;
 618+		num *= sign;
 619+		if (INT_MAX - ln < num)
 620+			goto invalid;
 621+		ln += num;
 622+	}
 623+	back(c);
 624+
 625+	if (ln < 0 || ln > lastln)
 626+		error("invalid address");
 627+	*line = ln;
 628+	return 1;
 629+
 630+invalid:
 631+	error("invalid address");
 632+	return -1; /* not reached */
 633+}
 634+
 635+static void
 636+getlst(void)
 637+{
 638+	int ln, c;
 639+
 640+	if ((c = input()) == ',') {
 641+		line1 = 1;
 642+		line2 = lastln;
 643+		nlines = lastln;
 644+		return;
 645+	} else if (c == ';') {
 646+		line1 = curln;
 647+		line2 = lastln;
 648+		nlines = lastln - curln + 1;
 649+		return;
 650+	}
 651+	back(c);
 652+	line2 = curln;
 653+	for (nlines = 0; address(&ln); ) {
 654+		line1 = line2;
 655+		line2 = ln;
 656+		++nlines;
 657+
 658+		skipblank();
 659+		if ((c = input()) != ',' && c != ';') {
 660+			back(c);
 661+			break;
 662+		}
 663+		if (c == ';')
 664+			curln = line2;
 665+	}
 666+	if (nlines > 2)
 667+		nlines = 2;
 668+	else if (nlines <= 1)
 669+		line1 = line2;
 670+}
 671+
 672+static void
 673+deflines(int def1, int def2)
 674+{
 675+	if (!nlines) {
 676+		line1 = def1;
 677+		line2 = def2;
 678+	}
 679+	if (line1 > line2 || line1 < 0 || line2 > lastln)
 680+		error("invalid address");
 681+}
 682+
 683+static void
 684+quit(void)
 685+{
 686+	clearbuf();
 687+	exit(exstatus);
 688+}
 689+
 690+static void
 691+setinput(char *s)
 692+{
 693+	copystring(&cmdline, s);
 694+	inputidx = 0;
 695+}
 696+
 697+static void
 698+getinput(void)
 699+{
 700+	int ch;
 701+
 702+	string(&cmdline);
 703+
 704+	while ((ch = getchar()) != '\n' && ch != EOF) {
 705+		if (ch == '\\') {
 706+			if ((ch = getchar()) == EOF)
 707+				break;
 708+			if (ch != '\n')
 709+				addchar('\\', &cmdline);
 710+		}
 711+		addchar(ch, &cmdline);
 712+	}
 713+
 714+	addchar('\0', &cmdline);
 715+	inputidx = 0;
 716+
 717+	if (ch == EOF) {
 718+		chksignals();
 719+		if (ferror(stdin)) {
 720+			exstatus = 1;
 721+			fputs("ed: error reading input\n", stderr);
 722+		}
 723+		quit();
 724+	}
 725+}
 726+
 727+static int
 728+moreinput(void)
 729+{
 730+	if (!uflag)
 731+		return cmdline.str[inputidx] != '\0';
 732+
 733+	getinput();
 734+	return 1;
 735+}
 736+
 737+static void dowrite(const char *, int);
 738+
 739+static void
 740+dump(void)
 741+{
 742+	char *home;
 743+
 744+	if (modflag)
 745+		return;
 746+
 747+	line1 = nextln(0);
 748+	line2 = lastln;
 749+
 750+	if (!setjmp(savesp)) {
 751+		dowrite("ed.hup", 1);
 752+		return;
 753+	}
 754+
 755+	home = getenv("HOME");
 756+	if (!home || chdir(home) < 0)
 757+		return;
 758+
 759+	if (!setjmp(savesp))
 760+		dowrite("ed.hup", 1);
 761+}
 762+
 763+static void
 764+chksignals(void)
 765+{
 766+	if (hup) {
 767+		exstatus = 1;
 768+		dump();
 769+		quit();
 770+	}
 771+
 772+	if (intr) {
 773+		intr = 0;
 774+		newcmd = 1;
 775+		clearerr(stdin);
 776+		error("Interrupt");
 777+	}
 778+}
 779+
 780+static const char *
 781+expandcmd(void)
 782+{
 783+	static String cmd;
 784+	char *p;
 785+	int c, repl = 0;
 786+
 787+	skipblank();
 788+	if ((c = input()) != '!') {
 789+		back(c);
 790+		string(&cmd);
 791+	} else if (cmd.siz) {
 792+		--cmd.siz;
 793+		repl = 1;
 794+	} else {
 795+		error("no previous command");
 796+	}
 797+
 798+	while ((c = input()) != '\0') {
 799+		switch (c) {
 800+		case '%':
 801+			if (savfname[0] == '\0')
 802+				error("no current filename");
 803+			repl = 1;
 804+			for (p = savfname; *p; ++p)
 805+				addchar(*p, &cmd);
 806+			break;
 807+		case '\\':
 808+			c = input();
 809+			if (c != '%') {
 810+				back(c);
 811+				c = '\\';
 812+			}
 813+		default:
 814+			addchar(c, &cmd);
 815+		}
 816+	}
 817+	addchar('\0', &cmd);
 818+
 819+	if (repl)
 820+		puts(cmd.str);
 821+
 822+	return cmd.str;
 823+}
 824+
 825+static void
 826+dowrite(const char *fname, int trunc)
 827+{
 828+	size_t bytecount = 0;
 829+	int i, r, line;
 830+	FILE *aux;
 831+	static int sh;
 832+	static FILE *fp;
 833+	char *mode;
 834+
 835+	if (fp) {
 836+		sh ? pclose(fp) : fclose(fp);
 837+		fp = NULL;
 838+	}
 839+
 840+	if (fname[0] == '!') {
 841+		sh = 1;
 842+		if((fp = popen(expandcmd(), "w")) == NULL)
 843+			error("bad exec");
 844+	} else {
 845+		sh = 0;
 846+		mode = (trunc) ? "w" : "a";
 847+		if ((fp = fopen(fname, mode)) == NULL)
 848+			error("cannot open input file");
 849+	}
 850+
 851+	line = curln;
 852+	for (i = line1; i <= line2; ++i) {
 853+		chksignals();
 854+
 855+		gettxt(i);
 856+		bytecount += text.siz - 1;
 857+		fwrite(text.str, 1, text.siz - 1, fp);
 858+	}
 859+
 860+	curln = line2;
 861+
 862+	aux = fp;
 863+	fp = NULL;
 864+	r = sh ? pclose(aux) : fclose(aux);
 865+	if (r)
 866+		error("input/output error");
 867+	strcpy(savfname, fname);
 868+	if (!sh)
 869+		modflag = 0;
 870+	curln = line;
 871+	if (optdiag)
 872+		printf("%zu\n", bytecount);
 873+}
 874+
 875+static void
 876+doread(const char *fname)
 877+{
 878+	int r;
 879+	size_t cnt;
 880+	ssize_t len;
 881+	char *p;
 882+	FILE *aux;
 883+	static size_t n;
 884+	static int sh;
 885+	static char *s;
 886+	static FILE *fp;
 887+
 888+	if (fp) {
 889+		sh ? pclose(fp) : fclose(fp);
 890+		fp = NULL;
 891+	}
 892+
 893+	if(fname[0] == '!') {
 894+		sh = 1;
 895+		if((fp = popen(expandcmd(), "r")) == NULL)
 896+			error("bad exec");
 897+	} else if ((fp = fopen(fname, "r")) == NULL) {
 898+		error("cannot open input file");
 899+	}
 900+
 901+	curln = line2;
 902+	for (cnt = 0; (len = getline(&s, &n, fp)) > 0; cnt += (size_t)len) {
 903+		chksignals();
 904+		if (s[len-1] != '\n') {
 905+			if (len+1 >= n) {
 906+				if (n == SIZE_MAX || !(p = realloc(s, ++n)))
 907+					error("out of memory");
 908+				s = p;
 909+			}
 910+			s[len] = '\n';
 911+			s[len+1] = '\0';
 912+		}
 913+		inject(s, AFTER);
 914+	}
 915+	if (optdiag)
 916+		printf("%zu\n", cnt);
 917+
 918+	aux = fp;
 919+	fp = NULL;
 920+	r = sh ? pclose(aux) : fclose(aux);
 921+	if (r)
 922+		error("input/output error");
 923+}
 924+
 925+static void
 926+doprint(void)
 927+{
 928+	int i, c;
 929+	char *s, *str;
 930+
 931+	if (line1 <= 0 || line2 > lastln)
 932+		error("incorrect address");
 933+	for (i = line1; i <= line2; ++i) {
 934+		chksignals();
 935+		if (pflag == 'n')
 936+			printf("%d\t", i);
 937+		for (s = gettxt(i); (c = *s) != '\n'; ++s) {
 938+			if (pflag != 'l')
 939+				goto print_char;
 940+			switch (c) {
 941+			case '$':
 942+				str = "\\$";
 943+				goto print_str;
 944+			case '\t':
 945+				str = "\\t";
 946+				goto print_str;
 947+			case '\b':
 948+				str = "\\b";
 949+				goto print_str;
 950+			case '\\':
 951+				str = "\\\\";
 952+				goto print_str;
 953+			default:
 954+				if (!isprint(c)) {
 955+					printf("\\x%x", 0xFF & c);
 956+					break;
 957+				}
 958+			print_char:
 959+				putchar(c);
 960+				break;
 961+			print_str:
 962+				fputs(str, stdout);
 963+				break;
 964+			}
 965+		}
 966+		if (pflag == 'l')
 967+			fputs("$", stdout);
 968+		putc('\n', stdout);
 969+	}
 970+	curln = i - 1;
 971+}
 972+
 973+static void
 974+dohelp(void)
 975+{
 976+	if (lasterr)
 977+		puts(lasterr);
 978+}
 979+
 980+static void
 981+chkprint(int flag)
 982+{
 983+	int c;
 984+
 985+	if (flag) {
 986+		if ((c = input()) == 'p' || c == 'l' || c == 'n')
 987+			pflag = c;
 988+		else
 989+			back(c);
 990+	}
 991+	if ((c = input()) != '\0' && c != '\n')
 992+		error("invalid command suffix");
 993+}
 994+
 995+static char *
 996+getfname(int comm)
 997+{
 998+	int c;
 999+	char *bp;
1000+	static char fname[FILENAME_MAX];
1001+
1002+	skipblank();
1003+	if ((c = input()) == '!') {
1004+		return strcpy(fname, "!");
1005+	}
1006+	back(c);
1007+	for (bp = fname; bp < &fname[FILENAME_MAX]; *bp++ = c) {
1008+		if ((c = input()) == '\0')
1009+			break;
1010+	}
1011+	if (bp == fname) {
1012+		if (savfname[0] == '\0')
1013+			error("no current filename");
1014+		return savfname;
1015+	}
1016+	if (bp == &fname[FILENAME_MAX])
1017+		error("file name too long");
1018+	*bp = '\0';
1019+
1020+	if (fname[0] == '!')
1021+		return fname;
1022+	if (savfname[0] == '\0' || comm == 'e' || comm == 'f')
1023+		strcpy(savfname, fname);
1024+	return fname;
1025+}
1026+
1027+static void
1028+append(int num)
1029+{
1030+	int ch;
1031+	static String line;
1032+
1033+	curln = num;
1034+	while (moreinput()) {
1035+		string(&line);
1036+		while ((ch = input()) != '\n' && ch != '\0')
1037+			addchar(ch, &line);
1038+		addchar('\n', &line);
1039+		addchar('\0', &line);
1040+
1041+		if (!strcmp(line.str, ".\n") || !strcmp(line.str, "."))
1042+			break;
1043+		inject(line.str, AFTER);
1044+	}
1045+}
1046+
1047+static void
1048+delete(int from, int to)
1049+{
1050+	int lto, lfrom;
1051+
1052+	if (!from)
1053+		error("incorrect address");
1054+
1055+	lfrom = getindex(prevln(from));
1056+	lto = getindex(nextln(to));
1057+	lastln -= to - from + 1;
1058+	curln = (from > lastln) ? lastln : from;;
1059+	relink(lto, lfrom, lto, lfrom);
1060+}
1061+
1062+static void
1063+move(int where)
1064+{
1065+	int before, after, lto, lfrom;
1066+
1067+	if (!line1 || (where >= line1 && where <= line2))
1068+		error("incorrect address");
1069+
1070+	before = getindex(prevln(line1));
1071+	after = getindex(nextln(line2));
1072+	lfrom = getindex(line1);
1073+	lto = getindex(line2);
1074+	relink(after, before, after, before);
1075+
1076+	if (where < line1) {
1077+		curln = where + line1 - line2 + 1;
1078+	} else {
1079+		curln = where;
1080+		where -= line1 - line2 + 1;
1081+	}
1082+	before = getindex(where);
1083+	after = getindex(nextln(where));
1084+	relink(lfrom, before, lfrom, before);
1085+	relink(after, lto, after, lto);
1086+}
1087+
1088+static void
1089+join(void)
1090+{
1091+	int i;
1092+	char *t, c;
1093+	static String s;
1094+
1095+	string(&s);
1096+	for (i = line1;; i = nextln(i)) {
1097+		chksignals();
1098+		for (t = gettxt(i); (c = *t) != '\n'; ++t)
1099+			addchar(*t, &s);
1100+		if (i == line2)
1101+			break;
1102+	}
1103+
1104+	addchar('\n', &s);
1105+	addchar('\0', &s);
1106+	delete(line1, line2);
1107+	inject(s.str, BEFORE);
1108+}
1109+
1110+static void
1111+scroll(int num)
1112+{
1113+	int max, ln, cnt;
1114+
1115+	if (!line1 || line1 == lastln)
1116+		error("incorrect address");
1117+
1118+	ln = line1;
1119+	max = line1 + num;
1120+	if (max > lastln)
1121+		max = lastln;
1122+	for (cnt = line1; cnt < max; cnt++) {
1123+		chksignals();
1124+		fputs(gettxt(ln), stdout);
1125+		ln = nextln(ln);
1126+	}
1127+	curln = ln;
1128+}
1129+
1130+static void
1131+copy(int where)
1132+{
1133+
1134+	if (!line1)
1135+		error("incorrect address");
1136+	curln = where;
1137+
1138+	while (line1 <= line2) {
1139+		chksignals();
1140+		inject(gettxt(line1), AFTER);
1141+		if (line2 >= curln)
1142+			line2 = nextln(line2);
1143+		line1 = nextln(line1);
1144+		if (line1 >= curln)
1145+			line1 = nextln(line1);
1146+	}
1147+}
1148+
1149+static void
1150+execsh(void)
1151+{
1152+	system(expandcmd());
1153+	if (optdiag)
1154+		puts("!");
1155+}
1156+
1157+static void
1158+getrhs(int delim)
1159+{
1160+	int c;
1161+	static String s;
1162+
1163+	string(&s);
1164+	while ((c = input()) != '\0' && c != delim)
1165+		addchar(c, &s);
1166+	addchar('\0', &s);
1167+	if (c == '\0') {
1168+		pflag = 'p';
1169+		back(c);
1170+	}
1171+
1172+	if (!strcmp("%", s.str)) {
1173+		if (!rhs)
1174+			error("no previous substitution");
1175+		free(s.str);
1176+	} else {
1177+		free(rhs);
1178+		rhs = s.str;
1179+	}
1180+	s.str = NULL;
1181+}
1182+
1183+static int
1184+getnth(void)
1185+{
1186+	int c;
1187+
1188+	if ((c = input()) == 'g') {
1189+		return -1;
1190+	} else if (isdigit(c)) {
1191+		if (c == '0')
1192+			return -1;
1193+		return c - '0';
1194+	} else {
1195+		back(c);
1196+		return 1;
1197+	}
1198+}
1199+
1200+static void
1201+addpre(String *s)
1202+{
1203+	char *p;
1204+
1205+	for (p = lastmatch; p < lastmatch + matchs[0].rm_so; ++p)
1206+		addchar(*p, s);
1207+}
1208+
1209+static void
1210+addpost(String *s)
1211+{
1212+	char c, *p;
1213+
1214+	for (p = lastmatch + matchs[0].rm_eo; (c = *p); ++p)
1215+		addchar(c, s);
1216+	addchar('\0', s);
1217+}
1218+
1219+static int
1220+addsub(String *s, int nth, int nmatch)
1221+{
1222+	char *end, *q, *p, c;
1223+	int sub;
1224+
1225+	if (nth != nmatch && nth != -1) {
1226+		q   = lastmatch + matchs[0].rm_so;
1227+		end = lastmatch + matchs[0].rm_eo;
1228+		while (q < end)
1229+			addchar(*q++, s);
1230+		return 0;
1231+	}
1232+
1233+	for (p = rhs; (c = *p); ++p) {
1234+		switch (c) {
1235+		case '&':
1236+			sub = 0;
1237+			goto copy_match;
1238+		case '\\':
1239+			if ((c = *++p) == '\0')
1240+				return 1;
1241+			if (!isdigit(c))
1242+				goto copy_char;
1243+			sub = c - '0';
1244+		copy_match:
1245+			q   = lastmatch + matchs[sub].rm_so;
1246+			end = lastmatch + matchs[sub].rm_eo;
1247+			while (q < end)
1248+				addchar(*q++, s);
1249+			break;
1250+		default:
1251+		copy_char:
1252+			addchar(c, s);
1253+			break;
1254+		}
1255+	}
1256+	return 1;
1257+}
1258+
1259+static void
1260+subline(int num, int nth)
1261+{
1262+	int i, m, changed;
1263+	static String s;
1264+
1265+	string(&s);
1266+	i = changed = 0;
1267+	for (m = match(num); m; m = (nth < 0 || i < nth) && rematch(num)) {
1268+		chksignals();
1269+		addpre(&s);
1270+		changed |= addsub(&s, nth, ++i);
1271+	}
1272+	if (!changed)
1273+		return;
1274+	addpost(&s);
1275+	delete(num, num);
1276+	curln = prevln(num);
1277+	inject(s.str, AFTER);
1278+}
1279+
1280+static void
1281+subst(int nth)
1282+{
1283+	int i, line, next;
1284+
1285+	line = line1;
1286+	for (i = 0; i < line2 - line1 + 1; i++) {
1287+		chksignals();
1288+
1289+		next = getindex(nextln(line));
1290+		subline(line, nth);
1291+
1292+		/*
1293+		 * The substitution command can add lines, so
1294+		 * we have to skip lines until we find the
1295+		 * index that we saved before the substitution
1296+		 */
1297+		do
1298+			line = nextln(line);
1299+		while (getindex(line) != next);
1300+	}
1301+}
1302+
1303+static void
1304+docmd(void)
1305+{
1306+	char *var;
1307+	int cmd, c, line3, num, trunc;
1308+
1309+repeat:
1310+	skipblank();
1311+	cmd = input();
1312+	trunc = pflag = 0;
1313+	switch (cmd) {
1314+	case '&':
1315+		skipblank();
1316+		chkprint(0);
1317+		if (!ocmdline)
1318+			error("no previous command");
1319+		setinput(ocmdline);
1320+		getlst();
1321+		goto repeat;
1322+	case '!':
1323+		execsh();
1324+		break;
1325+	case '\0':
1326+		num = gflag ? curln : curln+1;
1327+		deflines(num, num);
1328+		line1 = line2;
1329+		pflag = 'p';
1330+		goto print;
1331+	case 'l':
1332+	case 'n':
1333+	case 'p':
1334+		back(cmd);
1335+		chkprint(1);
1336+		deflines(curln, curln);
1337+		goto print;
1338+	case 'g':
1339+	case 'G':
1340+	case 'v':
1341+	case 'V':
1342+		error("cannot nest global commands");
1343+	case 'H':
1344+		if (nlines > 0)
1345+			goto unexpected;
1346+		chkprint(0);
1347+		optverbose ^= 1;
1348+		break;
1349+	case 'h':
1350+		if (nlines > 0)
1351+			goto unexpected;
1352+		chkprint(0);
1353+		dohelp();
1354+		break;
1355+	case 'w':
1356+		trunc = 1;
1357+	case 'W':
1358+		ensureblank();
1359+		deflines(nextln(0), lastln);
1360+		dowrite(getfname(cmd), trunc);
1361+		break;
1362+	case 'r':
1363+		ensureblank();
1364+		if (nlines > 1)
1365+			goto bad_address;
1366+		deflines(lastln, lastln);
1367+		doread(getfname(cmd));
1368+		break;
1369+	case 'd':
1370+		chkprint(1);
1371+		deflines(curln, curln);
1372+		delete(line1, line2);
1373+		break;
1374+	case '=':
1375+		if (nlines > 1)
1376+			goto bad_address;
1377+		chkprint(1);
1378+		deflines(lastln, lastln);
1379+		printf("%d\n", line1);
1380+		break;
1381+	case 'u':
1382+		if (nlines > 0)
1383+			goto bad_address;
1384+		chkprint(1);
1385+		if (udata.nr == 0)
1386+			error("nothing to undo");
1387+		undo();
1388+		break;
1389+	case 's':
1390+		deflines(curln, curln);
1391+		c = input();
1392+		compile(c);
1393+		getrhs(c);
1394+		num = getnth();
1395+		chkprint(1);
1396+		subst(num);
1397+		break;
1398+	case 'i':
1399+		if (nlines > 1)
1400+			goto bad_address;
1401+		chkprint(1);
1402+		deflines(curln, curln);
1403+		if (!line1)
1404+			line1++;
1405+		append(prevln(line1));
1406+		break;
1407+	case 'a':
1408+		if (nlines > 1)
1409+			goto bad_address;
1410+		chkprint(1);
1411+		deflines(curln, curln);
1412+		append(line1);
1413+		break;
1414+	case 'm':
1415+		deflines(curln, curln);
1416+		if (!address(&line3))
1417+			line3 = curln;
1418+		chkprint(1);
1419+		move(line3);
1420+		break;
1421+	case 't':
1422+		deflines(curln, curln);
1423+		if (!address(&line3))
1424+			line3 = curln;
1425+		chkprint(1);
1426+		copy(line3);
1427+		break;
1428+	case 'c':
1429+		chkprint(1);
1430+		deflines(curln, curln);
1431+		delete(line1, line2);
1432+		append(prevln(line1));
1433+		break;
1434+	case 'j':
1435+		chkprint(1);
1436+		deflines(curln, curln+1);
1437+		if (line1 != line2 && curln != 0)
1438+	      		join();
1439+		break;
1440+	case 'z':
1441+		if (nlines > 1)
1442+			goto bad_address;
1443+
1444+		num = 0;
1445+		if (isdigit(back(input())))
1446+			num = getnum();
1447+		else if ((var = getenv("LINES")) != NULL)
1448+			num = atoi(var) - 1;
1449+		if (num <= 0)
1450+			num = 23;
1451+		chkprint(1);
1452+		deflines(curln, curln);
1453+		scroll(num);
1454+		break;
1455+	case 'k':
1456+		if (nlines > 1)
1457+			goto bad_address;
1458+		if (!islower(c = input()))
1459+			error("invalid mark character");
1460+		chkprint(1);
1461+		deflines(curln, curln);
1462+		marks[c - 'a'] = line1;
1463+		break;
1464+	case 'P':
1465+		if (nlines > 0)
1466+			goto unexpected;
1467+		chkprint(1);
1468+		optprompt ^= 1;
1469+		break;
1470+	case 'x':
1471+		trunc = 1;
1472+	case 'X':
1473+		ensureblank();
1474+		if (nlines > 0)
1475+			goto unexpected;
1476+		exstatus = 0;
1477+		deflines(nextln(0), lastln);
1478+		dowrite(getfname(cmd), trunc);
1479+	case 'Q':
1480+	case 'q':
1481+		if (nlines > 0)
1482+			goto unexpected;
1483+		if (cmd != 'Q' && modflag)
1484+			goto modified;
1485+		modflag = 0;
1486+		quit();
1487+		break;
1488+	case 'f':
1489+		ensureblank();
1490+		if (nlines > 0)
1491+			goto unexpected;
1492+		if (back(input()) != '\0')
1493+			getfname(cmd);
1494+		else
1495+			puts(savfname);
1496+		chkprint(0);
1497+		break;
1498+	case 'E':
1499+	case 'e':
1500+		ensureblank();
1501+		if (nlines > 0)
1502+			goto unexpected;
1503+		if (cmd == 'e' && modflag)
1504+			goto modified;
1505+		setscratch();
1506+		deflines(curln, curln);
1507+		doread(getfname(cmd));
1508+		clearundo();
1509+		modflag = 0;
1510+		break;
1511+	default:
1512+		error("unknown command");
1513+	bad_address:
1514+		error("invalid address");
1515+	modified:
1516+		modflag = 0;
1517+		error("warning: file modified");
1518+	unexpected:
1519+		error("unexpected address");
1520+	}
1521+
1522+	if (!pflag)
1523+		return;
1524+	line1 = line2 = curln;
1525+
1526+print:
1527+	doprint();
1528+}
1529+
1530+static int
1531+chkglobal(void)
1532+{
1533+	int delim, c, dir, i, v;
1534+
1535+	uflag = 1;
1536+	gflag = 0;
1537+	skipblank();
1538+
1539+	switch (c = input()) {
1540+	case 'g':
1541+		uflag = 0;
1542+	case 'G':
1543+		dir = 1;
1544+		break;
1545+	case 'v':
1546+		uflag = 0;
1547+	case 'V':
1548+		dir = 0;
1549+		break;
1550+	default:
1551+		back(c);
1552+		return 0;
1553+	}
1554+	gflag = 1;
1555+	deflines(nextln(0), lastln);
1556+	delim = input();
1557+	compile(delim);
1558+
1559+	for (i = 1; i <= lastln; ++i) {
1560+		chksignals();
1561+		if (i >= line1 && i <= line2)
1562+			v = match(i) == dir;
1563+		else
1564+			v = 0;
1565+		setglobal(i, v);
1566+	}
1567+
1568+	return 1;
1569+}
1570+
1571+static void
1572+savecmd(void)
1573+{
1574+	int ch;
1575+
1576+	skipblank();
1577+	ch = input();
1578+	if (ch != '&') {
1579+		ocmdline = strdup(cmdline.str);
1580+		if (ocmdline == NULL)
1581+			error("out of memory");
1582+	}
1583+	back(ch);
1584+}
1585+
1586+static void
1587+doglobal(void)
1588+{
1589+	int cnt, ln, k, idx, c;
1590+
1591+	skipblank();
1592+	gflag = 1;
1593+	if (uflag)
1594+		chkprint(0);
1595+
1596+	ln = line1;
1597+	for (cnt = 0; cnt < lastln; ) {
1598+		chksignals();
1599+		k = getindex(ln);
1600+		if (zero[k].global) {
1601+			zero[k].global = 0;
1602+			curln = ln;
1603+			nlines = 0;
1604+
1605+			if (!uflag) {
1606+				idx = inputidx;
1607+				getlst();
1608+				for (;;) {
1609+					docmd();
1610+					if (!(c = input()))
1611+						break;
1612+					back(c);
1613+				}
1614+				inputidx = idx;
1615+				continue;
1616+			}
1617+
1618+			line1 = line2 = ln;
1619+			pflag = 0;
1620+			doprint();
1621+
1622+			for (;;) {
1623+				getinput();
1624+				if (strcmp(cmdline.str, "") == 0)
1625+					break;
1626+				savecmd();
1627+				getlst();
1628+				docmd();
1629+			}
1630+
1631+		} else {
1632+			cnt++;
1633+			ln = nextln(ln);
1634+		}
1635+	}
1636+}
1637+
1638+static void
1639+usage(void)
1640+{
1641+	eprintf("usage: %s [-s] [-p] [file]\n", argv0);
1642+}
1643+
1644+static void
1645+sigintr(int n)
1646+{
1647+	intr = 1;
1648+}
1649+
1650+static void
1651+sighup(int dummy)
1652+{
1653+	hup = 1;
1654+}
1655+
1656+static void
1657+edit(void)
1658+{
1659+	for (;;) {
1660+		newcmd = 1;
1661+		ocurln = curln;
1662+		olastln = lastln;
1663+		if (optprompt) {
1664+			fputs(prompt, stdout);
1665+			fflush(stdout);
1666+		}
1667+
1668+		getinput();
1669+		getlst();
1670+		chkglobal() ? doglobal() : docmd();
1671+	}
1672+}
1673+
1674+static void
1675+init(char *fname)
1676+{
1677+	size_t len;
1678+
1679+	setscratch();
1680+	if (!fname)
1681+		return;
1682+	if ((len = strlen(fname)) >= FILENAME_MAX || len == 0)
1683+		error("incorrect filename");
1684+	memcpy(savfname, fname, len);
1685+	doread(fname);
1686+	clearundo();
1687+}
1688+
1689+int
1690+main(int argc, char *argv[])
1691+{
1692+	ARGBEGIN {
1693+	case 'p':
1694+		prompt = EARGF(usage());
1695+		optprompt = 1;
1696+		break;
1697+	case 's':
1698+		optdiag = 0;
1699+		break;
1700+	default:
1701+		usage();
1702+	} ARGEND
1703+
1704+	if (argc > 1)
1705+		usage();
1706+
1707+	if (!setjmp(savesp)) {
1708+		sigaction(SIGINT,
1709+		          &(struct sigaction) {.sa_handler = sigintr},
1710+		          NULL);
1711+		sigaction(SIGHUP,
1712+		          &(struct sigaction) {.sa_handler = sighup},
1713+		          NULL);
1714+		sigaction(SIGQUIT,
1715+		          &(struct sigaction) {.sa_handler = SIG_IGN},
1716+		          NULL);
1717+		init(*argv);
1718+	}
1719+	edit();
1720+
1721+	/* not reached */
1722+	return 0;
1723+}
+49, -0
 1@@ -0,0 +1,49 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <string.h>
 7+#include <unistd.h>
 8+
 9+#include "util.h"
10+
11+extern char **environ;
12+
13+static void
14+usage(void)
15+{
16+	eprintf("usage: %s [-i] [-u var] ... [var=value] ... [cmd [arg ...]]\n", argv0);
17+}
18+
19+int
20+main(int argc, char *argv[])
21+{
22+	int savederrno;
23+
24+	ARGBEGIN {
25+	case 'i':
26+		*environ = NULL;
27+		break;
28+	case 'u':
29+		if (unsetenv(EARGF(usage())) < 0)
30+			eprintf("unsetenv:");
31+		break;
32+	default:
33+		usage();
34+	} ARGEND
35+
36+	for (; *argv && strchr(*argv, '='); argc--, argv++)
37+		putenv(*argv);
38+
39+	if (*argv) {
40+		execvp(*argv, argv);
41+		savederrno = errno;
42+		weprintf("execvp %s:", *argv);
43+		_exit(126 + (savederrno == ENOENT));
44+	}
45+
46+	for (; *environ; environ++)
47+		puts(*environ);
48+
49+	return fshut(stdout, "<stdout>");
50+}
+131, -0
  1@@ -0,0 +1,131 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <stdint.h>
  4+#include <stdlib.h>
  5+#include <string.h>
  6+
  7+#include "utf.h"
  8+#include "util.h"
  9+
 10+static int     iflag      = 0;
 11+static size_t *tablist    = NULL;
 12+static size_t  tablistlen = 0;
 13+
 14+static size_t
 15+parselist(const char *s)
 16+{
 17+	size_t i;
 18+	char  *p, *tmp;
 19+
 20+	tmp = estrdup(s);
 21+	for (i = 0; (p = strsep(&tmp, " ,")); i++) {
 22+		if (*p == '\0')
 23+			eprintf("empty field in tablist\n");
 24+		tablist = ereallocarray(tablist, i + 1, sizeof(*tablist));
 25+		tablist[i] = estrtonum(p, 1, MIN(LLONG_MAX, SIZE_MAX));
 26+		if (i > 0 && tablist[i - 1] >= tablist[i])
 27+			eprintf("tablist must be ascending\n");
 28+	}
 29+	tablist = ereallocarray(tablist, i + 1, sizeof(*tablist));
 30+	/* tab length = 1 for the overflowing case later in the matcher */
 31+	tablist[i] = 1;
 32+
 33+	return i;
 34+}
 35+
 36+static int
 37+expand(const char *file, FILE *fp)
 38+{
 39+	size_t bol = 1, col = 0, i;
 40+	Rune r;
 41+
 42+	while (efgetrune(&r, fp, file)) {
 43+		switch (r) {
 44+		case '\t':
 45+			if (tablistlen == 1)
 46+				i = 0;
 47+			else for (i = 0; i < tablistlen; i++)
 48+				if (col < tablist[i])
 49+					break;
 50+			if (bol || !iflag) {
 51+				do {
 52+					col++;
 53+					putchar(' ');
 54+				} while (col % tablist[i]);
 55+			} else {
 56+				putchar('\t');
 57+				col = tablist[i];
 58+			}
 59+			break;
 60+		case '\b':
 61+			bol = 0;
 62+			if (col)
 63+				col--;
 64+			putchar('\b');
 65+			break;
 66+		case '\n':
 67+			bol = 1;
 68+			col = 0;
 69+			putchar('\n');
 70+			break;
 71+		default:
 72+			col++;
 73+			if (r != ' ')
 74+				bol = 0;
 75+			efputrune(&r, stdout, "<stdout>");
 76+			break;
 77+		}
 78+	}
 79+
 80+	return 0;
 81+}
 82+
 83+static void
 84+usage(void)
 85+{
 86+	eprintf("usage: %s [-i] [-t tablist] [file ...]\n", argv0);
 87+}
 88+
 89+int
 90+main(int argc, char *argv[])
 91+{
 92+	FILE *fp;
 93+	int ret = 0;
 94+	char *tl = "8";
 95+
 96+	ARGBEGIN {
 97+	case 'i':
 98+		iflag = 1;
 99+		break;
100+	case 't':
101+		tl = EARGF(usage());
102+		if (!*tl)
103+			eprintf("tablist cannot be empty\n");
104+		break;
105+	default:
106+		usage();
107+	} ARGEND
108+
109+	tablistlen = parselist(tl);
110+
111+	if (!argc) {
112+		expand("<stdin>", stdin);
113+	} else {
114+		for (; *argv; argc--, argv++) {
115+			if (!strcmp(*argv, "-")) {
116+				*argv = "<stdin>";
117+				fp = stdin;
118+			} else if (!(fp = fopen(*argv, "r"))) {
119+				weprintf("fopen %s:", *argv);
120+				ret = 1;
121+				continue;
122+			}
123+			expand(*argv, fp);
124+			if (fp != stdin && fshut(fp, *argv))
125+				ret = 1;
126+		}
127+	}
128+
129+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
130+
131+	return ret;
132+}
+244, -0
  1@@ -0,0 +1,244 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <limits.h>
  4+#include <stdio.h>
  5+#include <stdlib.h>
  6+#include <string.h>
  7+
  8+#include "utf.h"
  9+#include "util.h"
 10+
 11+/* tokens, one-character operators represent themselves */
 12+enum {
 13+	VAL = CHAR_MAX + 1, GE, LE, NE
 14+};
 15+
 16+struct val {
 17+	char *str;
 18+	long long num;
 19+};
 20+
 21+static void
 22+tonum(struct val *v)
 23+{
 24+	const char *errstr;
 25+	long long d;
 26+
 27+	/* check if val is the result of an earlier calculation */
 28+	if (!v->str)
 29+		return;
 30+
 31+	d = strtonum(v->str, LLONG_MIN, LLONG_MAX, &errstr);
 32+	if (errstr)
 33+		enprintf(2, "error: expected integer, got %s\n", v->str);
 34+	v->num = d;
 35+}
 36+
 37+static void
 38+ezero(struct val *v)
 39+{
 40+	if (v->num != 0)
 41+		return;
 42+	enprintf(2, "division by zero\n");
 43+}
 44+
 45+static int
 46+valcmp(struct val *a, struct val *b)
 47+{
 48+	int ret;
 49+	const char *err1, *err2;
 50+	long long d1, d2;
 51+
 52+	d1 = strtonum(a->str, LLONG_MIN, LLONG_MAX, &err1);
 53+	d2 = strtonum(b->str, LLONG_MIN, LLONG_MAX, &err2);
 54+
 55+	if (!err1 && !err2) {
 56+		ret = (d1 > d2) - (d1 < d2);
 57+	} else {
 58+		ret = strcmp(a->str, b->str);
 59+	}
 60+
 61+	return ret;
 62+}
 63+
 64+static void
 65+match(struct val *vstr, struct val *vregx, struct val *ret)
 66+{
 67+	regex_t re;
 68+	regmatch_t matches[2];
 69+	size_t anchlen;
 70+	char *s, *p, *anchreg;
 71+	char *str = vstr->str, *regx = vregx->str;
 72+
 73+	/* anchored regex */
 74+	anchlen = strlen(regx) + 1 + 1;
 75+	anchreg = emalloc(anchlen);
 76+	estrlcpy(anchreg, "^", anchlen);
 77+	estrlcat(anchreg, regx, anchlen);
 78+	enregcomp(3, &re, anchreg, 0);
 79+	free(anchreg);
 80+
 81+	if (regexec(&re, str, 2, matches, 0)) {
 82+		regfree(&re);
 83+		ret->str = re.re_nsub ? "" : NULL;
 84+		return;
 85+	} else if (re.re_nsub) {
 86+		regfree(&re);
 87+
 88+		s = str + matches[1].rm_so;
 89+		p = str + matches[1].rm_eo;
 90+		*p = '\0';
 91+		ret->str = enstrdup(3, s);
 92+		return;
 93+	} else {
 94+		regfree(&re);
 95+		str += matches[0].rm_so;
 96+		ret->num = utfnlen(str, matches[0].rm_eo - matches[0].rm_so);
 97+		return;
 98+	}
 99+}
100+
101+static void
102+doop(int *ophead, int *opp, struct val *valhead, struct val *valp)
103+{
104+	struct val ret = { .str = NULL, .num = 0 }, *a, *b;
105+	int op;
106+
107+	/* an operation "a op b" needs an operator and two values */
108+	if (opp[-1] == '(')
109+		enprintf(2, "syntax error: extra (\n");
110+	if (valp - valhead < 2)
111+		enprintf(2, "syntax error: missing expression or extra operator\n");
112+
113+	a = valp - 2;
114+	b = valp - 1;
115+	op = opp[-1];
116+
117+	switch (op) {
118+	case '|':
119+		if      ( a->str && *a->str) ret.str = a->str;
120+		else if (!a->str &&  a->num) ret.num = a->num;
121+		else if ( b->str && *b->str) ret.str = b->str;
122+		else                         ret.num = b->num;
123+		break;
124+	case '&':
125+		if (((a->str && *a->str) || a->num) &&
126+		    ((b->str && *b->str) || b->num)) {
127+			ret.str = a->str;
128+			ret.num = a->num;
129+		}
130+		break;
131+
132+	case '=': ret.num = (valcmp(a, b) == 0); break;
133+	case '>': ret.num = (valcmp(a, b) >  0); break;
134+	case GE : ret.num = (valcmp(a, b) >= 0); break;
135+	case '<': ret.num = (valcmp(a, b) <  0); break;
136+	case LE : ret.num = (valcmp(a, b) <= 0); break;
137+	case NE : ret.num = (valcmp(a, b) != 0); break;
138+
139+	case '+': tonum(a); tonum(b);           ret.num = a->num + b->num; break;
140+	case '-': tonum(a); tonum(b);           ret.num = a->num - b->num; break;
141+	case '*': tonum(a); tonum(b);           ret.num = a->num * b->num; break;
142+	case '/': tonum(a); tonum(b); ezero(b); ret.num = a->num / b->num; break;
143+	case '%': tonum(a); tonum(b); ezero(b); ret.num = a->num % b->num; break;
144+
145+	case ':': match(a, b, &ret); break;
146+	}
147+
148+	valp[-2] = ret;
149+}
150+
151+static int
152+lex(char *s, struct val *v)
153+{
154+	int type = VAL;
155+	char *ops = "|&=><+-*/%():";
156+
157+	if (s[0] && strchr(ops, s[0]) && !s[1]) {
158+		/* one-char operand */
159+		type = s[0];
160+	} else if (s[0] && strchr("><!", s[0]) && s[1] == '=' && !s[2]) {
161+		/* two-char operand */
162+		type = (s[0] == '>') ? GE : (s[0] == '<') ? LE : NE;
163+	}
164+
165+	return type;
166+}
167+
168+static int
169+parse(char *expr[], int numexpr)
170+{
171+	struct val *valhead, *valp, v = { .str = NULL, .num = 0 };
172+	int *ophead, *opp, type, lasttype = 0;
173+	char prec[] = {
174+		[ 0 ] = 0, [VAL] = 0, ['('] = 0, [')'] = 0,
175+		['|'] = 1,
176+		['&'] = 2,
177+		['='] = 3, ['>'] = 3, [GE] = 3, ['<'] = 3, [LE] = 3, [NE] = 3,
178+		['+'] = 4, ['-'] = 4,
179+		['*'] = 5, ['/'] = 5, ['%'] = 5,
180+		[':'] = 6,
181+	};
182+
183+	valp = valhead = enreallocarray(3, NULL, numexpr, sizeof(*valp));
184+	opp = ophead = enreallocarray(3, NULL, numexpr, sizeof(*opp));
185+	for (; *expr; expr++) {
186+		switch ((type = lex(*expr, &v))) {
187+		case VAL:
188+			/* treatment of *expr is not known until
189+			 * doop(); treat as a string for now */
190+			valp->str = *expr;
191+			valp++;
192+			break;
193+		case '(':
194+			*opp++ = type;
195+			break;
196+		case ')':
197+			if (lasttype == '(')
198+				enprintf(2, "syntax error: empty ( )\n");
199+			while (opp > ophead && opp[-1] != '(')
200+				doop(ophead, opp--, valhead, valp--);
201+			if (opp == ophead)
202+				enprintf(2, "syntax error: extra )\n");
203+			opp--;
204+			break;
205+		default: /* operator */
206+			if (prec[lasttype])
207+				enprintf(2, "syntax error: extra operator\n");
208+			while (opp > ophead && prec[opp[-1]] >= prec[type])
209+				doop(ophead, opp--, valhead, valp--);
210+			*opp++ = type;
211+			break;
212+		}
213+		lasttype = type;
214+		v.str = NULL;
215+		v.num = 0;
216+	}
217+	while (opp > ophead)
218+		doop(ophead, opp--, valhead, valp--);
219+	if (valp == valhead)
220+		enprintf(2, "syntax error: missing expression\n");
221+	if (--valp > valhead)
222+		enprintf(2, "syntax error: extra expression\n");
223+
224+	if (valp->str)
225+		puts(valp->str);
226+	else
227+		printf("%lld\n", valp->num);
228+
229+	return (valp->str && *valp->str) || valp->num;
230+}
231+
232+int
233+main(int argc, char *argv[])
234+{
235+	int ret;
236+
237+	argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
238+
239+	ret = !parse(argv, argc);
240+
241+	if (fshut(stdout, "<stdout>"))
242+		ret = 3;
243+
244+	return ret;
245+}
+6, -0
1@@ -0,0 +1,6 @@
2+/* See LICENSE file for copyright and license details. */
3+int
4+main(void)
5+{
6+	return 1;
7+}
+1103, -0
   1@@ -0,0 +1,1103 @@
   2+/* See LICENSE file for copyright and license details. */
   3+#include <dirent.h>
   4+#include <errno.h>
   5+#include <fnmatch.h>
   6+#include <grp.h>
   7+#include <libgen.h>
   8+#include <pwd.h>
   9+#include <stdint.h>
  10+#include <stdio.h>
  11+#include <stdlib.h>
  12+#include <string.h>
  13+#include <time.h>
  14+#include <unistd.h>
  15+
  16+#include <sys/stat.h>
  17+#include <sys/wait.h>
  18+
  19+#include "util.h"
  20+
  21+/* because putting integers in pointers is undefined by the standard */
  22+union extra {
  23+	void    *p;
  24+	intmax_t i;
  25+};
  26+
  27+/* Argument passed into a primary's function */
  28+struct arg {
  29+	char        *path;
  30+	struct stat *st;
  31+	union extra  extra;
  32+};
  33+
  34+/* Information about each primary, for lookup table */
  35+struct pri_info {
  36+	char  *name;
  37+	int    (*func)(struct arg *arg);
  38+	char **(*getarg)(char **argv, union extra *extra);
  39+	void   (*freearg)(union extra extra);
  40+	char   narg; /* -xdev, -depth, -print don't take args but have getarg() */
  41+};
  42+
  43+/* Information about operators, for lookup table */
  44+struct op_info {
  45+	char *name;   /* string representation of op           */
  46+	char  type;   /* from tok.type                         */
  47+	char  prec;   /* precedence                            */
  48+	char  nargs;  /* number of arguments (unary or binary) */
  49+	char  lassoc; /* left associative                      */
  50+};
  51+
  52+/* Token when lexing/parsing
  53+ * (although also used for the expression tree) */
  54+struct tok {
  55+	struct tok *left, *right; /* if (type == NOT) left = NULL */
  56+	union extra extra;
  57+	union {
  58+		struct pri_info *pinfo; /* if (type == PRIM) */
  59+		struct op_info  *oinfo;
  60+	} u;
  61+	enum {
  62+		PRIM = 0, LPAR, RPAR, NOT, AND, OR, END
  63+	} type;
  64+};
  65+
  66+/* structures used for arg.extra.p and tok.extra.p */
  67+struct permarg {
  68+	mode_t mode;
  69+	char   exact;
  70+};
  71+
  72+struct okarg {
  73+	char ***braces;
  74+	char **argv;
  75+};
  76+
  77+/* for all arguments that take a number
  78+ * +n, n, -n mean > n, == n, < n respectively */
  79+struct narg {
  80+	int (*cmp)(int a, int b);
  81+	int n;
  82+};
  83+
  84+struct sizearg {
  85+	struct narg n;
  86+	char bytes; /* size is in bytes, not 512 byte sectors */
  87+};
  88+
  89+struct execarg {
  90+	union {
  91+		struct {
  92+			char ***braces; /* NULL terminated list of pointers into argv where {} were */
  93+		} s; /* semicolon */
  94+		struct {
  95+			size_t arglen;  /* number of bytes in argv before files are added */
  96+			size_t filelen; /* numer of bytes in file names added to argv     */
  97+			size_t first;   /* index one past last arg, where first file goes */
  98+			size_t next;    /* index where next file goes                     */
  99+			size_t cap;     /* capacity of argv                               */
 100+		} p; /* plus */
 101+	} u;
 102+	char **argv; /* NULL terminated list of arguments (allocated if isplus) */
 103+	char   isplus; /* -exec + instead of -exec ; */
 104+};
 105+
 106+/* used to find loops while recursing through directory structure */
 107+struct findhist {
 108+	struct findhist *next;
 109+	char *path;
 110+	dev_t dev;
 111+	ino_t ino;
 112+};
 113+
 114+/* Utility */
 115+static int spawn(char *argv[]);
 116+static int do_stat(char *path, struct stat *sb, struct findhist *hist);
 117+
 118+/* Primaries */
 119+static int pri_name   (struct arg *arg);
 120+static int pri_path   (struct arg *arg);
 121+static int pri_nouser (struct arg *arg);
 122+static int pri_nogroup(struct arg *arg);
 123+static int pri_xdev   (struct arg *arg);
 124+static int pri_prune  (struct arg *arg);
 125+static int pri_perm   (struct arg *arg);
 126+static int pri_type   (struct arg *arg);
 127+static int pri_links  (struct arg *arg);
 128+static int pri_user   (struct arg *arg);
 129+static int pri_group  (struct arg *arg);
 130+static int pri_size   (struct arg *arg);
 131+static int pri_atime  (struct arg *arg);
 132+static int pri_ctime  (struct arg *arg);
 133+static int pri_mtime  (struct arg *arg);
 134+static int pri_exec   (struct arg *arg);
 135+static int pri_ok     (struct arg *arg);
 136+static int pri_print  (struct arg *arg);
 137+static int pri_print0 (struct arg *arg);
 138+static int pri_newer  (struct arg *arg);
 139+static int pri_depth  (struct arg *arg);
 140+
 141+/* Getargs */
 142+static char **get_name_arg (char *argv[], union extra *extra);
 143+static char **get_path_arg (char *argv[], union extra *extra);
 144+static char **get_xdev_arg (char *argv[], union extra *extra);
 145+static char **get_perm_arg (char *argv[], union extra *extra);
 146+static char **get_type_arg (char *argv[], union extra *extra);
 147+static char **get_n_arg    (char *argv[], union extra *extra);
 148+static char **get_user_arg (char *argv[], union extra *extra);
 149+static char **get_group_arg(char *argv[], union extra *extra);
 150+static char **get_size_arg (char *argv[], union extra *extra);
 151+static char **get_exec_arg (char *argv[], union extra *extra);
 152+static char **get_ok_arg   (char *argv[], union extra *extra);
 153+static char **get_print_arg(char *argv[], union extra *extra);
 154+static char **get_newer_arg(char *argv[], union extra *extra);
 155+static char **get_depth_arg(char *argv[], union extra *extra);
 156+
 157+/* Freeargs */
 158+static void free_extra   (union extra extra);
 159+static void free_exec_arg(union extra extra);
 160+static void free_ok_arg  (union extra extra);
 161+
 162+/* Parsing/Building/Running */
 163+static void fill_narg(char *s, struct narg *n);
 164+static struct pri_info *find_primary(char *name);
 165+static struct op_info *find_op(char *name);
 166+static void parse(int argc, char **argv);
 167+static int eval(struct tok *tok, struct arg *arg);
 168+static void find(char *path, struct findhist *hist);
 169+static void usage(void);
 170+
 171+/* for comparisons with narg */
 172+static int cmp_gt(int a, int b) { return a >  b; }
 173+static int cmp_eq(int a, int b) { return a == b; }
 174+static int cmp_lt(int a, int b) { return a <  b; }
 175+
 176+/* order from find(1p), may want to alphabetize */
 177+static struct pri_info primaries[] = {
 178+	{ "-name"   , pri_name   , get_name_arg , NULL         , 1 },
 179+	{ "-path"   , pri_path   , get_path_arg , NULL         , 1 },
 180+	{ "-nouser" , pri_nouser , NULL         , NULL         , 1 },
 181+	{ "-nogroup", pri_nogroup, NULL         , NULL         , 1 },
 182+	{ "-xdev"   , pri_xdev   , get_xdev_arg , NULL         , 0 },
 183+	{ "-prune"  , pri_prune  , NULL         , NULL         , 1 },
 184+	{ "-perm"   , pri_perm   , get_perm_arg , free_extra   , 1 },
 185+	{ "-type"   , pri_type   , get_type_arg , NULL         , 1 },
 186+	{ "-links"  , pri_links  , get_n_arg    , free_extra   , 1 },
 187+	{ "-user"   , pri_user   , get_user_arg , NULL         , 1 },
 188+	{ "-group"  , pri_group  , get_group_arg, NULL         , 1 },
 189+	{ "-size"   , pri_size   , get_size_arg , free_extra   , 1 },
 190+	{ "-atime"  , pri_atime  , get_n_arg    , free_extra   , 1 },
 191+	{ "-ctime"  , pri_ctime  , get_n_arg    , free_extra   , 1 },
 192+	{ "-mtime"  , pri_mtime  , get_n_arg    , free_extra   , 1 },
 193+	{ "-exec"   , pri_exec   , get_exec_arg , free_exec_arg, 1 },
 194+	{ "-ok"     , pri_ok     , get_ok_arg   , free_ok_arg  , 1 },
 195+	{ "-print"  , pri_print  , get_print_arg, NULL         , 0 },
 196+	{ "-print0" , pri_print0 , get_print_arg, NULL         , 0 },
 197+	{ "-newer"  , pri_newer  , get_newer_arg, NULL         , 1 },
 198+	{ "-depth"  , pri_depth  , get_depth_arg, NULL         , 0 },
 199+
 200+	{ NULL, NULL, NULL, NULL, 0 }
 201+};
 202+
 203+static struct op_info ops[] = {
 204+	{ "(" , LPAR, 0, 0, 0 }, /* parens are handled specially */
 205+	{ ")" , RPAR, 0, 0, 0 },
 206+	{ "!" , NOT , 3, 1, 0 },
 207+	{ "-a", AND , 2, 2, 1 },
 208+	{ "-o", OR  , 1, 2, 1 },
 209+
 210+	{ NULL, 0, 0, 0, 0 }
 211+};
 212+
 213+extern char **environ;
 214+
 215+static struct tok *toks; /* holds allocated array of all toks created while parsing */
 216+static struct tok *root; /* points to root of expression tree, inside toks array */
 217+
 218+static struct timespec start; /* time find was started, used for -[acm]time */
 219+
 220+static size_t envlen; /* number of bytes in environ, used to calculate against ARG_MAX */
 221+static size_t argmax; /* value of ARG_MAX retrieved using sysconf(3p) */
 222+
 223+static struct {
 224+	char ret  ; /* return value from main                             */
 225+	char depth; /* -depth, directory contents before directory itself */
 226+	char h    ; /* -H, follow symlinks on command line                */
 227+	char l    ; /* -L, follow all symlinks (command line and search)  */
 228+	char prune; /* hit -prune                                         */
 229+	char xdev ; /* -xdev, prune directories on different devices      */
 230+	char print; /* whether we will need -print when parsing           */
 231+} gflags;
 232+
 233+/*
 234+ * Utility
 235+ */
 236+static int
 237+spawn(char *argv[])
 238+{
 239+	pid_t pid;
 240+	int status;
 241+
 242+	/* flush stdout so that -print output always appears before
 243+	 * any output from the command and does not get cut-off in
 244+	 * the middle of a line. */
 245+	fflush(stdout);
 246+
 247+	switch((pid = fork())) {
 248+	case -1:
 249+		eprintf("fork:");
 250+	case 0:
 251+		execvp(*argv, argv);
 252+		weprintf("exec %s failed:", *argv);
 253+		_exit(1);
 254+	}
 255+
 256+	/* FIXME: proper course of action for waitpid() on EINTR? */
 257+	waitpid(pid, &status, 0);
 258+	return status;
 259+}
 260+
 261+static int
 262+do_stat(char *path, struct stat *sb, struct findhist *hist)
 263+{
 264+	if (gflags.l || (gflags.h && !hist)) {
 265+		if (stat(path, sb) == 0) {
 266+			return 0;
 267+		} else if (errno != ENOENT && errno != ENOTDIR) {
 268+			return -1;
 269+		}
 270+	}
 271+
 272+	return lstat(path, sb);
 273+}
 274+
 275+/*
 276+ * Primaries
 277+ */
 278+static int
 279+pri_name(struct arg *arg)
 280+{
 281+	int ret;
 282+	char *path;
 283+
 284+	path = estrdup(arg->path);
 285+	ret = !fnmatch((char *)arg->extra.p, basename(path), 0);
 286+	free(path);
 287+
 288+	return ret;
 289+}
 290+
 291+static int
 292+pri_path(struct arg *arg)
 293+{
 294+	return !fnmatch((char *)arg->extra.p, arg->path, 0);
 295+}
 296+
 297+/* FIXME: what about errors? find(1p) literally just says
 298+ * "for which the getpwuid() function ... returns NULL" */
 299+static int
 300+pri_nouser(struct arg *arg)
 301+{
 302+	return !getpwuid(arg->st->st_uid);
 303+}
 304+
 305+static int
 306+pri_nogroup(struct arg *arg)
 307+{
 308+	return !getgrgid(arg->st->st_gid);
 309+}
 310+
 311+static int
 312+pri_xdev(struct arg *arg)
 313+{
 314+	return 1;
 315+}
 316+
 317+static int
 318+pri_prune(struct arg *arg)
 319+{
 320+	return gflags.prune = 1;
 321+}
 322+
 323+static int
 324+pri_perm(struct arg *arg)
 325+{
 326+	struct permarg *p = (struct permarg *)arg->extra.p;
 327+
 328+	return (arg->st->st_mode & 07777 & (p->exact ? -1U : p->mode)) == p->mode;
 329+}
 330+
 331+static int
 332+pri_type(struct arg *arg)
 333+{
 334+	switch ((char)arg->extra.i) {
 335+	default : return 0; /* impossible, but placate warnings */
 336+	case 'b': return S_ISBLK (arg->st->st_mode);
 337+	case 'c': return S_ISCHR (arg->st->st_mode);
 338+	case 'd': return S_ISDIR (arg->st->st_mode);
 339+	case 'l': return S_ISLNK (arg->st->st_mode);
 340+	case 'p': return S_ISFIFO(arg->st->st_mode);
 341+	case 'f': return S_ISREG (arg->st->st_mode);
 342+	case 's': return S_ISSOCK(arg->st->st_mode);
 343+	}
 344+}
 345+
 346+static int
 347+pri_links(struct arg *arg)
 348+{
 349+	struct narg *n = arg->extra.p;
 350+	return n->cmp(arg->st->st_nlink, n->n);
 351+}
 352+
 353+static int
 354+pri_user(struct arg *arg)
 355+{
 356+	return arg->st->st_uid == (uid_t)arg->extra.i;
 357+}
 358+
 359+static int
 360+pri_group(struct arg *arg)
 361+{
 362+	return arg->st->st_gid == (gid_t)arg->extra.i;
 363+}
 364+
 365+static int
 366+pri_size(struct arg *arg)
 367+{
 368+	struct sizearg *s = arg->extra.p;
 369+	off_t size = arg->st->st_size;
 370+
 371+	if (!s->bytes)
 372+		size = size / 512 + !!(size % 512);
 373+
 374+	return s->n.cmp(size, s->n.n);
 375+}
 376+
 377+/* FIXME: ignoring nanoseconds in atime, ctime, mtime */
 378+static int
 379+pri_atime(struct arg *arg)
 380+{
 381+	struct narg *n = arg->extra.p;
 382+	return n->cmp((start.tv_sec - arg->st->st_atime) / 86400, n->n);
 383+}
 384+
 385+static int
 386+pri_ctime(struct arg *arg)
 387+{
 388+	struct narg *n = arg->extra.p;
 389+	return n->cmp((start.tv_sec - arg->st->st_ctime) / 86400, n->n);
 390+}
 391+
 392+static int
 393+pri_mtime(struct arg *arg)
 394+{
 395+	struct narg *n = arg->extra.p;
 396+	return n->cmp((start.tv_sec - arg->st->st_mtime) / 86400, n->n);
 397+}
 398+
 399+static int
 400+pri_exec(struct arg *arg)
 401+{
 402+	int status;
 403+	size_t len;
 404+	char **sp, ***brace;
 405+	struct execarg *e = arg->extra.p;
 406+
 407+	if (e->isplus) {
 408+		len = strlen(arg->path) + 1;
 409+
 410+		/* if we reached ARG_MAX, fork, exec, wait, free file names, reset list */
 411+		if (len + e->u.p.arglen + e->u.p.filelen + envlen > argmax) {
 412+			e->argv[e->u.p.next] = NULL;
 413+
 414+			status = spawn(e->argv);
 415+			gflags.ret = gflags.ret || status;
 416+
 417+			for (sp = e->argv + e->u.p.first; *sp; sp++)
 418+				free(*sp);
 419+
 420+			e->u.p.next = e->u.p.first;
 421+			e->u.p.filelen = 0;
 422+		}
 423+
 424+		/* if we have too many files, realloc (with space for NULL termination) */
 425+		if (e->u.p.next + 1 == e->u.p.cap)
 426+			e->argv = ereallocarray(e->argv, e->u.p.cap *= 2, sizeof(*e->argv));
 427+
 428+		e->argv[e->u.p.next++] = estrdup(arg->path);
 429+		e->u.p.filelen += len + sizeof(arg->path);
 430+
 431+		return 1;
 432+	} else {
 433+		/* insert path everywhere user gave us {} */
 434+		for (brace = e->u.s.braces; *brace; brace++)
 435+			**brace = arg->path;
 436+
 437+		status = spawn(e->argv);
 438+		return !status;
 439+	}
 440+}
 441+
 442+static int
 443+pri_ok(struct arg *arg)
 444+{
 445+	int status, reply;
 446+	char ***brace, c;
 447+	struct okarg *o = arg->extra.p;
 448+
 449+	fprintf(stderr, "%s: %s ? ", *o->argv, arg->path);
 450+	reply = fgetc(stdin);
 451+
 452+	/* throw away rest of line */
 453+	while ((c = fgetc(stdin)) != '\n' && c != EOF)
 454+		/* FIXME: what if the first character of the rest of the line is a null
 455+		 * byte? */
 456+		;
 457+
 458+	if (feof(stdin)) /* FIXME: ferror()? */
 459+		clearerr(stdin);
 460+
 461+	if (reply != 'y' && reply != 'Y')
 462+		return 0;
 463+
 464+	/* insert filename everywhere user gave us {} */
 465+	for (brace = o->braces; *brace; brace++)
 466+		**brace = arg->path;
 467+
 468+	status = spawn(o->argv);
 469+	return !!status;
 470+}
 471+
 472+static int
 473+pri_print(struct arg *arg)
 474+{
 475+	if (puts(arg->path) == EOF)
 476+		eprintf("puts failed:");
 477+	return 1;
 478+}
 479+
 480+static int
 481+pri_print0(struct arg *arg)
 482+{
 483+	if (fwrite(arg->path, strlen(arg->path) + 1, 1, stdout) != 1)
 484+		eprintf("fwrite failed:");
 485+	return 1;
 486+}
 487+
 488+/* FIXME: ignoring nanoseconds */
 489+static int
 490+pri_newer(struct arg *arg)
 491+{
 492+	return arg->st->st_mtime > (time_t)arg->extra.i;
 493+}
 494+
 495+static int
 496+pri_depth(struct arg *arg)
 497+{
 498+	return 1;
 499+}
 500+
 501+/*
 502+ * Getargs
 503+ * consume any arguments for given primary and fill extra
 504+ * return pointer to last argument, the pointer will be incremented in parse()
 505+ */
 506+static char **
 507+get_name_arg(char *argv[], union extra *extra)
 508+{
 509+	extra->p = *argv;
 510+	return argv;
 511+}
 512+
 513+static char **
 514+get_path_arg(char *argv[], union extra *extra)
 515+{
 516+	extra->p = *argv;
 517+	return argv;
 518+}
 519+
 520+static char **
 521+get_xdev_arg(char *argv[], union extra *extra)
 522+{
 523+	gflags.xdev = 1;
 524+	return argv;
 525+}
 526+
 527+static char **
 528+get_perm_arg(char *argv[], union extra *extra)
 529+{
 530+	mode_t mask;
 531+	struct permarg *p = extra->p = emalloc(sizeof(*p));
 532+
 533+	if (**argv == '-')
 534+		(*argv)++;
 535+	else
 536+		p->exact = 1;
 537+
 538+	mask = umask(0);
 539+	umask(mask);
 540+
 541+	p->mode = parsemode(*argv, 0, mask);
 542+
 543+	return argv;
 544+}
 545+
 546+static char **
 547+get_type_arg(char *argv[], union extra *extra)
 548+{
 549+	if (!strchr("bcdlpfs", **argv))
 550+		eprintf("invalid type %c for -type primary\n", **argv);
 551+
 552+	extra->i = **argv;
 553+	return argv;
 554+}
 555+
 556+static char **
 557+get_n_arg(char *argv[], union extra *extra)
 558+{
 559+	struct narg *n = extra->p = emalloc(sizeof(*n));
 560+	fill_narg(*argv, n);
 561+	return argv;
 562+}
 563+
 564+static char **
 565+get_user_arg(char *argv[], union extra *extra)
 566+{
 567+	char *end;
 568+	struct passwd *p = getpwnam(*argv);
 569+
 570+	if (p) {
 571+		extra->i = p->pw_uid;
 572+	} else {
 573+		extra->i = strtol(*argv, &end, 10);
 574+		if (end == *argv || *end)
 575+			eprintf("unknown user '%s'\n", *argv);
 576+	}
 577+	return argv;
 578+}
 579+
 580+static char **
 581+get_group_arg(char *argv[], union extra *extra)
 582+{
 583+	char *end;
 584+	struct group *g = getgrnam(*argv);
 585+
 586+	if (g) {
 587+		extra->i = g->gr_gid;
 588+	} else {
 589+		extra->i = strtol(*argv, &end, 10);
 590+		if (end == *argv || *end)
 591+			eprintf("unknown group '%s'\n", *argv);
 592+	}
 593+	return argv;
 594+}
 595+
 596+static char **
 597+get_size_arg(char *argv[], union extra *extra)
 598+{
 599+	char *p = *argv + strlen(*argv);
 600+	struct sizearg *s = extra->p = emalloc(sizeof(*s));
 601+	/* if the number is followed by 'c', the size will by in bytes */
 602+	if ((s->bytes = (p > *argv && *--p == 'c')))
 603+		*p = '\0';
 604+
 605+	fill_narg(*argv, &s->n);
 606+	return argv;
 607+}
 608+
 609+static char **
 610+get_exec_arg(char *argv[], union extra *extra)
 611+{
 612+	char **arg, **new, ***braces;
 613+	int nbraces = 0;
 614+	struct execarg *e = extra->p = emalloc(sizeof(*e));
 615+
 616+	for (arg = argv; *arg; arg++)
 617+		if (!strcmp(*arg, ";"))
 618+			break;
 619+		else if (arg > argv && !strcmp(*(arg - 1), "{}") && !strcmp(*arg, "+"))
 620+			break;
 621+		else if (!strcmp(*arg, "{}"))
 622+			nbraces++;
 623+
 624+	if (!*arg)
 625+		eprintf("no terminating ; or {} + for -exec primary\n");
 626+
 627+	e->isplus = **arg == '+';
 628+	*arg = NULL;
 629+
 630+	if (e->isplus) {
 631+		*(arg - 1) = NULL; /* don't need the {} in there now */
 632+		e->u.p.arglen = e->u.p.filelen = 0;
 633+		e->u.p.first = e->u.p.next = arg - argv - 1;
 634+		e->u.p.cap = (arg - argv) * 2;
 635+		e->argv = ereallocarray(NULL, e->u.p.cap, sizeof(*e->argv));
 636+
 637+		for (arg = argv, new = e->argv; *arg; arg++, new++) {
 638+			*new = *arg;
 639+			e->u.p.arglen += strlen(*arg) + 1 + sizeof(*arg);
 640+		}
 641+		arg++; /* due to our extra NULL */
 642+	} else {
 643+		e->argv = argv;
 644+		e->u.s.braces = ereallocarray(NULL, ++nbraces, sizeof(*e->u.s.braces)); /* ++ for NULL */
 645+
 646+		for (arg = argv, braces = e->u.s.braces; *arg; arg++)
 647+			if (!strcmp(*arg, "{}"))
 648+				*braces++ = arg;
 649+		*braces = NULL;
 650+	}
 651+	gflags.print = 0;
 652+	return arg;
 653+}
 654+
 655+static char **
 656+get_ok_arg(char *argv[], union extra *extra)
 657+{
 658+	char **arg, ***braces;
 659+	int nbraces = 0;
 660+	struct okarg *o = extra->p = emalloc(sizeof(*o));
 661+
 662+	for (arg = argv; *arg; arg++)
 663+		if (!strcmp(*arg, ";"))
 664+			break;
 665+		else if (!strcmp(*arg, "{}"))
 666+			nbraces++;
 667+
 668+	if (!*arg)
 669+		eprintf("no terminating ; for -ok primary\n");
 670+	*arg = NULL;
 671+
 672+	o->argv = argv;
 673+	o->braces = ereallocarray(NULL, ++nbraces, sizeof(*o->braces));
 674+
 675+	for (arg = argv, braces = o->braces; *arg; arg++)
 676+		if (!strcmp(*arg, "{}"))
 677+			*braces++ = arg;
 678+	*braces = NULL;
 679+
 680+	gflags.print = 0;
 681+	return arg;
 682+}
 683+
 684+static char **
 685+get_print_arg(char *argv[], union extra *extra)
 686+{
 687+	gflags.print = 0;
 688+	return argv;
 689+}
 690+
 691+/* FIXME: ignoring nanoseconds */
 692+static char **
 693+get_newer_arg(char *argv[], union extra *extra)
 694+{
 695+	struct stat st;
 696+
 697+	if (do_stat(*argv, &st, NULL))
 698+		eprintf("failed to stat '%s':", *argv);
 699+
 700+	extra->i = st.st_mtime;
 701+	return argv;
 702+}
 703+
 704+static char **
 705+get_depth_arg(char *argv[], union extra *extra)
 706+{
 707+	gflags.depth = 1;
 708+	return argv;
 709+}
 710+
 711+/*
 712+ * Freeargs
 713+ */
 714+static void
 715+free_extra(union extra extra)
 716+{
 717+	free(extra.p);
 718+}
 719+
 720+static void
 721+free_exec_arg(union extra extra)
 722+{
 723+	int status;
 724+	char **arg;
 725+	struct execarg *e = extra.p;
 726+
 727+	if (!e->isplus) {
 728+		free(e->u.s.braces);
 729+	} else {
 730+		e->argv[e->u.p.next] = NULL;
 731+
 732+		/* if we have files, do the last exec */
 733+		if (e->u.p.first != e->u.p.next) {
 734+			status = spawn(e->argv);
 735+			gflags.ret = gflags.ret || status;
 736+		}
 737+		for (arg = e->argv + e->u.p.first; *arg; arg++)
 738+			free(*arg);
 739+		free(e->argv);
 740+	}
 741+	free(e);
 742+}
 743+
 744+static void
 745+free_ok_arg(union extra extra)
 746+{
 747+	struct okarg *o = extra.p;
 748+
 749+	free(o->braces);
 750+	free(o);
 751+}
 752+
 753+/*
 754+ * Parsing/Building/Running
 755+ */
 756+static void
 757+fill_narg(char *s, struct narg *n)
 758+{
 759+	char *end;
 760+
 761+	switch (*s) {
 762+	case '+': n->cmp = cmp_gt; s++; break;
 763+	case '-': n->cmp = cmp_lt; s++; break;
 764+	default : n->cmp = cmp_eq;      break;
 765+	}
 766+	n->n = strtol(s, &end, 10);
 767+	if (end == s || *end)
 768+		eprintf("bad number '%s'\n", s);
 769+}
 770+
 771+static struct pri_info *
 772+find_primary(char *name)
 773+{
 774+	struct pri_info *p;
 775+
 776+	for (p = primaries; p->name; p++)
 777+		if (!strcmp(name, p->name))
 778+			return p;
 779+	return NULL;
 780+}
 781+
 782+static struct op_info *
 783+find_op(char *name)
 784+{
 785+	struct op_info *o;
 786+
 787+	for (o = ops; o->name; o++)
 788+		if (!strcmp(name, o->name))
 789+			return o;
 790+	return NULL;
 791+}
 792+
 793+/* given the expression from the command line
 794+ * 1) convert arguments from strings to tok and place in an array duplicating
 795+ *    the infix expression given, inserting "-a" where it was omitted
 796+ * 2) allocate an array to hold the correct number of tok, and convert from
 797+ *    infix to rpn (using shunting-yard), add -a and -print if necessary
 798+ * 3) evaluate the rpn filling in left and right pointers to create an
 799+ *    expression tree (tok are still all contained in the rpn array, just
 800+ *    pointing at eachother)
 801+ */
 802+static void
 803+parse(int argc, char **argv)
 804+{
 805+	struct tok *tok, *rpn, *out, **top, *infix, **stack;
 806+	struct op_info *op;
 807+	struct pri_info *pri;
 808+	char **arg;
 809+	int lasttype = -1;
 810+	size_t ntok = 0;
 811+	struct tok and = { .u.oinfo = find_op("-a"), .type = AND };
 812+
 813+	gflags.print = 1;
 814+
 815+	/* convert argv to infix expression of tok, inserting in *tok */
 816+	infix = ereallocarray(NULL, 2 * argc + 1, sizeof(*infix));
 817+	for (arg = argv, tok = infix; *arg; arg++, tok++) {
 818+		pri = find_primary(*arg);
 819+
 820+		if (pri) { /* token is a primary, fill out tok and get arguments */
 821+			if (lasttype == PRIM || lasttype == RPAR) {
 822+				*tok++ = and;
 823+				ntok++;
 824+			}
 825+			if (pri->getarg) {
 826+				if (pri->narg && !*++arg)
 827+					eprintf("no argument for primary %s\n", pri->name);
 828+				arg = pri->getarg(arg, &tok->extra);
 829+			}
 830+			tok->u.pinfo = pri;
 831+			tok->type = PRIM;
 832+		} else if ((op = find_op(*arg))) { /* token is an operator */
 833+			if (lasttype == LPAR && op->type == RPAR)
 834+				eprintf("empty parens\n");
 835+			if ((lasttype == PRIM || lasttype == RPAR) &&
 836+			    (op->type == NOT || op->type == LPAR)) { /* need another implicit -a */
 837+				*tok++ = and;
 838+				ntok++;
 839+			}
 840+			tok->type = op->type;
 841+			tok->u.oinfo = op;
 842+		} else {
 843+			/* token is neither primary nor operator, must be */
 844+			if ((*arg)[0] == '-') /* an unsupported option */
 845+				eprintf("unknown operand: %s\n", *arg);
 846+			else /* or a path in the wrong place */
 847+				eprintf("paths must precede expression: %s\n", *arg);
 848+		}
 849+		if (tok->type != LPAR && tok->type != RPAR)
 850+			ntok++; /* won't have parens in rpn */
 851+		lasttype = tok->type;
 852+	}
 853+	tok->type = END;
 854+	ntok++;
 855+
 856+	if (gflags.print && (arg != argv)) /* need to add -a -print (not just -print) */
 857+		gflags.print++;
 858+
 859+	/* use shunting-yard to convert from infix to rpn
 860+	 * https://en.wikipedia.org/wiki/Shunting-yard_algorithm
 861+	 * read from infix, resulting rpn ends up in rpn, next position in rpn is out
 862+	 * push operators onto stack, next position in stack is top */
 863+	rpn = ereallocarray(NULL, ntok + gflags.print, sizeof(*rpn));
 864+	stack = ereallocarray(NULL, argc + gflags.print, sizeof(*stack));
 865+	for (tok = infix, out = rpn, top = stack; tok->type != END; tok++) {
 866+		switch (tok->type) {
 867+		case PRIM: *out++ = *tok; break;
 868+		case LPAR: *top++ =  tok; break;
 869+		case RPAR:
 870+			while (top-- > stack && (*top)->type != LPAR)
 871+				*out++ = **top;
 872+			if (top < stack)
 873+				eprintf("extra )\n");
 874+			break;
 875+		default:
 876+			/* this expression can be simplified, but I decided copy the
 877+			 * verbage from the wikipedia page in order to more clearly explain
 878+			 * what's going on */
 879+			while (top-- > stack &&
 880+			       (( tok->u.oinfo->lassoc && tok->u.oinfo->prec <= (*top)->u.oinfo->prec) ||
 881+			        (!tok->u.oinfo->lassoc && tok->u.oinfo->prec <  (*top)->u.oinfo->prec)))
 882+				*out++ = **top;
 883+
 884+			/* top now points to either an operator we didn't pop, or stack[-1]
 885+			 * either way we need to increment it before using it, then
 886+			 * increment again so the stack works */
 887+			top++;
 888+			*top++ = tok;
 889+			break;
 890+		}
 891+	}
 892+	while (top-- > stack) {
 893+		if ((*top)->type == LPAR)
 894+			eprintf("extra (\n");
 895+		*out++ = **top;
 896+	}
 897+
 898+	/* if there was no expression, use -print
 899+	 * if there was an expression but no -print, -exec, or -ok, add -a -print
 900+	 * in rpn, not infix */
 901+	if (gflags.print)
 902+		*out++ = (struct tok){ .u.pinfo = find_primary("-print"), .type = PRIM };
 903+	if (gflags.print == 2)
 904+		*out++ = and;
 905+
 906+	out->type = END;
 907+
 908+	/* rpn now holds all operators and arguments in reverse polish notation
 909+	 * values are pushed onto stack, operators pop values off stack into left
 910+	 * and right pointers, pushing operator node back onto stack
 911+	 * could probably just do this during shunting-yard, but this is simpler
 912+	 * code IMO */
 913+	for (tok = rpn, top = stack; tok->type != END; tok++) {
 914+		if (tok->type == PRIM) {
 915+			*top++ = tok;
 916+		} else {
 917+			if (top - stack < tok->u.oinfo->nargs)
 918+				eprintf("insufficient arguments for operator %s\n", tok->u.oinfo->name);
 919+			tok->right = *--top;
 920+			tok->left  = tok->u.oinfo->nargs == 2 ? *--top : NULL;
 921+			*top++ = tok;
 922+		}
 923+	}
 924+	if (--top != stack)
 925+		eprintf("extra arguments\n");
 926+
 927+	toks = rpn;
 928+	root = *top;
 929+
 930+	free(infix);
 931+	free(stack);
 932+}
 933+
 934+/* for a primary, run and return result
 935+ * for an operator evaluate the left side of the tree, decide whether or not to
 936+ * evaluate the right based on the short-circuit boolean logic, return result
 937+ * NOTE: operator NOT has NULL left side, expression on right side
 938+ */
 939+static int
 940+eval(struct tok *tok, struct arg *arg)
 941+{
 942+	int ret;
 943+
 944+	if (!tok)
 945+		return 0;
 946+
 947+	if (tok->type == PRIM) {
 948+		arg->extra = tok->extra;
 949+		return tok->u.pinfo->func(arg);
 950+	}
 951+
 952+	ret = eval(tok->left, arg);
 953+
 954+	if ((tok->type == AND && ret) || (tok->type == OR && !ret) || tok->type == NOT)
 955+		ret = eval(tok->right, arg);
 956+
 957+	return ret ^ (tok->type == NOT);
 958+}
 959+
 960+/* evaluate path, if it's a directory iterate through directory entries and
 961+ * recurse
 962+ */
 963+static void
 964+find(char *path, struct findhist *hist)
 965+{
 966+	struct stat st;
 967+	DIR *dir;
 968+	struct dirent *de;
 969+	struct findhist *f, cur;
 970+	size_t namelen, pathcap = 0, len;
 971+	struct arg arg = { path, &st, { NULL } };
 972+	char *p, *pathbuf = NULL;
 973+
 974+	len = strlen(path) + 2; /* \0 and '/' */
 975+
 976+	if (do_stat(path, &st, hist) < 0) {
 977+		weprintf("failed to stat %s:", path);
 978+		gflags.ret = 1;
 979+		return;
 980+	}
 981+
 982+	gflags.prune = 0;
 983+
 984+	/* don't eval now iff we will hit the eval at the bottom which means
 985+	 * 1. we are a directory 2. we have -depth 3. we don't have -xdev or we are
 986+	 * on same device (so most of the time we eval here) */
 987+	if (!S_ISDIR(st.st_mode) ||
 988+	    !gflags.depth        ||
 989+	    (gflags.xdev && hist && st.st_dev != hist->dev))
 990+		eval(root, &arg);
 991+
 992+	if (!S_ISDIR(st.st_mode)                          ||
 993+	    gflags.prune                                  ||
 994+	    (gflags.xdev && hist && st.st_dev != hist->dev))
 995+		return;
 996+
 997+	for (f = hist; f; f = f->next) {
 998+		if (f->dev == st.st_dev && f->ino == st.st_ino) {
 999+			weprintf("loop detected '%s' is '%s'\n", path, f->path);
1000+			gflags.ret = 1;
1001+			return;
1002+		}
1003+	}
1004+	cur.next = hist;
1005+	cur.path = path;
1006+	cur.dev  = st.st_dev;
1007+	cur.ino  = st.st_ino;
1008+
1009+	if (!(dir = opendir(path))) {
1010+		weprintf("failed to opendir %s:", path);
1011+		gflags.ret = 1;
1012+		/* should we just ignore this since we hit an error? */
1013+		if (gflags.depth)
1014+			eval(root, &arg);
1015+		return;
1016+	}
1017+
1018+	while (errno = 0, (de = readdir(dir))) {
1019+		if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
1020+			continue;
1021+		namelen = strlen(de->d_name);
1022+		if (len + namelen > pathcap) {
1023+			pathcap = len + namelen;
1024+			pathbuf = erealloc(pathbuf, pathcap);
1025+		}
1026+		p = pathbuf + estrlcpy(pathbuf, path, pathcap);
1027+		if (*--p != '/')
1028+			estrlcat(pathbuf, "/", pathcap);
1029+		estrlcat(pathbuf, de->d_name, pathcap);
1030+		find(pathbuf, &cur);
1031+	}
1032+	free(pathbuf);
1033+	if (errno) {
1034+		weprintf("readdir %s:", path);
1035+		gflags.ret = 1;
1036+		closedir(dir);
1037+		return;
1038+	}
1039+	closedir(dir);
1040+
1041+	if (gflags.depth)
1042+		eval(root, &arg);
1043+}
1044+
1045+static void
1046+usage(void)
1047+{
1048+	eprintf("usage: %s [-H | -L] path ... [expression ...]\n", argv0);
1049+}
1050+
1051+int
1052+main(int argc, char **argv)
1053+{
1054+	char **paths;
1055+	int npaths;
1056+	struct tok *t;
1057+
1058+	ARGBEGIN {
1059+	case 'H':
1060+		gflags.h = 1;
1061+		gflags.l = 0;
1062+		break;
1063+	case 'L':
1064+		gflags.l = 1;
1065+		gflags.h = 0;
1066+		break;
1067+	default:
1068+		usage();
1069+	} ARGEND
1070+
1071+	paths = argv;
1072+
1073+	for (; *argv && **argv != '-' && strcmp(*argv, "!") && strcmp(*argv, "("); argv++)
1074+		;
1075+
1076+	if (!(npaths = argv - paths))
1077+		eprintf("must specify a path\n");
1078+
1079+	parse(argc - npaths, argv);
1080+
1081+	/* calculate number of bytes in environ for -exec {} + ARG_MAX avoidance
1082+	 * libc implementation defined whether null bytes, pointers, and alignment
1083+	 * are counted, so count them */
1084+	for (argv = environ; *argv; argv++)
1085+		envlen += strlen(*argv) + 1 + sizeof(*argv);
1086+
1087+	if ((argmax = sysconf(_SC_ARG_MAX)) == (size_t)-1)
1088+		argmax = _POSIX_ARG_MAX;
1089+
1090+	if (clock_gettime(CLOCK_REALTIME, &start) < 0)
1091+		weprintf("clock_gettime() failed:");
1092+
1093+	while (npaths--)
1094+		find(*paths++, NULL);
1095+
1096+	for (t = toks; t->type != END; t++)
1097+		if (t->type == PRIM && t->u.pinfo->freearg)
1098+			t->u.pinfo->freearg(t->extra);
1099+	free(toks);
1100+
1101+	gflags.ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
1102+
1103+	return gflags.ret;
1104+}
+130, -0
  1@@ -0,0 +1,130 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <ctype.h>
  4+#include <stdint.h>
  5+#include <stdio.h>
  6+#include <stdlib.h>
  7+#include <string.h>
  8+
  9+#include "text.h"
 10+#include "util.h"
 11+#include "utf.h"
 12+
 13+static int    bflag = 0;
 14+static int    sflag = 0;
 15+static size_t width = 80;
 16+
 17+static void
 18+foldline(struct line *l, const char *fname) {
 19+	size_t i, col, last, spacesect, len;
 20+	Rune r;
 21+	int runelen;
 22+
 23+	for (i = 0, last = 0, col = 0, spacesect = 0; i < l->len; i += runelen) {
 24+		if (col >= width && ((l->data[i] != '\r' && l->data[i] != '\b') || bflag)) {
 25+			if (bflag && col > width)
 26+				i -= runelen;	/* never split a character */
 27+			len = ((sflag && spacesect) ? spacesect : i) - last;
 28+			if (fwrite(l->data + last, 1, len, stdout) != len)
 29+				eprintf("fwrite <stdout>:");
 30+			if (l->data[i] != '\n')
 31+				putchar('\n');
 32+			if (sflag && spacesect)
 33+				i = spacesect;
 34+			last = i;
 35+			col = 0;
 36+			spacesect = 0;
 37+		}
 38+		runelen = charntorune(&r, l->data + i, l->len - i);
 39+		if (!runelen || r == Runeerror)
 40+			eprintf("charntorune: %s: invalid utf\n", fname);
 41+		if (sflag && isblankrune(r))
 42+			spacesect = i + runelen;
 43+		if (!bflag && iscntrl(l->data[i])) {
 44+			switch(l->data[i]) {
 45+			case '\b':
 46+				col -= (col > 0);
 47+				break;
 48+			case '\r':
 49+				col = 0;
 50+				break;
 51+			case '\t':
 52+				col += (8 - (col % 8));
 53+				if (col >= width)
 54+					i--;
 55+				break;
 56+			}
 57+		} else {
 58+			col += bflag ? runelen : 1;
 59+		}
 60+	}
 61+	if (l->len - last)
 62+		fwrite(l->data + last, 1, l->len - last, stdout);
 63+}
 64+
 65+static void
 66+fold(FILE *fp, const char *fname)
 67+{
 68+	static struct line line;
 69+	static size_t size = 0;
 70+	ssize_t len;
 71+
 72+	while ((len = getline(&line.data, &size, fp)) > 0) {
 73+		line.len = len;
 74+		foldline(&line, fname);
 75+	}
 76+	if (ferror(fp))
 77+		eprintf("getline %s:", fname);
 78+}
 79+
 80+static void
 81+usage(void)
 82+{
 83+	eprintf("usage: %s [-bs] [-w num | -num] [FILE ...]\n", argv0);
 84+}
 85+
 86+int
 87+main(int argc, char *argv[])
 88+{
 89+	FILE *fp;
 90+	int ret = 0;
 91+
 92+	ARGBEGIN {
 93+	case 'b':
 94+		bflag = 1;
 95+		break;
 96+	case 's':
 97+		sflag = 1;
 98+		break;
 99+	case 'w':
100+		width = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
101+		break;
102+	ARGNUM:
103+		if (!(width = ARGNUMF()))
104+			eprintf("illegal width value, too small\n");
105+		break;
106+	default:
107+		usage();
108+	} ARGEND
109+
110+	if (!argc) {
111+		fold(stdin, "<stdin>");
112+	} else {
113+		for (; *argv; argc--, argv++) {
114+			if (!strcmp(*argv, "-")) {
115+				*argv = "<stdin>";
116+				fp = stdin;
117+			} else if (!(fp = fopen(*argv, "r"))) {
118+				weprintf("fopen %s:", *argv);
119+				ret = 1;
120+				continue;
121+			}
122+			fold(fp, *argv);
123+			if (fp != stdin && fshut(fp, *argv))
124+				ret = 1;
125+		}
126+	}
127+
128+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
129+
130+	return ret;
131+}
+108, -0
  1@@ -0,0 +1,108 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <errno.h>
  4+#include <unistd.h>
  5+#include <limits.h>
  6+#include <stdlib.h>
  7+#include <string.h>
  8+
  9+#include "util.h"
 10+
 11+struct var {
 12+	const char *k;
 13+	long v;
 14+};
 15+
 16+#include "getconf.h"
 17+
 18+void
 19+usage(void)
 20+{
 21+	eprintf("usage: %s [-v spec] var [path]\n", argv0);
 22+}
 23+
 24+int
 25+main(int argc, char *argv[])
 26+{
 27+	size_t len;
 28+	long res;
 29+	int i;
 30+	char *str;
 31+
 32+	ARGBEGIN {
 33+	case 'v':
 34+		/* ignore */
 35+		EARGF(usage());
 36+		break;
 37+	default:
 38+		usage();
 39+		break;
 40+	} ARGEND
 41+
 42+	if (argc == 1) {
 43+		/* sysconf */
 44+		for (i = 0; i < LEN(sysconf_l); i++) {
 45+			if (strcmp(argv[0], sysconf_l[i].k))
 46+				continue;
 47+			errno = 0;
 48+			if ((res = sysconf(sysconf_l[i].v)) < 0) {
 49+				if (errno)
 50+					eprintf("sysconf %ld:", sysconf_l[i].v);
 51+				puts("undefined");
 52+			} else {
 53+				printf("%ld\n", res);
 54+			}
 55+			return fshut(stdout, "<stdout>");
 56+		}
 57+		/* confstr */
 58+		for (i = 0; i < LEN(confstr_l); i++) {
 59+			if (strcmp(argv[0], confstr_l[i].k))
 60+				continue;
 61+			errno = 0;
 62+			if (!(len = confstr(confstr_l[i].v, NULL, 0))) {
 63+				if (errno)
 64+					eprintf("confstr %ld:", confstr_l[i].v);
 65+				puts("undefined");
 66+			} else {
 67+				str = emalloc(len);
 68+				errno = 0;
 69+				if (!confstr(confstr_l[i].v, str, len)) {
 70+					if (errno)
 71+						eprintf("confstr %ld:", confstr_l[i].v);
 72+					puts("undefined");
 73+				} else {
 74+					puts(str);
 75+				}
 76+				free(str);
 77+			}
 78+			return fshut(stdout, "<stdout>");
 79+		}
 80+		/* limits */
 81+		for (i = 0; i < LEN(limits_l); i++) {
 82+			if (strcmp(argv[0], limits_l[i].k))
 83+				continue;
 84+			printf("%ld\n", limits_l[i].v);
 85+			return fshut(stdout, "<stdout>");
 86+		}
 87+	} else if (argc == 2) {
 88+		/* pathconf */
 89+		for (i = 0; i < LEN(pathconf_l); i++) {
 90+			if (strcmp(argv[0], pathconf_l[i].k))
 91+				continue;
 92+			errno = 0;
 93+			if ((res = pathconf(argv[1], pathconf_l[i].v)) < 0) {
 94+				if (errno)
 95+					eprintf("pathconf %ld:", pathconf_l[i].v);
 96+				puts("undefined");
 97+			} else {
 98+				printf("%ld\n", res);
 99+			}
100+			return fshut(stdout, "<stdout>");
101+		}
102+	} else {
103+		usage();
104+	}
105+
106+	eprintf("invalid variable: %s\n", argv[0]);
107+
108+	return 0;
109+}
+266, -0
  1@@ -0,0 +1,266 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <regex.h>
  4+#include <stdio.h>
  5+#include <stdlib.h>
  6+#include <string.h>
  7+#include <strings.h>
  8+
  9+#include "queue.h"
 10+#include "util.h"
 11+
 12+enum { Match = 0, NoMatch = 1, Error = 2 };
 13+
 14+static void addpattern(const char *);
 15+static void addpatternfile(FILE *);
 16+static int grep(FILE *, const char *);
 17+
 18+static int Eflag;
 19+static int Fflag;
 20+static int Hflag;
 21+static int eflag;
 22+static int fflag;
 23+static int hflag;
 24+static int iflag;
 25+static int sflag;
 26+static int vflag;
 27+static int wflag;
 28+static int xflag;
 29+static int many;
 30+static int mode;
 31+
 32+struct pattern {
 33+	regex_t preg;
 34+	SLIST_ENTRY(pattern) entry;
 35+	char pattern[];
 36+};
 37+
 38+static SLIST_HEAD(phead, pattern) phead;
 39+
 40+static void
 41+addpattern(const char *pattern)
 42+{
 43+	struct pattern *pnode;
 44+	size_t patlen;
 45+
 46+	patlen = strlen(pattern);
 47+
 48+	pnode = enmalloc(Error, sizeof(*pnode) + patlen + 9);
 49+	SLIST_INSERT_HEAD(&phead, pnode, entry);
 50+
 51+	if (Fflag || (!xflag && !wflag)) {
 52+		memcpy(pnode->pattern, pattern, patlen + 1);
 53+	} else {
 54+		sprintf(pnode->pattern, "%s%s%s%s%s",
 55+			xflag ? "^" : "\\<",
 56+			Eflag ? "(" : "\\(",
 57+			pattern,
 58+			Eflag ? ")" : "\\)",
 59+			xflag ? "$" : "\\>");
 60+	}
 61+}
 62+
 63+static void
 64+addpatternfile(FILE *fp)
 65+{
 66+	static char *buf = NULL;
 67+	static size_t size = 0;
 68+	ssize_t len = 0;
 69+
 70+	while ((len = getline(&buf, &size, fp)) > 0) {
 71+		if (buf[len - 1] == '\n')
 72+			buf[len - 1] = '\0';
 73+		addpattern(buf);
 74+	}
 75+	if (ferror(fp))
 76+		enprintf(Error, "read error:");
 77+}
 78+
 79+static int
 80+grep(FILE *fp, const char *str)
 81+{
 82+	static char *buf = NULL;
 83+	static size_t size = 0;
 84+	ssize_t len = 0;
 85+	long c = 0, n;
 86+	struct pattern *pnode;
 87+	int match, result = NoMatch;
 88+
 89+	for (n = 1; (len = getline(&buf, &size, fp)) > 0; n++) {
 90+		/* Remove the trailing newline if one is present. */
 91+		if (buf[len - 1] == '\n')
 92+			buf[len - 1] = '\0';
 93+		match = 0;
 94+		SLIST_FOREACH(pnode, &phead, entry) {
 95+			if (Fflag) {
 96+				if (xflag) {
 97+					if (!(iflag ? strcasecmp : strcmp)(buf, pnode->pattern)) {
 98+						match = 1;
 99+						break;
100+					}
101+				} else {
102+					if ((iflag ? strcasestr : strstr)(buf, pnode->pattern)) {
103+						match = 1;
104+						break;
105+					}
106+				}
107+			} else {
108+				if (regexec(&pnode->preg, buf, 0, NULL, 0) == 0) {
109+					match = 1;
110+					break;
111+				}
112+			}
113+		}
114+		if (match != vflag) {
115+			result = Match;
116+			switch (mode) {
117+			case 'c':
118+				c++;
119+				break;
120+			case 'l':
121+				puts(str);
122+				goto end;
123+			case 'q':
124+				exit(Match);
125+			default:
126+				if (!hflag && (many || Hflag))
127+					printf("%s:", str);
128+				if (mode == 'n')
129+					printf("%ld:", n);
130+				puts(buf);
131+				break;
132+			}
133+		}
134+	}
135+	if (mode == 'c')
136+		printf("%ld\n", c);
137+end:
138+	if (ferror(fp)) {
139+		weprintf("%s: read error:", str);
140+		result = Error;
141+	}
142+	return result;
143+}
144+
145+static void
146+usage(void)
147+{
148+	enprintf(Error, "usage: %s [-EFHchilnqsvwx] [-e pattern] [-f file] "
149+	         "[pattern] [file ...]\n", argv0);
150+}
151+
152+int
153+main(int argc, char *argv[])
154+{
155+	struct pattern *pnode;
156+	int m, flags = REG_NOSUB, match = NoMatch;
157+	FILE *fp;
158+	char *arg;
159+
160+	SLIST_INIT(&phead);
161+
162+	ARGBEGIN {
163+	case 'E':
164+		Eflag = 1;
165+		Fflag = 0;
166+		flags |= REG_EXTENDED;
167+		break;
168+	case 'F':
169+		Fflag = 1;
170+		Eflag = 0;
171+		flags &= ~REG_EXTENDED;
172+		break;
173+	case 'H':
174+		Hflag = 1;
175+		hflag = 0;
176+		break;
177+	case 'e':
178+		arg = EARGF(usage());
179+		if (!(fp = fmemopen(arg, strlen(arg) + 1, "r")))
180+			eprintf("fmemopen:");
181+		addpatternfile(fp);
182+		efshut(fp, arg);
183+		eflag = 1;
184+		break;
185+	case 'f':
186+		arg = EARGF(usage());
187+		fp = fopen(arg, "r");
188+		if (!fp)
189+			enprintf(Error, "fopen %s:", arg);
190+		addpatternfile(fp);
191+		efshut(fp, arg);
192+		fflag = 1;
193+		break;
194+	case 'h':
195+		hflag = 1;
196+		Hflag = 0;
197+		break;
198+	case 'c':
199+	case 'l':
200+	case 'n':
201+	case 'q':
202+		mode = ARGC();
203+		break;
204+	case 'i':
205+		flags |= REG_ICASE;
206+		iflag = 1;
207+		break;
208+	case 's':
209+		sflag = 1;
210+		break;
211+	case 'v':
212+		vflag = 1;
213+		break;
214+	case 'w':
215+		wflag = 1;
216+		break;
217+	case 'x':
218+		xflag = 1;
219+		break;
220+	default:
221+		usage();
222+	} ARGEND
223+
224+	if (argc == 0 && !eflag && !fflag)
225+		usage(); /* no pattern */
226+
227+	/* just add literal pattern to list */
228+	if (!eflag && !fflag) {
229+		if (!(fp = fmemopen(argv[0], strlen(argv[0]) + 1, "r")))
230+			eprintf("fmemopen:");
231+		addpatternfile(fp);
232+		efshut(fp, argv[0]);
233+		argc--;
234+		argv++;
235+	}
236+
237+	if (!Fflag)
238+		/* Compile regex for all search patterns */
239+		SLIST_FOREACH(pnode, &phead, entry)
240+			enregcomp(Error, &pnode->preg, pnode->pattern, flags);
241+	many = (argc > 1);
242+	if (argc == 0) {
243+		match = grep(stdin, "<stdin>");
244+	} else {
245+		for (; *argv; argc--, argv++) {
246+			if (!strcmp(*argv, "-")) {
247+				*argv = "<stdin>";
248+				fp = stdin;
249+			} else if (!(fp = fopen(*argv, "r"))) {
250+				if (!sflag)
251+					weprintf("fopen %s:", *argv);
252+				match = Error;
253+				continue;
254+			}
255+			m = grep(fp, *argv);
256+			if (m == Error || (match != Error && m == Match))
257+				match = m;
258+			if (fp != stdin && fshut(fp, *argv))
259+				match = Error;
260+		}
261+	}
262+
263+	if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"))
264+		match = Error;
265+
266+	return match;
267+}
+77, -0
 1@@ -0,0 +1,77 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdint.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <string.h>
 7+
 8+#include "util.h"
 9+
10+static void
11+head(FILE *fp, const char *fname, size_t n)
12+{
13+	char *buf = NULL;
14+	size_t i = 0, size = 0;
15+	ssize_t len;
16+
17+	while (i < n && (len = getline(&buf, &size, fp)) > 0) {
18+		fwrite(buf, 1, len, stdout);
19+		i += (len && (buf[len - 1] == '\n'));
20+	}
21+	free(buf);
22+	if (ferror(fp))
23+		eprintf("getline %s:", fname);
24+}
25+
26+static void
27+usage(void)
28+{
29+	eprintf("usage: %s [-num | -n num] [file ...]\n", argv0);
30+}
31+
32+int
33+main(int argc, char *argv[])
34+{
35+	size_t n = 10;
36+	FILE *fp;
37+	int ret = 0, newline = 0, many = 0;
38+
39+	ARGBEGIN {
40+	case 'n':
41+		n = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
42+		break;
43+	ARGNUM:
44+		n = ARGNUMF();
45+		break;
46+	default:
47+		usage();
48+	} ARGEND
49+
50+	if (!argc) {
51+		head(stdin, "<stdin>", n);
52+	} else {
53+		many = argc > 1;
54+		for (newline = 0; *argv; argc--, argv++) {
55+			if (!strcmp(*argv, "-")) {
56+				*argv = "<stdin>";
57+				fp = stdin;
58+			} else if (!(fp = fopen(*argv, "r"))) {
59+				weprintf("fopen %s:", *argv);
60+				ret = 1;
61+				continue;
62+			}
63+			if (many) {
64+				if (newline)
65+					putchar('\n');
66+				printf("==> %s <==\n", *argv);
67+			}
68+			newline = 1;
69+			head(fp, *argv, n);
70+			if (fp != stdin && fshut(fp, *argv))
71+				ret = 1;
72+		}
73+	}
74+
75+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
76+
77+	return ret;
78+}
+176, -0
  1@@ -0,0 +1,176 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/types.h>
  4+
  5+#include <ctype.h>
  6+#include <errno.h>
  7+#include <grp.h>
  8+#include <limits.h>
  9+#include <pwd.h>
 10+#include <stdio.h>
 11+#include <stdlib.h>
 12+#include <unistd.h>
 13+
 14+#include "util.h"
 15+
 16+static void groupid(struct passwd *pw);
 17+static void user(struct passwd *pw);
 18+static void userid(uid_t id);
 19+static void usernam(const char *nam);
 20+
 21+static int gflag = 0;
 22+static int uflag = 0;
 23+static int Gflag = 0;
 24+static int nflag = 0;
 25+
 26+static void
 27+groupid(struct passwd *pw)
 28+{
 29+	gid_t gid, groups[NGROUPS_MAX];
 30+	struct group *gr;
 31+	int ngroups;
 32+	int i;
 33+
 34+	ngroups = NGROUPS_MAX;
 35+	getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
 36+	for (i = 0; i < ngroups; i++) {
 37+		gid = groups[i];
 38+		if (nflag) {
 39+			if (!(gr = getgrgid(gid)))
 40+				eprintf("getgrgid:");
 41+			printf("%s", gr->gr_name);
 42+		} else
 43+			printf("%u", gid);
 44+
 45+		if (i < ngroups - 1)
 46+			putchar(' ');
 47+	}
 48+	putchar('\n');
 49+}
 50+
 51+static void
 52+user(struct passwd *pw)
 53+{
 54+	struct group *gr;
 55+	gid_t gid, groups[NGROUPS_MAX];
 56+	int ngroups;
 57+	int i;
 58+
 59+	if (uflag) {
 60+		if (nflag)
 61+			printf("%s\n", pw->pw_name);
 62+		else
 63+			printf("%u\n", pw->pw_uid);
 64+		return;
 65+	} else if (gflag) {
 66+		if (nflag) {
 67+			if (!(gr = getgrgid(pw->pw_gid)))
 68+				eprintf("getgrgid:");
 69+			printf("%s\n", gr->gr_name);
 70+		} else
 71+			printf("%u\n", pw->pw_gid);
 72+		return;
 73+	}
 74+
 75+	printf("uid=%u(%s)", pw->pw_uid, pw->pw_name);
 76+	printf(" gid=%u", pw->pw_gid);
 77+	if (!(gr = getgrgid(pw->pw_gid)))
 78+		eprintf("getgrgid:");
 79+	printf("(%s)", gr->gr_name);
 80+
 81+	ngroups = NGROUPS_MAX;
 82+	getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
 83+	for (i = 0; i < ngroups; i++) {
 84+		gid = groups[i];
 85+		printf("%s%u", !i ? " groups=" : ",", gid);
 86+		if (!(gr = getgrgid(gid)))
 87+			eprintf("getgrgid:");
 88+		printf("(%s)", gr->gr_name);
 89+	}
 90+	putchar('\n');
 91+}
 92+
 93+static void
 94+usernam(const char *nam)
 95+{
 96+	struct passwd *pw;
 97+
 98+	errno = 0;
 99+	pw = getpwnam(nam);
100+	if (!pw) {
101+		if (errno)
102+			eprintf("getpwnam %s:", nam);
103+		else
104+			eprintf("getpwnam %s: no such user\n", nam);
105+	}
106+	if (Gflag)
107+		groupid(pw);
108+	else
109+		user(pw);
110+}
111+
112+static void
113+userid(uid_t id)
114+{
115+	struct passwd *pw;
116+
117+	errno = 0;
118+	pw = getpwuid(id);
119+	if (!pw) {
120+		if (errno)
121+			eprintf("getpwuid %d:", id);
122+		else
123+			eprintf("getpwuid %d: no such user\n", id);
124+	}
125+	if (Gflag)
126+		groupid(pw);
127+	else
128+		user(pw);
129+}
130+
131+static void
132+usage(void)
133+{
134+	eprintf("usage: %s [-n] [-g | -u | -G] [user | uid]\n", argv0);
135+}
136+
137+int
138+main(int argc, char *argv[])
139+{
140+	ARGBEGIN {
141+	case 'g':
142+		gflag = 1;
143+		break;
144+	case 'u':
145+		uflag = 1;
146+		break;
147+	case 'G':
148+		Gflag = 1;
149+		break;
150+	case 'n':
151+		nflag = 1;
152+		break;
153+	default:
154+		usage();
155+	} ARGEND;
156+
157+	/* ensure that only one of -g, -u, or -G was specified */
158+	if (gflag + uflag + Gflag > 1)
159+		usage();
160+
161+	switch (argc) {
162+	case 0:
163+		userid(getuid());
164+		break;
165+	case 1:
166+		/* user names can't begin [0-9] */
167+		if (isdigit(argv[0][0]))
168+			userid(estrtol(argv[0], 0));
169+		else
170+			usernam(argv[0]);
171+		break;
172+	default:
173+		usage();
174+	}
175+
176+	return 0;
177+}
+529, -0
  1@@ -0,0 +1,529 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <ctype.h>
  4+#include <stdint.h>
  5+#include <stdio.h>
  6+#include <stdlib.h>
  7+#include <string.h>
  8+
  9+#include "text.h"
 10+#include "utf.h"
 11+#include "util.h"
 12+
 13+enum {
 14+	INIT = 1,
 15+	GROW = 2,
 16+};
 17+
 18+enum {
 19+	EXPAND = 0,
 20+	RESET  = 1,
 21+};
 22+
 23+enum { FIELD_ERROR = -2, };
 24+
 25+struct field {
 26+	char *s;
 27+	size_t len;
 28+};
 29+
 30+struct jline {
 31+	struct line text;
 32+	size_t nf;
 33+	size_t maxf;
 34+	struct field *fields;
 35+};
 36+
 37+struct spec {
 38+	size_t fileno;
 39+	size_t fldno;
 40+};
 41+
 42+struct outlist {
 43+	size_t ns;
 44+	size_t maxs;
 45+	struct spec **specs;
 46+};
 47+
 48+struct span {
 49+	size_t nl;
 50+	size_t maxl;
 51+	struct jline **lines;
 52+};
 53+
 54+static char *sep = NULL;
 55+static char *replace = NULL;
 56+static const char defaultofs = ' ';
 57+static const int jfield = 1;            /* POSIX default join field */
 58+static int unpairsa = 0, unpairsb = 0;
 59+static int oflag = 0;
 60+static int pairs = 1;
 61+static size_t seplen;
 62+static struct outlist output;
 63+
 64+static void
 65+usage(void)
 66+{
 67+	eprintf("usage: %s [-1 field] [-2 field] [-o list] [-e string] "
 68+	        "[-a | -v fileno] [-t delim] file1 file2\n", argv0);
 69+}
 70+
 71+static void
 72+prfield(struct field *fp)
 73+{
 74+	if (fwrite(fp->s, 1, fp->len, stdout) != fp->len)
 75+		eprintf("fwrite:");
 76+}
 77+
 78+static void
 79+prsep(void)
 80+{
 81+	if (sep)
 82+		fwrite(sep, 1, seplen, stdout);
 83+	else
 84+		putchar(defaultofs);
 85+}
 86+
 87+static void
 88+swaplines(struct jline *la, struct jline *lb)
 89+{
 90+	struct jline tmp;
 91+
 92+	tmp = *la;
 93+	*la = *lb;
 94+	*lb = tmp;
 95+}
 96+
 97+static void
 98+prjoin(struct jline *la, struct jline *lb, size_t jfa, size_t jfb)
 99+{
100+	struct spec *sp;
101+	struct field *joinfield;
102+	size_t i;
103+
104+	if (jfa >= la->nf || jfb >= lb->nf)
105+		return;
106+
107+	joinfield = &la->fields[jfa];
108+
109+	if (oflag) {
110+		for (i = 0; i < output.ns; i++) {
111+			sp = output.specs[i];
112+
113+			if (sp->fileno == 1) {
114+				if (sp->fldno < la->nf)
115+					prfield(&la->fields[sp->fldno]);
116+				else if (replace)
117+					fputs(replace, stdout);
118+			} else if (sp->fileno == 2) {
119+				if (sp->fldno < lb->nf)
120+					prfield(&lb->fields[sp->fldno]);
121+				else if (replace)
122+					fputs(replace, stdout);
123+			} else if (sp->fileno == 0) {
124+				prfield(joinfield);
125+			}
126+
127+			if (i < output.ns - 1)
128+				prsep();
129+		}
130+	} else {
131+		prfield(joinfield);
132+		prsep();
133+
134+		for (i = 0; i < la->nf; i++) {
135+			if (i != jfa) {
136+				prfield(&la->fields[i]);
137+				prsep();
138+			}
139+		}
140+		for (i = 0; i < lb->nf; i++) {
141+			if (i != jfb) {
142+				prfield(&lb->fields[i]);
143+				if (i < lb->nf - 1)
144+					prsep();
145+			}
146+		}
147+	}
148+	putchar('\n');
149+}
150+
151+static void
152+prline(struct jline *lp)
153+{
154+	if (fwrite(lp->text.data, 1, lp->text.len, stdout) != lp->text.len)
155+		eprintf("fwrite:");
156+	putchar('\n');
157+}
158+
159+static int
160+jlinecmp(struct jline *la, struct jline *lb, size_t jfa, size_t jfb)
161+{
162+	int status;
163+
164+	/* return FIELD_ERROR if both lines are short */
165+	if (jfa >= la->nf) {
166+		status = (jfb >= lb->nf) ? FIELD_ERROR : -1;
167+	} else if (jfb >= lb->nf) {
168+		status = 1;
169+	} else {
170+		status = memcmp(la->fields[jfa].s, lb->fields[jfb].s,
171+		                MAX(la->fields[jfa].len, lb->fields[jfb].len));
172+		LIMIT(status, -1, 1);
173+	}
174+
175+	return status;
176+}
177+
178+static void
179+addfield(struct jline *lp, char *sp, size_t len)
180+{
181+	if (lp->nf >= lp->maxf) {
182+		lp->fields = ereallocarray(lp->fields, (GROW * lp->maxf),
183+		        sizeof(struct field));
184+		lp->maxf *= GROW;
185+	}
186+	lp->fields[lp->nf].s = sp;
187+	lp->fields[lp->nf].len = len;
188+	lp->nf++;
189+}
190+
191+static void
192+prspanjoin(struct span *spa, struct span *spb, size_t jfa, size_t jfb)
193+{
194+	size_t i, j;
195+
196+	for (i = 0; i < (spa->nl - 1); i++)
197+		for (j = 0; j < (spb->nl - 1); j++)
198+			prjoin(spa->lines[i], spb->lines[j], jfa, jfb);
199+}
200+
201+static struct jline *
202+makeline(char *s, size_t len)
203+{
204+	struct jline *lp;
205+	char *tmp;
206+	size_t i, end;
207+
208+	if (s[len - 1] == '\n')
209+		s[--len] = '\0';
210+
211+	lp = ereallocarray(NULL, INIT, sizeof(struct jline));
212+	lp->text.data = s;
213+	lp->text.len = len;
214+	lp->fields = ereallocarray(NULL, INIT, sizeof(struct field));
215+	lp->nf = 0;
216+	lp->maxf = INIT;
217+
218+	for (i = 0; i < lp->text.len && isblank(lp->text.data[i]); i++)
219+		;
220+	while (i < lp->text.len) {
221+		if (sep) {
222+			if ((lp->text.len - i) < seplen ||
223+			    !(tmp = memmem(lp->text.data + i,
224+			                   lp->text.len - i, sep, seplen))) {
225+				goto eol;
226+			}
227+			end = tmp - lp->text.data;
228+			addfield(lp, lp->text.data + i, end - i);
229+			i = end + seplen;
230+		} else {
231+			for (end = i; !(isblank(lp->text.data[end])); end++) {
232+				if (end + 1 == lp->text.len)
233+					goto eol;
234+			}
235+			addfield(lp, lp->text.data + i, end - i);
236+			for (i = end; isblank(lp->text.data[i]); i++)
237+				;
238+		}
239+	}
240+eol:
241+	addfield(lp, lp->text.data + i, lp->text.len - i);
242+
243+	return lp;
244+}
245+
246+static int
247+addtospan(struct span *sp, FILE *fp, int reset)
248+{
249+	char *newl = NULL;
250+	ssize_t len;
251+	size_t size = 0;
252+
253+	if ((len = getline(&newl, &size, fp)) < 0) {
254+		if (ferror(fp))
255+			eprintf("getline:");
256+		else
257+			return 0;
258+	}
259+
260+	if (reset)
261+		sp->nl = 0;
262+
263+	if (sp->nl >= sp->maxl) {
264+		sp->lines = ereallocarray(sp->lines, (GROW * sp->maxl),
265+		        sizeof(struct jline *));
266+		sp->maxl *= GROW;
267+	}
268+
269+	sp->lines[sp->nl] = makeline(newl, len);
270+	sp->nl++;
271+	return 1;
272+}
273+
274+static void
275+initspan(struct span *sp)
276+{
277+	sp->nl = 0;
278+	sp->maxl = INIT;
279+	sp->lines = ereallocarray(NULL, INIT, sizeof(struct jline *));
280+}
281+
282+static void
283+freespan(struct span *sp)
284+{
285+	size_t i;
286+
287+	for (i = 0; i < sp->nl; i++) {
288+		free(sp->lines[i]->fields);
289+		free(sp->lines[i]->text.data);
290+	}
291+	free(sp->lines);
292+}
293+
294+static void
295+initolist(struct outlist *olp)
296+{
297+	olp->ns = 0;
298+	olp->maxs = 1;
299+	olp->specs = ereallocarray(NULL, INIT, sizeof(struct spec *));
300+}
301+
302+static void
303+addspec(struct outlist *olp, struct spec *sp)
304+{
305+	if (olp->ns >= olp->maxs) {
306+		olp->specs = ereallocarray(olp->specs, (GROW * olp->maxs),
307+		        sizeof(struct spec *));
308+		olp->maxs *= GROW;
309+	}
310+	olp->specs[olp->ns] = sp;
311+	olp->ns++;
312+}
313+
314+static struct spec *
315+makespec(char *s)
316+{
317+	struct spec *sp;
318+	int fileno;
319+	size_t fldno;
320+
321+	if (!strcmp(s, "0")) {   /* join field must be 0 and nothing else */
322+		fileno = 0;
323+		fldno = 0;
324+	} else if ((s[0] == '1' || s[0] == '2') && s[1] == '.') {
325+		fileno = s[0] - '0';
326+		fldno = estrtonum(&s[2], 1, MIN(LLONG_MAX, SIZE_MAX)) - 1;
327+	} else {
328+		eprintf("%s: invalid format\n", s);
329+	}
330+
331+	sp = ereallocarray(NULL, INIT, sizeof(struct spec));
332+	sp->fileno = fileno;
333+	sp->fldno = fldno;
334+	return sp;
335+}
336+
337+static void
338+makeolist(struct outlist *olp, char *s)
339+{
340+	char *item, *sp;
341+	sp = s;
342+
343+	while (sp) {
344+		item = sp;
345+		sp = strpbrk(sp, ", \t");
346+		if (sp)
347+			*sp++ = '\0';
348+		addspec(olp, makespec(item));
349+	}
350+}
351+
352+static void
353+freespecs(struct outlist *olp)
354+{
355+	size_t i;
356+
357+	for (i = 0; i < olp->ns; i++)
358+		free(olp->specs[i]);
359+}
360+
361+static void
362+join(FILE *fa, FILE *fb, size_t jfa, size_t jfb)
363+{
364+	struct span spa, spb;
365+	int cmp, eofa, eofb;
366+
367+	initspan(&spa);
368+	initspan(&spb);
369+	cmp = eofa = eofb = 0;
370+
371+	addtospan(&spa, fa, RESET);
372+	addtospan(&spb, fb, RESET);
373+
374+	while (spa.nl && spb.nl) {
375+		if ((cmp = jlinecmp(spa.lines[0], spb.lines[0], jfa, jfb)) < 0) {
376+			if (unpairsa)
377+				prline(spa.lines[0]);
378+			if (!addtospan(&spa, fa, RESET)) {
379+				if (unpairsb) {    /* a is EOF'd; print the rest of b */
380+					do
381+						prline(spb.lines[0]);
382+					while (addtospan(&spb, fb, RESET));
383+				}
384+				eofa = eofb = 1;
385+			} else {
386+				continue;
387+			}
388+		} else if (cmp > 0) {
389+			if (unpairsb)
390+				prline(spb.lines[0]);
391+			if (!addtospan(&spb, fb, RESET)) {
392+				if (unpairsa) {    /* b is EOF'd; print the rest of a */
393+					do
394+						prline(spa.lines[0]);
395+					while (addtospan(&spa, fa, RESET));
396+				}
397+				eofa = eofb = 1;
398+			} else {
399+				continue;
400+			}
401+		} else if (cmp == 0) {
402+			/* read all consecutive matching lines from a */
403+			do {
404+				if (!addtospan(&spa, fa, EXPAND)) {
405+					eofa = 1;
406+					spa.nl++;
407+					break;
408+				}
409+			} while (jlinecmp(spa.lines[spa.nl-1], spb.lines[0], jfa, jfb) == 0);
410+
411+			/* read all consecutive matching lines from b */
412+			do {
413+				if (!addtospan(&spb, fb, EXPAND)) {
414+					eofb = 1;
415+					spb.nl++;
416+					break;
417+				}
418+			} while (jlinecmp(spa.lines[0], spb.lines[spb.nl-1], jfa, jfb) == 0);
419+
420+			if (pairs)
421+				prspanjoin(&spa, &spb, jfa, jfb);
422+
423+		} else {      /* FIELD_ERROR: both lines lacked join fields */
424+			if (unpairsa)
425+				prline(spa.lines[0]);
426+			if (unpairsb)
427+				prline(spb.lines[0]);
428+			eofa = addtospan(&spa, fa, RESET) ? 0 : 1;
429+			eofb = addtospan(&spb, fb, RESET) ? 0 : 1;
430+			if (!eofa && !eofb)
431+				continue;
432+		}
433+
434+		if (eofa) {
435+			spa.nl = 0;
436+		} else {
437+			swaplines(spa.lines[0], spa.lines[spa.nl - 1]);   /* ugly */
438+			spa.nl = 1;
439+		}
440+
441+		if (eofb) {
442+			spb.nl = 0;
443+		} else {
444+			swaplines(spb.lines[0], spb.lines[spb.nl - 1]);   /* ugly */
445+			spb.nl = 1;
446+		}
447+	}
448+	freespan(&spa);
449+	freespan(&spb);
450+}
451+
452+
453+int
454+main(int argc, char *argv[])
455+{
456+	size_t jf[2] = { jfield, jfield, };
457+	FILE *fp[2];
458+	int ret = 0, n;
459+	char *fno;
460+
461+	ARGBEGIN {
462+	case '1':
463+		jf[0] = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
464+		break;
465+	case '2':
466+		jf[1] = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
467+		break;
468+	case 'a':
469+		fno = EARGF(usage());
470+		if (strcmp(fno, "1") == 0)
471+			unpairsa = 1;
472+		else if (strcmp(fno, "2") == 0)
473+			unpairsb = 1;
474+		else
475+			usage();
476+		break;
477+	case 'e':
478+		replace = EARGF(usage());
479+		break;
480+	case 'o':
481+		oflag = 1;
482+		initolist(&output);
483+		makeolist(&output, EARGF(usage()));
484+		break;
485+	case 't':
486+		sep = EARGF(usage());
487+		break;
488+	case 'v':
489+		pairs = 0;
490+		fno = EARGF(usage());
491+		if (strcmp(fno, "1") == 0)
492+			unpairsa = 1;
493+		else if (strcmp(fno, "2") == 0)
494+			unpairsb = 1;
495+		else
496+			usage();
497+		break;
498+	default:
499+		usage();
500+	} ARGEND
501+
502+	if (sep)
503+		seplen = unescape(sep);
504+
505+	if (argc != 2)
506+		usage();
507+
508+	for (n = 0; n < 2; n++) {
509+		if (!strcmp(argv[n], "-")) {
510+			argv[n] = "<stdin>";
511+			fp[n] = stdin;
512+		} else if (!(fp[n] = fopen(argv[n], "r"))) {
513+			eprintf("fopen %s:", argv[n]);
514+		}
515+	}
516+
517+	jf[0]--;
518+	jf[1]--;
519+
520+	join(fp[0], fp[1], jf[0], jf[1]);
521+
522+	if (oflag)
523+		freespecs(&output);
524+
525+	if (fshut(fp[0], argv[0]) | (fp[0] != fp[1] && fshut(fp[1], argv[1])) |
526+	    fshut(stdout, "<stdout>"))
527+		ret = 2;
528+
529+	return ret;
530+}
+131, -0
  1@@ -0,0 +1,131 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/wait.h>
  4+
  5+#include <ctype.h>
  6+#include <limits.h>
  7+#include <signal.h>
  8+#include <stdio.h>
  9+#include <string.h>
 10+#include <strings.h>
 11+
 12+#include "util.h"
 13+
 14+struct {
 15+	const char *name;
 16+	const int   sig;
 17+} sigs[] = {
 18+	{ "0", 0 },
 19+#define SIG(n) { #n, SIG##n }
 20+	SIG(ABRT), SIG(ALRM), SIG(BUS),  SIG(CHLD), SIG(CONT), SIG(FPE),  SIG(HUP),
 21+	SIG(ILL),  SIG(INT),  SIG(KILL), SIG(PIPE), SIG(QUIT), SIG(SEGV), SIG(STOP),
 22+	SIG(TERM), SIG(TRAP), SIG(TSTP), SIG(TTIN), SIG(TTOU), SIG(USR1), SIG(USR2),
 23+	SIG(URG),
 24+#undef SIG
 25+};
 26+
 27+const char *
 28+sig2name(const int sig)
 29+{
 30+	size_t i;
 31+
 32+	for (i = 0; i < LEN(sigs); i++)
 33+		if (sigs[i].sig == sig)
 34+			return sigs[i].name;
 35+	eprintf("%d: bad signal number\n", sig);
 36+
 37+	return NULL; /* not reached */
 38+}
 39+
 40+int
 41+name2sig(const char *name)
 42+{
 43+	size_t i;
 44+
 45+	for (i = 0; i < LEN(sigs); i++)
 46+		if (!strcasecmp(sigs[i].name, name))
 47+			return sigs[i].sig;
 48+	eprintf("%s: bad signal name\n", name);
 49+
 50+	return -1; /* not reached */
 51+}
 52+
 53+static void
 54+usage(void)
 55+{
 56+	eprintf("usage: %s [-s signame | -num | -signame] pid ...\n"
 57+	        "       %s -l [num]\n", argv0, argv0);
 58+}
 59+
 60+int
 61+main(int argc, char *argv[])
 62+{
 63+	pid_t pid;
 64+	size_t i;
 65+	int ret = 0, sig = SIGTERM;
 66+
 67+	argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
 68+
 69+	if (!argc)
 70+		usage();
 71+
 72+	if ((*argv)[0] == '-') {
 73+		switch ((*argv)[1]) {
 74+		case 'l':
 75+			if ((*argv)[2])
 76+				goto longopt;
 77+			argc--, argv++;
 78+			if (!argc) {
 79+				for (i = 0; i < LEN(sigs); i++)
 80+					puts(sigs[i].name);
 81+			} else if (argc == 1) {
 82+				sig = estrtonum(*argv, 0, INT_MAX);
 83+				if (sig > 128)
 84+					sig = WTERMSIG(sig);
 85+				puts(sig2name(sig));
 86+			} else {
 87+				usage();
 88+			}
 89+			return fshut(stdout, "<stdout>");
 90+		case 's':
 91+			if ((*argv)[2])
 92+				goto longopt;
 93+			argc--, argv++;
 94+			if (!argc)
 95+				usage();
 96+			sig = name2sig(*argv);
 97+			argc--, argv++;
 98+			break;
 99+		case '-':
100+			if ((*argv)[2])
101+				goto longopt;
102+			argc--, argv++;
103+			break;
104+		default:
105+		longopt:
106+			/* XSI-extensions -argnum and -argname*/
107+			if (isdigit((*argv)[1])) {
108+				sig = estrtonum((*argv) + 1, 0, INT_MAX);
109+				sig2name(sig);
110+			} else {
111+				sig = name2sig((*argv) + 1);
112+			}
113+			argc--, argv++;
114+		}
115+	}
116+
117+	if (argc && !strcmp(*argv, "--"))
118+		argc--, argv++;
119+
120+	if (!argc)
121+		usage();
122+
123+	for (; *argv; argc--, argv++) {
124+		pid = estrtonum(*argv, INT_MIN, INT_MAX);
125+		if (kill(pid, sig) < 0) {
126+			weprintf("kill %d:", pid);
127+			ret = 1;
128+		}
129+	}
130+
131+	return ret;
132+}
+27, -0
 1@@ -0,0 +1,27 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <unistd.h>
 4+
 5+#include "util.h"
 6+
 7+static void
 8+usage(void)
 9+{
10+	eprintf("usage: %s target name\n", argv0);
11+}
12+
13+int
14+main(int argc, char *argv[])
15+{
16+	ARGBEGIN {
17+	default:
18+		usage();
19+	} ARGEND
20+
21+	if (argc != 2)
22+		usage();
23+
24+	if (link(argv[0], argv[1]) < 0)
25+		eprintf("link:");
26+
27+	return 0;
28+}
+103, -0
  1@@ -0,0 +1,103 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+
  5+#include <errno.h>
  6+#include <fcntl.h>
  7+#include <libgen.h>
  8+#include <string.h>
  9+#include <unistd.h>
 10+
 11+#include "util.h"
 12+
 13+static void
 14+usage(void)
 15+{
 16+	eprintf("usage: %s [-f] [-L | -P | -s] target [name]\n"
 17+	        "       %s [-f] [-L | -P | -s] target ... dir\n", argv0, argv0);
 18+}
 19+
 20+int
 21+main(int argc, char *argv[])
 22+{
 23+	char *targetdir = ".", *target = NULL;
 24+	int ret = 0, sflag = 0, fflag = 0, dirfd = AT_FDCWD,
 25+	    hastarget = 0, flags = AT_SYMLINK_FOLLOW;
 26+	struct stat st, tst;
 27+
 28+	ARGBEGIN {
 29+	case 'f':
 30+		fflag = 1;
 31+		break;
 32+	case 'L':
 33+		flags |= AT_SYMLINK_FOLLOW;
 34+		break;
 35+	case 'P':
 36+		flags &= ~AT_SYMLINK_FOLLOW;
 37+		break;
 38+	case 's':
 39+		sflag = 1;
 40+		break;
 41+	default:
 42+		usage();
 43+	} ARGEND
 44+
 45+	if (!argc)
 46+		usage();
 47+
 48+	if (argc > 1) {
 49+		if (!stat(argv[argc - 1], &st) && S_ISDIR(st.st_mode)) {
 50+			if ((dirfd = open(argv[argc - 1], O_RDONLY)) < 0)
 51+				eprintf("open %s:", argv[argc - 1]);
 52+			targetdir = argv[argc - 1];
 53+			if (targetdir[strlen(targetdir) - 1] == '/')
 54+				targetdir[strlen(targetdir) - 1] = '\0';
 55+		} else if (argc == 2) {
 56+			hastarget = 1;
 57+			target = argv[argc - 1];
 58+		} else {
 59+			eprintf("%s: not a directory\n", argv[argc - 1]);
 60+		}
 61+		argv[argc - 1] = NULL;
 62+		argc--;
 63+	}
 64+
 65+	for (; *argv; argc--, argv++) {
 66+		if (!hastarget)
 67+			target = basename(*argv);
 68+
 69+		if (!sflag) {
 70+			if (stat(*argv, &st) < 0) {
 71+				weprintf("stat %s:", *argv);
 72+				ret = 1;
 73+				continue;
 74+			} else if (fstatat(dirfd, target, &tst, AT_SYMLINK_NOFOLLOW) < 0) {
 75+				if (errno != ENOENT) {
 76+					weprintf("fstatat %s %s:", targetdir, target);
 77+					ret = 1;
 78+					continue;
 79+				}
 80+			} else if (st.st_dev == tst.st_dev && st.st_ino == tst.st_ino) {
 81+				if (!fflag) {
 82+					weprintf("%s and %s/%s are the same file\n",
 83+							*argv, targetdir, target);
 84+					ret = 1;
 85+				}
 86+				continue;
 87+			}
 88+		}
 89+
 90+		if (fflag && unlinkat(dirfd, target, 0) < 0 && errno != ENOENT) {
 91+			weprintf("unlinkat %s %s:", targetdir, target);
 92+			ret = 1;
 93+			continue;
 94+		}
 95+		if ((sflag ? symlinkat(*argv, dirfd, target) :
 96+		             linkat(AT_FDCWD, *argv, dirfd, target, flags)) < 0) {
 97+			weprintf("%s %s <- %s/%s:", sflag ? "symlinkat" : "linkat",
 98+			         *argv, targetdir, target);
 99+			ret = 1;
100+		}
101+	}
102+
103+	return ret;
104+}
+91, -0
 1@@ -0,0 +1,91 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <stdlib.h>
 5+#include <string.h>
 6+#include <strings.h>
 7+#define SYSLOG_NAMES
 8+#include <syslog.h>
 9+#include <unistd.h>
10+
11+#include "util.h"
12+
13+static int
14+decodetable(CODE *table, char *name)
15+{
16+	CODE *c;
17+
18+	for (c = table; c->c_name; c++)
19+		if (!strcasecmp(name, c->c_name))
20+			return c->c_val;
21+	eprintf("invalid priority name: %s\n", name);
22+
23+	return -1; /* not reached */
24+}
25+
26+static int
27+decodepri(char *pri)
28+{
29+	char *lev, *fac = pri;
30+
31+	if (!(lev = strchr(pri, '.')))
32+		eprintf("invalid priority name: %s\n", pri);
33+	*lev++ = '\0';
34+	if (!*lev)
35+		eprintf("invalid priority name: %s\n", pri);
36+
37+	return (decodetable(facilitynames, fac) & LOG_FACMASK) |
38+	       (decodetable(prioritynames, lev) & LOG_PRIMASK);
39+}
40+
41+static void
42+usage(void)
43+{
44+	eprintf("usage: %s [-is] [-p priority] [-t tag] [message ...]\n", argv0);
45+}
46+
47+int
48+main(int argc, char *argv[])
49+{
50+	size_t sz;
51+	int logflags = 0, priority = LOG_NOTICE, i;
52+	char *buf = NULL, *tag = NULL;
53+
54+	ARGBEGIN {
55+	case 'i':
56+		logflags |= LOG_PID;
57+		break;
58+	case 'p':
59+		priority = decodepri(EARGF(usage()));
60+		break;
61+	case 's':
62+		logflags |= LOG_PERROR;
63+		break;
64+	case 't':
65+		tag = EARGF(usage());
66+		break;
67+	default:
68+		usage();
69+	} ARGEND
70+
71+	openlog(tag ? tag : getlogin(), logflags, 0);
72+
73+	if (!argc) {
74+		while (getline(&buf, &sz, stdin) > 0)
75+			syslog(priority, "%s", buf);
76+	} else {
77+		for (i = 0, sz = 0; i < argc; i++)
78+			sz += strlen(argv[i]);
79+		sz += argc;
80+		buf = ecalloc(1, sz);
81+		for (i = 0; i < argc; i++) {
82+			estrlcat(buf, argv[i], sz);
83+			if (i + 1 < argc)
84+				estrlcat(buf, " ", sz);
85+		}
86+		syslog(priority, "%s", buf);
87+	}
88+
89+	closelog();
90+
91+	return fshut(stdin, "<stdin>");
92+}
+29, -0
 1@@ -0,0 +1,29 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <unistd.h>
 5+
 6+#include "util.h"
 7+
 8+static void
 9+usage(void)
10+{
11+	eprintf("usage: %s\n", argv0);
12+}
13+
14+int
15+main(int argc, char *argv[])
16+{
17+	char *login;
18+
19+	argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
20+
21+	if (argc)
22+		usage();
23+
24+	if ((login = getlogin()))
25+		puts(login);
26+	else
27+		eprintf("no login name\n");
28+
29+	return fshut(stdout, "<stdout>");
30+}
+491, -0
  1@@ -0,0 +1,491 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+#include <sys/types.h>
  5+#ifndef major
  6+#include <sys/sysmacros.h>
  7+#endif
  8+
  9+#include <dirent.h>
 10+#include <grp.h>
 11+#include <pwd.h>
 12+#include <stdio.h>
 13+#include <stdlib.h>
 14+#include <string.h>
 15+#include <time.h>
 16+#include <unistd.h>
 17+
 18+#include "utf.h"
 19+#include "util.h"
 20+
 21+struct entry {
 22+	char   *name;
 23+	mode_t  mode, tmode;
 24+	nlink_t nlink;
 25+	uid_t   uid;
 26+	gid_t   gid;
 27+	off_t   size;
 28+	struct timespec t;
 29+	dev_t   dev;
 30+	dev_t   rdev;
 31+	ino_t   ino, tino;
 32+};
 33+
 34+static struct {
 35+	dev_t dev;
 36+	ino_t ino;
 37+} *tree;
 38+
 39+static int ret   = 0;
 40+static int Aflag = 0;
 41+static int aflag = 0;
 42+static int cflag = 0;
 43+static int dflag = 0;
 44+static int Fflag = 0;
 45+static int fflag = 0;
 46+static int Hflag = 0;
 47+static int hflag = 0;
 48+static int iflag = 0;
 49+static int Lflag = 0;
 50+static int lflag = 0;
 51+static int nflag = 0;
 52+static int pflag = 0;
 53+static int qflag = 0;
 54+static int Rflag = 0;
 55+static int rflag = 0;
 56+static int Uflag = 0;
 57+static int uflag = 0;
 58+static int first = 1;
 59+static char sort = 0;
 60+static int showdirs;
 61+
 62+static void ls(const char *, const struct entry *, int);
 63+
 64+static void
 65+mkent(struct entry *ent, char *path, int dostat, int follow)
 66+{
 67+	struct stat st;
 68+
 69+	ent->name = path;
 70+	if (!dostat)
 71+		return;
 72+	if ((follow ? stat : lstat)(path, &st) < 0)
 73+		eprintf("%s %s:", follow ? "stat" : "lstat", path);
 74+	ent->mode  = st.st_mode;
 75+	ent->nlink = st.st_nlink;
 76+	ent->uid   = st.st_uid;
 77+	ent->gid   = st.st_gid;
 78+	ent->size  = st.st_size;
 79+	if (cflag)
 80+		ent->t = st.st_ctim;
 81+	else if (uflag)
 82+		ent->t = st.st_atim;
 83+	else
 84+		ent->t = st.st_mtim;
 85+	ent->dev   = st.st_dev;
 86+	ent->rdev  = st.st_rdev;
 87+	ent->ino   = st.st_ino;
 88+	if (S_ISLNK(ent->mode)) {
 89+		if (stat(path, &st) == 0) {
 90+			ent->tmode = st.st_mode;
 91+			ent->dev   = st.st_dev;
 92+			ent->tino  = st.st_ino;
 93+		} else {
 94+			ent->tmode = ent->tino = 0;
 95+		}
 96+	}
 97+}
 98+
 99+static char *
100+indicator(mode_t mode)
101+{
102+	if (pflag || Fflag)
103+		if (S_ISDIR(mode))
104+			return "/";
105+
106+	if (Fflag) {
107+		if (S_ISLNK(mode))
108+			return "@";
109+		else if (S_ISFIFO(mode))
110+			return "|";
111+		else if (S_ISSOCK(mode))
112+			return "=";
113+		else if (mode & S_IXUSR || mode & S_IXGRP || mode & S_IXOTH)
114+			return "*";
115+	}
116+
117+	return "";
118+}
119+
120+static void
121+printname(const char *name)
122+{
123+	const char *c;
124+	Rune r;
125+	size_t l;
126+
127+	for (c = name; *c; c += l) {
128+		l = chartorune(&r, c);
129+		if (!qflag || isprintrune(r))
130+			fwrite(c, 1, l, stdout);
131+		else
132+			putchar('?');
133+	}
134+}
135+
136+static void
137+output(const struct entry *ent)
138+{
139+	struct group *gr;
140+	struct passwd *pw;
141+	struct tm *tm;
142+	ssize_t len;
143+	char *fmt, buf[BUFSIZ], pwname[_SC_LOGIN_NAME_MAX],
144+	     grname[_SC_LOGIN_NAME_MAX], mode[] = "----------";
145+
146+	if (iflag)
147+		printf("%lu ", (unsigned long)ent->ino);
148+	if (!lflag) {
149+		printname(ent->name);
150+		puts(indicator(ent->mode));
151+		return;
152+	}
153+	if (S_ISREG(ent->mode))
154+		mode[0] = '-';
155+	else if (S_ISBLK(ent->mode))
156+		mode[0] = 'b';
157+	else if (S_ISCHR(ent->mode))
158+		mode[0] = 'c';
159+	else if (S_ISDIR(ent->mode))
160+		mode[0] = 'd';
161+	else if (S_ISFIFO(ent->mode))
162+		mode[0] = 'p';
163+	else if (S_ISLNK(ent->mode))
164+		mode[0] = 'l';
165+	else if (S_ISSOCK(ent->mode))
166+		mode[0] = 's';
167+	else
168+		mode[0] = '?';
169+
170+	if (ent->mode & S_IRUSR) mode[1] = 'r';
171+	if (ent->mode & S_IWUSR) mode[2] = 'w';
172+	if (ent->mode & S_IXUSR) mode[3] = 'x';
173+	if (ent->mode & S_IRGRP) mode[4] = 'r';
174+	if (ent->mode & S_IWGRP) mode[5] = 'w';
175+	if (ent->mode & S_IXGRP) mode[6] = 'x';
176+	if (ent->mode & S_IROTH) mode[7] = 'r';
177+	if (ent->mode & S_IWOTH) mode[8] = 'w';
178+	if (ent->mode & S_IXOTH) mode[9] = 'x';
179+
180+	if (ent->mode & S_ISUID) mode[3] = (mode[3] == 'x') ? 's' : 'S';
181+	if (ent->mode & S_ISGID) mode[6] = (mode[6] == 'x') ? 's' : 'S';
182+	if (ent->mode & S_ISVTX) mode[9] = (mode[9] == 'x') ? 't' : 'T';
183+
184+	if (!nflag && (pw = getpwuid(ent->uid)))
185+		snprintf(pwname, sizeof(pwname), "%s", pw->pw_name);
186+	else
187+		snprintf(pwname, sizeof(pwname), "%d", ent->uid);
188+
189+	if (!nflag && (gr = getgrgid(ent->gid)))
190+		snprintf(grname, sizeof(grname), "%s", gr->gr_name);
191+	else
192+		snprintf(grname, sizeof(grname), "%d", ent->gid);
193+
194+	if (time(NULL) > ent->t.tv_sec + (180 * 24 * 60 * 60)) /* 6 months ago? */
195+		fmt = "%b %d  %Y";
196+	else
197+		fmt = "%b %d %H:%M";
198+
199+	if ((tm = localtime(&ent->t.tv_sec)))
200+		strftime(buf, sizeof(buf), fmt, tm);
201+	else
202+		snprintf(buf, sizeof(buf), "%lld", (long long)(ent->t.tv_sec));
203+	printf("%s %4ld %-8.8s %-8.8s ", mode, (long)ent->nlink, pwname, grname);
204+
205+	if (S_ISBLK(ent->mode) || S_ISCHR(ent->mode))
206+		printf("%4u, %4u ", major(ent->rdev), minor(ent->rdev));
207+	else if (hflag)
208+		printf("%10s ", humansize(ent->size));
209+	else
210+		printf("%10lu ", (unsigned long)ent->size);
211+	printf("%s ", buf);
212+	printname(ent->name);
213+	fputs(indicator(ent->mode), stdout);
214+	if (S_ISLNK(ent->mode)) {
215+		if ((len = readlink(ent->name, buf, sizeof(buf) - 1)) < 0)
216+			eprintf("readlink %s:", ent->name);
217+		buf[len] = '\0';
218+		printf(" -> %s%s", buf, indicator(ent->tmode));
219+	}
220+	putchar('\n');
221+}
222+
223+static int
224+entcmp(const void *va, const void *vb)
225+{
226+	int cmp = 0;
227+	const struct entry *a = va, *b = vb;
228+
229+	switch (sort) {
230+	case 'S':
231+		cmp = b->size - a->size;
232+		break;
233+	case 't':
234+		if (!(cmp = b->t.tv_sec - a->t.tv_sec))
235+			cmp = b->t.tv_nsec - a->t.tv_nsec;
236+		break;
237+	}
238+
239+	if (!cmp)
240+		cmp = strcmp(a->name, b->name);
241+
242+	return rflag ? 0 - cmp : cmp;
243+}
244+
245+static void
246+lsdir(const char *path, const struct entry *dir)
247+{
248+	DIR *dp;
249+	struct entry *ent, *ents = NULL;
250+	struct dirent *d;
251+	size_t i, n = 0;
252+	char prefix[PATH_MAX];
253+
254+	if (!(dp = opendir(dir->name))) {
255+		ret = 1;
256+		weprintf("opendir %s%s:", path, dir->name);
257+		return;
258+	}
259+	if (chdir(dir->name) < 0)
260+		eprintf("chdir %s:", dir->name);
261+
262+	while ((d = readdir(dp))) {
263+		if (d->d_name[0] == '.' && !aflag && !Aflag)
264+			continue;
265+		else if (Aflag)
266+			if (strcmp(d->d_name, ".") == 0 ||
267+			    strcmp(d->d_name, "..") == 0)
268+				continue;
269+
270+		ents = ereallocarray(ents, ++n, sizeof(*ents));
271+		mkent(&ents[n - 1], estrdup(d->d_name), Fflag || iflag ||
272+		    lflag || pflag || Rflag || sort, Lflag);
273+	}
274+
275+	closedir(dp);
276+
277+	if (!Uflag)
278+		qsort(ents, n, sizeof(*ents), entcmp);
279+
280+	if (path[0] || showdirs) {
281+		fputs(path, stdout);
282+		printname(dir->name);
283+		puts(":");
284+	}
285+	for (i = 0; i < n; i++)
286+		output(&ents[i]);
287+
288+	if (Rflag) {
289+		if (snprintf(prefix, PATH_MAX, "%s%s/", path, dir->name) >=
290+		    PATH_MAX)
291+			eprintf("path too long: %s%s\n", path, dir->name);
292+
293+		for (i = 0; i < n; i++) {
294+			ent = &ents[i];
295+			if (strcmp(ent->name, ".") == 0 ||
296+			    strcmp(ent->name, "..") == 0)
297+				continue;
298+			if (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode) && !Lflag)
299+				continue;
300+
301+			ls(prefix, ent, 1);
302+		}
303+	}
304+
305+	for (i = 0; i < n; ++i)
306+		free(ents[i].name);
307+	free(ents);
308+}
309+
310+static int
311+visit(const struct entry *ent)
312+{
313+	dev_t dev;
314+	ino_t ino;
315+	int i;
316+
317+	dev = ent->dev;
318+	ino = S_ISLNK(ent->mode) ? ent->tino : ent->ino;
319+
320+	for (i = 0; i < PATH_MAX && tree[i].ino; ++i) {
321+		if (ino == tree[i].ino && dev == tree[i].dev)
322+			return -1;
323+	}
324+
325+	tree[i].ino = ino;
326+	tree[i].dev = dev;
327+
328+	return i;
329+}
330+
331+static void
332+ls(const char *path, const struct entry *ent, int listdir)
333+{
334+	int treeind;
335+	char cwd[PATH_MAX];
336+
337+	if (!listdir) {
338+		output(ent);
339+	} else if (S_ISDIR(ent->mode) ||
340+	    (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode))) {
341+		if ((treeind = visit(ent)) < 0) {
342+			ret = 1;
343+			weprintf("%s%s: Already visited\n", path, ent->name);
344+			return;
345+		}
346+
347+		if (!getcwd(cwd, PATH_MAX))
348+			eprintf("getcwd:");
349+
350+		if (first)
351+			first = 0;
352+		else
353+			putchar('\n');
354+
355+		lsdir(path, ent);
356+		tree[treeind].ino = 0;
357+
358+		if (chdir(cwd) < 0)
359+			eprintf("chdir %s:", cwd);
360+	}
361+}
362+
363+static void
364+usage(void)
365+{
366+	eprintf("usage: %s [-1AacdFfHhiLlnpqRrtUu] [file ...]\n", argv0);
367+}
368+
369+int
370+main(int argc, char *argv[])
371+{
372+	struct entry ent, *dents, *fents;
373+	size_t i, ds, fs;
374+
375+	tree = ereallocarray(NULL, PATH_MAX, sizeof(*tree));
376+
377+	ARGBEGIN {
378+	case '1':
379+		/* force output to 1 entry per line */
380+		qflag = 1;
381+		break;
382+	case 'A':
383+		Aflag = 1;
384+		break;
385+	case 'a':
386+		aflag = 1;
387+		break;
388+	case 'c':
389+		cflag = 1;
390+		uflag = 0;
391+		break;
392+	case 'd':
393+		dflag = 1;
394+		break;
395+	case 'f':
396+		aflag = 1;
397+		fflag = 1;
398+		Uflag = 1;
399+		break;
400+	case 'F':
401+		Fflag = 1;
402+		break;
403+	case 'H':
404+		Hflag = 1;
405+		break;
406+	case 'h':
407+		hflag = 1;
408+		break;
409+	case 'i':
410+		iflag = 1;
411+		break;
412+	case 'L':
413+		Lflag = 1;
414+		break;
415+	case 'l':
416+		lflag = 1;
417+		break;
418+	case 'n':
419+		lflag = 1;
420+		nflag = 1;
421+		break;
422+	case 'p':
423+		pflag = 1;
424+		break;
425+	case 'q':
426+		qflag = 1;
427+		break;
428+	case 'R':
429+		Rflag = 1;
430+		break;
431+	case 'r':
432+		rflag = 1;
433+		break;
434+	case 'S':
435+		sort = 'S';
436+		break;
437+	case 't':
438+		sort = 't';
439+		break;
440+	case 'U':
441+		Uflag = 1;
442+		break;
443+	case 'u':
444+		uflag = 1;
445+		cflag = 0;
446+		break;
447+	default:
448+		usage();
449+	} ARGEND
450+
451+	switch (argc) {
452+	case 0: /* fallthrough */
453+		*--argv = ".", ++argc;
454+	case 1:
455+		mkent(&ent, argv[0], 1, Hflag || Lflag);
456+		ls("", &ent, (!dflag && S_ISDIR(ent.mode)) ||
457+		    (S_ISLNK(ent.mode) && S_ISDIR(ent.tmode) &&
458+		     !(dflag || Fflag || lflag)));
459+
460+		break;
461+	default:
462+		for (i = ds = fs = 0, fents = dents = NULL; i < argc; ++i) {
463+			mkent(&ent, argv[i], 1, Hflag || Lflag);
464+
465+			if ((!dflag && S_ISDIR(ent.mode)) ||
466+			    (S_ISLNK(ent.mode) && S_ISDIR(ent.tmode) &&
467+			     !(dflag || Fflag || lflag))) {
468+				dents = ereallocarray(dents, ++ds, sizeof(*dents));
469+				memcpy(&dents[ds - 1], &ent, sizeof(ent));
470+			} else {
471+				fents = ereallocarray(fents, ++fs, sizeof(*fents));
472+				memcpy(&fents[fs - 1], &ent, sizeof(ent));
473+			}
474+		}
475+
476+		showdirs = ds > 1 || (ds && fs);
477+
478+		qsort(fents, fs, sizeof(ent), entcmp);
479+		qsort(dents, ds, sizeof(ent), entcmp);
480+
481+		for (i = 0; i < fs; ++i)
482+			ls("", &fents[i], 0);
483+		free(fents);
484+		if (fs && ds)
485+			putchar('\n');
486+		for (i = 0; i < ds; ++i)
487+			ls("", &dents[i], 1);
488+		free(dents);
489+	}
490+
491+	return (fshut(stdout, "<stdout>") | ret);
492+}
+61, -0
 1@@ -0,0 +1,61 @@
 2+char defaults[] = 
 3+	".SUFFIXES: .o .c .y .l .a .sh .f\n"
 4+
 5+	"AR = ar\n"
 6+	"ARFLAGS = -rv\n"
 7+	"CC = c99\n"
 8+	"CFLAGS = -O\n"
 9+	"FC = fort77\n"
10+	"FFLAGS = -O 1\n"
11+	"LDFLAGS =\n"
12+	"LEX = lex\n"
13+	"LFLAGS =\n"
14+	"YACC = yacc\n"
15+	"YFLAGS =\n"
16+	"SHELL = /bin/sh\n"
17+
18+	".c:\n"
19+	"\t${CC} ${CFLAGS} ${LDFLAGS} -o $@ $<\n"
20+
21+	".f:\n"
22+	"\t${FC} ${FFLAGS} ${LDFLAGS} -o $@ $<\n"
23+
24+	".sh:\n"
25+	"\tcp $< $@\n"
26+	"\tchmod a+x $@\n"
27+
28+	".c.o:\n"
29+	"\t${CC} ${CFLAGS} -c $<\n"
30+
31+	".f.o:\n"
32+	"\t${FC} ${FFLAGS} -c $<\n"
33+
34+	".y.o:\n"
35+	"\t${YACC} ${YFLAGS} $<\n"
36+	"\t${CC} ${CFLAGS} -c y.tab.c\n"
37+	"\trm -f y.tab.c\n"
38+	"\tmv y.tab.o $@\n"
39+
40+	".l.o:\n"
41+	"\t${LEX} ${LFLAGS} $<\n"
42+	"\t${CC} ${CFLAGS} -c lex.yy.c\n"
43+	"\trm -f lex.yy.c\n"
44+	"\tmv lex.yy.o $@\n"
45+
46+	".y.c:\n"
47+	"\t${YACC} ${YFLAGS} $<\n"
48+	"\tmv y.tab.c $@\n"
49+
50+	".l.c:\n"
51+	"\t${LEX} ${LFLAGS} $<\n"
52+	"\tmv lex.yy.c $@\n"
53+
54+	".c.a:\n"
55+	"\t${CC} -c ${CFLAGS} $<\n"
56+	"\t${AR} ${ARFLAGS} $@ $*.o\n"
57+	"\trm -f $*.o\n"
58+
59+	".f.a:\n"
60+	"\t${FC} -c ${FFLAGS} $<\n"
61+	"\t${AR} ${ARFLAGS} $@ $*.o\n"
62+	"\trm -f $*.o\n";
+377, -0
  1@@ -0,0 +1,377 @@
  2+#include <errno.h>
  3+#include <signal.h>
  4+#include <stdarg.h>
  5+#include <stdio.h>
  6+#include <stdlib.h>
  7+#include <string.h>
  8+
  9+#include "make.h"
 10+
 11+#ifndef SIGINT
 12+#define SIGINT -1
 13+#endif
 14+
 15+#ifndef SIGTERM
 16+#define SIGTERM -1
 17+#endif
 18+
 19+#ifndef SIGQUIT
 20+#define SIGQUIT -1
 21+#endif
 22+
 23+#ifndef SIGHUP
 24+#define SIGHUP -1
 25+#endif
 26+
 27+int kflag, dflag, nflag, iflag, sflag;
 28+int eflag, pflag, tflag, qflag;
 29+int exitstatus;
 30+volatile sig_atomic_t  stop;
 31+
 32+void
 33+debug(char *fmt, ...)
 34+{
 35+	va_list va;
 36+
 37+	if (!dflag)
 38+		return;
 39+
 40+	va_start(va, fmt);
 41+	vfprintf(stdout, fmt, va);
 42+	fputc('\n', stdout);
 43+	va_end(va);
 44+}
 45+
 46+int
 47+hash(char *name)
 48+{
 49+	int c;
 50+	unsigned h = 5381;
 51+
 52+	while (c = *name++)
 53+		h = h*33 ^ c;
 54+
 55+	return h;
 56+}
 57+
 58+void *
 59+emalloc(size_t siz)
 60+{
 61+	void *p;
 62+
 63+	if ((p = malloc(siz)) == NULL) {
 64+		perror("make");
 65+		exit(EXIT_FAILURE);
 66+	}
 67+
 68+	return p;
 69+}
 70+
 71+void *
 72+erealloc(void *p, size_t siz)
 73+{
 74+	if ((p = realloc(p, siz)) == NULL) {
 75+		perror("make");
 76+		exit(EXIT_FAILURE);
 77+	}
 78+
 79+	return p;
 80+}
 81+
 82+char *
 83+estrdup(char *s)
 84+{
 85+	size_t len;
 86+
 87+	len = strlen(s) + 1;
 88+	return memcpy(emalloc(len), s, len);
 89+}
 90+
 91+void
 92+sighandler(int signo)
 93+{
 94+	killchild();
 95+	stop = signo;
 96+}
 97+
 98+static void
 99+usage(void)
100+{
101+	fputs("usage: make [-eiknprSstd] [-f file] [-j jobs] "
102+	      "[macro=value ...] [target ...]\n",
103+	      stderr);
104+	exit(EXIT_FAILURE);
105+}
106+
107+static char *
108+getarg(char **args, char ***argv)
109+{
110+	char *s;
111+
112+	if ((*args)[1]) {
113+		s = (*args) + 1;
114+		*args += strlen(*args) - 1;
115+		return s;
116+	}
117+
118+	if (!argv)
119+		usage();
120+
121+	if ((*argv)[1] == NULL)
122+		usage();
123+	(*argv)++;
124+
125+	return **argv;
126+}
127+
128+static void
129+appendmakeflags(char *text)
130+{
131+	int n;
132+	char *s, *t, *fmt;
133+
134+	s = getmacro("MAKEFLAGS");
135+	fmt = *s ? "%s %s" : "%s%s";
136+	n = snprintf(NULL, 0, fmt, s, text);
137+
138+	t = emalloc(n+1);
139+	snprintf(t, n+1, fmt, s, text);
140+	setmacro("MAKEFLAGS", t, MAKEFLAGS, EXPORT);
141+
142+	free(t);
143+}
144+
145+static int
146+hasargs(int c)
147+{
148+	return c == 'f' || c == 'j';
149+}
150+
151+static void
152+parseflag(int flag, char **args, char ***argv)
153+{
154+	if (hasargs(flag))
155+		getarg(args, argv);
156+
157+	switch (flag) {
158+	case 'j':
159+	case 'f':
160+		break;
161+	case 'e':
162+		eflag = 1;
163+		appendmakeflags("-e");
164+		break;
165+	case 'i':
166+		iflag = 1;
167+		appendmakeflags("-i");
168+		break;
169+	case 'k':
170+		kflag = 1;
171+		appendmakeflags("-k");
172+		break;
173+	case 'n':
174+		nflag = 1;
175+		appendmakeflags("-n");
176+		break;
177+	case 'p':
178+		pflag = 1;
179+		break;
180+	case 'q':
181+		qflag = 1;
182+		appendmakeflags("-q");
183+		break;
184+	case 'r':
185+		addtarget(".SUFFIXES", 0);
186+		appendmakeflags("-r");
187+		break;	
188+	case 'S':
189+		kflag = 0;
190+		appendmakeflags("-S");
191+		break;
192+	case 's':
193+		sflag = 1;
194+		appendmakeflags("-s");
195+		break;
196+	case 't':
197+		tflag = 1;
198+		appendmakeflags("-t");
199+		break;
200+	case 'd':
201+		dflag = 1;
202+		appendmakeflags("-d");
203+		break;
204+	default:
205+		usage();
206+	}
207+}
208+
209+static int
210+assign(char *s, int where, int export)
211+{
212+	int pos;
213+	char *t;
214+
215+	if ((t = strchr(s, '=')) == NULL)
216+		return 0;
217+
218+	pos = t - s;
219+
220+	appendmakeflags(s);
221+	t = estrdup(s); 
222+	t[pos] = '\0';
223+
224+	setmacro(t, t+pos+1, where, export);
225+	free(t);
226+	return 1;
227+}
228+
229+static void
230+parseargv(char **argv, char ***targets, int where, int export)
231+{
232+	char *s;
233+	char *hm = NULL;
234+
235+	for ( ; *argv; ++argv) {
236+		s = *argv;
237+		if (hm == NULL && strcmp(s, "--") == 0) {
238+			hm = *argv;
239+		} else if (hm && s[0] == '-') {
240+			break;
241+		} else if (s[0] != '-') {
242+			if (!assign(s, where, export))
243+				break;
244+			continue;
245+		}
246+		while (hm == NULL && *++s)
247+			parseflag(*s, &s, &argv);
248+	}
249+
250+	if (targets)
251+		*targets = argv;
252+}
253+
254+static void
255+parsemakeflags(void)
256+{
257+	int c, n;
258+	char *s, *flags, **arr;
259+
260+	if ((flags = getenv("MAKEFLAGS")) == NULL)
261+		return;
262+
263+	setmacro("MAKEFLAGS", "", MAKEFLAGS, EXPORT);
264+
265+	while (*flags == ' ' || *flags == '\t')
266+		flags++;
267+
268+	if (flags[0] != '-' && !strchr(flags, '=')) {
269+		while (*flags) {
270+			parseflag(*flags, &flags, NULL);
271+			flags++;
272+		}
273+	} else {
274+		n = 0;
275+		arr = NULL;
276+		for (s = strtok(flags, " \t"); s; s = strtok(NULL, " \t")) {
277+			n++;
278+			arr = erealloc(arr, sizeof(char *) * (n+1));
279+			arr[n-1] = s;
280+			arr[n] = NULL;
281+		}
282+
283+		if (arr)
284+			parseargv(arr, NULL, MAKEFLAGS, NOEXPORT);
285+		free(arr);
286+	}
287+}
288+
289+static void
290+parsemakefiles(char **argv)
291+{
292+	char *s, *arg;
293+	int c, hasmake;
294+
295+	hasmake = 0;
296+	for ( ; *argv && **argv == '-'; ++argv) {
297+		for (s = *argv; c = *s; ++s) {
298+			if (hasargs(c))
299+				arg = getarg(&s, &argv);
300+
301+			if (c == 'f') {
302+				if (strcmp(arg, "-") == 0)
303+					arg = NULL;
304+				parse(arg);
305+				hasmake = 1;
306+			}
307+		}
308+	}
309+
310+	if (hasmake)
311+		return;
312+
313+	if (parse("makefile"))
314+		return;
315+	if (parse("Makefile"))
316+		return;
317+}
318+
319+/*
320+ * We want to enable debug as earlier as possible,
321+ * if we wait until we read the Makefiles then
322+ * we are going to lose to much debug information.
323+ */
324+static void
325+enadebug(char *argv[])
326+{
327+	int c;
328+	char *p;
329+
330+	for ( ; *argv && **argv == '-'; ++argv) {
331+		p = *argv;
332+		for (++p; c = *p; ++p) {
333+			if (hasargs(c))
334+				getarg(&p, &argv);
335+			if (c == 'd')
336+				dflag = 1;
337+		}
338+	}
339+}
340+
341+int
342+main(int argc, char *argv[])
343+{
344+	char *arg0, **targets;
345+
346+	signal(SIGINT, sighandler);
347+	signal(SIGHUP, sighandler);
348+	signal(SIGTERM, sighandler);
349+	signal(SIGQUIT, sighandler);
350+
351+	targets = NULL;
352+	arg0 = *argv++;
353+
354+	enadebug(argv);
355+	inject(defaults);
356+	setmacro("MAKE", arg0, MAKEFILE, NOEXPORT);
357+
358+	parsemakeflags();
359+	parseargv(argv, &targets, CMDLINE, EXPORT);
360+	parsemakefiles(argv);
361+
362+	if (pflag) {
363+		dumpmacros();
364+		dumprules();
365+		exit(EXIT_SUCCESS);
366+	}
367+
368+	if (!*targets) {
369+		build(NULL);
370+	} else {
371+		while (*targets)
372+			build(*targets++);
373+	}
374+
375+	exit(exitstatus);
376+
377+	return 0;
378+}
+87, -0
 1@@ -0,0 +1,87 @@
 2+#include <stddef.h>
 3+#include <time.h>
 4+
 5+typedef struct target Target;
 6+
 7+enum {
 8+	NOEXPORT,
 9+	EXPORT,
10+};
11+
12+enum {
13+	UNDEF,
14+	ENVIRON,
15+	CMDLINE,
16+	INTERNAL,
17+	MAKEFILE,
18+	MAKEFLAGS,
19+};
20+
21+struct loc {
22+	char *fname;
23+	int lineno;
24+};
25+
26+struct action {
27+	char *line;
28+	struct loc loc;
29+};
30+
31+struct target {
32+	char *name;
33+	char *target;
34+	char *req;
35+	time_t stamp;
36+	int defined;
37+
38+	int ndeps;
39+	struct target **deps;
40+
41+	int nactions;
42+	struct action *actions;
43+
44+	struct target *next;
45+};
46+
47+void *emalloc(size_t);
48+void *erealloc(void *, size_t);
49+char *estrdup(char *);
50+
51+void dumprules(void);
52+void dumpmacros(void);
53+
54+char *expandstring(char *, Target *, struct loc *);
55+void addtarget(char *, int);
56+void inject(char *);
57+int build(char *);
58+int hash(char *);
59+int parse(char *);
60+void debug(char *, ...);
61+void error(char *, ...);
62+void warning(char *, ...);
63+void adddep(char *, char *);
64+void addrule(char *, struct action *, int);
65+void freeloc(struct loc *);
66+
67+char *getmacro(char *);
68+void setmacro(char *, char *, int, int);
69+
70+/* system depdendant */
71+void killchild(void);
72+time_t stamp(char *);
73+int launch(char *, int);
74+int putenv(char *);
75+void exportvar(char *, char *);
76+int is_dir(char *);
77+
78+/* main.c */
79+extern int kflag, dflag, nflag, iflag, sflag;
80+extern int eflag, pflag, tflag, qflag;
81+extern int exitstatus;
82+
83+#ifdef SIGABRT
84+extern volatile sig_atomic_t stop;
85+#endif
86+
87+/* defaults.c */
88+extern char defaults[];
+1034, -0
   1@@ -0,0 +1,1034 @@
   2+#include <assert.h>
   3+#include <ctype.h>
   4+#include <errno.h>
   5+#include <limits.h>
   6+#include <stdarg.h>
   7+#include <stdio.h>
   8+#include <stdlib.h>
   9+#include <string.h>
  10+
  11+#include "make.h"
  12+
  13+#define MAXREPL  30
  14+#define TABSIZ   64
  15+#define MAXTOKEN FILENAME_MAX
  16+#define ITEM     128
  17+
  18+typedef struct macro Macro;
  19+
  20+enum inputype {
  21+	FTFILE,
  22+	FTEXPAN,
  23+};
  24+
  25+enum {
  26+	STBEGIN,
  27+	STINTERNAL,
  28+	STREPLACE,
  29+	STTO,
  30+	STEND,
  31+};
  32+
  33+struct input {
  34+	int siz;
  35+	int type;
  36+
  37+	FILE *fp;
  38+	struct loc loc;
  39+
  40+	int pos;
  41+	char *buf;
  42+
  43+	struct input *prev;
  44+};
  45+
  46+struct macro {
  47+	char *name;
  48+	char *value;
  49+	int where;
  50+
  51+	struct macro *next;
  52+};
  53+
  54+static struct input *input;
  55+static char token[MAXTOKEN];
  56+static int tok;
  57+static Macro *htab[TABSIZ];
  58+
  59+void
  60+dumpmacros(void)
  61+{
  62+	Macro **pp, *p;
  63+
  64+	for (pp = htab; pp < &htab[TABSIZ]; ++pp) {
  65+		for (p = *pp; p; p = p->next)
  66+			printf("%s = %s\n", p->name, getmacro(p->name));
  67+	}
  68+}
  69+
  70+static Macro *
  71+lookup(char *name)
  72+{
  73+	Macro *mp;
  74+	int h = hash(name) & TABSIZ-1;
  75+
  76+	for (mp = htab[h]; mp && strcmp(mp->name, name); mp = mp->next)
  77+		;
  78+
  79+	if (mp)
  80+		return mp;
  81+
  82+	mp = emalloc(sizeof(*mp));
  83+	mp->name = estrdup(name);
  84+	mp->value = estrdup("");
  85+	mp->next = htab[h];
  86+	mp->where = UNDEF;
  87+	htab[h] = mp;
  88+
  89+	return mp;
  90+}
  91+
  92+static char *
  93+macroinfo(char *name, int *pwhere, Macro **mpp)
  94+{
  95+	char *s, *t;
  96+	int hide, where;
  97+	Macro *mp = lookup(name);
  98+
  99+	hide = 0;
 100+	if (!strcmp(name, "SHELL") || !strcmp(name, "MAKEFLAGS"))
 101+		hide = 1;
 102+
 103+	s = mp->value;
 104+	where = mp->where;
 105+
 106+	if (!hide && (where == UNDEF || where == INTERNAL || eflag)) {
 107+		t = getenv(name);
 108+		if (t) {
 109+			where = ENVIRON;
 110+			s = t;
 111+		}
 112+	}
 113+
 114+	if (pwhere)
 115+		*pwhere = where;
 116+	if (mpp)
 117+		*mpp = mp;
 118+
 119+	return s;
 120+}
 121+
 122+char *
 123+getmacro(char *name)
 124+{
 125+	return macroinfo(name, NULL, NULL);
 126+}
 127+
 128+void
 129+setmacro(char *name, char *val, int where, int export)
 130+{
 131+	int owhere, set;
 132+	char *s;
 133+	Macro *mp;
 134+
 135+	assert(where != ENVIRON);
 136+
 137+	s = macroinfo(name, &owhere, &mp);
 138+
 139+	/*
 140+	 *  Default values are defined before anything else, and marked
 141+	 *  as INTERNAL because they are injected as parseable text, and
 142+	 *  MAKEFILE and INTERNAL variables are always overriden. ENVIRON
 143+	 *  macros are generated in macroinfo() and this is why this function
 144+	 *  should not receive a where == ENVIRON ever.
 145+	 */
 146+	switch (owhere) {
 147+	case UNDEF:
 148+	case INTERNAL:
 149+	case MAKEFILE:
 150+		set = 1;
 151+		break;
 152+	case ENVIRON:
 153+		set = (where == MAKEFLAGS || where == CMDLINE);
 154+		set |= (where == MAKEFILE && !eflag);
 155+		break;
 156+	case MAKEFLAGS:
 157+		set = (where == CMDLINE || where == MAKEFLAGS);
 158+		break;
 159+	case CMDLINE:
 160+		set = (where == CMDLINE);
 161+		break;
 162+	default:
 163+		abort();
 164+	}
 165+
 166+	if (!set) {
 167+		debug("hidding override of %s from '%s' to '%s'", name, s, val);
 168+	} else {
 169+		debug("override %s from '%s' to '%s'", name, s, val);
 170+		free(mp->value);
 171+		mp->value = estrdup(val);
 172+		mp->where = where;
 173+
 174+		if (export && strcmp(name, "SHELL") != 0) {
 175+			debug("exporting macro %s", name);
 176+			exportvar(name, val);
 177+		}
 178+	}
 179+}
 180+
 181+void
 182+freeloc(struct loc *loc)
 183+{
 184+	free(loc->fname);
 185+}
 186+
 187+static struct loc *
 188+getloc(void)
 189+{
 190+	struct input *ip;
 191+
 192+	for (ip = input; ip && ip->type != FTFILE; ip = ip->prev)
 193+		;
 194+	if (!ip)
 195+		return NULL;
 196+
 197+	return &ip->loc;
 198+}
 199+
 200+
 201+void
 202+error(char *fmt, ...)
 203+{
 204+	va_list va;
 205+	struct loc *loc;
 206+
 207+	fprintf(stderr, "make: error: ");
 208+	if ((loc = getloc()) != NULL)
 209+		fprintf(stderr, "%s:%d: ", loc->fname, loc->lineno);
 210+
 211+	va_start(va, fmt);
 212+	vfprintf(stderr, fmt, va);
 213+	va_end(va);
 214+	putc('\n', stderr);
 215+
 216+	exit(EXIT_FAILURE);
 217+}
 218+
 219+void
 220+warning(char *fmt, ...)
 221+{
 222+	va_list va;
 223+	struct loc *loc;
 224+
 225+	fprintf(stderr, "make: warning: ");
 226+	if ((loc = getloc()) != NULL)
 227+		fprintf(stderr, "%s:%d: ", loc->fname, loc->lineno);
 228+
 229+	va_start(va, fmt);
 230+	vfprintf(stderr, fmt, va);
 231+	va_end(va);
 232+	putc('\n', stderr);
 233+}
 234+
 235+static void
 236+pop(void)
 237+{
 238+	struct input *ip = input->prev;
 239+
 240+	if (input->type == FTFILE) {
 241+		if (input->fp)
 242+			fclose(input->fp);
 243+		freeloc(&input->loc);
 244+	}
 245+	free(input->buf);
 246+	free(input);
 247+
 248+	input = ip;
 249+}
 250+
 251+static void
 252+push(int type, ...)
 253+{
 254+	int line, len, pos;
 255+	FILE *fp = NULL;
 256+	char *buf, *s, *fname = NULL;
 257+	va_list va;
 258+	struct input *ip;
 259+
 260+	va_start(va, type);
 261+	switch (type) {
 262+	case FTFILE:
 263+		fp = va_arg(va, FILE *);
 264+		s = va_arg(va, char *);
 265+		line = va_arg(va, int);
 266+		fname = estrdup(s);
 267+		buf = emalloc(BUFSIZ);
 268+		pos = len = BUFSIZ;
 269+		break;
 270+	case FTEXPAN:
 271+		s = va_arg(va, char *);
 272+		buf = estrdup(s);
 273+		line = pos = 0;
 274+		len = strlen(s);
 275+		break;
 276+	}
 277+	va_end(va);
 278+
 279+	ip = emalloc(sizeof(*ip));
 280+	ip->siz = len;
 281+	ip->buf = buf;
 282+	ip->type = type;
 283+	ip->fp = fp;
 284+	ip->loc.fname = fname;
 285+	ip->loc.lineno = line;
 286+	ip->pos = pos;
 287+	ip->prev = input;
 288+
 289+	input = ip;
 290+}
 291+
 292+static char *
 293+trim(char *s)
 294+{
 295+	size_t len;
 296+
 297+	while (isspace(*s))
 298+		s++;
 299+
 300+	for (len = strlen(s); len > 0 && isspace(s[len-1]); --len)
 301+		s[len-1] = '\0';
 302+
 303+	return s;
 304+}
 305+
 306+static void
 307+include(char *s)
 308+{
 309+	int len;
 310+	FILE *fp;
 311+	char *fil, *t;
 312+
 313+	s = trim(s);
 314+	fil = expandstring(s, NULL, getloc());
 315+
 316+	t = trim(fil);
 317+	if (strlen(t) != 0) {
 318+		debug("including '%s'", t);
 319+		if ((fp = fopen(t, "r")) == NULL)
 320+			error("opening %s:%s", t, strerror(errno));
 321+		push(FTFILE, fp, t, 0);
 322+	}
 323+
 324+	free(fil);
 325+}
 326+
 327+static char *
 328+nextline(void)
 329+{
 330+	int c;
 331+	FILE *fp;
 332+	char *s, *lim;
 333+
 334+	assert(input->type == FTFILE);
 335+
 336+repeat:
 337+	fp = input->fp;
 338+	if (!fp || feof(fp))
 339+		return NULL;
 340+
 341+	lim = &input->buf[input->siz];
 342+	for (s = input->buf; s < lim; *s++ = c) {
 343+		c = getc(fp);
 344+		if (c == '\n' || c == EOF) {
 345+			input->loc.lineno++;
 346+			*s++ = '\n';
 347+			break;
 348+		}
 349+		if (c > UCHAR_MAX || c < 0)
 350+			error("invalid character '%c' (%d)", c, c);
 351+	}
 352+
 353+
 354+	if (s == lim)
 355+		error("too long line");
 356+	if (ferror(fp))
 357+		error(strerror(errno));
 358+	*s = '\0';
 359+
 360+	if (!strcmp(input->buf, ""))
 361+		goto repeat;
 362+
 363+	if (!strncmp(input->buf, "include", 7) && isblank(input->buf[7])) {
 364+		input->pos = input->siz;
 365+		include(input->buf+7);
 366+		goto repeat;
 367+	}
 368+
 369+	input->pos = 0;
 370+
 371+
 372+	return input->buf;
 373+}
 374+
 375+static int
 376+empty(struct input *ip)
 377+{
 378+	return ip->pos == ip->siz || ip->buf[ip->pos] == '\0';
 379+}
 380+
 381+static int
 382+moreinput(void)
 383+{
 384+	while (input) {
 385+		if (!empty(input))
 386+			break;
 387+
 388+		switch (input->type) {
 389+		case FTEXPAN:
 390+			pop();
 391+			break;
 392+		case FTFILE:
 393+			if (!nextline())
 394+				pop();
 395+			break;
 396+		}
 397+	}
 398+
 399+	return input != NULL;
 400+}
 401+
 402+static int
 403+nextc(void)
 404+{
 405+	if (!moreinput())
 406+		return EOF;
 407+
 408+	return input->buf[input->pos++];
 409+}
 410+
 411+/*
 412+ * This function only can be called after a call to nextc
 413+ * that didn't return EOF. It can return '\0', but as
 414+ * it is used only to check against '$' then it is not
 415+ * a problem.
 416+ */
 417+static int
 418+ahead(void)
 419+{
 420+	return input->buf[input->pos];
 421+}
 422+
 423+static int
 424+back(int c)
 425+{
 426+	if (c == EOF)
 427+		return c;
 428+	assert(input->pos > 0);
 429+	return input->buf[--input->pos] = c;
 430+}
 431+
 432+static void
 433+comment(void)
 434+{
 435+	int c;
 436+
 437+	while ((c = nextc()) != EOF && c != '\n') {
 438+		if (c == '\\' && nextc() == EOF)
 439+			break;
 440+	}
 441+}
 442+
 443+static void
 444+skipspaces(void)
 445+{
 446+	int c;
 447+
 448+	for (c = nextc(); c == ' ' || c == '\t'; c = nextc())
 449+		;
 450+	back(c);
 451+}
 452+
 453+static int
 454+validchar(int c)
 455+{
 456+	if (c == EOF)
 457+		return 0;
 458+	return c == '.' || c == '/' || c == '_' || c == '-' || isalnum(c);
 459+}
 460+
 461+static char *
 462+expandmacro(char *name)
 463+{
 464+	char *s;
 465+
 466+	s = expandstring(getmacro(name), NULL, getloc());
 467+	debug("macro %s expanded to '%s'", name, s);
 468+
 469+	return s;
 470+}
 471+
 472+static void
 473+replace(char *line, char *repl, char *to)
 474+{
 475+	int siz, at, len, replsiz, tosiz, sep, pos;
 476+	char *oline, *s, *cur, *buf;
 477+
 478+	debug("replacing '%s', with '%s' to '%s'", line, repl, to);
 479+	oline = line;
 480+	tosiz = strlen(to);
 481+	replsiz = strlen(repl);
 482+
 483+	buf = NULL;
 484+	for (pos = 0; *line; pos += siz) {
 485+		cur = NULL;
 486+		siz = 0;
 487+
 488+		for (siz = 0; *line == ' ' || *line == '\t'; ++siz) {
 489+			cur = erealloc(cur, siz+1);
 490+			cur[siz] = *line++;
 491+		}
 492+
 493+		len = strcspn(line, " \t");
 494+		at = len - replsiz;
 495+		if (at < 0 || memcmp(line + at, repl, replsiz)) {
 496+			cur = erealloc(cur, siz + len);
 497+			memcpy(cur + siz, line, len);
 498+			siz += len;
 499+		} else {
 500+			cur = erealloc(cur, siz + at + tosiz);
 501+			memcpy(cur + siz, line, at);
 502+			memcpy(cur + siz + at, to, tosiz);
 503+			siz += at + tosiz;
 504+		}
 505+
 506+		line += len;
 507+		buf = erealloc(buf, pos + siz);
 508+		memcpy(buf + pos, cur, siz);
 509+		free(cur);
 510+	}
 511+
 512+	if (pos > 0) {
 513+		buf = erealloc(buf, pos + 1);
 514+		buf[pos] = '\0';
 515+		debug("\treplace '%s' with '%s'", oline, buf);
 516+		push(FTEXPAN, buf);
 517+	}
 518+
 519+	free(buf);
 520+}
 521+
 522+static void
 523+expandsimple(Target *tp)
 524+{
 525+	char *s;
 526+	Target **p;
 527+	int len, c;
 528+
 529+	switch (c = nextc()) {
 530+	case '@':
 531+		if (!tp || !tp->target)
 532+			return;
 533+		push(FTEXPAN, tp->target);
 534+		break;
 535+	case '<':
 536+		if (!tp || !tp->req)
 537+			return;
 538+		push(FTEXPAN, tp->req);
 539+		break;
 540+	case '*':
 541+		if (!tp || !tp->target)
 542+			return;
 543+		s = strrchr(tp->target, '.');
 544+		if (!s) {
 545+			push(FTEXPAN, tp->target);
 546+			return;
 547+		}
 548+
 549+		len = s - tp->target;
 550+		s = emalloc(len+1);
 551+		memcpy(s, tp->target, len);
 552+		s[len] = '\0';
 553+		push(FTEXPAN, s);
 554+		free(s);
 555+		break;
 556+	case '?':
 557+		if (!tp)
 558+			return;
 559+
 560+		if (tp->req && stamp(tp->req) > tp->stamp) {
 561+			push(FTEXPAN, " ");
 562+			push(FTEXPAN, tp->req);
 563+		}
 564+
 565+		for (p = tp->deps; p && *p; ++p) {
 566+			if (stamp((*p)->name) > tp->stamp) {
 567+				push(FTEXPAN, " ");
 568+				push(FTEXPAN, (*p)->name);
 569+			}
 570+		}
 571+		break;
 572+	default:
 573+		token[0] = c;
 574+		token[1] = '\0';
 575+		s = expandmacro(token);
 576+		push(FTEXPAN, s);
 577+		free(s);
 578+		break;
 579+	}
 580+}
 581+
 582+static int
 583+internal(int ch)
 584+{
 585+	switch (ch) {
 586+	case '@':
 587+	case '?':
 588+	case '*':
 589+	case '<':
 590+		return 1;
 591+	default:
 592+		return 0;
 593+	}
 594+}
 595+
 596+static void
 597+expansion(Target *tp)
 598+{
 599+	int delim, c, repli, toi, namei, st;
 600+	char name[MAXTOKEN], repl[MAXREPL], to[MAXREPL];
 601+	char *s, *erepl;
 602+
 603+	c = nextc();
 604+	if (c == '(')
 605+		delim = ')';
 606+	else if (c == '{')
 607+		delim = '}';
 608+	else
 609+		delim = 0;
 610+
 611+	if (!delim) {
 612+		back(c);
 613+		expandsimple(tp);
 614+		return;
 615+	}
 616+
 617+	s = NULL;
 618+	namei = repli = toi = 0;
 619+	st = STBEGIN;
 620+
 621+	while (st != STEND && (c = nextc()) != EOF) {
 622+		switch (st) {
 623+		case STBEGIN:
 624+			if (c == ':') {
 625+				st = STREPLACE;
 626+				name[namei] = '\0';
 627+				s = expandmacro(name);
 628+				break;
 629+			}
 630+			if (c == delim) {
 631+				name[namei] = '\0';
 632+				s = expandmacro(name);
 633+				goto no_replace;
 634+			}
 635+			if (namei == MAXTOKEN-1)
 636+				error("expansion text too long");
 637+
 638+			if (namei == 0 && internal(c)) {
 639+				name[namei++] = '$';
 640+				name[namei++] = c;
 641+				name[namei] = '\0';
 642+				st = STINTERNAL;
 643+				s = expandstring(name, tp, getloc());
 644+				break;
 645+			}
 646+
 647+			if (!validchar(c))
 648+				error("invalid macro name in expansion");
 649+			name[namei++] = c;
 650+			break;
 651+		case STINTERNAL:
 652+			if (c == delim)
 653+				goto no_replace;
 654+			if (c != ':')
 655+				error("invalid internal macro in expansion");
 656+			st = STREPLACE;
 657+			break;
 658+		case STREPLACE:
 659+			if (c == '=') {
 660+				st = STTO;
 661+				break;
 662+			}
 663+			if (c == delim)
 664+				error("invalid replacement pattern in expansion");
 665+			if (repli == MAXREPL-1)
 666+				error("macro replacement too big");
 667+			repl[repli++] = c;
 668+			break;
 669+		case STTO:
 670+			if (c == delim) {
 671+				st = STEND;
 672+				break;
 673+			}
 674+
 675+			if (toi == MAXREPL-1)
 676+				error("macro substiturion too big");
 677+			to[toi++] = c;
 678+			break;
 679+		}
 680+	}
 681+
 682+	if (c == EOF)
 683+		error("found eof while parsing expansion");
 684+
 685+	repl[repli] = '\0';
 686+	to[toi] = '\0';
 687+
 688+	erepl = expandstring(repl, tp, getloc());
 689+	replace(s, erepl, to);
 690+
 691+	free(erepl);
 692+	free(s);
 693+	return;
 694+
 695+no_replace:
 696+	push(FTEXPAN, s);
 697+	free(s);
 698+}
 699+
 700+/*
 701+ * Horrible hack to do string expansion.
 702+ * We cannot use normal push and nextc because that
 703+ * would consume characters of the current file too.
 704+ * For that reason it cleans the input and it recovers
 705+ * it later.
 706+ */
 707+char *
 708+expandstring(char *line, Target *tp, struct loc *loc)
 709+{
 710+	int c, n;
 711+	char *s;
 712+	struct input *ip = input;
 713+
 714+	input = NULL;
 715+	push(FTFILE, NULL, loc->fname, loc->lineno);
 716+	push(FTEXPAN, line);
 717+
 718+	n = 0;
 719+	s = NULL;
 720+	while ((c = nextc()) != EOF) {
 721+		if (c != '$') {
 722+			s = erealloc(s, ++n);
 723+			s[n-1] = c;
 724+			continue;
 725+		}
 726+
 727+		if ((c = nextc()) == '$') {
 728+			s = erealloc(s, n += 2);
 729+			s[n-2] = '$';
 730+			s[n-1] = '$';
 731+		} else {
 732+			back(c);
 733+			expansion(tp);
 734+		}
 735+	}
 736+
 737+	s = erealloc(s, n+1);
 738+	s[n] = '\0';
 739+	input = ip;
 740+
 741+	return s;
 742+}
 743+
 744+static int
 745+item(void)
 746+{
 747+	int c;
 748+	char *s;
 749+	char buf[MAXTOKEN];
 750+
 751+	for (s = buf; s < &buf[MAXTOKEN] - 1; ) {
 752+		c = nextc();
 753+		if (c == '$' && ahead() != '$')
 754+			expansion(NULL);
 755+		else if (validchar(c))
 756+			*s++ = c;
 757+		else
 758+			break;
 759+	}
 760+	back(c);
 761+
 762+	if (s >= &buf[MAXTOKEN] - 1)
 763+		error("token too long");
 764+	if (s == buf)
 765+		error("invalid empty token");
 766+	*s++ = '\0';
 767+	memcpy(token, buf, s - buf);
 768+
 769+	return ITEM;
 770+}
 771+
 772+static int
 773+next(void)
 774+{
 775+	int c;
 776+
 777+repeat:
 778+	/*
 779+	 * It is better to avoid skipspaces() here, because
 780+	 * it can generate the need for 2 calls to back(),
 781+	 * and we need the character anyway.
 782+	 */
 783+	c = nextc();
 784+	if (c == ' ' || c == '\t')
 785+		goto repeat;
 786+
 787+	if (c == '\\') {
 788+		if ((c = nextc()) == '\n')
 789+			goto repeat;
 790+		back(c);
 791+		c = '\\';
 792+	}
 793+
 794+	switch (c) {
 795+	case EOF:
 796+		strcpy(token, "<EOF>");
 797+		tok = EOF;
 798+		break;
 799+	case '$':
 800+		if ((c = nextc()) == '$')
 801+			goto single;
 802+		back(c);
 803+		expansion(NULL);
 804+		goto repeat;
 805+	case '#':
 806+		comment();
 807+		c = '\n';
 808+	case ';':
 809+	case ':':
 810+	case '=':
 811+	case '\n':
 812+	single:
 813+		token[0] = c;
 814+		token[1] = '\0';
 815+		tok = c;
 816+		break;
 817+	default:
 818+		if (!validchar(c))
 819+			error("unexpected character '%c'", c);
 820+		back(c);
 821+		tok = item();
 822+		break;
 823+	}
 824+
 825+	return tok;
 826+}
 827+
 828+static char *
 829+readmacrodef(void)
 830+{
 831+	int n, c;
 832+	char *line;
 833+
 834+	n = 0;
 835+	line = NULL;
 836+	while ((c = nextc()) != EOF) {
 837+		line = erealloc(line, n+1);
 838+		if (c == '\n')
 839+			break;
 840+		if (c == '#') {
 841+			comment();
 842+			break;
 843+		}
 844+		if (c == '\\') {
 845+			if ((c = nextc()) != '\n') {
 846+				back(c);
 847+				c = '\\';
 848+			} else {
 849+				skipspaces();
 850+				c = ' ';
 851+			}
 852+		}
 853+
 854+		line[n++] = c;
 855+	}
 856+	if (c == EOF)
 857+		error("EOF while looking for end of line");
 858+	line[n] = '\0';
 859+
 860+	return line;
 861+}
 862+
 863+static struct action
 864+readcmd(void)
 865+{
 866+	int n, c;
 867+	struct loc *loc;
 868+	struct action act;
 869+
 870+	skipspaces();
 871+
 872+	loc = getloc();
 873+	act.loc.fname = estrdup(loc->fname);
 874+	act.loc.lineno = loc->lineno;
 875+
 876+	n = 0;
 877+	act.line = NULL;
 878+	while ((c = nextc()) != EOF) {
 879+		act.line = erealloc(act.line, n+1);
 880+		if (c == '\n')
 881+			break;
 882+		if (c == '\\') {
 883+			if ((c = nextc()) == '\n') {
 884+				if ((c = nextc()) != '\t')
 885+					back(c);
 886+				continue;
 887+			}
 888+			back(c);
 889+			c = '\\';
 890+		}
 891+		act.line[n++] = c;
 892+	}
 893+	if (c == EOF)
 894+		error("EOF while looking for end of command");
 895+	act.line[n] = '\0';
 896+
 897+	return act;
 898+}
 899+
 900+static void
 901+rule(char *targets[], int ntargets)
 902+{
 903+	int c, i, j, ndeps, nactions;
 904+	struct action *acts;
 905+	char **deps = NULL;
 906+
 907+	if (ntargets == 0)
 908+		error("missing target");
 909+
 910+	for (ndeps = 0; next() == ITEM; ++ndeps) {
 911+		deps = erealloc(deps, (ndeps+1) * sizeof(char *));
 912+		deps[ndeps] = estrdup(token);
 913+	}
 914+
 915+	if (tok != '\n' && tok != ';')
 916+		error("garbage at the end of the line");
 917+
 918+	nactions = 0;
 919+	acts = NULL;
 920+	if (tok == ';') {
 921+		nactions++;
 922+		acts = erealloc(acts, nactions * sizeof(*acts));
 923+		acts[nactions-1] = readcmd();
 924+	}
 925+
 926+	for (;;) {
 927+		if ((c = nextc()) == '#') {
 928+			comment();
 929+			continue;
 930+		}
 931+		if (c != '\t')
 932+			break;
 933+		nactions++;
 934+		acts = erealloc(acts, nactions * sizeof(*acts));
 935+		acts[nactions-1] = readcmd();
 936+	}
 937+	back(c);
 938+
 939+	for (i = 0; i < ntargets; i++) {
 940+		addtarget(targets[i], ndeps);
 941+		for (j = 0; j < ndeps; j++)
 942+			adddep(targets[i], deps[j]);
 943+		if (nactions > 0)
 944+			addrule(targets[i], acts, nactions);
 945+	}
 946+
 947+	for (i = 0; i < ndeps; i++)
 948+		free(deps[i]);
 949+	free(deps);
 950+
 951+	for (i = 0; i < nactions; i++) {
 952+		free(acts[i].line);
 953+		freeloc(&acts[i].loc);
 954+	}
 955+	free(acts);
 956+}
 957+
 958+static void
 959+assign(char *macros[], int where, int n)
 960+{
 961+	char *defs;
 962+
 963+	if (n != 1)
 964+		error("invalid macro definition");
 965+
 966+	skipspaces();
 967+	defs = readmacrodef();
 968+	setmacro(*macros, defs, where, NOEXPORT);
 969+	free(defs);
 970+}
 971+
 972+void
 973+parseinput(int where)
 974+{
 975+	int i, n;
 976+	char **targets;
 977+
 978+	while (moreinput()) {
 979+		n = 0;
 980+		targets = NULL;
 981+
 982+		next();
 983+		if (tok == '\n')
 984+			continue;
 985+
 986+		while (tok == ITEM) {
 987+			n++;
 988+			targets = erealloc(targets, n * sizeof(char *));
 989+			targets[n-1] = estrdup(token);
 990+			next();
 991+		}
 992+
 993+		switch (tok) {
 994+		case ':':
 995+			rule(targets, n);
 996+			break;
 997+		case '=':
 998+			assign(targets, where, n);
 999+			break;
1000+		default:
1001+			error("unexpected token '%s'(%d)", token, tok);
1002+		}
1003+
1004+		for (i = 0; i < n; i++)
1005+			free(targets[i]);
1006+		free(targets);
1007+	}
1008+}
1009+
1010+int
1011+parse(char *fname)
1012+{
1013+	FILE *fp;
1014+
1015+	if (!fname) {
1016+		fp = stdin;
1017+		fname = "<stdin>";
1018+	} else if ((fp = fopen(fname, "r")) == NULL) {
1019+		return 0;
1020+	}
1021+
1022+	debug("parsing %s", fname);
1023+	push(FTFILE, fp, fname, 0);
1024+	parseinput(MAKEFILE);
1025+
1026+	return 1;
1027+}
1028+
1029+void
1030+inject(char *s)
1031+{
1032+	push(FTFILE, NULL, "<internal>", 0);
1033+	push(FTEXPAN, s);
1034+	parseinput(INTERNAL);
1035+}
+119, -0
  1@@ -0,0 +1,119 @@
  2+#undef _POSIX_C_SOURCE
  3+#define _POSIX_C_SOURCE 200809L
  4+
  5+#include <signal.h>
  6+#include <sys/stat.h>
  7+#include <sys/wait.h>
  8+#include <unistd.h>
  9+
 10+#include <errno.h>
 11+#include <stdio.h>
 12+#include <string.h>
 13+
 14+#include "make.h"
 15+
 16+
 17+static volatile pid_t pid;
 18+
 19+void
 20+killchild(void)
 21+{
 22+	if (pid != 0)
 23+		kill(pid, SIGTERM);
 24+	pid = 0;
 25+}
 26+
 27+int
 28+is_dir(char *fname)
 29+{
 30+	struct stat st;
 31+
 32+	if (stat(fname, &st) < 0)
 33+		return 0;
 34+	return S_ISDIR(st.st_mode);
 35+}
 36+
 37+void
 38+exportvar(char *var, char *value)
 39+{
 40+	int n;
 41+	char *buf;
 42+
 43+	n = snprintf(NULL, 0, "%s=%s", var, value);
 44+	buf = emalloc(n+1);
 45+	snprintf(buf, n+1, "%s=%s", var, value);
 46+	putenv(buf);
 47+}
 48+
 49+time_t
 50+stamp(char *name)
 51+{
 52+	struct stat st;
 53+
 54+	if (stat(name, &st) < 0)
 55+		return -1;
 56+
 57+	return st.st_mtime;
 58+}
 59+
 60+int
 61+launch(char *cmd, int ignore)
 62+{
 63+	int st;
 64+	sigset_t new, old;
 65+	char *name, *shell;
 66+	char *args[] = {NULL, "-ec" , cmd, NULL};
 67+	static int initsignals;
 68+	extern char **environ;
 69+	extern void sighandler(int);
 70+
 71+	if (!initsignals) {
 72+		struct sigaction act = {
 73+			.sa_handler = sighandler
 74+		};
 75+
 76+		/* avoid BSD weirdness signal restart handling */
 77+		sigaction(SIGINT, &act, NULL);
 78+		sigaction(SIGHUP, &act, NULL);
 79+		sigaction(SIGTERM, &act, NULL);
 80+		sigaction(SIGQUIT, &act, NULL);
 81+		initsignals = 1;
 82+	}
 83+
 84+	sigfillset(&new);
 85+	sigprocmask(SIG_BLOCK, &new, &old);
 86+	if (stop)
 87+		goto unblock;
 88+
 89+	switch (pid = fork()) {
 90+	case -1:
 91+		perror("make");
 92+	unblock:
 93+		sigprocmask(SIG_SETMASK, &old, NULL);
 94+		return -1;
 95+	case 0:
 96+		signal(SIGINT, SIG_DFL);
 97+		signal(SIGHUP, SIG_DFL);
 98+		signal(SIGTERM, SIG_DFL);
 99+		signal(SIGQUIT, SIG_DFL);
100+
101+		sigprocmask(SIG_SETMASK, &old, NULL);
102+
103+		shell = getmacro("SHELL");
104+
105+		if (ignore)
106+			args[1] = "-c";
107+		if ((name = strrchr(shell, '/')) != NULL)
108+			++name;
109+		else
110+			name = shell;
111+		args[0] = name;
112+		execve(shell, args, environ);
113+		_exit(127);
114+	default:
115+		sigprocmask(SIG_SETMASK, &old, NULL);
116+		wait(&st);
117+
118+		return st;
119+	}
120+}
+582, -0
  1@@ -0,0 +1,582 @@
  2+#include <signal.h>
  3+#include <stdio.h>
  4+#include <stdlib.h>
  5+#include <string.h>
  6+
  7+#include "make.h"
  8+
  9+#define TABSIZ 128
 10+#define FORCE   1
 11+#define NOFORCE 0
 12+
 13+static Target *htab[TABSIZ], *deftarget;
 14+
 15+void
 16+dumprules(void)
 17+{
 18+	int i;
 19+	Target **pp, **q, *p;
 20+
 21+	for (pp = htab; pp < &htab[TABSIZ]; ++pp) {
 22+		for (p = *pp; p; p = p->next) {
 23+			if (!p->defined)
 24+				continue;
 25+			printf("%s:", p->name);
 26+			for (q = p->deps; q && *q; ++q)
 27+				printf(" %s", (*q)->name);
 28+			putchar('\n');
 29+			for (i = 0; i < p->nactions; i++)
 30+				printf("\t%s\n", p->actions[i].line);
 31+			putchar('\n');
 32+		}
 33+	}
 34+}
 35+
 36+static Target *
 37+lookup(char *name)
 38+{
 39+	Target *tp;
 40+	int h = hash(name) & TABSIZ-1;
 41+
 42+	for (tp = htab[h]; tp && strcmp(tp->name, name); tp = tp->next)
 43+		;
 44+
 45+	if (tp)
 46+		return tp;
 47+
 48+	tp = emalloc(sizeof(*tp));
 49+	tp->name = estrdup(name);
 50+	tp->target = tp->name;
 51+	tp->req = NULL;
 52+	tp->ndeps = 0;
 53+	tp->deps = NULL;
 54+	tp->actions = NULL;
 55+	tp->nactions = 0;
 56+	tp->next = htab[h];
 57+	tp->defined = 0;
 58+	htab[h] = tp;
 59+
 60+	return tp;
 61+}
 62+
 63+static void
 64+cleanup(Target *tp)
 65+{
 66+	int sig, precious;
 67+	Target *p, **q;
 68+
 69+	sig = stop;
 70+	printf("make: signal %d arrived\n", sig);
 71+
 72+	precious = 0;
 73+	p = lookup(".PRECIOUS");
 74+	for (q = p->deps; q && *q; q++) {
 75+		if (strcmp((*q)->name, tp->name) == 0) {
 76+			precious = 1;
 77+			break;
 78+		}
 79+	}
 80+
 81+	if (!precious && !nflag && !qflag && !is_dir(tp->name)) {
 82+		printf("make: trying to remove target %s\n", tp->name);
 83+		remove(tp->name);
 84+	}
 85+
 86+	signal(sig, SIG_DFL);
 87+	raise(sig);
 88+}
 89+
 90+static int
 91+depends(char *target, char *dep)
 92+{
 93+	int i;
 94+	Target **p, *tp = lookup(target);
 95+
 96+	for (p = tp->deps; p && *p; ++p) {
 97+		if (strcmp((*p)->name, target) == 0)
 98+			return 1;
 99+	}
100+
101+	return 0;
102+}
103+
104+static int
105+is_suffix(char *s)
106+{
107+	int n;
108+
109+	if (s[0] != '.')
110+		return 0;
111+
112+	for (n = 0; s = strchr(s, '.'); n++)
113+		s++;
114+
115+	return n == 2;
116+}
117+
118+void
119+addtarget(char *target, int ndeps)
120+{
121+	Target *tp = lookup(target);
122+
123+	tp->defined = 1;
124+	if (!deftarget && target[0] != '.') {
125+		deftarget = tp;
126+		return;
127+	}
128+
129+	if (strcmp(target, ".SUFFIXES") == 0 && ndeps == 0) {
130+		free(tp->deps);
131+		tp->deps = NULL;
132+		tp->ndeps = 0;
133+		return;
134+	}
135+
136+	if (strcmp(target, ".DEFAULT") == 0) {
137+		if (ndeps > 0)
138+			error("DEFAULT rule with prerequisites");
139+		return;
140+	}
141+
142+	if (strcmp(target, ".SILENT") == 0 && ndeps == 0) {
143+		sflag = 1;
144+		return;
145+	}
146+
147+	if (strcmp(target, ".IGNORE") == 0 && ndeps == 0) {
148+		iflag = 1;
149+		return;
150+	}
151+}
152+
153+void
154+adddep(char *target, char *dep)
155+{
156+	int i;
157+	size_t siz;
158+	Target **p, *tp = lookup(target);
159+
160+	if (depends(dep, target)) {
161+		warning("circular dependency %s <- %s dropped", target, dep);
162+		return;
163+	}
164+
165+	for (p = tp->deps; p && *p; ++p) {
166+		if (strcmp((*p)->name, dep) == 0)
167+			return;
168+	}
169+
170+	tp->ndeps++;
171+	siz = (tp->ndeps + 1) * sizeof(Target *);
172+	tp->deps = erealloc(tp->deps, siz);
173+	tp->deps[tp->ndeps-1] = lookup(dep);
174+	tp->deps[tp->ndeps] = NULL;
175+
176+	debug("adding dependency %s <- %s", target, dep);
177+}
178+
179+static void
180+freeaction(struct action *act)
181+{
182+	free(act->line);
183+	freeloc(&act->loc);
184+}
185+
186+void
187+addrule(char *target, struct action  *acts, int n)
188+{
189+	int i;
190+	struct action *v;
191+	Target *tp = lookup(target);
192+
193+	debug("adding actions for target %s", target);
194+
195+	if (tp->actions) {
196+		debug("overring actions of target %s", target);
197+		for (i = 0; i < tp->nactions; i++)
198+			freeaction(&tp->actions[i]);
199+		free(tp->actions);
200+	}
201+
202+	v = emalloc(n * sizeof(*v));
203+	for (i = 0; i < n; i++) {
204+		v[i].line = estrdup(acts[i].line);
205+		v[i].loc.lineno = acts[i].loc.lineno;
206+		v[i].loc.fname = estrdup(acts[i].loc.fname);
207+	}
208+
209+	tp->nactions = n;
210+	tp->actions = v;
211+}
212+
213+static int
214+execline(Target *tp, char *line, int ignore, int silence)
215+{
216+	char *s, *t;
217+	Target *p, **q;
218+	int r, at, plus, minus, l;
219+
220+	debug("executing '%s'", line);
221+
222+	at = plus = minus = 0;
223+	for (s = line; ; s++) {
224+		switch (*s) {
225+		case '@':
226+			at = 1;
227+			break;
228+		case '-':
229+			minus = 1;
230+			break;
231+		case '+':
232+			plus = 1;
233+			break;
234+		default:
235+			goto out_loop;
236+		}
237+	}
238+
239+out_loop:
240+	/* unescape $$ */
241+	for (l = strlen(s)+1, t = s; *t; --l, ++t) {
242+		if (t[0] == '$' && t[1] == '$') {
243+			memmove(t+1, t+2, l-2);
244+			l--;
245+		}
246+	}
247+
248+	if (tflag && !plus)
249+		return 0;
250+
251+	if (sflag || silence || (qflag && !plus))
252+		at = 1;
253+	if (nflag)
254+		at = 0;
255+	if (!at) {
256+		puts(s);
257+		fflush(stdout);
258+	}
259+
260+	if ((nflag || qflag) && !plus) {
261+		if (qflag)
262+			exitstatus = 1;
263+		return 0;
264+	}
265+
266+	if (minus || iflag || ignore)
267+		ignore = 1;
268+
269+	r = launch(s, ignore);
270+	if (ignore)
271+		return 0;
272+
273+	return r;
274+}
275+
276+static int
277+touch(char *name, int ignore, int silence)
278+{
279+	char *cmd;
280+	int r, n;
281+
282+	n = snprintf(NULL, 0, "touch %s", name) + 1;
283+	cmd = emalloc(n);
284+	snprintf(cmd, n, "touch %s", name);
285+
286+	if (!sflag && !silence)
287+		puts(cmd);
288+
289+	r = system(cmd);
290+	free(cmd);
291+
292+	if (ignore || iflag)
293+		return 0;
294+
295+	return r;
296+}
297+
298+static int
299+touchdeps(Target *tp, int ignore, int silent)
300+{
301+	int r;
302+	Target **p;
303+
304+	if (tp->req) {
305+		r = touch(tp->req, silent, ignore);
306+		if (r)
307+			return r;
308+	}
309+
310+	for (p = tp->deps; p && *p; ++p) {
311+		r = touch((*p)->name, silent, ignore);
312+		if (r)
313+			return r;
314+	}
315+
316+	return 0;
317+}
318+
319+static int
320+run(Target *tp)
321+{
322+	int r, i, ignore, silent;
323+	char *s;
324+	Target *p, **q;
325+
326+	silent = 0;
327+	p = lookup(".SILENT");
328+	for (q = p->deps; q && *q; ++q) {
329+		if (strcmp((*q)->name, tp->name) == 0) {
330+			debug("target %s error silent by .SILENT", tp->name);
331+			silent = 1;
332+		}
333+	}
334+
335+	ignore = 0;
336+	p = lookup(".IGNORE");
337+	for (q = p->deps; q && *q; ++q) {
338+		if (strcmp((*q)->name, tp->name) == 0) {
339+			debug("target %s error ignored by .IGNORE", tp->name);
340+			ignore = 1;
341+		}
342+	}
343+
344+	if (tflag) {
345+		r = touchdeps(tp, ignore, silent);
346+		if (r)
347+			return r;
348+	}
349+
350+	for (i = 0; i < tp->nactions; i++) {
351+		struct action *p;
352+
353+		if (stop)
354+			cleanup(tp);
355+
356+		p = &tp->actions[i];
357+		debug("executing action '%s'", p->line);
358+		s = expandstring(p->line, tp, &p->loc);
359+		r = execline(tp, s, ignore, silent);
360+		free(s);
361+
362+		if (r)
363+			return r;
364+	}
365+
366+	if (tflag) {
367+		r = touch(tp->target, ignore, silent);
368+		if (r)
369+			return r;
370+	}
371+
372+	return 0;
373+}
374+
375+static int
376+enabled(char *suffix)
377+{
378+	Target **p, *tp = lookup(".SUFFIXES");
379+
380+	for (p = tp->deps; p && *p; ++p) {
381+		if (strcmp(suffix, (*p)->name) == 0)
382+			return 1;
383+	}
384+
385+	return 0;
386+}
387+
388+static Target *
389+inference(Target *tp, int force)
390+{
391+	time_t t;
392+	int tolen, r;
393+	char *to, *from;
394+	Target *q, **p, *suffixes;
395+	char buf[FILENAME_MAX], fname[FILENAME_MAX];
396+
397+	debug("searching an inference rule for %s", tp->name);
398+
399+	to = strrchr(tp->name, '.');
400+	if (to && !enabled(to))
401+		return NULL;
402+	tolen = to ? to - tp->name : strlen(tp->name);
403+
404+	if (!to)
405+		to = "";
406+
407+	suffixes = lookup(".SUFFIXES");
408+	for (p = suffixes->deps; p && *p; ++p) {
409+		from = (*p)->name;
410+		debug("trying suffix %s", from);
411+
412+		r = snprintf(buf,
413+		             sizeof(buf),
414+		             "%s%s",
415+		             from, to);
416+
417+		if (r < 0 || r >= sizeof(buf))
418+			error("suffixes too long %s %s", from, to);
419+
420+		q = lookup(buf);
421+		if (!q->actions)
422+			continue;
423+
424+		r = snprintf(fname,
425+		             sizeof(fname),
426+		             "%*.*s%s",
427+		             tolen, tolen, tp->name, from);
428+
429+		if (r < 0 || r >= sizeof(fname)) {
430+			error("prerequisite name too long %s %s",
431+			      tp->name, from);
432+		}
433+
434+		debug("\tsearching prerequisite %s", fname);
435+
436+		t = stamp(fname);
437+		if (t == -1) {
438+			debug("\tprerequisite %s not found", fname);
439+			continue;
440+		}
441+
442+		if (!force && t <= tp->stamp) {
443+			debug("\tdiscarded because is newer");
444+			debug("\t%s: %s", tp->name, ctime(&tp->stamp));
445+			debug("\t%s: %s", fname, ctime(&t));
446+			continue;
447+		}
448+
449+		free(q->req);
450+		q->req = estrdup(fname);
451+		q->deps = tp->deps;
452+		q->target = tp->name;
453+		q->stamp = tp->stamp;
454+
455+		debug("using inference rule %s with %s", q->name, fname);
456+		return q;
457+	}
458+
459+	return NULL;
460+}
461+
462+static int
463+update(Target *tp)
464+{
465+	Target *p;
466+
467+	debug("%s needs to be updated", tp->name);
468+
469+	if (tp->actions) {
470+		debug("using target rule to build %s", tp->name);
471+		return run(tp);
472+	}
473+
474+	if ((p = inference(tp, FORCE)) != NULL) {
475+		debug("using inference rule %s", p->name);
476+		return run(p);
477+	}
478+
479+	p = lookup(".DEFAULT");
480+	if (p->defined) {
481+		debug("using default rule");
482+		return run(p);
483+	}
484+
485+	debug("not rule found to update %s", tp->name);
486+
487+	if (!tp->defined)
488+		error("don't know how to make %s", tp->name);
489+
490+	return 0;
491+}
492+
493+static int 
494+rebuild(Target *tp, int *buildp)
495+{
496+	Target **p, *q;;
497+	int r, need, build, err, def;
498+
499+	debug("checking rebuild of %s", tp->name);
500+
501+	tp->stamp = stamp(tp->name);
502+
503+	def = err = need = 0;
504+	for (p = tp->deps; p && *p; ++p) {
505+		if (stop)
506+			cleanup(tp);
507+
508+		q = *p;
509+		debug("checking dependency %s", q->name);
510+
511+		if (strcmp(q->name, tp->name) == 0 && q->actions)
512+			def = 1;
513+
514+		build = 0;
515+		if (rebuild(q, &build) != 0) {
516+			err = 1;
517+			continue;
518+		}
519+
520+		if (build) {
521+			debug("rebuild of %s forces rebuild of %s",
522+			       q->name, tp->name);
523+			need = 1;
524+		} else if (q->stamp > tp->stamp) {
525+			debug("dependency %s is newer than %s",
526+			      q->name, tp->name);
527+			need = 1;
528+		}
529+	}
530+
531+	if (tp->stamp == -1) {
532+		need = 1;
533+	} else if (!def)  {
534+		debug("no action found for %s, looking a inference rule",
535+		      tp->name);
536+		if (inference(tp, NOFORCE))
537+			need = 1;
538+	}
539+
540+	if (err) {
541+		warning("target %s not remade because of errors", tp->name);
542+		return 1;
543+	} else if (need) {
544+		*buildp = 1;
545+
546+		debug("target %s needs updating", tp->name);
547+		r = update(tp);
548+		if (r == 0)
549+			return 0;
550+
551+		if (stop)
552+			cleanup(tp);
553+
554+		exitstatus = 1;
555+
556+		if (!kflag)
557+			error("target %s: error %d", tp->name, r);
558+		else
559+			warning("target %s: error %d", tp->name, r);
560+		return r;
561+	}
562+
563+	return 0;
564+}
565+
566+int
567+build(char *name)
568+{
569+	int build, r;
570+
571+	if (!name) {
572+		if (!deftarget) {
573+			printf("make: no target to make\n");
574+			return 0;
575+		}
576+		name = deftarget->name;
577+	}
578+
579+	debug("checking target %s", name);
580+
581+	build = 0;
582+	return rebuild(lookup(name), &build);
583+}
+53, -0
 1@@ -0,0 +1,53 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+#include <sys/types.h>
 5+
 6+#include <stdio.h>
 7+#include <stdlib.h>
 8+#include <unistd.h>
 9+
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+	eprintf("usage: %s [n|y]\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+	struct stat sb;
22+	mode_t mode;
23+
24+	ARGBEGIN {
25+	default:
26+		usage();
27+	} ARGEND;
28+
29+	if (argc > 1)
30+		usage();
31+
32+	if (isatty(2) == 0)
33+		eprintf("stderr: not a tty\n");
34+
35+	if (fstat(2, &sb) < 0)
36+		eprintf("fstat stderr:");
37+
38+	if (argc == 0) {
39+		puts(sb.st_mode & (S_IWGRP | S_IWOTH) ? "is y" : "is n");
40+		return 0;
41+	}
42+
43+	if (argv[0][0] == 'y' && argv[0][1] == '\0')
44+		mode = sb.st_mode | S_IWGRP | S_IWOTH;
45+	else if (argv[0][0] == 'n' && argv[0][1] == '\0')
46+		mode = sb.st_mode & ~(S_IWGRP | S_IWOTH);
47+	else
48+		usage();
49+
50+	if (fchmod(2, mode) < 0)
51+		eprintf("fchmod stderr:");
52+
53+	return 0;
54+}
+49, -0
 1@@ -0,0 +1,49 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+
 5+#include <errno.h>
 6+#include <stdlib.h>
 7+
 8+#include "util.h"
 9+
10+static void
11+usage(void)
12+{
13+	eprintf("usage: %s [-p] [-m mode] name ...\n", argv0);
14+}
15+
16+int
17+main(int argc, char *argv[])
18+{
19+	mode_t mode, mask;
20+	int pflag = 0, ret = 0;
21+
22+	mask = umask(0);
23+	mode = 0777 & ~mask;
24+
25+	ARGBEGIN {
26+	case 'p':
27+		pflag = 1;
28+		break;
29+	case 'm':
30+		mode = parsemode(EARGF(usage()), 0777, mask);
31+		break;
32+	default:
33+		usage();
34+	} ARGEND
35+
36+	if (!argc)
37+		usage();
38+
39+	for (; *argv; argc--, argv++) {
40+		if (pflag) {
41+			if (mkdirp(*argv, mode, 0777 & (~mask | 0300)) < 0)
42+				ret = 1;
43+		} else if (mkdir(*argv, mode) < 0) {
44+			weprintf("mkdir %s:", *argv);
45+			ret = 1;
46+		}
47+	}
48+
49+	return ret;
50+}
+39, -0
 1@@ -0,0 +1,39 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+
 5+#include <stdlib.h>
 6+
 7+#include "util.h"
 8+
 9+static void
10+usage(void)
11+{
12+	eprintf("usage: %s [-m mode] name ...\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+	mode_t mode = 0666;
19+	int ret = 0;
20+
21+	ARGBEGIN {
22+	case 'm':
23+		mode = parsemode(EARGF(usage()), mode, umask(0));
24+		break;
25+	default:
26+		usage();
27+	} ARGEND
28+
29+	if (!argc)
30+		usage();
31+
32+	for (; *argv; argc--, argv++) {
33+		if (mkfifo(*argv, mode) < 0) {
34+			weprintf("mkfifo %s:", *argv);
35+			ret = 1;
36+		}
37+	}
38+
39+	return ret;
40+}
+68, -0
 1@@ -0,0 +1,68 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+
 5+#include <errno.h>
 6+#include <fcntl.h>
 7+#include <stdio.h>
 8+
 9+#include "fs.h"
10+#include "util.h"
11+
12+static int mv_status = 0;
13+
14+static int
15+mv(const char *s1, const char *s2, int depth)
16+{
17+	struct recursor r = { .fn = rm, .follow = 'P', .flags = SILENT };
18+
19+	if (!rename(s1, s2))
20+		return 0;
21+	if (errno == EXDEV) {
22+		cp_aflag = cp_rflag = cp_pflag = 1;
23+		cp_follow = 'P';
24+		cp_status = 0;
25+		rm_status = 0;
26+		cp(s1, s2, depth);
27+		if (cp_status == 0)
28+			recurse(AT_FDCWD, s1, NULL, &r);
29+		if (cp_status || rm_status)
30+			mv_status = 1;
31+	} else {
32+		weprintf("%s -> %s:", s1, s2);
33+		mv_status = 1;
34+	}
35+
36+	return 0;
37+}
38+
39+static void
40+usage(void)
41+{
42+	eprintf("usage: %s [-f] source ... dest\n", argv0);
43+}
44+
45+int
46+main(int argc, char *argv[])
47+{
48+	struct stat st;
49+
50+	ARGBEGIN {
51+	case 'f':
52+		break;
53+	default:
54+		usage();
55+	} ARGEND
56+
57+	if (argc < 2)
58+		usage();
59+
60+	if (argc > 2) {
61+		if (stat(argv[argc - 1], &st) < 0)
62+			eprintf("stat %s:", argv[argc - 1]);
63+		if (!S_ISDIR(st.st_mode))
64+			eprintf("%s: not a directory\n", argv[argc - 1]);
65+	}
66+	enmasse(argc, argv, mv);
67+
68+	return mv_status;
69+}
+56, -0
 1@@ -0,0 +1,56 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/resource.h>
 4+
 5+#include <errno.h>
 6+#include <stdlib.h>
 7+#include <unistd.h>
 8+
 9+#include "util.h"
10+
11+#ifndef PRIO_MIN
12+#define PRIO_MIN -NZERO
13+#endif
14+
15+#ifndef PRIO_MAX
16+#define PRIO_MAX (NZERO-1)
17+#endif
18+
19+static void
20+usage(void)
21+{
22+	eprintf("usage: %s [-n inc] cmd [arg ...]\n", argv0);
23+}
24+
25+int
26+main(int argc, char *argv[])
27+{
28+	int val = 10, r, savederrno;
29+
30+	ARGBEGIN {
31+	case 'n':
32+		val = estrtonum(EARGF(usage()), PRIO_MIN, PRIO_MAX);
33+		break;
34+	default:
35+		usage();
36+		break;
37+	} ARGEND
38+
39+	if (!argc)
40+		usage();
41+
42+	errno = 0;
43+	r = getpriority(PRIO_PROCESS, 0);
44+	if (errno)
45+		weprintf("getpriority:");
46+	else
47+		val += r;
48+	LIMIT(val, PRIO_MIN, PRIO_MAX);
49+	if (setpriority(PRIO_PROCESS, 0, val) < 0)
50+		weprintf("setpriority:");
51+
52+	execvp(argv[0], argv);
53+	savederrno = errno;
54+	weprintf("execvp %s:", argv[0]);
55+
56+	_exit(126 + (savederrno == ENOENT));
57+}
+212, -0
  1@@ -0,0 +1,212 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <limits.h>
  4+#include <stdint.h>
  5+#include <stdio.h>
  6+#include <stdlib.h>
  7+#include <string.h>
  8+
  9+#include "text.h"
 10+#include "utf.h"
 11+#include "util.h"
 12+
 13+static size_t   startnum = 1;
 14+static size_t   incr = 1;
 15+static size_t   blines = 1;
 16+static size_t   delimlen = 2;
 17+static size_t   seplen = 1;
 18+static int      width = 6;
 19+static int      pflag = 0;
 20+static char     type[] = { 'n', 't', 'n' }; /* footer, body, header */
 21+static char    *delim = "\\:";
 22+static char     format[6] = "%*ld";
 23+static char    *sep = "\t";
 24+static regex_t  preg[3];
 25+
 26+static int
 27+getsection(struct line *l, int *section)
 28+{
 29+	size_t i;
 30+	int sectionchanged = 0, newsection = *section;
 31+
 32+	for (i = 0; (l->len - i) >= delimlen &&
 33+	     !memcmp(l->data + i, delim, delimlen); i += delimlen) {
 34+		if (!sectionchanged) {
 35+			sectionchanged = 1;
 36+			newsection = 0;
 37+		} else {
 38+			newsection = (newsection + 1) % 3;
 39+		}
 40+	}
 41+
 42+	if (!(l->len - i) || l->data[i] == '\n')
 43+		*section = newsection;
 44+	else
 45+		sectionchanged = 0;
 46+
 47+	return sectionchanged;
 48+}
 49+
 50+static void
 51+nl(const char *fname, FILE *fp)
 52+{
 53+	static struct line line;
 54+	static size_t size;
 55+	size_t number = startnum, bl = 1;
 56+	ssize_t len;
 57+	int donumber, oldsection, section = 1;
 58+
 59+	while ((len = getline(&line.data, &size, fp)) > 0) {
 60+		line.len = len;
 61+		donumber = 0;
 62+		oldsection = section;
 63+
 64+		if (getsection(&line, &section)) {
 65+			if ((section >= oldsection) && !pflag)
 66+				number = startnum;
 67+			continue;
 68+		}
 69+
 70+		switch (type[section]) {
 71+		case 't':
 72+			if (line.data[0] != '\n')
 73+				donumber = 1;
 74+			break;
 75+		case 'p':
 76+			if (!regexec(preg + section, line.data, 0, NULL, 0))
 77+				donumber = 1;
 78+			break;
 79+		case 'a':
 80+			if (line.data[0] == '\n' && bl < blines) {
 81+				++bl;
 82+			} else {
 83+				donumber = 1;
 84+				bl = 1;
 85+			}
 86+		}
 87+
 88+		if (donumber) {
 89+			printf(format, width, number);
 90+			fwrite(sep, 1, seplen, stdout);
 91+			number += incr;
 92+		}
 93+		fwrite(line.data, 1, line.len, stdout);
 94+	}
 95+	free(line.data);
 96+	if (ferror(fp))
 97+		eprintf("getline %s:", fname);
 98+}
 99+
100+static void
101+usage(void)
102+{
103+	eprintf("usage: %s [-p] [-b type] [-d delim] [-f type]\n"
104+	        "       [-h type] [-i num] [-l num] [-n format]\n"
105+	        "       [-s sep] [-v num] [-w num] [file]\n", argv0);
106+}
107+
108+static char
109+getlinetype(char *type, regex_t *preg)
110+{
111+	if (type[0] == 'p')
112+		eregcomp(preg, type + 1, REG_NOSUB);
113+	else if (!type[0] || !strchr("ant", type[0]))
114+		usage();
115+
116+	return type[0];
117+}
118+
119+int
120+main(int argc, char *argv[])
121+{
122+	FILE *fp = NULL;
123+	size_t s;
124+	int ret = 0;
125+	char *d, *formattype, *formatblit;
126+
127+	ARGBEGIN {
128+	case 'd':
129+		switch (utflen((d = EARGF(usage())))) {
130+		case 0:
131+			eprintf("empty logical page delimiter\n");
132+		case 1:
133+			s = strlen(d);
134+			delim = emalloc(s + 1 + 1);
135+			estrlcpy(delim, d, s + 1 + 1);
136+			estrlcat(delim, ":", s + 1 + 1);
137+			delimlen = s + 1;
138+			break;
139+		default:
140+			delim = d;
141+			delimlen = strlen(delim);
142+			break;
143+		}
144+		break;
145+	case 'f':
146+		type[0] = getlinetype(EARGF(usage()), preg);
147+		break;
148+	case 'b':
149+		type[1] = getlinetype(EARGF(usage()), preg + 1);
150+		break;
151+	case 'h':
152+		type[2] = getlinetype(EARGF(usage()), preg + 2);
153+		break;
154+	case 'i':
155+		incr = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
156+		break;
157+	case 'l':
158+		blines = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
159+		break;
160+	case 'n':
161+		formattype = EARGF(usage());
162+		estrlcpy(format, "%", sizeof(format));
163+
164+		if (!strcmp(formattype, "ln")) {
165+			formatblit = "-";
166+		} else if (!strcmp(formattype, "rn")) {
167+			formatblit = "";
168+		} else if (!strcmp(formattype, "rz")) {
169+			formatblit = "0";
170+		} else {
171+			eprintf("%s: bad format\n", formattype);
172+		}
173+
174+		estrlcat(format, formatblit, sizeof(format));
175+		estrlcat(format, "*ld", sizeof(format));
176+		break;
177+	case 'p':
178+		pflag = 1;
179+		break;
180+	case 's':
181+		sep = EARGF(usage());
182+		seplen = unescape(sep);
183+		break;
184+	case 'v':
185+		startnum = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
186+		break;
187+	case 'w':
188+		width = estrtonum(EARGF(usage()), 1, INT_MAX);
189+		break;
190+	default:
191+		usage();
192+	} ARGEND
193+
194+	if (argc > 1)
195+		usage();
196+
197+	if (!argc) {
198+		nl("<stdin>", stdin);
199+	} else {
200+		if (!strcmp(argv[0], "-")) {
201+			argv[0] = "<stdin>";
202+			fp = stdin;
203+		} else if (!(fp = fopen(argv[0], "r"))) {
204+			eprintf("fopen %s:", argv[0]);
205+		}
206+		nl(argv[0], fp);
207+	}
208+
209+	ret |= fp && fp != stdin && fshut(fp, argv[0]);
210+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
211+
212+	return ret;
213+}
+48, -0
 1@@ -0,0 +1,48 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+
 5+#include <errno.h>
 6+#include <fcntl.h>
 7+#include <signal.h>
 8+#include <unistd.h>
 9+
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+	eprintf("usage: %s cmd [arg ...]\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+	int fd, savederrno;
22+
23+	ARGBEGIN {
24+	default:
25+		usage();
26+	} ARGEND
27+
28+	if (!argc)
29+		usage();
30+
31+	if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
32+		enprintf(127, "signal HUP:");
33+
34+	if (isatty(STDOUT_FILENO)) {
35+		if ((fd = open("nohup.out", O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR)) < 0)
36+			enprintf(127, "open nohup.out:");
37+		if (dup2(fd, STDOUT_FILENO) < 0)
38+			enprintf(127, "dup2:");
39+		close(fd);
40+	}
41+	if (isatty(STDERR_FILENO) && dup2(STDOUT_FILENO, STDERR_FILENO) < 0)
42+		enprintf(127, "dup2:");
43+
44+	execvp(argv[0], argv);
45+	savederrno = errno;
46+	weprintf("execvp %s:", argv[0]);
47+
48+	_exit(126 + (savederrno == ENOENT));
49+}
+332, -0
  1@@ -0,0 +1,332 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <ctype.h>
  4+#include <fcntl.h>
  5+#include <stdint.h>
  6+#include <stdio.h>
  7+#include <stdlib.h>
  8+#include <string.h>
  9+#include <unistd.h>
 10+
 11+#include "queue.h"
 12+#include "util.h"
 13+
 14+struct type {
 15+	unsigned char     format;
 16+	unsigned int      len;
 17+	TAILQ_ENTRY(type) entry;
 18+};
 19+
 20+static TAILQ_HEAD(head, type) head = TAILQ_HEAD_INITIALIZER(head);
 21+static unsigned char addr_format = 'o';
 22+static off_t skip = 0;
 23+static off_t max = -1;
 24+static size_t linelen = 1;
 25+static int big_endian;
 26+
 27+static void
 28+printaddress(off_t addr)
 29+{
 30+	char fmt[] = "%07j#";
 31+
 32+	if (addr_format == 'n') {
 33+		fputc(' ', stdout);
 34+	} else {
 35+		fmt[4] = addr_format;
 36+		printf(fmt, (intmax_t)addr);
 37+	}
 38+}
 39+
 40+static void
 41+printchunk(const unsigned char *s, unsigned char format, size_t len)
 42+{
 43+	long long res, basefac;
 44+	size_t i;
 45+	char fmt[] = " %#*ll#";
 46+	unsigned char c;
 47+
 48+	const char *namedict[] = {
 49+		"nul", "soh", "stx", "etx", "eot", "enq", "ack",
 50+		"bel", "bs",  "ht",  "nl",  "vt",  "ff",  "cr",
 51+		"so",  "si",  "dle", "dc1", "dc2", "dc3", "dc4",
 52+		"nak", "syn", "etb", "can", "em",  "sub", "esc",
 53+		"fs",  "gs",  "rs",  "us",  "sp",
 54+	};
 55+	const char *escdict[] = {
 56+		['\0'] = "\\0", ['\a'] = "\\a",
 57+		['\b'] = "\\b", ['\t'] = "\\t",
 58+		['\n'] = "\\n", ['\v'] = "\\v",
 59+		['\f'] = "\\f", ['\r'] = "\\r",
 60+	};
 61+
 62+	switch (format) {
 63+	case 'a':
 64+		c = *s & ~128; /* clear high bit as required by standard */
 65+		if (c < LEN(namedict) || c == 127) {
 66+			printf(" %3s", (c == 127) ? "del" : namedict[c]);
 67+		} else {
 68+			printf(" %3c", c);
 69+		}
 70+		break;
 71+	case 'c':
 72+		if (strchr("\a\b\t\n\v\f\r\0", *s)) {
 73+			printf(" %3s", escdict[*s]);
 74+		} else if (!isprint(*s)) {
 75+			printf(" %3o", *s);
 76+		} else {
 77+			printf(" %3c", *s);
 78+		}
 79+		break;
 80+	default:
 81+		if (big_endian) {
 82+			for (res = 0, basefac = 1, i = len; i; i--) {
 83+				res += s[i - 1] * basefac;
 84+				basefac <<= 8;
 85+			}
 86+		} else {
 87+			for (res = 0, basefac = 1, i = 0; i < len; i++) {
 88+				res += s[i] * basefac;
 89+				basefac <<= 8;
 90+			}
 91+		}
 92+		fmt[2] = big_endian ? '-' : ' ';
 93+		fmt[6] = format;
 94+		printf(fmt, (int)(3 * len + len - 1), res);
 95+	}
 96+}
 97+
 98+static void
 99+printline(const unsigned char *line, size_t len, off_t addr)
100+{
101+	struct type *t = NULL;
102+	size_t i;
103+	int first = 1;
104+	unsigned char *tmp;
105+
106+	if (TAILQ_EMPTY(&head))
107+		goto once;
108+	TAILQ_FOREACH(t, &head, entry) {
109+once:
110+		if (first) {
111+			printaddress(addr);
112+			first = 0;
113+		} else {
114+			printf("%*c", (addr_format == 'n') ? 1 : 7, ' ');
115+		}
116+		for (i = 0; i < len; i += MIN(len - i, t ? t->len : 4)) {
117+			if (len - i < (t ? t->len : 4)) {
118+				tmp = ecalloc(t ? t->len : 4, 1);
119+				memcpy(tmp, line + i, len - i);
120+				printchunk(tmp, t ? t->format : 'o',
121+				           t ? t->len : 4);
122+				free(tmp);
123+			} else {
124+				printchunk(line + i, t ? t->format : 'o',
125+				           t ? t->len : 4);
126+			}
127+		}
128+		fputc('\n', stdout);
129+		if (TAILQ_EMPTY(&head) || (!len && !first))
130+			break;
131+	}
132+}
133+
134+static int
135+od(int fd, char *fname, int last)
136+{
137+	static unsigned char *line;
138+	static size_t lineoff;
139+	static off_t addr;
140+	unsigned char buf[BUFSIZ];
141+	size_t i, size = sizeof(buf);
142+	ssize_t n;
143+
144+	while (skip - addr > 0) {
145+		n = read(fd, buf, MIN(skip - addr, sizeof(buf)));
146+		if (n < 0)
147+			weprintf("read %s:", fname);
148+		if (n <= 0)
149+			return n;
150+		addr += n;
151+	}
152+	if (!line)
153+		line = emalloc(linelen);
154+
155+	for (;;) {
156+		if (max >= 0)
157+			size = MIN(max - (addr - skip), size);
158+		if ((n = read(fd, buf, size)) <= 0)
159+			break;
160+		for (i = 0; i < n; i++, addr++) {
161+			line[lineoff++] = buf[i];
162+			if (lineoff == linelen) {
163+				printline(line, lineoff, addr - lineoff + 1);
164+				lineoff = 0;
165+			}
166+		}
167+	}
168+	if (n < 0) {
169+		weprintf("read %s:", fname);
170+		return n;
171+	}
172+	if (lineoff && last)
173+		printline(line, lineoff, addr - lineoff);
174+	if (last)
175+		printline((unsigned char *)"", 0, addr);
176+	return 0;
177+}
178+
179+static int
180+lcm(unsigned int a, unsigned int b)
181+{
182+	unsigned int c, d, e;
183+
184+	for (c = a, d = b; c ;) {
185+		e = c;
186+		c = d % c;
187+		d = e;
188+	}
189+
190+	return a / d * b;
191+}
192+
193+static void
194+addtype(char format, int len)
195+{
196+	struct type *t;
197+
198+	t = emalloc(sizeof(*t));
199+	t->format = format;
200+	t->len = len;
201+	TAILQ_INSERT_TAIL(&head, t, entry);
202+}
203+
204+static void
205+usage(void)
206+{
207+	eprintf("usage: %s [-bdosvx] [-A addressformat] [-E | -e] [-j skip] "
208+	        "[-t outputformat] [file ...]\n", argv0);
209+}
210+
211+int
212+main(int argc, char *argv[])
213+{
214+	int fd;
215+	struct type *t;
216+	int ret = 0, len;
217+	char *s;
218+
219+	big_endian = (*(uint16_t *)"\0\xff" == 0xff);
220+
221+	ARGBEGIN {
222+	case 'A':
223+		s = EARGF(usage());
224+		if (strlen(s) != 1 || !strchr("doxn", s[0]))
225+			usage();
226+		addr_format = s[0];
227+		break;
228+	case 'b':
229+		addtype('o', 1);
230+		break;
231+	case 'd':
232+		addtype('u', 2);
233+		break;
234+	case 'E':
235+	case 'e':
236+		big_endian = (ARGC() == 'E');
237+		break;
238+	case 'j':
239+		if ((skip = parseoffset(EARGF(usage()))) < 0)
240+			usage();
241+		break;
242+	case 'N':
243+		if ((max = parseoffset(EARGF(usage()))) < 0)
244+			usage();
245+		break;
246+	case 'o':
247+		addtype('o', 2);
248+		break;
249+	case 's':
250+		addtype('d', 2);
251+		break;
252+	case 't':
253+		s = EARGF(usage());
254+		for (; *s; s++) {
255+			switch (*s) {
256+			case 'a':
257+			case 'c':
258+				addtype(*s, 1);
259+				break;
260+			case 'd':
261+			case 'o':
262+			case 'u':
263+			case 'x':
264+				/* todo: allow multiple digits */
265+				if (*(s+1) > '0' && *(s+1) <= '9') {
266+					len = *(s+1) - '0';
267+				} else {
268+					switch (*(s+1)) {
269+					case 'C':
270+						len = sizeof(char);
271+						break;
272+					case 'S':
273+						len = sizeof(short);
274+						break;
275+					case 'I':
276+						len = sizeof(int);
277+						break;
278+					case 'L':
279+						len = sizeof(long);
280+						break;
281+					default:
282+						len = sizeof(int);
283+					}
284+				}
285+				addtype(*s, len);
286+				break;
287+			default:
288+				usage();
289+			}
290+		}
291+		break;
292+	case 'v':
293+		/* always set - use uniq(1) to handle duplicate lines */
294+		break;
295+	case 'x':
296+		addtype('x', 2);
297+		break;
298+	default:
299+		usage();
300+	} ARGEND
301+
302+	/* line length is lcm of type lengths and >= 16 by doubling */
303+	TAILQ_FOREACH(t, &head, entry)
304+		linelen = lcm(linelen, t->len);
305+	if (TAILQ_EMPTY(&head))
306+		linelen = 16;
307+	while (linelen < 16)
308+		linelen *= 2;
309+
310+	if (!argc) {
311+		if (od(0, "<stdin>", 1) < 0)
312+			ret = 1;
313+	} else {
314+		for (; *argv; argc--, argv++) {
315+			if (!strcmp(*argv, "-")) {
316+				*argv = "<stdin>";
317+				fd = 0;
318+			} else if ((fd = open(*argv, O_RDONLY)) < 0) {
319+				weprintf("open %s:", *argv);
320+				ret = 1;
321+				continue;
322+			}
323+			if (od(fd, *argv, (!*(argv + 1))) < 0)
324+				ret = 1;
325+			if (fd != 0)
326+				close(fd);
327+		}
328+	}
329+
330+	ret |= fshut(stdout, "<stdout>") | fshut(stderr, "<stderr>");
331+
332+	return ret;
333+}
+144, -0
  1@@ -0,0 +1,144 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <stdlib.h>
  4+#include <string.h>
  5+
  6+#include "utf.h"
  7+#include "util.h"
  8+
  9+struct fdescr {
 10+	FILE *fp;
 11+	const char *name;
 12+};
 13+
 14+static void
 15+sequential(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t delimlen)
 16+{
 17+	Rune c, last;
 18+	size_t i, d;
 19+
 20+	for (i = 0; i < fdescrlen; i++) {
 21+		d = 0;
 22+		last = 0;
 23+
 24+		while (efgetrune(&c, dsc[i].fp, dsc[i].name)) {
 25+			if (last == '\n') {
 26+				if (delim[d] != '\0')
 27+					efputrune(&delim[d], stdout, "<stdout>");
 28+				d = (d + 1) % delimlen;
 29+			}
 30+
 31+			if (c != '\n')
 32+				efputrune(&c, stdout, "<stdout>");
 33+			last = c;
 34+		}
 35+
 36+		if (last == '\n')
 37+			efputrune(&last, stdout, "<stdout>");
 38+	}
 39+}
 40+
 41+static void
 42+parallel(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t delimlen)
 43+{
 44+	Rune c, d;
 45+	size_t i, m;
 46+	ssize_t last;
 47+
 48+nextline:
 49+	last = -1;
 50+
 51+	for (i = 0; i < fdescrlen; i++) {
 52+		d = delim[i % delimlen];
 53+		c = 0;
 54+
 55+		while (efgetrune(&c, dsc[i].fp, dsc[i].name)) {
 56+			for (m = last + 1; m < i; m++) {
 57+				if (delim[m % delimlen] != '\0')
 58+					efputrune(&delim[m % delimlen], stdout, "<stdout>");
 59+			}
 60+			last = i;
 61+			if (c == '\n') {
 62+				if (i != fdescrlen - 1)
 63+					c = d;
 64+				efputrune(&c, stdout, "<stdout>");
 65+				break;
 66+			}
 67+			efputrune(&c, stdout, "<stdout>");
 68+		}
 69+
 70+		if (c == 0 && last != -1) {
 71+			if (i == fdescrlen - 1)
 72+				putchar('\n');
 73+			else if (d != '\0')
 74+				efputrune(&d, stdout, "<stdout>");
 75+			last++;
 76+		}
 77+	}
 78+	if (last != -1)
 79+		goto nextline;
 80+}
 81+
 82+static void
 83+usage(void)
 84+{
 85+	eprintf("usage: %s [-s] [-d list] file ...\n", argv0);
 86+}
 87+
 88+int
 89+main(int argc, char *argv[])
 90+{
 91+	struct fdescr *dsc;
 92+	Rune *delim_rune = NULL;
 93+	size_t delim_runelen, i, delim_bytelen = 1;
 94+	int seq = 0, ret = 0;
 95+	char *delim = "\t";
 96+
 97+	ARGBEGIN {
 98+	case 's':
 99+		seq = 1;
100+		break;
101+	case 'd':
102+		delim = EARGF(usage());
103+		delim_bytelen = unescape(delim);
104+		break;
105+	default:
106+		usage();
107+	} ARGEND
108+
109+	if (!argc)
110+		usage();
111+
112+	/* populate delimiters */
113+	delim_rune = ereallocarray(NULL,
114+		utfmemlen(delim, delim_bytelen) + 1, sizeof(*delim_rune));
115+	if (!(delim_runelen = utfntorunestr(delim, delim_bytelen, delim_rune))) {
116+		usage();
117+	}
118+
119+	/* populate file list */
120+	dsc = ereallocarray(NULL, argc, sizeof(*dsc));
121+
122+	for (i = 0; i < argc; i++) {
123+		if (!strcmp(argv[i], "-")) {
124+			argv[i] = "<stdin>";
125+			dsc[i].fp = stdin;
126+		} else if (!(dsc[i].fp = fopen(argv[i], "r"))) {
127+			eprintf("fopen %s:", argv[i]);
128+		}
129+		dsc[i].name = argv[i];
130+	}
131+
132+	if (seq) {
133+		sequential(dsc, argc, delim_rune, delim_runelen);
134+	} else {
135+		parallel(dsc, argc, delim_rune, delim_runelen);
136+	}
137+
138+	for (i = 0; i < argc; i++)
139+		if (dsc[i].fp != stdin && fshut(dsc[i].fp, argv[i]))
140+			ret |= fshut(dsc[i].fp, argv[i]);
141+
142+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
143+
144+	return ret;
145+}
+104, -0
  1@@ -0,0 +1,104 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+
  5+#include <errno.h>
  6+#include <limits.h>
  7+#include <stdint.h>
  8+#include <stdio.h>
  9+#include <stdlib.h>
 10+#include <string.h>
 11+
 12+#include "util.h"
 13+
 14+#define PORTABLE_CHARACTER_SET "0123456789._-qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"
 15+/* If your system supports more other characters, but not all non-NUL characters, define SYSTEM_CHARACTER_SET. */
 16+
 17+static int most = 0;
 18+static int extra = 0;
 19+
 20+static int
 21+pathchk(char *filename)
 22+{
 23+	char *invalid, *invalid_end, *p, *q;
 24+	const char *character_set;
 25+	size_t len, maxlen;
 26+	struct stat st;
 27+
 28+	/* Empty? */
 29+	if (extra && !*filename)
 30+		eprintf("empty filename\n");
 31+
 32+	/* Leading hyphen? */
 33+	if (extra && ((*filename == '-') || strstr(filename, "/-")))
 34+		eprintf("%s: leading '-' in component of filename\n", filename);
 35+
 36+	/* Nonportable character? */
 37+#ifdef SYSTEM_CHARACTER_SET
 38+	character_set = "/"SYSTEM_CHARACTER_SET;
 39+#else
 40+	character_set = 0;
 41+#endif
 42+	if (most)
 43+		character_set = "/"PORTABLE_CHARACTER_SET;
 44+	if (character_set && *(invalid = filename + strspn(filename, character_set))) {
 45+		for (invalid_end = invalid + 1; *invalid_end & 0x80; invalid_end++);
 46+		p = estrdup(filename);
 47+		*invalid_end = 0;
 48+		eprintf("%s: nonportable character '%s'\n", p, invalid);
 49+	}
 50+
 51+	/* Symlink error? Non-searchable directory? */
 52+	if (lstat(filename, &st) && errno != ENOENT) {
 53+		/* lstat rather than stat, so that if filename is a bad symlink, but
 54+		 * all parents are OK, no error will be detected. */
 55+		eprintf("%s:", filename);
 56+	}
 57+
 58+	/* Too long pathname? */
 59+	maxlen = most ? _POSIX_PATH_MAX : PATH_MAX;
 60+	if (strlen(filename) >= maxlen)
 61+		eprintf("%s: is longer than %zu bytes\n", filename, maxlen);
 62+
 63+	/* Too long component? */
 64+	maxlen = most ? _POSIX_NAME_MAX : NAME_MAX;
 65+	for (p = filename; p; p = q) {
 66+		q = strchr(p, '/');
 67+		len = q ? (size_t)(q++ - p) : strlen(p);
 68+		if (len > maxlen)
 69+			eprintf("%s: includes component longer than %zu bytes\n",
 70+			         filename, maxlen);
 71+	}
 72+
 73+	return 0;
 74+}
 75+
 76+static void
 77+usage(void)
 78+{
 79+	eprintf("usage: %s [-pP] filename...\n", argv0);
 80+}
 81+
 82+int
 83+main(int argc, char *argv[])
 84+{
 85+	int ret = 0;
 86+
 87+	ARGBEGIN {
 88+	case 'p':
 89+		most = 1;
 90+		break;
 91+	case 'P':
 92+		extra = 1;
 93+		break;
 94+	default:
 95+		usage();
 96+	} ARGEND
 97+
 98+	if (!argc)
 99+		usage();
100+
101+	for (; argc--; argv++)
102+		ret |= pathchk(*argv);
103+
104+	return ret;
105+}
+313, -0
  1@@ -0,0 +1,313 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <ctype.h>
  4+#include <errno.h>
  5+#include <limits.h>
  6+#include <stdio.h>
  7+#include <stdlib.h>
  8+#include <string.h>
  9+
 10+#include "utf.h"
 11+#include "util.h"
 12+
 13+#define is_odigit(c) ('0' <= (c) && (c) <= '7')
 14+
 15+static size_t
 16+unescape_pct(char *s, char *is_pct)
 17+{
 18+	static const char escapes[256] = {
 19+		['"'] = '"',
 20+		['\''] = '\'',
 21+		['\\'] = '\\',
 22+		['a'] = '\a',
 23+		['b'] = '\b',
 24+		['E'] = 033,
 25+		['e'] = 033,
 26+		['f'] = '\f',
 27+		['n'] = '\n',
 28+		['r'] = '\r',
 29+		['t'] = '\t',
 30+		['v'] = '\v'
 31+	};
 32+	size_t m, q;
 33+	char *r, *w;
 34+
 35+	for (r = w = s; *r;) {
 36+		if (*r != '\\') {
 37+			is_pct[w - s] = (*r == '%');
 38+			*w++ = *r++;
 39+			continue;
 40+		}
 41+		r++;
 42+		if (!*r) {
 43+			eprintf("null escape sequence\n");
 44+		} else if (escapes[(unsigned char)*r]) {
 45+			is_pct[w - s] = 0;
 46+			*w++ = escapes[(unsigned char)*r++];
 47+		} else if (is_odigit(*r)) {
 48+			for (q = 0, m = 3; m && is_odigit(*r); m--, r++)
 49+				q = q * 8 + (*r - '0');
 50+			is_pct[w - s] = 0;
 51+			*w++ = MIN(q, 255);
 52+		} else if (*r == 'x' && isxdigit(r[1])) {
 53+			r++;
 54+			for (q = 0, m = 2; m && isxdigit(*r); m--, r++)
 55+				if (isdigit(*r))
 56+					q = q * 16 + (*r - '0');
 57+				else
 58+					q = q * 16 + (tolower(*r) - 'a' + 10);
 59+			is_pct[w - s] = 0;
 60+			*w++ = q;
 61+		} else {
 62+			eprintf("invalid escape sequence '\\%c'\n", *r);
 63+		}
 64+	}
 65+	*w = '\0';
 66+
 67+	return w - s;
 68+}
 69+
 70+static void
 71+usage(void)
 72+{
 73+	eprintf("usage: %s format [arg ...]\n", argv0);
 74+}
 75+
 76+int
 77+main(int argc, char *argv[])
 78+{
 79+	Rune *rarg;
 80+	size_t i, j, f, formatlen, blen, nflags;
 81+	long long num;
 82+	double dou;
 83+	int cooldown = 0, width, precision, ret = 0, argi, lastargi;
 84+	int has_width, has_precision;
 85+	char *format, *tmp, *arg, *fmt, *fmt_ptr, *is_pct;
 86+
 87+	argv0 = argv[0];
 88+	if (argc < 2)
 89+		usage();
 90+
 91+	format = argv[1];
 92+	if ((tmp = strstr(format, "\\c"))) {
 93+		*tmp = 0;
 94+		cooldown = 1;
 95+	}
 96+	is_pct = ecalloc(strlen(format) + 1, sizeof(*is_pct));
 97+	formatlen = unescape_pct(format, is_pct);
 98+	if (formatlen == 0) {
 99+		free(is_pct);
100+		return 0;
101+	}
102+	lastargi = 0;
103+	for (i = 0, argi = 2; !cooldown || i < formatlen; i++, i = cooldown ? i : (i % formatlen)) {
104+		if (i == 0) {
105+			if (lastargi == argi)
106+				break;
107+			lastargi = argi;
108+		}
109+
110+		if (format[i] != '%' || !is_pct[i]) {
111+			putchar(format[i]);
112+			continue;
113+		}
114+
115+		/* flag */
116+		f = ++i;
117+		nflags = strspn(&format[f], "#-+ 0");
118+		i += nflags;
119+
120+		if (nflags > INT_MAX)
121+			eprintf("Too many flags in format\n");
122+
123+		/* field width */
124+		has_width = 0;
125+		width = 0;
126+		if (format[i] == '*') {
127+			has_width = 1;
128+			if (argi < argc)
129+				width = estrtonum(argv[argi++], INT_MIN, INT_MAX);
130+			else
131+				cooldown = 1;
132+			i++;
133+		} else {
134+			j = i;
135+			i += strspn(&format[i], "+-0123456789");
136+			if (j != i) {
137+				has_width = 1;
138+				tmp = estrndup(format + j, i - j);
139+				width = estrtonum(tmp, INT_MIN, INT_MAX);
140+				free(tmp);
141+			}
142+		}
143+
144+		/* field precision */
145+		has_precision = 0;
146+		precision = 0;
147+		if (format[i] == '.') {
148+			has_precision = 1;
149+			if (format[++i] == '*') {
150+				if (argi < argc)
151+					precision = estrtonum(argv[argi++], INT_MIN, INT_MAX);
152+				else
153+					cooldown = 1;
154+				i++;
155+			} else {
156+				j = i;
157+				i += strspn(&format[i], "+-0123456789");
158+				if (j != i) {
159+					tmp = estrndup(format + j, i - j);
160+					precision = estrtonum(tmp, INT_MIN, INT_MAX);
161+					free(tmp);
162+				}
163+			}
164+		}
165+
166+		if (format[i] != '%' || !is_pct[i]) {
167+			if (argi < argc)
168+				arg = argv[argi++];
169+			else {
170+				arg = "";
171+				cooldown = 1;
172+			}
173+		} else {
174+			putchar('%');
175+			continue;
176+		}
177+
178+		switch (format[i]) {
179+		case 'b':
180+			if ((tmp = strstr(arg, "\\c"))) {
181+				*tmp = 0;
182+				blen = unescape(arg);
183+				fwrite(arg, sizeof(*arg), blen, stdout);
184+				free(is_pct);
185+				return 0;
186+			}
187+			blen = unescape(arg);
188+			fwrite(arg, sizeof(*arg), blen, stdout);
189+			break;
190+		case 'c':
191+			unescape(arg);
192+			rarg = ereallocarray(NULL, utflen(arg) + 1, sizeof(*rarg));
193+			utftorunestr(arg, rarg);
194+			efputrune(rarg, stdout, "<stdout>");
195+			free(rarg);
196+			break;
197+		case 's':
198+			fmt = emalloc(nflags + 10);
199+			fmt_ptr = fmt;
200+			*fmt_ptr++ = '%';
201+			memcpy(fmt_ptr, &format[f], nflags);
202+			fmt_ptr += nflags;
203+			if (has_width)
204+				*fmt_ptr++ = '*';
205+			if (has_precision) {
206+				*fmt_ptr++ = '.';
207+				*fmt_ptr++ = '*';
208+			}
209+			*fmt_ptr++ = 's';
210+			*fmt_ptr = '\0';
211+
212+			if (has_width && has_precision)
213+				printf(fmt, width, precision, arg);
214+			else if (has_width)
215+				printf(fmt, width, arg);
216+			else if (has_precision)
217+				printf(fmt, precision, arg);
218+			else
219+				printf(fmt, arg);
220+			free(fmt);
221+			break;
222+		case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
223+			for (j = 0; isspace(arg[j]); j++);
224+			if (arg[j] == '\'' || arg[j] == '\"') {
225+				arg += j + 1;
226+				unescape(arg);
227+				rarg = ereallocarray(NULL, utflen(arg) + 1, sizeof(*rarg));
228+				utftorunestr(arg, rarg);
229+				num = rarg[0];
230+			} else if (arg[0]) {
231+				errno = 0;
232+				if (format[i] == 'd' || format[i] == 'i')
233+					num = strtol(arg, &tmp, 0);
234+				else
235+					num = strtoul(arg, &tmp, 0);
236+
237+				if (tmp == arg || *tmp != '\0') {
238+					ret = 1;
239+					weprintf("%%%c %s: conversion error\n",
240+					    format[i], arg);
241+				}
242+				if (errno == ERANGE) {
243+					ret = 1;
244+					weprintf("%%%c %s: out of range\n",
245+					    format[i], arg);
246+				}
247+			} else {
248+					num = 0;
249+			}
250+			fmt = emalloc(nflags + 15);
251+			fmt_ptr = fmt;
252+			*fmt_ptr++ = '%';
253+			memcpy(fmt_ptr, &format[f], nflags);
254+			fmt_ptr += nflags;
255+			if (has_width)
256+				*fmt_ptr++ = '*';
257+			if (has_precision) {
258+				*fmt_ptr++ = '.';
259+				*fmt_ptr++ = '*';
260+			}
261+			*fmt_ptr++ = 'l';
262+			*fmt_ptr++ = 'l';
263+			*fmt_ptr++ = format[i];
264+			*fmt_ptr = '\0';
265+
266+			if (has_width && has_precision)
267+				printf(fmt, width, precision, num);
268+			else if (has_width)
269+				printf(fmt, width, num);
270+			else if (has_precision)
271+				printf(fmt, precision, num);
272+			else
273+				printf(fmt, num);
274+			free(fmt);
275+			break;
276+		case 'a': case 'A': case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
277+			fmt = emalloc(nflags + 15);
278+			fmt_ptr = fmt;
279+			*fmt_ptr++ = '%';
280+			memcpy(fmt_ptr, &format[f], nflags);
281+			fmt_ptr += nflags;
282+			if (has_width)
283+				*fmt_ptr++ = '*';
284+			if (has_precision) {
285+				*fmt_ptr++ = '.';
286+				*fmt_ptr++ = '*';
287+			}
288+			*fmt_ptr++ = format[i];
289+			*fmt_ptr = '\0';
290+
291+			dou = (strlen(arg) > 0) ? estrtod(arg) : 0;
292+			if (has_width && has_precision)
293+				printf(fmt, width, precision, dou);
294+			else if (has_width)
295+				printf(fmt, width, dou);
296+			else if (has_precision)
297+				printf(fmt, precision, dou);
298+			else
299+				printf(fmt, dou);
300+			free(fmt);
301+			break;
302+		case '\0':
303+			eprintf("Missing format specifier.\n");
304+			break;
305+		default:
306+			eprintf("Invalid format specifier '%c'.\n", format[i]);
307+		}
308+		if (argi >= argc)
309+			cooldown = 1;
310+	}
311+
312+	free(is_pct);
313+	return fshut(stdout, "<stdout>") | ret;
314+}
+180, -0
  1@@ -0,0 +1,180 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/ioctl.h>
  4+#include <sys/sysinfo.h>
  5+
  6+#include <errno.h>
  7+#include <libgen.h>
  8+#include <limits.h>
  9+#include <pwd.h>
 10+#include <stdio.h>
 11+#include <stdlib.h>
 12+#include <string.h>
 13+#include <time.h>
 14+#include <unistd.h>
 15+
 16+#include "proc.h"
 17+#include "util.h"
 18+
 19+static void psout(struct procstat *ps);
 20+static void psr(const char *file);
 21+
 22+enum {
 23+	PS_aflag = 1 << 0,
 24+	PS_Aflag = 1 << 1,
 25+	PS_dflag = 1 << 2,
 26+	PS_fflag = 1 << 3
 27+};
 28+
 29+static int flags;
 30+
 31+static void
 32+psout(struct procstat *ps)
 33+{
 34+	struct procstatus pstatus;
 35+	char cmdline[BUFSIZ], *cmd;
 36+	char buf[BUFSIZ];
 37+	char ttystr[TTY_NAME_MAX], *myttystr;
 38+	int tty_maj, tty_min;
 39+	uid_t myeuid;
 40+	unsigned sutime;
 41+	time_t start;
 42+	char stimestr[sizeof("%H:%M")];
 43+	struct sysinfo info;
 44+	struct passwd *pw;
 45+	struct winsize w;
 46+
 47+	/* Ignore session leaders */
 48+	if (flags & PS_dflag)
 49+		if (ps->pid == ps->sid)
 50+			return;
 51+
 52+	devtotty(ps->tty_nr, &tty_maj, &tty_min);
 53+	ttytostr(tty_maj, tty_min, ttystr, sizeof(ttystr));
 54+
 55+	/* Only print processes that are associated with
 56+	 * a terminal and they are not session leaders */
 57+	if (flags & PS_aflag)
 58+		if (ps->pid == ps->sid || ttystr[0] == '?')
 59+			return;
 60+
 61+	if (parsestatus(ps->pid, &pstatus) < 0)
 62+		return;
 63+
 64+	/* This is the default case, only print processes that have
 65+	 * the same controlling terminal as the invoker and the same
 66+	 * euid as the current user */
 67+	if (!(flags & (PS_aflag | PS_Aflag | PS_dflag))) {
 68+		myttystr = ttyname(0);
 69+		if (myttystr) {
 70+			if (strcmp(myttystr + strlen("/dev/"), ttystr))
 71+				return;
 72+		} else {
 73+			/* The invoker has no controlling terminal - just
 74+			 * go ahead and print the processes anyway */
 75+			ttystr[0] = '?';
 76+			ttystr[1] = '\0';
 77+		}
 78+		myeuid = geteuid();
 79+		if (myeuid != pstatus.euid)
 80+			return;
 81+	}
 82+
 83+	sutime = (ps->stime + ps->utime) / sysconf(_SC_CLK_TCK);
 84+
 85+	ioctl(1, TIOCGWINSZ, &w);
 86+	if (!(flags & PS_fflag)) {
 87+		snprintf(buf, sizeof(buf), "%5d %-6s   %02u:%02u:%02u %s", ps->pid, ttystr,
 88+			 sutime / 3600, (sutime % 3600) / 60, sutime % 60,
 89+			 ps->comm);
 90+		if (w.ws_col)
 91+			printf("%.*s\n", w.ws_col, buf);
 92+		else
 93+			printf("%s\n", buf);
 94+	} else {
 95+		errno = 0;
 96+		pw = getpwuid(pstatus.uid);
 97+		if (!pw)
 98+			eprintf("getpwuid %d:", pstatus.uid);
 99+
100+		if (sysinfo(&info) < 0)
101+			eprintf("sysinfo:");
102+
103+		start = time(NULL) - info.uptime;
104+		start += (ps->starttime / sysconf(_SC_CLK_TCK));
105+		strftime(stimestr, sizeof(stimestr),
106+			 "%H:%M", localtime(&start));
107+
108+		/* For kthreads/zombies /proc/<pid>/cmdline will be
109+		 * empty so use ps->comm in that case */
110+		if (parsecmdline(ps->pid, cmdline, sizeof(cmdline)) < 0)
111+			cmd = ps->comm;
112+		else
113+			cmd = cmdline;
114+
115+		snprintf(buf, sizeof(buf), "%-8s %5d %5d  ? %5s %-5s    %02u:%02u:%02u %s%s%s",
116+			 pw->pw_name, ps->pid,
117+			 ps->ppid, stimestr, ttystr,
118+			 sutime / 3600, (sutime % 3600) / 60, sutime % 60,
119+			 (cmd == ps->comm) ? "[" : "", cmd,
120+			 (cmd == ps->comm) ? "]" : "");
121+		if (w.ws_col)
122+			printf("%.*s\n", w.ws_col, buf);
123+		else
124+			printf("%s\n", buf);
125+	}
126+}
127+
128+static void
129+psr(const char *file)
130+{
131+	char path[PATH_MAX], *p;
132+	struct procstat ps;
133+	pid_t pid;
134+
135+	if (strlcpy(path, file, sizeof(path)) >= sizeof(path))
136+		eprintf("path too long\n");
137+	p = basename(path);
138+	if (pidfile(p) == 0)
139+		return;
140+	pid = estrtol(p, 10);
141+	if (parsestat(pid, &ps) < 0)
142+		return;
143+	psout(&ps);
144+}
145+
146+static void
147+usage(void)
148+{
149+	eprintf("usage: %s [-aAdef]\n", argv0);
150+}
151+
152+int
153+main(int argc, char *argv[])
154+{
155+	ARGBEGIN {
156+	case 'a':
157+		flags |= PS_aflag;
158+		break;
159+	case 'A':
160+		flags |= PS_Aflag;
161+		break;
162+	case 'd':
163+		flags |= PS_dflag;
164+		break;
165+	case 'e':
166+		flags |= PS_Aflag;
167+		break;
168+	case 'f':
169+		flags |= PS_fflag;
170+		break;
171+	default:
172+		usage();
173+	} ARGEND;
174+
175+	if (!(flags & PS_fflag))
176+		printf("  PID TTY          TIME CMD\n");
177+	else
178+		printf("UID        PID  PPID  C STIME TTY          TIME CMD\n");
179+	recurse_dir("/proc", psr);
180+	return 0;
181+}
+50, -0
 1@@ -0,0 +1,50 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+
 5+#include <stdio.h>
 6+#include <stdlib.h>
 7+#include <unistd.h>
 8+
 9+#include "util.h"
10+
11+static const char *
12+getpwd(const char *cwd)
13+{
14+	const char *pwd;
15+	struct stat cst, pst;
16+
17+	if (!(pwd = getenv("PWD")) || pwd[0] != '/' || stat(pwd, &pst) < 0)
18+		return cwd;
19+	if (stat(cwd, &cst) < 0)
20+		eprintf("stat %s:", cwd);
21+
22+	return (pst.st_dev == cst.st_dev && pst.st_ino == cst.st_ino) ? pwd : cwd;
23+}
24+
25+static void
26+usage(void)
27+{
28+	eprintf("usage: %s [-LP]\n", argv0);
29+}
30+
31+int
32+main(int argc, char *argv[])
33+{
34+	char cwd[PATH_MAX];
35+	char mode = 'L';
36+
37+	ARGBEGIN {
38+	case 'L':
39+	case 'P':
40+		mode = ARGC();
41+		break;
42+	default:
43+		usage();
44+	} ARGEND
45+
46+	if (!getcwd(cwd, sizeof(cwd)))
47+		eprintf("getcwd:");
48+	puts((mode == 'L') ? getpwd(cwd) : cwd);
49+
50+	return fshut(stdout, "<stdout>");
51+}
+68, -0
 1@@ -0,0 +1,68 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <limits.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <string.h>
 7+#include <unistd.h>
 8+
 9+#include "util.h"
10+
11+static void
12+usage(void)
13+{
14+#ifdef STD_NON_POSIX
15+	eprintf("usage: %s [-fn] path\n", argv0);
16+#else
17+	eprintf("usage: %s [-n] path\n", argv0);
18+#endif
19+}
20+
21+int
22+main(int argc, char *argv[])
23+{
24+	char buf[PATH_MAX];
25+	ssize_t n;
26+	int nflag = 0;
27+#ifdef STD_NON_POSIX
28+	int fflag = 0;
29+#endif
30+
31+	ARGBEGIN
32+	{
33+#ifdef STD_NON_POSIX
34+	case 'f':
35+		fflag = 1;
36+		break;
37+#endif
38+	case 'n':
39+		nflag = 1;
40+		break;
41+	default:
42+		usage();
43+	}
44+	ARGEND
45+
46+	if (argc != 1)
47+		usage();
48+
49+	if (strlen(argv[0]) >= PATH_MAX)
50+		eprintf("path too long\n");
51+
52+#ifdef STD_NON_POSIX
53+	if (fflag) {
54+		if (!realpath(argv[0], buf))
55+			eprintf("realpath %s:", argv[0]);
56+	} else
57+#endif
58+	{
59+		if ((n = readlink(argv[0], buf, PATH_MAX - 1)) < 0)
60+			eprintf("readlink %s:", argv[0]);
61+		buf[n] = '\0';
62+	}
63+
64+	fputs(buf, stdout);
65+	if (!nflag)
66+		putchar('\n');
67+
68+	return fshut(stdout, "<stdout>");
69+}
+93, -0
 1@@ -0,0 +1,93 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/resource.h>
 4+
 5+#include <errno.h>
 6+#include <pwd.h>
 7+#include <stdlib.h>
 8+
 9+#include "util.h"
10+
11+#ifndef PRIO_MIN
12+#define PRIO_MIN -NZERO
13+#endif
14+
15+#ifndef PRIO_MAX
16+#define PRIO_MAX (NZERO-1)
17+#endif
18+
19+static int
20+renice(int which, int who, long adj)
21+{
22+	errno = 0;
23+	adj += getpriority(which, who);
24+	if (errno) {
25+		weprintf("getpriority %d:", who);
26+		return 0;
27+	}
28+
29+	adj = MAX(PRIO_MIN, MIN(adj, PRIO_MAX));
30+	if (setpriority(which, who, (int)adj) < 0) {
31+		weprintf("setpriority %d:", who);
32+		return 0;
33+	}
34+
35+	return 1;
36+}
37+
38+static void
39+usage(void)
40+{
41+	eprintf("usage: %s -n num [-g | -p | -u] id ...\n", argv0);
42+}
43+
44+int
45+main(int argc, char *argv[])
46+{
47+	const char *adj = NULL;
48+	long val;
49+	int which = PRIO_PROCESS, ret = 0;
50+	struct passwd *pw;
51+	int who;
52+
53+	ARGBEGIN {
54+	case 'n':
55+		adj = EARGF(usage());
56+		break;
57+	case 'g':
58+		which = PRIO_PGRP;
59+		break;
60+	case 'p':
61+		which = PRIO_PROCESS;
62+		break;
63+	case 'u':
64+		which = PRIO_USER;
65+		break;
66+	default:
67+		usage();
68+	} ARGEND
69+
70+	if (!argc || !adj)
71+		usage();
72+
73+	val = estrtonum(adj, PRIO_MIN, PRIO_MAX);
74+	for (; *argv; argc--, argv++) {
75+		if (which == PRIO_USER) {
76+			errno = 0;
77+			if (!(pw = getpwnam(*argv))) {
78+				if (errno)
79+					weprintf("getpwnam %s:", *argv);
80+				else
81+					weprintf("getpwnam %s: no user found\n", *argv);
82+				ret = 1;
83+				continue;
84+			}
85+			who = pw->pw_uid;
86+		} else {
87+			who = estrtonum(*argv, 1, INT_MAX);
88+		}
89+		if (!renice(which, who, val))
90+			ret = 1;
91+	}
92+
93+	return ret;
94+}
+87, -0
 1@@ -0,0 +1,87 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <fcntl.h>
 4+#include  <string.h>
 5+
 6+#include "fs.h"
 7+#include "util.h"
 8+
 9+static void
10+usage(void)
11+{
12+	eprintf("usage: %s [-f] [-iRr] file ...\n", argv0);
13+}
14+
15+static int
16+forbidden(char *path, struct stat *root)
17+{
18+	char *s, *t;
19+	size_t n;
20+	struct stat st;
21+	static int w1, w2;
22+
23+	n = strlen(path);
24+	for (t = path + n; t > path && t[-1] == '/'; --t)
25+		;
26+	for (s = t; s > path && s[-1] != '/'; --s)
27+		;
28+	n = t - s;
29+	if (n == 1 && *s == '.' || n == 2 && s[0] == '.' && s[1] == '.') {
30+		if (!w1)
31+			weprintf("\".\" and \"..\" may not be removed\n");
32+		w1 = 1;
33+		return 1;
34+	}
35+
36+	if (stat(path, &st) < 0)
37+		return 0;
38+	if (st.st_dev == root->st_dev && st.st_ino == root->st_ino) {
39+		if (!w2)
40+			weprintf("\"/\" may not be removed\n");
41+		w2 = 1;
42+		return 1;
43+	}
44+
45+	return 0;
46+}
47+
48+int
49+main(int argc, char *argv[])
50+{
51+	char *s;
52+	struct stat st;
53+	struct recursor r = { .fn = rm, .maxdepth = 1, .follow = 'P' };
54+
55+	ARGBEGIN {
56+	case 'f':
57+		r.flags |= SILENT | IGNORE;
58+		break;
59+	case 'i':
60+		r.flags |= CONFIRM;
61+		break;
62+	case 'R':
63+	case 'r':
64+		r.maxdepth = 0;
65+		break;
66+	default:
67+		usage();
68+	} ARGEND
69+
70+	if (!argc) {
71+		if (!(r.flags & IGNORE))
72+			usage();
73+		else
74+			return 0;
75+	}
76+
77+	if (stat("/", &st) < 0)
78+		eprintf("stat root:");
79+	for (; *argv; argc--, argv++) {
80+		if (forbidden(*argv, &st)) {
81+			rm_status = 1;
82+			continue;
83+		}
84+		recurse(AT_FDCWD, *argv, NULL, &r);
85+	}
86+
87+	return rm_status || recurse_status;
88+}
+49, -0
 1@@ -0,0 +1,49 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <libgen.h>
 4+#include <string.h>
 5+#include <unistd.h>
 6+
 7+#include "util.h"
 8+
 9+static void
10+usage(void)
11+{
12+	eprintf("usage: %s [-p] dir ...\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+	int pflag = 0, ret = 0;
19+	char *d;
20+
21+	ARGBEGIN {
22+	case 'p':
23+		pflag = 1;
24+		break;
25+	default:
26+		usage();
27+	} ARGEND
28+
29+	if (!argc)
30+		usage();
31+
32+	for (; *argv; argc--, argv++) {
33+		if (rmdir(*argv) < 0) {
34+			weprintf("rmdir %s:", *argv);
35+			ret = 1;
36+		} else if (pflag) {
37+			d = dirname(*argv);
38+			for (; strcmp(d, "/") && strcmp(d, ".") ;) {
39+				if (rmdir(d) < 0) {
40+					weprintf("rmdir %s:", d);
41+					ret = 1;
42+					break;
43+				}
44+				d = dirname(d);
45+			}
46+		}
47+	}
48+
49+	return ret;
50+}
+1738, -0
   1@@ -0,0 +1,1738 @@
   2+/* FIXME: summary
   3+ * decide whether we enforce valid UTF-8, right now it's enforced in certain
   4+ *     parts of the script, but not the input...
   5+ * nul bytes cause explosions due to use of libc string functions. thoughts?
   6+ * lack of newline at end of file, currently we add one. what should we do?
   7+ * allow "\\t" for "\t" etc. in regex? in replacement text?
   8+ * POSIX says don't flush on N when out of input, but GNU and busybox do.
   9+ */
  10+
  11+#include <ctype.h>
  12+#include <errno.h>
  13+#include <regex.h>
  14+#include <stdlib.h>
  15+#include <string.h>
  16+
  17+#include "utf.h"
  18+#include "util.h"
  19+
  20+/* Types */
  21+
  22+/* used as queue for writes and stack for {,:,b,t */
  23+typedef struct {
  24+	void **data;
  25+	size_t size;
  26+	size_t cap;
  27+} Vec;
  28+
  29+/* used for arbitrary growth, str is a C string
  30+ * FIXME: does it make sense to keep track of length? or just rely on libc
  31+ *        string functions? If we want to support nul bytes everything changes
  32+ */
  33+typedef struct {
  34+	char  *str;
  35+	size_t cap;
  36+} String;
  37+
  38+typedef struct Cmd Cmd;
  39+typedef struct {
  40+	void  (*fn)(Cmd *);
  41+	char *(*getarg)(Cmd *, char *);
  42+	void  (*freearg)(Cmd *);
  43+	unsigned char naddr;
  44+} Fninfo;
  45+
  46+typedef struct {
  47+	union {
  48+		size_t   lineno;
  49+		regex_t *re;
  50+	} u;
  51+	enum {
  52+		IGNORE, /* empty address, ignore        */
  53+		EVERY , /* every line                   */
  54+		LINE  , /* line number                  */
  55+		LAST  , /* last line ($)                */
  56+		REGEX , /* use included regex           */
  57+		LASTRE, /* use most recently used regex */
  58+	} type;
  59+} Addr;
  60+
  61+/* DISCUSS: naddr is not strictly necessary, but very helpful
  62+ * naddr == 0 iff beg.type == EVERY  && end.type == IGNORE
  63+ * naddr == 1 iff beg.type != IGNORE && end.type == IGNORE
  64+ * naddr == 2 iff beg.type != IGNORE && end.type != IGNORE
  65+ */
  66+typedef struct {
  67+	Addr          beg;
  68+	Addr          end;
  69+	unsigned char naddr;
  70+} Range;
  71+
  72+typedef struct {
  73+	regex_t      *re; /* if NULL use last regex */
  74+	String        repl;
  75+	FILE         *file;
  76+	size_t        occurrence; /* 0 for all (g flag) */
  77+	Rune          delim;
  78+	unsigned int  p:1;
  79+} Sarg;
  80+
  81+typedef struct {
  82+	Rune *set1;
  83+	Rune *set2;
  84+} Yarg;
  85+
  86+typedef struct {
  87+	String str; /* a,c,i text. r file path */
  88+	void  (*print)(char *, FILE *); /* check_puts for a, write_file for r, unused for c,i */
  89+} ACIRarg;
  90+
  91+struct Cmd {
  92+	Range   range;
  93+	Fninfo *fninfo;
  94+	union {
  95+		Cmd      *jump;   /* used for   b,t when running  */
  96+		char     *label;  /* used for :,b,t when building */
  97+		ptrdiff_t offset; /* used for { (pointers break during realloc) */
  98+		FILE     *file;   /* used for w */
  99+
 100+		/* FIXME: Should the following be in the union? or pointers and malloc? */
 101+		Sarg      s;
 102+		Yarg      y;
 103+		ACIRarg   acir;
 104+	} u; /* I find your lack of anonymous unions disturbing */
 105+	unsigned int in_match:1;
 106+	unsigned int negate  :1;
 107+};
 108+
 109+/* Files for w command (and s' w flag) */
 110+typedef struct {
 111+	char *path;
 112+	FILE *file;
 113+} Wfile;
 114+
 115+/*
 116+ * Function Declarations
 117+ */
 118+
 119+/* Dynamically allocated arrays and strings */
 120+static void resize(void **ptr, size_t *nmemb, size_t size, size_t new_nmemb, void **next);
 121+static void *pop(Vec *v);
 122+static void push(Vec *v, void *p);
 123+static void stracat(String *dst, char *src);
 124+static void strnacat(String *dst, char *src, size_t n);
 125+static void stracpy(String *dst, char *src);
 126+
 127+/* Cleanup and errors */
 128+static void usage(void);
 129+
 130+/* Parsing functions and related utilities */
 131+static void compile(char *s, int isfile);
 132+static int read_line(FILE *f, String *s);
 133+static char *make_range(Range *range, char *s);
 134+static char *make_addr(Addr *addr, char *s);
 135+static char *find_delim(char *s, Rune delim, int do_brackets);
 136+static char *chompr(char *s, Rune rune);
 137+static char *chomp(char *s);
 138+static Rune *strtorunes(char *s, size_t nrunes);
 139+static long stol(char *s, char **endp);
 140+static size_t escapes(char *beg, char *end, Rune delim, int n_newline);
 141+static size_t echarntorune(Rune *r, char *s, size_t n);
 142+static void insert_labels(void);
 143+
 144+/* Get and Free arg and related utilities */
 145+static char *get_aci_arg(Cmd *c, char *s);
 146+static void aci_append(Cmd *c, char *s);
 147+static void free_acir_arg(Cmd *c);
 148+static char *get_bt_arg(Cmd *c, char *s);
 149+static char *get_r_arg(Cmd *c, char *s);
 150+static char *get_s_arg(Cmd *c, char *s);
 151+static void free_s_arg(Cmd *c);
 152+static char *get_w_arg(Cmd *c, char *s);
 153+static char *get_y_arg(Cmd *c, char *s);
 154+static void free_y_arg(Cmd *c);
 155+static char *get_colon_arg(Cmd *c, char *s);
 156+static char *get_lbrace_arg(Cmd *c, char *s);
 157+static char *get_rbrace_arg(Cmd *c, char *s);
 158+static char *semicolon_arg(char *s);
 159+
 160+/* Running */
 161+static void run(void);
 162+static int in_range(Cmd *c);
 163+static int match_addr(Addr *a);
 164+static int next_file(void);
 165+static int is_eof(FILE *f);
 166+static void do_writes(void);
 167+static void write_file(char *path, FILE *out);
 168+static void check_puts(char *s, FILE *f);
 169+static void update_ranges(Cmd *beg, Cmd *end);
 170+
 171+/* Sed functions */
 172+static void cmd_y(Cmd *c);
 173+static void cmd_x(Cmd *c);
 174+static void cmd_w(Cmd *c);
 175+static void cmd_t(Cmd *c);
 176+static void cmd_s(Cmd *c);
 177+static void cmd_r(Cmd *c);
 178+static void cmd_q(Cmd *c);
 179+static void cmd_P(Cmd *c);
 180+static void cmd_p(Cmd *c);
 181+static void cmd_N(Cmd *c);
 182+static void cmd_n(Cmd *c);
 183+static void cmd_l(Cmd *c);
 184+static void cmd_i(Cmd *c);
 185+static void cmd_H(Cmd *c);
 186+static void cmd_h(Cmd *c);
 187+static void cmd_G(Cmd *c);
 188+static void cmd_g(Cmd *c);
 189+static void cmd_D(Cmd *c);
 190+static void cmd_d(Cmd *c);
 191+static void cmd_c(Cmd *c);
 192+static void cmd_b(Cmd *c);
 193+static void cmd_a(Cmd *c);
 194+static void cmd_colon(Cmd *c);
 195+static void cmd_equal(Cmd *c);
 196+static void cmd_lbrace(Cmd *c);
 197+static void cmd_rbrace(Cmd *c);
 198+static void cmd_last(Cmd *c);
 199+
 200+/* Actions */
 201+static void new_line(void);
 202+static void app_line(void);
 203+static void new_next(void);
 204+static void old_next(void);
 205+
 206+/*
 207+ * Globals
 208+ */
 209+static Vec braces, labels, branches; /* holds ptrdiff_t. addrs of {, :, bt */
 210+static Vec writes; /* holds cmd*. writes scheduled by a and r commands */
 211+static Vec wfiles; /* holds Wfile*. files for w and s///w commands */
 212+
 213+static Cmd   *prog, *pc; /* Program, program counter */
 214+static size_t pcap;
 215+static size_t lineno;
 216+
 217+static regex_t *lastre; /* last used regex for empty regex search */
 218+static char   **files;  /* list of file names from argv */
 219+static FILE    *file;   /* current file we are reading */
 220+static int      ret;    /* exit status */
 221+
 222+static String patt, hold, genbuf;
 223+
 224+static struct {
 225+	unsigned int n       :1; /* -n (no print) */
 226+	unsigned int E       :1; /* -E (extended re) */
 227+	unsigned int s       :1; /* s/// replacement happened */
 228+	unsigned int aci_cont:1; /* a,c,i text continuation */
 229+	unsigned int s_cont  :1; /* s/// replacement text continuation */
 230+	unsigned int halt    :1; /* halt execution */
 231+} gflags;
 232+
 233+/* FIXME: move character inside Fninfo and only use 26*sizeof(Fninfo) instead of 127*sizeof(Fninfo) bytes */
 234+static Fninfo fns[] = {
 235+	['a'] = { cmd_a     , get_aci_arg   , free_acir_arg , 1 }, /* schedule write of text for later                                                      */
 236+	['b'] = { cmd_b     , get_bt_arg    , NULL          , 2 }, /* branch to label char *label when building, Cmd *jump when running                     */
 237+	['c'] = { cmd_c     , get_aci_arg   , free_acir_arg , 2 }, /* delete pattern space. at 0 or 1 addr or end of 2 addr, write text                     */
 238+	['d'] = { cmd_d     , NULL          , NULL          , 2 }, /* delete pattern space                                                                  */
 239+	['D'] = { cmd_D     , NULL          , NULL          , 2 }, /* delete to first newline and start new cycle without reading (if no newline, d)        */
 240+	['g'] = { cmd_g     , NULL          , NULL          , 2 }, /* replace pattern space with hold space                                                 */
 241+	['G'] = { cmd_G     , NULL          , NULL          , 2 }, /* append newline and hold space to pattern space                                        */
 242+	['h'] = { cmd_h     , NULL          , NULL          , 2 }, /* replace hold space with pattern space                                                 */
 243+	['H'] = { cmd_H     , NULL          , NULL          , 2 }, /* append newline and pattern space to hold space                                        */
 244+	['i'] = { cmd_i     , get_aci_arg   , free_acir_arg , 1 }, /* write text                                                                            */
 245+	['l'] = { cmd_l     , NULL          , NULL          , 2 }, /* write pattern space in 'visually unambiguous form'                                    */
 246+	['n'] = { cmd_n     , NULL          , NULL          , 2 }, /* write pattern space (unless -n) read to replace pattern space (if no input, quit)     */
 247+	['N'] = { cmd_N     , NULL          , NULL          , 2 }, /* append to pattern space separated by newline, line number changes (if no input, quit) */
 248+	['p'] = { cmd_p     , NULL          , NULL          , 2 }, /* write pattern space                                                                   */
 249+	['P'] = { cmd_P     , NULL          , NULL          , 2 }, /* write pattern space up to first newline                                               */
 250+	['q'] = { cmd_q     , NULL          , NULL          , 1 }, /* quit                                                                                  */
 251+	['r'] = { cmd_r     , get_r_arg     , free_acir_arg , 1 }, /* write contents of file (unable to open/read treated as empty file)                    */
 252+	['s'] = { cmd_s     , get_s_arg     , free_s_arg    , 2 }, /* find/replace/all that crazy s stuff                                                   */
 253+	['t'] = { cmd_t     , get_bt_arg    , NULL          , 2 }, /* if s/// succeeded (since input or last t) branch to label (branch to end if no label) */
 254+	['w'] = { cmd_w     , get_w_arg     , NULL          , 2 }, /* append pattern space to file                                                          */
 255+	['x'] = { cmd_x     , NULL          , NULL          , 2 }, /* exchange pattern and hold spaces                                                      */
 256+	['y'] = { cmd_y     , get_y_arg     , free_y_arg    , 2 }, /* replace runes in set1 with runes in set2                                              */
 257+	[':'] = { cmd_colon , get_colon_arg , NULL          , 0 }, /* defines label for later b and t commands                                              */
 258+	['='] = { cmd_equal , NULL          , NULL          , 1 }, /* printf("%d\n", line_number);                                                          */
 259+	['{'] = { cmd_lbrace, get_lbrace_arg, NULL          , 2 }, /* if we match, run commands, otherwise jump to close                                    */
 260+	['}'] = { cmd_rbrace, get_rbrace_arg, NULL          , 0 }, /* noop, hold onto open for ease of building scripts                                     */
 261+
 262+	[0x7f] = { NULL, NULL, NULL, 0 }, /* index is checked with isascii(3p). fill out rest of array */
 263+};
 264+
 265+/*
 266+ * Function Definitions
 267+ */
 268+
 269+/* given memory pointed to by *ptr that currently holds *nmemb members of size
 270+ * size, realloc to hold new_nmemb members, return new_nmemb in *memb and one
 271+ * past old end in *next. if realloc fails...explode
 272+ */
 273+static void
 274+resize(void **ptr, size_t *nmemb, size_t size, size_t new_nmemb, void **next)
 275+{
 276+	void *n, *tmp;
 277+
 278+	if (new_nmemb) {
 279+		tmp = ereallocarray(*ptr, new_nmemb, size);
 280+	} else { /* turns out realloc(*ptr, 0) != free(*ptr) */
 281+		free(*ptr);
 282+		tmp = NULL;
 283+	}
 284+	n = (char *)tmp + *nmemb * size;
 285+	*nmemb = new_nmemb;
 286+	*ptr   = tmp;
 287+	if (next)
 288+		*next = n;
 289+}
 290+
 291+static void *
 292+pop(Vec *v)
 293+{
 294+	if (!v->size)
 295+		return NULL;
 296+	return v->data[--v->size];
 297+}
 298+
 299+static void
 300+push(Vec *v, void *p)
 301+{
 302+	if (v->size == v->cap)
 303+		resize((void **)&v->data, &v->cap, sizeof(*v->data), v->cap * 2 + 1, NULL);
 304+	v->data[v->size++] = p;
 305+}
 306+
 307+static void
 308+stracat(String *dst, char *src)
 309+{
 310+	int new = !dst->cap;
 311+	size_t len;
 312+
 313+	len = (new ? 0 : strlen(dst->str)) + strlen(src) + 1;
 314+	if (dst->cap < len)
 315+		resize((void **)&dst->str, &dst->cap, 1, len * 2, NULL);
 316+	if (new)
 317+		*dst->str = '\0';
 318+	strcat(dst->str, src);
 319+}
 320+
 321+static void
 322+strnacat(String *dst, char *src, size_t n)
 323+{
 324+	int new = !dst->cap;
 325+	size_t len;
 326+
 327+	len = strlen(src);
 328+	len = (new ? 0 : strlen(dst->str)) + MIN(n, len) + 1;
 329+	if (dst->cap < len)
 330+		resize((void **)&dst->str, &dst->cap, 1, len * 2, NULL);
 331+	if (new)
 332+		*dst->str = '\0';
 333+	strlcat(dst->str, src, len);
 334+}
 335+
 336+static void
 337+stracpy(String *dst, char *src)
 338+{
 339+	size_t len;
 340+
 341+	len = strlen(src) + 1;
 342+	if (dst->cap < len)
 343+		resize((void **)&dst->str, &dst->cap, 1, len * 2, NULL);
 344+	strcpy(dst->str, src);
 345+}
 346+
 347+static void
 348+leprintf(char *s)
 349+{
 350+	if (errno)
 351+		eprintf("%zu: %s: %s\n", lineno, s, strerror(errno));
 352+	else
 353+		eprintf("%zu: %s\n", lineno, s);
 354+}
 355+
 356+/* FIXME: write usage message */
 357+static void
 358+usage(void)
 359+{
 360+	eprintf("usage: sed [-nrE] script [file ...]\n"
 361+	        "       sed [-nrE] -e script [-e script] ... [-f scriptfile] ... [file ...]\n"
 362+	        "       sed [-nrE] [-e script] ... -f scriptfile [-f scriptfile] ... [file ...]\n");
 363+}
 364+
 365+/* Differences from POSIX
 366+ * we allows semicolons and trailing blanks inside {}
 367+ * we allow spaces after ! (and in between !s)
 368+ * we allow extended regular expressions (-E)
 369+ */
 370+static void
 371+compile(char *s, int isfile)
 372+{
 373+	FILE *f;
 374+
 375+	if (isfile) {
 376+		f = fopen(s, "r");
 377+		if (!f)
 378+			eprintf("fopen %s:", s);
 379+	} else {
 380+		if (!*s) /* empty string script */
 381+			return;
 382+		f = fmemopen(s, strlen(s), "r");
 383+		if (!f)
 384+			eprintf("fmemopen:");
 385+	}
 386+
 387+	/* NOTE: get arg functions can't use genbuf */
 388+	while (read_line(f, &genbuf) != EOF) {
 389+		s = genbuf.str;
 390+
 391+		/* if the first two characters of the script are "#n" default output shall be suppressed */
 392+		if (++lineno == 1 && *s == '#' && s[1] == 'n') {
 393+			gflags.n = 1;
 394+			continue;
 395+		}
 396+
 397+		if (gflags.aci_cont) {
 398+			aci_append(pc - 1, s);
 399+			continue;
 400+		}
 401+		if (gflags.s_cont)
 402+			s = (pc - 1)->fninfo->getarg(pc - 1, s);
 403+
 404+		while (*s) {
 405+			s = chompr(s, ';');
 406+			if (!*s || *s == '#')
 407+				break;
 408+
 409+			if ((size_t)(pc - prog) == pcap)
 410+				resize((void **)&prog, &pcap, sizeof(*prog), pcap * 2 + 1, (void **)&pc);
 411+
 412+			pc->range.beg.type = pc->range.end.type = IGNORE;
 413+			pc->fninfo = NULL;
 414+			pc->in_match = 0;
 415+
 416+			s = make_range(&pc->range, s);
 417+			s = chomp(s);
 418+			pc->negate = *s == '!';
 419+			s = chompr(s, '!');
 420+
 421+			if (!isascii(*s) || !(pc->fninfo = &fns[(unsigned)*s])->fn)
 422+				leprintf("bad sed function");
 423+			if (pc->range.naddr > pc->fninfo->naddr)
 424+				leprintf("wrong number of addresses");
 425+			s++;
 426+
 427+			if (pc->fninfo->getarg)
 428+				s = pc->fninfo->getarg(pc, s);
 429+
 430+			pc++;
 431+		}
 432+	}
 433+
 434+	fshut(f, s);
 435+}
 436+
 437+/* FIXME: if we decide to honor lack of trailing newline, set/clear a global
 438+ * flag when reading a line
 439+ */
 440+static int
 441+read_line(FILE *f, String *s)
 442+{
 443+	ssize_t len;
 444+
 445+	if (!f)
 446+		return EOF;
 447+
 448+	if ((len = getline(&s->str, &s->cap, f)) < 0) {
 449+		if (ferror(f))
 450+			eprintf("getline:");
 451+		return EOF;
 452+	}
 453+	if (s->str[--len] == '\n')
 454+		s->str[len] = '\0';
 455+	return 0;
 456+}
 457+
 458+/* read first range from s, return pointer to one past end of range */
 459+static char *
 460+make_range(Range *range, char *s)
 461+{
 462+	s = make_addr(&range->beg, s);
 463+
 464+	if (*s == ',')
 465+		s = make_addr(&range->end, s + 1);
 466+	else
 467+		range->end.type = IGNORE;
 468+
 469+	if      (range->beg.type == EVERY  && range->end.type == IGNORE) range->naddr = 0;
 470+	else if (range->beg.type != IGNORE && range->end.type == IGNORE) range->naddr = 1;
 471+	else if (range->beg.type != IGNORE && range->end.type != IGNORE) range->naddr = 2;
 472+	else leprintf("this is impossible...");
 473+
 474+	return s;
 475+}
 476+
 477+/* read first addr from s, return pointer to one past end of addr */
 478+static char *
 479+make_addr(Addr *addr, char *s)
 480+{
 481+	Rune r;
 482+	char *p = s + strlen(s);
 483+	size_t rlen = echarntorune(&r, s, p - s);
 484+
 485+	if (r == '$') {
 486+		addr->type = LAST;
 487+		s += rlen;
 488+	} else if (isdigitrune(r)) {
 489+		addr->type = LINE;
 490+		addr->u.lineno = stol(s, &s);
 491+	} else if (r == '/' || r == '\\') {
 492+		Rune delim;
 493+		if (r == '\\') {
 494+			s += rlen;
 495+			rlen = echarntorune(&r, s, p - s);
 496+		}
 497+		if (r == '\\')
 498+			leprintf("bad delimiter '\\'");
 499+		delim = r;
 500+		s += rlen;
 501+		rlen = echarntorune(&r, s, p - s);
 502+		if (r == delim) {
 503+			addr->type = LASTRE;
 504+			s += rlen;
 505+		} else {
 506+			addr->type = REGEX;
 507+			p = find_delim(s, delim, 1);
 508+			if (!*p)
 509+				leprintf("unclosed regex");
 510+			p -= escapes(s, p, delim, 0);
 511+			*p++ = '\0';
 512+			addr->u.re = emalloc(sizeof(*addr->u.re));
 513+			eregcomp(addr->u.re, s, gflags.E ? REG_EXTENDED : 0);
 514+			s = p;
 515+		}
 516+	} else {
 517+		addr->type = EVERY;
 518+	}
 519+
 520+	return s;
 521+}
 522+
 523+/* return pointer to first delim in s that is not escaped
 524+ * and if do_brackets is set, not in [] (note possible [::], [..], [==], inside [])
 525+ * return pointer to trailing nul byte if no delim found
 526+ *
 527+ * any escaped character that is not special is just itself (POSIX undefined)
 528+ * FIXME: pull out into some util thing, will be useful for ed as well
 529+ */
 530+static char *
 531+find_delim(char *s, Rune delim, int do_brackets)
 532+{
 533+	enum {
 534+		OUTSIDE         , /* not in brackets */
 535+		BRACKETS_OPENING, /* last char was first [ or last two were first [^ */
 536+		BRACKETS_INSIDE , /* inside [] */
 537+		INSIDE_OPENING  , /* inside [] and last char was [ */
 538+		CLASS_INSIDE    , /* inside class [::], or colating element [..] or [==], inside [] */
 539+		CLASS_CLOSING   , /* inside class [::], or colating element [..] or [==], and last character was the respective : . or = */
 540+	} state = OUTSIDE;
 541+
 542+	Rune r, c = 0; /* no c won't be used uninitialized, shutup -Wall */
 543+	size_t rlen;
 544+	int escape = 0;
 545+	char *end = s + strlen(s);
 546+
 547+	for (; *s; s += rlen) {
 548+		rlen = echarntorune(&r, s, end - s);
 549+
 550+		if      (state == BRACKETS_OPENING       &&  r == '^'  ) {                            continue; }
 551+		else if (state == BRACKETS_OPENING       &&  r == ']'  ) { state  = BRACKETS_INSIDE ; continue; }
 552+		else if (state == BRACKETS_OPENING                     ) { state  = BRACKETS_INSIDE ;           }
 553+
 554+		if      (state == CLASS_CLOSING          &&  r == ']'  ) { state  = BRACKETS_INSIDE ;           }
 555+		else if (state == CLASS_CLOSING                        ) { state  = CLASS_INSIDE    ;           }
 556+		else if (state == CLASS_INSIDE           &&  r ==  c   ) { state  = CLASS_CLOSING   ;           }
 557+		else if (state == INSIDE_OPENING         && (r == ':'  ||
 558+		                                             r == '.'  ||
 559+		                                             r == '=') ) { state  = CLASS_INSIDE    ; c = r;    }
 560+		else if (state == INSIDE_OPENING         &&  r == ']'  ) { state  = OUTSIDE         ;           }
 561+		else if (state == INSIDE_OPENING                       ) { state  = BRACKETS_INSIDE ;           }
 562+		else if (state == BRACKETS_INSIDE        &&  r == '['  ) { state  = INSIDE_OPENING  ;           }
 563+		else if (state == BRACKETS_INSIDE        &&  r == ']'  ) { state  = OUTSIDE         ;           }
 564+		else if (state == OUTSIDE                &&  escape    ) { escape = 0               ;           }
 565+		else if (state == OUTSIDE                &&  r == '\\' ) { escape = 1               ;           }
 566+		else if (state == OUTSIDE                &&  r == delim) return s;
 567+		else if (state == OUTSIDE && do_brackets &&  r == '['  ) { state  = BRACKETS_OPENING;           }
 568+	}
 569+	return s;
 570+}
 571+
 572+static char *
 573+chomp(char *s)
 574+{
 575+	return chompr(s, 0);
 576+}
 577+
 578+/* eat all leading whitespace and occurrences of rune */
 579+static char *
 580+chompr(char *s, Rune rune)
 581+{
 582+	Rune   r;
 583+	size_t rlen;
 584+	char  *end = s + strlen(s);
 585+
 586+	while (*s && (rlen = echarntorune(&r, s, end - s)) && (isspacerune(r) || r == rune))
 587+		s += rlen;
 588+	return s;
 589+}
 590+
 591+/* convert first nrunes Runes from UTF-8 string s in allocated Rune*
 592+ * NOTE: sequence must be valid UTF-8, check first */
 593+static Rune *
 594+strtorunes(char *s, size_t nrunes)
 595+{
 596+	Rune *rs, *rp;
 597+
 598+	rp = rs = ereallocarray(NULL, nrunes + 1, sizeof(*rs));
 599+
 600+	while (nrunes--)
 601+		s += chartorune(rp++, s);
 602+
 603+	*rp = '\0';
 604+	return rs;
 605+}
 606+
 607+static long
 608+stol(char *s, char **endp)
 609+{
 610+	long n;
 611+	errno = 0;
 612+	n = strtol(s, endp, 10);
 613+
 614+	if (errno)
 615+		leprintf("strtol:");
 616+	if (*endp == s)
 617+		leprintf("strtol: invalid number");
 618+
 619+	return n;
 620+}
 621+
 622+/* from beg to end replace "\\d" with "d" and "\\n" with "\n" (where d is delim)
 623+ * if delim is 'n' and n_newline is 0 then "\\n" is replaced with "n" (normal)
 624+ * if delim is 'n' and n_newline is 1 then "\\n" is replaced with "\n" (y command)
 625+ * if delim is 0 all escaped characters represent themselves (aci text)
 626+ * memmove rest of string (beyond end) into place
 627+ * return the number of converted escapes (backslashes removed)
 628+ * FIXME: this has had too many corner cases slapped on and is ugly. rewrite better
 629+ */
 630+static size_t
 631+escapes(char *beg, char *end, Rune delim, int n_newline)
 632+{
 633+	size_t num = 0;
 634+	char *src = beg, *dst = beg;
 635+
 636+	while (src < end) {
 637+		/* handle escaped backslash specially so we don't think the second
 638+		 * backslash is escaping something */
 639+		if (*src == '\\' && src[1] == '\\') {
 640+			*dst++ = *src++;
 641+			if (delim)
 642+				*dst++ = *src++;
 643+			else
 644+				src++;
 645+		} else if (*src == '\\' && !delim) {
 646+			src++;
 647+		} else if (*src == '\\' && src[1]) {
 648+			Rune r;
 649+			size_t rlen;
 650+			num++;
 651+			src++;
 652+			rlen = echarntorune(&r, src, end - src);
 653+
 654+			if (r == 'n' && delim == 'n') {
 655+				*src = n_newline ? '\n' : 'n'; /* src so we can still memmove() */
 656+			} else if (r == 'n') {
 657+				*src = '\n';
 658+			} else if (r != delim) {
 659+				*dst++ = '\\';
 660+				num--;
 661+			}
 662+
 663+			memmove(dst, src, rlen);
 664+			dst += rlen;
 665+			src += rlen;
 666+		} else {
 667+			*dst++ = *src++;
 668+		}
 669+	}
 670+	memmove(dst, src, strlen(src) + 1);
 671+	return num;
 672+}
 673+
 674+static size_t
 675+echarntorune(Rune *r, char *s, size_t n)
 676+{
 677+	size_t rlen = charntorune(r, s, n);
 678+	if (!rlen || *r == Runeerror)
 679+		leprintf("invalid UTF-8");
 680+	return rlen;
 681+}
 682+
 683+static void
 684+insert_labels(void)
 685+{
 686+	size_t i;
 687+	Cmd *from, *to;
 688+
 689+	while (branches.size) {
 690+		from = prog + (ptrdiff_t)pop(&branches);
 691+
 692+		if (!from->u.label) {/* no label branch to end of script */
 693+			from->u.jump = pc - 1;
 694+		} else {
 695+			for (i = 0; i < labels.size; i++) {
 696+				to = prog + (ptrdiff_t)labels.data[i];
 697+				if (!strcmp(from->u.label, to->u.label)) {
 698+					from->u.jump = to;
 699+					break;
 700+				}
 701+			}
 702+			if (i == labels.size)
 703+				leprintf("bad label");
 704+		}
 705+	}
 706+}
 707+
 708+/*
 709+ * Getargs / Freeargs
 710+ * Read argument from s, return pointer to one past last character of argument
 711+ */
 712+
 713+/* POSIX compliant
 714+ * i\
 715+ * foobar
 716+ *
 717+ * also allow the following non POSIX compliant
 718+ * i        # empty line
 719+ * ifoobar
 720+ * ifoobar\
 721+ * baz
 722+ *
 723+ * FIXME: GNU and busybox discard leading spaces
 724+ * i  foobar
 725+ * i foobar
 726+ * ifoobar
 727+ * are equivalent in GNU and busybox. We don't. Should we?
 728+ */
 729+static char *
 730+get_aci_arg(Cmd *c, char *s)
 731+{
 732+	c->u.acir.print = check_puts;
 733+	c->u.acir.str = (String){ NULL, 0 };
 734+
 735+	gflags.aci_cont = !!*s; /* no continue flag if empty string */
 736+
 737+	/* neither empty string nor POSIX compliant */
 738+	if (*s && !(*s == '\\' && !s[1]))
 739+		aci_append(c, s);
 740+
 741+	return s + strlen(s);
 742+}
 743+
 744+static void
 745+aci_append(Cmd *c, char *s)
 746+{
 747+	char *end = s + strlen(s), *p = end;
 748+
 749+	gflags.aci_cont = 0;
 750+	while (--p >= s && *p == '\\')
 751+		gflags.aci_cont = !gflags.aci_cont;
 752+
 753+	if (gflags.aci_cont)
 754+		*--end = '\n';
 755+
 756+	escapes(s, end, 0, 0);
 757+	stracat(&c->u.acir.str, s);
 758+}
 759+
 760+static void
 761+free_acir_arg(Cmd *c)
 762+{
 763+	free(c->u.acir.str.str);
 764+}
 765+
 766+/* POSIX dictates that label is rest of line, including semicolons, trailing
 767+ * whitespace, closing braces, etc. and can be limited to 8 bytes
 768+ *
 769+ * I allow a semicolon or closing brace to terminate a label name, it's not
 770+ * POSIX compliant, but it's useful and every sed version I've tried to date
 771+ * does the same.
 772+ *
 773+ * FIXME: POSIX dictates that leading whitespace is ignored but trailing
 774+ * whitespace is not. This is annoying and we should probably get rid of it.
 775+ */
 776+static char *
 777+get_bt_arg(Cmd *c, char *s)
 778+{
 779+	char *p = semicolon_arg(s = chomp(s));
 780+
 781+	if (p != s) {
 782+		c->u.label = estrndup(s, p - s);
 783+	} else {
 784+		c->u.label = NULL;
 785+	}
 786+
 787+	push(&branches, (void *)(c - prog));
 788+
 789+	return p;
 790+}
 791+
 792+/* POSIX dictates file name is rest of line including semicolons, trailing
 793+ * whitespace, closing braces, etc. and file name must be preceded by a space
 794+ *
 795+ * I allow a semicolon or closing brace to terminate a file name and don't
 796+ * enforce leading space.
 797+ *
 798+ * FIXME: decide whether trailing whitespace should be included and fix
 799+ * accordingly
 800+ */
 801+static char *
 802+get_r_arg(Cmd *c, char *s)
 803+{
 804+	char *p = semicolon_arg(s = chomp(s));
 805+
 806+	if (p == s)
 807+		leprintf("no file name");
 808+
 809+	c->u.acir.str.str = estrndup(s, p - s);
 810+	c->u.acir.print = write_file;
 811+
 812+	return p;
 813+}
 814+
 815+/* we allow "\\n" in replacement text to mean "\n" (undefined in POSIX)
 816+ *
 817+ * FIXME: allow other escapes in regex and replacement? if so change escapes()
 818+ */
 819+static char *
 820+get_s_arg(Cmd *c, char *s)
 821+{
 822+	Rune delim, r;
 823+	Cmd buf;
 824+	char *p;
 825+	int esc, lastre;
 826+
 827+	/* s/Find/Replace/Flags */
 828+
 829+	/* Find */
 830+	if (!gflags.s_cont) { /* NOT continuing from literal newline in replacement text */
 831+		lastre = 0;
 832+		c->u.s.repl = (String){ NULL, 0 };
 833+		c->u.s.occurrence = 1;
 834+		c->u.s.file = NULL;
 835+		c->u.s.p = 0;
 836+
 837+		if (!*s || *s == '\\')
 838+			leprintf("bad delimiter");
 839+
 840+		p = s + strlen(s);
 841+		s += echarntorune(&delim, s, p - s);
 842+		c->u.s.delim = delim;
 843+
 844+		echarntorune(&r, s, p - s);
 845+		if (r == delim) /* empty regex */
 846+			lastre = 1;
 847+
 848+		p = find_delim(s, delim, 1);
 849+		if (!*p)
 850+			leprintf("missing second delimiter");
 851+		p -= escapes(s, p, delim, 0);
 852+		*p = '\0';
 853+
 854+		if (lastre) {
 855+			c->u.s.re = NULL;
 856+		} else {
 857+			c->u.s.re = emalloc(sizeof(*c->u.s.re));
 858+			/* FIXME: different eregcomp that calls fatal */
 859+			eregcomp(c->u.s.re, s, gflags.E ? REG_EXTENDED : 0);
 860+		}
 861+		s = p + runelen(delim);
 862+	}
 863+
 864+	/* Replace */
 865+	delim = c->u.s.delim;
 866+
 867+	p = find_delim(s, delim, 0);
 868+	p -= escapes(s, p, delim, 0);
 869+	if (!*p) { /* no third delimiter */
 870+		/* FIXME: same backslash counting as aci_append() */
 871+		if (p[-1] != '\\')
 872+			leprintf("missing third delimiter or <backslash><newline>");
 873+		p[-1] = '\n';
 874+		gflags.s_cont = 1;
 875+	} else {
 876+		gflags.s_cont = 0;
 877+	}
 878+
 879+	/* check for bad references in replacement text */
 880+	*p = '\0';
 881+	for (esc = 0, p = s; *p; p++) {
 882+		if (esc) {
 883+			esc = 0;
 884+			if (isdigit(*p) && c->u.s.re && (size_t)(*p - '0') > c->u.s.re->re_nsub)
 885+				leprintf("back reference number greater than number of groups");
 886+		} else if (*p == '\\') {
 887+			esc = 1;
 888+		}
 889+	}
 890+	stracat(&c->u.s.repl, s);
 891+
 892+	if (gflags.s_cont)
 893+		return p;
 894+
 895+	s = p + runelen(delim);
 896+
 897+	/* Flags */
 898+	p = semicolon_arg(s = chomp(s));
 899+
 900+	/* FIXME: currently for simplicity take last of g or occurrence flags and
 901+	 *        ignore multiple p flags. need to fix that */
 902+	for (; s < p; s++) {
 903+		if (isdigit(*s)) {
 904+			c->u.s.occurrence = stol(s, &s);
 905+			s--; /* for loop will advance pointer */
 906+		} else {
 907+			switch (*s) {
 908+			case 'g': c->u.s.occurrence = 0; break;
 909+			case 'p': c->u.s.p = 1;          break;
 910+			case 'w':
 911+				/* must be last flag, take everything up to newline/semicolon
 912+				 * s == p after this */
 913+				s = get_w_arg(&buf, chomp(s+1));
 914+				c->u.s.file = buf.u.file;
 915+				break;
 916+			}
 917+		}
 918+	}
 919+	return p;
 920+}
 921+
 922+static void
 923+free_s_arg(Cmd *c)
 924+{
 925+	if (c->u.s.re)
 926+		regfree(c->u.s.re);
 927+	free(c->u.s.re);
 928+	free(c->u.s.repl.str);
 929+}
 930+
 931+/* see get_r_arg notes */
 932+static char *
 933+get_w_arg(Cmd *c, char *s)
 934+{
 935+	char *p = semicolon_arg(s = chomp(s));
 936+	Wfile *w, **wp;
 937+
 938+	if (p == s)
 939+		leprintf("no file name");
 940+
 941+	for (wp = (Wfile **)wfiles.data; (size_t)(wp - (Wfile **)wfiles.data) < wfiles.size; wp++) {
 942+		if (strlen((*wp)->path) == (size_t)(p - s) && !strncmp(s, (*wp)->path, p - s)) {
 943+			c->u.file = (*wp)->file;
 944+			return p;
 945+		}
 946+	}
 947+
 948+	w = emalloc(sizeof(*w));
 949+	w->path = estrndup(s, p - s);
 950+
 951+	if (!(w->file = fopen(w->path, "w")))
 952+		leprintf("fopen failed");
 953+
 954+	c->u.file = w->file;
 955+
 956+	push(&wfiles, w);
 957+	return p;
 958+}
 959+
 960+static char *
 961+get_y_arg(Cmd *c, char *s)
 962+{
 963+	Rune delim;
 964+	char *p = s + strlen(s);
 965+	size_t rlen = echarntorune(&delim, s, p - s);
 966+	size_t nrunes1, nrunes2;
 967+
 968+	c->u.y.set1 = c->u.y.set2 = NULL;
 969+
 970+	s += rlen;
 971+	p = find_delim(s, delim, 0);
 972+	p -= escapes(s, p, delim, 1);
 973+	nrunes1 = utfnlen(s, p - s);
 974+	c->u.y.set1 = strtorunes(s, nrunes1);
 975+
 976+	s = p + rlen;
 977+	p = find_delim(s, delim, 0);
 978+	p -= escapes(s, p, delim, 1);
 979+	nrunes2 = utfnlen(s, p - s);
 980+
 981+	if (nrunes1 != nrunes2)
 982+		leprintf("different set lengths");
 983+
 984+	c->u.y.set2 = strtorunes(s, utfnlen(s, p - s));
 985+
 986+	return p + rlen;
 987+}
 988+
 989+static void
 990+free_y_arg(Cmd *c)
 991+{
 992+	free(c->u.y.set1);
 993+	free(c->u.y.set2);
 994+}
 995+
 996+/* see get_bt_arg notes */
 997+static char *
 998+get_colon_arg(Cmd *c, char *s)
 999+{
1000+	char *p = semicolon_arg(s = chomp(s));
1001+
1002+	if (p == s)
1003+		leprintf("no label name");
1004+
1005+	c->u.label = estrndup(s, p - s);
1006+	push(&labels, (void *)(c - prog));
1007+	return p;
1008+}
1009+
1010+static char *
1011+get_lbrace_arg(Cmd *c, char *s)
1012+{
1013+	push(&braces, (void *)(c - prog));
1014+	return s;
1015+}
1016+
1017+static char *
1018+get_rbrace_arg(Cmd *c, char *s)
1019+{
1020+	Cmd *lbrace;
1021+
1022+	if (!braces.size)
1023+		leprintf("extra }");
1024+
1025+	lbrace = prog + (ptrdiff_t)pop(&braces);
1026+	lbrace->u.offset = c - prog;
1027+	return s;
1028+}
1029+
1030+/* s points to beginning of an argument that may be semicolon terminated
1031+ * return pointer to semicolon or nul byte after string
1032+ * or closing brace as to not force ; before }
1033+ * FIXME: decide whether or not to eat trailing whitespace for arguments that
1034+ *        we allow semicolon/brace termination that POSIX doesn't
1035+ *        b, r, t, w, :
1036+ *        POSIX says trailing whitespace is part of label name, file name, etc.
1037+ *        we should probably eat it
1038+ */
1039+static char *
1040+semicolon_arg(char *s)
1041+{
1042+	char *p = strpbrk(s, ";}");
1043+	if (!p)
1044+		p = s + strlen(s);
1045+	return p;
1046+}
1047+
1048+static void
1049+run(void)
1050+{
1051+	lineno = 0;
1052+	if (braces.size)
1053+		leprintf("extra {");
1054+
1055+	/* genbuf has already been initialized, patt will be in new_line
1056+	 * (or we'll halt) */
1057+	stracpy(&hold, "");
1058+
1059+	insert_labels();
1060+	next_file();
1061+	new_line();
1062+
1063+	for (pc = prog; !gflags.halt; pc++)
1064+		pc->fninfo->fn(pc);
1065+}
1066+
1067+/* return true if we are in range for c, set c->in_match appropriately */
1068+static int
1069+in_range(Cmd *c)
1070+{
1071+	if (match_addr(&c->range.beg)) {
1072+		if (c->range.naddr == 2) {
1073+			if (c->range.end.type == LINE && c->range.end.u.lineno <= lineno)
1074+				c->in_match = 0;
1075+			else
1076+				c->in_match = 1;
1077+		}
1078+		return !c->negate;
1079+	}
1080+	if (c->in_match && match_addr(&c->range.end)) {
1081+		c->in_match = 0;
1082+		return !c->negate;
1083+	}
1084+	return c->in_match ^ c->negate;
1085+}
1086+
1087+/* return true if addr matches current line */
1088+static int
1089+match_addr(Addr *a)
1090+{
1091+	switch (a->type) {
1092+	default:
1093+	case IGNORE: return 0;
1094+	case EVERY: return 1;
1095+	case LINE: return lineno == a->u.lineno;
1096+	case LAST:
1097+		while (is_eof(file) && !next_file())
1098+			;
1099+		return !file;
1100+	case REGEX:
1101+		lastre = a->u.re;
1102+		return !regexec(a->u.re, patt.str, 0, NULL, 0);
1103+	case LASTRE:
1104+		if (!lastre)
1105+			leprintf("no previous regex");
1106+		return !regexec(lastre, patt.str, 0, NULL, 0);
1107+	}
1108+}
1109+
1110+/* move to next input file
1111+ * stdin if first call and no files
1112+ * return 0 for success and 1 for no more files
1113+ */
1114+static int
1115+next_file(void)
1116+{
1117+	static unsigned char first = 1;
1118+
1119+	if (file == stdin)
1120+		clearerr(file);
1121+	else if (file)
1122+		fshut(file, "<file>");
1123+	/* given no files, default to stdin */
1124+	file = first && !*files ? stdin : NULL;
1125+	first = 0;
1126+
1127+	while (!file && *files) {
1128+		if (!strcmp(*files, "-")) {
1129+			file = stdin;
1130+		} else if (!(file = fopen(*files, "r"))) {
1131+			/* warn this file didn't open, but move on to next */
1132+			weprintf("fopen %s:", *files);
1133+			ret = 1;
1134+		}
1135+		files++;
1136+	}
1137+
1138+	return !file;
1139+}
1140+
1141+/* test if stream is at EOF */
1142+static int
1143+is_eof(FILE *f)
1144+{
1145+	int c;
1146+
1147+	if (!f || feof(f))
1148+		return 1;
1149+
1150+	c = fgetc(f);
1151+	if (c == EOF && ferror(f))
1152+		eprintf("fgetc:");
1153+	if (c != EOF && ungetc(c, f) == EOF)
1154+		eprintf("ungetc EOF\n");
1155+
1156+	return c == EOF;
1157+}
1158+
1159+/* perform writes that were scheduled
1160+ * for aci this is check_puts(string, stdout)
1161+ * for r this is write_file(path, stdout)
1162+ */
1163+static void
1164+do_writes(void)
1165+{
1166+	Cmd *c;
1167+	size_t i;
1168+
1169+	for (i = 0; i < writes.size; i++) {
1170+		c = writes.data[i];
1171+		c->u.acir.print(c->u.acir.str.str, stdout);
1172+	}
1173+	writes.size = 0;
1174+}
1175+
1176+/* used for r's u.acir.print()
1177+ * FIXME: something like util's concat() would be better
1178+ */
1179+static void
1180+write_file(char *path, FILE *out)
1181+{
1182+	FILE *in = fopen(path, "r");
1183+	if (!in) /* no file is treated as empty file */
1184+		return;
1185+
1186+	while (read_line(in, &genbuf) != EOF)
1187+		check_puts(genbuf.str, out);
1188+
1189+	fshut(in, path);
1190+}
1191+
1192+static void
1193+check_puts(char *s, FILE *f)
1194+{
1195+	if (s && fputs(s, f) == EOF)
1196+		eprintf("fputs:");
1197+	if (fputs("\n", f) == EOF)
1198+		eprintf("fputs:");
1199+}
1200+
1201+/* iterate from beg to end updating ranges so we don't miss any commands
1202+ * e.g. sed -n '1d;1,3p' should still print lines 2 and 3
1203+ */
1204+static void
1205+update_ranges(Cmd *beg, Cmd *end)
1206+{
1207+	while (beg < end)
1208+		in_range(beg++);
1209+}
1210+
1211+/*
1212+ * Sed functions
1213+ */
1214+static void
1215+cmd_a(Cmd *c)
1216+{
1217+	if (in_range(c))
1218+		push(&writes, c);
1219+}
1220+
1221+static void
1222+cmd_b(Cmd *c)
1223+{
1224+	if (!in_range(c))
1225+		return;
1226+
1227+	/* if we jump backwards update to end, otherwise update to destination */
1228+	update_ranges(c + 1, c->u.jump > c ? c->u.jump : prog + pcap);
1229+	pc = c->u.jump;
1230+}
1231+
1232+static void
1233+cmd_c(Cmd *c)
1234+{
1235+	if (!in_range(c))
1236+		return;
1237+
1238+	/* write the text on the last line of the match */
1239+	if (!c->in_match)
1240+		check_puts(c->u.acir.str.str, stdout);
1241+	/* otherwise start the next cycle without printing pattern space
1242+	 * effectively deleting the text */
1243+	new_next();
1244+}
1245+
1246+static void
1247+cmd_d(Cmd *c)
1248+{
1249+	if (!in_range(c))
1250+		return;
1251+
1252+	new_next();
1253+}
1254+
1255+static void
1256+cmd_D(Cmd *c)
1257+{
1258+	char *p;
1259+
1260+	if (!in_range(c))
1261+		return;
1262+
1263+	if ((p = strchr(patt.str, '\n'))) {
1264+		p++;
1265+		memmove(patt.str, p, strlen(p) + 1);
1266+		old_next();
1267+	} else {
1268+		new_next();
1269+	}
1270+}
1271+
1272+static void
1273+cmd_g(Cmd *c)
1274+{
1275+	if (in_range(c))
1276+		stracpy(&patt, hold.str);
1277+}
1278+
1279+static void
1280+cmd_G(Cmd *c)
1281+{
1282+	if (!in_range(c))
1283+		return;
1284+
1285+	stracat(&patt, "\n");
1286+	stracat(&patt, hold.str);
1287+}
1288+
1289+static void
1290+cmd_h(Cmd *c)
1291+{
1292+	if (in_range(c))
1293+		stracpy(&hold, patt.str);
1294+}
1295+
1296+static void
1297+cmd_H(Cmd *c)
1298+{
1299+	if (!in_range(c))
1300+		return;
1301+
1302+	stracat(&hold, "\n");
1303+	stracat(&hold, patt.str);
1304+}
1305+
1306+static void
1307+cmd_i(Cmd *c)
1308+{
1309+	if (in_range(c))
1310+		check_puts(c->u.acir.str.str, stdout);
1311+}
1312+
1313+/* I think it makes sense to print invalid UTF-8 sequences in octal to satisfy
1314+ * the "visually unambiguous form" sed(1p)
1315+ */
1316+static void
1317+cmd_l(Cmd *c)
1318+{
1319+	Rune   r;
1320+	char  *p, *end;
1321+	size_t rlen;
1322+
1323+	char *escapes[] = { /* FIXME: 7 entries and search instead of 127 */
1324+		['\\'] = "\\\\", ['\a'] = "\\a", ['\b'] = "\\b",
1325+		['\f'] = "\\f" , ['\r'] = "\\r", ['\t'] = "\\t",
1326+		['\v'] = "\\v" , [0x7f] = NULL, /* fill out the table */
1327+	};
1328+
1329+	if (!in_range(c))
1330+		return;
1331+
1332+	/* FIXME: line wrapping. sed(1p) says "length at which folding occurs is
1333+	 * unspecified, but should be appropraite for the output device"
1334+	 * just wrap at 80 Runes?
1335+	 */
1336+	for (p = patt.str, end = p + strlen(p); p < end; p += rlen) {
1337+		if (isascii(*p) && escapes[(unsigned int)*p]) {
1338+			fputs(escapes[(unsigned int)*p], stdout);
1339+			rlen = 1;
1340+		} else if (!(rlen = charntorune(&r, p, end - p))) {
1341+			/* ran out of chars, print the bytes of the short sequence */
1342+			for (; p < end; p++)
1343+				printf("\\%03hho", (unsigned char)*p);
1344+			break;
1345+		} else if (r == Runeerror) {
1346+			for (; rlen; rlen--, p++)
1347+				printf("\\%03hho", (unsigned char)*p);
1348+		} else {
1349+			while (fwrite(p, rlen, 1, stdout) < 1 && errno == EINTR)
1350+				;
1351+			if (ferror(stdout))
1352+				eprintf("fwrite:");
1353+		}
1354+	}
1355+	check_puts("$", stdout);
1356+}
1357+
1358+static void
1359+cmd_n(Cmd *c)
1360+{
1361+	if (!in_range(c))
1362+		return;
1363+
1364+	if (!gflags.n)
1365+		check_puts(patt.str, stdout);
1366+	do_writes();
1367+	new_line();
1368+}
1369+
1370+static void
1371+cmd_N(Cmd *c)
1372+{
1373+	if (!in_range(c))
1374+		return;
1375+	do_writes();
1376+	app_line();
1377+}
1378+
1379+static void
1380+cmd_p(Cmd *c)
1381+{
1382+	if (in_range(c))
1383+		check_puts(patt.str, stdout);
1384+}
1385+
1386+static void
1387+cmd_P(Cmd *c)
1388+{
1389+	char *p;
1390+
1391+	if (!in_range(c))
1392+		return;
1393+
1394+	if ((p = strchr(patt.str, '\n')))
1395+		*p = '\0';
1396+
1397+	check_puts(patt.str, stdout);
1398+
1399+	if (p)
1400+		*p = '\n';
1401+}
1402+
1403+static void
1404+cmd_q(Cmd *c)
1405+{
1406+	if (!in_range(c))
1407+		return;
1408+
1409+	if (!gflags.n)
1410+		check_puts(patt.str, stdout);
1411+	do_writes();
1412+	gflags.halt = 1;
1413+}
1414+
1415+static void
1416+cmd_r(Cmd *c)
1417+{
1418+	if (in_range(c))
1419+		push(&writes, c);
1420+}
1421+
1422+static void
1423+cmd_s(Cmd *c)
1424+{
1425+	String tmp;
1426+	Rune r;
1427+	size_t plen, rlen, len;
1428+	char *p, *s, *end;
1429+	unsigned int matches = 0, last_empty = 1, qflag = 0, cflags = 0;
1430+	regex_t *re;
1431+	regmatch_t *rm, *pmatch = NULL;
1432+
1433+	if (!in_range(c))
1434+		return;
1435+
1436+	if (!c->u.s.re && !lastre)
1437+		leprintf("no previous regex");
1438+
1439+	re = c->u.s.re ? c->u.s.re : lastre;
1440+	lastre = re;
1441+
1442+	plen = re->re_nsub + 1;
1443+	pmatch = ereallocarray(NULL, plen, sizeof(regmatch_t));
1444+
1445+	*genbuf.str = '\0';
1446+	s = patt.str;
1447+
1448+	while (!qflag && !regexec(re, s, plen, pmatch, cflags)) {
1449+		cflags = REG_NOTBOL; /* match against beginning of line first time, but not again */
1450+		if (!*s) /* match against empty string first time, but not again */
1451+			qflag = 1;
1452+
1453+		/* don't substitute if last match was not empty but this one is.
1454+		 * s_a*_._g
1455+		 * foobar -> .f.o.o.b.r.
1456+		 */
1457+		if ((last_empty || pmatch[0].rm_eo) &&
1458+		    (++matches == c->u.s.occurrence || !c->u.s.occurrence)) {
1459+			/* copy over everything before the match */
1460+			strnacat(&genbuf, s, pmatch[0].rm_so);
1461+
1462+			/* copy over replacement text, taking into account &, backreferences, and \ escapes */
1463+			for (p = c->u.s.repl.str, len = strcspn(p, "\\&"); *p; len = strcspn(++p, "\\&")) {
1464+				strnacat(&genbuf, p, len);
1465+				p += len;
1466+				switch (*p) {
1467+				default: leprintf("this shouldn't be possible");
1468+				case '\0':
1469+					/* we're at the end, back up one so the ++p will put us on
1470+					 * the null byte to break out of the loop */
1471+					--p;
1472+					break;
1473+				case '&':
1474+					strnacat(&genbuf, s + pmatch[0].rm_so, pmatch[0].rm_eo - pmatch[0].rm_so);
1475+					break;
1476+				case '\\':
1477+					if (isdigit(*++p)) { /* backreference */
1478+						/* only need to check here if using lastre, otherwise we checked when building */
1479+						if (!c->u.s.re && (size_t)(*p - '0') > re->re_nsub)
1480+							leprintf("back reference number greater than number of groups");
1481+						rm = &pmatch[*p - '0'];
1482+						strnacat(&genbuf, s + rm->rm_so, rm->rm_eo - rm->rm_so);
1483+					} else { /* character after backslash taken literally (well one byte, but it works) */
1484+						strnacat(&genbuf, p, 1);
1485+					}
1486+					break;
1487+				}
1488+			}
1489+		} else {
1490+			/* not replacing, copy over everything up to and including the match */
1491+			strnacat(&genbuf, s, pmatch[0].rm_eo);
1492+		}
1493+
1494+		if (!pmatch[0].rm_eo) { /* empty match, advance one rune and add it to output */
1495+			end = s + strlen(s);
1496+			rlen = charntorune(&r, s, end - s);
1497+
1498+			if (!rlen) { /* ran out of bytes, copy short sequence */
1499+				stracat(&genbuf, s);
1500+				s = end;
1501+			} else { /* copy whether or not it's a good rune */
1502+				strnacat(&genbuf, s, rlen);
1503+				s += rlen;
1504+			}
1505+		}
1506+		last_empty = !pmatch[0].rm_eo;
1507+		s += pmatch[0].rm_eo;
1508+	}
1509+	free(pmatch);
1510+
1511+	if (!(matches && matches >= c->u.s.occurrence)) /* no replacement */
1512+		return;
1513+
1514+	gflags.s = 1;
1515+
1516+	stracat(&genbuf, s);
1517+
1518+	tmp    = patt;
1519+	patt   = genbuf;
1520+	genbuf = tmp;
1521+
1522+	if (c->u.s.p)
1523+		check_puts(patt.str, stdout);
1524+	if (c->u.s.file)
1525+		check_puts(patt.str, c->u.s.file);
1526+}
1527+
1528+static void
1529+cmd_t(Cmd *c)
1530+{
1531+	if (!in_range(c) || !gflags.s)
1532+		return;
1533+
1534+	/* if we jump backwards update to end, otherwise update to destination */
1535+	update_ranges(c + 1, c->u.jump > c ? c->u.jump : prog + pcap);
1536+	pc = c->u.jump;
1537+	gflags.s = 0;
1538+}
1539+
1540+static void
1541+cmd_w(Cmd *c)
1542+{
1543+	if (in_range(c))
1544+		check_puts(patt.str, c->u.file);
1545+}
1546+
1547+static void
1548+cmd_x(Cmd *c)
1549+{
1550+	String tmp;
1551+
1552+	if (!in_range(c))
1553+		return;
1554+
1555+	tmp  = patt;
1556+	patt = hold;
1557+	hold = tmp;
1558+}
1559+
1560+static void
1561+cmd_y(Cmd *c)
1562+{
1563+	String tmp;
1564+	Rune r, *rp;
1565+	size_t n, rlen;
1566+	char *s, *end, buf[UTFmax];
1567+
1568+	if (!in_range(c))
1569+		return;
1570+
1571+	*genbuf.str = '\0';
1572+	for (s = patt.str, end = s + strlen(s); *s; s += rlen) {
1573+		if (!(rlen = charntorune(&r, s, end - s))) { /* ran out of chars, copy rest */
1574+			stracat(&genbuf, s);
1575+			break;
1576+		} else if (r == Runeerror) { /* bad UTF-8 sequence, copy bytes */
1577+			strnacat(&genbuf, s, rlen);
1578+		} else {
1579+			for (rp = c->u.y.set1; *rp; rp++)
1580+				if (*rp == r)
1581+					break;
1582+			if (*rp) { /* found r in set1, replace with Rune from set2 */
1583+				n = runetochar(buf, c->u.y.set2 + (rp - c->u.y.set1));
1584+				strnacat(&genbuf, buf, n);
1585+			} else {
1586+				strnacat(&genbuf, s, rlen);
1587+			}
1588+		}
1589+	}
1590+	tmp    = patt;
1591+	patt   = genbuf;
1592+	genbuf = tmp;
1593+}
1594+
1595+static void
1596+cmd_colon(Cmd *c)
1597+{
1598+}
1599+
1600+static void
1601+cmd_equal(Cmd *c)
1602+{
1603+	if (in_range(c))
1604+		printf("%zu\n", lineno);
1605+}
1606+
1607+static void
1608+cmd_lbrace(Cmd *c)
1609+{
1610+	Cmd *jump;
1611+
1612+	if (in_range(c))
1613+		return;
1614+
1615+	/* update ranges on all commands we skip */
1616+	jump = prog + c->u.offset;
1617+	update_ranges(c + 1, jump);
1618+	pc = jump;
1619+}
1620+
1621+static void
1622+cmd_rbrace(Cmd *c)
1623+{
1624+}
1625+
1626+/* not actually a sed function, but acts like one, put in last spot of script */
1627+static void
1628+cmd_last(Cmd *c)
1629+{
1630+	if (!gflags.n)
1631+		check_puts(patt.str, stdout);
1632+	do_writes();
1633+	new_next();
1634+}
1635+
1636+/*
1637+ * Actions
1638+ */
1639+
1640+/* read new line, continue current cycle */
1641+static void
1642+new_line(void)
1643+{
1644+	while (read_line(file, &patt) == EOF) {
1645+		if (next_file()) {
1646+			gflags.halt = 1;
1647+			return;
1648+		}
1649+	}
1650+	gflags.s = 0;
1651+	lineno++;
1652+}
1653+
1654+/* append new line, continue current cycle
1655+ * FIXME: used for N, POSIX specifies do not print pattern space when out of
1656+ *        input, but GNU does so busybox does as well. Currently we don't.
1657+ *        Should we?
1658+ */
1659+static void
1660+app_line(void)
1661+{
1662+	while (read_line(file, &genbuf) == EOF) {
1663+		if (next_file()) {
1664+			gflags.halt = 1;
1665+			return;
1666+		}
1667+	}
1668+
1669+	stracat(&patt, "\n");
1670+	stracat(&patt, genbuf.str);
1671+	gflags.s = 0;
1672+	lineno++;
1673+}
1674+
1675+/* read new line, start new cycle */
1676+static void
1677+new_next(void)
1678+{
1679+	*patt.str = '\0';
1680+	update_ranges(pc + 1, prog + pcap);
1681+	new_line();
1682+	pc = prog - 1;
1683+}
1684+
1685+/* keep old pattern space, start new cycle */
1686+static void
1687+old_next(void)
1688+{
1689+	update_ranges(pc + 1, prog + pcap);
1690+	pc = prog - 1;
1691+}
1692+
1693+int
1694+main(int argc, char *argv[])
1695+{
1696+	char *arg;
1697+	int script = 0;
1698+
1699+	ARGBEGIN {
1700+	case 'n':
1701+		gflags.n = 1;
1702+		break;
1703+	case 'r':
1704+	case 'E':
1705+		gflags.E = 1;
1706+		break;
1707+	case 'e':
1708+		arg = EARGF(usage());
1709+		compile(arg, 0);
1710+		script = 1;
1711+		break;
1712+	case 'f':
1713+		arg = EARGF(usage());
1714+		compile(arg, 1);
1715+		script = 1;
1716+		break;
1717+	default : usage();
1718+	} ARGEND
1719+
1720+	/* no script to run */
1721+	if (!script && !argc)
1722+		usage();
1723+
1724+	/* no script yet, next argument is script */
1725+	if (!script)
1726+		compile(*argv++, 0);
1727+
1728+	/* shrink/grow memory to fit and add our last instruction */
1729+	resize((void **)&prog, &pcap, sizeof(*prog), pc - prog + 1, NULL);
1730+	pc = prog + pcap - 1;
1731+	pc->fninfo = &(Fninfo){ cmd_last, NULL, NULL, 0 };
1732+
1733+	files = argv;
1734+	run();
1735+
1736+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
1737+
1738+	return ret;
1739+}
+30, -0
 1@@ -0,0 +1,30 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <unistd.h>
 4+
 5+#include "util.h"
 6+
 7+static void
 8+usage(void)
 9+{
10+	eprintf("usage: %s num\n", argv0);
11+}
12+
13+int
14+main(int argc, char *argv[])
15+{
16+	unsigned seconds;
17+
18+	ARGBEGIN {
19+	default:
20+		usage();
21+	} ARGEND
22+
23+	if (argc != 1)
24+		usage();
25+
26+	seconds = estrtonum(argv[0], 0, UINT_MAX);
27+	while ((seconds = sleep(seconds)) > 0)
28+		;
29+
30+	return 0;
31+}
+438, -0
  1@@ -0,0 +1,438 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <ctype.h>
  4+#include <stdio.h>
  5+#include <stdlib.h>
  6+#include <string.h>
  7+
  8+#include "queue.h"
  9+#include "text.h"
 10+#include "utf.h"
 11+#include "util.h"
 12+
 13+struct keydef {
 14+	int start_column;
 15+	int end_column;
 16+	int start_char;
 17+	int end_char;
 18+	int flags;
 19+	TAILQ_ENTRY(keydef) entry;
 20+};
 21+
 22+struct column {
 23+	struct line line;
 24+	size_t cap;
 25+};
 26+
 27+enum {
 28+	MOD_N      = 1 << 0,
 29+	MOD_STARTB = 1 << 1,
 30+	MOD_ENDB   = 1 << 2,
 31+	MOD_R      = 1 << 3,
 32+	MOD_D      = 1 << 4,
 33+	MOD_F      = 1 << 5,
 34+	MOD_I      = 1 << 6,
 35+};
 36+
 37+static TAILQ_HEAD(kdhead, keydef) kdhead = TAILQ_HEAD_INITIALIZER(kdhead);
 38+
 39+static int Cflag = 0, cflag = 0, uflag = 0;
 40+static char *fieldsep = NULL;
 41+static size_t fieldseplen = 0;
 42+static struct column col1, col2;
 43+
 44+static void
 45+skipblank(struct line *a)
 46+{
 47+	while (a->len && (*(a->data) == ' ' || *(a->data) == '\t')) {
 48+		a->data++;
 49+		a->len--;
 50+	}
 51+}
 52+
 53+static void
 54+skipnonblank(struct line *a)
 55+{
 56+	while (a->len && (*(a->data) != '\n' && *(a->data) != ' ' &&
 57+	                  *(a->data) != '\t')) {
 58+		a->data++;
 59+		a->len--;
 60+	}
 61+}
 62+
 63+static void
 64+skipcolumn(struct line *a, int skip_to_next_col)
 65+{
 66+	char *s;
 67+
 68+	if (fieldsep) {
 69+		if ((s = memmem(a->data, a->len, fieldsep, fieldseplen))) {
 70+			if (skip_to_next_col)
 71+				s += fieldseplen;
 72+			a->len -= s - a->data;
 73+			a->data = s;
 74+		} else {
 75+			a->data += a->len - 1;
 76+			a->len = 1;
 77+		}
 78+	} else {
 79+		skipblank(a);
 80+		skipnonblank(a);
 81+	}
 82+}
 83+
 84+static void
 85+columns(struct line *line, const struct keydef *kd, struct column *col)
 86+{
 87+	Rune r;
 88+	struct line start, end;
 89+	size_t utflen, rlen;
 90+	int i;
 91+
 92+	start.data = line->data;
 93+	start.len = line->len;
 94+	for (i = 1; i < kd->start_column; i++)
 95+		skipcolumn(&start, 1);
 96+	if (kd->flags & MOD_STARTB)
 97+		skipblank(&start);
 98+	for (utflen = 0; start.len > 1 && utflen < kd->start_char - 1;) {
 99+		rlen = chartorune(&r, start.data);
100+		start.data += rlen;
101+		start.len -= rlen;
102+		utflen++;
103+	}
104+
105+	end.data = line->data;
106+	end.len = line->len;
107+	if (kd->end_column) {
108+		for (i = 1; i < kd->end_column; i++)
109+			skipcolumn(&end, 1);
110+		if (kd->flags & MOD_ENDB)
111+			skipblank(&end);
112+		if (kd->end_char) {
113+			for (utflen = 0; end.len > 1 && utflen < kd->end_char;) {
114+				rlen = chartorune(&r, end.data);
115+				end.data += rlen;
116+				end.len -= rlen;
117+				utflen++;
118+			}
119+		} else {
120+			skipcolumn(&end, 0);
121+		}
122+	} else {
123+		end.data += end.len - 1;
124+		end.len = 1;
125+	}
126+	col->line.len = MAX(0, end.data - start.data);
127+	if (!(col->line.data) || col->cap < col->line.len + 1) {
128+		free(col->line.data);
129+		col->line.data = emalloc(col->line.len + 1);
130+		col->cap = col->line.len + 1;
131+	}
132+	memcpy(col->line.data, start.data, col->line.len);
133+	col->line.data[col->line.len] = '\0';
134+}
135+
136+static int
137+skipmodcmp(struct line *a, struct line *b, int flags)
138+{
139+	Rune r1, r2;
140+	size_t offa = 0, offb = 0;
141+
142+	do {
143+		offa += chartorune(&r1, a->data + offa);
144+		offb += chartorune(&r2, b->data + offb);
145+
146+		if (flags & MOD_D && flags & MOD_I) {
147+			while (offa < a->len && ((!isblankrune(r1) &&
148+			       !isalnumrune(r1)) || (!isprintrune(r1))))
149+				offa += chartorune(&r1, a->data + offa);
150+			while (offb < b->len && ((!isblankrune(r2) &&
151+			       !isalnumrune(r2)) || (!isprintrune(r2))))
152+				offb += chartorune(&r2, b->data + offb);
153+		}
154+		else if (flags & MOD_D) {
155+			while (offa < a->len && !isblankrune(r1) &&
156+			       !isalnumrune(r1))
157+				offa += chartorune(&r1, a->data + offa);
158+			while (offb < b->len && !isblankrune(r2) &&
159+			       !isalnumrune(r2))
160+				offb += chartorune(&r2, b->data + offb);
161+		}
162+		else if (flags & MOD_I) {
163+			while (offa < a->len && !isprintrune(r1))
164+				offa += chartorune(&r1, a->data + offa);
165+			while (offb < b->len && !isprintrune(r2))
166+				offb += chartorune(&r2, b->data + offb);
167+		}
168+		if (flags & MOD_F) {
169+			r1 = toupperrune(r1);
170+			r2 = toupperrune(r2);
171+		}
172+	} while (r1 && r1 == r2);
173+
174+	return r1 - r2;
175+}
176+
177+static int
178+slinecmp(struct line *a, struct line *b)
179+{
180+	int res = 0;
181+	double x, y;
182+	struct keydef *kd;
183+
184+	TAILQ_FOREACH(kd, &kdhead, entry) {
185+		columns(a, kd, &col1);
186+		columns(b, kd, &col2);
187+
188+		/* if -u is given, don't use default key definition
189+		 * unless it is the only one */
190+		if (uflag && kd == TAILQ_LAST(&kdhead, kdhead) &&
191+		    TAILQ_LAST(&kdhead, kdhead) != TAILQ_FIRST(&kdhead)) {
192+			res = 0;
193+		} else if (kd->flags & MOD_N) {
194+			x = strtod(col1.line.data, NULL);
195+			y = strtod(col2.line.data, NULL);
196+			res = (x < y) ? -1 : (x > y);
197+		} else if (kd->flags & (MOD_D | MOD_F | MOD_I)) {
198+			res = skipmodcmp(&col1.line, &col2.line, kd->flags);
199+		} else {
200+			res = linecmp(&col1.line, &col2.line);
201+		}
202+
203+		if (kd->flags & MOD_R)
204+			res = -res;
205+		if (res)
206+			break;
207+	}
208+
209+	return res;
210+}
211+
212+static int
213+check(FILE *fp, const char *fname)
214+{
215+	static struct line prev, cur, tmp;
216+	static size_t prevsize, cursize, tmpsize;
217+	ssize_t len;
218+
219+	if (!prev.data) {
220+		if ((len = getline(&prev.data, &prevsize, fp)) < 0)
221+			eprintf("getline:");
222+		prev.len = len;
223+	}
224+	while ((len = getline(&cur.data, &cursize, fp)) > 0) {
225+		cur.len = len;
226+		if (uflag > slinecmp(&cur, &prev)) {
227+			if (!Cflag) {
228+				weprintf("disorder %s: ", fname);
229+				fwrite(cur.data, 1, cur.len, stderr);
230+			}
231+			return 1;
232+		}
233+		tmp = cur;
234+		tmpsize = cursize;
235+		cur = prev;
236+		cursize = prevsize;
237+		prev = tmp;
238+		prevsize = tmpsize;
239+	}
240+
241+	return 0;
242+}
243+
244+static int
245+parse_flags(char **s, int *flags, int bflag)
246+{
247+	while (isalpha((int)**s)) {
248+		switch (*((*s)++)) {
249+		case 'b':
250+			*flags |= bflag;
251+			break;
252+		case 'd':
253+			*flags |= MOD_D;
254+			break;
255+		case 'f':
256+			*flags |= MOD_F;
257+			break;
258+		case 'i':
259+			*flags |= MOD_I;
260+			break;
261+		case 'n':
262+			*flags |= MOD_N;
263+			break;
264+		case 'r':
265+			*flags |= MOD_R;
266+			break;
267+		default:
268+			return -1;
269+		}
270+	}
271+
272+	return 0;
273+}
274+
275+static void
276+addkeydef(char *kdstr, int flags)
277+{
278+	struct keydef *kd;
279+
280+	kd = enmalloc(2, sizeof(*kd));
281+
282+	/* parse key definition kdstr with format
283+	 * start_column[.start_char][flags][,end_column[.end_char][flags]]
284+	 */
285+	kd->start_column = 1;
286+	kd->start_char = 1;
287+	kd->end_column = 0; /* 0 means end of line */
288+	kd->end_char = 0;   /* 0 means end of column */
289+	kd->flags = flags;
290+
291+	if ((kd->start_column = strtol(kdstr, &kdstr, 10)) < 1)
292+		enprintf(2, "invalid start column in key definition\n");
293+
294+	if (*kdstr == '.') {
295+		if ((kd->start_char = strtol(kdstr + 1, &kdstr, 10)) < 1)
296+			enprintf(2, "invalid start character in key "
297+			         "definition\n");
298+	}
299+	if (parse_flags(&kdstr, &kd->flags, MOD_STARTB) < 0)
300+		enprintf(2, "invalid start flags in key definition\n");
301+
302+	if (*kdstr == ',') {
303+		if ((kd->end_column = strtol(kdstr + 1, &kdstr, 10)) < 0)
304+			enprintf(2, "invalid end column in key definition\n");
305+		if (*kdstr == '.') {
306+			if ((kd->end_char = strtol(kdstr + 1, &kdstr, 10)) < 0)
307+				enprintf(2, "invalid end character in key "
308+				         "definition\n");
309+		}
310+		if (parse_flags(&kdstr, &kd->flags, MOD_ENDB) < 0)
311+			enprintf(2, "invalid end flags in key definition\n");
312+	}
313+
314+	if (*kdstr != '\0')
315+		enprintf(2, "invalid key definition\n");
316+
317+	TAILQ_INSERT_TAIL(&kdhead, kd, entry);
318+}
319+
320+static void
321+usage(void)
322+{
323+	enprintf(2, "usage: %s [-Cbcdfimnru] [-o outfile] [-t delim] "
324+	         "[-k def]... [file ...]\n", argv0);
325+}
326+
327+int
328+main(int argc, char *argv[])
329+{
330+	FILE *fp, *ofp = stdout;
331+	struct linebuf linebuf = EMPTY_LINEBUF;
332+	size_t i;
333+	int global_flags = 0, ret = 0;
334+	char *outfile = NULL;
335+
336+	ARGBEGIN {
337+	case 'C':
338+		Cflag = 1;
339+		break;
340+	case 'b':
341+		global_flags |= MOD_STARTB | MOD_ENDB;
342+		break;
343+	case 'c':
344+		cflag = 1;
345+		break;
346+	case 'd':
347+		global_flags |= MOD_D;
348+		break;
349+	case 'f':
350+		global_flags |= MOD_F;
351+		break;
352+	case 'i':
353+		global_flags |= MOD_I;
354+		break;
355+	case 'k':
356+		addkeydef(EARGF(usage()), global_flags);
357+		break;
358+	case 'm':
359+		/* more or less for free, but for performance-reasons,
360+		 * we should keep this flag in mind and maybe some later
361+		 * day implement it properly so we don't run out of memory
362+		 * while merging large sorted files.
363+		 */
364+		break;
365+	case 'n':
366+		global_flags |= MOD_N;
367+		break;
368+	case 'o':
369+		outfile = EARGF(usage());
370+		break;
371+	case 'r':
372+		global_flags |= MOD_R;
373+		break;
374+	case 't':
375+		fieldsep = EARGF(usage());
376+		if (!*fieldsep)
377+			eprintf("empty delimiter\n");
378+		fieldseplen = unescape(fieldsep);
379+		break;
380+	case 'u':
381+		uflag = 1;
382+		break;
383+	default:
384+		usage();
385+	} ARGEND
386+
387+	/* -b shall only apply to custom key definitions */
388+	if (TAILQ_EMPTY(&kdhead) && global_flags)
389+		addkeydef("1", global_flags & ~(MOD_STARTB | MOD_ENDB));
390+	if (TAILQ_EMPTY(&kdhead) || (!Cflag && !cflag))
391+		addkeydef("1", global_flags & MOD_R);
392+
393+	if (!argc) {
394+		if (Cflag || cflag) {
395+			if (check(stdin, "<stdin>") && !ret)
396+				ret = 1;
397+		} else {
398+			getlines(stdin, &linebuf);
399+		}
400+	} else for (; *argv; argc--, argv++) {
401+		if (!strcmp(*argv, "-")) {
402+			*argv = "<stdin>";
403+			fp = stdin;
404+		} else if (!(fp = fopen(*argv, "r"))) {
405+			enprintf(2, "fopen %s:", *argv);
406+			continue;
407+		}
408+		if (Cflag || cflag) {
409+			if (check(fp, *argv) && !ret)
410+				ret = 1;
411+		} else {
412+			getlines(fp, &linebuf);
413+		}
414+		if (fp != stdin && fshut(fp, *argv))
415+			ret = 2;
416+	}
417+
418+	if (!Cflag && !cflag) {
419+		if (outfile && !(ofp = fopen(outfile, "w")))
420+			eprintf("fopen %s:", outfile);
421+
422+		qsort(linebuf.lines, linebuf.nlines, sizeof(*linebuf.lines),
423+				(int (*)(const void *, const void *))slinecmp);
424+
425+		for (i = 0; i < linebuf.nlines; i++) {
426+			if (!uflag || i == 0 ||
427+			    slinecmp(&linebuf.lines[i], &linebuf.lines[i - 1])) {
428+				fwrite(linebuf.lines[i].data, 1,
429+				       linebuf.lines[i].len, ofp);
430+			}
431+		}
432+	}
433+
434+	if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>") |
435+	    fshut(stderr, "<stderr>"))
436+		ret = 2;
437+
438+	return ret;
439+}
+111, -0
  1@@ -0,0 +1,111 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <ctype.h>
  4+#include <stdint.h>
  5+#include <stdio.h>
  6+#include <stdlib.h>
  7+#include <string.h>
  8+
  9+#include "util.h"
 10+
 11+static int base = 26, start = 'a';
 12+
 13+static int
 14+itostr(char *str, int x, int n)
 15+{
 16+	str[n] = '\0';
 17+	while (n-- > 0) {
 18+		str[n] = start + (x % base);
 19+		x /= base;
 20+	}
 21+
 22+	return x ? -1 : 0;
 23+}
 24+
 25+static FILE *
 26+nextfile(FILE *f, char *buf, int plen, int slen)
 27+{
 28+	static int filecount = 0;
 29+
 30+	if (f)
 31+		fshut(f, "<file>");
 32+	if (itostr(buf + plen, filecount++, slen) < 0)
 33+		return NULL;
 34+
 35+	if (!(f = fopen(buf, "w")))
 36+		eprintf("'%s':", buf);
 37+
 38+	return f;
 39+}
 40+
 41+static void
 42+usage(void)
 43+{
 44+	eprintf("usage: %s [-a num] [-b num[k|m|g] | -l num] [-d] "
 45+	        "[file [prefix]]\n", argv0);
 46+}
 47+
 48+int
 49+main(int argc, char *argv[])
 50+{
 51+	FILE *in = stdin, *out = NULL;
 52+	off_t size = 1000, n;
 53+	int ret = 0, ch, plen, slen = 2, always = 0;
 54+	char name[NAME_MAX + 1], *prefix = "x", *file = NULL;
 55+
 56+	ARGBEGIN {
 57+	case 'a':
 58+		slen = estrtonum(EARGF(usage()), 0, INT_MAX);
 59+		break;
 60+	case 'b':
 61+		always = 1;
 62+		if ((size = parseoffset(EARGF(usage()))) < 0)
 63+			return 1;
 64+		if (!size)
 65+			eprintf("size needs to be positive\n");
 66+		break;
 67+	case 'd':
 68+		base = 10;
 69+		start = '0';
 70+		break;
 71+	case 'l':
 72+		always = 0;
 73+		size = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SSIZE_MAX));
 74+		break;
 75+	default:
 76+		usage();
 77+	} ARGEND
 78+
 79+	if (*argv)
 80+		file = *argv++;
 81+	if (*argv)
 82+		prefix = *argv++;
 83+	if (*argv)
 84+		usage();
 85+
 86+	plen = strlen(prefix);
 87+	if (plen + slen > NAME_MAX)
 88+		eprintf("names cannot exceed %d bytes\n", NAME_MAX);
 89+	estrlcpy(name, prefix, sizeof(name));
 90+
 91+	if (file && strcmp(file, "-")) {
 92+		if (!(in = fopen(file, "r")))
 93+			eprintf("fopen %s:", file);
 94+	}
 95+
 96+	n = 0;
 97+	while ((ch = getc(in)) != EOF) {
 98+		if (!out || n >= size) {
 99+			if (!(out = nextfile(out, name, plen, slen)))
100+				eprintf("fopen: %s:", name);
101+			n = 0;
102+		}
103+		n += (always || ch == '\n');
104+		putc(ch, out);
105+	}
106+
107+	ret |= (in != stdin) && fshut(in, "<infile>");
108+	ret |= out && (out != stdout) && fshut(out, "<outfile>");
109+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
110+
111+	return ret;
112+}
+229, -0
  1@@ -0,0 +1,229 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+
  5+#include <fcntl.h>
  6+#include <unistd.h>
  7+#include <stdint.h>
  8+#include <stdio.h>
  9+#include <stdlib.h>
 10+#include <string.h>
 11+#include <unistd.h>
 12+
 13+#include "utf.h"
 14+#include "util.h"
 15+
 16+static char mode = 'n';
 17+
 18+static int
 19+dropinit(int fd, const char *fname, size_t count)
 20+{
 21+	Rune r;
 22+	char buf[BUFSIZ], *p;
 23+	ssize_t n;
 24+	int nr;
 25+
 26+	if (count < 2)
 27+		goto copy;
 28+	count--;  /* numbering starts at 1 */
 29+	while (count && (n = read(fd, buf, sizeof(buf))) > 0) {
 30+		switch (mode) {
 31+		case 'n':  /* lines */
 32+			for (p = buf; count && n > 0; p++, n--) {
 33+				if (*p == '\n')
 34+					count--;
 35+			}
 36+			break;
 37+		case 'c':  /* bytes */
 38+			if (count > n) {
 39+				count -= n;
 40+			} else {
 41+				p = buf + count;
 42+				n -= count;
 43+				count = 0;
 44+			}
 45+			break;
 46+		case 'm':  /* runes */
 47+			for (p = buf; count && n > 0; p += nr, n -= nr, count--) {
 48+				nr = charntorune(&r, p, n);
 49+				if (!nr) {
 50+					/* we don't have a full rune, move
 51+					 * remaining data to beginning and read
 52+					 * again */
 53+					memmove(buf, p, n);
 54+					break;
 55+				}
 56+			}
 57+			break;
 58+		}
 59+	}
 60+	if (count) {
 61+		if (n < 0)
 62+			weprintf("read %s:", fname);
 63+		if (n <= 0)
 64+			return n;
 65+	}
 66+
 67+	/* write the rest of the buffer */
 68+	if (writeall(1, p, n) < 0)
 69+		eprintf("write:");
 70+copy:
 71+	switch (concat(fd, fname, 1, "<stdout>")) {
 72+	case -1:  /* read error */
 73+		return -1;
 74+	case -2:  /* write error */
 75+		exit(1);
 76+	default:
 77+		return 0;
 78+	}
 79+}
 80+
 81+static int
 82+taketail(int fd, const char *fname, size_t count)
 83+{
 84+	static char *buf = NULL;
 85+	static size_t size = 0;
 86+	char *p;
 87+	size_t len = 0, left;
 88+	ssize_t n;
 89+
 90+	if (!count)
 91+		return 0;
 92+	for (;;) {
 93+		if (len + BUFSIZ > size) {
 94+			/* make sure we have at least BUFSIZ to read */
 95+			size += 2 * BUFSIZ;
 96+			buf = erealloc(buf, size);
 97+		}
 98+		n = read(fd, buf + len, size - len);
 99+		if (n < 0) {
100+			weprintf("read %s:", fname);
101+			return -1;
102+		}
103+		if (n == 0)
104+			break;
105+		len += n;
106+		switch (mode) {
107+		case 'n':  /* lines */
108+			/* ignore the last character; if it is a newline, it
109+			 * ends the last line */
110+			for (p = buf + len - 2, left = count; p >= buf; p--) {
111+				if (*p != '\n')
112+					continue;
113+				left--;
114+				if (!left) {
115+					p++;
116+					break;
117+				}
118+			}
119+			break;
120+		case 'c':  /* bytes */
121+			p = count < len ? buf + len - count : buf;
122+			break;
123+		case 'm':  /* runes */
124+			for (p = buf + len - 1, left = count; p >= buf; p--) {
125+				/* skip utf-8 continuation bytes */
126+				if (UTF8_POINT(*p))
127+					continue;
128+				left--;
129+				if (!left)
130+					break;
131+			}
132+			break;
133+		}
134+		if (p > buf) {
135+			len -= p - buf;
136+			memmove(buf, p, len);
137+		}
138+	}
139+	if (writeall(1, buf, len) < 0)
140+		eprintf("write:");
141+	return 0;
142+}
143+
144+static void
145+usage(void)
146+{
147+	eprintf("usage: %s [-f] [-c num | -m num | -n num | -num] [file ...]\n", argv0);
148+}
149+
150+int
151+main(int argc, char *argv[])
152+{
153+	struct stat st1, st2;
154+	int fd;
155+	size_t n = 10;
156+	int fflag = 0, ret = 0, newline = 0, many = 0;
157+	char *numstr;
158+	int (*tail)(int, const char *, size_t) = taketail;
159+
160+	ARGBEGIN {
161+	case 'f':
162+		fflag = 1;
163+		break;
164+	case 'c':
165+	case 'm':
166+	case 'n':
167+		mode = ARGC();
168+		numstr = EARGF(usage());
169+		n = MIN(llabs(estrtonum(numstr, LLONG_MIN + 1,
170+		                        MIN(LLONG_MAX, SIZE_MAX))), SIZE_MAX);
171+		if (strchr(numstr, '+'))
172+			tail = dropinit;
173+		break;
174+	ARGNUM:
175+		n = ARGNUMF();
176+		break;
177+	default:
178+		usage();
179+	} ARGEND
180+
181+	if (!argc) {
182+		if (tail(0, "<stdin>", n) < 0)
183+			ret = 1;
184+	} else {
185+		if ((many = argc > 1) && fflag)
186+			usage();
187+		for (newline = 0; *argv; argc--, argv++) {
188+			if (!strcmp(*argv, "-")) {
189+				*argv = "<stdin>";
190+				fd = 0;
191+			} else if ((fd = open(*argv, O_RDONLY)) < 0) {
192+				weprintf("open %s:", *argv);
193+				ret = 1;
194+				continue;
195+			}
196+			if (many)
197+				printf("%s==> %s <==\n", newline ? "\n" : "", *argv);
198+			if (fstat(fd, &st1) < 0)
199+				eprintf("fstat %s:", *argv);
200+			if (!(S_ISFIFO(st1.st_mode) || S_ISREG(st1.st_mode)))
201+				fflag = 0;
202+			newline = 1;
203+			if (tail(fd, *argv, n) < 0) {
204+				ret = 1;
205+				fflag = 0;
206+			}
207+
208+			if (!fflag) {
209+				if (fd != 0)
210+					close(fd);
211+				continue;
212+			}
213+			for (;;) {
214+				if (concat(fd, *argv, 1, "<stdout>") < 0)
215+					exit(1);
216+				if (fstat(fd, &st2) < 0)
217+					eprintf("fstat %s:", *argv);
218+				if (st2.st_size < st1.st_size) {
219+					fprintf(stderr, "%s: file truncated\n", *argv);
220+					if (lseek(fd, SEEK_SET, 0) < 0)
221+						eprintf("lseek:");
222+				}
223+				st1 = st2;
224+				sleep(1);
225+			}
226+		}
227+	}
228+
229+	return ret;
230+}
+60, -0
 1@@ -0,0 +1,60 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <fcntl.h>
 4+#include <signal.h>
 5+#include <unistd.h>
 6+
 7+#include "util.h"
 8+
 9+static void
10+usage(void)
11+{
12+	eprintf("usage: %s [-ai] [file ...]\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+	int *fds = NULL;
19+	size_t i, nfds;
20+	ssize_t n;
21+	int ret = 0, aflag = O_TRUNC, iflag = 0;
22+	char buf[BUFSIZ];
23+
24+	ARGBEGIN {
25+	case 'a':
26+		aflag = O_APPEND;
27+		break;
28+	case 'i':
29+		iflag = 1;
30+		break;
31+	default:
32+		usage();
33+	} ARGEND
34+
35+	if (iflag && signal(SIGINT, SIG_IGN) == SIG_ERR)
36+		eprintf("signal:");
37+	nfds = argc + 1;
38+	fds = ecalloc(nfds, sizeof(*fds));
39+
40+	for (i = 0; i < argc; i++) {
41+		if ((fds[i] = open(argv[i], O_WRONLY|O_CREAT|aflag, 0666)) < 0) {
42+			weprintf("open %s:", argv[i]);
43+			ret = 1;
44+		}
45+	}
46+	fds[i] = 1;
47+
48+	while ((n = read(0, buf, sizeof(buf))) > 0) {
49+		for (i = 0; i < nfds; i++) {
50+			if (fds[i] >= 0 && writeall(fds[i], buf, n) < 0) {
51+				weprintf("write %s:", (i != argc) ? argv[i] : "<stdout>");
52+				fds[i] = -1;
53+				ret = 1;
54+			}
55+		}
56+	}
57+	if (n < 0)
58+		eprintf("read <stdin>:");
59+
60+	return ret;
61+}
+247, -0
  1@@ -0,0 +1,247 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+
  5+#include <ctype.h>
  6+#include <fcntl.h>
  7+#include <string.h>
  8+#include <unistd.h>
  9+
 10+#include "util.h"
 11+
 12+static int
 13+intcmp(char *a, char *b)
 14+{
 15+	char *s;
 16+	int asign = *a == '-' ? -1 : 1;
 17+	int bsign = *b == '-' ? -1 : 1;
 18+
 19+	if (*a == '-' || *a == '+') a += 1;
 20+	if (*b == '-' || *b == '+') b += 1;
 21+
 22+	if (!*a || !*b)
 23+		goto noint;
 24+	for (s = a; *s; s++)
 25+		if (!isdigit(*s))
 26+			goto noint;
 27+	for (s = b; *s; s++)
 28+		if (!isdigit(*s))
 29+			goto noint;
 30+
 31+	while (*a == '0') a++;
 32+	while (*b == '0') b++;
 33+	asign *= !!*a;
 34+	bsign *= !!*b;
 35+
 36+	if (asign != bsign)
 37+		return asign < bsign ? -1 : 1;
 38+	else if (strlen(a) != strlen(b))
 39+		return asign * (strlen(a) < strlen(b) ? -1 : 1);
 40+	else
 41+		return asign * strcmp(a, b);
 42+
 43+noint:
 44+	enprintf(2, "expected integer operands\n");
 45+
 46+	return 0; /* not reached */
 47+}
 48+
 49+static int
 50+mtimecmp(struct stat *buf1, struct stat *buf2)
 51+{
 52+	if (buf1->st_mtime < buf2->st_mtime) return -1;
 53+	if (buf1->st_mtime > buf2->st_mtime) return +1;
 54+#ifdef st_mtime
 55+	if (buf1->st_mtim.tv_nsec < buf2->st_mtim.tv_nsec) return -1;
 56+	if (buf1->st_mtim.tv_nsec > buf2->st_mtim.tv_nsec) return +1;
 57+#endif
 58+	return 0;
 59+}
 60+
 61+static int unary_b(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISBLK  (buf.st_mode); }
 62+static int unary_c(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISCHR  (buf.st_mode); }
 63+static int unary_d(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISDIR  (buf.st_mode); }
 64+static int unary_f(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISREG  (buf.st_mode); }
 65+static int unary_g(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISGID & buf.st_mode ; }
 66+static int unary_h(char *s) { struct stat buf; if (lstat(s, &buf)) return 0; return S_ISLNK  (buf.st_mode); }
 67+static int unary_k(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISVTX & buf.st_mode ; }
 68+static int unary_p(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISFIFO (buf.st_mode); }
 69+static int unary_S(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISSOCK (buf.st_mode); }
 70+static int unary_s(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return           buf.st_size ; }
 71+static int unary_u(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISUID & buf.st_mode ; }
 72+
 73+static int unary_n(char *s) { return  *s; }
 74+static int unary_z(char *s) { return !*s; }
 75+
 76+static int unary_e(char *s) { return !faccessat(AT_FDCWD, s, F_OK, AT_EACCESS); }
 77+static int unary_r(char *s) { return !faccessat(AT_FDCWD, s, R_OK, AT_EACCESS); }
 78+static int unary_w(char *s) { return !faccessat(AT_FDCWD, s, W_OK, AT_EACCESS); }
 79+static int unary_x(char *s) { return !faccessat(AT_FDCWD, s, X_OK, AT_EACCESS); }
 80+
 81+static int unary_t(char *s) { int fd = enstrtonum(2, s, 0, INT_MAX); return isatty(fd); }
 82+
 83+static int binary_se(char *s1, char *s2) { return !strcmp(s1, s2); }
 84+static int binary_sn(char *s1, char *s2) { return  strcmp(s1, s2); }
 85+
 86+static int binary_eq(char *s1, char *s2) { return intcmp(s1, s2) == 0; }
 87+static int binary_ne(char *s1, char *s2) { return intcmp(s1, s2) != 0; }
 88+static int binary_gt(char *s1, char *s2) { return intcmp(s1, s2) >  0; }
 89+static int binary_ge(char *s1, char *s2) { return intcmp(s1, s2) >= 0; }
 90+static int binary_lt(char *s1, char *s2) { return intcmp(s1, s2) <  0; }
 91+static int binary_le(char *s1, char *s2) { return intcmp(s1, s2) <= 0; }
 92+
 93+static int
 94+binary_ef(char *s1, char *s2)
 95+{
 96+	struct stat buf1, buf2;
 97+	if (stat(s1, &buf1) || stat(s2, &buf2)) return 0;
 98+	return buf1.st_dev == buf2.st_dev && buf1.st_ino == buf2.st_ino;
 99+}
100+
101+static int
102+binary_ot(char *s1, char *s2)
103+{
104+	struct stat buf1, buf2;
105+	if (stat(s1, &buf1) || stat(s2, &buf2)) return 0;
106+	return mtimecmp(&buf1, &buf2) < 0;
107+}
108+
109+static int
110+binary_nt(char *s1, char *s2)
111+{
112+	struct stat buf1, buf2;
113+	if (stat(s1, &buf1) || stat(s2, &buf2)) return 0;
114+	return mtimecmp(&buf1, &buf2) > 0;
115+}
116+
117+struct test {
118+	char *name;
119+	union {
120+		int (*u)(char *);
121+		int (*b)(char *, char *);
122+	} func;
123+};
124+
125+static struct test unary[] = {
126+	{ "-b", { .u = unary_b } },
127+	{ "-c", { .u = unary_c } },
128+	{ "-d", { .u = unary_d } },
129+	{ "-e", { .u = unary_e } },
130+	{ "-f", { .u = unary_f } },
131+	{ "-g", { .u = unary_g } },
132+	{ "-h", { .u = unary_h } },
133+	{ "-k", { .u = unary_k } },
134+	{ "-L", { .u = unary_h } },
135+	{ "-n", { .u = unary_n } },
136+	{ "-p", { .u = unary_p } },
137+	{ "-r", { .u = unary_r } },
138+	{ "-S", { .u = unary_S } },
139+	{ "-s", { .u = unary_s } },
140+	{ "-t", { .u = unary_t } },
141+	{ "-u", { .u = unary_u } },
142+	{ "-w", { .u = unary_w } },
143+	{ "-x", { .u = unary_x } },
144+	{ "-z", { .u = unary_z } },
145+
146+	{ NULL },
147+};
148+
149+static struct test binary[] = {
150+	{ "="  , { .b = binary_se } },
151+	{ "!=" , { .b = binary_sn } },
152+	{ "-eq", { .b = binary_eq } },
153+	{ "-ne", { .b = binary_ne } },
154+	{ "-gt", { .b = binary_gt } },
155+	{ "-ge", { .b = binary_ge } },
156+	{ "-lt", { .b = binary_lt } },
157+	{ "-le", { .b = binary_le } },
158+	{ "-ef", { .b = binary_ef } },
159+	{ "-ot", { .b = binary_ot } },
160+	{ "-nt", { .b = binary_nt } },
161+
162+	{ NULL },
163+};
164+
165+static struct test *
166+find_test(struct test *tests, char *name)
167+{
168+	struct test *t;
169+
170+	for (t = tests; t->name; t++)
171+		if (!strcmp(t->name, name))
172+			return t;
173+
174+	return NULL;
175+}
176+
177+static int
178+noarg(char *argv[])
179+{
180+	return 0;
181+}
182+
183+static int
184+onearg(char *argv[])
185+{
186+	return unary_n(argv[0]);
187+}
188+
189+static int
190+twoarg(char *argv[])
191+{
192+	struct test *t;
193+
194+	if (!strcmp(argv[0], "!"))
195+		return !onearg(argv + 1);
196+
197+	if ((t = find_test(unary, *argv)))
198+		return t->func.u(argv[1]);
199+
200+	enprintf(2, "bad unary test %s\n", argv[0]);
201+
202+	return 0; /* not reached */
203+}
204+
205+static int
206+threearg(char *argv[])
207+{
208+	struct test *t = find_test(binary, argv[1]);
209+
210+	if (t)
211+		return t->func.b(argv[0], argv[2]);
212+
213+	if (!strcmp(argv[0], "!"))
214+		return !twoarg(argv + 1);
215+
216+	enprintf(2, "bad binary test %s\n", argv[1]);
217+
218+	return 0; /* not reached */
219+}
220+
221+static int
222+fourarg(char *argv[])
223+{
224+	if (!strcmp(argv[0], "!"))
225+		return !threearg(argv + 1);
226+
227+	enprintf(2, "too many arguments\n");
228+
229+	return 0; /* not reached */
230+}
231+
232+int
233+main(int argc, char *argv[])
234+{
235+	int (*narg[])(char *[]) = { noarg, onearg, twoarg, threearg, fourarg };
236+	size_t len;
237+
238+	argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
239+
240+	len = argv0 ? strlen(argv0) : 0;
241+	if (len && argv0[--len] == '[' && (!len || argv0[--len] == '/') && strcmp(argv[--argc], "]"))
242+		enprintf(2, "no matching ]\n");
243+
244+	if (argc > 4)
245+		enprintf(2, "too many arguments\n");
246+
247+	return !narg[argc](argv);
248+}
+73, -0
 1@@ -0,0 +1,73 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/times.h>
 4+#include <sys/wait.h>
 5+
 6+#include <errno.h>
 7+#include <stdio.h>
 8+#include <unistd.h>
 9+
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+	eprintf("usage: %s [-p] cmd [arg ...]\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+	pid_t pid;
22+	struct tms tms; /* user and sys times */
23+	clock_t r0, r1; /* real time */
24+	long ticks;     /* per second */
25+	int status, savederrno, ret = 0;
26+
27+	ARGBEGIN {
28+	case 'p':
29+		break;
30+	default:
31+		usage();
32+	} ARGEND
33+
34+	if (!argc)
35+		usage();
36+
37+	if ((ticks = sysconf(_SC_CLK_TCK)) <= 0)
38+		eprintf("sysconf _SC_CLK_TCK:");
39+
40+	if ((r0 = times(&tms)) == (clock_t)-1)
41+		eprintf("times:");
42+
43+	switch ((pid = fork())) {
44+	case -1:
45+		eprintf("fork:");
46+	case 0:
47+		execvp(argv[0], argv);
48+		savederrno = errno;
49+		weprintf("execvp %s:", argv[0]);
50+		_exit(126 + (savederrno == ENOENT));
51+	default:
52+		break;
53+	}
54+	waitpid(pid, &status, 0);
55+
56+	if ((r1 = times(&tms)) == (clock_t)-1)
57+		eprintf("times:");
58+
59+	if (WIFSIGNALED(status)) {
60+		fprintf(stderr, "Command terminated by signal %d\n",
61+		        WTERMSIG(status));
62+		ret = 128 + WTERMSIG(status);
63+	}
64+
65+	fprintf(stderr, "real %f\nuser %f\nsys %f\n",
66+	        (r1 - r0)      / (double)ticks,
67+	        tms.tms_cutime / (double)ticks,
68+	        tms.tms_cstime / (double)ticks);
69+
70+	if (WIFEXITED(status))
71+		ret = WEXITSTATUS(status);
72+
73+	return ret;
74+}
+159, -0
  1@@ -0,0 +1,159 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+
  5+#include <errno.h>
  6+#include <fcntl.h>
  7+#include <stdlib.h>
  8+#include <string.h>
  9+#include <time.h>
 10+#include <unistd.h>
 11+
 12+#include "util.h"
 13+
 14+static int aflag;
 15+static int cflag;
 16+static int mflag;
 17+static struct timespec times[2] = {{.tv_nsec = UTIME_NOW}};
 18+
 19+static void
 20+touch(const char *file)
 21+{
 22+	int fd, ret;
 23+
 24+	if (utimensat(AT_FDCWD, file, times, 0) == 0)
 25+		return;
 26+	if (errno != ENOENT)
 27+		eprintf("utimensat %s:", file);
 28+	if (cflag)
 29+		return;
 30+	if ((fd = open(file, O_WRONLY | O_CREAT, 0666)) < 0)
 31+		eprintf("open %s:", file);
 32+	ret = futimens(fd, times);
 33+	close(fd);
 34+	if (ret < 0)
 35+		eprintf("futimens %s:", file);
 36+}
 37+
 38+static time_t
 39+parsetime(char *str)
 40+{
 41+	time_t now;
 42+	struct tm *cur, t = { 0 };
 43+	int zulu = 0;
 44+	char *format;
 45+	size_t len = strlen(str);
 46+
 47+	if ((now = time(NULL)) == -1)
 48+		eprintf("time:");
 49+	if (!(cur = localtime(&now)))
 50+		eprintf("localtime:");
 51+	t.tm_isdst = -1;
 52+
 53+	switch (len) {
 54+	/* -t flag argument */
 55+	case 8:
 56+		t.tm_year = cur->tm_year;
 57+		format = "%m%d%H%M";
 58+		break;
 59+	case 10:
 60+		format = "%y%m%d%H%M";
 61+		break;
 62+	case 11:
 63+		t.tm_year = cur->tm_year;
 64+		format = "%m%d%H%M.%S";
 65+		break;
 66+	case 12:
 67+		format = "%Y%m%d%H%M";
 68+		break;
 69+	case 13:
 70+		format = "%y%m%d%H%M.%S";
 71+		break;
 72+	case 15:
 73+		format = "%Y%m%d%H%M.%S";
 74+		break;
 75+	/* -d flag argument */
 76+	case 19:
 77+		format = "%Y-%m-%dT%H:%M:%S";
 78+		break;
 79+	case 20:
 80+		/* only Zulu-timezone supported */
 81+		if (str[19] != 'Z')
 82+			eprintf("Invalid time zone\n");
 83+		str[19] = 0;
 84+		zulu = 1;
 85+		format = "%Y-%m-%dT%H:%M:%S";
 86+		break;
 87+	default:
 88+		eprintf("Invalid date format length\n", str);
 89+	}
 90+
 91+	if (!strptime(str, format, &t))
 92+		eprintf("strptime %s: Invalid date format\n", str);
 93+	if (zulu) {
 94+		t.tm_hour += t.tm_gmtoff / 60;
 95+		t.tm_gmtoff = 0;
 96+		t.tm_zone = "Z";
 97+	}
 98+
 99+	return mktime(&t);
100+}
101+
102+static void
103+usage(void)
104+{
105+	eprintf("usage: %s [-acm] [-d time | -r ref_file | -t time | -T time] "
106+	        "file ...\n", argv0);
107+}
108+
109+int
110+main(int argc, char *argv[])
111+{
112+	struct stat st;
113+	char *ref = NULL;
114+
115+	ARGBEGIN {
116+	case 'a':
117+		aflag = 1;
118+		break;
119+	case 'c':
120+		cflag = 1;
121+		break;
122+	case 'd':
123+	case 't':
124+		times[0].tv_sec = parsetime(EARGF(usage()));
125+		times[0].tv_nsec = 0;
126+		break;
127+	case 'm':
128+		mflag = 1;
129+		break;
130+	case 'r':
131+		ref = EARGF(usage());
132+		if (stat(ref, &st) < 0)
133+			eprintf("stat '%s':", ref);
134+		times[0] = st.st_atim;
135+		times[1] = st.st_mtim;
136+		break;
137+	case 'T':
138+		times[0].tv_sec = estrtonum(EARGF(usage()), 0, LLONG_MAX);
139+		times[0].tv_nsec = 0;
140+		break;
141+	default:
142+		usage();
143+	} ARGEND
144+
145+	if (!argc)
146+		usage();
147+	if (!aflag && !mflag)
148+		aflag = mflag = 1;
149+	if (!ref)
150+		times[1] = times[0];
151+	if (!aflag)
152+		times[0].tv_nsec = UTIME_OMIT;
153+	if (!mflag)
154+		times[1].tv_nsec = UTIME_OMIT;
155+
156+	for (; *argv; argc--, argv++)
157+		touch(*argv);
158+
159+	return 0;
160+}
+318, -0
  1@@ -0,0 +1,318 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <stdlib.h>
  4+
  5+#include "utf.h"
  6+#include "util.h"
  7+
  8+static int cflag = 0;
  9+static int dflag = 0;
 10+static int sflag = 0;
 11+
 12+struct range {
 13+	Rune   start;
 14+	Rune   end;
 15+	size_t quant;
 16+};
 17+
 18+static struct {
 19+	char    *name;
 20+	int    (*check)(Rune);
 21+} classes[] = {
 22+	{ "alnum",  isalnumrune  },
 23+	{ "alpha",  isalpharune  },
 24+	{ "blank",  isblankrune  },
 25+	{ "cntrl",  iscntrlrune  },
 26+	{ "digit",  isdigitrune  },
 27+	{ "graph",  isgraphrune  },
 28+	{ "lower",  islowerrune  },
 29+	{ "print",  isprintrune  },
 30+	{ "punct",  ispunctrune  },
 31+	{ "space",  isspacerune  },
 32+	{ "upper",  isupperrune  },
 33+	{ "xdigit", isxdigitrune },
 34+};
 35+
 36+#define ISLOWERBIT 		   1U << 6
 37+#define ISUPPERBIT 		   1U << 10
 38+
 39+static struct   range *set1 = NULL;
 40+static size_t   set1ranges  = 0;
 41+static unsigned set1checks  = 0;
 42+static struct   range *set2 = NULL;
 43+static size_t   set2ranges  = 0;
 44+static unsigned set2checks  = 0;
 45+
 46+static int
 47+check(Rune rune, unsigned checks)
 48+{
 49+	size_t i;
 50+
 51+	for (i = 0; checks && i < LEN(classes); i++, checks >>= 1)
 52+		if (checks & 1 && classes[i].check(rune))
 53+			return 1;
 54+
 55+	return 0;
 56+}
 57+
 58+static size_t
 59+rangelen(struct range r)
 60+{
 61+	return (r.end - r.start + 1) * r.quant;
 62+}
 63+
 64+static size_t
 65+setlen(struct range *set, size_t setranges)
 66+{
 67+	size_t len = 0, i;
 68+
 69+	for (i = 0; i < setranges; i++)
 70+		len += rangelen(set[i]);
 71+
 72+	return len;
 73+}
 74+
 75+static int
 76+rstrmatch(Rune *r, char *s, size_t n)
 77+{
 78+	size_t i;
 79+
 80+	for (i = 0; i < n; i++)
 81+		if (r[i] != s[i])
 82+			return 0;
 83+	return 1;
 84+}
 85+
 86+static size_t
 87+makeset(char *str, struct range **set, unsigned *checks)
 88+{
 89+	Rune  *rstr;
 90+	size_t len, i, j, m, n;
 91+	size_t q, setranges = 0;
 92+	int    factor, base;
 93+
 94+	/* rstr defines at most len ranges */
 95+	unescape(str);
 96+	rstr = ereallocarray(NULL, utflen(str) + 1, sizeof(*rstr));
 97+	len = utftorunestr(str, rstr);
 98+	*set = ereallocarray(NULL, len, sizeof(**set));
 99+
100+	for (i = 0; i < len; i++) {
101+		if (rstr[i] == '[') {
102+			j = i;
103+nextbrack:
104+			if (j >= len)
105+				goto literal;
106+			for (m = j; m < len; m++)
107+				if (rstr[m] == ']') {
108+					j = m;
109+					break;
110+				}
111+			if (j == i)
112+				goto literal;
113+
114+			/* CLASSES [=EQUIV=] (skip) */
115+			if (j - i > 3 && rstr[i + 1] == '=' && rstr[m - 1] == '=') {
116+				if (j - i != 4)
117+					goto literal;
118+				(*set)[setranges].start = rstr[i + 2];
119+				(*set)[setranges].end   = rstr[i + 2];
120+				(*set)[setranges].quant = 1;
121+				setranges++;
122+				i = j;
123+				continue;
124+			}
125+
126+			/* CLASSES [:CLASS:] */
127+			if (j - i > 3 && rstr[i + 1] == ':' && rstr[m - 1] == ':') {
128+				for (n = 0; n < LEN(classes); n++) {
129+					if (rstrmatch(rstr + i + 2, classes[n].name, j - i - 3)) {
130+						*checks |= 1 << n;
131+						i = j;
132+						break;
133+					}
134+				}
135+				if (n < LEN(classes))
136+					continue;
137+				eprintf("Invalid character class.\n");
138+			}
139+
140+			/* REPEAT  [_*n] (only allowed in set2) */
141+			if (j - i > 2 && rstr[i + 2] == '*') {
142+				/* check if right side of '*' is a number */
143+				q = 0;
144+				factor = 1;
145+				base = (rstr[i + 3] == '0') ? 8 : 10;
146+				for (n = j - 1; n > i + 2; n--) {
147+					if (rstr[n] < '0' || rstr[n] > '9') {
148+						n = 0;
149+						break;
150+					}
151+					q += (rstr[n] - '0') * factor;
152+					factor *= base;
153+				}
154+				if (n == 0) {
155+					j = m + 1;
156+					goto nextbrack;
157+				}
158+				(*set)[setranges].start = rstr[i + 1];
159+				(*set)[setranges].end   = rstr[i + 1];
160+				(*set)[setranges].quant = q ? q : setlen(set1, MAX(set1ranges, 1));
161+				setranges++;
162+				i = j;
163+				continue;
164+			}
165+
166+			j = m + 1;
167+			goto nextbrack;
168+		}
169+literal:
170+		/* RANGES [_-__-_], _-__-_ */
171+		/* LITERALS _______ */
172+		(*set)[setranges].start = rstr[i];
173+
174+		if (i < len - 2 && rstr[i + 1] == '-' && rstr[i + 2] >= rstr[i])
175+			i += 2;
176+		(*set)[setranges].end = rstr[i];
177+		(*set)[setranges].quant = 1;
178+		setranges++;
179+	}
180+
181+	free(rstr);
182+	return setranges;
183+}
184+
185+static void
186+usage(void)
187+{
188+	eprintf("usage: %s [-cCds] set1 [set2]\n", argv0);
189+}
190+
191+int
192+main(int argc, char *argv[])
193+{
194+	Rune r, lastrune = 0;
195+	size_t off1, off2, i, m;
196+	int ret = 0;
197+
198+	ARGBEGIN {
199+	case 'c':
200+	case 'C':
201+		cflag = 1;
202+		break;
203+	case 'd':
204+		dflag = 1;
205+		break;
206+	case 's':
207+		sflag = 1;
208+		break;
209+	default:
210+		usage();
211+	} ARGEND
212+
213+	if (!argc || argc > 2 || (dflag == sflag && argc != 2) ||
214+	    (dflag && argc != 1))
215+		usage();
216+
217+	set1ranges = makeset(argv[0], &set1, &set1checks);
218+	if (argc == 2) {
219+		set2ranges = makeset(argv[1], &set2, &set2checks);
220+		/* sanity checks as we are translating */
221+		if (!set2ranges && !set2checks)
222+			eprintf("cannot map to an empty set.\n");
223+		if (set2checks && set2checks != ISLOWERBIT &&
224+		    set2checks != ISUPPERBIT) {
225+			eprintf("can only map to 'lower' and 'upper' class.\n");
226+		}
227+	}
228+read:
229+	if (!efgetrune(&r, stdin, "<stdin>")) {
230+		ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
231+		return ret;
232+	}
233+	if (argc == 1 && sflag)
234+		goto write;
235+	for (i = 0, off1 = 0; i < set1ranges; off1 += rangelen(set1[i]), i++) {
236+		if (set1[i].start <= r && r <= set1[i].end) {
237+			if (dflag) {
238+				if (cflag)
239+					goto write;
240+				else
241+					goto read;
242+			}
243+			if (cflag)
244+				goto write;
245+
246+			/* map r to set2 */
247+			if (set2checks) {
248+				if (set2checks == ISLOWERBIT)
249+					r = tolowerrune(r);
250+				else
251+					r = toupperrune(r);
252+			} else {
253+				off1 += r - set1[i].start;
254+				if (off1 > setlen(set2, set2ranges) - 1) {
255+					r = set2[set2ranges - 1].end;
256+					goto write;
257+				}
258+				for (m = 0, off2 = 0; m < set2ranges; m++) {
259+					if (off2 + rangelen(set2[m]) > off1) {
260+						m++;
261+						break;
262+					}
263+					off2 += rangelen(set2[m]);
264+				}
265+				m--;
266+				r = set2[m].start + (off1 - off2) / set2[m].quant;
267+			}
268+			goto write;
269+		}
270+	}
271+	if (check(r, set1checks)) {
272+		if (cflag)
273+			goto write;
274+		if (dflag)
275+			goto read;
276+		if (set2checks) {
277+			if (set2checks == ISLOWERBIT)
278+				r = tolowerrune(r);
279+			else
280+				r = toupperrune(r);
281+		} else {
282+			r = set2[set2ranges - 1].end;
283+		}
284+		goto write;
285+	}
286+	if (!dflag && cflag) {
287+		if (set2checks) {
288+			if (set2checks == ISLOWERBIT)
289+				r = tolowerrune(r);
290+			else
291+				r = toupperrune(r);
292+		} else {
293+			r = set2[set2ranges - 1].end;
294+		}
295+		goto write;
296+	}
297+	if (dflag && cflag)
298+		goto read;
299+write:
300+	if (argc == 1 && sflag && r == lastrune) {
301+		if (check(r, set1checks))
302+			goto read;
303+		for (i = 0; i < set1ranges; i++) {
304+			if (set1[i].start <= r && r <= set1[i].end)
305+				goto read;
306+		}
307+	}
308+	if (argc == 2 && sflag && r == lastrune) {
309+		if (set2checks && check(r, set2checks))
310+			goto read;
311+		for (i = 0; i < set2ranges; i++) {
312+			if (set2[i].start <= r && r <= set2[i].end)
313+				goto read;
314+		}
315+	}
316+	efputrune(&r, stdout, "<stdout>");
317+	lastrune = r;
318+	goto read;
319+}
+6, -0
1@@ -0,0 +1,6 @@
2+/* See LICENSE file for copyright and license details. */
3+int
4+main(void)
5+{
6+	return 0;
7+}
+209, -0
  1@@ -0,0 +1,209 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <stdio.h>
  4+#include <string.h>
  5+#include <stdlib.h>
  6+#include <ctype.h>
  7+
  8+#include "util.h"
  9+
 10+enum { WHITE = 0, GREY, BLACK };
 11+
 12+struct vertex;
 13+
 14+struct edge {
 15+	struct vertex *to;
 16+	struct edge *next;
 17+};
 18+
 19+struct vertex {
 20+	char *name;
 21+	struct vertex *next;
 22+	struct edge edges;
 23+	size_t in_edges;
 24+	int colour;
 25+};
 26+
 27+static struct vertex graph;
 28+
 29+static void
 30+find_vertex(const char *name, struct vertex **it, struct vertex **prev)
 31+{
 32+	for (*prev = &graph; (*it = (*prev)->next); *prev = *it) {
 33+		int cmp = strcmp(name, (*it)->name);
 34+		if (cmp > 0)
 35+			continue;
 36+		if (cmp < 0)
 37+			*it = 0;
 38+		return;
 39+	}
 40+}
 41+
 42+static void
 43+find_edge(struct vertex *from, const char *to, struct edge **it, struct edge **prev)
 44+{
 45+	for (*prev = &(from->edges); (*it = (*prev)->next); *prev = *it) {
 46+		int cmp = strcmp(to, (*it)->to->name);
 47+		if (cmp > 0)
 48+			continue;
 49+		if (cmp < 0)
 50+			*it = 0;
 51+		return;
 52+	}
 53+}
 54+
 55+static struct vertex *
 56+add_vertex(char *name)
 57+{
 58+	struct vertex *vertex;
 59+	struct vertex *prev;
 60+
 61+	find_vertex(name, &vertex, &prev);
 62+	if (vertex)
 63+		return vertex;
 64+
 65+	vertex = encalloc(2, 1, sizeof(*vertex));
 66+	vertex->name = name;
 67+	vertex->next = prev->next;
 68+	prev->next = vertex;
 69+
 70+	return vertex;
 71+}
 72+
 73+static struct edge *
 74+add_edge(struct vertex *from, struct vertex* to)
 75+{
 76+	struct edge *edge;
 77+	struct edge *prev;
 78+
 79+	find_edge(from, to->name, &edge, &prev);
 80+	if (edge)
 81+		return edge;
 82+
 83+	edge = encalloc(2, 1, sizeof(*edge));
 84+	edge->to = to;
 85+	edge->next = prev->next;
 86+	prev->next = edge;
 87+	to->in_edges += 1;
 88+
 89+	return edge;
 90+}
 91+
 92+static void
 93+load_graph(FILE *fp)
 94+{
 95+#define SKIP(VAR, START, FUNC)  for (VAR = START; FUNC(*VAR) && *VAR; VAR++)
 96+#define TOKEN_END(P)            do { if (*P) *P++ = 0; else P = 0; } while (0)
 97+
 98+	char *line = 0;
 99+	size_t size = 0;
100+	ssize_t len;
101+	char *p;
102+	char *name;
103+	struct vertex *from = 0;
104+
105+	while ((len = getline(&line, &size, fp)) != -1) {
106+		if (line[len - 1] == '\n')
107+			line[--len] = 0;
108+		for (p = line; p;) {
109+			SKIP(name, p, isspace);
110+			if (!*name)
111+				break;
112+			SKIP(p, name, !isspace);
113+			TOKEN_END(p);
114+			if (!from) {
115+				from = add_vertex(enstrdup(2, name));
116+			} else if (strcmp(from->name, name)) {
117+				add_edge(from, add_vertex(enstrdup(2, name)));
118+				from = 0;
119+			} else {
120+				from = 0;
121+			}
122+		}
123+	}
124+
125+	free(line);
126+
127+	if (from)
128+		enprintf(2, "odd number of tokens in input\n");
129+}
130+
131+static int
132+sort_graph_visit(struct vertex *u)
133+{
134+	struct edge *e = &(u->edges);
135+	struct vertex *v;
136+	int r = 0;
137+	u->colour = GREY;
138+	printf("%s\n", u->name);
139+	while ((e = e->next)) {
140+		v = e->to;
141+		if (v->colour == WHITE) {
142+			v->in_edges -= 1;
143+			if (v->in_edges == 0)
144+				r |= sort_graph_visit(v);
145+		} else if (v->colour == GREY) {
146+			r = 1;
147+			fprintf(stderr, "%s: loop detected between %s and %s\n",
148+			        argv0, u->name, v->name);
149+		}
150+	}
151+	u->colour = BLACK;
152+	return r;
153+}
154+
155+static int
156+sort_graph(void)
157+{
158+	struct vertex *u, *prev;
159+	int r = 0;
160+	size_t in_edges;
161+	for (in_edges = 0; graph.next; in_edges++) {
162+		for (prev = &graph; (u = prev->next); prev = u) {
163+			if (u->colour != WHITE)
164+				goto unlist;
165+			if (u->in_edges > in_edges)
166+				continue;
167+			r |= sort_graph_visit(u);
168+		unlist:
169+			prev->next = u->next;
170+			u = prev;
171+		}
172+	}
173+	return r;
174+}
175+
176+static void
177+usage(void)
178+{
179+	enprintf(2, "usage: %s [file]\n", argv0);
180+}
181+
182+int
183+main(int argc, char *argv[])
184+{
185+	FILE *fp = stdin;
186+	const char *fn = "<stdin>";
187+	int ret = 0;
188+
189+	ARGBEGIN {
190+	default:
191+		usage();
192+	} ARGEND
193+
194+	if (argc > 1)
195+		usage();
196+	if (argc && strcmp(*argv, "-"))
197+		if (!(fp = fopen(fn = *argv, "r")))
198+			enprintf(2, "fopen %s:", *argv);
199+
200+	memset(&graph, 0, sizeof(graph));
201+	load_graph(fp);
202+	enfshut(2, fp, fn);
203+
204+	ret = sort_graph();
205+
206+	if (fshut(stdout, "<stdout>") | fshut(stderr, "<stderr>"))
207+		ret = 2;
208+
209+	return ret;
210+}
+31, -0
 1@@ -0,0 +1,31 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <unistd.h>
 5+
 6+#include "util.h"
 7+
 8+static void
 9+usage(void)
10+{
11+	enprintf(2, "usage: %s\n", argv0);
12+}
13+
14+int
15+main(int argc, char *argv[])
16+{
17+	char *tty;
18+
19+	ARGBEGIN {
20+	default:
21+		usage();
22+	} ARGEND
23+
24+	if (argc)
25+		usage();
26+
27+	tty = ttyname(STDIN_FILENO);
28+	puts(tty ? tty : "not a tty");
29+
30+	enfshut(2, stdout, "<stdout>");
31+	return !tty;
32+}
+62, -0
 1@@ -0,0 +1,62 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/utsname.h>
 4+
 5+#include <stdio.h>
 6+
 7+#include "util.h"
 8+
 9+static void
10+usage(void)
11+{
12+	eprintf("usage: %s [-amnrsv]\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+	struct utsname u;
19+	int mflag = 0, nflag = 0, rflag = 0, sflag = 0, vflag = 0;
20+
21+	ARGBEGIN {
22+	case 'a':
23+		mflag = nflag = rflag = sflag = vflag = 1;
24+		break;
25+	case 'm':
26+		mflag = 1;
27+		break;
28+	case 'n':
29+		nflag = 1;
30+		break;
31+	case 'r':
32+		rflag = 1;
33+		break;
34+	case 's':
35+		sflag = 1;
36+		break;
37+	case 'v':
38+		vflag = 1;
39+		break;
40+	default:
41+		usage();
42+	} ARGEND
43+
44+	if (argc)
45+		usage();
46+
47+	if (uname(&u) < 0)
48+		eprintf("uname:");
49+
50+	if (sflag || !(nflag || rflag || vflag || mflag))
51+		putword(stdout, u.sysname);
52+	if (nflag)
53+		putword(stdout, u.nodename);
54+	if (rflag)
55+		putword(stdout, u.release);
56+	if (vflag)
57+		putword(stdout, u.version);
58+	if (mflag)
59+		putword(stdout, u.machine);
60+	putchar('\n');
61+
62+	return fshut(stdout, "<stdout>");
63+}
+174, -0
  1@@ -0,0 +1,174 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <stdint.h>
  4+#include <stdlib.h>
  5+#include <string.h>
  6+
  7+#include "utf.h"
  8+#include "util.h"
  9+
 10+static int     aflag      = 0;
 11+static size_t *tablist    = NULL;
 12+static size_t  tablistlen = 8;
 13+
 14+static size_t
 15+parselist(const char *s)
 16+{
 17+	size_t i;
 18+	char  *p, *tmp;
 19+
 20+	tmp = estrdup(s);
 21+	for (i = 0; (p = strsep(&tmp, " ,")); i++) {
 22+		if (*p == '\0')
 23+			eprintf("empty field in tablist\n");
 24+		tablist = ereallocarray(tablist, i + 1, sizeof(*tablist));
 25+		tablist[i] = estrtonum(p, 1, MIN(LLONG_MAX, SIZE_MAX));
 26+		if (i > 0 && tablist[i - 1] >= tablist[i])
 27+			eprintf("tablist must be ascending\n");
 28+	}
 29+	tablist = ereallocarray(tablist, i + 1, sizeof(*tablist));
 30+
 31+	return i;
 32+}
 33+
 34+static void
 35+unexpandspan(size_t last, size_t col)
 36+{
 37+	size_t off, i, j;
 38+	Rune r;
 39+
 40+	if (tablistlen == 1) {
 41+		i = 0;
 42+		off = last % tablist[i];
 43+
 44+		if ((col - last) + off >= tablist[i] && last < col)
 45+			last -= off;
 46+
 47+		r = '\t';
 48+		for (; last + tablist[i] <= col; last += tablist[i])
 49+			efputrune(&r, stdout, "<stdout>");
 50+		r = ' ';
 51+		for (; last < col; last++)
 52+			efputrune(&r, stdout, "<stdout>");
 53+	} else {
 54+		for (i = 0; i < tablistlen; i++)
 55+			if (col < tablist[i])
 56+				break;
 57+		for (j = 0; j < tablistlen; j++)
 58+			if (last < tablist[j])
 59+				break;
 60+		r = '\t';
 61+		for (; j < i; j++) {
 62+			efputrune(&r, stdout, "<stdout>");
 63+			last = tablist[j];
 64+		}
 65+		r = ' ';
 66+		for (; last < col; last++)
 67+			efputrune(&r, stdout, "<stdout>");
 68+	}
 69+}
 70+
 71+static void
 72+unexpand(const char *file, FILE *fp)
 73+{
 74+	Rune r;
 75+	size_t last = 0, col = 0, i;
 76+	int bol = 1;
 77+
 78+	while (efgetrune(&r, fp, file)) {
 79+		switch (r) {
 80+		case ' ':
 81+			if (!bol && !aflag)
 82+				last++;
 83+			col++;
 84+			break;
 85+		case '\t':
 86+			if (tablistlen == 1) {
 87+				if (!bol && !aflag)
 88+					last += tablist[0] - col % tablist[0];
 89+				col += tablist[0] - col % tablist[0];
 90+			} else {
 91+				for (i = 0; i < tablistlen; i++)
 92+					if (col < tablist[i])
 93+						break;
 94+				if (!bol && !aflag)
 95+					last = tablist[i];
 96+				col = tablist[i];
 97+			}
 98+			break;
 99+		case '\b':
100+			if (bol || aflag)
101+				unexpandspan(last, col);
102+			col -= (col > 0);
103+			last = col;
104+			bol = 0;
105+			break;
106+		case '\n':
107+			if (bol || aflag)
108+				unexpandspan(last, col);
109+			last = col = 0;
110+			bol = 1;
111+			break;
112+		default:
113+			if (bol || aflag)
114+				unexpandspan(last, col);
115+			last = ++col;
116+			bol = 0;
117+			break;
118+		}
119+		if ((r != ' ' && r != '\t') || (!aflag && !bol))
120+			efputrune(&r, stdout, "<stdout>");
121+	}
122+	if (last < col && (bol || aflag))
123+		unexpandspan(last, col);
124+}
125+
126+static void
127+usage(void)
128+{
129+	eprintf("usage: %s [-a] [-t tablist] [file ...]\n", argv0);
130+}
131+
132+int
133+main(int argc, char *argv[])
134+{
135+	FILE *fp;
136+	int ret = 0;
137+	char *tl = "8";
138+
139+	ARGBEGIN {
140+	case 't':
141+		tl = EARGF(usage());
142+		if (!*tl)
143+			eprintf("tablist cannot be empty\n");
144+		/* Fallthrough: -t implies -a */
145+	case 'a':
146+		aflag = 1;
147+		break;
148+	default:
149+		usage();
150+	} ARGEND
151+
152+	tablistlen = parselist(tl);
153+
154+	if (!argc) {
155+		unexpand("<stdin>", stdin);
156+	} else {
157+		for (; *argv; argc--, argv++) {
158+			if (!strcmp(*argv, "-")) {
159+				*argv = "<stdin>";
160+				fp = stdin;
161+			} else if (!(fp = fopen(*argv, "r"))) {
162+				weprintf("fopen %s:", *argv);
163+				ret = 1;
164+				continue;
165+			}
166+			unexpand(*argv, fp);
167+			if (fp != stdin && fshut(fp, *argv))
168+				ret = 1;
169+		}
170+	}
171+
172+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
173+
174+	return ret;
175+}
+144, -0
  1@@ -0,0 +1,144 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <ctype.h>
  4+#include <stdio.h>
  5+#include <stdlib.h>
  6+#include <string.h>
  7+
  8+#include "text.h"
  9+#include "util.h"
 10+
 11+static const char *countfmt = "";
 12+static int dflag = 0;
 13+static int uflag = 0;
 14+static int fskip = 0;
 15+static int sskip = 0;
 16+
 17+static struct line prevl;
 18+static ssize_t prevoff    = -1;
 19+static long prevlinecount = 0;
 20+
 21+static size_t
 22+uniqskip(struct line *l)
 23+{
 24+	size_t i;
 25+	int f = fskip, s = sskip;
 26+
 27+	for (i = 0; i < l->len && f; --f) {
 28+		while (isblank(l->data[i]))
 29+			i++;
 30+		while (i < l->len && !isblank(l->data[i]))
 31+			i++;
 32+	}
 33+	for (; s && i < l->len && l->data[i] != '\n'; --s, i++)
 34+		;
 35+
 36+	return i;
 37+}
 38+
 39+static void
 40+uniqline(FILE *ofp, struct line *l)
 41+{
 42+	size_t loff;
 43+
 44+	if (l) {
 45+		loff = uniqskip(l);
 46+
 47+		if (prevoff >= 0 && (l->len - loff) == (prevl.len - prevoff) &&
 48+		    !memcmp(l->data + loff, prevl.data + prevoff, l->len - loff)) {
 49+			++prevlinecount;
 50+			return;
 51+		}
 52+	}
 53+
 54+	if (prevoff >= 0) {
 55+		if ((prevlinecount == 1 && !dflag) ||
 56+		    (prevlinecount != 1 && !uflag)) {
 57+			if (*countfmt)
 58+				fprintf(ofp, countfmt, prevlinecount);
 59+			fwrite(prevl.data, 1, prevl.len, ofp);
 60+		}
 61+		prevoff = -1;
 62+	}
 63+
 64+	if (l) {
 65+		if (!prevl.data || l->len >= prevl.len) {
 66+			prevl.data = erealloc(prevl.data, l->len);
 67+		}
 68+		prevl.len = l->len;
 69+		memcpy(prevl.data, l->data, prevl.len);
 70+		prevoff = loff;
 71+	}
 72+	prevlinecount = 1;
 73+}
 74+
 75+static void
 76+uniq(FILE *fp, FILE *ofp)
 77+{
 78+	static struct line line;
 79+	static size_t size;
 80+	ssize_t len;
 81+
 82+	while ((len = getline(&line.data, &size, fp)) > 0) {
 83+		line.len = len;
 84+		uniqline(ofp, &line);
 85+	}
 86+}
 87+
 88+static void
 89+uniqfinish(FILE *ofp)
 90+{
 91+	uniqline(ofp, NULL);
 92+}
 93+
 94+static void
 95+usage(void)
 96+{
 97+	eprintf("usage: %s [-c] [-d | -u] [-f fields] [-s chars]"
 98+	        " [input [output]]\n", argv0);
 99+}
100+
101+int
102+main(int argc, char *argv[])
103+{
104+	FILE *fp[2] = { stdin, stdout };
105+	int ret = 0, i;
106+	char *fname[2] = { "<stdin>", "<stdout>" };
107+
108+	ARGBEGIN {
109+	case 'c':
110+		countfmt = "%7ld ";
111+		break;
112+	case 'd':
113+		dflag = 1;
114+		break;
115+	case 'u':
116+		uflag = 1;
117+		break;
118+	case 'f':
119+		fskip = estrtonum(EARGF(usage()), 0, INT_MAX);
120+		break;
121+	case 's':
122+		sskip = estrtonum(EARGF(usage()), 0, INT_MAX);
123+		break;
124+	default:
125+		usage();
126+	} ARGEND
127+
128+	if (argc > 2)
129+		usage();
130+
131+	for (i = 0; i < argc; i++) {
132+		if (strcmp(argv[i], "-")) {
133+			fname[i] = argv[i];
134+			if (!(fp[i] = fopen(argv[i], (i == 0) ? "r" : "w")))
135+				eprintf("fopen %s:", argv[i]);
136+		}
137+	}
138+
139+	uniq(fp[0], fp[1]);
140+	uniqfinish(fp[1]);
141+
142+	ret |= fshut(fp[0], fname[0]) | fshut(fp[1], fname[1]);
143+
144+	return ret;
145+}
+27, -0
 1@@ -0,0 +1,27 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <unistd.h>
 4+
 5+#include "util.h"
 6+
 7+static void
 8+usage(void)
 9+{
10+	eprintf("usage: %s file\n", argv0);
11+}
12+
13+int
14+main(int argc, char *argv[])
15+{
16+	ARGBEGIN {
17+	default:
18+		usage();
19+	} ARGEND
20+
21+	if (argc != 1)
22+		usage();
23+
24+	if (unlink(argv[0]) < 0)
25+		eprintf("unlink: '%s':", argv[0]);
26+
27+	return 0;
28+}
+282, -0
  1@@ -0,0 +1,282 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+
  5+#include <errno.h>
  6+#include <stdio.h>
  7+#include <stdlib.h>
  8+#include <string.h>
  9+
 10+#include "util.h"
 11+
 12+static int mflag = 0;
 13+static int oflag = 0;
 14+
 15+static FILE *
 16+parsefile(const char *fname)
 17+{
 18+	struct stat st;
 19+	int ret;
 20+
 21+	if (!strcmp(fname, "/dev/stdout") || !strcmp(fname, "-"))
 22+		return stdout;
 23+	ret = lstat(fname, &st);
 24+	/* if it is a new file, try to open it */
 25+	if (ret < 0 && errno == ENOENT)
 26+		goto tropen;
 27+	if (ret < 0) {
 28+		weprintf("lstat %s:", fname);
 29+		return NULL;
 30+	}
 31+	if (!S_ISREG(st.st_mode)) {
 32+		weprintf("for safety uudecode operates only on regular files and /dev/stdout\n");
 33+		return NULL;
 34+	}
 35+tropen:
 36+	return fopen(fname, "w");
 37+}
 38+
 39+static void
 40+parseheader(FILE *fp, const char *s, char **header, mode_t *mode, char **fname)
 41+{
 42+	static char bufs[PATH_MAX + 18]; /* len header + mode + maxname */
 43+	char *p, *q;
 44+	size_t n;
 45+
 46+	if (!fgets(bufs, sizeof(bufs), fp))
 47+		if (ferror(fp))
 48+			eprintf("%s: read error:", s);
 49+	if (bufs[0] == '\0' || feof(fp))
 50+		eprintf("empty or nil header string\n");
 51+	if (!(p = strchr(bufs, '\n')))
 52+		eprintf("header string too long or non-newline terminated file\n");
 53+	p = bufs;
 54+	if (!(q = strchr(p, ' ')))
 55+		eprintf("malformed mode string in header, expected ' '\n");
 56+	*header = bufs;
 57+	*q++ = '\0';
 58+	p = q;
 59+	/* now header should be null terminated, q points to mode */
 60+	if (!(q = strchr(p, ' ')))
 61+		eprintf("malformed mode string in header, expected ' '\n");
 62+	*q++ = '\0';
 63+	/* now mode should be null terminated, q points to fname */
 64+	*mode = parsemode(p, *mode, 0);
 65+	n = strlen(q);
 66+	while (n > 0 && (q[n - 1] == '\n' || q[n - 1] == '\r'))
 67+		q[--n] = '\0';
 68+	if (n > 0)
 69+		*fname = q;
 70+	else
 71+		eprintf("header string does not contain output file\n");
 72+}
 73+
 74+static const char b64dt[] = {
 75+	-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 76+	-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
 77+	52,53,54,55,56,57,58,59,60,61,-1,-1,-1, 0,-1,-1,-1, 0, 1, 2, 3, 4, 5, 6,
 78+	 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
 79+	-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
 80+	49,50,51,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 81+	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 82+	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 83+	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 84+	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 85+	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 86+};
 87+
 88+static void
 89+uudecodeb64(FILE *fp, FILE *outfp)
 90+{
 91+	char bufb[60], *pb;
 92+	char out[45], *po;
 93+	size_t n;
 94+	int b = 0, e, t = -1, l = 1;
 95+	unsigned char b24[3] = {0, 0, 0};
 96+
 97+	while ((n = fread(bufb, 1, sizeof(bufb), fp))) {
 98+		for (pb = bufb, po = out; pb < bufb + n; pb++) {
 99+			if (*pb == '\n') {
100+				l++;
101+				continue;
102+			} else if (*pb == '=') {
103+				switch (b) {
104+				case 0:
105+					/* expected '=' remaining
106+					 * including footer */
107+					if (--t) {
108+						fwrite(out, 1,
109+						       (po - out),
110+						       outfp);
111+						return;
112+					}
113+					continue;
114+				case 1:
115+					eprintf("%d: unexpected \"=\""
116+					        "appeared\n", l);
117+				case 2:
118+					*po++ = b24[0];
119+					b = 0;
120+					t = 5; /* expect 5 '=' */
121+					continue;
122+				case 3:
123+					*po++ = b24[0];
124+					*po++ = b24[1];
125+					b = 0;
126+					t = 6; /* expect 6 '=' */
127+					continue;
128+				}
129+			} else if ((e = b64dt[(int)*pb]) == -1)
130+				eprintf("%d: invalid byte \"%c\"\n", l, *pb);
131+			else if (e == -2) /* whitespace */
132+				continue;
133+			else if (t > 0) /* state is parsing pad/footer */
134+				eprintf("%d: invalid byte \"%c\""
135+					" after padding\n",
136+				        l, *pb);
137+			switch (b) { /* decode next base64 chr based on state */
138+				case 0: b24[0] |= e << 2; break;
139+				case 1: b24[0] |= (e >> 4) & 0x3;
140+				        b24[1] |= (e & 0xf) << 4; break;
141+				case 2: b24[1] |= (e >> 2) & 0xf;
142+				        b24[2] |= (e & 0x3) << 6; break;
143+				case 3: b24[2] |= e; break;
144+			}
145+			if (++b == 4) { /* complete decoding an octet */
146+				*po++ = b24[0];
147+				*po++ = b24[1];
148+				*po++ = b24[2];
149+				b24[0] = b24[1] = b24[2] = 0;
150+				b = 0;
151+			}
152+		}
153+		fwrite(out, 1, (po - out), outfp);
154+	}
155+	eprintf("%d: invalid uudecode footer \"====\" not found\n", l);
156+}
157+
158+static void
159+uudecode(FILE *fp, FILE *outfp)
160+{
161+	char *bufb = NULL, *p;
162+	size_t n = 0;
163+	ssize_t len;
164+	int ch, i;
165+
166+#define DEC(c)  (((c) - ' ') & 077) /* single character decode */
167+#define IS_DEC(c) ( (((c) - ' ') >= 0) && (((c) - ' ') <= 077 + 1) )
168+#define OUT_OF_RANGE(c) eprintf("character %c out of range: [%d-%d]\n", (c), 1 + ' ', 077 + ' ' + 1)
169+
170+	while ((len = getline(&bufb, &n, fp)) > 0) {
171+		p = bufb;
172+		/* trim newlines */
173+		if (!len || bufb[len - 1] != '\n')
174+			eprintf("no newline found, aborting\n");
175+		bufb[len - 1] = '\0';
176+
177+		/* check for last line */
178+		if ((i = DEC(*p)) <= 0)
179+			break;
180+		for (++p; i > 0; p += 4, i -= 3) {
181+			if (i >= 3) {
182+				if (!(IS_DEC(*p) && IS_DEC(*(p + 1)) &&
183+				      IS_DEC(*(p + 2)) && IS_DEC(*(p + 3))))
184+					OUT_OF_RANGE(*p);
185+
186+				ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
187+				putc(ch, outfp);
188+				ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
189+				putc(ch, outfp);
190+				ch = DEC(p[2]) << 6 | DEC(p[3]);
191+				putc(ch, outfp);
192+			} else {
193+				if (i >= 1) {
194+					if (!(IS_DEC(*p) && IS_DEC(*(p + 1))))
195+						OUT_OF_RANGE(*p);
196+
197+					ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
198+					putc(ch, outfp);
199+				}
200+				if (i >= 2) {
201+					if (!(IS_DEC(*(p + 1)) &&
202+					      IS_DEC(*(p + 2))))
203+						OUT_OF_RANGE(*p);
204+
205+					ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
206+					putc(ch, outfp);
207+				}
208+			}
209+		}
210+		if (ferror(fp))
211+			eprintf("read error:");
212+	}
213+	/* check for end or fail */
214+	if ((len = getline(&bufb, &n, fp)) < 0)
215+		eprintf("getline:");
216+	if (len < 3 || strncmp(bufb, "end", 3) || bufb[3] != '\n')
217+		eprintf("invalid uudecode footer \"end\" not found\n");
218+	free(bufb);
219+}
220+
221+static void
222+usage(void)
223+{
224+	eprintf("usage: %s [-m] [-o output] [file]\n", argv0);
225+}
226+
227+int
228+main(int argc, char *argv[])
229+{
230+	FILE *fp = NULL, *nfp = NULL;
231+	mode_t mode = 0;
232+	int ret = 0;
233+	char *fname, *header, *ifname, *ofname = NULL;
234+	void (*d) (FILE *, FILE *) = NULL;
235+
236+	ARGBEGIN {
237+	case 'm':
238+		mflag = 1; /* accepted but unused (autodetect file type) */
239+		break;
240+	case 'o':
241+		oflag = 1;
242+		ofname = EARGF(usage());
243+		break;
244+	default:
245+		usage();
246+	} ARGEND
247+
248+	if (argc > 1)
249+		usage();
250+
251+	if (!argc || !strcmp(argv[0], "-")) {
252+		fp = stdin;
253+		ifname = "<stdin>";
254+	} else {
255+		if (!(fp = fopen(argv[0], "r")))
256+			eprintf("fopen %s:", argv[0]);
257+		ifname = argv[0];
258+	}
259+
260+	parseheader(fp, ifname, &header, &mode, &fname);
261+
262+	if (!strncmp(header, "begin", sizeof("begin")))
263+		d = uudecode;
264+	else if (!strncmp(header, "begin-base64", sizeof("begin-base64")))
265+		d = uudecodeb64;
266+	else
267+		eprintf("unknown header %s:", header);
268+
269+	if (oflag)
270+		fname = ofname;
271+	if (!(nfp = parsefile(fname)))
272+		eprintf("fopen %s:", fname);
273+
274+	d(fp, nfp);
275+
276+	if (nfp != stdout && chmod(fname, mode) < 0)
277+		eprintf("chmod %s:", fname);
278+
279+	ret |= fshut(fp, (fp == stdin) ? "<stdin>" : argv[0]);
280+	ret |= fshut(nfp, (nfp == stdout) ? "<stdout>" : fname);
281+
282+	return ret;
283+}
+129, -0
  1@@ -0,0 +1,129 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+
  5+#include <stdio.h>
  6+#include <string.h>
  7+
  8+#include "util.h"
  9+
 10+static unsigned int
 11+b64e(unsigned char *b)
 12+{
 13+	unsigned int o, p = b[2] | (b[1] << 8) | (b[0] << 16);
 14+	const char b64et[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 15+
 16+	o = b64et[p & 0x3f]; p >>= 6;
 17+	o = (o << 8) | b64et[p & 0x3f]; p >>= 6;
 18+	o = (o << 8) | b64et[p & 0x3f]; p >>= 6;
 19+	o = (o << 8) | b64et[p & 0x3f];
 20+
 21+	return o;
 22+}
 23+
 24+static void
 25+uuencodeb64(FILE *fp, const char *name, const char *s)
 26+{
 27+	struct stat st;
 28+	ssize_t n, m = 0;
 29+	unsigned char buf[45], *pb;
 30+	unsigned int out[sizeof(buf)/3 + 1], *po;
 31+
 32+	if (fstat(fileno(fp), &st) < 0)
 33+		eprintf("fstat %s:", s);
 34+	printf("begin-base64 %o %s\n", st.st_mode & 0777, name);
 35+	/* write line by line */
 36+	while ((n = fread(buf, 1, sizeof(buf), fp))) {
 37+		/* clear old buffer if converting with non-multiple of 3 */
 38+		if (n != sizeof(buf) && (m = n % 3) != 0) {
 39+			buf[n] = '\0'; /* m == 2 */
 40+			if (m == 1) buf[n+1] = '\0'; /* m == 1 */
 41+		}
 42+		for (pb = buf, po = out; pb < buf + n; pb += 3)
 43+			*po++ = b64e(pb);
 44+		if (m != 0) {
 45+			unsigned int mask = 0xffffffff, dest = 0x3d3d3d3d;
 46+			/* m==2 -> 0x00ffffff; m==1 -> 0x0000ffff */
 47+			mask >>= ((3-m) << 3);
 48+			po[-1] = (po[-1] & mask) | (dest & ~mask);
 49+		}
 50+		*po++ = '\n';
 51+		fwrite(out, 1, (po - out) * sizeof(unsigned int) - 3, stdout);
 52+	}
 53+	if (ferror(fp))
 54+		eprintf("'%s' read error:", s);
 55+	puts("====");
 56+}
 57+
 58+static void
 59+uuencode(FILE *fp, const char *name, const char *s)
 60+{
 61+	struct stat st;
 62+	unsigned char buf[45], *p;
 63+	ssize_t n;
 64+	int ch;
 65+
 66+	if (fstat(fileno(fp), &st) < 0)
 67+		eprintf("fstat %s:", s);
 68+	printf("begin %o %s\n", st.st_mode & 0777, name);
 69+	while ((n = fread(buf, 1, sizeof(buf), fp))) {
 70+		ch = ' ' + (n & 0x3f);
 71+		putchar(ch == ' ' ? '`' : ch);
 72+		for (p = buf; n > 0; n -= 3, p += 3) {
 73+			if (n < 3) {
 74+				p[2] = '\0';
 75+				if (n < 2)
 76+					p[1] = '\0';
 77+			}
 78+			ch = ' ' + ((p[0] >> 2) & 0x3f);
 79+			putchar(ch == ' ' ? '`' : ch);
 80+			ch = ' ' + (((p[0] << 4) | ((p[1] >> 4) & 0xf)) & 0x3f);
 81+			putchar(ch == ' ' ? '`' : ch);
 82+			ch = ' ' + (((p[1] << 2) | ((p[2] >> 6) & 0x3)) & 0x3f);
 83+			putchar(ch == ' ' ? '`' : ch);
 84+			ch = ' ' + (p[2] & 0x3f);
 85+			putchar(ch == ' ' ? '`' : ch);
 86+		}
 87+		putchar('\n');
 88+	}
 89+	if (ferror(fp))
 90+		eprintf("'%s' read error:", s);
 91+	printf("%c\nend\n", '`');
 92+}
 93+
 94+static void
 95+usage(void)
 96+{
 97+	eprintf("usage: %s [-m] [file] name\n", argv0);
 98+}
 99+
100+int
101+main(int argc, char *argv[])
102+{
103+	FILE *fp = NULL;
104+	void (*uuencode_f)(FILE *, const char *, const char *) = uuencode;
105+	int ret = 0;
106+
107+	ARGBEGIN {
108+	case 'm':
109+		uuencode_f = uuencodeb64;
110+		break;
111+	default:
112+		usage();
113+	} ARGEND
114+
115+	if (!argc || argc > 2)
116+		usage();
117+
118+	if (argc == 1 || !strcmp(argv[0], "-")) {
119+		uuencode_f(stdin, argv[0], "<stdin>");
120+	} else {
121+		if (!(fp = fopen(argv[0], "r")))
122+			eprintf("fopen %s:", argv[0]);
123+		uuencode_f(fp, argv[1], argv[0]);
124+	}
125+
126+	ret |= fp && fshut(fp, argv[0]);
127+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
128+
129+	return ret;
130+}
+122, -0
  1@@ -0,0 +1,122 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <string.h>
  4+
  5+#include "utf.h"
  6+#include "util.h"
  7+
  8+static int    lflag = 0;
  9+static int    wflag = 0;
 10+static char   cmode = 0;
 11+static size_t tc = 0, tl = 0, tw = 0;
 12+
 13+static void
 14+output(const char *str, size_t nc, size_t nl, size_t nw)
 15+{
 16+	int first = 1;
 17+
 18+	if (lflag) {
 19+		first = 0;
 20+		printf("%zu", nl);
 21+	}
 22+	if (wflag) {
 23+		if (!first)
 24+			putchar(' ');
 25+		first = 0;
 26+		printf("%zu", nw);
 27+	}
 28+	if (cmode) {
 29+		if (!first)
 30+			putchar(' ');
 31+		printf("%zu", nc);
 32+	}
 33+	if (str)
 34+		printf(" %s", str);
 35+	putchar('\n');
 36+}
 37+
 38+static void
 39+wc(FILE *fp, const char *str)
 40+{
 41+	int word = 0, rlen;
 42+	Rune c;
 43+	size_t nc = 0, nl = 0, nw = 0;
 44+
 45+	while ((rlen = efgetrune(&c, fp, str))) {
 46+		nc += (cmode == 'c') ? rlen : (c != Runeerror);
 47+		if (c == '\n')
 48+			nl++;
 49+		if (!isspacerune(c))
 50+			word = 1;
 51+		else if (word) {
 52+			word = 0;
 53+			nw++;
 54+		}
 55+	}
 56+	if (word)
 57+		nw++;
 58+	tc += nc;
 59+	tl += nl;
 60+	tw += nw;
 61+	output(str, nc, nl, nw);
 62+}
 63+
 64+static void
 65+usage(void)
 66+{
 67+	eprintf("usage: %s [-c | -m] [-lw] [file ...]\n", argv0);
 68+}
 69+
 70+int
 71+main(int argc, char *argv[])
 72+{
 73+	FILE *fp;
 74+	int many;
 75+	int ret = 0;
 76+
 77+	ARGBEGIN {
 78+	case 'c':
 79+		cmode = 'c';
 80+		break;
 81+	case 'm':
 82+		cmode = 'm';
 83+		break;
 84+	case 'l':
 85+		lflag = 1;
 86+		break;
 87+	case 'w':
 88+		wflag = 1;
 89+		break;
 90+	default:
 91+		usage();
 92+	} ARGEND
 93+
 94+	if (!lflag && !wflag && !cmode) {
 95+		cmode = 'c';
 96+		lflag = 1;
 97+		wflag = 1;
 98+	}
 99+
100+	if (!argc) {
101+		wc(stdin, NULL);
102+	} else {
103+		for (many = (argc > 1); *argv; argc--, argv++) {
104+			if (!strcmp(*argv, "-")) {
105+				*argv = "<stdin>";
106+				fp = stdin;
107+			} else if (!(fp = fopen(*argv, "r"))) {
108+				weprintf("fopen %s:", *argv);
109+				ret = 1;
110+				continue;
111+			}
112+			wc(fp, *argv);
113+			if (fp != stdin && fshut(fp, *argv))
114+				ret = 1;
115+		}
116+		if (many)
117+			output("total", tc, tl, tw);
118+	}
119+
120+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
121+
122+	return ret;
123+}
+64, -0
 1@@ -0,0 +1,64 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <stdlib.h>
 5+#include <string.h>
 6+#include <time.h>
 7+#include <unistd.h>
 8+#include <utmp.h>
 9+
10+#include "config.h"
11+#include "util.h"
12+
13+static void
14+usage(void)
15+{
16+	eprintf("usage: %s [-ml]\n", argv0);
17+}
18+
19+int
20+main(int argc, char *argv[])
21+{
22+	struct utmp usr;
23+	FILE *ufp;
24+	char timebuf[sizeof "yyyy-mm-dd hh:mm"];
25+	char *tty, *ttmp;
26+	int mflag = 0, lflag = 0;
27+	time_t t;
28+
29+	ARGBEGIN {
30+	case 'm':
31+		mflag = 1;
32+		tty = ttyname(0);
33+		if (!tty)
34+			eprintf("ttyname: stdin:");
35+		if ((ttmp = strrchr(tty, '/')))
36+			tty = ttmp+1;
37+		break;
38+	case 'l':
39+		lflag = 1;
40+		break;
41+	default:
42+		usage();
43+	} ARGEND;
44+
45+	if (argc > 0)
46+		usage();
47+
48+	if (!(ufp = fopen(UTMP_PATH, "r")))
49+		eprintf("fopen: %s:", UTMP_PATH);
50+
51+	while (fread(&usr, sizeof(usr), 1, ufp) == 1) {
52+		if (!*usr.ut_name || !*usr.ut_line ||
53+		    usr.ut_line[0] == '~')
54+			continue;
55+		if (mflag != 0 && strcmp(usr.ut_line, tty) != 0)
56+			continue;
57+		if (!!strcmp(usr.ut_name, "LOGIN") == lflag)
58+			continue;
59+		t = usr.ut_time;
60+		strftime(timebuf, sizeof timebuf, "%Y-%m-%d %H:%M", localtime(&t));
61+		printf("%-8s %-12s %-16s\n", usr.ut_name, usr.ut_line, timebuf);
62+	}
63+	fclose(ufp);
64+	return 0;
65+}
+405, -0
  1@@ -0,0 +1,405 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/wait.h>
  4+
  5+#include <errno.h>
  6+#include <limits.h>
  7+#include <stdint.h>
  8+#include <stdio.h>
  9+#include <stdlib.h>
 10+#include <string.h>
 11+#include <unistd.h>
 12+
 13+#include "util.h"
 14+
 15+#define NARGS 10000
 16+
 17+static int inputc(void);
 18+static void fillargbuf(int);
 19+static int eatspace(void);
 20+static int parsequote(int);
 21+static int parseescape(void);
 22+static char *poparg(void);
 23+static void waitchld(int);
 24+static void spawn(void);
 25+
 26+static size_t argbsz;
 27+static size_t argbpos;
 28+static size_t maxargs;
 29+static size_t curprocs, maxprocs = 1;
 30+static int nerrors;
 31+static int nulflag, nflag, pflag, rflag, tflag, xflag, Iflag, Lflag;
 32+static size_t maxlines;
 33+static int newline = 1;
 34+static int arg_newline;
 35+static char *argb;
 36+static char **cmd;
 37+static char *eofstr;
 38+
 39+static int
 40+inputc(void)
 41+{
 42+	int ch;
 43+
 44+	ch = getc(stdin);
 45+	if (ch == EOF && ferror(stdin))
 46+		eprintf("getc <stdin>:");
 47+	if (ch == '\n')
 48+		newline = 1;
 49+
 50+	return ch;
 51+}
 52+
 53+static void
 54+fillargbuf(int ch)
 55+{
 56+	if (argbpos >= argbsz) {
 57+		argbsz = argbpos == 0 ? 1 : argbsz * 2;
 58+		argb = erealloc(argb, argbsz);
 59+	}
 60+	argb[argbpos] = ch;
 61+}
 62+
 63+static int
 64+eatspace(void)
 65+{
 66+	int ch;
 67+
 68+	while ((ch = inputc()) != EOF) {
 69+		if (nulflag || !(ch == ' ' || ch == '\t' || ch == '\n')) {
 70+			ungetc(ch, stdin);
 71+			return ch;
 72+		}
 73+	}
 74+	return -1;
 75+}
 76+
 77+static int
 78+parsequote(int q)
 79+{
 80+	int ch;
 81+
 82+	while ((ch = inputc()) != EOF) {
 83+		if (ch == q)
 84+			return 0;
 85+		if (ch != '\n') {
 86+			fillargbuf(ch);
 87+			argbpos++;
 88+		}
 89+	}
 90+
 91+	return -1;
 92+}
 93+
 94+static int
 95+parseescape(void)
 96+{
 97+	int ch;
 98+
 99+	if ((ch = inputc()) != EOF) {
100+		fillargbuf(ch);
101+		argbpos++;
102+		return ch;
103+	}
104+
105+	return -1;
106+}
107+
108+static char *
109+poparg(void)
110+{
111+	int ch;
112+
113+	argbpos = 0;
114+	if (eatspace() < 0)
115+		return NULL;
116+
117+	arg_newline = newline;
118+	newline = 0;
119+	while ((ch = inputc()) != EOF) {
120+		/* NUL separator: no escaping */
121+		if (nulflag) {
122+			if (ch == '\0')
123+				goto out;
124+			else
125+				goto fill;
126+		}
127+
128+		switch (ch) {
129+		case ' ':
130+		case '\t':
131+			if (Iflag)
132+				goto fill;
133+		case '\n':
134+			goto out;
135+		case '\'':
136+			if (parsequote('\'') < 0)
137+				eprintf("unterminated single quote\n");
138+			break;
139+		case '\"':
140+			if (parsequote('\"') < 0)
141+				eprintf("unterminated double quote\n");
142+			break;
143+		case '\\':
144+			if (parseescape() < 0)
145+				eprintf("backslash at EOF\n");
146+			break;
147+		default:
148+		fill:
149+			fillargbuf(ch);
150+			argbpos++;
151+			break;
152+		}
153+	}
154+out:
155+	fillargbuf('\0');
156+
157+	return (eofstr && !strcmp(argb, eofstr)) ? NULL : argb;
158+}
159+
160+static void
161+waitchld(int waitall)
162+{
163+	pid_t pid;
164+	int status;
165+
166+	while ((pid = waitpid(-1, &status,
167+			      !waitall && curprocs < maxprocs ? WNOHANG : 0)) >
168+	       0) {
169+		curprocs--;
170+
171+		if (WIFEXITED(status)) {
172+			if (WEXITSTATUS(status) == 255)
173+				exit(124);
174+			if (WEXITSTATUS(status) == 127 ||
175+			    WEXITSTATUS(status) == 126)
176+				exit(WEXITSTATUS(status));
177+			if (WEXITSTATUS(status))
178+				nerrors++;
179+		}
180+		if (WIFSIGNALED(status))
181+			exit(125);
182+	}
183+	if (pid == -1 && errno != ECHILD)
184+		eprintf("waitpid:");
185+}
186+
187+static int
188+prompt(void)
189+{
190+	FILE *fp;
191+	int ch, ret;
192+
193+	if (!(fp = fopen("/dev/tty", "r")))
194+		return -1;
195+
196+	fputs("?...", stderr);
197+	fflush(stderr);
198+
199+	ch = fgetc(fp);
200+	ret = (ch == 'y' || ch == 'Y');
201+	if (ch != EOF && ch != '\n') {
202+		while ((ch = fgetc(fp)) != EOF) {
203+			if (ch == '\n')
204+				break;
205+		}
206+	}
207+
208+	fclose(fp);
209+
210+	return ret;
211+}
212+
213+static void
214+spawn(void)
215+{
216+	int savederrno;
217+	int first = 1;
218+	char **p;
219+
220+	if (pflag || tflag) {
221+		for (p = cmd; *p; p++) {
222+			if (!first)
223+				fputc(' ', stderr);
224+			fputs(*p, stderr);
225+			first = 0;
226+		}
227+		if (pflag) {
228+			switch (prompt()) {
229+			case -1:
230+				break; /* error */
231+			case 0:
232+				return; /* no */
233+			case 1:
234+				goto dospawn; /* yes */
235+			}
236+		}
237+		fputc('\n', stderr);
238+		fflush(stderr);
239+	}
240+
241+dospawn:
242+	switch (fork()) {
243+	case -1:
244+		eprintf("fork:");
245+	case 0:
246+		execvp(*cmd, cmd);
247+		savederrno = errno;
248+		weprintf("execvp %s:", *cmd);
249+		_exit(126 + (savederrno == ENOENT));
250+	}
251+	curprocs++;
252+	waitchld(0);
253+}
254+
255+static void
256+usage(void)
257+{
258+	eprintf("usage: %s [-0prtx] [-E eofstr] [-I replstr] [-L maxlines] [-n "
259+		"num] [-P maxprocs] [-s num] "
260+		"[cmd [arg ...]]\n",
261+		argv0);
262+}
263+
264+int
265+main(int argc, char *argv[])
266+{
267+	int ret = 0, leftover = 0, i, j;
268+	size_t argsz, argmaxsz;
269+	size_t arglen, a;
270+	char *arg = "";
271+	char *replstr;
272+
273+	if ((argmaxsz = sysconf(_SC_ARG_MAX)) == (size_t)-1)
274+		argmaxsz = _POSIX_ARG_MAX;
275+	/* Leave some room for environment variables */
276+	argmaxsz -= 4096;
277+	cmd = emalloc(NARGS * sizeof(*cmd));
278+
279+	ARGBEGIN
280+	{
281+	case '0':
282+		nulflag = 1;
283+		break;
284+	case 'n':
285+		nflag = 1;
286+		maxargs =
287+			estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG_MAX));
288+		break;
289+	case 'p':
290+		pflag = 1;
291+		break;
292+	case 'r':
293+		rflag = 1;
294+		break;
295+	case 's':
296+		argmaxsz =
297+			estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG_MAX));
298+		break;
299+	case 't':
300+		tflag = 1;
301+		break;
302+	case 'x':
303+		xflag = 1;
304+		break;
305+	case 'E':
306+		eofstr = EARGF(usage());
307+		break;
308+	case 'I':
309+		Iflag = 1;
310+		xflag = 1;
311+		nflag = 1;
312+		maxargs = 1;
313+		replstr = EARGF(usage());
314+		break;
315+	case 'L':
316+		Lflag = 1;
317+		maxlines =
318+			estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG_MAX));
319+		break;
320+	case 'P':
321+		maxprocs =
322+			estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG_MAX));
323+		break;
324+	default:
325+		usage();
326+	}
327+	ARGEND
328+
329+	do {
330+		size_t linecount = 0;
331+		argsz = 0;
332+		i = 0;
333+		a = 0;
334+		if (argc) {
335+			for (; i < argc; i++) {
336+				cmd[i] = estrdup(argv[i]);
337+				argsz += strlen(cmd[i]) + 1;
338+			}
339+		} else {
340+			cmd[i] = estrdup("/bin/echo");
341+			argsz += strlen("/bin/echo") + 1;
342+			i++;
343+		}
344+		while (leftover || (arg = poparg())) {
345+			if (arg) {
346+				if (linecount == 0) {
347+					linecount = 1;
348+				} else if (arg_newline) {
349+					linecount++;
350+					arg_newline = 0;
351+				}
352+				if (Lflag && linecount > maxlines) {
353+					leftover = 1;
354+					break;
355+				}
356+			}
357+			arglen = strlen(arg);
358+			if (argsz + arglen >= argmaxsz || i >= NARGS - 1) {
359+				if (xflag || arglen >= argmaxsz || leftover)
360+					eprintf("insufficient argument "
361+						"space\n");
362+				leftover = 1;
363+				break;
364+			}
365+
366+			if (!Iflag) {
367+				cmd[i] = estrdup(arg);
368+				argsz += arglen + 1;
369+			} else {
370+				for (j = 1; j < i; j++) {
371+					char *p = cmd[j];
372+					argsz -= strlen(cmd[j]);
373+					strnsubst(&cmd[j], replstr, arg, 255);
374+					argsz += strlen(cmd[j]);
375+					free(p);
376+				}
377+			}
378+
379+			i++;
380+			a++;
381+			leftover = 0;
382+			if (nflag && a >= maxargs)
383+				break;
384+		}
385+		cmd[i] = NULL;
386+		if (a >= maxargs && nflag)
387+			spawn();
388+		else if (Lflag && linecount >= maxlines)
389+			spawn();
390+		else if (!a || (i == 1 && rflag))
391+			;
392+		else
393+			spawn();
394+		for (; i >= 0; i--)
395+			free(cmd[i]);
396+	} while (arg);
397+
398+	free(argb);
399+
400+	waitchld(1);
401+
402+	if (nerrors || (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>")))
403+		ret = 123;
404+
405+	return ret;
406+}
+49, -0
 1@@ -0,0 +1,49 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <stdlib.h>
 5+#include <unistd.h>
 6+
 7+#include "util.h"
 8+
 9+static void
10+usage(void)
11+{
12+	eprintf("usage: %s dir [cmd [arg ...]]\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+	char *shell[] = { "/bin/sh", "-i", NULL }, *aux, *cmd;
19+	int savederrno;
20+
21+	ARGBEGIN {
22+	default:
23+		usage();
24+	} ARGEND
25+
26+	if (!argc)
27+		usage();
28+
29+	if ((aux = getenv("SHELL")))
30+		shell[0] = aux;
31+
32+	if (chroot(argv[0]) < 0)
33+		eprintf("chroot %s:", argv[0]);
34+
35+	if (chdir("/") < 0)
36+		eprintf("chdir:");
37+
38+	if (argc == 1) {
39+		cmd = *shell;
40+		execvp(cmd, shell);
41+	} else {
42+		cmd = argv[1];
43+		execvp(cmd, argv + 1);
44+	}
45+
46+	savederrno = errno;
47+	weprintf("execvp %s:", cmd);
48+
49+	_exit(126 + (savederrno == ENOENT));
50+}
+23, -0
 1@@ -0,0 +1,23 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+
 5+#include "util.h"
 6+
 7+static void
 8+usage(void)
 9+{
10+	eprintf("usage: %s\n", argv0);
11+}
12+
13+int
14+main(int argc, char *argv[])
15+{
16+	argv0 = argv[0], argc--, argv++;
17+
18+	if (argc)
19+		usage();
20+
21+	printf("\x1b[2J\x1b[H");
22+
23+	return 0;
24+}
+98, -0
 1@@ -0,0 +1,98 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/ioctl.h>
 4+
 5+#include <limits.h>
 6+#include <stdint.h>
 7+#include <stdio.h>
 8+#include <stdlib.h>
 9+#include <string.h>
10+#include <unistd.h>
11+
12+#include "text.h"
13+#include "util.h"
14+
15+static void
16+usage(void)
17+{
18+	eprintf("usage: %s [-c num] [file ...]\n", argv0);
19+}
20+
21+int
22+main(int argc, char *argv[])
23+{
24+	FILE *fp;
25+	struct winsize w;
26+	struct linebuf b = EMPTY_LINEBUF;
27+	size_t chars = 65, maxlen = 0, i, j, k, len, cols, rows;
28+	int cflag = 0, ret = 0;
29+	char *p;
30+
31+	ARGBEGIN {
32+	case 'c':
33+		cflag = 1;
34+		chars = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
35+		break;
36+	default:
37+		usage();
38+	} ARGEND
39+
40+	if (!cflag) {
41+		if ((p = getenv("COLUMNS")))
42+			chars = estrtonum(p, 1, MIN(LLONG_MAX, SIZE_MAX));
43+		else if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) && w.ws_col > 0)
44+			chars = w.ws_col;
45+	}
46+
47+	if (!argc) {
48+		getlines(stdin, &b);
49+	} else {
50+		for (; *argv; argc--, argv++) {
51+			if (!strcmp(*argv, "-")) {
52+				*argv = "<stdin>";
53+				fp = stdin;
54+			} else if (!(fp = fopen(*argv, "r"))) {
55+				weprintf("fopen %s:", *argv);
56+				ret = 1;
57+				continue;
58+			}
59+			getlines(fp, &b);
60+			if (fp != stdin && fshut(fp, *argv))
61+				ret = 1;
62+		}
63+	}
64+
65+	for (i = 0; i < b.nlines; i++) {
66+		for (j = 0, len = 0; j < b.lines[i].len; j++) {
67+			if (UTF8_POINT(b.lines[i].data[j]))
68+				len++;
69+		}
70+		if (len && b.lines[i].data[b.lines[i].len - 1] == '\n') {
71+			b.lines[i].data[--(b.lines[i].len)] = '\0';
72+			len--;
73+		}
74+		if (len > maxlen)
75+			maxlen = len;
76+	}
77+
78+	for (cols = 1; (cols + 1) * maxlen + cols <= chars; cols++);
79+	rows = b.nlines / cols + (b.nlines % cols > 0);
80+
81+	for (i = 0; i < rows; i++) {
82+		for (j = 0; j < cols && i + j * rows < b.nlines; j++) {
83+			for (k = 0, len = 0; k < b.lines[i + j * rows].len; k++) {
84+				if (UTF8_POINT(b.lines[i + j * rows].data[k]))
85+					len++;
86+			}
87+			fwrite(b.lines[i + j * rows].data, 1,
88+			       b.lines[i + j * rows].len, stdout);
89+			if (j < cols - 1)
90+				for (k = len; k < maxlen + 1; k++)
91+					putchar(' ');
92+		}
93+		putchar('\n');
94+	}
95+
96+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
97+
98+	return ret;
99+}
+566, -0
  1@@ -0,0 +1,566 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/types.h>
  4+#include <sys/wait.h>
  5+
  6+#include <errno.h>
  7+#include <limits.h>
  8+#include <signal.h>
  9+#include <stdarg.h>
 10+#include <stdlib.h>
 11+#include <stdio.h>
 12+#include <ctype.h>
 13+#include <string.h>
 14+#include <syslog.h>
 15+#include <time.h>
 16+#include <unistd.h>
 17+
 18+#include "queue.h"
 19+#include "util.h"
 20+
 21+struct field {
 22+	enum {
 23+		ERROR,
 24+		WILDCARD,
 25+		NUMBER,
 26+		RANGE,
 27+		REPEAT,
 28+		LIST
 29+	} type;
 30+	long *val;
 31+	int len;
 32+};
 33+
 34+struct ctabentry {
 35+	struct field min;
 36+	struct field hour;
 37+	struct field mday;
 38+	struct field mon;
 39+	struct field wday;
 40+	char *cmd;
 41+	TAILQ_ENTRY(ctabentry) entry;
 42+};
 43+
 44+struct jobentry {
 45+	char *cmd;
 46+	pid_t pid;
 47+	TAILQ_ENTRY(jobentry) entry;
 48+};
 49+
 50+static sig_atomic_t chldreap;
 51+static sig_atomic_t reload;
 52+static sig_atomic_t quit;
 53+static TAILQ_HEAD(, ctabentry) ctabhead = TAILQ_HEAD_INITIALIZER(ctabhead);
 54+static TAILQ_HEAD(, jobentry) jobhead = TAILQ_HEAD_INITIALIZER(jobhead);
 55+static char *config = "/etc/crontab";
 56+static char *pidfile = "/var/run/crond.pid";
 57+static int nflag;
 58+
 59+static void
 60+loginfo(const char *fmt, ...)
 61+{
 62+	va_list ap;
 63+	va_start(ap, fmt);
 64+	if (nflag == 0)
 65+		vsyslog(LOG_INFO, fmt, ap);
 66+	else
 67+		vfprintf(stdout, fmt, ap);
 68+	fflush(stdout);
 69+	va_end(ap);
 70+}
 71+
 72+static void
 73+logwarn(const char *fmt, ...)
 74+{
 75+	va_list ap;
 76+	va_start(ap, fmt);
 77+	if (nflag == 0)
 78+		vsyslog(LOG_WARNING, fmt, ap);
 79+	else
 80+		vfprintf(stderr, fmt, ap);
 81+	va_end(ap);
 82+}
 83+
 84+static void
 85+logerr(const char *fmt, ...)
 86+{
 87+	va_list ap;
 88+	va_start(ap, fmt);
 89+	if (nflag == 0)
 90+		vsyslog(LOG_ERR, fmt, ap);
 91+	else
 92+		vfprintf(stderr, fmt, ap);
 93+	va_end(ap);
 94+}
 95+
 96+static void
 97+runjob(char *cmd)
 98+{
 99+	struct jobentry *je;
100+	time_t t;
101+	pid_t pid;
102+
103+	t = time(NULL);
104+
105+	/* If command is already running, skip it */
106+	TAILQ_FOREACH(je, &jobhead, entry) {
107+		if (strcmp(je->cmd, cmd) == 0) {
108+			loginfo("already running %s pid: %d at %s",
109+				je->cmd, je->pid, ctime(&t));
110+			return;
111+		}
112+	}
113+
114+	switch ((pid = fork())) {
115+	case -1:
116+		logerr("error: failed to fork job: %s time: %s",
117+		       cmd, ctime(&t));
118+		return;
119+	case 0:
120+		setsid();
121+		loginfo("run: %s pid: %d at %s",
122+			cmd, getpid(), ctime(&t));
123+		execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL);
124+		logerr("error: failed to execute job: %s time: %s",
125+		       cmd, ctime(&t));
126+		_exit(1);
127+	default:
128+		je = emalloc(sizeof(*je));
129+		je->cmd = estrdup(cmd);
130+		je->pid = pid;
131+		TAILQ_INSERT_TAIL(&jobhead, je, entry);
132+	}
133+}
134+
135+static void
136+waitjob(void)
137+{
138+	struct jobentry *je, *tmp;
139+	int status;
140+	time_t t;
141+	pid_t pid;
142+
143+	t = time(NULL);
144+
145+	while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
146+		je = NULL;
147+		TAILQ_FOREACH(tmp, &jobhead, entry) {
148+			if (tmp->pid == pid) {
149+				je = tmp;
150+				break;
151+			}
152+		}
153+		if (je) {
154+			TAILQ_REMOVE(&jobhead, je, entry);
155+			free(je->cmd);
156+			free(je);
157+		}
158+		if (WIFEXITED(status) == 1)
159+			loginfo("complete: pid: %d returned: %d time: %s",
160+				pid, WEXITSTATUS(status), ctime(&t));
161+		else if (WIFSIGNALED(status) == 1)
162+			loginfo("complete: pid: %d terminated by signal: %s time: %s",
163+				pid, strsignal(WTERMSIG(status)), ctime(&t));
164+		else if (WIFSTOPPED(status) == 1)
165+			loginfo("complete: pid: %d stopped by signal: %s time: %s",
166+				pid, strsignal(WSTOPSIG(status)), ctime(&t));
167+	}
168+}
169+
170+static int
171+isleap(int year)
172+{
173+	if (year % 400 == 0)
174+		return 1;
175+	if (year % 100 == 0)
176+		return 0;
177+	return (year % 4 == 0);
178+}
179+
180+static int
181+daysinmon(int mon, int year)
182+{
183+	int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
184+	if (year < 1900)
185+		year += 1900;
186+	if (isleap(year))
187+		days[1] = 29;
188+	return days[mon];
189+}
190+
191+static int
192+matchentry(struct ctabentry *cte, struct tm *tm)
193+{
194+	struct {
195+		struct field *f;
196+		int tm;
197+		int len;
198+	} matchtbl[] = {
199+		{ .f = &cte->min,  .tm = tm->tm_min,  .len = 60 },
200+		{ .f = &cte->hour, .tm = tm->tm_hour, .len = 24 },
201+		{ .f = &cte->mday, .tm = tm->tm_mday, .len = daysinmon(tm->tm_mon, tm->tm_year) },
202+		{ .f = &cte->mon,  .tm = tm->tm_mon,  .len = 12 },
203+		{ .f = &cte->wday, .tm = tm->tm_wday, .len = 7  },
204+	};
205+	size_t i;
206+	int j;
207+
208+	for (i = 0; i < LEN(matchtbl); i++) {
209+		switch (matchtbl[i].f->type) {
210+		case WILDCARD:
211+			continue;
212+		case NUMBER:
213+			if (matchtbl[i].f->val[0] == matchtbl[i].tm)
214+				continue;
215+			break;
216+		case RANGE:
217+			if (matchtbl[i].f->val[0] <= matchtbl[i].tm)
218+				if (matchtbl[i].f->val[1] >= matchtbl[i].tm)
219+					continue;
220+			break;
221+		case REPEAT:
222+			if (matchtbl[i].tm > 0) {
223+				if (matchtbl[i].tm % matchtbl[i].f->val[0] == 0)
224+					continue;
225+			} else {
226+				if (matchtbl[i].len % matchtbl[i].f->val[0] == 0)
227+					continue;
228+			}
229+			break;
230+		case LIST:
231+			for (j = 0; j < matchtbl[i].f->len; j++)
232+				if (matchtbl[i].f->val[j] == matchtbl[i].tm)
233+					break;
234+			if (j < matchtbl[i].f->len)
235+				continue;
236+			break;
237+		default:
238+			break;
239+		}
240+		break;
241+	}
242+	if (i != LEN(matchtbl))
243+		return 0;
244+	return 1;
245+}
246+
247+static int
248+parsefield(const char *field, long low, long high, struct field *f)
249+{
250+	int i;
251+	char *e1, *e2;
252+	const char *p;
253+
254+	p = field;
255+	while (isdigit(*p))
256+		p++;
257+
258+	f->type = ERROR;
259+
260+	switch (*p) {
261+	case '*':
262+		if (strcmp(field, "*") == 0) {
263+			f->val = NULL;
264+			f->len = 0;
265+			f->type = WILDCARD;
266+		} else if (strncmp(field, "*/", 2) == 0) {
267+			f->val = emalloc(sizeof(*f->val));
268+			f->len = 1;
269+
270+			errno = 0;
271+			f->val[0] = strtol(field + 2, &e1, 10);
272+			if (e1[0] != '\0' || errno != 0 || f->val[0] == 0)
273+				break;
274+
275+			f->type = REPEAT;
276+		}
277+		break;
278+	case '\0':
279+		f->val = emalloc(sizeof(*f->val));
280+		f->len = 1;
281+
282+		errno = 0;
283+		f->val[0] = strtol(field, &e1, 10);
284+		if (e1[0] != '\0' || errno != 0)
285+			break;
286+
287+		f->type = NUMBER;
288+		break;
289+	case '-':
290+		f->val = emalloc(2 * sizeof(*f->val));
291+		f->len = 2;
292+
293+		errno = 0;
294+		f->val[0] = strtol(field, &e1, 10);
295+		if (e1[0] != '-' || errno != 0)
296+			break;
297+
298+		errno = 0;
299+		f->val[1] = strtol(e1 + 1, &e2, 10);
300+		if (e2[0] != '\0' || errno != 0)
301+			break;
302+
303+		f->type = RANGE;
304+		break;
305+	case ',':
306+		for (i = 1; isdigit(*p) || *p == ','; p++)
307+			if (*p == ',')
308+				i++;
309+		f->val = emalloc(i * sizeof(*f->val));
310+		f->len = i;
311+
312+		errno = 0;
313+		f->val[0] = strtol(field, &e1, 10);
314+		if (f->val[0] < low || f->val[0] > high)
315+			break;
316+
317+		for (i = 1; *e1 == ',' && errno == 0; i++) {
318+			errno = 0;
319+			f->val[i] = strtol(e1 + 1, &e2, 10);
320+			e1 = e2;
321+		}
322+		if (e1[0] != '\0' || errno != 0)
323+			break;
324+
325+		f->type = LIST;
326+		break;
327+	default:
328+		return -1;
329+	}
330+
331+	for (i = 0; i < f->len; i++)
332+		if (f->val[i] < low || f->val[i] > high)
333+			f->type = ERROR;
334+
335+	if (f->type == ERROR) {
336+		free(f->val);
337+		return -1;
338+	}
339+
340+	return 0;
341+}
342+
343+static void
344+freecte(struct ctabentry *cte, int nfields)
345+{
346+	switch (nfields) {
347+	case 6:
348+		free(cte->cmd);
349+	case 5:
350+		free(cte->wday.val);
351+	case 4:
352+		free(cte->mon.val);
353+	case 3:
354+		free(cte->mday.val);
355+	case 2:
356+		free(cte->hour.val);
357+	case 1:
358+		free(cte->min.val);
359+	}
360+	free(cte);
361+}
362+
363+static void
364+unloadentries(void)
365+{
366+	struct ctabentry *cte, *tmp;
367+
368+	for (cte = TAILQ_FIRST(&ctabhead); cte; cte = tmp) {
369+		tmp = TAILQ_NEXT(cte, entry);
370+		TAILQ_REMOVE(&ctabhead, cte, entry);
371+		freecte(cte, 6);
372+	}
373+}
374+
375+static int
376+loadentries(void)
377+{
378+	struct ctabentry *cte;
379+	FILE *fp;
380+	char *line = NULL, *p, *col;
381+	int r = 0, y;
382+	size_t size = 0;
383+	ssize_t len;
384+	struct fieldlimits {
385+		char *name;
386+		long min;
387+		long max;
388+		struct field *f;
389+	} flim[] = {
390+		{ "min",  0, 59, NULL },
391+		{ "hour", 0, 23, NULL },
392+		{ "mday", 1, 31, NULL },
393+		{ "mon",  1, 12, NULL },
394+		{ "wday", 0, 6,  NULL }
395+	};
396+	size_t x;
397+
398+	if ((fp = fopen(config, "r")) == NULL) {
399+		logerr("error: can't open %s: %s\n", config, strerror(errno));
400+		return -1;
401+	}
402+
403+	for (y = 0; (len = getline(&line, &size, fp)) != -1; y++) {
404+		p = line;
405+		if (line[0] == '#' || line[0] == '\n' || line[0] == '\0')
406+			continue;
407+
408+		cte = emalloc(sizeof(*cte));
409+		flim[0].f = &cte->min;
410+		flim[1].f = &cte->hour;
411+		flim[2].f = &cte->mday;
412+		flim[3].f = &cte->mon;
413+		flim[4].f = &cte->wday;
414+
415+		for (x = 0; x < LEN(flim); x++) {
416+			do
417+				col = strsep(&p, "\t\n ");
418+			while (col && col[0] == '\0');
419+
420+			if (!col || parsefield(col, flim[x].min, flim[x].max, flim[x].f) < 0) {
421+				logerr("error: failed to parse `%s' field on line %d\n",
422+						flim[x].name, y + 1);
423+				freecte(cte, x);
424+				r = -1;
425+				break;
426+			}
427+		}
428+
429+		if (r == -1)
430+			break;
431+
432+		col = strsep(&p, "\n");
433+		if (col)
434+			while (col[0] == '\t' || col[0] == ' ')
435+				col++;
436+		if (!col || col[0] == '\0') {
437+			logerr("error: missing `cmd' field on line %d\n",
438+			       y + 1);
439+			freecte(cte, 5);
440+			r = -1;
441+			break;
442+		}
443+		cte->cmd = estrdup(col);
444+
445+		TAILQ_INSERT_TAIL(&ctabhead, cte, entry);
446+	}
447+
448+	if (r < 0)
449+		unloadentries();
450+
451+	free(line);
452+	fclose(fp);
453+
454+	return r;
455+}
456+
457+static void
458+reloadentries(void)
459+{
460+	unloadentries();
461+	if (loadentries() < 0)
462+		logwarn("warning: discarding old crontab entries\n");
463+}
464+
465+static void
466+sighandler(int sig)
467+{
468+	switch (sig) {
469+	case SIGCHLD:
470+		chldreap = 1;
471+		break;
472+	case SIGHUP:
473+		reload = 1;
474+		break;
475+	case SIGTERM:
476+		quit = 1;
477+		break;
478+	}
479+}
480+
481+static void
482+usage(void)
483+{
484+	eprintf("usage: %s [-f file] [-n]\n", argv0);
485+}
486+
487+int
488+main(int argc, char *argv[])
489+{
490+	FILE *fp;
491+	struct ctabentry *cte;
492+	time_t t;
493+	struct tm *tm;
494+	struct sigaction sa;
495+
496+	ARGBEGIN {
497+	case 'n':
498+		nflag = 1;
499+		break;
500+	case 'f':
501+		config = EARGF(usage());
502+		break;
503+	default:
504+		usage();
505+	} ARGEND
506+
507+	if (argc > 0)
508+		usage();
509+
510+	if (nflag == 0) {
511+		openlog(argv[0], LOG_CONS | LOG_PID, LOG_CRON);
512+		if (daemon(1, 0) < 0) {
513+			logerr("error: failed to daemonize %s\n", strerror(errno));
514+			return 1;
515+		}
516+		if ((fp = fopen(pidfile, "w"))) {
517+			fprintf(fp, "%d\n", getpid());
518+			fclose(fp);
519+		}
520+	}
521+
522+	sa.sa_handler = sighandler;
523+	sigfillset(&sa.sa_mask);
524+	sa.sa_flags = SA_RESTART;
525+	sigaction(SIGCHLD, &sa, NULL);
526+	sigaction(SIGHUP, &sa, NULL);
527+	sigaction(SIGTERM, &sa, NULL);
528+
529+	loadentries();
530+
531+	while (1) {
532+		t = time(NULL);
533+		sleep(60 - t % 60);
534+
535+		if (quit == 1) {
536+			if (nflag == 0)
537+				unlink(pidfile);
538+			unloadentries();
539+			/* Don't wait or kill forked processes, just exit */
540+			break;
541+		}
542+
543+		if (reload == 1 || chldreap == 1) {
544+			if (reload == 1) {
545+				reloadentries();
546+				reload = 0;
547+			}
548+			if (chldreap == 1) {
549+				waitjob();
550+				chldreap = 0;
551+			}
552+			continue;
553+		}
554+
555+		TAILQ_FOREACH(cte, &ctabhead, entry) {
556+			t = time(NULL);
557+			tm = localtime(&t);
558+			if (matchentry(cte, tm) == 1)
559+				runjob(cte->cmd);
560+		}
561+	}
562+
563+	if (nflag == 0)
564+		closelog();
565+
566+	return 0;
567+}
+82, -0
 1@@ -0,0 +1,82 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/file.h>
 4+#include <sys/wait.h>
 5+
 6+#include <errno.h>
 7+#include <fcntl.h>
 8+#include <stdio.h>
 9+#include <unistd.h>
10+
11+#include "util.h"
12+
13+static void
14+usage(void)
15+{
16+	eprintf("usage: %s [-nosux] file cmd [arg ...]\n", argv0);
17+}
18+
19+int
20+main(int argc, char *argv[])
21+{
22+	int fd, status, savederrno, flags = LOCK_EX, nonblk = 0, oflag = 0;
23+	pid_t pid;
24+
25+	ARGBEGIN {
26+	case 'n':
27+		nonblk = LOCK_NB;
28+		break;
29+	case 'o':
30+		oflag = 1;
31+		break;
32+	case 's':
33+		flags = LOCK_SH;
34+		break;
35+	case 'u':
36+		flags = LOCK_UN;
37+		break;
38+	case 'x':
39+		flags = LOCK_EX;
40+		break;
41+	default:
42+		usage();
43+	} ARGEND
44+
45+	if (argc < 2)
46+		usage();
47+
48+	if ((fd = open(*argv, O_RDONLY | O_CREAT, 0644)) < 0)
49+		eprintf("open %s:", *argv);
50+
51+	if (flock(fd, flags | nonblk)) {
52+		if (nonblk && errno == EWOULDBLOCK)
53+			return 1;
54+		eprintf("flock:");
55+	}
56+
57+	switch ((pid = fork())) {
58+	case -1:
59+		eprintf("fork:");
60+	case 0:
61+		if (oflag && close(fd) < 0)
62+			eprintf("close:");
63+		argv++;
64+		execvp(*argv, argv);
65+		savederrno = errno;
66+		weprintf("execvp %s:", *argv);
67+		_exit(126 + (savederrno == ENOENT));
68+	default:
69+		break;
70+	}
71+	if (waitpid(pid, &status, 0) < 0)
72+		eprintf("waitpid:");
73+
74+	if (close(fd) < 0)
75+		eprintf("close:");
76+
77+	if (WIFSIGNALED(status))
78+		return 128 + WTERMSIG(status);
79+	if (WIFEXITED(status))
80+		return WEXITSTATUS(status);
81+
82+	return 0;
83+}
+140, -0
  1@@ -0,0 +1,140 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/ioctl.h>
  4+#include <sys/stat.h>
  5+#include <sys/types.h>
  6+
  7+#include <fcntl.h>
  8+#include <limits.h>
  9+#include <signal.h>
 10+#include <stdio.h>
 11+#include <stdlib.h>
 12+#include <string.h>
 13+#include <unistd.h>
 14+#include <utmp.h>
 15+
 16+#include "config.h"
 17+#include "util.h"
 18+
 19+static char *tty = "/dev/tty1";
 20+static char *defaultterm = "linux";
 21+
 22+static void
 23+usage(void)
 24+{
 25+	eprintf("usage: %s [tty] [term] [cmd] [args...]\n", argv0);
 26+}
 27+
 28+int
 29+main(int argc, char *argv[])
 30+{
 31+	char term[128], logname[LOGIN_NAME_MAX], c;
 32+	char hostname[HOST_NAME_MAX + 1];
 33+	struct utmp usr;
 34+	struct sigaction sa;
 35+	FILE *fp;
 36+	int fd;
 37+	unsigned int i = 0;
 38+	ssize_t n;
 39+	long pos;
 40+
 41+	ARGBEGIN {
 42+	default:
 43+		usage();
 44+	} ARGEND;
 45+
 46+	strlcpy(term, defaultterm, sizeof(term));
 47+	if (argc > 0) {
 48+		tty = argv[0];
 49+		if (argc > 1)
 50+			strlcpy(term, argv[1], sizeof(term));
 51+	}
 52+
 53+	sa.sa_handler = SIG_IGN;
 54+	sa.sa_flags = 0;
 55+	sigemptyset(&sa.sa_mask);
 56+	sigaction(SIGHUP, &sa, NULL);
 57+
 58+	setenv("TERM", term, 1);
 59+
 60+	setsid();
 61+
 62+	fd = open(tty, O_RDWR);
 63+	if (fd < 0)
 64+		eprintf("open %s:", tty);
 65+	if (isatty(fd) == 0)
 66+		eprintf("%s is not a tty\n", tty);
 67+
 68+	/* steal the controlling terminal if necessary */
 69+	if (ioctl(fd, TIOCSCTTY, (void *)1) != 0)
 70+		weprintf("TIOCSCTTY: could not set controlling tty\n");
 71+	vhangup();
 72+	close(fd);
 73+
 74+	fd = open(tty, O_RDWR);
 75+	if (fd < 0)
 76+		eprintf("open %s:", tty);
 77+	dup2(fd, 0);
 78+	dup2(fd, 1);
 79+	dup2(fd, 2);
 80+	if (fchown(fd, 0, 0) < 0)
 81+		weprintf("fchown %s:", tty);
 82+	if (fchmod(fd, 0600) < 0)
 83+		weprintf("fchmod %s:", tty);
 84+	if (fd > 2)
 85+		close(fd);
 86+
 87+	sa.sa_handler = SIG_DFL;
 88+	sa.sa_flags = 0;
 89+	sigemptyset(&sa.sa_mask);
 90+	sigaction(SIGHUP, &sa, NULL);
 91+
 92+	/* Clear all utmp entries for this tty */
 93+	fp = fopen(UTMP_PATH, "r+");
 94+	if (fp) {
 95+		do {
 96+			pos = ftell(fp);
 97+			if (fread(&usr, sizeof(usr), 1, fp) != 1)
 98+				break;
 99+			if (usr.ut_line[0] == '\0')
100+				continue;
101+			if (strcmp(usr.ut_line, tty) != 0)
102+				continue;
103+			memset(&usr, 0, sizeof(usr));
104+			fseek(fp, pos, SEEK_SET);
105+			if (fwrite(&usr, sizeof(usr), 1, fp) != 1)
106+				break;
107+		} while (1);
108+		if (ferror(fp))
109+			weprintf("%s: I/O error:", UTMP_PATH);
110+		fclose(fp);
111+	}
112+
113+	if (argc > 2)
114+		return execvp(argv[2], argv + 2);
115+
116+	if (gethostname(hostname, sizeof(hostname)) == 0)
117+		printf("%s ", hostname);
118+	printf("login: ");
119+	fflush(stdout);
120+
121+	/* Flush pending input */
122+	ioctl(0, TCFLSH, (void *)0);
123+	memset(logname, 0, sizeof(logname));
124+	while (1) {
125+		n = read(0, &c, 1);
126+		if (n < 0)
127+			eprintf("read:");
128+		if (n == 0)
129+			return 1;
130+		if (i >= sizeof(logname) - 1)
131+			eprintf("login name too long\n");
132+		if (c == '\n' || c == '\r')
133+			break;
134+		logname[i++] = c;
135+	}
136+	if (logname[0] == '-')
137+		eprintf("login name cannot start with '-'\n");
138+	if (logname[0] == '\0')
139+		return 1;
140+	return execlp("/bin/login", "login", "-p", logname, NULL);
141+}
+51, -0
 1@@ -0,0 +1,51 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/syscall.h>
 4+
 5+#include <stdio.h>
 6+#include <stdlib.h>
 7+#include <unistd.h>
 8+
 9+#include "reboot.h"
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+	eprintf("usage: %s [-pr]\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+	int pflag = 0, rflag = 0;
22+	int cmd = LINUX_REBOOT_CMD_HALT;
23+
24+	ARGBEGIN {
25+	case 'p':
26+		pflag = 1;
27+		break;
28+	case 'r':
29+		rflag = 1;
30+		break;
31+	default:
32+		usage();
33+	} ARGEND;
34+
35+	if (argc > 0)
36+		usage();
37+
38+	sync();
39+
40+	if (pflag && rflag)
41+		usage();
42+
43+	if (pflag)
44+		cmd = LINUX_REBOOT_CMD_POWER_OFF;
45+	if (rflag)
46+		cmd = LINUX_REBOOT_CMD_RESTART;
47+
48+	if (syscall(__NR_reboot, LINUX_REBOOT_MAGIC1,
49+		    LINUX_REBOOT_MAGIC2, cmd, NULL) < 0)
50+		eprintf("reboot:");
51+	return 0;
52+}
+36, -0
 1@@ -0,0 +1,36 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <string.h>
 5+#include <unistd.h>
 6+
 7+#include "util.h"
 8+
 9+static void
10+usage(void)
11+{
12+	eprintf("usage: %s [name]\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+	char host[HOST_NAME_MAX + 1];
19+
20+	ARGBEGIN {
21+	default:
22+		usage();
23+	} ARGEND
24+
25+	if (!argc) {
26+		if (gethostname(host, sizeof(host)) < 0)
27+			eprintf("gethostname:");
28+		puts(host);
29+	} else if (argc == 1) {
30+		if (sethostname(argv[0], strlen(argv[0])) < 0)
31+			eprintf("sethostname:");
32+	} else {
33+		usage();
34+	}
35+
36+	return fshut(stdout, "<stdout>");
37+}
+111, -0
  1@@ -0,0 +1,111 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <dirent.h>
  4+#include <limits.h>
  5+#include <signal.h>
  6+#include <stdio.h>
  7+#include <stdlib.h>
  8+#include <string.h>
  9+#include <unistd.h>
 10+
 11+#include "proc.h"
 12+#include "queue.h"
 13+#include "util.h"
 14+
 15+struct {
 16+	const char *name;
 17+	int sig;
 18+} sigs[] = {
 19+#define SIG(n) { #n, SIG##n }
 20+	SIG(ABRT), SIG(ALRM), SIG(BUS),  SIG(CHLD), SIG(CONT), SIG(FPE),  SIG(HUP),
 21+	SIG(ILL),  SIG(INT),  SIG(KILL), SIG(PIPE), SIG(QUIT), SIG(SEGV), SIG(STOP),
 22+	SIG(TERM), SIG(TSTP), SIG(TTIN), SIG(TTOU), SIG(USR1), SIG(USR2), SIG(URG),
 23+#undef SIG
 24+};
 25+
 26+struct pidentry {
 27+	pid_t pid;
 28+	SLIST_ENTRY(pidentry) entry;
 29+};
 30+
 31+static SLIST_HEAD(, pidentry) omitpid_head;
 32+
 33+static void
 34+usage(void)
 35+{
 36+	eprintf("usage: %s [-o pid1,pid2,..,pidN] [-s signal]\n", argv0);
 37+}
 38+
 39+int
 40+main(int argc, char *argv[])
 41+{
 42+	struct pidentry *pe;
 43+	struct dirent *entry;
 44+	DIR *dp;
 45+	char *p, *arg = NULL;
 46+	char *end, *v;
 47+	int oflag = 0;
 48+	int sig = SIGTERM;
 49+	pid_t pid;
 50+	size_t i;
 51+
 52+	ARGBEGIN {
 53+	case 's':
 54+		v = EARGF(usage());
 55+		sig = strtol(v, &end, 0);
 56+		if (*end == '\0')
 57+			break;
 58+		for (i = 0; i < LEN(sigs); i++) {
 59+			if (strcasecmp(v, sigs[i].name) == 0) {
 60+				sig = sigs[i].sig;
 61+				break;
 62+			}
 63+		}
 64+		if (i == LEN(sigs))
 65+			eprintf("%s: unknown signal\n", v);
 66+		break;
 67+	case 'o':
 68+		oflag = 1;
 69+		arg = EARGF(usage());
 70+		break;
 71+	default:
 72+		usage();
 73+	} ARGEND;
 74+
 75+	SLIST_INIT(&omitpid_head);
 76+
 77+	if (oflag) {
 78+		for (p = strtok(arg, ","); p; p = strtok(NULL, ",")) {
 79+			pe = emalloc(sizeof(*pe));
 80+			pe->pid = estrtol(p, 10);
 81+			SLIST_INSERT_HEAD(&omitpid_head, pe, entry);
 82+		}
 83+	}
 84+
 85+	if (sig != SIGSTOP && sig != SIGCONT)
 86+		kill(-1, SIGSTOP);
 87+
 88+	if (!(dp = opendir("/proc")))
 89+		eprintf("opendir /proc:");
 90+	while ((entry = readdir(dp))) {
 91+		if (pidfile(entry->d_name) == 0)
 92+			continue;
 93+		pid = estrtol(entry->d_name, 10);
 94+		if (pid == 1 || pid == getpid() ||
 95+		    getsid(pid) == getsid(0) || getsid(pid) == 0)
 96+			continue;
 97+		if (oflag == 1) {
 98+			SLIST_FOREACH(pe, &omitpid_head, entry)
 99+				if (pe->pid == pid)
100+					break;
101+			if (pe)
102+				continue;
103+		}
104+		kill(pid, sig);
105+	}
106+	closedir(dp);
107+
108+	if (sig != SIGSTOP && sig != SIGCONT)
109+		kill(-1, SIGCONT);
110+
111+	return 0;
112+}
+64, -0
 1@@ -0,0 +1,64 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <libgen.h>
 5+#include <paths.h>
 6+#include <pwd.h>
 7+#include <stdio.h>
 8+#include <stdlib.h>
 9+#include <string.h>
10+#include <time.h>
11+#include <utmp.h>
12+#include <unistd.h>
13+
14+#include "config.h"
15+#include "util.h"
16+
17+static void
18+usage(void)
19+{
20+	eprintf("usage: %s [user]\n", argv0);
21+}
22+
23+int
24+main(int argc, char **argv)
25+{
26+	FILE *fp;
27+	struct utmp ut;
28+	char *user, *file, *prog;
29+	time_t t;
30+
31+	ARGBEGIN {
32+	default:
33+		usage();
34+	} ARGEND;
35+
36+	switch (argc) {
37+	case 0:
38+		user = NULL;
39+		break;
40+	case 1:
41+		user = argv[0];
42+		break;
43+	default:
44+		usage();
45+	}
46+
47+	prog = basename(argv0);
48+	file = (!strcmp(prog, "last")) ? WTMP_PATH : BTMP_PATH;
49+	if ((fp = fopen(file, "r")) == NULL)
50+		eprintf("fopen %s:", file);
51+
52+	while (fread(&ut, sizeof(ut), 1, fp) == 1) {
53+		if (ut.ut_type != USER_PROCESS ||
54+		    (user && strcmp(user, ut.ut_name))) {
55+			continue;
56+		}
57+
58+		t = ut.ut_time;
59+		printf("%-8.8s %-8.8s %-16.16s %s",
60+		       ut.ut_user, ut.ut_line, ut.ut_host, ctime(&t));
61+	}
62+	if (fclose(fp))
63+		eprintf("fclose %s:", file);
64+	return 0;
65+}
+78, -0
 1@@ -0,0 +1,78 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <paths.h>
 5+#include <pwd.h>
 6+#include <stdio.h>
 7+#include <stdlib.h>
 8+#include <string.h>
 9+#include <time.h>
10+#include <utmp.h>
11+
12+#include "text.h"
13+#include "util.h"
14+
15+#define PASSWD   "/etc/passwd"
16+
17+static FILE *last;
18+
19+static void
20+lastlog(char *user)
21+{
22+	struct passwd *pwd;
23+	struct lastlog ll;
24+	time_t lltime;
25+
26+	errno = 0;
27+	if ((pwd = getpwnam(user)) == NULL) {
28+		if (errno)
29+			weprintf("getpwnam %s:", user);
30+		else
31+			weprintf("unknown user: %s\n", user);
32+		return;
33+	}
34+
35+	fseek(last, pwd->pw_uid * sizeof(struct lastlog), 0);
36+	fread(&ll, sizeof(struct lastlog), 1, last);
37+
38+	if (ferror(last))
39+		eprintf("%s: read error:", _PATH_LASTLOG);
40+
41+	/* on glibc `ll_time' can be an int32_t with compat32
42+	 * avoid compiler warning when calling ctime() */
43+	lltime = ll.ll_time;
44+	printf("%-8.8s %-8.8s %-16.16s %s",
45+	       user, ll.ll_line, ll.ll_host, ctime(&lltime));
46+}
47+
48+int
49+main(int argc, char **argv)
50+{
51+	FILE *fp;
52+	char *line = NULL, *p;
53+	size_t sz = 0;
54+
55+	if ((last = fopen(_PATH_LASTLOG, "r")) == NULL)
56+		eprintf("fopen %s:", _PATH_LASTLOG);
57+
58+	if (argc > 1) {
59+		while (*++argv)
60+			lastlog(*argv);
61+	} else {
62+		if ((fp = fopen(PASSWD, "r")) == NULL)
63+			eprintf("fopen %s:", PASSWD);
64+		while (agetline(&line, &sz, fp) != -1) {
65+			if ((p = strchr(line, ':')) == NULL)
66+				eprintf("invalid passwd entry\n");
67+			*p = '\0';
68+			lastlog(line);
69+		}
70+		if (fclose(fp))
71+			eprintf("fclose %s:", PASSWD);
72+		free(line);
73+	}
74+
75+	if (fclose(last))
76+		eprintf("fclose %s:", _PATH_LASTLOG);
77+
78+	return 0;
79+}
+130, -0
  1@@ -0,0 +1,130 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/ioctl.h>
  4+#include <sys/types.h>
  5+
  6+#include <errno.h>
  7+#include <grp.h>
  8+#include <pwd.h>
  9+#include <stdio.h>
 10+#include <stdlib.h>
 11+#include <string.h>
 12+#include <time.h>
 13+#include <unistd.h>
 14+#include <utmp.h>
 15+
 16+#include "config.h"
 17+#include "passwd.h"
 18+#include "util.h"
 19+
 20+/* Write utmp entry */
 21+static void
 22+writeutmp(const char *user, const char *tty)
 23+{
 24+	struct utmp usr;
 25+	FILE *fp;
 26+
 27+	memset(&usr, 0, sizeof(usr));
 28+
 29+	usr.ut_type = USER_PROCESS;
 30+	usr.ut_pid = getpid();
 31+	strlcpy(usr.ut_user, user, sizeof(usr.ut_user));
 32+	strlcpy(usr.ut_line, tty, sizeof(usr.ut_line));
 33+	usr.ut_tv.tv_sec = time(NULL);
 34+
 35+	fp = fopen(UTMP_PATH, "a");
 36+	if (fp) {
 37+		if (fwrite(&usr, sizeof(usr), 1, fp) != 1)
 38+			if (ferror(fp))
 39+				weprintf("%s: write error:", UTMP_PATH);
 40+		fclose(fp);
 41+	} else {
 42+		weprintf("fopen %s:", UTMP_PATH);
 43+	}
 44+}
 45+
 46+static int
 47+dologin(struct passwd *pw, int preserve)
 48+{
 49+	char *shell = pw->pw_shell[0] == '\0' ? "/bin/sh" : pw->pw_shell;
 50+
 51+	if (preserve == 0)
 52+		clearenv();
 53+	setenv("HOME", pw->pw_dir, 1);
 54+	setenv("SHELL", shell, 1);
 55+	setenv("USER", pw->pw_name, 1);
 56+	setenv("LOGNAME", pw->pw_name, 1);
 57+	setenv("PATH", ENV_PATH, 1);
 58+	if (chdir(pw->pw_dir) < 0)
 59+		eprintf("chdir %s:", pw->pw_dir);
 60+	execlp(shell, shell, "-l", NULL);
 61+	weprintf("execlp %s:", shell);
 62+	return (errno == ENOENT) ? 127 : 126;
 63+}
 64+
 65+static void
 66+usage(void)
 67+{
 68+	eprintf("usage: %s [-p] username\n", argv0);
 69+}
 70+
 71+int
 72+main(int argc, char *argv[])
 73+{
 74+	struct passwd *pw;
 75+	char *pass, *user;
 76+	char *tty;
 77+	uid_t uid;
 78+	gid_t gid;
 79+	int pflag = 0;
 80+
 81+	ARGBEGIN {
 82+	case 'p':
 83+		pflag = 1;
 84+		break;
 85+	default:
 86+		usage();
 87+	} ARGEND;
 88+
 89+	if (argc < 1)
 90+		usage();
 91+
 92+	if (isatty(0) == 0 || isatty(1) == 0 || isatty(2) == 0)
 93+		eprintf("no tty");
 94+
 95+	user = argv[0];
 96+	errno = 0;
 97+	pw = getpwnam(user);
 98+	if (!pw) {
 99+		if (errno)
100+			eprintf("getpwnam %s:", user);
101+		else
102+			eprintf("who are you?\n");
103+	}
104+
105+	uid = pw->pw_uid;
106+	gid = pw->pw_gid;
107+
108+	/* Flush pending input */
109+	ioctl(0, TCFLSH, (void *)0);
110+
111+	pass = getpass("Password: ");
112+	if (!pass)
113+		eprintf("getpass:");
114+	if (pw_check(pw, pass) <= 0)
115+		exit(1);
116+
117+	tty = ttyname(0);
118+	if (!tty)
119+		eprintf("ttyname:");
120+
121+	writeutmp(user, tty);
122+
123+	if (initgroups(user, gid) < 0)
124+		eprintf("initgroups:");
125+	if (setgid(gid) < 0)
126+		eprintf("setgid:");
127+	if (setuid(uid) < 0)
128+		eprintf("setuid:");
129+
130+	return dologin(pw, pflag);
131+}
+46, -0
 1@@ -0,0 +1,46 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <stdlib.h>
 5+#include <stdint.h>
 6+
 7+#include "crypt.h"
 8+#include "md5.h"
 9+#include "util.h"
10+
11+static struct md5 s;
12+struct crypt_ops md5_ops = {
13+	md5_init,
14+	md5_update,
15+	md5_sum,
16+	&s,
17+};
18+
19+static void
20+usage(void)
21+{
22+	eprintf("usage: %s [-c] [file ...]\n", argv0);
23+}
24+
25+int
26+main(int argc, char *argv[])
27+{
28+	int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
29+	uint8_t md[MD5_DIGEST_LENGTH];
30+
31+	ARGBEGIN {
32+	case 'b':
33+	case 't':
34+		/* ignore */
35+		break;
36+	case 'c':
37+		cryptfunc = cryptcheck;
38+		break;
39+	default:
40+		usage();
41+	} ARGEND
42+
43+	ret |= cryptfunc(argc, argv, &md5_ops, md, sizeof(md));
44+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
45+
46+	return ret;
47+}
+92, -0
 1@@ -0,0 +1,92 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <libgen.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <string.h>
 7+#include <unistd.h>
 8+
 9+#include "util.h"
10+
11+static void
12+usage(void)
13+{
14+	eprintf("usage: %s [-dqtu] [-p directory] [template]\n", argv0);
15+}
16+
17+int
18+main(int argc, char *argv[])
19+{
20+	int dflag = 0, pflag = 0, qflag = 0, tflag = 0, uflag = 0, fd;
21+	char *template = "tmp.XXXXXXXXXX", *tmpdir = "", *pdir,
22+	     *p, path[PATH_MAX], tmp[PATH_MAX];
23+	size_t len;
24+
25+	ARGBEGIN {
26+	case 'd':
27+		dflag = 1;
28+		break;
29+	case 'p':
30+		pflag = 1;
31+		pdir = EARGF(usage());
32+		break;
33+	case 'q':
34+		qflag = 1;
35+		break;
36+	case 't':
37+		tflag = 1;
38+		break;
39+	case 'u':
40+		uflag = 1;
41+		break;
42+	default:
43+		usage();
44+	} ARGEND
45+
46+	if (argc > 1)
47+		usage();
48+	else if (argc == 1)
49+		template = argv[0];
50+
51+	if (!argc || pflag || tflag) {
52+		if ((p = getenv("TMPDIR")))
53+			tmpdir = p;
54+		else if (pflag)
55+			tmpdir = pdir;
56+		else
57+			tmpdir = "/tmp";
58+	}
59+
60+	len = estrlcpy(path, tmpdir, sizeof(path));
61+	if (path[0] && path[len - 1] != '/')
62+		estrlcat(path, "/", sizeof(path));
63+
64+	estrlcpy(tmp, template, sizeof(tmp));
65+	p = dirname(tmp);
66+	if (!(p[0] == '.' && p[1] == '\0')) {
67+		if (tflag && !pflag)
68+			eprintf("template must not contain directory separators in -t mode\n");
69+	}
70+	estrlcat(path, template, sizeof(path));
71+
72+	if (dflag) {
73+		if (!mkdtemp(path)) {
74+			if (!qflag)
75+				eprintf("mkdtemp %s:", path);
76+			return 1;
77+		}
78+	} else {
79+		if ((fd = mkstemp(path)) < 0) {
80+			if (!qflag)
81+				eprintf("mkstemp %s:", path);
82+			return 1;
83+		}
84+		if (close(fd))
85+			eprintf("close %s:", path);
86+	}
87+	if (uflag)
88+		unlink(path);
89+	puts(path);
90+
91+	efshut(stdout, "<stdout>");
92+	return 0;
93+}
+22, -0
 1@@ -0,0 +1,22 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <fcntl.h>
 4+#include <stdio.h>
 5+#include <unistd.h>
 6+
 7+int
 8+main(void)
 9+{
10+	int fd;
11+	char buf[BUFSIZ];
12+	ssize_t n;
13+
14+	fd = open("/etc/nologin.txt", O_RDONLY);
15+	if (fd >= 0) {
16+		while ((n = read(fd, buf, sizeof(buf))) > 0)
17+			write(STDOUT_FILENO, buf, n);
18+		close(fd);
19+	} else {
20+		printf("The account is currently unavailable.\n");
21+	}
22+	return 1;
23+}
+32, -0
 1@@ -0,0 +1,32 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <stdlib.h>
 5+#include <unistd.h>
 6+
 7+#include "util.h"
 8+
 9+static void
10+usage(void)
11+{
12+	eprintf("usage: %s\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+	long pagesz;
19+
20+	ARGBEGIN {
21+	default:
22+		usage();
23+	} ARGEND;
24+
25+	pagesz = sysconf(_SC_PAGESIZE);
26+	if (pagesz <= 0) {
27+		pagesz = sysconf(_SC_PAGE_SIZE);
28+		if (pagesz <= 0)
29+			eprintf("can't determine pagesize\n");
30+	}
31+	printf("%ld\n", pagesz);
32+	return 0;
33+}
+39, -0
 1@@ -0,0 +1,39 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <stdlib.h>
 5+
 6+#include "util.h"
 7+
 8+extern char **environ;
 9+
10+static void
11+usage(void)
12+{
13+	eprintf("usage: %s [var ...]\n", argv0);
14+}
15+
16+int
17+main(int argc, char *argv[])
18+{
19+	char *var;
20+	int ret = 0;
21+
22+	ARGBEGIN {
23+	default:
24+		usage();
25+	} ARGEND
26+
27+	if (!argc) {
28+		for (; *environ; environ++)
29+			puts(*environ);
30+	} else {
31+		for (; *argv; argc--, argv++) {
32+			if ((var = getenv(*argv)))
33+				puts(var);
34+			else
35+				ret = 1;
36+		}
37+	}
38+
39+	return fshut(stdout, "<stdout>") ? 2 : ret;
40+}
+113, -0
  1@@ -0,0 +1,113 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+#include <sys/time.h>
  5+#include <sys/types.h>
  6+#include <sys/wait.h>
  7+
  8+#include <errno.h>
  9+#include <fcntl.h>
 10+#include <poll.h>
 11+#include <signal.h>
 12+#include <stdio.h>
 13+#include <stdlib.h>
 14+#include <unistd.h>
 15+
 16+#include "util.h"
 17+
 18+static void
 19+sigterm(int sig)
 20+{
 21+	if (sig == SIGTERM) {
 22+		kill(0, SIGTERM);
 23+		_exit(0);
 24+	}
 25+}
 26+
 27+static void
 28+usage(void)
 29+{
 30+	eprintf("usage: %s [-l fifo] [-d N] cmd [args...]\n", argv0);
 31+}
 32+
 33+int
 34+main(int argc, char *argv[])
 35+{
 36+	char *fifo = NULL;
 37+	unsigned int delay = 0;
 38+	pid_t pid;
 39+	char buf[BUFSIZ];
 40+	int savederrno;
 41+	ssize_t n;
 42+	struct pollfd pollset[1];
 43+	int polln;
 44+
 45+	ARGBEGIN {
 46+	case 'd':
 47+		delay = estrtol(EARGF(usage()), 0);
 48+		break;
 49+	case 'l':
 50+		fifo = EARGF(usage());
 51+		break;
 52+	default:
 53+		usage();
 54+	} ARGEND;
 55+
 56+	if (argc < 1)
 57+		usage();
 58+
 59+	if (fifo && delay > 0)
 60+		usage();
 61+
 62+	setsid();
 63+
 64+	signal(SIGTERM, sigterm);
 65+
 66+	if (fifo) {
 67+		pollset->fd = open(fifo, O_RDONLY | O_NONBLOCK);
 68+		if (pollset->fd < 0)
 69+			eprintf("open %s:", fifo);
 70+		pollset->events = POLLIN;
 71+	}
 72+
 73+	while (1) {
 74+		if (fifo) {
 75+			pollset->revents = 0;
 76+			polln = poll(pollset, 1, -1);
 77+			if (polln <= 0) {
 78+				if (polln == 0 || errno == EAGAIN)
 79+					continue;
 80+				eprintf("poll:");
 81+			}
 82+			while ((n = read(pollset->fd, buf, sizeof(buf))) > 0)
 83+				;
 84+			if (n < 0)
 85+				if (errno != EAGAIN)
 86+					eprintf("read %s:", fifo);
 87+			if (n == 0) {
 88+				close(pollset->fd);
 89+				pollset->fd = open(fifo, O_RDONLY | O_NONBLOCK);
 90+				if (pollset->fd < 0)
 91+					eprintf("open %s:", fifo);
 92+				pollset->events = POLLIN;
 93+			}
 94+		}
 95+		pid = fork();
 96+		if (pid < 0)
 97+			eprintf("fork:");
 98+		switch (pid) {
 99+		case 0:
100+			execvp(argv[0], argv);
101+			savederrno = errno;
102+			weprintf("execvp %s:", argv[0]);
103+			_exit(savederrno == ENOENT ? 127 : 126);
104+			break;
105+		default:
106+			waitpid(pid, NULL, 0);
107+			break;
108+		}
109+		if (!fifo)
110+			sleep(delay);
111+	}
112+	/* not reachable */
113+	return 0;
114+}
+74, -0
 1@@ -0,0 +1,74 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <string.h>
 5+#include <unistd.h>
 6+
 7+#include "text.h"
 8+#include "util.h"
 9+
10+static void
11+usage(void)
12+{
13+	eprintf("usage: %s [file ...]\n", argv0);
14+}
15+
16+static void
17+rev(FILE *fp)
18+{
19+	static char *line = NULL;
20+	static size_t size = 0;
21+	size_t i;
22+	ssize_t n;
23+	int lf;
24+
25+	while ((n = getline(&line, &size, fp)) > 0) {
26+		lf = n && line[n - 1] == '\n';
27+		i = n -= lf;
28+		for (n = 0; i--;) {
29+			if (UTF8_POINT(line[i])) {
30+				n++;
31+			} else {
32+				fwrite(line + i, 1, n + 1, stdout);
33+				n = 0;
34+			}
35+		}
36+		if (n)
37+			fwrite(line, 1, n, stdout);
38+		if (lf)
39+			fputc('\n', stdout);
40+	}
41+}
42+
43+int
44+main(int argc, char *argv[])
45+{
46+	FILE *fp;
47+	int ret = 0;
48+
49+	ARGBEGIN {
50+	default:
51+		usage();
52+	} ARGEND
53+
54+	if (!argc) {
55+		rev(stdin);
56+	} else {
57+		for (; *argv; argc--, argv++) {
58+			if (!strcmp(*argv, "-")) {
59+				*argv = "<stdin>";
60+				fp = stdin;
61+			} else if (!(fp = fopen(*argv, "r"))) {
62+				weprintf("fopen %s:", *argv);
63+				ret = 1;
64+				continue;
65+			}
66+			rev(fp);
67+			if (fp != stdin && fshut(fp, *argv))
68+				ret = 1;
69+		}
70+	}
71+
72+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
73+
74+	return ret;
75+}
+147, -0
  1@@ -0,0 +1,147 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <stdio.h>
  4+#include <stdlib.h>
  5+#include <string.h>
  6+
  7+#include "util.h"
  8+
  9+static int
 10+digitsleft(const char *d)
 11+{
 12+	int shift;
 13+	char *exp;
 14+
 15+	if (*d == '+')
 16+		d++;
 17+	exp = strpbrk(d, "eE");
 18+	shift = exp ? estrtonum(exp + 1, INT_MIN, INT_MAX) : 0;
 19+
 20+	return MAX(0, strspn(d, "-0123456789") + shift);
 21+}
 22+
 23+static int
 24+digitsright(const char *d)
 25+{
 26+	int shift, after;
 27+	char *exp;
 28+
 29+	exp = strpbrk(d, "eE");
 30+	shift = exp ? estrtonum(&exp[1], INT_MIN, INT_MAX) : 0;
 31+	after = (d = strchr(d, '.')) ? strspn(&d[1], "0123456789") : 0;
 32+
 33+	return MAX(0, after - shift);
 34+}
 35+
 36+static int
 37+validfmt(const char *fmt)
 38+{
 39+	int occur = 0;
 40+
 41+literal:
 42+	while (*fmt)
 43+		if (*fmt++ == '%')
 44+			goto format;
 45+	return occur == 1;
 46+
 47+format:
 48+	if (*fmt == '%') {
 49+		fmt++;
 50+		goto literal;
 51+	}
 52+	fmt += strspn(fmt, "-+#0 '");
 53+	fmt += strspn(fmt, "0123456789");
 54+	if (*fmt == '.') {
 55+		fmt++;
 56+		fmt += strspn(fmt, "0123456789");
 57+	}
 58+	if (*fmt == 'L')
 59+		fmt++;
 60+
 61+	switch (*fmt) {
 62+	case 'f': case 'F':
 63+	case 'g': case 'G':
 64+	case 'e': case 'E':
 65+	case 'a': case 'A':
 66+		occur++;
 67+		goto literal;
 68+	default:
 69+		return 0;
 70+	}
 71+}
 72+
 73+static void
 74+usage(void)
 75+{
 76+	eprintf("usage: %s [-f fmt] [-s sep] [-w] "
 77+	        "[startnum [step]] endnum\n", argv0);
 78+}
 79+
 80+int
 81+main(int argc, char *argv[])
 82+{
 83+	double start, step, end, out, dir;
 84+	int wflag = 0, left, right;
 85+	char *tmp, ftmp[BUFSIZ], *fmt = ftmp;
 86+	const char *starts = "1", *steps = "1", *ends = "1", *sep = "\n";
 87+
 88+	ARGBEGIN {
 89+	case 'f':
 90+		if (!validfmt(tmp=EARGF(usage())))
 91+			eprintf("%s: invalid format\n", tmp);
 92+		fmt = tmp;
 93+		break;
 94+	case 's':
 95+		sep = EARGF(usage());
 96+		break;
 97+	case 'w':
 98+		wflag = 1;
 99+		break;
100+	default:
101+		usage();
102+	} ARGEND
103+
104+	switch (argc) {
105+	case 3:
106+		steps = argv[1];
107+		argv[1] = argv[2];
108+		/* fallthrough */
109+	case 2:
110+		starts = argv[0];
111+		argv++;
112+		/* fallthrough */
113+	case 1:
114+		ends = argv[0];
115+		break;
116+	default:
117+		usage();
118+	}
119+	start = estrtod(starts);
120+	step  = estrtod(steps);
121+	end   = estrtod(ends);
122+
123+	dir = (step > 0) ? 1.0 : -1.0;
124+	if (step == 0 || start * dir > end * dir)
125+		return 1;
126+
127+	if (fmt == ftmp) {
128+		right = MAX(digitsright(starts),
129+		            MAX(digitsright(ends),
130+		                digitsright(steps)));
131+
132+		if (wflag) {
133+			left = MAX(digitsleft(starts), digitsleft(ends));
134+
135+			snprintf(ftmp, sizeof ftmp, "%%0%d.%df",
136+					right + left + (right != 0), right);
137+		} else
138+			snprintf(ftmp, sizeof ftmp, "%%.%df", right);
139+	}
140+	for (out = start; out * dir <= end * dir; out += step) {
141+		if (out != start)
142+			fputs(sep, stdout);
143+		printf(fmt, out);
144+	}
145+	putchar('\n');
146+
147+	return fshut(stdout, "<stdout>");
148+}
+48, -0
 1@@ -0,0 +1,48 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <unistd.h>
 5+
 6+#include "util.h"
 7+
 8+static int fflag = 0;
 9+
10+static void
11+usage(void)
12+{
13+	eprintf("usage: %s [-f] cmd [arg ...]\n", argv0);
14+}
15+
16+int
17+main(int argc, char *argv[])
18+{
19+	int savederrno;
20+
21+	ARGBEGIN {
22+	case 'f':
23+		fflag = 1;
24+		break;
25+	default:
26+		usage();
27+	} ARGEND
28+
29+	if (!argc)
30+		usage();
31+
32+	if (fflag || getpgrp() == getpid()) {
33+		switch (fork()) {
34+		case -1:
35+			eprintf("fork:");
36+		case 0:
37+			break;
38+		default:
39+			return 0;
40+		}
41+	}
42+	if (setsid() < 0)
43+		eprintf("setsid:");
44+	execvp(argv[0], argv);
45+	savederrno = errno;
46+	weprintf("execvp %s:", argv[0]);
47+
48+	_exit(126 + (savederrno == ENOENT));
49+}
+45, -0
 1@@ -0,0 +1,45 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdint.h>
 4+#include <stdio.h>
 5+
 6+#include "crypt.h"
 7+#include "sha1.h"
 8+#include "util.h"
 9+
10+static struct sha1 s;
11+struct crypt_ops sha1_ops = {
12+	sha1_init,
13+	sha1_update,
14+	sha1_sum,
15+	&s,
16+};
17+
18+static void
19+usage(void)
20+{
21+	eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+	int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+	uint8_t md[SHA1_DIGEST_LENGTH];
29+
30+	ARGBEGIN {
31+	case 'b':
32+	case 't':
33+		/* ignore */
34+		break;
35+	case 'c':
36+		cryptfunc = cryptcheck;
37+		break;
38+	default:
39+		usage();
40+	} ARGEND
41+
42+	ret |= cryptfunc(argc, argv, &sha1_ops, md, sizeof(md));
43+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+	return ret;
46+}
+45, -0
 1@@ -0,0 +1,45 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdint.h>
 4+#include <stdio.h>
 5+
 6+#include "crypt.h"
 7+#include "sha224.h"
 8+#include "util.h"
 9+
10+static struct sha224 s;
11+struct crypt_ops sha224_ops = {
12+	sha224_init,
13+	sha224_update,
14+	sha224_sum,
15+	&s,
16+};
17+
18+static void
19+usage(void)
20+{
21+	eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+	int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+	uint8_t md[SHA224_DIGEST_LENGTH];
29+
30+	ARGBEGIN {
31+	case 'b':
32+	case 't':
33+		/* ignore */
34+		break;
35+	case 'c':
36+		cryptfunc = cryptcheck;
37+		break;
38+	default:
39+		usage();
40+	} ARGEND
41+
42+	ret |= cryptfunc(argc, argv, &sha224_ops, md, sizeof(md));
43+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+	return ret;
46+}
+45, -0
 1@@ -0,0 +1,45 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdint.h>
 4+#include <stdio.h>
 5+
 6+#include "crypt.h"
 7+#include "sha256.h"
 8+#include "util.h"
 9+
10+static struct sha256 s;
11+struct crypt_ops sha256_ops = {
12+	sha256_init,
13+	sha256_update,
14+	sha256_sum,
15+	&s,
16+};
17+
18+static void
19+usage(void)
20+{
21+	eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+	int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+	uint8_t md[SHA256_DIGEST_LENGTH];
29+
30+	ARGBEGIN {
31+	case 'b':
32+	case 't':
33+		/* ignore */
34+		break;
35+	case 'c':
36+		cryptfunc = cryptcheck;
37+		break;
38+	default:
39+		usage();
40+	} ARGEND
41+
42+	ret |= cryptfunc(argc, argv, &sha256_ops, md, sizeof(md));
43+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+	return ret;
46+}
+45, -0
 1@@ -0,0 +1,45 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdint.h>
 4+#include <stdio.h>
 5+
 6+#include "crypt.h"
 7+#include "sha384.h"
 8+#include "util.h"
 9+
10+static struct sha384 s;
11+struct crypt_ops sha384_ops = {
12+	sha384_init,
13+	sha384_update,
14+	sha384_sum,
15+	&s,
16+};
17+
18+static void
19+usage(void)
20+{
21+	eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+	int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+	uint8_t md[SHA384_DIGEST_LENGTH];
29+
30+	ARGBEGIN {
31+	case 'b':
32+	case 't':
33+		/* ignore */
34+		break;
35+	case 'c':
36+		cryptfunc = cryptcheck;
37+		break;
38+	default:
39+		usage();
40+	} ARGEND
41+
42+	ret |= cryptfunc(argc, argv, &sha384_ops, md, sizeof(md));
43+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+	return ret;
46+}
+45, -0
 1@@ -0,0 +1,45 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdint.h>
 4+#include <stdio.h>
 5+
 6+#include "crypt.h"
 7+#include "sha512-224.h"
 8+#include "util.h"
 9+
10+static struct sha512_224 s;
11+struct crypt_ops sha512_224_ops = {
12+	sha512_224_init,
13+	sha512_224_update,
14+	sha512_224_sum,
15+	&s,
16+};
17+
18+static void
19+usage(void)
20+{
21+	eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+	int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+	uint8_t md[SHA512_224_DIGEST_LENGTH];
29+
30+	ARGBEGIN {
31+	case 'b':
32+	case 't':
33+		/* ignore */
34+		break;
35+	case 'c':
36+		cryptfunc = cryptcheck;
37+		break;
38+	default:
39+		usage();
40+	} ARGEND
41+
42+	ret |= cryptfunc(argc, argv, &sha512_224_ops, md, sizeof(md));
43+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+	return ret;
46+}
+45, -0
 1@@ -0,0 +1,45 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdint.h>
 4+#include <stdio.h>
 5+
 6+#include "crypt.h"
 7+#include "sha512-256.h"
 8+#include "util.h"
 9+
10+static struct sha512_256 s;
11+struct crypt_ops sha512_256_ops = {
12+	sha512_256_init,
13+	sha512_256_update,
14+	sha512_256_sum,
15+	&s,
16+};
17+
18+static void
19+usage(void)
20+{
21+	eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+	int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+	uint8_t md[SHA512_256_DIGEST_LENGTH];
29+
30+	ARGBEGIN {
31+	case 'b':
32+	case 't':
33+		/* ignore */
34+		break;
35+	case 'c':
36+		cryptfunc = cryptcheck;
37+		break;
38+	default:
39+		usage();
40+	} ARGEND
41+
42+	ret |= cryptfunc(argc, argv, &sha512_256_ops, md, sizeof(md));
43+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+	return ret;
46+}
+45, -0
 1@@ -0,0 +1,45 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdint.h>
 4+#include <stdio.h>
 5+
 6+#include "crypt.h"
 7+#include "sha512.h"
 8+#include "util.h"
 9+
10+static struct sha512 s;
11+struct crypt_ops sha512_ops = {
12+	sha512_init,
13+	sha512_update,
14+	sha512_sum,
15+	&s,
16+};
17+
18+static void
19+usage(void)
20+{
21+	eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+	int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+	uint8_t md[SHA512_DIGEST_LENGTH];
29+
30+	ARGBEGIN {
31+	case 'b':
32+	case 't':
33+		/* ignore */
34+		break;
35+	case 'c':
36+		cryptfunc = cryptcheck;
37+		break;
38+	default:
39+		usage();
40+	} ARGEND
41+
42+	ret |= cryptfunc(argc, argv, &sha512_ops, md, sizeof(md));
43+	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+	return ret;
46+}
+42, -0
 1@@ -0,0 +1,42 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <fcntl.h>
 4+#include <stdlib.h>
 5+#include <unistd.h>
 6+
 7+#include "util.h"
 8+
 9+static void
10+usage(void)
11+{
12+	eprintf("usage: %s file\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+	char tmp[] = "/tmp/sponge-XXXXXX";
19+	int fd, tmpfd;
20+
21+	ARGBEGIN {
22+	default:
23+		usage();
24+	} ARGEND
25+
26+	if (argc != 1)
27+		usage();
28+
29+	if ((tmpfd = mkstemp(tmp)) < 0)
30+		eprintf("mkstemp:");
31+	unlink(tmp);
32+	if (concat(0, "<stdin>", tmpfd, "<tmpfile>") < 0)
33+		return 1;
34+	if (lseek(tmpfd, 0, SEEK_SET) < 0)
35+		eprintf("lseek:");
36+
37+	if ((fd = creat(argv[0], 0666)) < 0)
38+		eprintf("creat %s:", argv[0]);
39+	if (concat(tmpfd, "<tmpfile>", fd, argv[0]) < 0)
40+		return 1;
41+
42+	return 0;
43+}
+90, -0
 1@@ -0,0 +1,90 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+#include <sys/sysmacros.h>
 5+#include <sys/types.h>
 6+
 7+#include <inttypes.h>
 8+#include <stdio.h>
 9+#include <stdlib.h>
10+#include <time.h>
11+#include <unistd.h>
12+
13+#include "util.h"
14+
15+static void
16+show_stat_terse(const char *file, struct stat *st)
17+{
18+	printf("%s ", file);
19+	printf("%lu %lu ", (unsigned long)st->st_size,
20+	       (unsigned long)st->st_blocks);
21+	printf("%04o %u %u ", st->st_mode & 0777, st->st_uid, st->st_gid);
22+	printf("%llx ", (unsigned long long)st->st_dev);
23+	printf("%lu %lu ", (unsigned long)st->st_ino, (unsigned long)st->st_nlink);
24+	printf("%d %d ", major(st->st_rdev), minor(st->st_rdev));
25+	printf("%ld %ld %ld ", st->st_atime, st->st_mtime, st->st_ctime);
26+	printf("%lu\n", (unsigned long)st->st_blksize);
27+}
28+
29+static void
30+show_stat(const char *file, struct stat *st)
31+{
32+	char buf[100];
33+
34+	printf("  File: ‘%s’\n", file);
35+	printf("  Size: %lu\tBlocks: %lu\tIO Block: %lu\n", (unsigned long)st->st_size,
36+	       (unsigned long)st->st_blocks, (unsigned long)st->st_blksize);
37+	printf("Device: %xh/%ud\tInode: %lu\tLinks %lu\n", major(st->st_dev),
38+	       minor(st->st_dev), (unsigned long)st->st_ino, (unsigned long)st->st_nlink);
39+	printf("Access: %04o\tUid: %u\tGid: %u\n", st->st_mode & 0777, st->st_uid, st->st_gid);
40+	strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&st->st_atime));
41+	printf("Access: %s\n", buf);
42+	strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&st->st_mtime));
43+	printf("Modify: %s\n", buf);
44+	strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&st->st_ctime));
45+	printf("Change: %s\n", buf);
46+}
47+
48+static void
49+usage(void)
50+{
51+	eprintf("usage: %s [-L] [-t] [file...]\n", argv0);
52+}
53+
54+int
55+main(int argc, char *argv[])
56+{
57+	struct stat st;
58+	int i, ret = 0;
59+	int (*fn)(const char *, struct stat *) = lstat;
60+	char *fnname = "lstat";
61+	void (*showstat)(const char *, struct stat *) = show_stat;
62+
63+	ARGBEGIN {
64+	case 'L':
65+		fn = stat;
66+		fnname = "stat";
67+		break;
68+	case 't':
69+		showstat = show_stat_terse;
70+		break;
71+	default:
72+		usage();
73+	} ARGEND;
74+
75+	if (argc == 0) {
76+		if (fstat(0, &st) < 0)
77+			eprintf("stat <stdin>:");
78+		show_stat("<stdin>", &st);
79+	}
80+
81+	for (i = 0; i < argc; i++) {
82+		if (fn(argv[i], &st) == -1) {
83+			weprintf("%s %s:", fnname, argv[i]);
84+			ret = 1;
85+			continue;
86+		}
87+		showstat(argv[i], &st);
88+	}
89+
90+	return ret;
91+}
+697, -0
  1@@ -0,0 +1,697 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+#include <sys/time.h>
  5+#include <sys/types.h>
  6+#ifndef major
  7+#include <sys/sysmacros.h>
  8+#endif
  9+
 10+#include <assert.h>
 11+#include <errno.h>
 12+#include <fcntl.h>
 13+#include <grp.h>
 14+#include <libgen.h>
 15+#include <pwd.h>
 16+#include <stdio.h>
 17+#include <stdlib.h>
 18+#include <string.h>
 19+#include <unistd.h>
 20+
 21+#include "fs.h"
 22+#include "utf.h"
 23+#include "util.h"
 24+
 25+#ifdef STD_NON_POSIX
 26+static void
 27+safe_puts(const char *s)
 28+{
 29+	Rune r;
 30+	int n;
 31+
 32+	if (isatty(1)) {
 33+		while (*s) {
 34+			n = chartorune(&r, s);
 35+			if (r == Runeerror) {
 36+				putchar('?');
 37+				s++;
 38+			} else if (isprintrune(r)) {
 39+				fputrune(&r, stdout);
 40+				s += n;
 41+			} else {
 42+				putchar('?');
 43+				s += n;
 44+			}
 45+		}
 46+		putchar('\n');
 47+	} else {
 48+		puts(s);
 49+	}
 50+}
 51+#else
 52+#define safe_puts(s) puts(s)
 53+#endif
 54+
 55+#define BLKSIZ (sizeof (struct header)) /* must equal 512 bytes */
 56+
 57+enum Type {
 58+	REG       = '0',
 59+	AREG      = '\0',
 60+	HARDLINK  = '1',
 61+	SYMLINK   = '2',
 62+	CHARDEV   = '3',
 63+	BLOCKDEV  = '4',
 64+	DIRECTORY = '5',
 65+	FIFO      = '6',
 66+	RESERVED  = '7'
 67+};
 68+
 69+struct header {
 70+	char name[100];
 71+	char mode[8];
 72+	char uid[8];
 73+	char gid[8];
 74+	char size[12];
 75+	char mtime[12];
 76+	char chksum[8];
 77+	char type;
 78+	char linkname[100];
 79+	char magic[6];
 80+	char version[2];
 81+	char uname[32];
 82+	char gname[32];
 83+	char major[8];
 84+	char minor[8];
 85+	char prefix[155];
 86+	char padding[12];
 87+};
 88+
 89+static struct dirtime {
 90+	char *name;
 91+	time_t mtime;
 92+} *dirtimes;
 93+
 94+static size_t dirtimeslen;
 95+
 96+static int tarfd;
 97+static ino_t tarinode;
 98+static dev_t tardev;
 99+
100+static int mflag, vflag;
101+static int filtermode;
102+static const char *filtertool;
103+
104+static const char *filtertools[] = {
105+	['J'] = "xz",
106+	['Z'] = "compress",
107+	['a'] = "lzma",
108+	['j'] = "bzip2",
109+	['z'] = "gzip",
110+};
111+
112+static void
113+pushdirtime(char *name, time_t mtime)
114+{
115+	dirtimes = ereallocarray(dirtimes, dirtimeslen + 1, sizeof(*dirtimes));
116+	dirtimes[dirtimeslen].name = estrdup(name);
117+	dirtimes[dirtimeslen].mtime = mtime;
118+	dirtimeslen++;
119+}
120+
121+static struct dirtime *
122+popdirtime(void)
123+{
124+	if (dirtimeslen) {
125+		dirtimeslen--;
126+		return &dirtimes[dirtimeslen];
127+	}
128+	return NULL;
129+}
130+
131+static int
132+comp(int fd, const char *tool, const char *flags)
133+{
134+	int fds[2];
135+
136+	if (pipe(fds) < 0)
137+		eprintf("pipe:");
138+
139+	switch (fork()) {
140+	case -1:
141+		eprintf("fork:");
142+	case 0:
143+		dup2(fd, 1);
144+		dup2(fds[0], 0);
145+		close(fds[0]);
146+		close(fds[1]);
147+
148+		execlp(tool, tool, flags, NULL);
149+		weprintf("execlp %s:", tool);
150+		_exit(1);
151+	}
152+	close(fds[0]);
153+	return fds[1];
154+}
155+
156+static int
157+decomp(int fd, const char *tool, const char *flags)
158+{
159+	int fds[2];
160+
161+	if (pipe(fds) < 0)
162+		eprintf("pipe:");
163+
164+	switch (fork()) {
165+	case -1:
166+		eprintf("fork:");
167+	case 0:
168+		dup2(fd, 0);
169+		dup2(fds[1], 1);
170+		close(fds[0]);
171+		close(fds[1]);
172+
173+		execlp(tool, tool, flags, NULL);
174+		weprintf("execlp %s:", tool);
175+		_exit(1);
176+	}
177+	close(fds[1]);
178+	return fds[0];
179+}
180+
181+static ssize_t
182+eread(int fd, void *buf, size_t n)
183+{
184+	ssize_t r;
185+
186+again:
187+	r = read(fd, buf, n);
188+	if (r < 0) {
189+		if (errno == EINTR)
190+			goto again;
191+		eprintf("read:");
192+	}
193+	return r;
194+}
195+
196+static ssize_t
197+ewrite(int fd, const void *buf, size_t n)
198+{
199+	ssize_t r;
200+
201+	if ((r = write(fd, buf, n)) != n)
202+		eprintf("write:");
203+	return r;
204+}
205+
206+static unsigned
207+chksum(struct header *h)
208+{
209+	unsigned sum, i;
210+
211+	memset(h->chksum, ' ', sizeof(h->chksum));
212+	for (i = 0, sum = 0, assert(BLKSIZ == 512); i < BLKSIZ; i++)
213+		sum += *((unsigned char *)h + i);
214+	return sum;
215+}
216+
217+static void
218+putoctal(char *dst, unsigned num, int size)
219+{
220+	if (snprintf(dst, size, "%.*o", size - 1, num) >= size)
221+		eprintf("putoctal: input number '%o' too large\n", num);
222+}
223+
224+static int
225+archive(const char *path)
226+{
227+	static const struct header blank = {
228+		"././@LongLink", "0000600", "0000000", "0000000", "00000000000",
229+		"00000000000"  , "       ",  AREG    , ""       , "ustar", "00",
230+	};
231+	char   b[BLKSIZ + BLKSIZ], *p;
232+	struct header *h = (struct header *)b;
233+	struct group  *gr;
234+	struct passwd *pw;
235+	struct stat st;
236+	ssize_t l, n, r;
237+	int fd = -1;
238+
239+	if (lstat(path, &st) < 0) {
240+		weprintf("lstat %s:", path);
241+		return 0;
242+	} else if (st.st_ino == tarinode && st.st_dev == tardev) {
243+		weprintf("ignoring %s\n", path);
244+		return 0;
245+	}
246+	pw = getpwuid(st.st_uid);
247+	gr = getgrgid(st.st_gid);
248+
249+	*h = blank;
250+	n  = strlcpy(h->name, path, sizeof(h->name));
251+	if (n >= sizeof(h->name)) {
252+		*++h = blank;
253+		h->type = 'L';
254+		putoctal(h->size,   n,         sizeof(h->size));
255+		putoctal(h->chksum, chksum(h), sizeof(h->chksum));
256+		ewrite(tarfd, (char *)h, BLKSIZ);
257+
258+		for (p = (char *)path; n > 0; n -= BLKSIZ, p += BLKSIZ) {
259+			if (n < BLKSIZ) {
260+				p = memcpy(h--, p, n);
261+				memset(p + n, 0, BLKSIZ - n);
262+			}
263+			ewrite(tarfd, p, BLKSIZ);
264+		}
265+	}
266+
267+	putoctal(h->mode,    (unsigned)st.st_mode & 0777, sizeof(h->mode));
268+	putoctal(h->uid,     (unsigned)st.st_uid,         sizeof(h->uid));
269+	putoctal(h->gid,     (unsigned)st.st_gid,         sizeof(h->gid));
270+	putoctal(h->mtime,   (unsigned)st.st_mtime,       sizeof(h->mtime));
271+	estrlcpy(h->uname,   pw ? pw->pw_name : "",       sizeof(h->uname));
272+	estrlcpy(h->gname,   gr ? gr->gr_name : "",       sizeof(h->gname));
273+
274+	if (S_ISREG(st.st_mode)) {
275+		h->type = REG;
276+		putoctal(h->size, st.st_size,  sizeof(h->size));
277+		fd = open(path, O_RDONLY);
278+		if (fd < 0)
279+			eprintf("open %s:", path);
280+	} else if (S_ISDIR(st.st_mode)) {
281+		h->type = DIRECTORY;
282+	} else if (S_ISLNK(st.st_mode)) {
283+		h->type = SYMLINK;
284+		if ((r = readlink(path, h->linkname, sizeof(h->linkname) - 1)) < 0)
285+			eprintf("readlink %s:", path);
286+		h->linkname[r] = '\0';
287+	} else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
288+		h->type = S_ISCHR(st.st_mode) ? CHARDEV : BLOCKDEV;
289+		putoctal(h->major, (unsigned)major(st.st_dev), sizeof(h->major));
290+		putoctal(h->minor, (unsigned)minor(st.st_dev), sizeof(h->minor));
291+	} else if (S_ISFIFO(st.st_mode)) {
292+		h->type = FIFO;
293+	}
294+
295+	putoctal(h->chksum, chksum(h), sizeof(h->chksum));
296+	ewrite(tarfd, b, BLKSIZ);
297+
298+	if (fd != -1) {
299+		while ((l = eread(fd, b, BLKSIZ)) > 0) {
300+			if (l < BLKSIZ)
301+				memset(b + l, 0, BLKSIZ - l);
302+			ewrite(tarfd, b, BLKSIZ);
303+		}
304+		close(fd);
305+	}
306+
307+	return 0;
308+}
309+
310+static int
311+unarchive(char *fname, ssize_t l, char b[BLKSIZ])
312+{
313+	struct header *h = (struct header *)b;
314+	struct timespec times[2];
315+	char lname[101], *tmp, *p;
316+	long mode, major, minor, type, mtime, uid, gid;
317+	int  fd = -1, lnk = h->type == SYMLINK;
318+
319+	if (!mflag && ((mtime = strtol(h->mtime, &p, 8)) < 0 || *p != '\0'))
320+		eprintf("strtol %s: invalid mtime\n", h->mtime);
321+	if (strcmp(fname, ".") && strcmp(fname, "./") && remove(fname) < 0)
322+		if (errno != ENOENT) weprintf("remove %s:", fname);
323+
324+	tmp = estrdup(fname);
325+	mkdirp(dirname(tmp), 0777, 0777);
326+	free(tmp);
327+
328+	switch (h->type) {
329+	case REG:
330+	case AREG:
331+	case RESERVED:
332+		if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
333+			eprintf("strtol %s: invalid mode\n", h->mode);
334+#ifdef STD_NON_POSIX
335+		fd = open(fname, O_WRONLY | O_TRUNC | O_CREAT | O_NOFOLLOW, 0600);
336+#else
337+		fd = open(fname, O_WRONLY | O_TRUNC | O_CREAT, 0600);
338+#endif
339+		if (fd < 0)
340+			eprintf("open %s:", fname);
341+		break;
342+	case HARDLINK:
343+	case SYMLINK:
344+		snprintf(lname, sizeof(lname), "%.*s", (int)sizeof(h->linkname),
345+		         h->linkname);
346+		if ((lnk ? symlink:link)(lname, fname) < 0)
347+			eprintf("%s %s -> %s:", lnk ? "symlink":"link", fname, lname);
348+		lnk++;
349+		break;
350+	case DIRECTORY:
351+		if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
352+			eprintf("strtol %s: invalid mode\n", h->mode);
353+		if (mkdir(fname, (mode_t)mode) < 0 && errno != EEXIST)
354+			eprintf("mkdir %s:", fname);
355+		pushdirtime(fname, mtime);
356+		break;
357+	case CHARDEV:
358+	case BLOCKDEV:
359+		if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
360+			eprintf("strtol %s: invalid mode\n", h->mode);
361+		if ((major = strtol(h->major, &p, 8)) < 0 || *p != '\0')
362+			eprintf("strtol %s: invalid major device\n", h->major);
363+		if ((minor = strtol(h->minor, &p, 8)) < 0 || *p != '\0')
364+			eprintf("strtol %s: invalid minor device\n", h->minor);
365+		type = (h->type == CHARDEV) ? S_IFCHR : S_IFBLK;
366+		if (mknod(fname, type | mode, makedev(major, minor)) < 0)
367+			eprintf("mknod %s:", fname);
368+		break;
369+	case FIFO:
370+		if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
371+			eprintf("strtol %s: invalid mode\n", h->mode);
372+		if (mknod(fname, S_IFIFO | mode, 0) < 0)
373+			eprintf("mknod %s:", fname);
374+		break;
375+	default:
376+		eprintf("unsupported tar-filetype %c\n", h->type);
377+	}
378+
379+	if ((uid = strtol(h->uid, &p, 8)) < 0 || *p != '\0')
380+		eprintf("strtol %s: invalid uid\n", h->uid);
381+	if ((gid = strtol(h->gid, &p, 8)) < 0 || *p != '\0')
382+		eprintf("strtol %s: invalid gid\n", h->gid);
383+
384+	if (fd != -1) {
385+		for (; l > 0; l -= BLKSIZ)
386+			if (eread(tarfd, b, BLKSIZ) > 0)
387+				ewrite(fd, b, MIN(l, BLKSIZ));
388+		close(fd);
389+	}
390+
391+	if (lnk == 1)
392+		return 0;
393+
394+	times[0].tv_sec = times[1].tv_sec = mtime;
395+	times[0].tv_nsec = times[1].tv_nsec = 0;
396+	if (!mflag && utimensat(AT_FDCWD, fname, times, AT_SYMLINK_NOFOLLOW) < 0)
397+		weprintf("utimensat %s:", fname);
398+	if (lnk) {
399+		if (!getuid() && lchown(fname, uid, gid))
400+			weprintf("lchown %s:", fname);
401+	} else {
402+		if (!getuid() && chown(fname, uid, gid))
403+			weprintf("chown %s:", fname);
404+		if (chmod(fname, mode) < 0)
405+			eprintf("fchmod %s:", fname);
406+	}
407+
408+	return 0;
409+}
410+
411+static void
412+skipblk(ssize_t l)
413+{
414+	char b[BLKSIZ];
415+
416+	for (; l > 0; l -= BLKSIZ)
417+		if (!eread(tarfd, b, BLKSIZ))
418+			break;
419+}
420+
421+static int
422+print(char *fname, ssize_t l, char b[BLKSIZ])
423+{
424+	safe_puts(fname);
425+	skipblk(l);
426+	return 0;
427+}
428+
429+static void
430+c(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
431+{
432+	archive(r->path);
433+	if (vflag)
434+		safe_puts(r->path);
435+
436+	if (S_ISDIR(st->st_mode))
437+		recurse(dirfd, name, NULL, r);
438+}
439+
440+static void
441+sanitize(struct header *h)
442+{
443+	size_t i, j, l;
444+	struct {
445+		char  *f;
446+		size_t l;
447+	} fields[] = {
448+		{ h->mode,   sizeof(h->mode)   },
449+		{ h->uid,    sizeof(h->uid)    },
450+		{ h->gid,    sizeof(h->gid)    },
451+		{ h->size,   sizeof(h->size)   },
452+		{ h->mtime,  sizeof(h->mtime)  },
453+		{ h->chksum, sizeof(h->chksum) },
454+		{ h->major,  sizeof(h->major)  },
455+		{ h->minor,  sizeof(h->minor)  }
456+	};
457+
458+	/* Numeric fields can be terminated with spaces instead of
459+	 * NULs as per the ustar specification.  Patch all of them to
460+	 * use NULs so we can perform string operations on them. */
461+	for (i = 0; i < LEN(fields); i++){
462+		j = 0, l = fields[i].l - 1;
463+		for (; j < l && fields[i].f[j] == ' '; j++);
464+		for (; j <= l; j++)
465+			if (fields[i].f[j] == ' ')
466+				fields[i].f[j] = '\0';
467+		if (fields[i].f[l])
468+			eprintf("numeric field #%d (%.*s) is not null or space terminated\n",
469+			        i, l+1, fields[i].f);
470+	}
471+}
472+
473+static void
474+chktar(struct header *h)
475+{
476+	const char *reason;
477+	char tmp[sizeof h->chksum], *err;
478+	long sum, i;
479+
480+	if (h->prefix[0] == '\0' && h->name[0] == '\0') {
481+		reason = "empty filename";
482+		goto bad;
483+	}
484+	if (h->magic[0] && strncmp("ustar", h->magic, 5)) {
485+		reason = "not ustar format";
486+		goto bad;
487+	}
488+	memcpy(tmp, h->chksum, sizeof(tmp));
489+	for (i = sizeof(tmp)-1; i > 0 && tmp[i] == ' '; i--) {
490+		tmp[i] = '\0';
491+	}
492+	sum = strtol(tmp, &err, 8);
493+	if (sum < 0 || sum >= BLKSIZ*256 || *err != '\0') {
494+		reason = "invalid checksum";
495+		goto bad;
496+	}
497+	if (sum != chksum(h)) {
498+		reason = "incorrect checksum";
499+		goto bad;
500+	}
501+	memcpy(h->chksum, tmp, sizeof(tmp));
502+	return;
503+bad:
504+	eprintf("malformed tar archive: %s\n", reason);
505+}
506+
507+static void
508+xt(int argc, char *argv[], int mode)
509+{
510+	long size;
511+	char b[BLKSIZ], fname[PATH_MAX + 1], *p, *q = NULL;
512+	int i, m, n;
513+	int (*fn)(char *, ssize_t, char[BLKSIZ]) = (mode == 'x') ? unarchive : print;
514+	struct timespec times[2];
515+	struct header *h = (struct header *)b;
516+	struct dirtime *dirtime;
517+
518+	while (eread(tarfd, b, BLKSIZ) > 0 && (h->name[0] || h->prefix[0])) {
519+		chktar(h);
520+		sanitize(h);
521+
522+		if ((size = strtol(h->size, &p, 8)) < 0 || *p != '\0')
523+			eprintf("strtol %s: invalid size\n", h->size);
524+
525+		/* Long file path is read directly into fname*/
526+		if (h->type == 'L' || h->type == 'x' || h->type == 'g') {
527+
528+			/* Read header only up to size of fname buffer */
529+			for (q = fname; q < fname+size; q += BLKSIZ) {
530+				if (q + BLKSIZ >= fname + sizeof fname)
531+					eprintf("name exceeds buffer: %.*s\n", q-fname, fname);
532+				eread(tarfd, q, BLKSIZ);
533+			}
534+
535+			/* Convert pax x header with 'path=' field into L header */
536+			if (h->type == 'x') for (q = fname; q < fname+size-16; q += n) {
537+				if ((n = strtol(q, &p, 10)) < 0 || *p != ' ')
538+					eprintf("strtol %.*s: invalid number\n", p+1-q, q);
539+				if (n && strncmp(p+1, "path=", 5) == 0) {
540+					memmove(fname, p+6, size = q+n - p-6 - 1);
541+					h->type = 'L';
542+					break;
543+				}
544+			}
545+			fname[size] = '\0';
546+
547+			/* Non L-like header (eg. pax 'g') is skipped by setting q=null */
548+			if (h->type != 'L')
549+				q = NULL;
550+			continue;
551+		}
552+
553+		/* Ustar path is copied into fname if no L header (ie: q is NULL) */
554+		if (!q) {
555+			m = sizeof h->prefix, n = sizeof h->name;
556+			p = "/" + !h->prefix[0];
557+			snprintf(fname, sizeof fname, "%.*s%s%.*s", m, h->prefix, p, n, h->name);
558+		}
559+		q = NULL;
560+
561+		/* If argc > 0 then only extract the given files/dirs */
562+		if (argc) {
563+			for (i = 0; i < argc; i++) {
564+				if (strncmp(argv[i], fname, n = strlen(argv[i])) == 0)
565+					if (strchr("/", fname[n]) || argv[i][n-1] == '/')
566+						break;
567+			}
568+			if (i == argc) {
569+				skipblk(size);
570+				continue;
571+			}
572+		}
573+
574+		fn(fname, size, b);
575+		if (vflag && mode != 't')
576+			safe_puts(fname);
577+	}
578+
579+	if (mode == 'x' && !mflag) {
580+		while ((dirtime = popdirtime())) {
581+			times[0].tv_sec = times[1].tv_sec = dirtime->mtime;
582+			times[0].tv_nsec = times[1].tv_nsec = 0;
583+			if (utimensat(AT_FDCWD, dirtime->name, times, 0) < 0)
584+				eprintf("utimensat %s:", fname);
585+			free(dirtime->name);
586+		}
587+		free(dirtimes);
588+		dirtimes = NULL;
589+	}
590+}
591+
592+char **args;
593+int argn;
594+
595+static void
596+usage(void)
597+{
598+	eprintf("usage: %s [x | t | -x | -t] [-C dir] [-J | -Z | -a | -j | -z] [-m] [-p] "
599+	        "[-f file] [file ...]\n"
600+	        "       %s [c | -c] [-C dir] [-J | -Z | -a | -j | -z] [-h] path ... "
601+	        "[-f file]\n", argv0, argv0);
602+}
603+
604+int
605+main(int argc, char *argv[])
606+{
607+	struct recursor r = { .fn = c, .follow = 'P', .flags = DIRFIRST };
608+	struct stat st;
609+	char *file = NULL, *dir = ".", mode = '\0';
610+	int fd;
611+
612+	argv0 = argv[0];
613+	if (argc > 1 && strchr("cxt", mode = *argv[1]))
614+		*(argv[1]+1) ? *argv[1] = '-' : (*++argv = argv0, --argc);
615+
616+	ARGBEGIN {
617+	case 'x':
618+	case 'c':
619+	case 't':
620+		mode = ARGC();
621+		break;
622+	case 'C':
623+		dir = EARGF(usage());
624+		break;
625+	case 'f':
626+		file = EARGF(usage());
627+		break;
628+	case 'm':
629+		mflag = 1;
630+		break;
631+	case 'J':
632+	case 'Z':
633+	case 'a':
634+	case 'j':
635+	case 'z':
636+		filtermode = ARGC();
637+		filtertool = filtertools[filtermode];
638+		break;
639+	case 'h':
640+		r.follow = 'L';
641+		break;
642+	case 'v':
643+		vflag = 1;
644+		break;
645+	case 'p':
646+		break;  /* Do nothing as already default behaviour */
647+	default:
648+		usage();
649+	} ARGEND
650+
651+	switch (mode) {
652+	case 'c':
653+		if (!argc)
654+			usage();
655+		tarfd = 1;
656+		if (file && *file != '-') {
657+			tarfd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
658+			if (tarfd < 0)
659+				eprintf("open %s:", file);
660+			if (lstat(file, &st) < 0)
661+				eprintf("lstat %s:", file);
662+			tarinode = st.st_ino;
663+			tardev = st.st_dev;
664+		}
665+
666+		if (filtertool)
667+			tarfd = comp(tarfd, filtertool, "-cf");
668+
669+		if (chdir(dir) < 0)
670+			eprintf("chdir %s:", dir);
671+		for (; *argv; argc--, argv++)
672+			recurse(AT_FDCWD, *argv, NULL, &r);
673+		break;
674+	case 't':
675+	case 'x':
676+		tarfd = 0;
677+		if (file && *file != '-') {
678+			tarfd = open(file, O_RDONLY);
679+			if (tarfd < 0)
680+				eprintf("open %s:", file);
681+		}
682+
683+		if (filtertool) {
684+			fd = tarfd;
685+			tarfd = decomp(tarfd, filtertool, "-cdf");
686+			close(fd);
687+		}
688+
689+		if (chdir(dir) < 0)
690+			eprintf("chdir %s:", dir);
691+		xt(argc, argv, mode);
692+		break;
693+	default:
694+		usage();
695+	}
696+
697+	return recurse_status;
698+}
+53, -0
 1@@ -0,0 +1,53 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+
 5+#include <fcntl.h>
 6+#include <stdio.h>
 7+#include <stdlib.h>
 8+#include <unistd.h>
 9+
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+	eprintf("usage: %s [-c] -s size file...\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+	int cflag = 0, sflag = 0;
22+	int fd, i, ret = 0;
23+	long size = 0;
24+
25+	ARGBEGIN {
26+	case 's':
27+		sflag = 1;
28+		size = estrtol(EARGF(usage()), 10);
29+		break;
30+	case 'c':
31+		cflag = 1;
32+		break;
33+	default:
34+		usage();
35+	} ARGEND;
36+
37+	if (argc < 1 || sflag == 0)
38+		usage();
39+
40+	for (i = 0; i < argc; i++) {
41+		fd = open(argv[i], O_WRONLY | (cflag ? 0 : O_CREAT), 0644);
42+		if (fd < 0) {
43+			weprintf("open: cannot open `%s' for writing:", argv[i]);
44+			ret = 1;
45+			continue;
46+		}
47+		if (ftruncate(fd, size) < 0) {
48+			weprintf("ftruncate: cannot open `%s' for writing:", argv[i]);
49+			ret = 1;
50+		}
51+		close(fd);
52+	}
53+	return ret;
54+}
+58, -0
 1@@ -0,0 +1,58 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <unistd.h>
 7+
 8+#include "util.h"
 9+
10+static void
11+usage(void)
12+{
13+	eprintf("usage: %s [-t] [-n interval] command\n", argv0);
14+}
15+
16+int
17+main(int argc, char *argv[])
18+{
19+	char cmd[BUFSIZ];
20+	char *end;
21+	useconds_t interval = 2 * 1E6;
22+	float period;
23+	int i;
24+
25+	ARGBEGIN {
26+	case 't':
27+		break;
28+	case 'n':
29+		period = strtof(EARGF(usage()), &end);
30+		if (*end != '\0' || errno != 0)
31+			eprintf("invalid interval\n");
32+		if (period < 0)
33+			period = 0.1f;
34+		interval = period * 1E6;
35+		break;
36+	default:
37+		usage();
38+	} ARGEND;
39+
40+	if (argc < 1)
41+		usage();
42+
43+	if (strlcpy(cmd, argv[0], sizeof(cmd)) >= sizeof(cmd))
44+		eprintf("command too long\n");
45+	for (i = 1; i < argc; i++) {
46+		if (strlcat(cmd, " ", sizeof(cmd)) >= sizeof(cmd))
47+			eprintf("command too long\n");
48+		if (strlcat(cmd, argv[i], sizeof(cmd)) >= sizeof(cmd))
49+			eprintf("command too long\n");
50+	}
51+
52+	for (;;) {
53+		printf("\x1b[2J\x1b[H"); /* clear */
54+		fflush(NULL);
55+		system(cmd);
56+		usleep(interval);
57+	}
58+	return 0;
59+}
+101, -0
  1@@ -0,0 +1,101 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+#include <sys/types.h>
  5+
  6+#include <fcntl.h>
  7+#include <limits.h>
  8+#include <stdio.h>
  9+#include <stdlib.h>
 10+#include <string.h>
 11+#include <unistd.h>
 12+
 13+#include "util.h"
 14+
 15+static int aflag;
 16+
 17+static int
 18+canexec(int fd, const char *name)
 19+{
 20+	struct stat st;
 21+
 22+	if (fstatat(fd, name, &st, 0) < 0 || !S_ISREG(st.st_mode))
 23+		return 0;
 24+	return faccessat(fd, name, X_OK, AT_EACCESS) == 0;
 25+}
 26+
 27+static int
 28+which(const char *path, const char *name)
 29+{
 30+	char *ptr, *p;
 31+	size_t i, len;
 32+	int dirfd, found = 0;
 33+
 34+	if (strchr(name, '/')) {
 35+		found = canexec(AT_FDCWD, name);
 36+		if (found)
 37+			puts(name);
 38+		return found;
 39+	}
 40+
 41+	ptr = p = enstrdup(3, path);
 42+	len = strlen(p);
 43+	for (i = 0; i < len + 1; i++) {
 44+		if (ptr[i] != ':' && ptr[i] != '\0')
 45+			continue;
 46+		ptr[i] = '\0';
 47+		if ((dirfd = open(p, O_RDONLY)) >= 0) {
 48+			if (canexec(dirfd, name)) {
 49+				found = 1;
 50+				fputs(p, stdout);
 51+				if (i && ptr[i - 1] != '/')
 52+					fputc('/', stdout);
 53+				puts(name);
 54+			}
 55+			close(dirfd);
 56+			if (!aflag && found)
 57+				break;
 58+		}
 59+		p = ptr + i + 1;
 60+	}
 61+	free(ptr);
 62+
 63+	return found;
 64+}
 65+
 66+static void
 67+usage(void)
 68+{
 69+	eprintf("usage: %s [-a] name ...\n", argv0);
 70+}
 71+
 72+int
 73+main(int argc, char *argv[])
 74+{
 75+	char *path;
 76+	int found = 0, foundall = 1;
 77+
 78+	ARGBEGIN {
 79+	case 'a':
 80+		aflag = 1;
 81+		break;
 82+	default:
 83+		usage();
 84+	} ARGEND
 85+
 86+	if (!argc)
 87+		usage();
 88+
 89+	if (!(path = getenv("PATH")))
 90+		enprintf(3, "$PATH is not set\n");
 91+
 92+	for (; *argv; argc--, argv++) {
 93+		if (which(path, *argv)) {
 94+			found = 1;
 95+		} else {
 96+			weprintf("%s: not an external command\n", *argv);
 97+			foundall = 0;
 98+		}
 99+	}
100+
101+	return found ? foundall ? 0 : 1 : 2;
102+}
+37, -0
 1@@ -0,0 +1,37 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <stdio.h>
 5+#include <unistd.h>
 6+#include <pwd.h>
 7+
 8+#include "util.h"
 9+
10+static void
11+usage(void)
12+{
13+	eprintf("usage: %s\n", argv0);
14+}
15+
16+int
17+main(int argc, char *argv[])
18+{
19+	uid_t uid;
20+	struct passwd *pw;
21+
22+	argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
23+
24+	if (argc)
25+		usage();
26+
27+	uid = geteuid();
28+	errno = 0;
29+	if (!(pw = getpwuid(uid))) {
30+		if (errno)
31+			eprintf("getpwuid %d:", uid);
32+		else
33+			eprintf("getpwuid %d: no such user\n", uid);
34+	}
35+	puts(pw->pw_name);
36+
37+	return fshut(stdout, "<stdout>");
38+}
+194, -0
  1@@ -0,0 +1,194 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <grp.h>
  4+#include <pwd.h>
  5+#include <errno.h>
  6+#include <fcntl.h>
  7+#include <unistd.h>
  8+#include <stdlib.h>
  9+#include <string.h>
 10+#include <dirent.h>
 11+#include <sys/stat.h>
 12+#include <sys/wait.h>
 13+
 14+#include "util.h"
 15+
 16+static int Dflag = 0;
 17+static gid_t group;
 18+static uid_t owner;
 19+static mode_t mode = 0755;
 20+
 21+static void
 22+make_dir(char *dir, int was_missing)
 23+{
 24+	if (!mkdir(dir, was_missing ? 0755 : mode)) {
 25+		if (!was_missing && (lchown(dir, owner, group) < 0))
 26+			eprintf("lchmod %s:", dir);
 27+	} else if (errno != EEXIST) {
 28+		eprintf("mkdir %s:", dir);
 29+	}
 30+}
 31+
 32+static void
 33+make_dirs(char *dir, int was_missing)
 34+{
 35+	char *p;
 36+	for (p = strchr(dir + (dir[0] == '/'), '/'); p; p = strchr(p + 1, '/')) {
 37+		*p = '\0';
 38+		make_dir(dir, was_missing);
 39+		*p = '/';
 40+	}
 41+	make_dir(dir, was_missing);
 42+}
 43+
 44+static int
 45+install(const char *s1, const char *s2, int depth)
 46+{
 47+	int f1, f2;
 48+
 49+	if ((f1 = open(s1, O_RDONLY)) < 0)
 50+		eprintf("open %s:", s1);
 51+	if ((f2 = creat(s2, 0600)) < 0) {
 52+		if (unlink(s2) < 0 && errno != ENOENT)
 53+			eprintf("unlink %s:", s2);
 54+		if ((f2 = creat(s2, 0600)) < 0)
 55+			eprintf("creat %s:", s2);
 56+	}
 57+	if (concat(f1, s1, f2, s2) < 0)
 58+		goto fail;
 59+	if (fchmod(f2, mode) < 0) {
 60+		weprintf("fchmod %s:", s2);
 61+		goto fail;
 62+	}
 63+	if (fchown(f2, owner, group) < 0) {
 64+		weprintf("fchown %s:", s2);
 65+		goto fail;
 66+	}
 67+
 68+	close(f1);
 69+	close(f2);
 70+
 71+	return 0;
 72+
 73+fail:
 74+	unlink(s2);
 75+	exit(1);
 76+}
 77+
 78+static void
 79+usage(void)
 80+{
 81+	eprintf("usage: %s [-g group] [-o owner] [-m mode] (-d dir ... | [-D] (-t dest source ... | source ... dest))\n", argv0);
 82+}
 83+
 84+int
 85+main(int argc, char *argv[])
 86+{
 87+	int dflag = 0;
 88+	char *gflag = 0;
 89+	char *oflag = 0;
 90+	char *mflag = 0;
 91+	char *tflag = 0;
 92+	struct group *gr;
 93+	struct passwd *pw;
 94+	struct stat st;
 95+	char *p;
 96+
 97+	ARGBEGIN {
 98+	case 'c':
 99+		/* no-op for compatibility */
100+		break;
101+	case 'd':
102+		dflag = 1;
103+		break;
104+	case 'D':
105+		Dflag = 1;
106+		break;
107+	case 's':
108+		/* no-op for compatibility */
109+		break;
110+	case 'g':
111+		gflag = EARGF(usage());
112+		break;
113+	case 'o':
114+		oflag = EARGF(usage());
115+		break;
116+	case 'm':
117+		mflag = EARGF(usage());
118+		break;
119+	case 't':
120+		tflag = EARGF(usage());
121+		break;
122+	default:
123+		usage();
124+	} ARGEND
125+
126+	if (argc < 1 + (!tflag & !dflag) || dflag & (Dflag | !!tflag))
127+		usage();
128+
129+	if (gflag) {
130+		errno = 0;
131+		gr = getgrnam(gflag);
132+		if (gr) {
133+			group = gr->gr_gid;
134+		} else {
135+			if (errno)
136+				eprintf("getgrnam %s:", gflag);
137+			group = estrtonum(gflag, 0, UINT_MAX);
138+		}
139+	} else {
140+		group = getgid();
141+	}
142+
143+	if (oflag) {
144+		errno = 0;
145+		pw = getpwnam(oflag);
146+		if (pw) {
147+			owner = pw->pw_uid;
148+		} else {
149+			if (errno)
150+				eprintf("getpwnam %s:", oflag);
151+			owner = estrtonum(oflag, 0, UINT_MAX);
152+		}
153+	} else {
154+		owner = getuid();
155+	}
156+
157+	if (mflag)
158+		mode = parsemode(mflag, mode, 0);
159+
160+	if (dflag) {
161+		for (; *argv; argc--, argv++)
162+			make_dirs(*argv, 0);
163+		return 0;
164+	}
165+
166+	if (tflag) {
167+		argv = memmove(argv - 1, argv, argc * sizeof(*argv));
168+		argv[argc++] = tflag;
169+	}
170+	if (tflag || argc > 2) {
171+		if (stat(argv[argc - 1], &st) < 0) {
172+			if ((errno == ENOENT) && Dflag) {
173+				make_dirs(argv[argc - 1], 1);
174+			} else {
175+				eprintf("stat %s:", argv[argc - 1]);
176+			}
177+		} else if (!S_ISDIR(st.st_mode)) {
178+			eprintf("%s: not a directory\n", argv[argc - 1]);
179+		}
180+	}
181+	if (stat(argv[argc - 1], &st) < 0) {
182+		if (errno != ENOENT)
183+			eprintf("stat %s:", argv[argc - 1]);
184+		if (tflag || Dflag || argc > 2) {
185+			if ((p = strrchr(argv[argc - 1], '/')) != NULL) {
186+				*p = '\0';
187+				make_dirs(argv[argc - 1], 1);
188+				*p = '/';
189+			}
190+		}
191+	}
192+	enmasse(argc, argv, install);
193+
194+	return 0;
195+}
+25, -0
 1@@ -0,0 +1,25 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+
 5+#include "util.h"
 6+
 7+static void
 8+usage(void)
 9+{
10+	eprintf("usage: %s [string]\n", argv0);
11+}
12+
13+int
14+main(int argc, char *argv[])
15+{
16+	const char *s;
17+
18+	ARGBEGIN {
19+	default:
20+		usage();
21+	} ARGEND
22+
23+	s = argc ? argv[0] : "y";
24+	for (;;)
25+		puts(s);
26+}
+72, -0
 1@@ -0,0 +1,72 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+#include <sys/types.h>
 5+#ifndef makedev
 6+#include <sys/sysmacros.h>
 7+#endif
 8+
 9+#include <fcntl.h>
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+#include <unistd.h>
14+
15+#include "util.h"
16+
17+static void
18+usage(void)
19+{
20+	eprintf("usage: %s [-m mode] name b|c|u major minor\n"
21+	        "       %s [-m mode] name p\n",
22+	        argv0, argv0);
23+}
24+
25+int
26+main(int argc, char *argv[])
27+{
28+	mode_t mode = 0666;
29+	dev_t dev;
30+
31+	ARGBEGIN {
32+	case 'm':
33+		mode = parsemode(EARGF(usage()), mode, umask(0));
34+		break;
35+	default:
36+		usage();
37+	} ARGEND;
38+
39+	if (argc < 2)
40+		usage();
41+
42+	if (strlen(argv[1]) != 1)
43+		goto invalid;
44+	switch (argv[1][0]) {
45+	case 'b':
46+		mode |= S_IFBLK;
47+		break;
48+	case 'u':
49+	case 'c':
50+		mode |= S_IFCHR;
51+		break;
52+	case 'p':
53+		mode |= S_IFIFO;
54+		break;
55+	default:
56+	invalid:
57+		eprintf("invalid type '%s'\n", argv[1]);
58+	}
59+
60+	if (S_ISFIFO(mode)) {
61+		if (argc != 2)
62+			usage();
63+		dev = 0;
64+	} else {
65+		if (argc != 4)
66+			usage();
67+		dev = makedev(estrtonum(argv[2], 0, LLONG_MAX), estrtonum(argv[3], 0, LLONG_MAX));
68+	}
69+
70+	if (mknod(argv[0], mode, dev) == -1)
71+		eprintf("mknod %s:", argv[0]);
72+	return 0;
73+}
+288, -0
  1@@ -0,0 +1,288 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/ioctl.h>
  4+#include <sys/stat.h>
  5+#include <sys/types.h>
  6+#include <sys/syscall.h>
  7+
  8+#include <errno.h>
  9+#include <fcntl.h>
 10+#include <limits.h>
 11+#include <pwd.h>
 12+#include <shadow.h>
 13+#include <stdint.h>
 14+#include <stdio.h>
 15+#include <stdlib.h>
 16+#include <string.h>
 17+#include <unistd.h>
 18+
 19+#include "config.h"
 20+#include "passwd.h"
 21+#include "text.h"
 22+#include "util.h"
 23+
 24+static FILE *
 25+spw_get_file(const char *user)
 26+{
 27+	FILE *fp = NULL;
 28+	char file[PATH_MAX];
 29+	int r;
 30+
 31+	r = snprintf(file, sizeof(file), "/etc/tcb/%s/shadow", user);
 32+	if (r < 0 || (size_t)r >= sizeof(file))
 33+		eprintf("snprintf:");
 34+	fp = fopen(file, "r+");
 35+	if (!fp)
 36+		fp = fopen("/etc/shadow", "r+");
 37+	return fp;
 38+}
 39+
 40+static int
 41+spw_write_file(FILE *fp, const struct spwd *spw, char *pwhash)
 42+{
 43+	struct spwd *spwent;
 44+	int r = -1, w = 0;
 45+	FILE *tfp = NULL;
 46+
 47+	/* write to temporary file. */
 48+	tfp = tmpfile();
 49+	if (!tfp) {
 50+		weprintf("tmpfile:");
 51+		goto cleanup;
 52+	}
 53+	while ((spwent = fgetspent(fp))) {
 54+		/* update entry on name match */
 55+		if (strcmp(spwent->sp_namp, spw->sp_namp) == 0) {
 56+			spwent->sp_pwdp = pwhash;
 57+			w++;
 58+		}
 59+		errno = 0;
 60+		if (putspent(spwent, tfp) == -1) {
 61+			weprintf("putspent:");
 62+			goto cleanup;
 63+		}
 64+	}
 65+	if (!w) {
 66+		weprintf("shadow: no matching entry to write to\n");
 67+		goto cleanup;
 68+	}
 69+	fflush(tfp);
 70+
 71+	if (fseek(fp, 0, SEEK_SET) == -1 || fseek(tfp, 0, SEEK_SET) == -1) {
 72+		weprintf("fseek:");
 73+		goto cleanup;
 74+	}
 75+
 76+	/* write temporary file to (tcb) shadow file */
 77+	fconcat(tfp, "tmpfile", fp, "shadow");
 78+	ftruncate(fileno(fp), ftell(tfp));
 79+
 80+	r = 0; /* success */
 81+cleanup:
 82+	if (tfp)
 83+		fclose(tfp);
 84+	return r;
 85+}
 86+
 87+static int
 88+pw_write_file(FILE *fp, const struct passwd *pw, char *pwhash) {
 89+	struct passwd *pwent;
 90+	int r = -1, w = 0;
 91+	FILE *tfp = NULL;
 92+
 93+	/* write to temporary file. */
 94+	tfp = tmpfile();
 95+	if (!tfp) {
 96+		weprintf("tmpfile:");
 97+		goto cleanup;
 98+	}
 99+	while ((pwent = fgetpwent(fp))) {
100+		/* update entry on name match */
101+		if (strcmp(pwent->pw_name, pw->pw_name) == 0) {
102+			pwent->pw_passwd = pwhash;
103+			w++;
104+		}
105+		errno = 0;
106+		if (putpwent(pwent, tfp) == -1) {
107+			weprintf("putpwent:");
108+			goto cleanup;
109+		}
110+	}
111+	if (!w) {
112+		weprintf("passwd: no matching entry to write to\n");
113+		goto cleanup;
114+	}
115+	fflush(tfp);
116+
117+	if (fseek(fp, 0, SEEK_SET) == -1 || fseek(tfp, 0, SEEK_SET) == -1) {
118+		weprintf("fseek:");
119+		goto cleanup;
120+	}
121+
122+	/* write to passwd file. */
123+	fconcat(tfp, "tmpfile", fp, "passwd");
124+	ftruncate(fileno(fp), ftell(tfp));
125+
126+	r = 0; /* success */
127+cleanup:
128+	if (tfp)
129+		fclose(tfp);
130+	return r;
131+}
132+
133+/* generates a random base64-encoded salt string of length 16 */
134+static void
135+gensalt(char *s)
136+{
137+	static const char b64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
138+	uint8_t buf[12];
139+	uint32_t n;
140+	int i;
141+
142+	if (syscall(SYS_getrandom, buf, sizeof(buf), 0) < 0)
143+		eprintf("getrandom:");
144+	for (i = 0; i < 12; i += 3) {
145+		n = buf[i] << 16 | buf[i+1] << 8 | buf[i+2];
146+		*s++ = b64[n%64]; n /= 64;
147+		*s++ = b64[n%64]; n /= 64;
148+		*s++ = b64[n%64]; n /= 64;
149+		*s++ = b64[n];
150+	}
151+	*s++ = '\0';
152+}
153+
154+static void
155+usage(void)
156+{
157+	eprintf("usage: %s [username]\n", argv0);
158+}
159+
160+int
161+main(int argc, char *argv[])
162+{
163+	char *cryptpass1 = NULL, *cryptpass2 = NULL, *cryptpass3 = NULL;
164+	char *inpass, *p, *prevhash = NULL, salt[sizeof(PW_CIPHER) + 16] = PW_CIPHER;
165+	struct passwd *pw;
166+	struct spwd *spw = NULL;
167+	FILE *fp = NULL;
168+	int r = -1, status = 1;
169+
170+	ARGBEGIN {
171+	default:
172+		usage();
173+	} ARGEND;
174+
175+	pw_init();
176+	umask(077);
177+
178+	errno = 0;
179+	if (argc == 0)
180+		pw = getpwuid(getuid());
181+	else
182+		pw = getpwnam(argv[0]);
183+	if (!pw) {
184+		if (errno)
185+			eprintf("getpwnam: %s:", argv[0]);
186+		else
187+			eprintf("who are you?\n");
188+	}
189+
190+	/* is using shadow entry ? */
191+	if (pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0') {
192+		errno = 0;
193+		spw = getspnam(pw->pw_name);
194+		if (!spw) {
195+			if (errno)
196+				eprintf("getspnam: %s:", pw->pw_name);
197+			else
198+				eprintf("who are you?\n");
199+		}
200+	}
201+
202+	/* Flush pending input */
203+	ioctl(0, TCFLSH, (void *)0);
204+
205+	if (getuid() == 0) {
206+		goto newpass;
207+	} else {
208+		if (pw->pw_passwd[0] == '!' ||
209+		    pw->pw_passwd[0] == '*')
210+			eprintf("denied\n");
211+		if (pw->pw_passwd[0] == '\0') {
212+			goto newpass;
213+		}
214+		if (pw->pw_passwd[0] == 'x' &&
215+		    pw->pw_passwd[1] == '\0')
216+			prevhash = spw->sp_pwdp;
217+		else
218+			prevhash = pw->pw_passwd;
219+	}
220+
221+	printf("Changing password for %s\n", pw->pw_name);
222+	inpass = getpass("Old password: ");
223+	if (!inpass)
224+		eprintf("getpass:");
225+	if (inpass[0] == '\0')
226+		eprintf("no password supplied\n");
227+	p = crypt(inpass, prevhash);
228+	if (!p)
229+		eprintf("crypt:");
230+	cryptpass1 = estrdup(p);
231+	if (strcmp(cryptpass1, prevhash) != 0)
232+		eprintf("incorrect password\n");
233+
234+newpass:
235+	inpass = getpass("Enter new password: ");
236+	if (!inpass)
237+		eprintf("getpass:");
238+	if (inpass[0] == '\0')
239+		eprintf("no password supplied\n");
240+
241+	if(prevhash) {
242+		p = crypt(inpass, prevhash);
243+		if (!p)
244+			eprintf("crypt:");
245+		if (cryptpass1 && strcmp(cryptpass1, p) == 0)
246+			eprintf("password left unchanged\n");
247+	}
248+	gensalt(salt + strlen(salt));
249+	p = crypt(inpass, salt);
250+	if (!p)
251+		eprintf("crypt:");
252+	cryptpass2 = estrdup(p);
253+
254+	/* Flush pending input */
255+	ioctl(0, TCFLSH, (void *)0);
256+
257+	inpass = getpass("Retype new password: ");
258+	if (!inpass)
259+		eprintf("getpass:");
260+	if (inpass[0] == '\0')
261+		eprintf("no password supplied\n");
262+	p = crypt(inpass, salt);
263+	if (!p)
264+		eprintf("crypt:");
265+	cryptpass3 = estrdup(p);
266+	if (strcmp(cryptpass2, cryptpass3) != 0)
267+		eprintf("passwords don't match\n");
268+
269+	fp = spw_get_file(pw->pw_name);
270+	if (fp) {
271+		r = spw_write_file(fp, spw, cryptpass3);
272+	} else {
273+		fp = fopen("/etc/passwd", "r+");
274+		if (fp)
275+			r = pw_write_file(fp, pw, cryptpass3);
276+		else
277+			weprintf("fopen:");
278+	}
279+	if (!r)
280+		status = 0;
281+
282+	if (fp)
283+		fclose(fp);
284+	free(cryptpass3);
285+	free(cryptpass2);
286+	free(cryptpass1);
287+
288+	return status;
289+}
+108, -0
  1@@ -0,0 +1,108 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/types.h>
  4+
  5+#include <errno.h>
  6+#include <grp.h>
  7+#include <pwd.h>
  8+#include <stdio.h>
  9+#include <stdlib.h>
 10+#include <string.h>
 11+#include <unistd.h>
 12+
 13+#include "passwd.h"
 14+#include "util.h"
 15+
 16+extern char **environ;
 17+
 18+static int lflag = 0;
 19+static int pflag = 0;
 20+
 21+static void
 22+usage(void)
 23+{
 24+	eprintf("usage: %s [-lp] [username]\n", argv0);
 25+}
 26+
 27+int
 28+main(int argc, char *argv[])
 29+{
 30+	char *usr, *pass;
 31+	char *shell, *envshell, *term;
 32+	struct passwd *pw;
 33+	char *newargv[3];
 34+	uid_t uid;
 35+
 36+	ARGBEGIN {
 37+	case 'l':
 38+		lflag = 1;
 39+		break;
 40+	case 'p':
 41+		pflag = 1;
 42+		break;
 43+	default:
 44+		usage();
 45+	} ARGEND;
 46+
 47+	if (argc > 1)
 48+		usage();
 49+	usr = argc > 0 ? argv[0] : "root";
 50+
 51+	errno = 0;
 52+	pw = getpwnam(usr);
 53+	if (!pw) {
 54+		if (errno)
 55+			eprintf("getpwnam: %s:", usr);
 56+		else
 57+			eprintf("who are you?\n");
 58+	}
 59+
 60+	uid = getuid();
 61+	if (uid) {
 62+		pass = getpass("Password: ");
 63+		if (!pass)
 64+			eprintf("getpass:");
 65+		if (pw_check(pw, pass) <= 0)
 66+			exit(1);
 67+	}
 68+
 69+	if (initgroups(usr, pw->pw_gid) < 0)
 70+		eprintf("initgroups:");
 71+	if (setgid(pw->pw_gid) < 0)
 72+		eprintf("setgid:");
 73+	if (setuid(pw->pw_uid) < 0)
 74+		eprintf("setuid:");
 75+
 76+	shell = pw->pw_shell[0] == '\0' ? "/bin/sh" : pw->pw_shell;
 77+	if (lflag) {
 78+		term = getenv("TERM");
 79+		clearenv();
 80+		setenv("HOME", pw->pw_dir, 1);
 81+		setenv("SHELL", shell, 1);
 82+		setenv("USER", pw->pw_name, 1);
 83+		setenv("LOGNAME", pw->pw_name, 1);
 84+		setenv("TERM", term ? term : "linux", 1);
 85+		if (chdir(pw->pw_dir) < 0)
 86+			eprintf("chdir %s:", pw->pw_dir);
 87+		newargv[0] = shell;
 88+		newargv[1] = "-l";
 89+		newargv[2] = NULL;
 90+	} else {
 91+		if (pflag) {
 92+			envshell = getenv("SHELL");
 93+			if (envshell && envshell[0] != '\0')
 94+				shell = envshell;
 95+		} else {
 96+			setenv("HOME", pw->pw_dir, 1);
 97+			setenv("SHELL", shell, 1);
 98+			if (strcmp(pw->pw_name, "root") != 0) {
 99+				setenv("USER", pw->pw_name, 1);
100+				setenv("LOGNAME", pw->pw_name, 1);
101+			}
102+		}
103+		newargv[0] = shell;
104+		newargv[1] = NULL;
105+	}
106+	execve(shell, newargv, environ);
107+	weprintf("execve %s:", shell);
108+	return (errno == ENOENT) ? 127 : 126;
109+}
+23, -0
 1@@ -0,0 +1,23 @@
 2+VERSION = 2026-06-08T05-53-UTC-03
 3+
 4+PREFIX    = /usr/local
 5+MANPREFIX = $(PREFIX)/share/man
 6+
 7+RANLIB  = ranlib
 8+AR      = ar
 9+ARFLAGS = rc
10+
11+CPPFLAGS =\
12+	-Ishared\
13+	-DPREFIX=\"$(PREFIX)\"\
14+	-D_DEFAULT_SOURCE\
15+	-D_GNU_SOURCE\
16+	-D_NETBSD_SOURCE\
17+	-D_BSD_SOURCE\
18+	-D_XOPEN_SOURCE=700\
19+	-D_FILE_OFFSET_BITS=64\
20+	-DSTD_NON_POSIX
21+
22+CFLAGS   = -std=c99 -Wall -Wextra -pedantic
23+LDFLAGS  =
24+LDLIBS   = -lcrypt -lresolv
+218, -0
  1@@ -0,0 +1,218 @@
  2+#!/bin/sh
  3+
  4+ifdef() {
  5+	printf 'static const struct var %s[] = {\n' "$1"
  6+	awk '{printf("#ifdef %s\n\t{\"%s\",\t%s},\n#endif\n", $2, $1, $2)}'
  7+	echo '};'
  8+}
  9+
 10+ifdef confstr_l << EOF
 11+PATH                           _CS_PATH
 12+POSIX_V7_ILP32_OFF32_CFLAGS    _CS_POSIX_V7_ILP32_OFF32_CFLAGS
 13+POSIX_V7_ILP32_OFF32_LDFLAGS   _CS_POSIX_V7_ILP32_OFF32_LDFLAGS
 14+POSIX_V7_ILP32_OFF32_LIBS      _CS_POSIX_V7_ILP32_OFF32_LIBS
 15+POSIX_V7_ILP32_OFFBIG_CFLAGS   _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS
 16+POSIX_V7_ILP32_OFFBIG_LDFLAGS  _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS
 17+POSIX_V7_ILP32_OFFBIG_LIBS     _CS_POSIX_V7_ILP32_OFFBIG_LIBS
 18+POSIX_V7_LP64_OFF64_CFLAGS     _CS_POSIX_V7_LP64_OFF64_CFLAGS
 19+POSIX_V7_LP64_OFF64_LDFLAGS    _CS_POSIX_V7_LP64_OFF64_LDFLAGS
 20+POSIX_V7_LP64_OFF64_LIBS       _CS_POSIX_V7_LP64_OFF64_LIBS
 21+POSIX_V7_LPBIG_OFFBIG_CFLAGS   _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS
 22+POSIX_V7_LPBIG_OFFBIG_LDFLAGS  _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS
 23+POSIX_V7_LPBIG_OFFBIG_LIBS     _CS_POSIX_V7_LPBIG_OFFBIG_LIBS
 24+POSIX_V7_THREADS_CFLAGS        _CS_POSIX_V7_THREADS_CFLAGS
 25+POSIX_V7_THREADS_LDFLAGS       _CS_POSIX_V7_THREADS_LDFLAGS
 26+POSIX_V7_WIDTH_RESTRICTED_ENVS _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS
 27+V7_ENV                         _CS_V7_ENV
 28+EOF
 29+
 30+ifdef limits_l << EOF
 31+_POSIX_CLOCKRES_MIN                 _POSIX_CLOCKRES_MIN
 32+_POSIX_AIO_LISTIO_MAX               _POSIX_AIO_LISTIO_MAX
 33+_POSIX_AIO_MAX                      _POSIX_AIO_MAX
 34+_POSIX_ARG_MAX                      _POSIX_ARG_MAX
 35+_POSIX_CHILD_MAX                    _POSIX_CHILD_MAX
 36+_POSIX_DELAYTIMER_MAX               _POSIX_DELAYTIMER_MAX
 37+_POSIX_HOST_NAME_MAX                _POSIX_HOST_NAME_MAX
 38+_POSIX_LINK_MAX                     _POSIX_LINK_MAX
 39+_POSIX_LOGIN_NAME_MAX               _POSIX_LOGIN_NAME_MAX
 40+_POSIX_MAX_CANON                    _POSIX_MAX_CANON
 41+_POSIX_MAX_INPUT                    _POSIX_MAX_INPUT
 42+_POSIX_MQ_OPEN_MAX                  _POSIX_MQ_OPEN_MAX
 43+_POSIX_MQ_PRIO_MAX                  _POSIX_MQ_PRIO_MAX
 44+_POSIX_NAME_MAX                     _POSIX_NAME_MAX
 45+_POSIX_NGROUPS_MAX                  _POSIX_NGROUPS_MAX
 46+_POSIX_OPEN_MAX                     _POSIX_OPEN_MAX
 47+_POSIX_PATH_MAX                     _POSIX_PATH_MAX
 48+_POSIX_PIPE_BUF                     _POSIX_PIPE_BUF
 49+_POSIX_RE_DUP_MAX                   _POSIX_RE_DUP_MAX
 50+_POSIX_RTSIG_MAX                    _POSIX_RTSIG_MAX
 51+_POSIX_SEM_NSEMS_MAX                _POSIX_SEM_NSEMS_MAX
 52+_POSIX_SEM_VALUE_MAX                _POSIX_SEM_VALUE_MAX
 53+_POSIX_SIGQUEUE_MAX                 _POSIX_SIGQUEUE_MAX
 54+_POSIX_SSIZE_MAX                    _POSIX_SSIZE_MAX
 55+_POSIX_SS_REPL_MAX                  _POSIX_SS_REPL_MAX
 56+_POSIX_STREAM_MAX                   _POSIX_STREAM_MAX
 57+_POSIX_SYMLINK_MAX                  _POSIX_SYMLINK_MAX
 58+_POSIX_SYMLOOP_MAX                  _POSIX_SYMLOOP_MAX
 59+_POSIX_THREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS
 60+_POSIX_THREAD_KEYS_MAX              _POSIX_THREAD_KEYS_MAX
 61+_POSIX_THREAD_THREADS_MAX           _POSIX_THREAD_THREADS_MAX
 62+_POSIX_TIMER_MAX                    _POSIX_TIMER_MAX
 63+_POSIX_TTY_NAME_MAX                 _POSIX_TTY_NAME_MAX
 64+_POSIX_TZNAME_MAX                   _POSIX_TZNAME_MAX
 65+_POSIX2_BC_BASE_MAX                 _POSIX2_BC_BASE_MAX
 66+_POSIX2_BC_DIM_MAX                  _POSIX2_BC_DIM_MAX
 67+_POSIX2_BC_SCALE_MAX                _POSIX2_BC_SCALE_MAX
 68+_POSIX2_BC_STRING_MAX               _POSIX2_BC_STRING_MAX
 69+_POSIX2_CHARCLASS_NAME_MAX          _POSIX2_CHARCLASS_NAME_MAX
 70+_POSIX2_COLL_WEIGHTS_MAX            _POSIX2_COLL_WEIGHTS_MAX
 71+_POSIX2_EXPR_NEST_MAX               _POSIX2_EXPR_NEST_MAX
 72+_POSIX2_LINE_MAX                    _POSIX2_LINE_MAX
 73+_POSIX2_RE_DUP_MAX                  _POSIX2_RE_DUP_MAX
 74+EOF
 75+
 76+ifdef sysconf_l << EOF
 77+AIO_LISTIO_MAX                    _SC_AIO_LISTIO_MAX
 78+AIO_MAX                           _SC_AIO_MAX
 79+AIO_PRIO_DELTA_MAX                _SC_AIO_PRIO_DELTA_MAX
 80+ARG_MAX                           _SC_ARG_MAX
 81+ATEXIT_MAX                        _SC_ATEXIT_MAX
 82+BC_BASE_MAX                       _SC_BC_BASE_MAX
 83+BC_DIM_MAX                        _SC_BC_DIM_MAX
 84+BC_SCALE_MAX                      _SC_BC_SCALE_MAX
 85+BC_STRING_MAX                     _SC_BC_STRING_MAX
 86+CHILD_MAX                         _SC_CHILD_MAX
 87+COLL_WEIGHTS_MAX                  _SC_COLL_WEIGHTS_MAX
 88+DELAYTIMER_MAX                    _SC_DELAYTIMER_MAX
 89+EXPR_NEST_MAX                     _SC_EXPR_NEST_MAX
 90+HOST_NAME_MAX                     _SC_HOST_NAME_MAX
 91+IOV_MAX                           _SC_IOV_MAX
 92+LINE_MAX                          _SC_LINE_MAX
 93+LOGIN_NAME_MAX                    _SC_LOGIN_NAME_MAX
 94+NGROUPS_MAX                       _SC_NGROUPS_MAX
 95+MQ_OPEN_MAX                       _SC_MQ_OPEN_MAX
 96+MQ_PRIO_MAX                       _SC_MQ_PRIO_MAX
 97+OPEN_MAX                          _SC_OPEN_MAX
 98+_POSIX_ADVISORY_INFO              _SC_ADVISORY_INFO
 99+_POSIX_BARRIERS                   _SC_BARRIERS
100+_POSIX_ASYNCHRONOUS_IO            _SC_ASYNCHRONOUS_IO
101+_POSIX_CLOCK_SELECTION            _SC_CLOCK_SELECTION
102+_POSIX_CPUTIME                    _SC_CPUTIME
103+_POSIX_FSYNC                      _SC_FSYNC
104+_POSIX_IPV6                       _SC_IPV6
105+_POSIX_JOB_CONTROL                _SC_JOB_CONTROL
106+_POSIX_MAPPED_FILES               _SC_MAPPED_FILES
107+_POSIX_MEMLOCK                    _SC_MEMLOCK
108+_POSIX_MEMLOCK_RANGE              _SC_MEMLOCK_RANGE
109+_POSIX_MEMORY_PROTECTION          _SC_MEMORY_PROTECTION
110+_POSIX_MESSAGE_PASSING            _SC_MESSAGE_PASSING
111+_POSIX_MONOTONIC_CLOCK            _SC_MONOTONIC_CLOCK
112+_POSIX_PRIORITIZED_IO             _SC_PRIORITIZED_IO
113+_POSIX_PRIORITY_SCHEDULING        _SC_PRIORITY_SCHEDULING
114+_POSIX_RAW_SOCKETS                _SC_RAW_SOCKETS
115+_POSIX_READER_WRITER_LOCKS        _SC_READER_WRITER_LOCKS
116+_POSIX_REALTIME_SIGNALS           _SC_REALTIME_SIGNALS
117+_POSIX_REGEXP                     _SC_REGEXP
118+_POSIX_SAVED_IDS                  _SC_SAVED_IDS
119+_POSIX_SEMAPHORES                 _SC_SEMAPHORES
120+_POSIX_SHARED_MEMORY_OBJECTS      _SC_SHARED_MEMORY_OBJECTS
121+_POSIX_SHELL                      _SC_SHELL
122+_POSIX_SPAWN                      _SC_SPAWN
123+_POSIX_SPIN_LOCKS                 _SC_SPIN_LOCKS
124+_POSIX_SPORADIC_SERVER            _SC_SPORADIC_SERVER
125+_POSIX_SS_REPL_MAX                _SC_SS_REPL_MAX
126+_POSIX_SYNCHRONIZED_IO            _SC_SYNCHRONIZED_IO
127+_POSIX_THREAD_ATTR_STACKADDR      _SC_THREAD_ATTR_STACKADDR
128+_POSIX_THREAD_ATTR_STACKSIZE      _SC_THREAD_ATTR_STACKSIZE
129+_POSIX_THREAD_CPUTIME             _SC_THREAD_CPUTIME
130+_POSIX_THREAD_PRIO_INHERIT        _SC_THREAD_PRIO_INHERIT
131+_POSIX_THREAD_PRIO_PROTECT        _SC_THREAD_PRIO_PROTECT
132+_POSIX_THREAD_PRIORITY_SCHEDULING _SC_THREAD_PRIORITY_SCHEDULING
133+_POSIX_THREAD_PROCESS_SHARED      _SC_THREAD_PROCESS_SHARED
134+_POSIX_THREAD_ROBUST_PRIO_INHERIT _SC_THREAD_ROBUST_PRIO_INHERIT
135+_POSIX_THREAD_ROBUST_PRIO_PROTECT _SC_THREAD_ROBUST_PRIO_PROTECT
136+_POSIX_THREAD_SAFE_FUNCTIONS      _SC_THREAD_SAFE_FUNCTIONS
137+_POSIX_THREAD_SPORADIC_SERVER     _SC_THREAD_SPORADIC_SERVER
138+_POSIX_THREADS                    _SC_THREADS
139+_POSIX_TIMEOUTS                   _SC_TIMEOUTS
140+_POSIX_TIMERS                     _SC_TIMERS
141+_POSIX_TRACE                      _SC_TRACE
142+_POSIX_TRACE_EVENT_FILTER         _SC_TRACE_EVENT_FILTER
143+_POSIX_TRACE_EVENT_NAME_MAX       _SC_TRACE_EVENT_NAME_MAX
144+_POSIX_TRACE_INHERIT              _SC_TRACE_INHERIT
145+_POSIX_TRACE_LOG                  _SC_TRACE_LOG
146+_POSIX_TRACE_NAME_MAX             _SC_TRACE_NAME_MAX
147+_POSIX_TRACE_SYS_MAX              _SC_TRACE_SYS_MAX
148+_POSIX_TRACE_USER_EVENT_MAX       _SC_TRACE_USER_EVENT_MAX
149+_POSIX_TYPED_MEMORY_OBJECTS       _SC_TYPED_MEMORY_OBJECTS
150+_POSIX_VERSION                    _SC_VERSION
151+_POSIX_V7_ILP32_OFF32             _SC_V7_ILP32_OFF32
152+_POSIX_V7_ILP32_OFFBIG            _SC_V7_ILP32_OFFBIG
153+_POSIX_V7_LP64_OFF64              _SC_V7_LP64_OFF64
154+_POSIX_V7_LPBIG_OFFBIG            _SC_V7_LPBIG_OFFBIG
155+_POSIX2_C_BIND                    _SC_2_C_BIND
156+_POSIX2_C_DEV                     _SC_2_C_DEV
157+_POSIX2_CHAR_TERM                 _SC_2_CHAR_TERM
158+_POSIX2_FORT_DEV                  _SC_2_FORT_DEV
159+_POSIX2_FORT_RUN                  _SC_2_FORT_RUN
160+_POSIX2_LOCALEDEF                 _SC_2_LOCALEDEF
161+_POSIX2_PBS                       _SC_2_PBS
162+_POSIX2_PBS_ACCOUNTING            _SC_2_PBS_ACCOUNTING
163+_POSIX2_PBS_CHECKPOINT            _SC_2_PBS_CHECKPOINT
164+_POSIX2_PBS_LOCATE                _SC_2_PBS_LOCATE
165+_POSIX2_PBS_MESSAGE               _SC_2_PBS_MESSAGE
166+_POSIX2_PBS_TRACK                 _SC_2_PBS_TRACK
167+_POSIX2_SW_DEV                    _SC_2_SW_DEV
168+_POSIX2_UPE                       _SC_2_UPE
169+_POSIX2_VERSION                   _SC_2_VERSION
170+PAGE_SIZE                         _SC_PAGE_SIZE
171+PAGESIZE                          _SC_PAGESIZE
172+PTHREAD_DESTRUCTOR_ITERATIONS     _SC_THREAD_DESTRUCTOR_ITERATIONS
173+PTHREAD_KEYS_MAX                  _SC_THREAD_KEYS_MAX
174+PTHREAD_STACK_MIN                 _SC_THREAD_STACK_MIN
175+PTHREAD_THREADS_MAX               _SC_THREAD_THREADS_MAX
176+RE_DUP_MAX                        _SC_RE_DUP_MAX
177+RTSIG_MAX                         _SC_RTSIG_MAX
178+SEM_NSEMS_MAX                     _SC_SEM_NSEMS_MAX
179+SEM_VALUE_MAX                     _SC_SEM_VALUE_MAX
180+SIGQUEUE_MAX                      _SC_SIGQUEUE_MAX
181+STREAM_MAX                        _SC_STREAM_MAX
182+SYMLOOP_MAX                       _SC_SYMLOOP_MAX
183+TIMER_MAX                         _SC_TIMER_MAX
184+TTY_NAME_MAX                      _SC_TTY_NAME_MAX
185+TZNAME_MAX                        _SC_TZNAME_MAX
186+_XOPEN_CRYPT                      _SC_XOPEN_CRYPT
187+_XOPEN_ENH_I18N                   _SC_XOPEN_ENH_I18N
188+_XOPEN_REALTIME                   _SC_XOPEN_REALTIME
189+_XOPEN_REALTIME_THREADS           _SC_XOPEN_REALTIME_THREADS
190+_XOPEN_SHM                        _SC_XOPEN_SHM
191+_XOPEN_STREAMS                    _SC_XOPEN_STREAMS
192+_XOPEN_UNIX                       _SC_XOPEN_UNIX
193+_XOPEN_UUCP                       _SC_XOPEN_UUCP
194+_XOPEN_VERSION                    _SC_XOPEN_VERSION
195+EOF
196+
197+ifdef pathconf_l << EOF
198+FILESIZEBITS                _PC_FILESIZEBITS
199+LINK_MAX                    _PC_LINK_MAX
200+MAX_CANON                   _PC_MAX_CANON
201+MAX_INPUT                   _PC_MAX_INPUT
202+NAME_MAX                    _PC_NAME_MAX
203+PATH_MAX                    _PC_PATH_MAX
204+PIPE_BUF                    _PC_PIPE_BUF
205+POSIX2_SYMLINKS             _PC_2_SYMLINKS
206+POSIX_ALLOC_SIZE_MIN        _PC_ALLOC_SIZE_MIN
207+POSIX_REC_INCR_XFER_SIZE    _PC_REC_INCR_XFER_SIZE
208+POSIX_REC_MAX_XFER_SIZE     _PC_REC_MAX_XFER_SIZE
209+POSIX_REC_MIN_XFER_SIZE     _PC_REC_MIN_XFER_SIZE
210+POSIX_REC_XFER_ALIGN        _PC_REC_XFER_ALIGN
211+SYMLINK_MAX                 _PC_SYMLINK_MAX
212+_POSIX_CHOWN_RESTRICTED     _PC_CHOWN_RESTRICTED
213+_POSIX_NO_TRUNC             _PC_NO_TRUNC
214+_POSIX_VDISABLE             _PC_VDISABLE
215+_POSIX_ASYNC_IO             _PC_ASYNC_IO
216+_POSIX_PRIO_IO              _PC_PRIO_IO
217+_POSIX_SYNC_IO              _PC_SYNC_IO
218+_POSIX_TIMESTAMP_RESOLUTION _PC_TIMESTAMP_RESOLUTION
219+EOF
+278, -0
  1@@ -0,0 +1,278 @@
  2+#!/bin/sh
  3+# mkbox - build aruu-box, the aruu multi-call binary
  4+#
  5+# expects CC CPPFLAGS CFLAGS LDFLAGS LDLIBS OBJCOPY from the environment;
  6+# defaults match config.mk but can be overridden
  7+#
  8+# run from the source root (the Makefile does this automatically)
  9+
 10+set -e
 11+
 12+: "${CC:=cc}"
 13+: "${CPPFLAGS:=-Ishared -D_DEFAULT_SOURCE -D_GNU_SOURCE -D_NETBSD_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_FILE_OFFSET_BITS=64 -DSTD_NON_POSIX}"
 14+: "${CFLAGS:=-std=c99 -Wall -Wextra -pedantic}"
 15+: "${LDFLAGS:=}"
 16+: "${LDLIBS:=-lcrypt -lresolv}"
 17+: "${OBJCOPY:=objcopy}"
 18+
 19+ROOT=$(CDPATH= cd "$(dirname "$0")/.." && pwd)
 20+BDIR="${ROOT}/.box"
 21+BOX="${ROOT}/aruu-box"
 22+LIBUTIL="${ROOT}/shared/libutil/libutil.a"
 23+LIBUTF="${ROOT}/shared/libutf/libutf.a"
 24+
 25+die() {
 26+	printf 'mkbox: %s\n' "$*" >&2
 27+	exit 1
 28+}
 29+
 30+# Clean up build directory on exit or signal termination
 31+trap 'rm -rf "${BDIR}"' EXIT INT QUIT TERM
 32+
 33+[ -f "${LIBUTIL}" ] || die "libutil.a not found; run 'make' first"
 34+[ -f "${LIBUTF}" ]  || die "libutf.a not found; run 'make' first"
 35+
 36+[ -f "${ROOT}/cmd/posix/getconf.h" ] || {
 37+	printf 'mkbox: generating getconf.h\n'
 38+	"${ROOT}/scripts/getconf.sh" > "${ROOT}/cmd/posix/getconf.h" ||
 39+		die "scripts/getconf.sh failed"
 40+}
 41+
 42+rm -rf "${BDIR}"
 43+mkdir -p "${BDIR}"
 44+
 45+OBJS=""
 46+DECL_F="${BDIR}/decls.inc"
 47+ENT_F="${BDIR}/entries.inc"
 48+: > "${DECL_F}"
 49+: > "${ENT_F}"
 50+
 51+alias_entry() {
 52+	printf '\t{ "%s", %s_main, "%s" },\n' "$1" "$2" "$3" >> "${ENT_F}"
 53+}
 54+
 55+compile_tool() {
 56+	src="$1"
 57+	name="$2"
 58+	fn="$3"
 59+	catg="$4"
 60+	extra="${5:-}"
 61+	out="${BDIR}/${fn}.o"
 62+	symf="${BDIR}/${fn}.syms"
 63+
 64+	printf 'mkbox: cc %s\n' "${name}"
 65+	eval "${CC} ${CPPFLAGS} ${extra} ${CFLAGS} -c \"\$src\" -o \"\$out\"" ||
 66+		die "compile failed: ${src}"
 67+	printf 'main %s_main\n' "${fn}" > "${symf}"
 68+	${OBJCOPY} --redefine-syms="${symf}" "${out}" ||
 69+		die "objcopy failed: ${name}"
 70+	${OBJCOPY} --keep-global-symbol="${fn}_main" "${out}" ||
 71+		die "objcopy localize failed: ${name}"
 72+	rm -f "${symf}"
 73+	OBJS="${OBJS} ${out}"
 74+	printf 'int %s_main(int, char **);\n' "${fn}" >> "${DECL_F}"
 75+	printf '\t{ "%s", %s_main, "%s" },\n' "${name}" "${fn}" "${catg}" >> "${ENT_F}"
 76+}
 77+
 78+compile_make() {
 79+	mdir="${ROOT}/cmd/posix/make"
 80+	symf="${BDIR}/make.syms"
 81+	printf 'mkbox: cc make (multi)\n'
 82+	make_objs=""
 83+	for s in defaults parser posix rules; do
 84+		out="${BDIR}/make_${s}.o"
 85+		eval "${CC} ${CPPFLAGS} ${CFLAGS} -I\"\$mdir\" -c \"\$mdir/\$s.c\" -o \"\$out\"" ||
 86+			die "compile failed: make/${s}.c"
 87+		make_objs="${make_objs} ${out}"
 88+	done
 89+	out_main="${BDIR}/make_main.o"
 90+	eval "${CC} ${CPPFLAGS} ${CFLAGS} -I\"\$mdir\" -c \"\$mdir/main.c\" -o \"\${out_main}\"" ||
 91+		die "compile failed: make/main.c"
 92+	make_objs="${make_objs} ${out_main}"
 93+
 94+	# Combined incremental link to resolve internal symbols cleanly
 95+	combined="${BDIR}/make_combined.o"
 96+	${LD:-ld} -r -o "${combined}" ${make_objs} ||
 97+		die "ld -r failed: make"
 98+
 99+	printf 'main make_main\n' > "${symf}"
100+	${OBJCOPY} --redefine-syms="${symf}" "${combined}" ||
101+		die "objcopy failed: make"
102+	${OBJCOPY} --keep-global-symbol=make_main "${combined}" ||
103+		die "objcopy localize failed: make"
104+	rm -f "${symf}" ${make_objs}
105+
106+	OBJS="${OBJS} ${combined}"
107+	printf 'int make_main(int, char **);\n' >> "${DECL_F}"
108+	printf '\t{ "make", make_main, "posix/make" },\n' >> "${ENT_F}"
109+}
110+
111+process_dir() {
112+	dir="$1"
113+	catg="$2"
114+	extra="${3:-}"
115+	for src in "${dir}"/*.c; do
116+		[ -f "${src}" ] || continue
117+		name=${src##*/}
118+		name=${name%.c}
119+		fn=$(printf '%s' "${name}" | tr '.-' '__')
120+		compile_tool "${src}" "${name}" "${fn}" "${catg}" "${extra}"
121+		if [ "${name}" = "test" ]; then
122+			alias_entry "[" "test" "${catg}"
123+		fi
124+		if [ "${name}" = "xinstall" ]; then
125+			alias_entry "install" "xinstall" "${catg}"
126+		fi
127+	done
128+}
129+
130+process_dir "${ROOT}/cmd/posix" "posix"
131+compile_make
132+process_dir "${ROOT}/cmd/linux" "linux"
133+process_dir "${ROOT}/cmd/net" "net"
134+process_dir "${ROOT}/cmd/pseudo" "pseudo"
135+process_dir "${ROOT}/cmd/xsi" "xsi"
136+
137+DISP="${BDIR}/aruu-box.c"
138+printf 'mkbox: generating dispatch\n'
139+
140+cat > "${DISP}" << 'DISPATCH_HEAD'
141+/* This software is released into the public domain, or
142+   registered under the ISC License, see ./LICENSE for details
143+   2026 xplshn [anto@xplshn.com.ar](mailto:anto@xplshn.com.ar) */
144+
145+/* routes argv[0] to the appropriate tool main */
146+#include "util.h"
147+
148+#include <stdio.h>
149+#include <stdlib.h>
150+#include <string.h>
151+#include <unistd.h>
152+
153+extern char *argv0;
154+
155+DISPATCH_HEAD
156+
157+cat "${DECL_F}" >> "${DISP}"
158+
159+cat >> "${DISP}" << 'DISPATCH_STRUCT'
160+
161+struct Cmd {
162+	const char *name;
163+	int (*fn)(int, char **);
164+	const char *cat;
165+};
166+
167+static struct Cmd cmds[] = {
168+DISPATCH_STRUCT
169+
170+cat "${ENT_F}" >> "${DISP}"
171+
172+cat >> "${DISP}" << 'DISPATCH_TAIL'
173+	{ NULL, NULL, NULL }
174+};
175+
176+static void
177+usage(void)
178+{
179+	struct Cmd *c;
180+	const char *last;
181+	int col;
182+
183+	last = NULL;
184+	col = 0;
185+	fprintf(stderr, "usage: %s [-i path] [command [args...]]\n", argv0);
186+	for (c = cmds; c->name; c++) {
187+		if (!last || strcmp(c->cat, last) != 0) {
188+			if (last)
189+				fprintf(stderr, "\n\n");
190+			last = c->cat;
191+			fprintf(stderr, "%s:\n", last);
192+			col = 0;
193+		}
194+		if (col == 0) {
195+			fprintf(stderr, "\t%s", c->name);
196+			col = 8 + strlen(c->name);
197+		} else if (col + 2 + strlen(c->name) >= 78) {
198+			fprintf(stderr, ",\n\t%s", c->name);
199+			col = 8 + strlen(c->name);
200+		} else {
201+			fprintf(stderr, ", %s", c->name);
202+			col += 2 + strlen(c->name);
203+		}
204+	}
205+	if (last)
206+		fputc('\n', stderr);
207+	exit(1);
208+}
209+
210+static void
211+x_install(const char *path)
212+{
213+	struct Cmd *c;
214+	char buf[4096];
215+	int r;
216+
217+	for (c = cmds; c->name; c++) {
218+		r = snprintf(buf, sizeof buf, "%s/%s", path, c->name);
219+		if (r < 0 || r >= (int)sizeof buf)
220+			eprintf("install: '%s/%s': path too long\n", path, c->name);
221+		remove(buf);
222+		if (symlink("aruu-box", buf) < 0)
223+			eprintf("install: symlink '%s':", buf);
224+	}
225+}
226+
227+int
228+main(int argc, char *argv[])
229+{
230+	struct Cmd *c;
231+	char *s;
232+
233+	argv0 = argv[0];
234+
235+	s = strrchr(argv[0], '/');
236+	if (s)
237+		s++;
238+	else
239+		s = argv[0];
240+
241+	if (strcmp(s, "aruu-box") == 0) {
242+		if (argc < 2)
243+			usage();
244+		argc--;
245+		argv++;
246+		if (strcmp(argv[0], "-i") == 0) {
247+			if (argc < 2)
248+				eprintf("usage: aruu-box -i path\n");
249+			x_install(argv[1]);
250+			return 0;
251+		}
252+		s = strrchr(argv[0], '/');
253+		if (s)
254+			s++;
255+		else
256+			s = argv[0];
257+	}
258+	for (c = cmds; c->name; c++) {
259+		if (strcmp(c->name, s) == 0) {
260+			argv0 = (char *)c->name;
261+			argv[0] = (char *)c->name;
262+			return c->fn(argc, argv);
263+		}
264+	}
265+	enprintf(127, "%s: not found\n", s);
266+	return 1;
267+}
268+DISPATCH_TAIL
269+
270+printf 'mkbox: cc dispatch\n'
271+eval "${CC} ${CPPFLAGS} ${CFLAGS} -c \"\$DISP\" -o \"\${BDIR}/aruu-box.o\"" ||
272+	die "compile failed: dispatch"
273+OBJS="${OBJS} ${BDIR}/aruu-box.o"
274+
275+printf 'mkbox: ld aruu-box\n'
276+eval "${CC} ${LDFLAGS} -o \"\$BOX\" \$OBJS \"\$LIBUTIL\" \"\$LIBUTF\" \${LDLIBS}" ||
277+	die "link failed"
278+
279+printf 'mkbox: done => %s\n' "${BOX}"
+65, -0
 1@@ -0,0 +1,65 @@
 2+/*
 3+ * Copy me if you can.
 4+ * by 20h
 5+ */
 6+
 7+#ifndef ARG_H__
 8+#define ARG_H__
 9+
10+extern char *argv0;
11+
12+/* use main(int argc, char *argv[]) */
13+#define ARGBEGIN	for (argv0 = *argv, argv++, argc--;\
14+					argv[0] && argv[0][0] == '-'\
15+					&& argv[0][1];\
16+					argc--, argv++) {\
17+				char argc_;\
18+				char **argv_;\
19+				int brk_;\
20+				if (argv[0][1] == '-' && argv[0][2] == '\0') {\
21+					argv++;\
22+					argc--;\
23+					break;\
24+				}\
25+				for (brk_ = 0, argv[0]++, argv_ = argv;\
26+						argv[0][0] && !brk_;\
27+						argv[0]++) {\
28+					if (argv_ != argv)\
29+						break;\
30+					argc_ = argv[0][0];\
31+					switch (argc_)
32+
33+/* Handles obsolete -NUM syntax */
34+#define ARGNUM				case '0':\
35+					case '1':\
36+					case '2':\
37+					case '3':\
38+					case '4':\
39+					case '5':\
40+					case '6':\
41+					case '7':\
42+					case '8':\
43+					case '9'
44+
45+#define ARGEND			}\
46+			}
47+
48+#define ARGC()		argc_
49+
50+#define ARGNUMF()	(brk_ = 1, estrtonum(argv[0], 0, INT_MAX))
51+
52+#define EARGF(x)	((argv[0][1] == '\0' && argv[1] == NULL)?\
53+				((x), abort(), (char *)0) :\
54+				(brk_ = 1, (argv[0][1] != '\0')?\
55+					(&argv[0][1]) :\
56+					(argc--, argv++, argv[0])))
57+
58+#define ARGF()		((argv[0][1] == '\0' && argv[1] == NULL)?\
59+				(char *)0 :\
60+				(brk_ = 1, (argv[0][1] != '\0')?\
61+					(&argv[0][1]) :\
62+					(argc--, argv++, argv[0])))
63+
64+#define LNGARG()	&argv[0][0]
65+
66+#endif
+6, -0
1@@ -0,0 +1,6 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <limits.h>
4+
5+#ifndef HOST_NAME_MAX
6+#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
7+#endif
+10, -0
 1@@ -0,0 +1,10 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#define ENV_PATH	"/bin"
 5+#define PW_CIPHER	"$6$"	/* SHA-512 */
 6+#undef UTMP_PATH
 7+#define UTMP_PATH	"/var/run/utmp"
 8+#undef BTMP_PATH
 9+#define BTMP_PATH	"/var/log/btmp"
10+#undef WTMP_PATH
11+#define WTMP_PATH	"/var/log/wtmp"
+12, -0
 1@@ -0,0 +1,12 @@
 2+/* See LICENSE file for copyright and license details. */
 3+struct crypt_ops {
 4+	void (*init)(void *);
 5+	void (*update)(void *, const void *, unsigned long);
 6+	void (*sum)(void *, uint8_t *);
 7+	void *s;
 8+};
 9+
10+int cryptcheck(int, char **, struct crypt_ops *, uint8_t *, size_t);
11+int cryptmain(int, char **, struct crypt_ops *, uint8_t *, size_t);
12+int cryptsum(struct crypt_ops *, int, const char *, uint8_t *);
13+void mdprint(const uint8_t *, const char *, size_t);
+47, -0
 1@@ -0,0 +1,47 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <limits.h>
 4+#include <sys/stat.h>
 5+#include <sys/types.h>
 6+
 7+struct history {
 8+	struct history *prev;
 9+	dev_t dev;
10+	ino_t ino;
11+};
12+
13+struct recursor {
14+	void (*fn)(int, const char *, struct stat *, void *, struct recursor *);
15+	char path[PATH_MAX];
16+	size_t pathlen;
17+	struct history *hist;
18+	int depth;
19+	int maxdepth;
20+	int follow;
21+	int flags;
22+};
23+
24+enum {
25+	SAMEDEV  = 1 << 0,
26+	DIRFIRST = 1 << 1,
27+	SILENT   = 1 << 2,
28+	CONFIRM  = 1 << 3,
29+	IGNORE   = 1 << 4,
30+};
31+
32+extern int cp_aflag;
33+extern int cp_fflag;
34+extern int cp_iflag;
35+extern int cp_pflag;
36+extern int cp_rflag;
37+extern int cp_vflag;
38+extern int cp_follow;
39+extern int cp_status;
40+
41+extern int rm_status;
42+
43+extern int recurse_status;
44+
45+void recurse(int, const char *, void *, struct recursor *);
46+
47+int cp(const char *, const char *, int);
48+void rm(int, const char *, struct stat *st, void *, struct recursor *);
+6, -0
1@@ -0,0 +1,6 @@
2+AWK = awk
3+UNICODE = http://unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
4+
5+default:
6+	@echo Downloading and parsing $(UNICODE)
7+	@curl -\# $(UNICODE) | $(AWK) -f mkrunetype.awk
+36, -0
 1@@ -0,0 +1,36 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <string.h>
 7+
 8+#include "../utf.h"
 9+
10+int
11+fgetrune(Rune *r, FILE *fp)
12+{
13+	char buf[UTFmax];
14+	int  i = 0, c;
15+
16+	while (i < UTFmax && (c = fgetc(fp)) != EOF) {
17+		buf[i++] = c;
18+		if (charntorune(r, buf, i) > 0)
19+			break;
20+	}
21+	if (ferror(fp))
22+		return -1;
23+
24+	return i;
25+}
26+
27+int
28+efgetrune(Rune *r, FILE *fp, const char *file)
29+{
30+	int ret;
31+
32+	if ((ret = fgetrune(r, fp)) < 0) {
33+		fprintf(stderr, "fgetrune %s: %s\n", file, strerror(errno));
34+		exit(1);
35+	}
36+	return ret;
37+}
+27, -0
 1@@ -0,0 +1,27 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <string.h>
 7+
 8+#include "../utf.h"
 9+
10+int
11+fputrune(const Rune *r, FILE *fp)
12+{
13+	char buf[UTFmax];
14+
15+	return fwrite(buf, runetochar(buf, r), 1, fp);
16+}
17+
18+int
19+efputrune(const Rune *r, FILE *fp, const char *file)
20+{
21+	int ret;
22+
23+	if ((ret = fputrune(r, fp)) < 0) {
24+		fprintf(stderr, "fputrune %s: %s\n", file, strerror(errno));
25+		exit(1);
26+	}
27+	return ret;
28+}
+9, -0
 1@@ -0,0 +1,9 @@
 2+/* Automatically generated by mkrunetype.awk */
 3+#include "../utf.h"
 4+#include "runetype.h"
 5+
 6+int
 7+isalnumrune(Rune r)
 8+{
 9+	return isalpharune(r) || isdigitrune(r);
10+}
+830, -0
  1@@ -0,0 +1,830 @@
  2+/* Automatically generated by mkrunetype.awk */
  3+#include <stdlib.h>
  4+
  5+#include "../utf.h"
  6+#include "runetype.h"
  7+
  8+static const Rune alpha3[][2] = {
  9+	{ 0x00D6, 0x00D8 },
 10+	{ 0x00F6, 0x00F8 },
 11+	{ 0x02EC, 0x02EE },
 12+	{ 0x0374, 0x0376 },
 13+	{ 0x037D, 0x037F },
 14+	{ 0x0386, 0x0388 },
 15+	{ 0x038A, 0x038E },
 16+	{ 0x03A1, 0x03A3 },
 17+	{ 0x03F5, 0x03F7 },
 18+	{ 0x052F, 0x0531 },
 19+	{ 0x066F, 0x0671 },
 20+	{ 0x06D3, 0x06D5 },
 21+	{ 0x0710, 0x0712 },
 22+	{ 0x0887, 0x0889 },
 23+	{ 0x09A8, 0x09AA },
 24+	{ 0x09B0, 0x09B2 },
 25+	{ 0x09DD, 0x09DF },
 26+	{ 0x0A28, 0x0A2A },
 27+	{ 0x0A30, 0x0A32 },
 28+	{ 0x0A33, 0x0A35 },
 29+	{ 0x0A36, 0x0A38 },
 30+	{ 0x0A5C, 0x0A5E },
 31+	{ 0x0A8D, 0x0A8F },
 32+	{ 0x0A91, 0x0A93 },
 33+	{ 0x0AA8, 0x0AAA },
 34+	{ 0x0AB0, 0x0AB2 },
 35+	{ 0x0AB3, 0x0AB5 },
 36+	{ 0x0B28, 0x0B2A },
 37+	{ 0x0B30, 0x0B32 },
 38+	{ 0x0B33, 0x0B35 },
 39+	{ 0x0B5D, 0x0B5F },
 40+	{ 0x0B83, 0x0B85 },
 41+	{ 0x0B90, 0x0B92 },
 42+	{ 0x0B9A, 0x0B9E },
 43+	{ 0x0C0C, 0x0C0E },
 44+	{ 0x0C10, 0x0C12 },
 45+	{ 0x0C28, 0x0C2A },
 46+	{ 0x0C8C, 0x0C8E },
 47+	{ 0x0C90, 0x0C92 },
 48+	{ 0x0CA8, 0x0CAA },
 49+	{ 0x0CB3, 0x0CB5 },
 50+	{ 0x0CDE, 0x0CE0 },
 51+	{ 0x0D0C, 0x0D0E },
 52+	{ 0x0D10, 0x0D12 },
 53+	{ 0x0DB1, 0x0DB3 },
 54+	{ 0x0DBB, 0x0DBD },
 55+	{ 0x0E30, 0x0E32 },
 56+	{ 0x0E82, 0x0E86 },
 57+	{ 0x0E8A, 0x0E8C },
 58+	{ 0x0EA3, 0x0EA7 },
 59+	{ 0x0EB0, 0x0EB2 },
 60+	{ 0x0EC4, 0x0EC6 },
 61+	{ 0x0F47, 0x0F49 },
 62+	{ 0x10C5, 0x10C7 },
 63+	{ 0x10FA, 0x10FC },
 64+	{ 0x1248, 0x124A },
 65+	{ 0x1256, 0x125A },
 66+	{ 0x1288, 0x128A },
 67+	{ 0x12B0, 0x12B2 },
 68+	{ 0x12BE, 0x12C2 },
 69+	{ 0x12D6, 0x12D8 },
 70+	{ 0x1310, 0x1312 },
 71+	{ 0x167F, 0x1681 },
 72+	{ 0x176C, 0x176E },
 73+	{ 0x18A8, 0x18AA },
 74+	{ 0x1CEC, 0x1CEE },
 75+	{ 0x1CF3, 0x1CF5 },
 76+	{ 0x1F57, 0x1F5F },
 77+	{ 0x1FB4, 0x1FB6 },
 78+	{ 0x1FBC, 0x1FBE },
 79+	{ 0x1FC4, 0x1FC6 },
 80+	{ 0x1FF4, 0x1FF6 },
 81+	{ 0x2113, 0x2115 },
 82+	{ 0x2124, 0x212A },
 83+	{ 0x212D, 0x212F },
 84+	{ 0x2D25, 0x2D27 },
 85+	{ 0x2DA6, 0x2DA8 },
 86+	{ 0x2DAE, 0x2DB0 },
 87+	{ 0x2DB6, 0x2DB8 },
 88+	{ 0x2DBE, 0x2DC0 },
 89+	{ 0x2DC6, 0x2DC8 },
 90+	{ 0x2DCE, 0x2DD0 },
 91+	{ 0x2DD6, 0x2DD8 },
 92+	{ 0x309F, 0x30A1 },
 93+	{ 0x30FA, 0x30FC },
 94+	{ 0x312F, 0x3131 },
 95+	{ 0xA7D1, 0xA7D5 },
 96+	{ 0xA801, 0xA803 },
 97+	{ 0xA805, 0xA807 },
 98+	{ 0xA80A, 0xA80C },
 99+	{ 0xA8FB, 0xA8FD },
100+	{ 0xA9E4, 0xA9E6 },
101+	{ 0xA9FE, 0xAA00 },
102+	{ 0xAA42, 0xAA44 },
103+	{ 0xAAAF, 0xAAB1 },
104+	{ 0xAAC0, 0xAAC2 },
105+	{ 0xAB26, 0xAB28 },
106+	{ 0xAB2E, 0xAB30 },
107+	{ 0xAB5A, 0xAB5C },
108+	{ 0xFB1D, 0xFB1F },
109+	{ 0xFB28, 0xFB2A },
110+	{ 0xFB36, 0xFB38 },
111+	{ 0xFB3C, 0xFB40 },
112+	{ 0xFB41, 0xFB43 },
113+	{ 0xFB44, 0xFB46 },
114+	{ 0xFE74, 0xFE76 },
115+	{ 0x1000B, 0x1000D },
116+	{ 0x10026, 0x10028 },
117+	{ 0x1003A, 0x1003C },
118+	{ 0x1003D, 0x1003F },
119+	{ 0x10340, 0x10342 },
120+	{ 0x1057A, 0x1057C },
121+	{ 0x1058A, 0x1058C },
122+	{ 0x10592, 0x10594 },
123+	{ 0x10595, 0x10597 },
124+	{ 0x105A1, 0x105A3 },
125+	{ 0x105B1, 0x105B3 },
126+	{ 0x105B9, 0x105BB },
127+	{ 0x10785, 0x10787 },
128+	{ 0x107B0, 0x107B2 },
129+	{ 0x10808, 0x1080A },
130+	{ 0x10835, 0x10837 },
131+	{ 0x108F2, 0x108F4 },
132+	{ 0x10A13, 0x10A15 },
133+	{ 0x10A17, 0x10A19 },
134+	{ 0x10AC7, 0x10AC9 },
135+	{ 0x111DA, 0x111DC },
136+	{ 0x11211, 0x11213 },
137+	{ 0x11286, 0x1128A },
138+	{ 0x1128D, 0x1128F },
139+	{ 0x1129D, 0x1129F },
140+	{ 0x11328, 0x1132A },
141+	{ 0x11330, 0x11332 },
142+	{ 0x11333, 0x11335 },
143+	{ 0x114C5, 0x114C7 },
144+	{ 0x11913, 0x11915 },
145+	{ 0x11916, 0x11918 },
146+	{ 0x1193F, 0x11941 },
147+	{ 0x119E1, 0x119E3 },
148+	{ 0x11C08, 0x11C0A },
149+	{ 0x11D06, 0x11D08 },
150+	{ 0x11D09, 0x11D0B },
151+	{ 0x11D65, 0x11D67 },
152+	{ 0x11D68, 0x11D6A },
153+	{ 0x11F02, 0x11F04 },
154+	{ 0x11F10, 0x11F12 },
155+	{ 0x16FE1, 0x16FE3 },
156+	{ 0x1AFF3, 0x1AFF5 },
157+	{ 0x1AFFB, 0x1AFFD },
158+	{ 0x1AFFE, 0x1B000 },
159+	{ 0x1D454, 0x1D456 },
160+	{ 0x1D49C, 0x1D49E },
161+	{ 0x1D4AC, 0x1D4AE },
162+	{ 0x1D4B9, 0x1D4BD },
163+	{ 0x1D4C3, 0x1D4C5 },
164+	{ 0x1D505, 0x1D507 },
165+	{ 0x1D514, 0x1D516 },
166+	{ 0x1D51C, 0x1D51E },
167+	{ 0x1D539, 0x1D53B },
168+	{ 0x1D53E, 0x1D540 },
169+	{ 0x1D544, 0x1D546 },
170+	{ 0x1D550, 0x1D552 },
171+	{ 0x1D6C0, 0x1D6C2 },
172+	{ 0x1D6DA, 0x1D6DC },
173+	{ 0x1D6FA, 0x1D6FC },
174+	{ 0x1D714, 0x1D716 },
175+	{ 0x1D734, 0x1D736 },
176+	{ 0x1D74E, 0x1D750 },
177+	{ 0x1D76E, 0x1D770 },
178+	{ 0x1D788, 0x1D78A },
179+	{ 0x1D7A8, 0x1D7AA },
180+	{ 0x1D7C2, 0x1D7C4 },
181+	{ 0x1E7E6, 0x1E7E8 },
182+	{ 0x1E7EB, 0x1E7ED },
183+	{ 0x1E7EE, 0x1E7F0 },
184+	{ 0x1E7FE, 0x1E800 },
185+	{ 0x1EE03, 0x1EE05 },
186+	{ 0x1EE1F, 0x1EE21 },
187+	{ 0x1EE22, 0x1EE24 },
188+	{ 0x1EE27, 0x1EE29 },
189+	{ 0x1EE32, 0x1EE34 },
190+	{ 0x1EE37, 0x1EE3B },
191+	{ 0x1EE47, 0x1EE4D },
192+	{ 0x1EE4F, 0x1EE51 },
193+	{ 0x1EE52, 0x1EE54 },
194+	{ 0x1EE57, 0x1EE61 },
195+	{ 0x1EE62, 0x1EE64 },
196+	{ 0x1EE6A, 0x1EE6C },
197+	{ 0x1EE72, 0x1EE74 },
198+	{ 0x1EE77, 0x1EE79 },
199+	{ 0x1EE7C, 0x1EE80 },
200+	{ 0x1EE89, 0x1EE8B },
201+	{ 0x1EEA3, 0x1EEA5 },
202+	{ 0x1EEA9, 0x1EEAB },
203+};
204+
205+static const Rune alpha2[][2] = {
206+	{ 0x0041, 0x005A },
207+	{ 0x0061, 0x007A },
208+	{ 0x00C0, 0x00D6 },
209+	{ 0x00D8, 0x00F6 },
210+	{ 0x00F8, 0x02C1 },
211+	{ 0x02C6, 0x02D1 },
212+	{ 0x02E0, 0x02E4 },
213+	{ 0x0370, 0x0374 },
214+	{ 0x0376, 0x0377 },
215+	{ 0x037A, 0x037D },
216+	{ 0x0388, 0x038A },
217+	{ 0x038E, 0x03A1 },
218+	{ 0x03A3, 0x03F5 },
219+	{ 0x03F7, 0x0481 },
220+	{ 0x048A, 0x052F },
221+	{ 0x0531, 0x0556 },
222+	{ 0x0560, 0x0588 },
223+	{ 0x05D0, 0x05EA },
224+	{ 0x05EF, 0x05F2 },
225+	{ 0x0620, 0x064A },
226+	{ 0x066E, 0x066F },
227+	{ 0x0671, 0x06D3 },
228+	{ 0x06E5, 0x06E6 },
229+	{ 0x06EE, 0x06EF },
230+	{ 0x06FA, 0x06FC },
231+	{ 0x0712, 0x072F },
232+	{ 0x074D, 0x07A5 },
233+	{ 0x07CA, 0x07EA },
234+	{ 0x07F4, 0x07F5 },
235+	{ 0x0800, 0x0815 },
236+	{ 0x0840, 0x0858 },
237+	{ 0x0860, 0x086A },
238+	{ 0x0870, 0x0887 },
239+	{ 0x0889, 0x088E },
240+	{ 0x08A0, 0x08C9 },
241+	{ 0x0904, 0x0939 },
242+	{ 0x0958, 0x0961 },
243+	{ 0x0971, 0x0980 },
244+	{ 0x0985, 0x098C },
245+	{ 0x098F, 0x0990 },
246+	{ 0x0993, 0x09A8 },
247+	{ 0x09AA, 0x09B0 },
248+	{ 0x09B6, 0x09B9 },
249+	{ 0x09DC, 0x09DD },
250+	{ 0x09DF, 0x09E1 },
251+	{ 0x09F0, 0x09F1 },
252+	{ 0x0A05, 0x0A0A },
253+	{ 0x0A0F, 0x0A10 },
254+	{ 0x0A13, 0x0A28 },
255+	{ 0x0A2A, 0x0A30 },
256+	{ 0x0A32, 0x0A33 },
257+	{ 0x0A35, 0x0A36 },
258+	{ 0x0A38, 0x0A39 },
259+	{ 0x0A59, 0x0A5C },
260+	{ 0x0A72, 0x0A74 },
261+	{ 0x0A85, 0x0A8D },
262+	{ 0x0A8F, 0x0A91 },
263+	{ 0x0A93, 0x0AA8 },
264+	{ 0x0AAA, 0x0AB0 },
265+	{ 0x0AB2, 0x0AB3 },
266+	{ 0x0AB5, 0x0AB9 },
267+	{ 0x0AE0, 0x0AE1 },
268+	{ 0x0B05, 0x0B0C },
269+	{ 0x0B0F, 0x0B10 },
270+	{ 0x0B13, 0x0B28 },
271+	{ 0x0B2A, 0x0B30 },
272+	{ 0x0B32, 0x0B33 },
273+	{ 0x0B35, 0x0B39 },
274+	{ 0x0B5C, 0x0B5D },
275+	{ 0x0B5F, 0x0B61 },
276+	{ 0x0B85, 0x0B8A },
277+	{ 0x0B8E, 0x0B90 },
278+	{ 0x0B92, 0x0B95 },
279+	{ 0x0B99, 0x0B9A },
280+	{ 0x0B9E, 0x0B9F },
281+	{ 0x0BA3, 0x0BA4 },
282+	{ 0x0BA8, 0x0BAA },
283+	{ 0x0BAE, 0x0BB9 },
284+	{ 0x0C05, 0x0C0C },
285+	{ 0x0C0E, 0x0C10 },
286+	{ 0x0C12, 0x0C28 },
287+	{ 0x0C2A, 0x0C39 },
288+	{ 0x0C58, 0x0C5A },
289+	{ 0x0C60, 0x0C61 },
290+	{ 0x0C85, 0x0C8C },
291+	{ 0x0C8E, 0x0C90 },
292+	{ 0x0C92, 0x0CA8 },
293+	{ 0x0CAA, 0x0CB3 },
294+	{ 0x0CB5, 0x0CB9 },
295+	{ 0x0CDD, 0x0CDE },
296+	{ 0x0CE0, 0x0CE1 },
297+	{ 0x0CF1, 0x0CF2 },
298+	{ 0x0D04, 0x0D0C },
299+	{ 0x0D0E, 0x0D10 },
300+	{ 0x0D12, 0x0D3A },
301+	{ 0x0D54, 0x0D56 },
302+	{ 0x0D5F, 0x0D61 },
303+	{ 0x0D7A, 0x0D7F },
304+	{ 0x0D85, 0x0D96 },
305+	{ 0x0D9A, 0x0DB1 },
306+	{ 0x0DB3, 0x0DBB },
307+	{ 0x0DC0, 0x0DC6 },
308+	{ 0x0E01, 0x0E30 },
309+	{ 0x0E32, 0x0E33 },
310+	{ 0x0E40, 0x0E46 },
311+	{ 0x0E81, 0x0E82 },
312+	{ 0x0E86, 0x0E8A },
313+	{ 0x0E8C, 0x0EA3 },
314+	{ 0x0EA7, 0x0EB0 },
315+	{ 0x0EB2, 0x0EB3 },
316+	{ 0x0EC0, 0x0EC4 },
317+	{ 0x0EDC, 0x0EDF },
318+	{ 0x0F40, 0x0F47 },
319+	{ 0x0F49, 0x0F6C },
320+	{ 0x0F88, 0x0F8C },
321+	{ 0x1000, 0x102A },
322+	{ 0x1050, 0x1055 },
323+	{ 0x105A, 0x105D },
324+	{ 0x1065, 0x1066 },
325+	{ 0x106E, 0x1070 },
326+	{ 0x1075, 0x1081 },
327+	{ 0x10A0, 0x10C5 },
328+	{ 0x10D0, 0x10FA },
329+	{ 0x10FC, 0x1248 },
330+	{ 0x124A, 0x124D },
331+	{ 0x1250, 0x1256 },
332+	{ 0x125A, 0x125D },
333+	{ 0x1260, 0x1288 },
334+	{ 0x128A, 0x128D },
335+	{ 0x1290, 0x12B0 },
336+	{ 0x12B2, 0x12B5 },
337+	{ 0x12B8, 0x12BE },
338+	{ 0x12C2, 0x12C5 },
339+	{ 0x12C8, 0x12D6 },
340+	{ 0x12D8, 0x1310 },
341+	{ 0x1312, 0x1315 },
342+	{ 0x1318, 0x135A },
343+	{ 0x1380, 0x138F },
344+	{ 0x13A0, 0x13F5 },
345+	{ 0x13F8, 0x13FD },
346+	{ 0x1401, 0x166C },
347+	{ 0x166F, 0x167F },
348+	{ 0x1681, 0x169A },
349+	{ 0x16A0, 0x16EA },
350+	{ 0x16F1, 0x16F8 },
351+	{ 0x1700, 0x1711 },
352+	{ 0x171F, 0x1731 },
353+	{ 0x1740, 0x1751 },
354+	{ 0x1760, 0x176C },
355+	{ 0x176E, 0x1770 },
356+	{ 0x1780, 0x17B3 },
357+	{ 0x1820, 0x1878 },
358+	{ 0x1880, 0x1884 },
359+	{ 0x1887, 0x18A8 },
360+	{ 0x18B0, 0x18F5 },
361+	{ 0x1900, 0x191E },
362+	{ 0x1950, 0x196D },
363+	{ 0x1970, 0x1974 },
364+	{ 0x1980, 0x19AB },
365+	{ 0x19B0, 0x19C9 },
366+	{ 0x1A00, 0x1A16 },
367+	{ 0x1A20, 0x1A54 },
368+	{ 0x1B05, 0x1B33 },
369+	{ 0x1B45, 0x1B4C },
370+	{ 0x1B83, 0x1BA0 },
371+	{ 0x1BAE, 0x1BAF },
372+	{ 0x1BBA, 0x1BE5 },
373+	{ 0x1C00, 0x1C23 },
374+	{ 0x1C4D, 0x1C4F },
375+	{ 0x1C5A, 0x1C7D },
376+	{ 0x1C80, 0x1C88 },
377+	{ 0x1C90, 0x1CBA },
378+	{ 0x1CBD, 0x1CBF },
379+	{ 0x1CE9, 0x1CEC },
380+	{ 0x1CEE, 0x1CF3 },
381+	{ 0x1CF5, 0x1CF6 },
382+	{ 0x1D00, 0x1DBF },
383+	{ 0x1E00, 0x1F15 },
384+	{ 0x1F18, 0x1F1D },
385+	{ 0x1F20, 0x1F45 },
386+	{ 0x1F48, 0x1F4D },
387+	{ 0x1F50, 0x1F57 },
388+	{ 0x1F5F, 0x1F7D },
389+	{ 0x1F80, 0x1FB4 },
390+	{ 0x1FB6, 0x1FBC },
391+	{ 0x1FC2, 0x1FC4 },
392+	{ 0x1FC6, 0x1FCC },
393+	{ 0x1FD0, 0x1FD3 },
394+	{ 0x1FD6, 0x1FDB },
395+	{ 0x1FE0, 0x1FEC },
396+	{ 0x1FF2, 0x1FF4 },
397+	{ 0x1FF6, 0x1FFC },
398+	{ 0x2090, 0x209C },
399+	{ 0x210A, 0x2113 },
400+	{ 0x2119, 0x211D },
401+	{ 0x212A, 0x212D },
402+	{ 0x212F, 0x2139 },
403+	{ 0x213C, 0x213F },
404+	{ 0x2145, 0x2149 },
405+	{ 0x2183, 0x2184 },
406+	{ 0x2C00, 0x2CE4 },
407+	{ 0x2CEB, 0x2CEE },
408+	{ 0x2CF2, 0x2CF3 },
409+	{ 0x2D00, 0x2D25 },
410+	{ 0x2D30, 0x2D67 },
411+	{ 0x2D80, 0x2D96 },
412+	{ 0x2DA0, 0x2DA6 },
413+	{ 0x2DA8, 0x2DAE },
414+	{ 0x2DB0, 0x2DB6 },
415+	{ 0x2DB8, 0x2DBE },
416+	{ 0x2DC0, 0x2DC6 },
417+	{ 0x2DC8, 0x2DCE },
418+	{ 0x2DD0, 0x2DD6 },
419+	{ 0x2DD8, 0x2DDE },
420+	{ 0x3005, 0x3006 },
421+	{ 0x3031, 0x3035 },
422+	{ 0x303B, 0x303C },
423+	{ 0x3041, 0x3096 },
424+	{ 0x309D, 0x309F },
425+	{ 0x30A1, 0x30FA },
426+	{ 0x30FC, 0x30FF },
427+	{ 0x3105, 0x312F },
428+	{ 0x3131, 0x318E },
429+	{ 0x31A0, 0x31BF },
430+	{ 0x31F0, 0x31FF },
431+	{ 0x9FFF, 0xA48C },
432+	{ 0xA4D0, 0xA4FD },
433+	{ 0xA500, 0xA60C },
434+	{ 0xA610, 0xA61F },
435+	{ 0xA62A, 0xA62B },
436+	{ 0xA640, 0xA66E },
437+	{ 0xA67F, 0xA69D },
438+	{ 0xA6A0, 0xA6E5 },
439+	{ 0xA717, 0xA71F },
440+	{ 0xA722, 0xA788 },
441+	{ 0xA78B, 0xA7CA },
442+	{ 0xA7D0, 0xA7D1 },
443+	{ 0xA7D5, 0xA7D9 },
444+	{ 0xA7F2, 0xA801 },
445+	{ 0xA803, 0xA805 },
446+	{ 0xA807, 0xA80A },
447+	{ 0xA80C, 0xA822 },
448+	{ 0xA840, 0xA873 },
449+	{ 0xA882, 0xA8B3 },
450+	{ 0xA8F2, 0xA8F7 },
451+	{ 0xA8FD, 0xA8FE },
452+	{ 0xA90A, 0xA925 },
453+	{ 0xA930, 0xA946 },
454+	{ 0xA960, 0xA97C },
455+	{ 0xA984, 0xA9B2 },
456+	{ 0xA9E0, 0xA9E4 },
457+	{ 0xA9E6, 0xA9EF },
458+	{ 0xA9FA, 0xA9FE },
459+	{ 0xAA00, 0xAA28 },
460+	{ 0xAA40, 0xAA42 },
461+	{ 0xAA44, 0xAA4B },
462+	{ 0xAA60, 0xAA76 },
463+	{ 0xAA7E, 0xAAAF },
464+	{ 0xAAB5, 0xAAB6 },
465+	{ 0xAAB9, 0xAABD },
466+	{ 0xAADB, 0xAADD },
467+	{ 0xAAE0, 0xAAEA },
468+	{ 0xAAF2, 0xAAF4 },
469+	{ 0xAB01, 0xAB06 },
470+	{ 0xAB09, 0xAB0E },
471+	{ 0xAB11, 0xAB16 },
472+	{ 0xAB20, 0xAB26 },
473+	{ 0xAB28, 0xAB2E },
474+	{ 0xAB30, 0xAB5A },
475+	{ 0xAB5C, 0xAB69 },
476+	{ 0xAB70, 0xABE2 },
477+	{ 0xD7B0, 0xD7C6 },
478+	{ 0xD7CB, 0xD7FB },
479+	{ 0xF900, 0xFA6D },
480+	{ 0xFA70, 0xFAD9 },
481+	{ 0xFB00, 0xFB06 },
482+	{ 0xFB13, 0xFB17 },
483+	{ 0xFB1F, 0xFB28 },
484+	{ 0xFB2A, 0xFB36 },
485+	{ 0xFB38, 0xFB3C },
486+	{ 0xFB40, 0xFB41 },
487+	{ 0xFB43, 0xFB44 },
488+	{ 0xFB46, 0xFBB1 },
489+	{ 0xFBD3, 0xFD3D },
490+	{ 0xFD50, 0xFD8F },
491+	{ 0xFD92, 0xFDC7 },
492+	{ 0xFDF0, 0xFDFB },
493+	{ 0xFE70, 0xFE74 },
494+	{ 0xFE76, 0xFEFC },
495+	{ 0xFF21, 0xFF3A },
496+	{ 0xFF41, 0xFF5A },
497+	{ 0xFF66, 0xFFBE },
498+	{ 0xFFC2, 0xFFC7 },
499+	{ 0xFFCA, 0xFFCF },
500+	{ 0xFFD2, 0xFFD7 },
501+	{ 0xFFDA, 0xFFDC },
502+	{ 0x10000, 0x1000B },
503+	{ 0x1000D, 0x10026 },
504+	{ 0x10028, 0x1003A },
505+	{ 0x1003C, 0x1003D },
506+	{ 0x1003F, 0x1004D },
507+	{ 0x10050, 0x1005D },
508+	{ 0x10080, 0x100FA },
509+	{ 0x10280, 0x1029C },
510+	{ 0x102A0, 0x102D0 },
511+	{ 0x10300, 0x1031F },
512+	{ 0x1032D, 0x10340 },
513+	{ 0x10342, 0x10349 },
514+	{ 0x10350, 0x10375 },
515+	{ 0x10380, 0x1039D },
516+	{ 0x103A0, 0x103C3 },
517+	{ 0x103C8, 0x103CF },
518+	{ 0x10400, 0x1049D },
519+	{ 0x104B0, 0x104D3 },
520+	{ 0x104D8, 0x104FB },
521+	{ 0x10500, 0x10527 },
522+	{ 0x10530, 0x10563 },
523+	{ 0x10570, 0x1057A },
524+	{ 0x1057C, 0x1058A },
525+	{ 0x1058C, 0x10592 },
526+	{ 0x10594, 0x10595 },
527+	{ 0x10597, 0x105A1 },
528+	{ 0x105A3, 0x105B1 },
529+	{ 0x105B3, 0x105B9 },
530+	{ 0x105BB, 0x105BC },
531+	{ 0x10600, 0x10736 },
532+	{ 0x10740, 0x10755 },
533+	{ 0x10760, 0x10767 },
534+	{ 0x10780, 0x10785 },
535+	{ 0x10787, 0x107B0 },
536+	{ 0x107B2, 0x107BA },
537+	{ 0x10800, 0x10805 },
538+	{ 0x1080A, 0x10835 },
539+	{ 0x10837, 0x10838 },
540+	{ 0x1083F, 0x10855 },
541+	{ 0x10860, 0x10876 },
542+	{ 0x10880, 0x1089E },
543+	{ 0x108E0, 0x108F2 },
544+	{ 0x108F4, 0x108F5 },
545+	{ 0x10900, 0x10915 },
546+	{ 0x10920, 0x10939 },
547+	{ 0x10980, 0x109B7 },
548+	{ 0x109BE, 0x109BF },
549+	{ 0x10A10, 0x10A13 },
550+	{ 0x10A15, 0x10A17 },
551+	{ 0x10A19, 0x10A35 },
552+	{ 0x10A60, 0x10A7C },
553+	{ 0x10A80, 0x10A9C },
554+	{ 0x10AC0, 0x10AC7 },
555+	{ 0x10AC9, 0x10AE4 },
556+	{ 0x10B00, 0x10B35 },
557+	{ 0x10B40, 0x10B55 },
558+	{ 0x10B60, 0x10B72 },
559+	{ 0x10B80, 0x10B91 },
560+	{ 0x10C00, 0x10C48 },
561+	{ 0x10C80, 0x10CB2 },
562+	{ 0x10CC0, 0x10CF2 },
563+	{ 0x10D00, 0x10D23 },
564+	{ 0x10E80, 0x10EA9 },
565+	{ 0x10EB0, 0x10EB1 },
566+	{ 0x10F00, 0x10F1C },
567+	{ 0x10F30, 0x10F45 },
568+	{ 0x10F70, 0x10F81 },
569+	{ 0x10FB0, 0x10FC4 },
570+	{ 0x10FE0, 0x10FF6 },
571+	{ 0x11003, 0x11037 },
572+	{ 0x11071, 0x11072 },
573+	{ 0x11083, 0x110AF },
574+	{ 0x110D0, 0x110E8 },
575+	{ 0x11103, 0x11126 },
576+	{ 0x11150, 0x11172 },
577+	{ 0x11183, 0x111B2 },
578+	{ 0x111C1, 0x111C4 },
579+	{ 0x11200, 0x11211 },
580+	{ 0x11213, 0x1122B },
581+	{ 0x1123F, 0x11240 },
582+	{ 0x11280, 0x11286 },
583+	{ 0x1128A, 0x1128D },
584+	{ 0x1128F, 0x1129D },
585+	{ 0x1129F, 0x112A8 },
586+	{ 0x112B0, 0x112DE },
587+	{ 0x11305, 0x1130C },
588+	{ 0x1130F, 0x11310 },
589+	{ 0x11313, 0x11328 },
590+	{ 0x1132A, 0x11330 },
591+	{ 0x11332, 0x11333 },
592+	{ 0x11335, 0x11339 },
593+	{ 0x1135D, 0x11361 },
594+	{ 0x11400, 0x11434 },
595+	{ 0x11447, 0x1144A },
596+	{ 0x1145F, 0x11461 },
597+	{ 0x11480, 0x114AF },
598+	{ 0x114C4, 0x114C5 },
599+	{ 0x11580, 0x115AE },
600+	{ 0x115D8, 0x115DB },
601+	{ 0x11600, 0x1162F },
602+	{ 0x11680, 0x116AA },
603+	{ 0x11700, 0x1171A },
604+	{ 0x11740, 0x11746 },
605+	{ 0x11800, 0x1182B },
606+	{ 0x118A0, 0x118DF },
607+	{ 0x118FF, 0x11906 },
608+	{ 0x1190C, 0x11913 },
609+	{ 0x11915, 0x11916 },
610+	{ 0x11918, 0x1192F },
611+	{ 0x119A0, 0x119A7 },
612+	{ 0x119AA, 0x119D0 },
613+	{ 0x11A0B, 0x11A32 },
614+	{ 0x11A5C, 0x11A89 },
615+	{ 0x11AB0, 0x11AF8 },
616+	{ 0x11C00, 0x11C08 },
617+	{ 0x11C0A, 0x11C2E },
618+	{ 0x11C72, 0x11C8F },
619+	{ 0x11D00, 0x11D06 },
620+	{ 0x11D08, 0x11D09 },
621+	{ 0x11D0B, 0x11D30 },
622+	{ 0x11D60, 0x11D65 },
623+	{ 0x11D67, 0x11D68 },
624+	{ 0x11D6A, 0x11D89 },
625+	{ 0x11EE0, 0x11EF2 },
626+	{ 0x11F04, 0x11F10 },
627+	{ 0x11F12, 0x11F33 },
628+	{ 0x12000, 0x12399 },
629+	{ 0x12480, 0x12543 },
630+	{ 0x12F90, 0x12FF0 },
631+	{ 0x13000, 0x1342F },
632+	{ 0x13441, 0x13446 },
633+	{ 0x14400, 0x14646 },
634+	{ 0x16800, 0x16A38 },
635+	{ 0x16A40, 0x16A5E },
636+	{ 0x16A70, 0x16ABE },
637+	{ 0x16AD0, 0x16AED },
638+	{ 0x16B00, 0x16B2F },
639+	{ 0x16B40, 0x16B43 },
640+	{ 0x16B63, 0x16B77 },
641+	{ 0x16B7D, 0x16B8F },
642+	{ 0x16E40, 0x16E7F },
643+	{ 0x16F00, 0x16F4A },
644+	{ 0x16F93, 0x16F9F },
645+	{ 0x16FE0, 0x16FE1 },
646+	{ 0x18800, 0x18CD5 },
647+	{ 0x1AFF0, 0x1AFF3 },
648+	{ 0x1AFF5, 0x1AFFB },
649+	{ 0x1AFFD, 0x1AFFE },
650+	{ 0x1B000, 0x1B122 },
651+	{ 0x1B150, 0x1B152 },
652+	{ 0x1B164, 0x1B167 },
653+	{ 0x1B170, 0x1B2FB },
654+	{ 0x1BC00, 0x1BC6A },
655+	{ 0x1BC70, 0x1BC7C },
656+	{ 0x1BC80, 0x1BC88 },
657+	{ 0x1BC90, 0x1BC99 },
658+	{ 0x1D400, 0x1D454 },
659+	{ 0x1D456, 0x1D49C },
660+	{ 0x1D49E, 0x1D49F },
661+	{ 0x1D4A5, 0x1D4A6 },
662+	{ 0x1D4A9, 0x1D4AC },
663+	{ 0x1D4AE, 0x1D4B9 },
664+	{ 0x1D4BD, 0x1D4C3 },
665+	{ 0x1D4C5, 0x1D505 },
666+	{ 0x1D507, 0x1D50A },
667+	{ 0x1D50D, 0x1D514 },
668+	{ 0x1D516, 0x1D51C },
669+	{ 0x1D51E, 0x1D539 },
670+	{ 0x1D53B, 0x1D53E },
671+	{ 0x1D540, 0x1D544 },
672+	{ 0x1D54A, 0x1D550 },
673+	{ 0x1D552, 0x1D6A5 },
674+	{ 0x1D6A8, 0x1D6C0 },
675+	{ 0x1D6C2, 0x1D6DA },
676+	{ 0x1D6DC, 0x1D6FA },
677+	{ 0x1D6FC, 0x1D714 },
678+	{ 0x1D716, 0x1D734 },
679+	{ 0x1D736, 0x1D74E },
680+	{ 0x1D750, 0x1D76E },
681+	{ 0x1D770, 0x1D788 },
682+	{ 0x1D78A, 0x1D7A8 },
683+	{ 0x1D7AA, 0x1D7C2 },
684+	{ 0x1D7C4, 0x1D7CB },
685+	{ 0x1DF00, 0x1DF1E },
686+	{ 0x1DF25, 0x1DF2A },
687+	{ 0x1E030, 0x1E06D },
688+	{ 0x1E100, 0x1E12C },
689+	{ 0x1E137, 0x1E13D },
690+	{ 0x1E290, 0x1E2AD },
691+	{ 0x1E2C0, 0x1E2EB },
692+	{ 0x1E4D0, 0x1E4EB },
693+	{ 0x1E7E0, 0x1E7E6 },
694+	{ 0x1E7E8, 0x1E7EB },
695+	{ 0x1E7ED, 0x1E7EE },
696+	{ 0x1E7F0, 0x1E7FE },
697+	{ 0x1E800, 0x1E8C4 },
698+	{ 0x1E900, 0x1E943 },
699+	{ 0x1EE00, 0x1EE03 },
700+	{ 0x1EE05, 0x1EE1F },
701+	{ 0x1EE21, 0x1EE22 },
702+	{ 0x1EE29, 0x1EE32 },
703+	{ 0x1EE34, 0x1EE37 },
704+	{ 0x1EE4D, 0x1EE4F },
705+	{ 0x1EE51, 0x1EE52 },
706+	{ 0x1EE61, 0x1EE62 },
707+	{ 0x1EE67, 0x1EE6A },
708+	{ 0x1EE6C, 0x1EE72 },
709+	{ 0x1EE74, 0x1EE77 },
710+	{ 0x1EE79, 0x1EE7C },
711+	{ 0x1EE80, 0x1EE89 },
712+	{ 0x1EE8B, 0x1EE9B },
713+	{ 0x1EEA1, 0x1EEA3 },
714+	{ 0x1EEA5, 0x1EEA9 },
715+	{ 0x1EEAB, 0x1EEBB },
716+	{ 0x2F800, 0x2FA1D },
717+};
718+
719+static const Rune alpha1[] = {
720+	0x00AA,
721+	0x00B5,
722+	0x00BA,
723+	0x0559,
724+	0x06FF,
725+	0x07B1,
726+	0x07FA,
727+	0x081A,
728+	0x0824,
729+	0x0828,
730+	0x093D,
731+	0x0950,
732+	0x09BD,
733+	0x09CE,
734+	0x09FC,
735+	0x0ABD,
736+	0x0AD0,
737+	0x0AF9,
738+	0x0B3D,
739+	0x0B71,
740+	0x0BD0,
741+	0x0C3D,
742+	0x0C5D,
743+	0x0C80,
744+	0x0CBD,
745+	0x0D3D,
746+	0x0D4E,
747+	0x0EBD,
748+	0x0F00,
749+	0x103F,
750+	0x1061,
751+	0x108E,
752+	0x10CD,
753+	0x17D7,
754+	0x17DC,
755+	0x1AA7,
756+	0x1CFA,
757+	0x2071,
758+	0x207F,
759+	0x2102,
760+	0x2107,
761+	0x214E,
762+	0x2D2D,
763+	0x2D6F,
764+	0x2E2F,
765+	0x3400,
766+	0x4DBF,
767+	0x4E00,
768+	0xA9CF,
769+	0xAA7A,
770+	0xAC00,
771+	0xD7A3,
772+	0x1083C,
773+	0x10A00,
774+	0x10F27,
775+	0x11075,
776+	0x11144,
777+	0x11147,
778+	0x11176,
779+	0x1133D,
780+	0x11350,
781+	0x11644,
782+	0x116B8,
783+	0x11909,
784+	0x11A00,
785+	0x11A3A,
786+	0x11A50,
787+	0x11A9D,
788+	0x11C40,
789+	0x11D46,
790+	0x11D98,
791+	0x11FB0,
792+	0x16F50,
793+	0x17000,
794+	0x187F7,
795+	0x18D00,
796+	0x18D08,
797+	0x1B132,
798+	0x1B155,
799+	0x1D4A2,
800+	0x1E14E,
801+	0x1E94B,
802+	0x1EE42,
803+	0x20000,
804+	0x2A6DF,
805+	0x2A700,
806+	0x2B739,
807+	0x2B740,
808+	0x2B81D,
809+	0x2B820,
810+	0x2CEA1,
811+	0x2CEB0,
812+	0x2EBE0,
813+	0x30000,
814+	0x3134A,
815+	0x31350,
816+	0x323AF,
817+};
818+
819+int
820+isalpharune(Rune r)
821+{
822+	const Rune *match;
823+
824+	if((match = bsearch(&r, alpha3, nelem(alpha3), sizeof *alpha3, &rune2cmp)))
825+		return !((r - match[0]) % 2);
826+	if(bsearch(&r, alpha2, nelem(alpha2), sizeof *alpha2, &rune2cmp))
827+		return 1;
828+	if(bsearch(&r, alpha1, nelem(alpha1), sizeof *alpha1, &rune1cmp))
829+		return 1;
830+	return 0;
831+}
+9, -0
 1@@ -0,0 +1,9 @@
 2+/* Automatically generated by mkrunetype.awk */
 3+#include "../utf.h"
 4+#include "runetype.h"
 5+
 6+int
 7+isblankrune(Rune r)
 8+{
 9+	return r == ' ' || r == '\t';
10+}
+18, -0
 1@@ -0,0 +1,18 @@
 2+/* Automatically generated by mkrunetype.awk */
 3+#include <stdlib.h>
 4+
 5+#include "../utf.h"
 6+#include "runetype.h"
 7+
 8+static const Rune cntrl2[][2] = {
 9+	{ 0x0000, 0x001F },
10+	{ 0x007F, 0x009F },
11+};
12+
13+int
14+iscntrlrune(Rune r)
15+{
16+	if(bsearch(&r, cntrl2, nelem(cntrl2), sizeof *cntrl2, &rune2cmp))
17+		return 1;
18+	return 0;
19+}
+80, -0
 1@@ -0,0 +1,80 @@
 2+/* Automatically generated by mkrunetype.awk */
 3+#include <stdlib.h>
 4+
 5+#include "../utf.h"
 6+#include "runetype.h"
 7+
 8+static const Rune digit2[][2] = {
 9+	{ 0x0030, 0x0039 },
10+	{ 0x0660, 0x0669 },
11+	{ 0x06F0, 0x06F9 },
12+	{ 0x07C0, 0x07C9 },
13+	{ 0x0966, 0x096F },
14+	{ 0x09E6, 0x09EF },
15+	{ 0x0A66, 0x0A6F },
16+	{ 0x0AE6, 0x0AEF },
17+	{ 0x0B66, 0x0B6F },
18+	{ 0x0BE6, 0x0BEF },
19+	{ 0x0C66, 0x0C6F },
20+	{ 0x0CE6, 0x0CEF },
21+	{ 0x0D66, 0x0D6F },
22+	{ 0x0DE6, 0x0DEF },
23+	{ 0x0E50, 0x0E59 },
24+	{ 0x0ED0, 0x0ED9 },
25+	{ 0x0F20, 0x0F29 },
26+	{ 0x1040, 0x1049 },
27+	{ 0x1090, 0x1099 },
28+	{ 0x17E0, 0x17E9 },
29+	{ 0x1810, 0x1819 },
30+	{ 0x1946, 0x194F },
31+	{ 0x19D0, 0x19D9 },
32+	{ 0x1A80, 0x1A89 },
33+	{ 0x1A90, 0x1A99 },
34+	{ 0x1B50, 0x1B59 },
35+	{ 0x1BB0, 0x1BB9 },
36+	{ 0x1C40, 0x1C49 },
37+	{ 0x1C50, 0x1C59 },
38+	{ 0xA620, 0xA629 },
39+	{ 0xA8D0, 0xA8D9 },
40+	{ 0xA900, 0xA909 },
41+	{ 0xA9D0, 0xA9D9 },
42+	{ 0xA9F0, 0xA9F9 },
43+	{ 0xAA50, 0xAA59 },
44+	{ 0xABF0, 0xABF9 },
45+	{ 0xFF10, 0xFF19 },
46+	{ 0x104A0, 0x104A9 },
47+	{ 0x10D30, 0x10D39 },
48+	{ 0x11066, 0x1106F },
49+	{ 0x110F0, 0x110F9 },
50+	{ 0x11136, 0x1113F },
51+	{ 0x111D0, 0x111D9 },
52+	{ 0x112F0, 0x112F9 },
53+	{ 0x11450, 0x11459 },
54+	{ 0x114D0, 0x114D9 },
55+	{ 0x11650, 0x11659 },
56+	{ 0x116C0, 0x116C9 },
57+	{ 0x11730, 0x11739 },
58+	{ 0x118E0, 0x118E9 },
59+	{ 0x11950, 0x11959 },
60+	{ 0x11C50, 0x11C59 },
61+	{ 0x11D50, 0x11D59 },
62+	{ 0x11DA0, 0x11DA9 },
63+	{ 0x11F50, 0x11F59 },
64+	{ 0x16A60, 0x16A69 },
65+	{ 0x16AC0, 0x16AC9 },
66+	{ 0x16B50, 0x16B59 },
67+	{ 0x1D7CE, 0x1D7FF },
68+	{ 0x1E140, 0x1E149 },
69+	{ 0x1E2F0, 0x1E2F9 },
70+	{ 0x1E4F0, 0x1E4F9 },
71+	{ 0x1E950, 0x1E959 },
72+	{ 0x1FBF0, 0x1FBF9 },
73+};
74+
75+int
76+isdigitrune(Rune r)
77+{
78+	if(bsearch(&r, digit2, nelem(digit2), sizeof *digit2, &rune2cmp))
79+		return 1;
80+	return 0;
81+}
+9, -0
 1@@ -0,0 +1,9 @@
 2+/* Automatically generated by mkrunetype.awk */
 3+#include "../utf.h"
 4+#include "runetype.h"
 5+
 6+int
 7+isgraphrune(Rune r)
 8+{
 9+	return !isspacerune(r) && isprintrune(r);
10+}
+10, -0
 1@@ -0,0 +1,10 @@
 2+/* Automatically generated by mkrunetype.awk */
 3+#include "../utf.h"
 4+#include "runetype.h"
 5+
 6+int
 7+isprintrune(Rune r)
 8+{
 9+	return !iscntrlrune(r) && (r != 0x2028) && (r != 0x2029) &&
10+	       ((r < 0xFFF9) || (r > 0xFFFB));
11+}
+9, -0
 1@@ -0,0 +1,9 @@
 2+/* Automatically generated by mkrunetype.awk */
 3+#include "../utf.h"
 4+#include "runetype.h"
 5+
 6+int
 7+ispunctrune(Rune r)
 8+{
 9+	return isgraphrune(r) && !isalnumrune(r);
10+}
+31, -0
 1@@ -0,0 +1,31 @@
 2+/* Automatically generated by mkrunetype.awk */
 3+#include <stdlib.h>
 4+
 5+#include "../utf.h"
 6+#include "runetype.h"
 7+
 8+static const Rune space2[][2] = {
 9+	{ 0x0009, 0x000D },
10+	{ 0x001C, 0x0020 },
11+	{ 0x2000, 0x200A },
12+	{ 0x2028, 0x2029 },
13+};
14+
15+static const Rune space1[] = {
16+	0x0085,
17+	0x00A0,
18+	0x1680,
19+	0x202F,
20+	0x205F,
21+	0x3000,
22+};
23+
24+int
25+isspacerune(Rune r)
26+{
27+	if(bsearch(&r, space2, nelem(space2), sizeof *space2, &rune2cmp))
28+		return 1;
29+	if(bsearch(&r, space1, nelem(space1), sizeof *space1, &rune1cmp))
30+		return 1;
31+	return 0;
32+}
+31, -0
 1@@ -0,0 +1,31 @@
 2+/* Automatically generated by mkrunetype.awk */
 3+#include <stdlib.h>
 4+
 5+#include "../utf.h"
 6+#include "runetype.h"
 7+
 8+static const Rune title2[][2] = {
 9+	{ 0x1F88, 0x1F8F },
10+	{ 0x1F98, 0x1F9F },
11+	{ 0x1FA8, 0x1FAF },
12+};
13+
14+static const Rune title1[] = {
15+	0x01C5,
16+	0x01C8,
17+	0x01CB,
18+	0x01F2,
19+	0x1FBC,
20+	0x1FCC,
21+	0x1FFC,
22+};
23+
24+int
25+istitlerune(Rune r)
26+{
27+	if(bsearch(&r, title2, nelem(title2), sizeof *title2, &rune2cmp))
28+		return 1;
29+	if(bsearch(&r, title1, nelem(title1), sizeof *title1, &rune1cmp))
30+		return 1;
31+	return 0;
32+}
+9, -0
 1@@ -0,0 +1,9 @@
 2+/* Automatically generated by mkrunetype.awk */
 3+#include "../utf.h"
 4+#include "runetype.h"
 5+
 6+int
 7+isxdigitrune(Rune r)
 8+{
 9+	return (r >= '0' && (r - '0') < 10) || (r >= 'a' && (r - 'a') < 6);
10+}
+356, -0
  1@@ -0,0 +1,356 @@
  2+/* Automatically generated by mkrunetype.awk */
  3+#include <stdlib.h>
  4+
  5+#include "../utf.h"
  6+#include "runetype.h"
  7+
  8+static const Rune lower4[][2] = {
  9+	{ 0x0101, 0x012F },
 10+	{ 0x0133, 0x0137 },
 11+	{ 0x013A, 0x0148 },
 12+	{ 0x014B, 0x0177 },
 13+	{ 0x017A, 0x017E },
 14+	{ 0x0183, 0x0185 },
 15+	{ 0x01A1, 0x01A5 },
 16+	{ 0x01B4, 0x01B6 },
 17+	{ 0x01CE, 0x01DC },
 18+	{ 0x01DF, 0x01EF },
 19+	{ 0x01F9, 0x021F },
 20+	{ 0x0223, 0x0233 },
 21+	{ 0x0247, 0x024F },
 22+	{ 0x0371, 0x0373 },
 23+	{ 0x03D9, 0x03EF },
 24+	{ 0x0461, 0x0481 },
 25+	{ 0x048B, 0x04BF },
 26+	{ 0x04C2, 0x04CE },
 27+	{ 0x04D1, 0x052F },
 28+	{ 0x1E01, 0x1E95 },
 29+	{ 0x1EA1, 0x1EFF },
 30+	{ 0x2C68, 0x2C6C },
 31+	{ 0x2C81, 0x2CE3 },
 32+	{ 0x2CEC, 0x2CEE },
 33+	{ 0xA641, 0xA66D },
 34+	{ 0xA681, 0xA69B },
 35+	{ 0xA723, 0xA72F },
 36+	{ 0xA733, 0xA76F },
 37+	{ 0xA77A, 0xA77C },
 38+	{ 0xA77F, 0xA787 },
 39+	{ 0xA791, 0xA793 },
 40+	{ 0xA797, 0xA7A9 },
 41+	{ 0xA7B5, 0xA7C3 },
 42+	{ 0xA7C8, 0xA7CA },
 43+	{ 0xA7D7, 0xA7D9 },
 44+};
 45+
 46+static const Rune lower2[][3] = {
 47+	{ 0x0061, 0x007A, 0x0041 },
 48+	{ 0x00E0, 0x00F6, 0x00C0 },
 49+	{ 0x00F8, 0x00FE, 0x00D8 },
 50+	{ 0x01AA, 0x01AB, 0x01AA },
 51+	{ 0x0234, 0x0239, 0x0234 },
 52+	{ 0x023F, 0x0240, 0x2C7E },
 53+	{ 0x0256, 0x0257, 0x0189 },
 54+	{ 0x025D, 0x025F, 0x025D },
 55+	{ 0x026D, 0x026E, 0x026D },
 56+	{ 0x0273, 0x0274, 0x0273 },
 57+	{ 0x0276, 0x027C, 0x0276 },
 58+	{ 0x027E, 0x027F, 0x027E },
 59+	{ 0x0284, 0x0286, 0x0284 },
 60+	{ 0x028A, 0x028B, 0x01B1 },
 61+	{ 0x028D, 0x0291, 0x028D },
 62+	{ 0x0295, 0x029C, 0x0295 },
 63+	{ 0x029F, 0x02AF, 0x029F },
 64+	{ 0x037B, 0x037D, 0x03FD },
 65+	{ 0x03AD, 0x03AF, 0x0388 },
 66+	{ 0x03B1, 0x03C1, 0x0391 },
 67+	{ 0x03C3, 0x03CB, 0x03A3 },
 68+	{ 0x03CD, 0x03CE, 0x038E },
 69+	{ 0x0430, 0x044F, 0x0410 },
 70+	{ 0x0450, 0x045F, 0x0400 },
 71+	{ 0x0561, 0x0586, 0x0531 },
 72+	{ 0x0587, 0x0588, 0x0587 },
 73+	{ 0x10D0, 0x10FA, 0x1C90 },
 74+	{ 0x10FD, 0x10FF, 0x1CBD },
 75+	{ 0x13F8, 0x13FD, 0x13F0 },
 76+	{ 0x1C83, 0x1C84, 0x0421 },
 77+	{ 0x1D00, 0x1D2B, 0x1D00 },
 78+	{ 0x1D6B, 0x1D77, 0x1D6B },
 79+	{ 0x1D7A, 0x1D7C, 0x1D7A },
 80+	{ 0x1D7E, 0x1D8D, 0x1D7E },
 81+	{ 0x1D8F, 0x1D9A, 0x1D8F },
 82+	{ 0x1E96, 0x1E9A, 0x1E96 },
 83+	{ 0x1E9C, 0x1E9D, 0x1E9C },
 84+	{ 0x1F00, 0x1F07, 0x1F08 },
 85+	{ 0x1F10, 0x1F15, 0x1F18 },
 86+	{ 0x1F20, 0x1F27, 0x1F28 },
 87+	{ 0x1F30, 0x1F37, 0x1F38 },
 88+	{ 0x1F40, 0x1F45, 0x1F48 },
 89+	{ 0x1F60, 0x1F67, 0x1F68 },
 90+	{ 0x1F70, 0x1F71, 0x1FBA },
 91+	{ 0x1F72, 0x1F75, 0x1FC8 },
 92+	{ 0x1F76, 0x1F77, 0x1FDA },
 93+	{ 0x1F78, 0x1F79, 0x1FF8 },
 94+	{ 0x1F7A, 0x1F7B, 0x1FEA },
 95+	{ 0x1F7C, 0x1F7D, 0x1FFA },
 96+	{ 0x1F80, 0x1F87, 0x1F88 },
 97+	{ 0x1F90, 0x1F97, 0x1F98 },
 98+	{ 0x1FA0, 0x1FA7, 0x1FA8 },
 99+	{ 0x1FB0, 0x1FB1, 0x1FB8 },
100+	{ 0x1FB6, 0x1FB7, 0x1FB6 },
101+	{ 0x1FC6, 0x1FC7, 0x1FC6 },
102+	{ 0x1FD0, 0x1FD1, 0x1FD8 },
103+	{ 0x1FD2, 0x1FD3, 0x1FD2 },
104+	{ 0x1FD6, 0x1FD7, 0x1FD6 },
105+	{ 0x1FE0, 0x1FE1, 0x1FE8 },
106+	{ 0x1FE2, 0x1FE4, 0x1FE2 },
107+	{ 0x1FE6, 0x1FE7, 0x1FE6 },
108+	{ 0x1FF6, 0x1FF7, 0x1FF6 },
109+	{ 0x210E, 0x210F, 0x210E },
110+	{ 0x213C, 0x213D, 0x213C },
111+	{ 0x2146, 0x2149, 0x2146 },
112+	{ 0x2C30, 0x2C5F, 0x2C00 },
113+	{ 0x2C77, 0x2C7B, 0x2C77 },
114+	{ 0x2D00, 0x2D25, 0x10A0 },
115+	{ 0xA730, 0xA731, 0xA730 },
116+	{ 0xA771, 0xA778, 0xA771 },
117+	{ 0xAB30, 0xAB52, 0xAB30 },
118+	{ 0xAB54, 0xAB5A, 0xAB54 },
119+	{ 0xAB60, 0xAB68, 0xAB60 },
120+	{ 0xAB70, 0xABBF, 0x13A0 },
121+	{ 0xFB00, 0xFB06, 0xFB00 },
122+	{ 0xFB13, 0xFB17, 0xFB13 },
123+	{ 0xFF41, 0xFF5A, 0xFF21 },
124+	{ 0x10428, 0x1044F, 0x10400 },
125+	{ 0x104D8, 0x104FB, 0x104B0 },
126+	{ 0x10597, 0x105A1, 0x10570 },
127+	{ 0x105A3, 0x105B1, 0x1057C },
128+	{ 0x105B3, 0x105B9, 0x1058C },
129+	{ 0x105BB, 0x105BC, 0x10594 },
130+	{ 0x10CC0, 0x10CF2, 0x10C80 },
131+	{ 0x118C0, 0x118DF, 0x118A0 },
132+	{ 0x16E60, 0x16E7F, 0x16E40 },
133+	{ 0x1D41A, 0x1D433, 0x1D41A },
134+	{ 0x1D44E, 0x1D454, 0x1D44E },
135+	{ 0x1D456, 0x1D467, 0x1D456 },
136+	{ 0x1D482, 0x1D49B, 0x1D482 },
137+	{ 0x1D4B6, 0x1D4B9, 0x1D4B6 },
138+	{ 0x1D4BD, 0x1D4C3, 0x1D4BD },
139+	{ 0x1D4C5, 0x1D4CF, 0x1D4C5 },
140+	{ 0x1D4EA, 0x1D503, 0x1D4EA },
141+	{ 0x1D51E, 0x1D537, 0x1D51E },
142+	{ 0x1D552, 0x1D56B, 0x1D552 },
143+	{ 0x1D586, 0x1D59F, 0x1D586 },
144+	{ 0x1D5BA, 0x1D5D3, 0x1D5BA },
145+	{ 0x1D5EE, 0x1D607, 0x1D5EE },
146+	{ 0x1D622, 0x1D63B, 0x1D622 },
147+	{ 0x1D656, 0x1D66F, 0x1D656 },
148+	{ 0x1D68A, 0x1D6A5, 0x1D68A },
149+	{ 0x1D6C2, 0x1D6DA, 0x1D6C2 },
150+	{ 0x1D6DC, 0x1D6E1, 0x1D6DC },
151+	{ 0x1D6FC, 0x1D714, 0x1D6FC },
152+	{ 0x1D716, 0x1D71B, 0x1D716 },
153+	{ 0x1D736, 0x1D74E, 0x1D736 },
154+	{ 0x1D750, 0x1D755, 0x1D750 },
155+	{ 0x1D770, 0x1D788, 0x1D770 },
156+	{ 0x1D78A, 0x1D78F, 0x1D78A },
157+	{ 0x1D7AA, 0x1D7C2, 0x1D7AA },
158+	{ 0x1D7C4, 0x1D7C9, 0x1D7C4 },
159+	{ 0x1DF00, 0x1DF09, 0x1DF00 },
160+	{ 0x1DF0B, 0x1DF1E, 0x1DF0B },
161+	{ 0x1DF25, 0x1DF2A, 0x1DF25 },
162+	{ 0x1E922, 0x1E943, 0x1E900 },
163+};
164+
165+static const Rune lower1[][2] = {
166+	{ 0x00B5, 0x039C },
167+	{ 0x00DF, 0x00DF },
168+	{ 0x00FF, 0x0178 },
169+	{ 0x0131, 0x0049 },
170+	{ 0x0138, 0x0138 },
171+	{ 0x0149, 0x0149 },
172+	{ 0x017F, 0x0053 },
173+	{ 0x0180, 0x0243 },
174+	{ 0x0188, 0x0187 },
175+	{ 0x018C, 0x018B },
176+	{ 0x018D, 0x018D },
177+	{ 0x0192, 0x0191 },
178+	{ 0x0195, 0x01F6 },
179+	{ 0x0199, 0x0198 },
180+	{ 0x019A, 0x023D },
181+	{ 0x019B, 0x019B },
182+	{ 0x019E, 0x0220 },
183+	{ 0x01A8, 0x01A7 },
184+	{ 0x01AD, 0x01AC },
185+	{ 0x01B0, 0x01AF },
186+	{ 0x01B9, 0x01B8 },
187+	{ 0x01BA, 0x01BA },
188+	{ 0x01BD, 0x01BC },
189+	{ 0x01BE, 0x01BE },
190+	{ 0x01BF, 0x01F7 },
191+	{ 0x01C6, 0x01C4 },
192+	{ 0x01C9, 0x01C7 },
193+	{ 0x01CC, 0x01CA },
194+	{ 0x01DD, 0x018E },
195+	{ 0x01F0, 0x01F0 },
196+	{ 0x01F3, 0x01F1 },
197+	{ 0x01F5, 0x01F4 },
198+	{ 0x0221, 0x0221 },
199+	{ 0x023C, 0x023B },
200+	{ 0x0242, 0x0241 },
201+	{ 0x0250, 0x2C6F },
202+	{ 0x0251, 0x2C6D },
203+	{ 0x0252, 0x2C70 },
204+	{ 0x0253, 0x0181 },
205+	{ 0x0254, 0x0186 },
206+	{ 0x0255, 0x0255 },
207+	{ 0x0258, 0x0258 },
208+	{ 0x0259, 0x018F },
209+	{ 0x025A, 0x025A },
210+	{ 0x025B, 0x0190 },
211+	{ 0x025C, 0xA7AB },
212+	{ 0x0260, 0x0193 },
213+	{ 0x0261, 0xA7AC },
214+	{ 0x0262, 0x0262 },
215+	{ 0x0263, 0x0194 },
216+	{ 0x0264, 0x0264 },
217+	{ 0x0265, 0xA78D },
218+	{ 0x0266, 0xA7AA },
219+	{ 0x0267, 0x0267 },
220+	{ 0x0268, 0x0197 },
221+	{ 0x0269, 0x0196 },
222+	{ 0x026A, 0xA7AE },
223+	{ 0x026B, 0x2C62 },
224+	{ 0x026C, 0xA7AD },
225+	{ 0x026F, 0x019C },
226+	{ 0x0270, 0x0270 },
227+	{ 0x0271, 0x2C6E },
228+	{ 0x0272, 0x019D },
229+	{ 0x0275, 0x019F },
230+	{ 0x027D, 0x2C64 },
231+	{ 0x0280, 0x01A6 },
232+	{ 0x0281, 0x0281 },
233+	{ 0x0282, 0xA7C5 },
234+	{ 0x0283, 0x01A9 },
235+	{ 0x0287, 0xA7B1 },
236+	{ 0x0288, 0x01AE },
237+	{ 0x0289, 0x0244 },
238+	{ 0x028C, 0x0245 },
239+	{ 0x0292, 0x01B7 },
240+	{ 0x0293, 0x0293 },
241+	{ 0x029D, 0xA7B2 },
242+	{ 0x029E, 0xA7B0 },
243+	{ 0x0377, 0x0376 },
244+	{ 0x0390, 0x0390 },
245+	{ 0x03AC, 0x0386 },
246+	{ 0x03B0, 0x03B0 },
247+	{ 0x03C2, 0x03A3 },
248+	{ 0x03CC, 0x038C },
249+	{ 0x03D0, 0x0392 },
250+	{ 0x03D1, 0x0398 },
251+	{ 0x03D5, 0x03A6 },
252+	{ 0x03D6, 0x03A0 },
253+	{ 0x03D7, 0x03CF },
254+	{ 0x03F0, 0x039A },
255+	{ 0x03F1, 0x03A1 },
256+	{ 0x03F2, 0x03F9 },
257+	{ 0x03F3, 0x037F },
258+	{ 0x03F5, 0x0395 },
259+	{ 0x03F8, 0x03F7 },
260+	{ 0x03FB, 0x03FA },
261+	{ 0x03FC, 0x03FC },
262+	{ 0x04CF, 0x04C0 },
263+	{ 0x0560, 0x0560 },
264+	{ 0x1C80, 0x0412 },
265+	{ 0x1C81, 0x0414 },
266+	{ 0x1C82, 0x041E },
267+	{ 0x1C85, 0x0422 },
268+	{ 0x1C86, 0x042A },
269+	{ 0x1C87, 0x0462 },
270+	{ 0x1C88, 0xA64A },
271+	{ 0x1D79, 0xA77D },
272+	{ 0x1D7D, 0x2C63 },
273+	{ 0x1D8E, 0xA7C6 },
274+	{ 0x1E9B, 0x1E60 },
275+	{ 0x1E9F, 0x1E9F },
276+	{ 0x1F50, 0x1F50 },
277+	{ 0x1F51, 0x1F59 },
278+	{ 0x1F52, 0x1F52 },
279+	{ 0x1F53, 0x1F5B },
280+	{ 0x1F54, 0x1F54 },
281+	{ 0x1F55, 0x1F5D },
282+	{ 0x1F56, 0x1F56 },
283+	{ 0x1F57, 0x1F5F },
284+	{ 0x1FB2, 0x1FB2 },
285+	{ 0x1FB3, 0x1FBC },
286+	{ 0x1FB4, 0x1FB4 },
287+	{ 0x1FBE, 0x0399 },
288+	{ 0x1FC2, 0x1FC2 },
289+	{ 0x1FC3, 0x1FCC },
290+	{ 0x1FC4, 0x1FC4 },
291+	{ 0x1FE5, 0x1FEC },
292+	{ 0x1FF2, 0x1FF2 },
293+	{ 0x1FF3, 0x1FFC },
294+	{ 0x1FF4, 0x1FF4 },
295+	{ 0x210A, 0x210A },
296+	{ 0x2113, 0x2113 },
297+	{ 0x212F, 0x212F },
298+	{ 0x2134, 0x2134 },
299+	{ 0x2139, 0x2139 },
300+	{ 0x214E, 0x2132 },
301+	{ 0x2184, 0x2183 },
302+	{ 0x2C61, 0x2C60 },
303+	{ 0x2C65, 0x023A },
304+	{ 0x2C66, 0x023E },
305+	{ 0x2C71, 0x2C71 },
306+	{ 0x2C73, 0x2C72 },
307+	{ 0x2C74, 0x2C74 },
308+	{ 0x2C76, 0x2C75 },
309+	{ 0x2CE4, 0x2CE4 },
310+	{ 0x2CF3, 0x2CF2 },
311+	{ 0x2D27, 0x10C7 },
312+	{ 0x2D2D, 0x10CD },
313+	{ 0xA78C, 0xA78B },
314+	{ 0xA78E, 0xA78E },
315+	{ 0xA794, 0xA7C4 },
316+	{ 0xA795, 0xA795 },
317+	{ 0xA7AF, 0xA7AF },
318+	{ 0xA7D1, 0xA7D0 },
319+	{ 0xA7D3, 0xA7D3 },
320+	{ 0xA7D5, 0xA7D5 },
321+	{ 0xA7F6, 0xA7F5 },
322+	{ 0xA7FA, 0xA7FA },
323+	{ 0xAB53, 0xA7B3 },
324+	{ 0x1D4BB, 0x1D4BB },
325+	{ 0x1D7CB, 0x1D7CB },
326+};
327+
328+int
329+islowerrune(Rune r)
330+{
331+	const Rune *match;
332+
333+	if((match = bsearch(&r, lower4, nelem(lower4), sizeof *lower4, &rune2cmp)))
334+		return !((r - match[0]) % 2);
335+	if(bsearch(&r, lower2, nelem(lower2), sizeof *lower2, &rune2cmp))
336+		return 1;
337+	if(bsearch(&r, lower1, nelem(lower1), sizeof *lower1, &rune1cmp))
338+		return 1;
339+	return 0;
340+}
341+
342+int
343+toupperrune(Rune r)
344+{
345+	Rune *match;
346+
347+	match = bsearch(&r, lower4, nelem(lower4), sizeof *lower4, &rune2cmp);
348+	if (match)
349+		return ((r - match[0]) % 2) ? r : r - 1;
350+	match = bsearch(&r, lower2, nelem(lower2), sizeof *lower2, &rune2cmp);
351+	if (match)
352+		return match[2] + (r - match[0]);
353+	match = bsearch(&r, lower1, nelem(lower1), sizeof *lower1, &rune1cmp);
354+	if (match)
355+		return match[1];
356+	return r;
357+}
+240, -0
  1@@ -0,0 +1,240 @@
  2+# See LICENSE file for copyright and license details.
  3+
  4+BEGIN {
  5+	FS = ";"
  6+	# set up hexadecimal lookup table
  7+	for(i = 0; i < 16; i++)
  8+		hex[sprintf("%X",i)] = i;
  9+	HEADER = "/* Automatically generated by mkrunetype.awk */\n#include <stdlib.h>\n\n#include \"../utf.h\"\n#include \"runetype.h\"\n"
 10+	HEADER_OTHER = "/* Automatically generated by mkrunetype.awk */\n#include \"../utf.h\"\n#include \"runetype.h\"\n"
 11+}
 12+
 13+$3  ~ /^L/ { alphav[alphac++] = $1; }
 14+($3  ~ /^Z/) || ($5 == "WS") || ($5 == "S") || ($5 == "B") { spacev[spacec++] = $1; }
 15+$3 == "Cc" { cntrlv[cntrlc++] = $1; }
 16+$3 == "Lu" { upperv[upperc++] = $1; tolowerv[uppercc++] = ($14 == "") ? $1 : $14; }
 17+$3 == "Ll" { lowerv[lowerc++] = $1; toupperv[lowercc++] = ($13 == "") ? $1 : $13; }
 18+$3 == "Lt" { titlev[titlec++] = $1; }
 19+$3 == "Nd" { digitv[digitc++] = $1; }
 20+
 21+END {
 22+	system("rm -f isalpharune.c isspacerune.c iscntrlrune.c upperrune.c lowerrune.c istitlerune.c isdigitrune.c");
 23+
 24+	mkis("alpha", alphav, alphac, "isalpharune.c", q, "");
 25+	mkis("space", spacev, spacec, "isspacerune.c", q, "");
 26+	mkis("cntrl", cntrlv, cntrlc, "iscntrlrune.c", q, "");
 27+	mkis("upper", upperv, upperc,   "upperrune.c", tolowerv, "lower");
 28+	mkis("lower", lowerv, lowerc,   "lowerrune.c", toupperv, "upper");
 29+	mkis("title", titlev, titlec, "istitlerune.c", q, "");
 30+	mkis("digit", digitv, digitc, "isdigitrune.c", q, "");
 31+
 32+	system("rm -f isalnumrune.c isblankrune.c isprintrune.c isgraphrune.c ispunctrune.c isxdigitrune.c");
 33+
 34+	otheris();
 35+}
 36+
 37+# parse hexadecimal rune index to int
 38+function code(s) {
 39+	x = 0;
 40+	for(i = 1; i <= length(s); i++) {
 41+		c = substr(s, i, 1);
 42+		x = (x*16) + hex[c];
 43+	}
 44+	return x;
 45+}
 46+
 47+# generate 'is<name>rune' unicode lookup function
 48+function mkis(name, runev, runec, file, casev, casename) {
 49+	rune1c = 0;
 50+	rune2c = 0;
 51+	rune3c = 0;
 52+	rune4c = 0;
 53+	mode = 1;
 54+
 55+	#sort rune groups into singletons, ranges and laces
 56+	for(j = 0; j < runec; j++) {
 57+		# range
 58+		if(code(runev[j+1]) == code(runev[j])+1 && ((length(casev) == 0) ||
 59+		   code(casev[j+1]) == code(casev[j])+1) && j+1 < runec) {
 60+			if (mode == 2) {
 61+				continue;
 62+			} else if (mode == 3) {
 63+				rune3v1[rune3c] = runev[j];
 64+				rune3c++;
 65+			} else if (mode == 4) {
 66+				rune4v1[rune4c] = runev[j];
 67+				rune4c++;
 68+			}
 69+			mode = 2;
 70+			rune2v0[rune2c] = runev[j];
 71+			if(length(casev) > 0) {
 72+				case2v[rune2c] = casev[j];
 73+			}
 74+			continue;
 75+		}
 76+		# lace 1
 77+		if(code(runev[j+1]) == code(runev[j])+2 && ((length(casev) == 0) ||
 78+		   (code(casev[j+1]) == code(runev[j+1])+1 && code(casev[j]) == code(runev[j])+1)) &&
 79+		   j+1 < runec) {
 80+			if (mode == 3) {
 81+				continue;
 82+			} else if (mode == 2) {
 83+				rune2v1[rune2c] = runev[j];
 84+				rune2c++;
 85+			} else if (mode == 4) {
 86+				rune4v1[rune2c] = runev[j];
 87+				rune4c++;
 88+			}
 89+			mode = 3;
 90+			rune3v0[rune3c] = runev[j];
 91+			continue;
 92+		}
 93+		# lace 2
 94+		if(code(runev[j+1]) == code(runev[j])+2 && ((length(casev) == 0) ||
 95+		   (code(casev[j+1]) == code(runev[j+1])-1 && code(casev[j]) == code(runev[j])-1)) &&
 96+		   j+1 < runec) {
 97+			if (mode == 4) {
 98+				continue;
 99+			} else if (mode == 2) {
100+				rune2v1[rune2c] = runev[j];
101+				rune2c++;
102+			} else if (mode == 3) {
103+				rune3v1[rune2c] = runev[j];
104+				rune3c++;
105+			}
106+			mode = 4;
107+			rune4v0[rune4c] = runev[j];
108+			continue;
109+		}
110+		# terminating case
111+		if (mode == 1) {
112+			rune1v[rune1c] = runev[j];
113+			if (length(casev) > 0) {
114+				case1v[rune1c] = casev[j];
115+			}
116+			rune1c++;
117+		} else if (mode == 2) {
118+			rune2v1[rune2c] = runev[j];
119+			rune2c++;
120+		} else if (mode == 3) {
121+			rune3v1[rune3c] = runev[j];
122+			rune3c++;
123+		} else { #lace 2
124+			rune4v1[rune4c] = runev[j];
125+			rune4c++;
126+		}
127+		mode = 1;
128+	}
129+	print HEADER > file;
130+
131+	#generate list of laces 1
132+	if(rune3c > 0) {
133+		print "static const Rune "name"3[][2] = {" > file;
134+		for(j = 0; j < rune3c; j++) {
135+			print "\t{ 0x"rune3v0[j]", 0x"rune3v1[j]" }," > file;
136+		}
137+		print "};\n" > file;
138+	}
139+
140+	#generate list of laces 2
141+	if(rune4c > 0) {
142+		print "static const Rune "name"4[][2] = {" > file;
143+		for(j = 0; j < rune4c; j++) {
144+			print "\t{ 0x"rune4v0[j]", 0x"rune4v1[j]" }," > file;
145+		}
146+		print "};\n" > file;
147+	}
148+
149+	# generate list of ranges
150+	if(rune2c > 0) {
151+		if(length(casev) > 0) {
152+			print "static const Rune "name"2[][3] = {" > file;
153+			for(j = 0; j < rune2c; j++) {
154+				print "\t{ 0x"rune2v0[j]", 0x"rune2v1[j]", 0x"case2v[j]" }," > file;
155+			}
156+		} else {
157+			print "static const Rune "name"2[][2] = {" > file
158+			for(j = 0; j < rune2c; j++) {
159+				print "\t{ 0x"rune2v0[j]", 0x"rune2v1[j]" }," > file;
160+			}
161+		}
162+		print "};\n" > file;
163+	}
164+
165+	# generate list of singletons
166+	if(rune1c > 0) {
167+		if(length(casev) > 0) {
168+			print "static const Rune "name"1[][2] = {" > file;
169+			for(j = 0; j < rune1c; j++) {
170+				print "\t{ 0x"rune1v[j]", 0x"case1v[j]" }," > file;
171+			}
172+		} else {
173+			print "static const Rune "name"1[] = {" > file;
174+			for(j = 0; j < rune1c; j++) {
175+				print "\t0x"rune1v[j]"," > file;
176+			}
177+		}
178+		print "};\n" > file;
179+	}
180+	# generate lookup function
181+	print "int\nis"name"rune(Rune r)\n{" > file;
182+	if(rune4c > 0 || rune3c > 0)
183+		print "\tconst Rune *match;\n" > file;
184+	if(rune4c > 0) {
185+		print "\tif((match = bsearch(&r, "name"4, nelem("name"4), sizeof *"name"4, &rune2cmp)))" > file;
186+		print "\t\treturn !((r - match[0]) % 2);" > file;
187+	}
188+	if(rune3c > 0) {
189+		print "\tif((match = bsearch(&r, "name"3, nelem("name"3), sizeof *"name"3, &rune2cmp)))" > file;
190+		print "\t\treturn !((r - match[0]) % 2);" > file;
191+	}
192+	if(rune2c > 0) {
193+		print "\tif(bsearch(&r, "name"2, nelem("name"2), sizeof *"name"2, &rune2cmp))\n\t\treturn 1;" > file;
194+	}
195+	if(rune1c > 0) {
196+		print "\tif(bsearch(&r, "name"1, nelem("name"1), sizeof *"name"1, &rune1cmp))\n\t\treturn 1;" > file;
197+	}
198+	print "\treturn 0;\n}" > file;
199+
200+	# generate case conversion function
201+	if(length(casev) > 0) {
202+		print "\nint\nto"casename"rune(Rune r)\n{\n\tRune *match;\n" > file;
203+		if(rune4c > 0) {
204+			print "\tmatch = bsearch(&r, "name"4, nelem("name"4), sizeof *"name"4, &rune2cmp);" > file;
205+			print "\tif (match)" > file;
206+			print "\t\treturn ((r - match[0]) % 2) ? r : r - 1;" > file;
207+		}
208+		if(rune3c > 0) {
209+			print "\tmatch = bsearch(&r, "name"3, nelem("name"3), sizeof *"name"3, &rune2cmp);" > file;
210+			print "\tif (match)" > file;
211+			print "\t\treturn ((r - match[0]) % 2) ? r : r + 1;" > file;
212+		}
213+		if(rune2c > 0) {
214+			print "\tmatch = bsearch(&r, "name"2, nelem("name"2), sizeof *"name"2, &rune2cmp);" > file;
215+			print "\tif (match)" > file;
216+			print "\t\treturn match[2] + (r - match[0]);" > file;
217+		}
218+		if(rune1c > 0) {
219+			print "\tmatch = bsearch(&r, "name"1, nelem("name"1), sizeof *"name"1, &rune1cmp);" > file;
220+			print "\tif (match)" > file;
221+			print "\t\treturn match[1];" > file;
222+		}
223+		print "\treturn r;\n}" > file;
224+	}
225+}
226+
227+function otheris() {
228+	print HEADER_OTHER > "isalnumrune.c";
229+	print "int\nisalnumrune(Rune r)\n{\n\treturn isalpharune(r) || isdigitrune(r);\n}" > "isalnumrune.c";
230+	print HEADER_OTHER > "isblankrune.c";
231+	print "int\nisblankrune(Rune r)\n{\n\treturn r == ' ' || r == '\\t';\n}" > "isblankrune.c";
232+	print HEADER_OTHER > "isprintrune.c";
233+	print "int\nisprintrune(Rune r)\n{\n\treturn !iscntrlrune(r) && (r != 0x2028) && (r != 0x2029) &&" > "isprintrune.c";
234+	print "\t       ((r < 0xFFF9) || (r > 0xFFFB));\n}" > "isprintrune.c";
235+	print HEADER_OTHER > "isgraphrune.c";
236+	print "int\nisgraphrune(Rune r)\n{\n\treturn !isspacerune(r) && isprintrune(r);\n}" > "isgraphrune.c";
237+	print HEADER_OTHER > "ispunctrune.c";
238+	print "int\nispunctrune(Rune r)\n{\n\treturn isgraphrune(r) && !isalnumrune(r);\n}" > "ispunctrune.c";
239+	print HEADER_OTHER > "isxdigitrune.c";
240+	print "int\nisxdigitrune(Rune r)\n{\n\treturn (r >= '0' && (r - '0') < 10) || (r >= 'a' && (r - 'a') < 6);\n}" > "isxdigitrune.c";
241+}
+148, -0
  1@@ -0,0 +1,148 @@
  2+/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
  3+ *
  4+ * Permission is hereby granted, free of charge, to any person obtaining a
  5+ * copy of this software and associated documentation files (the "Software"),
  6+ * to deal in the Software without restriction, including without limitation
  7+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8+ * and/or sell copies of the Software, and to permit persons to whom the
  9+ * Software is furnished to do so, subject to the following conditions:
 10+ *
 11+ * The above copyright notice and this permission notice shall be included in
 12+ * all copies or substantial portions of the Software.
 13+ *
 14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 17+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 19+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 20+ * DEALINGS IN THE SOFTWARE.
 21+ */
 22+#include "../utf.h"
 23+
 24+#define MIN(x,y)  ((x) < (y) ? (x) : (y))
 25+
 26+#define UTFSEQ(x) ((((x) & 0x80) == 0x00) ? 1 /* 0xxxxxxx */ \
 27+                 : (((x) & 0xC0) == 0x80) ? 0 /* 10xxxxxx */ \
 28+                 : (((x) & 0xE0) == 0xC0) ? 2 /* 110xxxxx */ \
 29+                 : (((x) & 0xF0) == 0xE0) ? 3 /* 1110xxxx */ \
 30+                 : (((x) & 0xF8) == 0xF0) ? 4 /* 11110xxx */ \
 31+                 : (((x) & 0xFC) == 0xF8) ? 5 /* 111110xx */ \
 32+                 : (((x) & 0xFE) == 0xFC) ? 6 /* 1111110x */ \
 33+                                          : 0 )
 34+
 35+#define BADRUNE(x) ((x) < 0 || (x) > Runemax \
 36+                || ((x) & 0xFFFE) == 0xFFFE \
 37+                || ((x) >= 0xD800 && (x) <= 0xDFFF) \
 38+                || ((x) >= 0xFDD0 && (x) <= 0xFDEF))
 39+
 40+int
 41+runetochar(char *s, const Rune *p)
 42+{
 43+	Rune r = *p;
 44+
 45+	switch(runelen(r)) {
 46+	case 1: /* 0aaaaaaa */
 47+		s[0] = r;
 48+		return 1;
 49+	case 2: /* 00000aaa aabbbbbb */
 50+		s[0] = 0xC0 | ((r & 0x0007C0) >>  6); /* 110aaaaa */
 51+		s[1] = 0x80 |  (r & 0x00003F);        /* 10bbbbbb */
 52+		return 2;
 53+	case 3: /* aaaabbbb bbcccccc */
 54+		s[0] = 0xE0 | ((r & 0x00F000) >> 12); /* 1110aaaa */
 55+		s[1] = 0x80 | ((r & 0x000FC0) >>  6); /* 10bbbbbb */
 56+		s[2] = 0x80 |  (r & 0x00003F);        /* 10cccccc */
 57+		return 3;
 58+	case 4: /* 000aaabb bbbbcccc ccdddddd */
 59+		s[0] = 0xF0 | ((r & 0x1C0000) >> 18); /* 11110aaa */
 60+		s[1] = 0x80 | ((r & 0x03F000) >> 12); /* 10bbbbbb */
 61+		s[2] = 0x80 | ((r & 0x000FC0) >>  6); /* 10cccccc */
 62+		s[3] = 0x80 |  (r & 0x00003F);        /* 10dddddd */
 63+		return 4;
 64+	default:
 65+		return 0; /* error */
 66+	}
 67+}
 68+
 69+int
 70+chartorune(Rune *p, const char *s)
 71+{
 72+	return charntorune(p, s, UTFmax);
 73+}
 74+
 75+int
 76+charntorune(Rune *p, const char *s, size_t len)
 77+{
 78+	unsigned int i, n;
 79+	Rune r;
 80+
 81+	if(len == 0) /* can't even look at s[0] */
 82+		return 0;
 83+
 84+	switch((n = UTFSEQ(s[0]))) {
 85+	case 1: r = s[0];        break; /* 0xxxxxxx */
 86+	case 2: r = s[0] & 0x1F; break; /* 110xxxxx */
 87+	case 3: r = s[0] & 0x0F; break; /* 1110xxxx */
 88+	case 4: r = s[0] & 0x07; break; /* 11110xxx */
 89+	case 5: r = s[0] & 0x03; break; /* 111110xx */
 90+	case 6: r = s[0] & 0x01; break; /* 1111110x */
 91+	default: /* invalid sequence */
 92+		*p = Runeerror;
 93+		return 1;
 94+	}
 95+	/* add values from continuation bytes */
 96+	for(i = 1; i < MIN(n, len); i++)
 97+		if((s[i] & 0xC0) == 0x80) {
 98+			/* add bits from continuation byte to rune value
 99+			 * cannot overflow: 6 byte sequences contain 31 bits */
100+			r = (r << 6) | (s[i] & 0x3F); /* 10xxxxxx */
101+		}
102+		else { /* expected continuation */
103+			*p = Runeerror;
104+			return i;
105+		}
106+
107+	if(i < n) /* must have reached len limit */
108+		return 0;
109+
110+	/* reject invalid or overlong sequences */
111+	if(BADRUNE(r) || runelen(r) < (int)n)
112+		r = Runeerror;
113+
114+	*p = r;
115+	return n;
116+}
117+
118+int
119+runelen(Rune r)
120+{
121+	if(BADRUNE(r))
122+		return 0; /* error */
123+	else if(r <= 0x7F)
124+		return 1;
125+	else if(r <= 0x07FF)
126+		return 2;
127+	else if(r <= 0xFFFF)
128+		return 3;
129+	else
130+		return 4;
131+}
132+
133+size_t
134+runenlen(const Rune *p, size_t len)
135+{
136+	size_t i, n = 0;
137+
138+	for(i = 0; i < len; i++)
139+		n += runelen(p[i]);
140+	return n;
141+}
142+
143+int
144+fullrune(const char *s, size_t len)
145+{
146+	Rune r;
147+
148+	return charntorune(&r, s, len) > 0;
149+}
+41, -0
 1@@ -0,0 +1,41 @@
 2+/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
 3+ *                            (c) 2015 Laslo Hunhold <dev@frign.de>
 4+ *
 5+ * Permission is hereby granted, free of charge, to any person obtaining a
 6+ * copy of this software and associated documentation files (the "Software"),
 7+ * to deal in the Software without restriction, including without limitation
 8+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 9+ * and/or sell copies of the Software, and to permit persons to whom the
10+ * Software is furnished to do so, subject to the following conditions:
11+ *
12+ * The above copyright notice and this permission notice shall be included in
13+ * all copies or substantial portions of the Software.
14+ *
15+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21+ * DEALINGS IN THE SOFTWARE.
22+ */
23+#include "../utf.h"
24+
25+int
26+rune1cmp(const void *v1, const void *v2)
27+{
28+	Rune r1 = *(Rune *)v1, r2 = *(Rune *)v2;
29+
30+	return r1 - r2;
31+}
32+
33+int
34+rune2cmp(const void *v1, const void *v2)
35+{
36+	Rune r = *(Rune *)v1, *p = (Rune *)v2;
37+
38+	if(r >= p[0] && r <= p[1])
39+		return 0;
40+	else
41+		return r - p[0];
42+}
+26, -0
 1@@ -0,0 +1,26 @@
 2+/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
 3+ *                            (c) 2015 Laslo Hunhold <dev@frign.de>
 4+ *
 5+ * Permission is hereby granted, free of charge, to any person obtaining a
 6+ * copy of this software and associated documentation files (the "Software"),
 7+ * to deal in the Software without restriction, including without limitation
 8+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 9+ * and/or sell copies of the Software, and to permit persons to whom the
10+ * Software is furnished to do so, subject to the following conditions:
11+ *
12+ * The above copyright notice and this permission notice shall be included in
13+ * all copies or substantial portions of the Software.
14+ *
15+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21+ * DEALINGS IN THE SOFTWARE.
22+ */
23+
24+#define nelem(x)  (sizeof (x) / sizeof *(x))
25+
26+int rune1cmp(const void *, const void *);
27+int rune2cmp(const void *, const void *);
+265, -0
  1@@ -0,0 +1,265 @@
  2+/* Automatically generated by mkrunetype.awk */
  3+#include <stdlib.h>
  4+
  5+#include "../utf.h"
  6+#include "runetype.h"
  7+
  8+static const Rune upper3[][2] = {
  9+	{ 0x0100, 0x012E },
 10+	{ 0x0132, 0x0136 },
 11+	{ 0x0139, 0x0147 },
 12+	{ 0x014A, 0x0176 },
 13+	{ 0x0179, 0x017D },
 14+	{ 0x0182, 0x0184 },
 15+	{ 0x01A0, 0x01A4 },
 16+	{ 0x01B3, 0x01B5 },
 17+	{ 0x01CD, 0x01DB },
 18+	{ 0x01DE, 0x01EE },
 19+	{ 0x01F8, 0x021E },
 20+	{ 0x0222, 0x0232 },
 21+	{ 0x0246, 0x024E },
 22+	{ 0x0370, 0x0372 },
 23+	{ 0x03D8, 0x03EE },
 24+	{ 0x0460, 0x0480 },
 25+	{ 0x048A, 0x04BE },
 26+	{ 0x04C1, 0x04CD },
 27+	{ 0x04D0, 0x052E },
 28+	{ 0x1E00, 0x1E94 },
 29+	{ 0x1EA0, 0x1EFE },
 30+	{ 0x2C67, 0x2C6B },
 31+	{ 0x2C80, 0x2CE2 },
 32+	{ 0x2CEB, 0x2CED },
 33+	{ 0xA640, 0xA66C },
 34+	{ 0xA680, 0xA69A },
 35+	{ 0xA722, 0xA72E },
 36+	{ 0xA732, 0xA76E },
 37+	{ 0xA779, 0xA77B },
 38+	{ 0xA77E, 0xA786 },
 39+	{ 0xA790, 0xA792 },
 40+	{ 0xA796, 0xA7A8 },
 41+	{ 0xA7B4, 0xA7C2 },
 42+	{ 0xA7C7, 0xA7C9 },
 43+	{ 0xA7D6, 0xA7D8 },
 44+};
 45+
 46+static const Rune upper2[][3] = {
 47+	{ 0x0041, 0x005A, 0x0061 },
 48+	{ 0x00C0, 0x00D6, 0x00E0 },
 49+	{ 0x00D8, 0x00DE, 0x00F8 },
 50+	{ 0x0189, 0x018A, 0x0256 },
 51+	{ 0x01B1, 0x01B2, 0x028A },
 52+	{ 0x0388, 0x038A, 0x03AD },
 53+	{ 0x038E, 0x038F, 0x03CD },
 54+	{ 0x0391, 0x03A1, 0x03B1 },
 55+	{ 0x03A3, 0x03AB, 0x03C3 },
 56+	{ 0x03D2, 0x03D4, 0x03D2 },
 57+	{ 0x03FD, 0x03FF, 0x037B },
 58+	{ 0x0400, 0x040F, 0x0450 },
 59+	{ 0x0410, 0x042F, 0x0430 },
 60+	{ 0x0531, 0x0556, 0x0561 },
 61+	{ 0x10A0, 0x10C5, 0x2D00 },
 62+	{ 0x13A0, 0x13EF, 0xAB70 },
 63+	{ 0x13F0, 0x13F5, 0x13F8 },
 64+	{ 0x1C90, 0x1CBA, 0x10D0 },
 65+	{ 0x1CBD, 0x1CBF, 0x10FD },
 66+	{ 0x1F08, 0x1F0F, 0x1F00 },
 67+	{ 0x1F18, 0x1F1D, 0x1F10 },
 68+	{ 0x1F28, 0x1F2F, 0x1F20 },
 69+	{ 0x1F38, 0x1F3F, 0x1F30 },
 70+	{ 0x1F48, 0x1F4D, 0x1F40 },
 71+	{ 0x1F68, 0x1F6F, 0x1F60 },
 72+	{ 0x1FB8, 0x1FB9, 0x1FB0 },
 73+	{ 0x1FBA, 0x1FBB, 0x1F70 },
 74+	{ 0x1FC8, 0x1FCB, 0x1F72 },
 75+	{ 0x1FD8, 0x1FD9, 0x1FD0 },
 76+	{ 0x1FDA, 0x1FDB, 0x1F76 },
 77+	{ 0x1FE8, 0x1FE9, 0x1FE0 },
 78+	{ 0x1FEA, 0x1FEB, 0x1F7A },
 79+	{ 0x1FF8, 0x1FF9, 0x1F78 },
 80+	{ 0x1FFA, 0x1FFB, 0x1F7C },
 81+	{ 0x210B, 0x210D, 0x210B },
 82+	{ 0x2110, 0x2112, 0x2110 },
 83+	{ 0x2119, 0x211D, 0x2119 },
 84+	{ 0x212C, 0x212D, 0x212C },
 85+	{ 0x2130, 0x2131, 0x2130 },
 86+	{ 0x213E, 0x213F, 0x213E },
 87+	{ 0x2C00, 0x2C2F, 0x2C30 },
 88+	{ 0x2C7E, 0x2C7F, 0x023F },
 89+	{ 0xFF21, 0xFF3A, 0xFF41 },
 90+	{ 0x10400, 0x10427, 0x10428 },
 91+	{ 0x104B0, 0x104D3, 0x104D8 },
 92+	{ 0x10570, 0x1057A, 0x10597 },
 93+	{ 0x1057C, 0x1058A, 0x105A3 },
 94+	{ 0x1058C, 0x10592, 0x105B3 },
 95+	{ 0x10594, 0x10595, 0x105BB },
 96+	{ 0x10C80, 0x10CB2, 0x10CC0 },
 97+	{ 0x118A0, 0x118BF, 0x118C0 },
 98+	{ 0x16E40, 0x16E5F, 0x16E60 },
 99+	{ 0x1D400, 0x1D419, 0x1D400 },
100+	{ 0x1D434, 0x1D44D, 0x1D434 },
101+	{ 0x1D468, 0x1D481, 0x1D468 },
102+	{ 0x1D49E, 0x1D49F, 0x1D49E },
103+	{ 0x1D4A5, 0x1D4A6, 0x1D4A5 },
104+	{ 0x1D4A9, 0x1D4AC, 0x1D4A9 },
105+	{ 0x1D4AE, 0x1D4B5, 0x1D4AE },
106+	{ 0x1D4D0, 0x1D4E9, 0x1D4D0 },
107+	{ 0x1D504, 0x1D505, 0x1D504 },
108+	{ 0x1D507, 0x1D50A, 0x1D507 },
109+	{ 0x1D50D, 0x1D514, 0x1D50D },
110+	{ 0x1D516, 0x1D51C, 0x1D516 },
111+	{ 0x1D538, 0x1D539, 0x1D538 },
112+	{ 0x1D53B, 0x1D53E, 0x1D53B },
113+	{ 0x1D540, 0x1D544, 0x1D540 },
114+	{ 0x1D54A, 0x1D550, 0x1D54A },
115+	{ 0x1D56C, 0x1D585, 0x1D56C },
116+	{ 0x1D5A0, 0x1D5B9, 0x1D5A0 },
117+	{ 0x1D5D4, 0x1D5ED, 0x1D5D4 },
118+	{ 0x1D608, 0x1D621, 0x1D608 },
119+	{ 0x1D63C, 0x1D655, 0x1D63C },
120+	{ 0x1D670, 0x1D689, 0x1D670 },
121+	{ 0x1D6A8, 0x1D6C0, 0x1D6A8 },
122+	{ 0x1D6E2, 0x1D6FA, 0x1D6E2 },
123+	{ 0x1D71C, 0x1D734, 0x1D71C },
124+	{ 0x1D756, 0x1D76E, 0x1D756 },
125+	{ 0x1D790, 0x1D7A8, 0x1D790 },
126+	{ 0x1E900, 0x1E921, 0x1E922 },
127+};
128+
129+static const Rune upper1[][2] = {
130+	{ 0x0130, 0x0069 },
131+	{ 0x0178, 0x00FF },
132+	{ 0x0181, 0x0253 },
133+	{ 0x0186, 0x0254 },
134+	{ 0x0187, 0x0188 },
135+	{ 0x018B, 0x018C },
136+	{ 0x018E, 0x01DD },
137+	{ 0x018F, 0x0259 },
138+	{ 0x0190, 0x025B },
139+	{ 0x0191, 0x0192 },
140+	{ 0x0193, 0x0260 },
141+	{ 0x0194, 0x0263 },
142+	{ 0x0196, 0x0269 },
143+	{ 0x0197, 0x0268 },
144+	{ 0x0198, 0x0199 },
145+	{ 0x019C, 0x026F },
146+	{ 0x019D, 0x0272 },
147+	{ 0x019F, 0x0275 },
148+	{ 0x01A6, 0x0280 },
149+	{ 0x01A7, 0x01A8 },
150+	{ 0x01A9, 0x0283 },
151+	{ 0x01AC, 0x01AD },
152+	{ 0x01AE, 0x0288 },
153+	{ 0x01AF, 0x01B0 },
154+	{ 0x01B7, 0x0292 },
155+	{ 0x01B8, 0x01B9 },
156+	{ 0x01BC, 0x01BD },
157+	{ 0x01C4, 0x01C6 },
158+	{ 0x01C7, 0x01C9 },
159+	{ 0x01CA, 0x01CC },
160+	{ 0x01F1, 0x01F3 },
161+	{ 0x01F4, 0x01F5 },
162+	{ 0x01F6, 0x0195 },
163+	{ 0x01F7, 0x01BF },
164+	{ 0x0220, 0x019E },
165+	{ 0x023A, 0x2C65 },
166+	{ 0x023B, 0x023C },
167+	{ 0x023D, 0x019A },
168+	{ 0x023E, 0x2C66 },
169+	{ 0x0241, 0x0242 },
170+	{ 0x0243, 0x0180 },
171+	{ 0x0244, 0x0289 },
172+	{ 0x0245, 0x028C },
173+	{ 0x0376, 0x0377 },
174+	{ 0x037F, 0x03F3 },
175+	{ 0x0386, 0x03AC },
176+	{ 0x038C, 0x03CC },
177+	{ 0x03CF, 0x03D7 },
178+	{ 0x03F4, 0x03B8 },
179+	{ 0x03F7, 0x03F8 },
180+	{ 0x03F9, 0x03F2 },
181+	{ 0x03FA, 0x03FB },
182+	{ 0x04C0, 0x04CF },
183+	{ 0x10C7, 0x2D27 },
184+	{ 0x10CD, 0x2D2D },
185+	{ 0x1E9E, 0x00DF },
186+	{ 0x1F59, 0x1F51 },
187+	{ 0x1F5B, 0x1F53 },
188+	{ 0x1F5D, 0x1F55 },
189+	{ 0x1F5F, 0x1F57 },
190+	{ 0x1FEC, 0x1FE5 },
191+	{ 0x2102, 0x2102 },
192+	{ 0x2107, 0x2107 },
193+	{ 0x2115, 0x2115 },
194+	{ 0x2124, 0x2124 },
195+	{ 0x2126, 0x03C9 },
196+	{ 0x2128, 0x2128 },
197+	{ 0x212A, 0x006B },
198+	{ 0x212B, 0x00E5 },
199+	{ 0x2132, 0x214E },
200+	{ 0x2133, 0x2133 },
201+	{ 0x2145, 0x2145 },
202+	{ 0x2183, 0x2184 },
203+	{ 0x2C60, 0x2C61 },
204+	{ 0x2C62, 0x026B },
205+	{ 0x2C63, 0x1D7D },
206+	{ 0x2C64, 0x027D },
207+	{ 0x2C6D, 0x0251 },
208+	{ 0x2C6E, 0x0271 },
209+	{ 0x2C6F, 0x0250 },
210+	{ 0x2C70, 0x0252 },
211+	{ 0x2C72, 0x2C73 },
212+	{ 0x2C75, 0x2C76 },
213+	{ 0x2CF2, 0x2CF3 },
214+	{ 0xA77D, 0x1D79 },
215+	{ 0xA78B, 0xA78C },
216+	{ 0xA78D, 0x0265 },
217+	{ 0xA7AA, 0x0266 },
218+	{ 0xA7AB, 0x025C },
219+	{ 0xA7AC, 0x0261 },
220+	{ 0xA7AD, 0x026C },
221+	{ 0xA7AE, 0x026A },
222+	{ 0xA7B0, 0x029E },
223+	{ 0xA7B1, 0x0287 },
224+	{ 0xA7B2, 0x029D },
225+	{ 0xA7B3, 0xAB53 },
226+	{ 0xA7C4, 0xA794 },
227+	{ 0xA7C5, 0x0282 },
228+	{ 0xA7C6, 0x1D8E },
229+	{ 0xA7D0, 0xA7D1 },
230+	{ 0xA7F5, 0xA7F6 },
231+	{ 0x1D49C, 0x1D49C },
232+	{ 0x1D4A2, 0x1D4A2 },
233+	{ 0x1D546, 0x1D546 },
234+	{ 0x1D7CA, 0x1D7CA },
235+};
236+
237+int
238+isupperrune(Rune r)
239+{
240+	const Rune *match;
241+
242+	if((match = bsearch(&r, upper3, nelem(upper3), sizeof *upper3, &rune2cmp)))
243+		return !((r - match[0]) % 2);
244+	if(bsearch(&r, upper2, nelem(upper2), sizeof *upper2, &rune2cmp))
245+		return 1;
246+	if(bsearch(&r, upper1, nelem(upper1), sizeof *upper1, &rune1cmp))
247+		return 1;
248+	return 0;
249+}
250+
251+int
252+tolowerrune(Rune r)
253+{
254+	Rune *match;
255+
256+	match = bsearch(&r, upper3, nelem(upper3), sizeof *upper3, &rune2cmp);
257+	if (match)
258+		return ((r - match[0]) % 2) ? r : r + 1;
259+	match = bsearch(&r, upper2, nelem(upper2), sizeof *upper2, &rune2cmp);
260+	if (match)
261+		return match[2] + (r - match[0]);
262+	match = bsearch(&r, upper1, nelem(upper1), sizeof *upper1, &rune1cmp);
263+	if (match)
264+		return match[1];
265+	return r;
266+}
+142, -0
  1@@ -0,0 +1,142 @@
  2+/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
  3+ *
  4+ * Permission is hereby granted, free of charge, to any person obtaining a
  5+ * copy of this software and associated documentation files (the "Software"),
  6+ * to deal in the Software without restriction, including without limitation
  7+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8+ * and/or sell copies of the Software, and to permit persons to whom the
  9+ * Software is furnished to do so, subject to the following conditions:
 10+ *
 11+ * The above copyright notice and this permission notice shall be included in
 12+ * all copies or substantial portions of the Software.
 13+ *
 14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 17+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 19+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 20+ * DEALINGS IN THE SOFTWARE.
 21+ */
 22+#include <string.h>
 23+#include "../utf.h"
 24+
 25+char *
 26+utfecpy(char *to, char *end, const char *from)
 27+{
 28+	Rune r = Runeerror;
 29+	size_t i, n;
 30+
 31+	/* seek through to find final full rune */
 32+	for(i = 0; r != '\0' && (n = charntorune(&r, &from[i], end - &to[i])); i += n)
 33+		;
 34+	memcpy(to, from, i); /* copy over bytes up to this rune */
 35+
 36+	if(i > 0 && r != '\0')
 37+		to[i] = '\0'; /* terminate if unterminated */
 38+	return &to[i];
 39+}
 40+
 41+size_t
 42+utflen(const char *s)
 43+{
 44+	const char *p = s;
 45+	size_t i;
 46+	Rune r;
 47+
 48+	for(i = 0; *p != '\0'; i++)
 49+		p += chartorune(&r, p);
 50+	return i;
 51+}
 52+
 53+size_t
 54+utfnlen(const char *s, size_t len)
 55+{
 56+	const char *p = s;
 57+	size_t i;
 58+	Rune r;
 59+	int n;
 60+
 61+	for(i = 0; (n = charntorune(&r, p, len-(p-s))) && r != '\0'; i++)
 62+		p += n;
 63+	return i;
 64+}
 65+
 66+size_t
 67+utfmemlen(const char *s, size_t len)
 68+{
 69+	const char *p = s;
 70+	size_t i;
 71+	Rune r;
 72+	int n;
 73+
 74+	for(i = 0; (n = charntorune(&r, p, len-(p-s))); i++)
 75+		p += n;
 76+	return i;
 77+}
 78+
 79+char *
 80+utfrune(const char *s, Rune r)
 81+{
 82+	if(r < Runeself) {
 83+		return strchr(s, r);
 84+	}
 85+	else if(r == Runeerror) {
 86+		Rune r0;
 87+		int n;
 88+
 89+		for(; *s != '\0'; s += n) {
 90+			n = chartorune(&r0, s);
 91+			if(r == r0)
 92+				return (char *)s;
 93+		}
 94+	}
 95+	else {
 96+		char buf[UTFmax+1];
 97+		int n;
 98+
 99+		if(!(n = runetochar(buf, &r)))
100+			return NULL;
101+		buf[n] = '\0';
102+		return strstr(s, buf);
103+	}
104+	return NULL;
105+}
106+
107+char *
108+utfrrune(const char *s, Rune r)
109+{
110+	const char *p = NULL;
111+	Rune r0;
112+	int n;
113+
114+	if(r < Runeself)
115+		return strrchr(s, r);
116+
117+	for(; *s != '\0'; s += n) {
118+		n = chartorune(&r0, s);
119+		if(r == r0)
120+			p = s;
121+	}
122+	return (char *)p;
123+}
124+
125+char *
126+utfutf(const char *s, const char *t)
127+{
128+	const char *p, *q;
129+	Rune r0, r1, r2;
130+	int n, m;
131+
132+	for(chartorune(&r0, t); (s = utfrune(s, r0)); s++) {
133+		for(p = s, q = t; *q && *p; p += n, q += m) {
134+			n = chartorune(&r1, p);
135+			m = chartorune(&r2, q);
136+			if(r1 != r2)
137+				break;
138+		}
139+		if(!*q)
140+			return (char *)s;
141+	}
142+	return NULL;
143+}
+27, -0
 1@@ -0,0 +1,27 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include "../utf.h"
 4+
 5+size_t
 6+utftorunestr(const char *str, Rune *r)
 7+{
 8+	size_t i;
 9+	int n;
10+
11+	for (i = 0; (n = chartorune(&r[i], str)) && r[i]; i++)
12+		str += n;
13+
14+	return i;
15+}
16+
17+size_t
18+utfntorunestr(const char *str, size_t len, Rune *r)
19+{
20+	size_t i;
21+	int n;
22+	const char *end = str + len;
23+
24+	for (i = 0; (n = charntorune(&r[i], str, end - str)); i++)
25+		str += n;
26+
27+	return i;
28+}
+18, -0
 1@@ -0,0 +1,18 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <unistd.h>
 4+
 5+#include "../util.h"
 6+
 7+char *
 8+agetcwd(void)
 9+{
10+	char *buf;
11+	long size;
12+
13+	apathmax(&buf, &size);
14+	if (!getcwd(buf, size))
15+		eprintf("getcwd:");
16+
17+	return buf;
18+}
19+
+13, -0
 1@@ -0,0 +1,13 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <stdlib.h>
 5+#include <string.h>
 6+
 7+#include "../text.h"
 8+#include "../util.h"
 9+
10+ssize_t
11+agetline(char **p, size_t *size, FILE *fp)
12+{
13+	return getline(p, size, fp);
14+}
+22, -0
 1@@ -0,0 +1,22 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <unistd.h>
 7+
 8+#include "../util.h"
 9+
10+void
11+apathmax(char **p, long *size)
12+{
13+	errno = 0;
14+
15+	if ((*size = pathconf("/", _PC_PATH_MAX)) == -1) {
16+		if (errno == 0) {
17+			*size = BUFSIZ;
18+		} else {
19+			eprintf("pathconf:");
20+		}
21+	}
22+	*p = emalloc(*size);
23+}
+23, -0
 1@@ -0,0 +1,23 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <unistd.h>
 4+
 5+#include "../util.h"
 6+
 7+int
 8+concat(int f1, const char *s1, int f2, const char *s2)
 9+{
10+	char buf[BUFSIZ];
11+	ssize_t n;
12+
13+	while ((n = read(f1, buf, sizeof(buf))) > 0) {
14+		if (writeall(f2, buf, n) < 0) {
15+			weprintf("write %s:", s2);
16+			return -2;
17+		}
18+	}
19+	if (n < 0) {
20+		weprintf("read %s:", s1);
21+		return -1;
22+	}
23+	return 0;
24+}
+22, -0
 1@@ -0,0 +1,22 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdarg.h>
 4+#include <ctype.h>
 5+
 6+#include "../util.h"
 7+
 8+int
 9+confirm(const char *fmt, ...)
10+{
11+	int c, ans;
12+	va_list ap;
13+
14+	va_start(ap, fmt);
15+	xvprintf(fmt, ap);
16+	va_end(ap);
17+
18+	c = getchar();
19+	ans = (c == 'y' || c == 'Y');
20+	while (c != '\n' && c != EOF)
21+		c = getchar();
22+	return ans;
23+}
+176, -0
  1@@ -0,0 +1,176 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <dirent.h>
  4+#include <errno.h>
  5+#include <fcntl.h>
  6+#include <limits.h>
  7+#include <stdio.h>
  8+#include <stdlib.h>
  9+#include <string.h>
 10+#include <sys/stat.h>
 11+#include <sys/types.h>
 12+#include <unistd.h>
 13+#include <utime.h>
 14+
 15+#include "../fs.h"
 16+#include "../util.h"
 17+
 18+int cp_aflag  = 0;
 19+int cp_fflag  = 0;
 20+int cp_iflag  = 0;
 21+int cp_pflag  = 0;
 22+int cp_rflag  = 0;
 23+int cp_vflag  = 0;
 24+int cp_status = 0;
 25+int cp_follow;
 26+
 27+int
 28+cp(const char *s1, const char *s2, int depth)
 29+{
 30+	DIR *dp;
 31+	int f1, f2, flags = 0;
 32+	struct dirent *d;
 33+	struct stat st;
 34+	struct timespec times[2];
 35+	ssize_t r;
 36+	char target[PATH_MAX], ns1[PATH_MAX], ns2[PATH_MAX];
 37+
 38+	if (cp_follow == 'P' || (cp_follow == 'H' && depth))
 39+		flags |= AT_SYMLINK_NOFOLLOW;
 40+
 41+	if (fstatat(AT_FDCWD, s1, &st, flags) < 0) {
 42+		weprintf("stat %s:", s1);
 43+		cp_status = 1;
 44+		return 0;
 45+	}
 46+
 47+	if (cp_iflag && access(s2, F_OK) == 0) {
 48+		if (!confirm("overwrite '%s'? ", s2))
 49+			return 0;
 50+	}
 51+
 52+	if (cp_vflag)
 53+		printf("%s -> %s\n", s1, s2);
 54+
 55+	if (S_ISLNK(st.st_mode)) {
 56+		if ((r = readlink(s1, target, sizeof(target) - 1)) >= 0) {
 57+			target[r] = '\0';
 58+			if (cp_fflag && unlink(s2) < 0 && errno != ENOENT) {
 59+				weprintf("unlink %s:", s2);
 60+				cp_status = 1;
 61+				return 0;
 62+			} else if (symlink(target, s2) < 0) {
 63+				weprintf("symlink %s -> %s:", s2, target);
 64+				cp_status = 1;
 65+				return 0;
 66+			}
 67+		}
 68+	} else if (S_ISDIR(st.st_mode)) {
 69+		if (!cp_rflag) {
 70+			weprintf("%s is a directory\n", s1);
 71+			cp_status = 1;
 72+			return 0;
 73+		}
 74+		if (!(dp = opendir(s1))) {
 75+			weprintf("opendir %s:", s1);
 76+			cp_status = 1;
 77+			return 0;
 78+		}
 79+		if (mkdir(s2, st.st_mode) < 0 && errno != EEXIST) {
 80+			weprintf("mkdir %s:", s2);
 81+			cp_status = 1;
 82+			closedir(dp);
 83+			return 0;
 84+		}
 85+
 86+		while ((d = readdir(dp))) {
 87+			if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
 88+				continue;
 89+
 90+			estrlcpy(ns1, s1, sizeof(ns1));
 91+			if (s1[strlen(s1) - 1] != '/')
 92+				estrlcat(ns1, "/", sizeof(ns1));
 93+			estrlcat(ns1, d->d_name, sizeof(ns1));
 94+
 95+			estrlcpy(ns2, s2, sizeof(ns2));
 96+			if (s2[strlen(s2) - 1] != '/')
 97+				estrlcat(ns2, "/", sizeof(ns2));
 98+			estrlcat(ns2, d->d_name, sizeof(ns2));
 99+
100+			fnck(ns1, ns2, cp, depth + 1);
101+		}
102+
103+		closedir(dp);
104+	} else if (cp_aflag && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) ||
105+	           S_ISSOCK(st.st_mode) || S_ISFIFO(st.st_mode))) {
106+		if (cp_fflag && unlink(s2) < 0 && errno != ENOENT) {
107+			weprintf("unlink %s:", s2);
108+			cp_status = 1;
109+			return 0;
110+		} else if (mknod(s2, st.st_mode, st.st_rdev) < 0) {
111+			weprintf("mknod %s:", s2);
112+			cp_status = 1;
113+			return 0;
114+		}
115+	} else {
116+		if ((f1 = open(s1, O_RDONLY)) < 0) {
117+			weprintf("open %s:", s1);
118+			cp_status = 1;
119+			return 0;
120+		}
121+		if ((f2 = creat(s2, st.st_mode)) < 0 && cp_fflag) {
122+			if (unlink(s2) < 0 && errno != ENOENT) {
123+				weprintf("unlink %s:", s2);
124+				cp_status = 1;
125+				close(f1);
126+				return 0;
127+			}
128+			f2 = creat(s2, st.st_mode);
129+		}
130+		if (f2 < 0) {
131+			weprintf("creat %s:", s2);
132+			cp_status = 1;
133+			close(f1);
134+			return 0;
135+		}
136+		if (concat(f1, s1, f2, s2) < 0) {
137+			cp_status = 1;
138+			close(f1);
139+			close(f2);
140+			return 0;
141+		}
142+
143+		close(f1);
144+		close(f2);
145+	}
146+
147+	if (cp_aflag || cp_pflag) {
148+		/* atime and mtime */
149+		times[0] = st.st_atim;
150+		times[1] = st.st_mtim;
151+		if (utimensat(AT_FDCWD, s2, times, AT_SYMLINK_NOFOLLOW) < 0) {
152+			weprintf("utimensat %s:", s2);
153+			cp_status = 1;
154+		}
155+
156+		/* owner and mode */
157+		if (!S_ISLNK(st.st_mode)) {
158+			if (chown(s2, st.st_uid, st.st_gid) < 0) {
159+				weprintf("chown %s:", s2);
160+				cp_status = 1;
161+				st.st_mode &= ~(S_ISUID | S_ISGID);
162+			}
163+			if (chmod(s2, st.st_mode) < 0) {
164+				weprintf("chmod %s:", s2);
165+				cp_status = 1;
166+			}
167+		} else {
168+			if (lchown(s2, st.st_uid, st.st_gid) < 0) {
169+				weprintf("lchown %s:", s2);
170+				cp_status = 1;
171+				return 0;
172+			}
173+		}
174+	}
175+
176+	return 0;
177+}
+188, -0
  1@@ -0,0 +1,188 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <fcntl.h>
  4+#include <stdint.h>
  5+#include <stdio.h>
  6+#include <stdlib.h>
  7+#include <string.h>
  8+#include <unistd.h>
  9+
 10+#include "../crypt.h"
 11+#include "../text.h"
 12+#include "../util.h"
 13+
 14+static int
 15+hexdec(int c)
 16+{
 17+	if (c >= '0' && c <= '9')
 18+		return c - '0';
 19+	else if (c >= 'A' && c <= 'F')
 20+		return c - 'A' + 10;
 21+	else if (c >= 'a' && c <= 'f')
 22+		return c - 'a' + 10;
 23+	return -1; /* unknown character */
 24+}
 25+
 26+static int
 27+mdcheckline(const char *s, uint8_t *md, size_t sz)
 28+{
 29+	size_t i;
 30+	int b1, b2;
 31+
 32+	for (i = 0; i < sz; i++) {
 33+		if (!*s || (b1 = hexdec(*s++)) < 0)
 34+			return -1; /* invalid format */
 35+		if (!*s || (b2 = hexdec(*s++)) < 0)
 36+			return -1; /* invalid format */
 37+		if ((uint8_t)((b1 << 4) | b2) != md[i])
 38+			return 1; /* value mismatch */
 39+	}
 40+	return (i == sz) ? 0 : 1;
 41+}
 42+
 43+static void
 44+mdchecklist(FILE *listfp, struct crypt_ops *ops, uint8_t *md, size_t sz,
 45+            int *formatsucks, int *noread, int *nonmatch)
 46+{
 47+	int fd;
 48+	size_t bufsiz = 0;
 49+	int r;
 50+	char *line = NULL, *file, *p;
 51+
 52+	while (getline(&line, &bufsiz, listfp) > 0) {
 53+		file = strchr(line, ' ');
 54+		if (file == NULL || (file[1] != ' ' && file[1] != '*')) {
 55+			(*formatsucks)++;
 56+			continue;
 57+		}
 58+		if (file - line != sz * 2) {
 59+			(*formatsucks)++; /* checksum length mismatch */
 60+			continue;
 61+		}
 62+		*file = '\0';
 63+		file += 2;
 64+		for (p = file; *p && *p != '\n' && *p != '\r'; p++); /* strip newline */
 65+		*p = '\0';
 66+		if ((fd = open(file, O_RDONLY)) < 0) {
 67+			weprintf("open %s:", file);
 68+			(*noread)++;
 69+			continue;
 70+		}
 71+		if (cryptsum(ops, fd, file, md)) {
 72+			(*noread)++;
 73+			continue;
 74+		}
 75+		r = mdcheckline(line, md, sz);
 76+		if (r == 0) {
 77+			printf("%s: OK\n", file);
 78+		} else if (r == 1) {
 79+			printf("%s: FAILED\n", file);
 80+			(*nonmatch)++;
 81+		} else {
 82+			(*formatsucks)++;
 83+		}
 84+		close(fd);
 85+	}
 86+	free(line);
 87+}
 88+
 89+int
 90+cryptcheck(int argc, char *argv[], struct crypt_ops *ops, uint8_t *md, size_t sz)
 91+{
 92+	FILE *fp;
 93+	int formatsucks = 0, noread = 0, nonmatch = 0, ret = 0;
 94+
 95+	if (argc == 0) {
 96+		mdchecklist(stdin, ops, md, sz, &formatsucks, &noread, &nonmatch);
 97+	} else {
 98+		for (; *argv; argc--, argv++) {
 99+			if ((*argv)[0] == '-' && !(*argv)[1]) {
100+				fp = stdin;
101+			} else if (!(fp = fopen(*argv, "r"))) {
102+				weprintf("fopen %s:", *argv);
103+				ret = 1;
104+				continue;
105+			}
106+			mdchecklist(fp, ops, md, sz, &formatsucks, &noread, &nonmatch);
107+			if (fp != stdin)
108+				fclose(fp);
109+		}
110+	}
111+
112+	if (formatsucks) {
113+		weprintf("%d improperly formatted line%s\n",
114+		         formatsucks, formatsucks > 1 ? "s" : "");
115+		ret = 1;
116+	}
117+	if (noread) {
118+		weprintf("%d listed file%s could not be read\n",
119+		         noread, noread > 1 ? "s" : "");
120+		ret = 1;
121+	}
122+	if (nonmatch) {
123+		weprintf("%d computed checksum%s did NOT match\n",
124+		         nonmatch, nonmatch > 1 ? "s" : "");
125+		ret = 1;
126+	}
127+
128+	return ret;
129+}
130+
131+int
132+cryptmain(int argc, char *argv[], struct crypt_ops *ops, uint8_t *md, size_t sz)
133+{
134+	int fd;
135+	int ret = 0;
136+
137+	if (argc == 0) {
138+		if (cryptsum(ops, 0, "<stdin>", md))
139+			ret = 1;
140+		else
141+			mdprint(md, "<stdin>", sz);
142+	} else {
143+		for (; *argv; argc--, argv++) {
144+			if ((*argv)[0] == '-' && !(*argv)[1]) {
145+				*argv = "<stdin>";
146+				fd = 0;
147+			} else if ((fd = open(*argv, O_RDONLY)) < 0) {
148+				weprintf("open %s:", *argv);
149+				ret = 1;
150+				continue;
151+			}
152+			if (cryptsum(ops, fd, *argv, md))
153+				ret = 1;
154+			else
155+				mdprint(md, *argv, sz);
156+			if (fd != 0)
157+				close(fd);
158+		}
159+	}
160+
161+	return ret;
162+}
163+
164+int
165+cryptsum(struct crypt_ops *ops, int fd, const char *f, uint8_t *md)
166+{
167+	uint8_t buf[BUFSIZ];
168+	ssize_t n;
169+
170+	ops->init(ops->s);
171+	while ((n = read(fd, buf, sizeof(buf))) > 0)
172+		ops->update(ops->s, buf, n);
173+	if (n < 0) {
174+		weprintf("%s: read error:", f);
175+		return 1;
176+	}
177+	ops->sum(ops->s, md);
178+	return 0;
179+}
180+
181+void
182+mdprint(const uint8_t *md, const char *f, size_t len)
183+{
184+	size_t i;
185+
186+	for (i = 0; i < len; i++)
187+		printf("%02x", md[i]);
188+	printf("  %s\n", f);
189+}
+88, -0
 1@@ -0,0 +1,88 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdlib.h>
 4+#include <string.h>
 5+
 6+#include "../util.h"
 7+
 8+void *
 9+ecalloc(size_t nmemb, size_t size)
10+{
11+	return encalloc(1, nmemb, size);
12+}
13+
14+void *
15+emalloc(size_t size)
16+{
17+	return enmalloc(1, size);
18+}
19+
20+void *
21+erealloc(void *p, size_t size)
22+{
23+	return enrealloc(1, p, size);
24+}
25+
26+char *
27+estrdup(const char *s)
28+{
29+	return enstrdup(1, s);
30+}
31+
32+char *
33+estrndup(const char *s, size_t n)
34+{
35+	return enstrndup(1, s, n);
36+}
37+
38+void *
39+encalloc(int status, size_t nmemb, size_t size)
40+{
41+	void *p;
42+
43+	p = calloc(nmemb, size);
44+	if (!p)
45+		enprintf(status, "calloc: out of memory\n");
46+	return p;
47+}
48+
49+void *
50+enmalloc(int status, size_t size)
51+{
52+	void *p;
53+
54+	p = malloc(size);
55+	if (!p)
56+		enprintf(status, "malloc: out of memory\n");
57+	return p;
58+}
59+
60+void *
61+enrealloc(int status, void *p, size_t size)
62+{
63+	p = realloc(p, size);
64+	if (!p)
65+		enprintf(status, "realloc: out of memory\n");
66+	return p;
67+}
68+
69+char *
70+enstrdup(int status, const char *s)
71+{
72+	char *p;
73+
74+	p = strdup(s);
75+	if (!p)
76+		enprintf(status, "strdup: out of memory\n");
77+	return p;
78+}
79+
80+char *
81+enstrndup(int status, const char *s, size_t n)
82+{
83+	char *p;
84+
85+	p = strndup(s, n);
86+	if (!p)
87+		enprintf(status, "strndup: out of memory\n");
88+	return p;
89+}
+38, -0
 1@@ -0,0 +1,38 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <libgen.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <string.h>
 7+#include <sys/stat.h>
 8+#include <unistd.h>
 9+
10+#include "../util.h"
11+
12+void
13+enmasse(int argc, char *argv[], int (*fn)(const char *, const char *, int))
14+{
15+	struct stat st;
16+	char buf[PATH_MAX], *dir;
17+	int i, len;
18+	size_t dlen;
19+
20+	if (argc == 2 && !(stat(argv[1], &st) == 0 && S_ISDIR(st.st_mode))) {
21+		fnck(argv[0], argv[1], fn, 0);
22+		return;
23+	} else {
24+		dir = (argc == 1) ? "." : argv[--argc];
25+	}
26+
27+	for (i = 0; i < argc; i++) {
28+		dlen = strlen(dir);
29+		if (dlen > 0 && dir[dlen - 1] == '/')
30+			len = snprintf(buf, sizeof(buf), "%s%s", dir, basename(argv[i]));
31+		else
32+			len = snprintf(buf, sizeof(buf), "%s/%s", dir, basename(argv[i]));
33+		if (len < 0 || len >= sizeof(buf)) {
34+			eprintf("%s/%s: filename too long\n", dir,
35+			        basename(argv[i]));
36+		}
37+		fnck(argv[i], buf, fn, 0);
38+	}
39+}
+57, -0
 1@@ -0,0 +1,57 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdarg.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <string.h>
 7+
 8+#include "../util.h"
 9+
10+char *argv0;
11+
12+void
13+eprintf(const char *fmt, ...)
14+{
15+	va_list ap;
16+
17+	va_start(ap, fmt);
18+	xvprintf(fmt, ap);
19+	va_end(ap);
20+
21+	exit(1);
22+}
23+
24+void
25+enprintf(int status, const char *fmt, ...)
26+{
27+	va_list ap;
28+
29+	va_start(ap, fmt);
30+	xvprintf(fmt, ap);
31+	va_end(ap);
32+
33+	exit(status);
34+}
35+
36+void
37+weprintf(const char *fmt, ...)
38+{
39+	va_list ap;
40+
41+	va_start(ap, fmt);
42+	xvprintf(fmt, ap);
43+	va_end(ap);
44+}
45+
46+void
47+xvprintf(const char *fmt, va_list ap)
48+{
49+	if (argv0 && strncmp(fmt, "usage", strlen("usage")))
50+		fprintf(stderr, "%s: ", argv0);
51+
52+	vfprintf(stderr, fmt, ap);
53+
54+	if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
55+		fputc(' ', stderr);
56+		perror(NULL);
57+	}
58+}
+27, -0
 1@@ -0,0 +1,27 @@
 2+#include <sys/types.h>
 3+
 4+#include <regex.h>
 5+#include <stdio.h>
 6+
 7+#include "../util.h"
 8+
 9+int
10+enregcomp(int status, regex_t *preg, const char *regex, int cflags)
11+{
12+	char errbuf[BUFSIZ] = "";
13+	int r;
14+
15+	if ((r = regcomp(preg, regex, cflags)) == 0)
16+		return r;
17+
18+	regerror(r, preg, errbuf, sizeof(errbuf));
19+	enprintf(status, "invalid regex: %s\n", errbuf);
20+
21+	return r;
22+}
23+
24+int
25+eregcomp(regex_t *preg, const char *regex, int cflags)
26+{
27+	return enregcomp(1, preg, regex, cflags);
28+}
+18, -0
 1@@ -0,0 +1,18 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+
 7+#include "../util.h"
 8+
 9+double
10+estrtod(const char *s)
11+{
12+	char *end;
13+	double d;
14+
15+	d = strtod(s, &end);
16+	if (end == s || *end != '\0')
17+		eprintf("%s: not a real number\n", s);
18+	return d;
19+}
+27, -0
 1@@ -0,0 +1,27 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+
 7+#include "../util.h"
 8+
 9+long
10+estrtol(const char *s, int base)
11+{
12+	char *end;
13+	long n;
14+
15+	errno = 0;
16+	n = strtol(s, &end, base);
17+	if (*end != '\0') {
18+		if (base == 0)
19+			eprintf("%s: not an integer\n", s);
20+		else
21+			eprintf("%s: not a base %d integer\n", s, base);
22+	}
23+	if (errno != 0)
24+		eprintf("%s:", s);
25+
26+	return n;
27+}
28+
+26, -0
 1@@ -0,0 +1,26 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <errno.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+
 7+#include "../util.h"
 8+
 9+unsigned long
10+estrtoul(const char *s, int base)
11+{
12+	char *end;
13+	unsigned long n;
14+
15+	errno = 0;
16+	n = strtoul(s, &end, base);
17+	if (*end != '\0') {
18+		if (base == 0)
19+			eprintf("%s: not an integer\n", s);
20+		else
21+			eprintf("%s: not a base %d integer\n", s, base);
22+	}
23+	if (errno != 0)
24+		eprintf("%s:", s);
25+
26+	return n;
27+}
+12, -0
 1@@ -0,0 +1,12 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <string.h>
 4+
 5+#include "../util.h"
 6+
 7+static void *(*volatile explicit_memset)(void *, int, size_t) = memset;
 8+
 9+void
10+explicit_bzero(void *b, size_t len)
11+{
12+	(*explicit_memset)(b, 0, len);
13+}
+21, -0
 1@@ -0,0 +1,21 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+
 5+#include "../text.h"
 6+#include "../util.h"
 7+
 8+void
 9+fconcat(FILE *fp1, const char *s1, FILE *fp2, const char *s2)
10+{
11+	char buf[BUFSIZ];
12+	size_t n;
13+
14+	while ((n = fread(buf, 1, sizeof(buf), fp1)) > 0) {
15+		if (fwrite(buf, 1, n, fp2) != n)
16+			eprintf("%s: write error:", s2);
17+		if (feof(fp1))
18+			break;
19+	}
20+	if (ferror(fp1))
21+		eprintf("%s: read error:", s1);
22+}
+22, -0
 1@@ -0,0 +1,22 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+
 5+#include "../util.h"
 6+
 7+void
 8+fnck(const char *a, const char *b,
 9+     int (*fn)(const char *, const char *, int), int depth)
10+{
11+	struct stat sta, stb;
12+
13+	if (!stat(a, &sta)
14+	    && !stat(b, &stb)
15+	    && sta.st_dev == stb.st_dev
16+	    && sta.st_ino == stb.st_ino) {
17+		weprintf("%s -> %s: same file\n", a, b);
18+		return;
19+	}
20+
21+	if (fn(a, b, depth) < 0)
22+		eprintf("%s -> %s:", a, b);
23+}
+43, -0
 1@@ -0,0 +1,43 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <stdlib.h>
 5+
 6+#include "../util.h"
 7+
 8+int
 9+fshut(FILE *fp, const char *fname)
10+{
11+	int ret = 0;
12+
13+	/* fflush() is undefined for input streams by ISO C,
14+	 * but not POSIX 2008 if you ignore ISO C overrides.
15+	 * Leave it unchecked and rely on the following
16+	 * functions to detect errors.
17+	 */
18+	fflush(fp);
19+
20+	if (ferror(fp) && !ret) {
21+		weprintf("ferror %s:", fname);
22+		ret = 1;
23+	}
24+
25+	if (fclose(fp) && !ret) {
26+		weprintf("fclose %s:", fname);
27+		ret = 1;
28+	}
29+
30+	return ret;
31+}
32+
33+void
34+enfshut(int status, FILE *fp, const char *fname)
35+{
36+	if (fshut(fp, fname))
37+		exit(status);
38+}
39+
40+void
41+efshut(FILE *fp, const char *fname)
42+{
43+	enfshut(1, fp, fname);
44+}
+32, -0
 1@@ -0,0 +1,32 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <stdlib.h>
 5+#include <string.h>
 6+
 7+#include "../text.h"
 8+#include "../util.h"
 9+
10+void
11+getlines(FILE *fp, struct linebuf *b)
12+{
13+	char *line = NULL;
14+	size_t size = 0, linelen = 0;
15+	ssize_t len;
16+
17+	while ((len = getline(&line, &size, fp)) > 0) {
18+		if (++b->nlines > b->capacity) {
19+			b->capacity += 512;
20+			b->lines = ereallocarray(b->lines, b->capacity, sizeof(*b->lines));
21+		}
22+		linelen = len;
23+		b->lines[b->nlines - 1].data = memcpy(emalloc(linelen + 1), line, linelen + 1);
24+		b->lines[b->nlines - 1].len = linelen;
25+	}
26+	free(line);
27+	if (b->lines && b->nlines && linelen && b->lines[b->nlines - 1].data[linelen - 1] != '\n') {
28+		b->lines[b->nlines - 1].data = erealloc(b->lines[b->nlines - 1].data, linelen + 2);
29+		b->lines[b->nlines - 1].data[linelen] = '\n';
30+		b->lines[b->nlines - 1].data[linelen + 1] = '\0';
31+		b->lines[b->nlines - 1].len++;
32+	}
33+}
+25, -0
 1@@ -0,0 +1,25 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <string.h>
 5+#include <stdint.h>
 6+
 7+#include "../util.h"
 8+
 9+char *
10+humansize(off_t n)
11+{
12+	static char buf[16];
13+	const char postfixes[] = "BKMGTPE";
14+	double size;
15+	int i;
16+
17+	for (size = n, i = 0; size >= 1024 && i < strlen(postfixes); i++)
18+		size /= 1024;
19+
20+	if (!i)
21+		snprintf(buf, sizeof(buf), "%ju", (uintmax_t)n);
22+	else
23+		snprintf(buf, sizeof(buf), "%.1f%c", size, postfixes[i]);
24+
25+	return buf;
26+}
+17, -0
 1@@ -0,0 +1,17 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+#include <string.h>
 5+
 6+#include "../text.h"
 7+#include "../util.h"
 8+
 9+int
10+linecmp(struct line *a, struct line *b)
11+{
12+	int res = 0;
13+
14+	if (!(res = memcmp(a->data, b->data, MIN(a->len, b->len))))
15+		res = a->len - b->len;
16+
17+	return res;
18+}
+148, -0
  1@@ -0,0 +1,148 @@
  2+/* public domain md5 implementation based on rfc1321 and libtomcrypt */
  3+#include <stdint.h>
  4+#include <string.h>
  5+
  6+#include "../md5.h"
  7+
  8+static uint32_t rol(uint32_t n, int k) { return (n << k) | (n >> (32-k)); }
  9+#define F(x,y,z) (z ^ (x & (y ^ z)))
 10+#define G(x,y,z) (y ^ (z & (y ^ x)))
 11+#define H(x,y,z) (x ^ y ^ z)
 12+#define I(x,y,z) (y ^ (x | ~z))
 13+#define FF(a,b,c,d,w,s,t) a += F(b,c,d) + w + t; a = rol(a,s) + b
 14+#define GG(a,b,c,d,w,s,t) a += G(b,c,d) + w + t; a = rol(a,s) + b
 15+#define HH(a,b,c,d,w,s,t) a += H(b,c,d) + w + t; a = rol(a,s) + b
 16+#define II(a,b,c,d,w,s,t) a += I(b,c,d) + w + t; a = rol(a,s) + b
 17+
 18+static const uint32_t tab[64] = {
 19+	0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
 20+	0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
 21+	0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
 22+	0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
 23+	0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
 24+	0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
 25+	0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
 26+	0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
 27+};
 28+
 29+static void
 30+processblock(struct md5 *s, const uint8_t *buf)
 31+{
 32+	uint32_t i, W[16], a, b, c, d;
 33+
 34+	for (i = 0; i < 16; i++) {
 35+		W[i] = buf[4*i];
 36+		W[i] |= (uint32_t)buf[4*i+1]<<8;
 37+		W[i] |= (uint32_t)buf[4*i+2]<<16;
 38+		W[i] |= (uint32_t)buf[4*i+3]<<24;
 39+	}
 40+
 41+	a = s->h[0];
 42+	b = s->h[1];
 43+	c = s->h[2];
 44+	d = s->h[3];
 45+
 46+	i = 0;
 47+	while (i < 16) {
 48+		FF(a,b,c,d, W[i],  7, tab[i]); i++;
 49+		FF(d,a,b,c, W[i], 12, tab[i]); i++;
 50+		FF(c,d,a,b, W[i], 17, tab[i]); i++;
 51+		FF(b,c,d,a, W[i], 22, tab[i]); i++;
 52+	}
 53+	while (i < 32) {
 54+		GG(a,b,c,d, W[(5*i+1)%16],  5, tab[i]); i++;
 55+		GG(d,a,b,c, W[(5*i+1)%16],  9, tab[i]); i++;
 56+		GG(c,d,a,b, W[(5*i+1)%16], 14, tab[i]); i++;
 57+		GG(b,c,d,a, W[(5*i+1)%16], 20, tab[i]); i++;
 58+	}
 59+	while (i < 48) {
 60+		HH(a,b,c,d, W[(3*i+5)%16],  4, tab[i]); i++;
 61+		HH(d,a,b,c, W[(3*i+5)%16], 11, tab[i]); i++;
 62+		HH(c,d,a,b, W[(3*i+5)%16], 16, tab[i]); i++;
 63+		HH(b,c,d,a, W[(3*i+5)%16], 23, tab[i]); i++;
 64+	}
 65+	while (i < 64) {
 66+		II(a,b,c,d, W[7*i%16],  6, tab[i]); i++;
 67+		II(d,a,b,c, W[7*i%16], 10, tab[i]); i++;
 68+		II(c,d,a,b, W[7*i%16], 15, tab[i]); i++;
 69+		II(b,c,d,a, W[7*i%16], 21, tab[i]); i++;
 70+	}
 71+
 72+	s->h[0] += a;
 73+	s->h[1] += b;
 74+	s->h[2] += c;
 75+	s->h[3] += d;
 76+}
 77+
 78+static void
 79+pad(struct md5 *s)
 80+{
 81+	unsigned r = s->len % 64;
 82+
 83+	s->buf[r++] = 0x80;
 84+	if (r > 56) {
 85+		memset(s->buf + r, 0, 64 - r);
 86+		r = 0;
 87+		processblock(s, s->buf);
 88+	}
 89+	memset(s->buf + r, 0, 56 - r);
 90+	s->len *= 8;
 91+	s->buf[56] = s->len;
 92+	s->buf[57] = s->len >> 8;
 93+	s->buf[58] = s->len >> 16;
 94+	s->buf[59] = s->len >> 24;
 95+	s->buf[60] = s->len >> 32;
 96+	s->buf[61] = s->len >> 40;
 97+	s->buf[62] = s->len >> 48;
 98+	s->buf[63] = s->len >> 56;
 99+	processblock(s, s->buf);
100+}
101+
102+void
103+md5_init(void *ctx)
104+{
105+	struct md5 *s = ctx;
106+	s->len = 0;
107+	s->h[0] = 0x67452301;
108+	s->h[1] = 0xefcdab89;
109+	s->h[2] = 0x98badcfe;
110+	s->h[3] = 0x10325476;
111+}
112+
113+void
114+md5_sum(void *ctx, uint8_t md[MD5_DIGEST_LENGTH])
115+{
116+	struct md5 *s = ctx;
117+	int i;
118+
119+	pad(s);
120+	for (i = 0; i < 4; i++) {
121+		md[4*i] = s->h[i];
122+		md[4*i+1] = s->h[i] >> 8;
123+		md[4*i+2] = s->h[i] >> 16;
124+		md[4*i+3] = s->h[i] >> 24;
125+	}
126+}
127+
128+void
129+md5_update(void *ctx, const void *m, unsigned long len)
130+{
131+	struct md5 *s = ctx;
132+	const uint8_t *p = m;
133+	unsigned r = s->len % 64;
134+
135+	s->len += len;
136+	if (r) {
137+		if (len < 64 - r) {
138+			memcpy(s->buf + r, p, len);
139+			return;
140+		}
141+		memcpy(s->buf + r, p, 64 - r);
142+		len -= 64 - r;
143+		p += 64 - r;
144+		processblock(s, s->buf);
145+	}
146+	for (; len >= 64; len -= 64, p += 64)
147+		processblock(s, p);
148+	memcpy(s->buf, p, len);
149+}
+66, -0
 1@@ -0,0 +1,66 @@
 2+/*	$OpenBSD: memmem.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */
 3+
 4+/*
 5+ * Copyright (c) 2005 Pascal Gloor <pascal.gloor@spale.com>
 6+ *
 7+ * Redistribution and use in source and binary forms, with or without
 8+ * modification, are permitted provided that the following conditions
 9+ * are met:
10+ * 1. Redistributions of source code must retain the above copyright
11+ *    notice, this list of conditions and the following disclaimer.
12+ * 2. Redistributions in binary form must reproduce the above copyright
13+ *    notice, this list of conditions and the following disclaimer in the
14+ *    documentation and/or other materials provided with the distribution.
15+ * 3. The name of the author may not be used to endorse or promote
16+ *    products derived from this software without specific prior written
17+ *    permission.
18+ *
19+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29+ * SUCH DAMAGE.
30+ */
31+
32+#include <string.h>
33+
34+#include "../util.h"
35+
36+/*
37+ * Find the first occurrence of the byte string s in byte string l.
38+ */
39+
40+void *
41+memmem(const void *l, size_t l_len, const void *s, size_t s_len)
42+{
43+	const char *cur, *last;
44+	const char *cl = l;
45+	const char *cs = s;
46+
47+	/* a zero length needle should just return the haystack */
48+	if (s_len == 0)
49+		return (void *)cl;
50+
51+	/* "s" must be smaller or equal to "l" */
52+	if (l_len < s_len)
53+		return NULL;
54+
55+	/* special case where s_len == 1 */
56+	if (s_len == 1)
57+		return memchr(l, *cs, l_len);
58+
59+	/* the last position where its possible to find "s" in "l" */
60+	last = cl + l_len - s_len;
61+
62+	for (cur = cl; cur <= last; cur++)
63+		if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
64+			return (void *)cur;
65+
66+	return NULL;
67+}
+39, -0
 1@@ -0,0 +1,39 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+
 5+#include <errno.h>
 6+#include <limits.h>
 7+
 8+#include "../util.h"
 9+
10+int
11+mkdirp(const char *path, mode_t mode, mode_t pmode)
12+{
13+	char tmp[PATH_MAX], *p;
14+	struct stat st;
15+
16+	if (stat(path, &st) == 0) {
17+		if (S_ISDIR(st.st_mode))
18+			return 0;
19+		errno = ENOTDIR;
20+		weprintf("%s:", path);
21+		return -1;
22+	}
23+
24+	estrlcpy(tmp, path, sizeof(tmp));
25+	for (p = tmp + (tmp[0] == '/'); *p; p++) {
26+		if (*p != '/')
27+			continue;
28+		*p = '\0';
29+		if (mkdir(tmp, pmode) < 0 && errno != EEXIST) {
30+			weprintf("mkdir %s:", tmp);
31+			return -1;
32+		}
33+		*p = '/';
34+	}
35+	if (mkdir(tmp, mode) < 0 && errno != EEXIST) {
36+		weprintf("mkdir %s:", tmp);
37+		return -1;
38+	}
39+	return 0;
40+}
+152, -0
  1@@ -0,0 +1,152 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <stdlib.h>
  4+#include <string.h>
  5+#include <sys/stat.h>
  6+#include <unistd.h>
  7+
  8+#include "../util.h"
  9+
 10+mode_t
 11+getumask(void)
 12+{
 13+	mode_t mask = umask(0);
 14+	umask(mask);
 15+	return mask;
 16+}
 17+
 18+mode_t
 19+parsemode(const char *str, mode_t mode, mode_t mask)
 20+{
 21+	char *end;
 22+	const char *p = str;
 23+	int octal, op;
 24+	mode_t who, perm, clear;
 25+
 26+	octal = strtol(str, &end, 8);
 27+	if (*end == '\0') {
 28+		if (octal < 0 || octal > 07777)
 29+			eprintf("%s: invalid mode\n", str);
 30+		return octal;
 31+	}
 32+next:
 33+	/* first, determine which bits we will be modifying */
 34+	for (who = 0; *p; p++) {
 35+		switch (*p) {
 36+		/* masks */
 37+		case 'u':
 38+			who |= S_IRWXU|S_ISUID;
 39+			continue;
 40+		case 'g':
 41+			who |= S_IRWXG|S_ISGID;
 42+			continue;
 43+		case 'o':
 44+			who |= S_IRWXO|S_ISVTX;
 45+			continue;
 46+		case 'a':
 47+			who |= S_IRWXU|S_ISUID|S_IRWXG|S_ISGID|S_IRWXO|S_ISVTX;
 48+			continue;
 49+		}
 50+		break;
 51+	}
 52+	if (who) {
 53+		clear = who;
 54+	} else {
 55+		clear = S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO;
 56+		who = ~mask;
 57+	}
 58+	while (*p) {
 59+		switch (*p) {
 60+		/* opers */
 61+		case '=':
 62+		case '+':
 63+		case '-':
 64+			op = (int)*p;
 65+			break;
 66+		default:
 67+			eprintf("%s: invalid mode\n", str);
 68+		}
 69+
 70+		perm = 0;
 71+		switch (*++p) {
 72+		/* copy */
 73+		case 'u':
 74+			if (mode & S_IRUSR)
 75+				perm |= S_IRUSR|S_IRGRP|S_IROTH;
 76+			if (mode & S_IWUSR)
 77+				perm |= S_IWUSR|S_IWGRP|S_IWOTH;
 78+			if (mode & S_IXUSR)
 79+				perm |= S_IXUSR|S_IXGRP|S_IXOTH;
 80+			if (mode & S_ISUID)
 81+				perm |= S_ISUID|S_ISGID;
 82+			p++;
 83+			break;
 84+		case 'g':
 85+			if (mode & S_IRGRP)
 86+				perm |= S_IRUSR|S_IRGRP|S_IROTH;
 87+			if (mode & S_IWGRP)
 88+				perm |= S_IWUSR|S_IWGRP|S_IWOTH;
 89+			if (mode & S_IXGRP)
 90+				perm |= S_IXUSR|S_IXGRP|S_IXOTH;
 91+			if (mode & S_ISGID)
 92+				perm |= S_ISUID|S_ISGID;
 93+			p++;
 94+			break;
 95+		case 'o':
 96+			if (mode & S_IROTH)
 97+				perm |= S_IRUSR|S_IRGRP|S_IROTH;
 98+			if (mode & S_IWOTH)
 99+				perm |= S_IWUSR|S_IWGRP|S_IWOTH;
100+			if (mode & S_IXOTH)
101+				perm |= S_IXUSR|S_IXGRP|S_IXOTH;
102+			p++;
103+			break;
104+		default:
105+			for (; *p; p++) {
106+				switch (*p) {
107+				/* modes */
108+				case 'r':
109+					perm |= S_IRUSR|S_IRGRP|S_IROTH;
110+					break;
111+				case 'w':
112+					perm |= S_IWUSR|S_IWGRP|S_IWOTH;
113+					break;
114+				case 'x':
115+					perm |= S_IXUSR|S_IXGRP|S_IXOTH;
116+					break;
117+				case 'X':
118+					if (S_ISDIR(mode) || mode & (S_IXUSR|S_IXGRP|S_IXOTH))
119+						perm |= S_IXUSR|S_IXGRP|S_IXOTH;
120+					break;
121+				case 's':
122+					perm |= S_ISUID|S_ISGID;
123+					break;
124+				case 't':
125+					perm |= S_ISVTX;
126+					break;
127+				default:
128+					goto apply;
129+				}
130+			}
131+		}
132+
133+apply:
134+		/* apply */
135+		switch (op) {
136+		case '=':
137+			mode &= ~clear;
138+			/* fallthrough */
139+		case '+':
140+			mode |= perm & who;
141+			break;
142+		case '-':
143+			mode &= ~(perm & who);
144+			break;
145+		}
146+		/* if we hit a comma, move on to the next clause */
147+		if (*p == ',') {
148+			p++;
149+			goto next;
150+		}
151+	}
152+	return mode & ~S_IFMT;
153+}
+61, -0
 1@@ -0,0 +1,61 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <ctype.h>
 4+#include <errno.h>
 5+#include <inttypes.h>
 6+#include <stdlib.h>
 7+#include <string.h>
 8+
 9+#include "../util.h"
10+
11+off_t
12+parseoffset(const char *str)
13+{
14+	off_t res, scale = 1;
15+	char *end;
16+
17+	/* strictly check what strtol() usually would let pass */
18+	if (!str || !*str || isspace(*str) || *str == '+' || *str == '-') {
19+		weprintf("parseoffset %s: invalid value\n", str);
20+		return -1;
21+	}
22+
23+	errno = 0;
24+	res = strtol(str, &end, 0);
25+	if (errno) {
26+		weprintf("parseoffset %s: invalid value\n", str);
27+		return -1;
28+	}
29+	if (res < 0) {
30+		weprintf("parseoffset %s: negative value\n", str);
31+		return -1;
32+	}
33+
34+	/* suffix */
35+	if (*end) {
36+		switch (toupper((int)*end)) {
37+		case 'B':
38+			scale = 512L;
39+			break;
40+		case 'K':
41+			scale = 1024L;
42+			break;
43+		case 'M':
44+			scale = 1024L * 1024L;
45+			break;
46+		case 'G':
47+			scale = 1024L * 1024L * 1024L;
48+			break;
49+		default:
50+			weprintf("parseoffset %s: invalid suffix '%s'\n", str, end);
51+			return -1;
52+		}
53+	}
54+
55+	/* prevent overflow */
56+	if (res > (SSIZE_MAX / scale)) {
57+		weprintf("parseoffset %s: out of range\n", str);
58+		return -1;
59+	}
60+
61+	return res * scale;
62+}
+77, -0
 1@@ -0,0 +1,77 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/resource.h>
 4+#include <sys/time.h>
 5+
 6+#include <errno.h>
 7+#include <pwd.h>
 8+#include <shadow.h>
 9+#include <stdio.h>
10+#include <stdlib.h>
11+#include <string.h>
12+#include <unistd.h>
13+
14+#include "../passwd.h"
15+#include "../text.h"
16+#include "../util.h"
17+
18+/* Returns -1 on error, 0 for incorrect password
19+ * and 1 if all went OK */
20+int
21+pw_check(const struct passwd *pw, const char *pass)
22+{
23+	char *cryptpass, *p;
24+	struct spwd *spw;
25+
26+	p = pw->pw_passwd;
27+	if (p[0] == '!' || p[0] == '*') {
28+		weprintf("denied\n");
29+		return -1;
30+	}
31+
32+	if (pw->pw_passwd[0] == '\0') {
33+		if (pass[0] == '\0')
34+			return 1;
35+		weprintf("incorrect password\n");
36+		return 0;
37+	}
38+
39+	if (pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0') {
40+		errno = 0;
41+		spw = getspnam(pw->pw_name);
42+		if (!spw) {
43+			if (errno)
44+				weprintf("getspnam: %s:", pw->pw_name);
45+			else
46+				weprintf("who are you?\n");
47+			return -1;
48+		}
49+		p = spw->sp_pwdp;
50+		if (p[0] == '!' || p[0] == '*') {
51+			weprintf("denied\n");
52+			return -1;
53+		}
54+	}
55+
56+	cryptpass = crypt(pass, p);
57+	if (!cryptpass) {
58+		weprintf("crypt:");
59+		return -1;
60+	}
61+	if (strcmp(cryptpass, p) != 0) {
62+		weprintf("incorrect password\n");
63+		return 0;
64+	}
65+	return 1;
66+}
67+
68+int
69+pw_init(void)
70+{
71+	struct rlimit rlim;
72+
73+	rlim.rlim_cur = 0;
74+	rlim.rlim_max = 0;
75+	if (setrlimit(RLIMIT_CORE, &rlim) < 0)
76+		eprintf("setrlimit:");
77+	return 0;
78+}
+117, -0
  1@@ -0,0 +1,117 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/stat.h>
  4+
  5+#include <errno.h>
  6+#include <fcntl.h>
  7+#include <limits.h>
  8+#include <stdio.h>
  9+#include <stdlib.h>
 10+#include <string.h>
 11+#include <unistd.h>
 12+
 13+#include "../proc.h"
 14+#include "../util.h"
 15+
 16+int
 17+parsecmdline(pid_t pid, char *buf, size_t siz)
 18+{
 19+	int fd;
 20+	char path[PATH_MAX];
 21+	ssize_t n, i;
 22+
 23+	snprintf(path, sizeof(path), "/proc/%ld/cmdline", (long)pid);
 24+	fd = open(path, O_RDONLY);
 25+	if (fd < 0)
 26+		return -1;
 27+	n = read(fd, buf, siz > 0 ? siz - 1 : 0);
 28+	if (n < 0) {
 29+		weprintf("read %s:", path);
 30+		close(fd);
 31+		return -1;
 32+	}
 33+	if (!n) {
 34+		close(fd);
 35+		return -1;
 36+	}
 37+	buf[n] = '\0';
 38+	for (i = 0; i < n; i++)
 39+		if (buf[i] == '\0')
 40+			buf[i] = ' ';
 41+	close(fd);
 42+	return 0;
 43+}
 44+
 45+int
 46+parsestat(pid_t pid, struct procstat *ps)
 47+{
 48+	char path[PATH_MAX];
 49+	FILE *fp;
 50+	size_t len;
 51+
 52+	snprintf(path, sizeof(path), "/proc/%d/stat", pid);
 53+	if (!(fp = fopen(path, "r")))
 54+		return -1;
 55+	fscanf(fp, "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu",
 56+	       &ps->pid, ps->comm,
 57+	       &ps->state, &ps->ppid, &ps->pgrp,
 58+	       &ps->sid, &ps->tty_nr, &ps->tpgid, &ps->flags,
 59+	       &ps->minflt, &ps->cminflt, &ps->majflt, &ps->cmajflt,
 60+	       &ps->utime, &ps->stime);
 61+	fscanf(fp, "%ld %ld %ld %ld %ld %ld %llu %lu %ld %ld",
 62+	       &ps->cutime, &ps->cstime, &ps->priority, &ps->nice,
 63+	       &ps->num_threads, &ps->itrealvalue, &ps->starttime,
 64+	       &ps->vsize, &ps->rss, &ps->rsslim);
 65+	/* Filter out '(' and ')' from comm */
 66+	if ((len = strlen(ps->comm)) > 0)
 67+		len--;
 68+	ps->comm[len] = '\0';
 69+	memmove(ps->comm, ps->comm + 1, len);
 70+	fclose(fp);
 71+	return 0;
 72+}
 73+
 74+int
 75+parsestatus(pid_t pid, struct procstatus *pstatus)
 76+{
 77+	char path[PATH_MAX];
 78+	char buf[BUFSIZ], *off;
 79+	int fd;
 80+	ssize_t n;
 81+
 82+	snprintf(path, sizeof(path), "/proc/%d/status", pid);
 83+	fd = open(path, O_RDONLY);
 84+	if (fd < 0)
 85+		return -1;
 86+	n = read(fd, buf, sizeof(buf) - 1);
 87+	if (n < 0)
 88+		eprintf("%s: read error:", path);
 89+	if (!n) {
 90+		close(fd);
 91+		return -1;
 92+	}
 93+	buf[n] = '\0';
 94+	close(fd);
 95+	off = strstr(buf, "Uid:");
 96+	if (!off)
 97+		return -1;
 98+	sscanf(off, "Uid: %u %u", &pstatus->uid, &pstatus->euid);
 99+	off = strstr(buf, "Gid:");
100+	if (!off)
101+		return -1;
102+	sscanf(off, "Gid: %u %u", &pstatus->gid, &pstatus->egid);
103+	return 0;
104+}
105+
106+int
107+pidfile(const char *file)
108+{
109+	char *end;
110+
111+	errno = 0;
112+	strtol(file, &end, 10);
113+	if (*end != '\0')
114+		return 0;
115+	if (errno != 0)
116+		return 0;
117+	return 1;
118+}
+16, -0
 1@@ -0,0 +1,16 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <stdio.h>
 4+
 5+#include "../util.h"
 6+
 7+void
 8+putword(FILE *fp, const char *s)
 9+{
10+	static int first = 1;
11+
12+	if (!first)
13+		fputc(' ', fp);
14+
15+	fputs(s, fp);
16+	first = 0;
17+}
+56, -0
 1@@ -0,0 +1,56 @@
 2+/*
 3+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
 4+ *
 5+ * Permission to use, copy, modify, and distribute this software for any
 6+ * purpose with or without fee is hereby granted, provided that the above
 7+ * copyright notice and this permission notice appear in all copies.
 8+ *
 9+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16+ */
17+
18+#include <sys/types.h>
19+#include <errno.h>
20+#include <stdint.h>
21+#include <stdlib.h>
22+
23+#include "../util.h"
24+
25+/*
26+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
27+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
28+ */
29+#define MUL_NO_OVERFLOW	(1UL << (sizeof(size_t) * 4))
30+
31+void *
32+reallocarray(void *optr, size_t nmemb, size_t size)
33+{
34+	if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
35+	    nmemb > 0 && SIZE_MAX / nmemb < size) {
36+		errno = ENOMEM;
37+		return NULL;
38+	}
39+	return realloc(optr, size * nmemb);
40+}
41+
42+void *
43+ereallocarray(void *optr, size_t nmemb, size_t size)
44+{
45+	return enreallocarray(1, optr, nmemb, size);
46+}
47+
48+void *
49+enreallocarray(int status, void *optr, size_t nmemb, size_t size)
50+{
51+	void *p;
52+
53+	if (!(p = reallocarray(optr, nmemb, size)))
54+		enprintf(status, "reallocarray: out of memory\n");
55+
56+	return p;
57+}
+108, -0
  1@@ -0,0 +1,108 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <dirent.h>
  4+#include <errno.h>
  5+#include <fcntl.h>
  6+#include <limits.h>
  7+#include <stdio.h>
  8+#include <stdlib.h>
  9+#include <string.h>
 10+#include <sys/stat.h>
 11+#include <sys/types.h>
 12+#include <unistd.h>
 13+
 14+#include "../fs.h"
 15+#include "../util.h"
 16+
 17+int recurse_status = 0;
 18+
 19+void
 20+recurse(int dirfd, const char *name, void *data, struct recursor *r)
 21+{
 22+	struct dirent *d;
 23+	struct history *new, *h;
 24+	struct stat st, dst;
 25+	DIR *dp;
 26+	int flags = 0, fd;
 27+	size_t pathlen = r->pathlen;
 28+
 29+	if (dirfd == AT_FDCWD)
 30+		pathlen = estrlcpy(r->path, name, sizeof(r->path));
 31+
 32+	if (r->follow == 'P' || (r->follow == 'H' && r->depth))
 33+		flags |= AT_SYMLINK_NOFOLLOW;
 34+
 35+	if (fstatat(dirfd, name, &st, flags) < 0) {
 36+		if (!(r->flags & SILENT)) {
 37+			weprintf("stat %s:", r->path);
 38+			recurse_status = 1;
 39+		}
 40+		return;
 41+	}
 42+	if (!S_ISDIR(st.st_mode)) {
 43+		r->fn(dirfd, name, &st, data, r);
 44+		return;
 45+	}
 46+
 47+	new = emalloc(sizeof(struct history));
 48+	new->prev  = r->hist;
 49+	r->hist    = new;
 50+	new->dev   = st.st_dev;
 51+	new->ino   = st.st_ino;
 52+
 53+	for (h = new->prev; h; h = h->prev)
 54+		if (h->ino == st.st_ino && h->dev == st.st_dev)
 55+			return;
 56+
 57+	if (!r->depth && (r->flags & DIRFIRST))
 58+		r->fn(dirfd, name, &st, data, r);
 59+
 60+	if (!r->maxdepth || r->depth + 1 < r->maxdepth) {
 61+		fd = openat(dirfd, name, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
 62+		if (fd < 0) {
 63+			weprintf("open %s:", r->path);
 64+			recurse_status = 1;
 65+		}
 66+		if (!(dp = fdopendir(fd))) {
 67+			if (!(r->flags & SILENT)) {
 68+				weprintf("fdopendir:");
 69+				recurse_status = 1;
 70+			}
 71+			return;
 72+		}
 73+		if (r->path[pathlen - 1] != '/')
 74+			r->path[pathlen++] = '/';
 75+		if (r->follow == 'H')
 76+			flags |= AT_SYMLINK_NOFOLLOW;
 77+		while ((d = readdir(dp))) {
 78+			if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
 79+				continue;
 80+			r->pathlen = pathlen + estrlcpy(r->path + pathlen, d->d_name, sizeof(r->path) - pathlen);
 81+			if (fstatat(fd, d->d_name, &dst, flags) < 0) {
 82+				if (!(r->flags & SILENT)) {
 83+					weprintf("stat %s:", r->path);
 84+					recurse_status = 1;
 85+				}
 86+			} else if ((r->flags & SAMEDEV) && dst.st_dev != st.st_dev) {
 87+				continue;
 88+			} else {
 89+				r->depth++;
 90+				r->fn(fd, d->d_name, &dst, data, r);
 91+				r->depth--;
 92+			}
 93+		}
 94+		r->path[pathlen - 1] = '\0';
 95+		r->pathlen = pathlen - 1;
 96+		closedir(dp);
 97+	}
 98+
 99+	if (!r->depth) {
100+		if (!(r->flags & DIRFIRST))
101+			r->fn(dirfd, name, &st, data, r);
102+
103+		while (r->hist) {
104+			h = r->hist;
105+			r->hist = r->hist->prev;
106+			free(h);
107+		}
108+	}
109+}
+42, -0
 1@@ -0,0 +1,42 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <dirent.h>
 4+#include <limits.h>
 5+#include <stdio.h>
 6+#include <stdlib.h>
 7+#include <string.h>
 8+#include <sys/stat.h>
 9+#include <sys/types.h>
10+#include <unistd.h>
11+
12+#include "../util.h"
13+
14+void
15+recurse_dir(const char *path, void (*fn)(const char *))
16+{
17+	char buf[PATH_MAX];
18+	struct dirent *d;
19+	struct stat st;
20+	DIR *dp;
21+
22+	if (lstat(path, &st) == -1 || S_ISDIR(st.st_mode) == 0)
23+		return;
24+
25+	if (!(dp = opendir(path)))
26+		eprintf("opendir %s:", path);
27+
28+	while ((d = readdir(dp))) {
29+		if (strcmp(d->d_name, ".") == 0 ||
30+		    strcmp(d->d_name, "..") == 0)
31+			continue;
32+		if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf))
33+			eprintf("path too long\n");
34+		if (buf[strlen(buf) - 1] != '/')
35+			if (strlcat(buf, "/", sizeof(buf)) >= sizeof(buf))
36+				eprintf("path too long\n");
37+		if (strlcat(buf, d->d_name, sizeof(buf)) >= sizeof(buf))
38+			eprintf("path too long\n");
39+		fn(buf);
40+	}
41+
42+	closedir(dp);
43+}
+49, -0
 1@@ -0,0 +1,49 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/stat.h>
 4+
 5+#include <errno.h>
 6+#include <fcntl.h>
 7+#include <stdio.h>
 8+#include <unistd.h>
 9+
10+#include "../fs.h"
11+#include "../util.h"
12+
13+int rm_status = 0;
14+
15+void
16+rm(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
17+{
18+	int quiet, ask, write, flags, ignore;
19+
20+	ignore = r->flags & IGNORE;
21+	quiet = r->flags & SILENT;
22+	ask = r->flags & CONFIRM;
23+	write = S_ISLNK(st->st_mode) || faccessat(dirfd, name, W_OK, 0) == 0;
24+	flags = 0;
25+
26+	if (S_ISDIR(st->st_mode) && r->maxdepth) {
27+		errno = EISDIR;
28+		goto err;
29+	}
30+
31+	if (!quiet && (!write && isatty(0) || ask)) {
32+		if (!confirm("remove file '%s'? ", r->path))
33+			return;
34+	}
35+
36+	if (S_ISDIR(st->st_mode)) {
37+		flags = AT_REMOVEDIR;
38+		recurse(dirfd, name, NULL, r);
39+	}
40+
41+	if (unlinkat(dirfd, name, flags) < 0)
42+		goto err;
43+	return;
44+
45+err:
46+	if (!ignore) {
47+		weprintf("cannot remove '%s':", r->path);
48+		rm_status = 1;
49+	}
50+}
+144, -0
  1@@ -0,0 +1,144 @@
  2+/* public domain sha1 implementation based on rfc3174 and libtomcrypt */
  3+#include <stdint.h>
  4+#include <string.h>
  5+
  6+#include "../sha1.h"
  7+
  8+static uint32_t rol(uint32_t n, int k) { return (n << k) | (n >> (32-k)); }
  9+#define F0(b,c,d) (d ^ (b & (c ^ d)))
 10+#define F1(b,c,d) (b ^ c ^ d)
 11+#define F2(b,c,d) ((b & c) | (d & (b | c)))
 12+#define F3(b,c,d) (b ^ c ^ d)
 13+#define G0(a,b,c,d,e,i) e += rol(a,5)+F0(b,c,d)+W[i]+0x5A827999; b = rol(b,30)
 14+#define G1(a,b,c,d,e,i) e += rol(a,5)+F1(b,c,d)+W[i]+0x6ED9EBA1; b = rol(b,30)
 15+#define G2(a,b,c,d,e,i) e += rol(a,5)+F2(b,c,d)+W[i]+0x8F1BBCDC; b = rol(b,30)
 16+#define G3(a,b,c,d,e,i) e += rol(a,5)+F3(b,c,d)+W[i]+0xCA62C1D6; b = rol(b,30)
 17+
 18+static void
 19+processblock(struct sha1 *s, const uint8_t *buf)
 20+{
 21+	uint32_t W[80], a, b, c, d, e;
 22+	int i;
 23+
 24+	for (i = 0; i < 16; i++) {
 25+		W[i] = (uint32_t)buf[4*i]<<24;
 26+		W[i] |= (uint32_t)buf[4*i+1]<<16;
 27+		W[i] |= (uint32_t)buf[4*i+2]<<8;
 28+		W[i] |= buf[4*i+3];
 29+	}
 30+	for (; i < 80; i++)
 31+		W[i] = rol(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
 32+	a = s->h[0];
 33+	b = s->h[1];
 34+	c = s->h[2];
 35+	d = s->h[3];
 36+	e = s->h[4];
 37+	for (i = 0; i < 20; ) {
 38+		G0(a,b,c,d,e,i++);
 39+		G0(e,a,b,c,d,i++);
 40+		G0(d,e,a,b,c,i++);
 41+		G0(c,d,e,a,b,i++);
 42+		G0(b,c,d,e,a,i++);
 43+	}
 44+	while (i < 40) {
 45+		G1(a,b,c,d,e,i++);
 46+		G1(e,a,b,c,d,i++);
 47+		G1(d,e,a,b,c,i++);
 48+		G1(c,d,e,a,b,i++);
 49+		G1(b,c,d,e,a,i++);
 50+	}
 51+	while (i < 60) {
 52+		G2(a,b,c,d,e,i++);
 53+		G2(e,a,b,c,d,i++);
 54+		G2(d,e,a,b,c,i++);
 55+		G2(c,d,e,a,b,i++);
 56+		G2(b,c,d,e,a,i++);
 57+	}
 58+	while (i < 80) {
 59+		G3(a,b,c,d,e,i++);
 60+		G3(e,a,b,c,d,i++);
 61+		G3(d,e,a,b,c,i++);
 62+		G3(c,d,e,a,b,i++);
 63+		G3(b,c,d,e,a,i++);
 64+	}
 65+	s->h[0] += a;
 66+	s->h[1] += b;
 67+	s->h[2] += c;
 68+	s->h[3] += d;
 69+	s->h[4] += e;
 70+}
 71+
 72+static void
 73+pad(struct sha1 *s)
 74+{
 75+	unsigned r = s->len % 64;
 76+
 77+	s->buf[r++] = 0x80;
 78+	if (r > 56) {
 79+		memset(s->buf + r, 0, 64 - r);
 80+		r = 0;
 81+		processblock(s, s->buf);
 82+	}
 83+	memset(s->buf + r, 0, 56 - r);
 84+	s->len *= 8;
 85+	s->buf[56] = s->len >> 56;
 86+	s->buf[57] = s->len >> 48;
 87+	s->buf[58] = s->len >> 40;
 88+	s->buf[59] = s->len >> 32;
 89+	s->buf[60] = s->len >> 24;
 90+	s->buf[61] = s->len >> 16;
 91+	s->buf[62] = s->len >> 8;
 92+	s->buf[63] = s->len;
 93+	processblock(s, s->buf);
 94+}
 95+
 96+void
 97+sha1_init(void *ctx)
 98+{
 99+	struct sha1 *s = ctx;
100+
101+	s->len = 0;
102+	s->h[0] = 0x67452301;
103+	s->h[1] = 0xEFCDAB89;
104+	s->h[2] = 0x98BADCFE;
105+	s->h[3] = 0x10325476;
106+	s->h[4] = 0xC3D2E1F0;
107+}
108+
109+void
110+sha1_sum(void *ctx, uint8_t md[SHA1_DIGEST_LENGTH])
111+{
112+	struct sha1 *s = ctx;
113+	int i;
114+
115+	pad(s);
116+	for (i = 0; i < 5; i++) {
117+		md[4*i] = s->h[i] >> 24;
118+		md[4*i+1] = s->h[i] >> 16;
119+		md[4*i+2] = s->h[i] >> 8;
120+		md[4*i+3] = s->h[i];
121+	}
122+}
123+
124+void
125+sha1_update(void *ctx, const void *m, unsigned long len)
126+{
127+	struct sha1 *s = ctx;
128+	const uint8_t *p = m;
129+	unsigned r = s->len % 64;
130+
131+	s->len += len;
132+	if (r) {
133+		if (len < 64 - r) {
134+			memcpy(s->buf + r, p, len);
135+			return;
136+		}
137+		memcpy(s->buf + r, p, 64 - r);
138+		len -= 64 - r;
139+		p += 64 - r;
140+		processblock(s, s->buf);
141+	}
142+	for (; len >= 64; len -= 64, p += 64)
143+		processblock(s, p);
144+	memcpy(s->buf, p, len);
145+}
+26, -0
 1@@ -0,0 +1,26 @@
 2+/* public domain sha224 implementation based on fips180-3 */
 3+#include <stdint.h>
 4+#include "../sha224.h"
 5+
 6+extern void sha256_sum_n(void *, uint8_t *, int n);
 7+
 8+void
 9+sha224_init(void *ctx)
10+{
11+	struct sha224 *s = ctx;
12+	s->len = 0;
13+	s->h[0] = 0xc1059ed8;
14+	s->h[1] = 0x367cd507;
15+	s->h[2] = 0x3070dd17;
16+	s->h[3] = 0xf70e5939;
17+	s->h[4] = 0xffc00b31;
18+	s->h[5] = 0x68581511;
19+	s->h[6] = 0x64f98fa7;
20+	s->h[7] = 0xbefa4fa4;
21+}
22+
23+void
24+sha224_sum(void *ctx, uint8_t md[SHA224_DIGEST_LENGTH])
25+{
26+	sha256_sum_n(ctx, md, 7);
27+}
+154, -0
  1@@ -0,0 +1,154 @@
  2+/* public domain sha256 implementation based on fips180-3 */
  3+#include <ctype.h>
  4+#include <stdint.h>
  5+#include <stdio.h>
  6+#include <stdlib.h>
  7+#include <string.h>
  8+
  9+#include "../sha256.h"
 10+
 11+static uint32_t ror(uint32_t n, int k) { return (n >> k) | (n << (32-k)); }
 12+#define Ch(x,y,z)  (z ^ (x & (y ^ z)))
 13+#define Maj(x,y,z) ((x & y) | (z & (x | y)))
 14+#define S0(x)      (ror(x,2) ^ ror(x,13) ^ ror(x,22))
 15+#define S1(x)      (ror(x,6) ^ ror(x,11) ^ ror(x,25))
 16+#define R0(x)      (ror(x,7) ^ ror(x,18) ^ (x>>3))
 17+#define R1(x)      (ror(x,17) ^ ror(x,19) ^ (x>>10))
 18+
 19+static const uint32_t K[64] = {
 20+0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
 21+0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
 22+0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
 23+0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
 24+0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
 25+0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
 26+0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
 27+0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
 28+};
 29+
 30+static void
 31+processblock(struct sha256 *s, const uint8_t *buf)
 32+{
 33+	uint32_t W[64], t1, t2, a, b, c, d, e, f, g, h;
 34+	int i;
 35+
 36+	for (i = 0; i < 16; i++) {
 37+		W[i] = (uint32_t)buf[4*i]<<24;
 38+		W[i] |= (uint32_t)buf[4*i+1]<<16;
 39+		W[i] |= (uint32_t)buf[4*i+2]<<8;
 40+		W[i] |= buf[4*i+3];
 41+	}
 42+	for (; i < 64; i++)
 43+		W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16];
 44+	a = s->h[0];
 45+	b = s->h[1];
 46+	c = s->h[2];
 47+	d = s->h[3];
 48+	e = s->h[4];
 49+	f = s->h[5];
 50+	g = s->h[6];
 51+	h = s->h[7];
 52+	for (i = 0; i < 64; i++) {
 53+		t1 = h + S1(e) + Ch(e,f,g) + K[i] + W[i];
 54+		t2 = S0(a) + Maj(a,b,c);
 55+		h = g;
 56+		g = f;
 57+		f = e;
 58+		e = d + t1;
 59+		d = c;
 60+		c = b;
 61+		b = a;
 62+		a = t1 + t2;
 63+	}
 64+	s->h[0] += a;
 65+	s->h[1] += b;
 66+	s->h[2] += c;
 67+	s->h[3] += d;
 68+	s->h[4] += e;
 69+	s->h[5] += f;
 70+	s->h[6] += g;
 71+	s->h[7] += h;
 72+}
 73+
 74+static void
 75+pad(struct sha256 *s)
 76+{
 77+	unsigned r = s->len % 64;
 78+
 79+	s->buf[r++] = 0x80;
 80+	if (r > 56) {
 81+		memset(s->buf + r, 0, 64 - r);
 82+		r = 0;
 83+		processblock(s, s->buf);
 84+	}
 85+	memset(s->buf + r, 0, 56 - r);
 86+	s->len *= 8;
 87+	s->buf[56] = s->len >> 56;
 88+	s->buf[57] = s->len >> 48;
 89+	s->buf[58] = s->len >> 40;
 90+	s->buf[59] = s->len >> 32;
 91+	s->buf[60] = s->len >> 24;
 92+	s->buf[61] = s->len >> 16;
 93+	s->buf[62] = s->len >> 8;
 94+	s->buf[63] = s->len;
 95+	processblock(s, s->buf);
 96+}
 97+
 98+void
 99+sha256_init(void *ctx)
100+{
101+	struct sha256 *s = ctx;
102+	s->len = 0;
103+	s->h[0] = 0x6a09e667;
104+	s->h[1] = 0xbb67ae85;
105+	s->h[2] = 0x3c6ef372;
106+	s->h[3] = 0xa54ff53a;
107+	s->h[4] = 0x510e527f;
108+	s->h[5] = 0x9b05688c;
109+	s->h[6] = 0x1f83d9ab;
110+	s->h[7] = 0x5be0cd19;
111+}
112+
113+void
114+sha256_sum_n(void *ctx, uint8_t *md, int n)
115+{
116+	struct sha256 *s = ctx;
117+	int i;
118+
119+	pad(s);
120+	for (i = 0; i < n; i++) {
121+		md[4*i] = s->h[i] >> 24;
122+		md[4*i+1] = s->h[i] >> 16;
123+		md[4*i+2] = s->h[i] >> 8;
124+		md[4*i+3] = s->h[i];
125+	}
126+}
127+
128+void
129+sha256_sum(void *ctx, uint8_t md[SHA256_DIGEST_LENGTH])
130+{
131+	sha256_sum_n(ctx, md, 8);
132+}
133+
134+void
135+sha256_update(void *ctx, const void *m, unsigned long len)
136+{
137+	struct sha256 *s = ctx;
138+	const uint8_t *p = m;
139+	unsigned r = s->len % 64;
140+
141+	s->len += len;
142+	if (r) {
143+		if (len < 64 - r) {
144+			memcpy(s->buf + r, p, len);
145+			return;
146+		}
147+		memcpy(s->buf + r, p, 64 - r);
148+		len -= 64 - r;
149+		p += 64 - r;
150+		processblock(s, s->buf);
151+	}
152+	for (; len >= 64; len -= 64, p += 64)
153+		processblock(s, p);
154+	memcpy(s->buf, p, len);
155+}
+26, -0
 1@@ -0,0 +1,26 @@
 2+/* public domain sha384 implementation based on fips180-3 */
 3+#include <stdint.h>
 4+#include "../sha384.h"
 5+
 6+extern void sha512_sum_n(void *, uint8_t *, int n);
 7+
 8+void
 9+sha384_init(void *ctx)
10+{
11+	struct sha384 *s = ctx;
12+	s->len = 0;
13+	s->h[0] = 0xcbbb9d5dc1059ed8ULL;
14+	s->h[1] = 0x629a292a367cd507ULL;
15+	s->h[2] = 0x9159015a3070dd17ULL;
16+	s->h[3] = 0x152fecd8f70e5939ULL;
17+	s->h[4] = 0x67332667ffc00b31ULL;
18+	s->h[5] = 0x8eb44a8768581511ULL;
19+	s->h[6] = 0xdb0c2e0d64f98fa7ULL;
20+	s->h[7] = 0x47b5481dbefa4fa4ULL;
21+}
22+
23+void
24+sha384_sum(void *ctx, uint8_t md[SHA384_DIGEST_LENGTH])
25+{
26+	sha512_sum_n(ctx, md, 6);
27+}
+29, -0
 1@@ -0,0 +1,29 @@
 2+/* public domain sha512/224 implementation based on fips180-3 */
 3+#include <stdint.h>
 4+#include <string.h>
 5+#include "../sha512-224.h"
 6+
 7+extern void sha512_sum_n(void *, uint8_t *, int n);
 8+
 9+void
10+sha512_224_init(void *ctx)
11+{
12+	struct sha512_224 *s = ctx;
13+	s->len = 0;
14+	s->h[0] = 0x8c3d37c819544da2ULL;
15+	s->h[1] = 0x73e1996689dcd4d6ULL;
16+	s->h[2] = 0x1dfab7ae32ff9c82ULL;
17+	s->h[3] = 0x679dd514582f9fcfULL;
18+	s->h[4] = 0x0f6d2b697bd44da8ULL;
19+	s->h[5] = 0x77e36f7304c48942ULL;
20+	s->h[6] = 0x3f9d85a86a1d36c8ULL;
21+	s->h[7] = 0x1112e6ad91d692a1ULL;
22+}
23+
24+void
25+sha512_224_sum(void *ctx, uint8_t md[SHA512_224_DIGEST_LENGTH])
26+{
27+	uint8_t buf[32];
28+	sha512_sum_n(ctx, buf, 4);
29+	memcpy(md, buf, SHA512_224_DIGEST_LENGTH);
30+}
+26, -0
 1@@ -0,0 +1,26 @@
 2+/* public domain sha512/256 implementation based on fips180-3 */
 3+#include <stdint.h>
 4+#include "../sha512-256.h"
 5+
 6+extern void sha512_sum_n(void *, uint8_t *, int n);
 7+
 8+void
 9+sha512_256_init(void *ctx)
10+{
11+	struct sha512_256 *s = ctx;
12+	s->len = 0;
13+	s->h[0] = 0x22312194fc2bf72cULL;
14+	s->h[1] = 0x9f555fa3c84c64c2ULL;
15+	s->h[2] = 0x2393b86b6f53b151ULL;
16+	s->h[3] = 0x963877195940eabdULL;
17+	s->h[4] = 0x96283ee2a88effe3ULL;
18+	s->h[5] = 0xbe5e1e2553863992ULL;
19+	s->h[6] = 0x2b0199fc2c85b8aaULL;
20+	s->h[7] = 0x0eb72ddc81c52ca2ULL;
21+}
22+
23+void
24+sha512_256_sum(void *ctx, uint8_t md[SHA512_256_DIGEST_LENGTH])
25+{
26+	sha512_sum_n(ctx, md, 4);
27+}
+175, -0
  1@@ -0,0 +1,175 @@
  2+/* public domain sha256 implementation based on fips180-3 */
  3+
  4+#include <ctype.h>
  5+#include <stdint.h>
  6+#include <stdio.h>
  7+#include <stdlib.h>
  8+#include <string.h>
  9+
 10+#include "../sha512.h"
 11+
 12+static uint64_t ror(uint64_t n, int k) { return (n >> k) | (n << (64-k)); }
 13+#define Ch(x,y,z)  (z ^ (x & (y ^ z)))
 14+#define Maj(x,y,z) ((x & y) | (z & (x | y)))
 15+#define S0(x)      (ror(x,28) ^ ror(x,34) ^ ror(x,39))
 16+#define S1(x)      (ror(x,14) ^ ror(x,18) ^ ror(x,41))
 17+#define R0(x)      (ror(x,1) ^ ror(x,8) ^ (x>>7))
 18+#define R1(x)      (ror(x,19) ^ ror(x,61) ^ (x>>6))
 19+
 20+static const uint64_t K[80] = {
 21+0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
 22+0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
 23+0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
 24+0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
 25+0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
 26+0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
 27+0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
 28+0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
 29+0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
 30+0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
 31+0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
 32+0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
 33+0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
 34+0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
 35+0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
 36+0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
 37+0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
 38+0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
 39+0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
 40+0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
 41+};
 42+
 43+static void
 44+processblock(struct sha512 *s, const uint8_t *buf)
 45+{
 46+	uint64_t W[80], t1, t2, a, b, c, d, e, f, g, h;
 47+	int i;
 48+
 49+	for (i = 0; i < 16; i++) {
 50+		W[i] = (uint64_t)buf[8*i]<<56;
 51+		W[i] |= (uint64_t)buf[8*i+1]<<48;
 52+		W[i] |= (uint64_t)buf[8*i+2]<<40;
 53+		W[i] |= (uint64_t)buf[8*i+3]<<32;
 54+		W[i] |= (uint64_t)buf[8*i+4]<<24;
 55+		W[i] |= (uint64_t)buf[8*i+5]<<16;
 56+		W[i] |= (uint64_t)buf[8*i+6]<<8;
 57+		W[i] |= buf[8*i+7];
 58+	}
 59+	for (; i < 80; i++)
 60+		W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16];
 61+	a = s->h[0];
 62+	b = s->h[1];
 63+	c = s->h[2];
 64+	d = s->h[3];
 65+	e = s->h[4];
 66+	f = s->h[5];
 67+	g = s->h[6];
 68+	h = s->h[7];
 69+	for (i = 0; i < 80; i++) {
 70+		t1 = h + S1(e) + Ch(e,f,g) + K[i] + W[i];
 71+		t2 = S0(a) + Maj(a,b,c);
 72+		h = g;
 73+		g = f;
 74+		f = e;
 75+		e = d + t1;
 76+		d = c;
 77+		c = b;
 78+		b = a;
 79+		a = t1 + t2;
 80+	}
 81+	s->h[0] += a;
 82+	s->h[1] += b;
 83+	s->h[2] += c;
 84+	s->h[3] += d;
 85+	s->h[4] += e;
 86+	s->h[5] += f;
 87+	s->h[6] += g;
 88+	s->h[7] += h;
 89+}
 90+
 91+static void
 92+pad(struct sha512 *s)
 93+{
 94+	unsigned r = s->len % 128;
 95+
 96+	s->buf[r++] = 0x80;
 97+	if (r > 112) {
 98+		memset(s->buf + r, 0, 128 - r);
 99+		r = 0;
100+		processblock(s, s->buf);
101+	}
102+	memset(s->buf + r, 0, 120 - r);
103+	s->len *= 8;
104+	s->buf[120] = s->len >> 56;
105+	s->buf[121] = s->len >> 48;
106+	s->buf[122] = s->len >> 40;
107+	s->buf[123] = s->len >> 32;
108+	s->buf[124] = s->len >> 24;
109+	s->buf[125] = s->len >> 16;
110+	s->buf[126] = s->len >> 8;
111+	s->buf[127] = s->len;
112+	processblock(s, s->buf);
113+}
114+
115+void
116+sha512_init(void *ctx)
117+{
118+	struct sha512 *s = ctx;
119+	s->len = 0;
120+	s->h[0] = 0x6a09e667f3bcc908ULL;
121+	s->h[1] = 0xbb67ae8584caa73bULL;
122+	s->h[2] = 0x3c6ef372fe94f82bULL;
123+	s->h[3] = 0xa54ff53a5f1d36f1ULL;
124+	s->h[4] = 0x510e527fade682d1ULL;
125+	s->h[5] = 0x9b05688c2b3e6c1fULL;
126+	s->h[6] = 0x1f83d9abfb41bd6bULL;
127+	s->h[7] = 0x5be0cd19137e2179ULL;
128+}
129+
130+void
131+sha512_sum_n(void *ctx, uint8_t *md, int n)
132+{
133+	struct sha512 *s = ctx;
134+	int i;
135+
136+	pad(s);
137+	for (i = 0; i < n; i++) {
138+		md[8*i] = s->h[i] >> 56;
139+		md[8*i+1] = s->h[i] >> 48;
140+		md[8*i+2] = s->h[i] >> 40;
141+		md[8*i+3] = s->h[i] >> 32;
142+		md[8*i+4] = s->h[i] >> 24;
143+		md[8*i+5] = s->h[i] >> 16;
144+		md[8*i+6] = s->h[i] >> 8;
145+		md[8*i+7] = s->h[i];
146+	}
147+}
148+
149+void
150+sha512_sum(void *ctx, uint8_t md[SHA512_DIGEST_LENGTH])
151+{
152+	sha512_sum_n(ctx, md, 8);
153+}
154+
155+void
156+sha512_update(void *ctx, const void *m, unsigned long len)
157+{
158+	struct sha512 *s = ctx;
159+	const uint8_t *p = m;
160+	unsigned r = s->len % 128;
161+
162+	s->len += len;
163+	if (r) {
164+		if (len < 128 - r) {
165+			memcpy(s->buf + r, p, len);
166+			return;
167+		}
168+		memcpy(s->buf + r, p, 128 - r);
169+		len -= 128 - r;
170+		p += 128 - r;
171+		processblock(s, s->buf);
172+	}
173+	for (; len >= 128; len -= 128, p += 128)
174+		processblock(s, p);
175+	memcpy(s->buf, p, len);
176+}
+38, -0
 1@@ -0,0 +1,38 @@
 2+/*
 3+ * Copyright 2005-2014 Rich Felker, et al.
 4+ *
 5+ * Permission is hereby granted, free of charge, to any person obtaining
 6+ * a copy of this software and associated documentation files (the
 7+ * "Software"), to deal in the Software without restriction, including
 8+ * without limitation the rights to use, copy, modify, merge, publish,
 9+ * distribute, sublicense, and/or sell copies of the Software, and to
10+ * permit persons to whom the Software is furnished to do so, subject to
11+ * the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be
14+ * included in all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+*/
24+#include <string.h>
25+#include <strings.h>
26+
27+#include "../util.h"
28+
29+char *
30+strcasestr(const char *h, const char *n)
31+{
32+	size_t l = strlen(n);
33+
34+	for (; *h; h++)
35+		if (!strncasecmp(h, n, l))
36+			return (char *)h;
37+
38+	return 0;
39+}
+63, -0
 1@@ -0,0 +1,63 @@
 2+/*
 3+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
 4+ *
 5+ * Permission to use, copy, modify, and distribute this software for any
 6+ * purpose with or without fee is hereby granted, provided that the above
 7+ * copyright notice and this permission notice appear in all copies.
 8+ *
 9+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16+ */
17+
18+#include <string.h>
19+#include <sys/types.h>
20+
21+#include "../util.h"
22+
23+/*
24+ * Appends src to string dst of size siz (unlike strncat, siz is the
25+ * full size of dst, not space left). At most siz-1 characters
26+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
27+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
28+ * If retval >= siz, truncation occurred.
29+ */
30+size_t
31+strlcat(char *dst, const char *src, size_t siz)
32+{
33+	char *d = dst;
34+	const char *s = src;
35+	size_t n = siz;
36+	size_t dlen;
37+	/* Find the end of dst and adjust bytes left but don't go past end */
38+	while (n-- != 0 && *d != '\0')
39+		d++;
40+	dlen = d - dst;
41+	n = siz - dlen;
42+	if (n == 0)
43+		return(dlen + strlen(s));
44+	while (*s != '\0') {
45+		if (n != 1) {
46+			*d++ = *s;
47+			n--;
48+		}
49+		s++;
50+	}
51+	*d = '\0';
52+	return(dlen + (s - src)); /* count does not include NUL */
53+}
54+
55+size_t
56+estrlcat(char *dst, const char *src, size_t siz)
57+{
58+	size_t ret;
59+
60+	if ((ret = strlcat(dst, src, siz)) >= siz)
61+		eprintf("strlcat: input string too long\n");
62+
63+	return ret;
64+}
+59, -0
 1@@ -0,0 +1,59 @@
 2+/*
 3+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
 4+ *
 5+ * Permission to use, copy, modify, and distribute this software for any
 6+ * purpose with or without fee is hereby granted, provided that the above
 7+ * copyright notice and this permission notice appear in all copies.
 8+ *
 9+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16+ */
17+
18+#include <string.h>
19+#include <sys/types.h>
20+
21+#include "../util.h"
22+
23+/*
24+ * Copy src to string dst of size siz. At most siz-1 characters
25+ * will be copied. Always NUL terminates (unless siz == 0).
26+ * Returns strlen(src); if retval >= siz, truncation occurred.
27+ */
28+size_t
29+strlcpy(char *dst, const char *src, size_t siz)
30+{
31+	char *d = dst;
32+	const char *s = src;
33+	size_t n = siz;
34+	/* Copy as many bytes as will fit */
35+	if (n != 0) {
36+		while (--n != 0) {
37+			if ((*d++ = *s++) == '\0')
38+				break;
39+		}
40+	}
41+	/* Not enough room in dst, add NUL and traverse rest of src */
42+	if (n == 0) {
43+		if (siz != 0)
44+			*d = '\0'; /* NUL-terminate dst */
45+		while (*s++)
46+			;
47+	}
48+	return(s - src - 1); /* count does not include NUL */
49+}
50+
51+size_t
52+estrlcpy(char *dst, const char *src, size_t siz)
53+{
54+	size_t ret;
55+
56+	if ((ret = strlcpy(dst, src, siz)) >= siz)
57+		eprintf("strlcpy: input string too long\n");
58+
59+	return ret;
60+}
+61, -0
 1@@ -0,0 +1,61 @@
 2+/*
 3+ * Copyright (c) 2002 J. Mallett.  All rights reserved.
 4+ * You may do whatever you want with this file as long as
 5+ * the above copyright and this notice remain intact, along
 6+ * with the following statement:
 7+ * 	For the man who taught me vi, and who got too old, too young.
 8+ */
 9+
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+
14+#include "../util.h"
15+
16+/*
17+ * Replaces str with a string consisting of str with match replaced with
18+ * replstr as many times as can be done before the constructed string is
19+ * maxsize bytes large.  It does not free the string pointed to by str, it
20+ * is up to the calling program to be sure that the original contents of
21+ * str as well as the new contents are handled in an appropriate manner.
22+ * If replstr is NULL, then that internally is changed to a nil-string, so
23+ * that we can still pretend to do somewhat meaningful substitution.
24+ * No value is returned.
25+ */
26+void
27+strnsubst(char **str, const char *match, const char *replstr, size_t maxsize)
28+{
29+	char *s1, *s2, *this;
30+	size_t matchlen, s2len;
31+	int n;
32+
33+	if ((s1 = *str) == NULL)
34+		return;
35+	s2 = emalloc(maxsize);
36+
37+	if (replstr == NULL)
38+		replstr = "";
39+
40+	if (match == NULL || *match == '\0' || strlen(s1) >= maxsize) {
41+		strlcpy(s2, s1, maxsize);
42+		goto done;
43+	}
44+
45+	*s2 = '\0';
46+	s2len = 0;
47+	matchlen = strlen(match);
48+	for (;;) {
49+		if ((this = strstr(s1, match)) == NULL)
50+			break;
51+		n = snprintf(s2 + s2len, maxsize - s2len, "%.*s%s",
52+		    (int)(this - s1), s1, replstr);
53+		if (n == -1 || n + s2len + strlen(this + matchlen) >= maxsize)
54+			break;			/* out of room */
55+		s2len += n;
56+		s1 = this + matchlen;
57+	}
58+	strlcpy(s2 + s2len, s1, maxsize - s2len);
59+done:
60+	*str = s2;
61+	return;
62+}
+37, -0
 1@@ -0,0 +1,37 @@
 2+/*
 3+ * Copyright 2005-2014 Rich Felker, et al.
 4+ *
 5+ * Permission is hereby granted, free of charge, to any person obtaining
 6+ * a copy of this software and associated documentation files (the
 7+ * "Software"), to deal in the Software without restriction, including
 8+ * without limitation the rights to use, copy, modify, merge, publish,
 9+ * distribute, sublicense, and/or sell copies of the Software, and to
10+ * permit persons to whom the Software is furnished to do so, subject to
11+ * the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be
14+ * included in all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+*/
24+#include <string.h>
25+
26+#include "../util.h"
27+
28+char *
29+strsep(char **str, const char *sep)
30+{
31+	char *s = *str, *end;
32+	if (!s) return NULL;
33+	end = s + strcspn(s, sep);
34+	if (*end) *end++ = 0;
35+	else end = 0;
36+	*str = end;
37+	return s;
38+}
+85, -0
 1@@ -0,0 +1,85 @@
 2+/*	$OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $	*/
 3+
 4+/*
 5+ * Copyright (c) 2004 Ted Unangst and Todd Miller
 6+ * All rights reserved.
 7+ *
 8+ * Permission to use, copy, modify, and distribute this software for any
 9+ * purpose with or without fee is hereby granted, provided that the above
10+ * copyright notice and this permission notice appear in all copies.
11+ *
12+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19+ */
20+
21+#include <errno.h>
22+#include <limits.h>
23+#include <stdlib.h>
24+
25+#include "../util.h"
26+
27+#define	INVALID		1
28+#define	TOOSMALL	2
29+#define	TOOLARGE	3
30+
31+long long
32+strtonum(const char *numstr, long long minval, long long maxval,
33+         const char **errstrp)
34+{
35+	long long ll = 0;
36+	int error = 0;
37+	char *ep;
38+	struct errval {
39+		const char *errstr;
40+		int err;
41+	} ev[4] = {
42+		{ NULL,		0 },
43+		{ "invalid",	EINVAL },
44+		{ "too small",	ERANGE },
45+		{ "too large",	ERANGE },
46+	};
47+
48+	ev[0].err = errno;
49+	errno = 0;
50+	if (minval > maxval) {
51+		error = INVALID;
52+	} else {
53+		ll = strtoll(numstr, &ep, 10);
54+		if (numstr == ep || *ep != '\0')
55+			error = INVALID;
56+		else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
57+			error = TOOSMALL;
58+		else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
59+			error = TOOLARGE;
60+	}
61+	if (errstrp != NULL)
62+		*errstrp = ev[error].errstr;
63+	errno = ev[error].err;
64+	if (error)
65+		ll = 0;
66+
67+	return (ll);
68+}
69+
70+long long
71+enstrtonum(int status, const char *numstr, long long minval, long long maxval)
72+{
73+	const char *errstr;
74+	long long ll;
75+
76+	ll = strtonum(numstr, minval, maxval, &errstr);
77+	if (errstr)
78+		enprintf(status, "strtonum %s: %s\n", numstr, errstr);
79+	return ll;
80+}
81+
82+long long
83+estrtonum(const char *numstr, long long minval, long long maxval)
84+{
85+	return enstrtonum(1, numstr, minval, maxval);
86+}
+98, -0
 1@@ -0,0 +1,98 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <sys/sysmacros.h>
 4+#include <sys/types.h>
 5+#include <sys/stat.h>
 6+
 7+#include <fcntl.h>
 8+#include <dirent.h>
 9+#include <limits.h>
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+#include <unistd.h>
14+
15+#include "../util.h"
16+
17+void
18+devtotty(int dev, int *tty_maj, int *tty_min)
19+{
20+	*tty_maj = (dev >> 8) & 0xfff;
21+	*tty_min = (dev & 0xff) | ((dev >> 12) & 0xfff00);
22+}
23+
24+int
25+ttytostr(int tty_maj, int tty_min, char *str, size_t n)
26+{
27+	struct stat sb;
28+	struct dirent *dp;
29+	DIR *dirp;
30+	char path[PATH_MAX];
31+	int fd;
32+	int r = 0;
33+
34+	switch (tty_maj) {
35+	case 136:
36+		snprintf(str, n, "pts/%d", tty_min);
37+		return 0;
38+	case 4:
39+		snprintf(str, n, "tty%d", tty_min);
40+		return 0;
41+	default:
42+		str[0] = '?';
43+		str[1] = '\0';
44+		break;
45+	}
46+
47+	dirp = opendir("/dev");
48+	if (!dirp) {
49+		weprintf("opendir /dev:");
50+		return -1;
51+	}
52+
53+	while ((dp = readdir(dirp))) {
54+		if (!strcmp(dp->d_name, ".") ||
55+		    !strcmp(dp->d_name, ".."))
56+			continue;
57+
58+		if (strlcpy(path, "/dev/", sizeof(path)) >= sizeof(path)) {
59+			weprintf("path too long\n");
60+			r = -1;
61+			goto err0;
62+		}
63+		if (strlcat(path, dp->d_name, sizeof(path)) >= sizeof(path)) {
64+			weprintf("path too long\n");
65+			r = -1;
66+			goto err0;
67+		}
68+
69+		if (stat(path, &sb) < 0) {
70+			weprintf("stat %s:", path);
71+			r = -1;
72+			goto err0;
73+		}
74+
75+		if ((int)major(sb.st_rdev) == tty_maj &&
76+		    (int)minor(sb.st_rdev) == tty_min) {
77+			fd = open(path, O_RDONLY | O_NONBLOCK);
78+			if (fd < 0)
79+				continue;
80+			if (isatty(fd)) {
81+				strlcpy(str, dp->d_name, n);
82+				close(fd);
83+				break;
84+			} else {
85+				close(fd);
86+				r = -1;
87+				goto err0;
88+			}
89+		}
90+	}
91+
92+err0:
93+	if (closedir(dirp) < 0) {
94+		weprintf("closedir /dev:");
95+		r = -1;
96+	}
97+
98+	return r;
99+}
+58, -0
 1@@ -0,0 +1,58 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <ctype.h>
 4+#include <string.h>
 5+
 6+#include "../util.h"
 7+
 8+#define is_odigit(c)  ('0' <= c && c <= '7')
 9+
10+size_t
11+unescape(char *s)
12+{
13+	static const char escapes[256] = {
14+		['"'] = '"',
15+		['\''] = '\'',
16+		['\\'] = '\\',
17+		['a'] = '\a',
18+		['b'] = '\b',
19+		['E'] = 033,
20+		['e'] = 033,
21+		['f'] = '\f',
22+		['n'] = '\n',
23+		['r'] = '\r',
24+		['t'] = '\t',
25+		['v'] = '\v'
26+	};
27+	size_t m, q;
28+	char *r, *w;
29+
30+	for (r = w = s; *r;) {
31+		if (*r != '\\') {
32+			*w++ = *r++;
33+			continue;
34+		}
35+		r++;
36+		if (!*r) {
37+			eprintf("null escape sequence\n");
38+		} else if (escapes[(unsigned char)*r]) {
39+			*w++ = escapes[(unsigned char)*r++];
40+		} else if (is_odigit(*r)) {
41+			for (q = 0, m = 3; m && is_odigit(*r); m--, r++)
42+				q = q * 8 + (*r - '0');
43+			*w++ = MIN(q, 255);
44+		} else if (*r == 'x' && isxdigit(r[1])) {
45+			r++;
46+			for (q = 0, m = 2; m && isxdigit(*r); m--, r++)
47+				if (isdigit(*r))
48+					q = q * 16 + (*r - '0');
49+				else
50+					q = q * 16 + (tolower(*r) - 'a' + 10);
51+			*w++ = q;
52+		} else {
53+			eprintf("invalid escape sequence '\\%c'\n", *r);
54+		}
55+	}
56+	*w = '\0';
57+
58+	return w - s;
59+}
+21, -0
 1@@ -0,0 +1,21 @@
 2+/* See LICENSE file for copyright and license details. */
 3+#include <unistd.h>
 4+
 5+#include "../util.h"
 6+
 7+ssize_t
 8+writeall(int fd, const void *buf, size_t len)
 9+{
10+	const char *p = buf;
11+	ssize_t n;
12+
13+	while (len) {
14+		n = write(fd, p, len);
15+		if (n <= 0)
16+			return n;
17+		p += n;
18+		len -= n;
19+	}
20+
21+	return p - (const char *)buf;
22+}
+18, -0
 1@@ -0,0 +1,18 @@
 2+/* public domain md5 implementation based on rfc1321 and libtomcrypt */
 3+
 4+struct md5 {
 5+	uint64_t len;    /* processed message length */
 6+	uint32_t h[4];   /* hash state */
 7+	uint8_t buf[64]; /* message block buffer */
 8+};
 9+
10+enum { MD5_DIGEST_LENGTH = 16 };
11+
12+/* reset state */
13+void md5_init(void *ctx);
14+/* process message */
15+void md5_update(void *ctx, const void *m, unsigned long len);
16+/* get message digest */
17+/* state is ruined after sum, keep a copy if multiple sum is needed */
18+/* part of the message might be left in s, zero it if secrecy is needed */
19+void md5_sum(void *ctx, uint8_t md[MD5_DIGEST_LENGTH]);
+4, -0
1@@ -0,0 +1,4 @@
2+/* See LICENSE file for copyright and license details. */
3+/* passwd.c */
4+int pw_check(const struct passwd *, const char *);
5+int pw_init(void);
+42, -0
 1@@ -0,0 +1,42 @@
 2+/* See LICENSE file for copyright and license details. */
 3+struct procstat {
 4+	int pid;
 5+	char comm[PATH_MAX + 2]; /* + 2 for '(' and ')' */
 6+	unsigned char state;
 7+	int ppid;
 8+	int pgrp;
 9+	int sid;
10+	int tty_nr;
11+	int tpgid;
12+	unsigned flags;
13+	unsigned long minflt;
14+	unsigned long cminflt;
15+	unsigned long majflt;
16+	unsigned long cmajflt;
17+	unsigned long utime;
18+	unsigned long stime;
19+	long cutime;
20+	long cstime;
21+	long priority;
22+	long nice;
23+	long num_threads;
24+	long itrealvalue;
25+	unsigned long long starttime;
26+	unsigned long vsize;
27+	long rss;
28+	long rsslim;
29+};
30+
31+struct procstatus {
32+	uid_t uid;
33+	uid_t euid;
34+	gid_t gid;
35+	gid_t egid;
36+};
37+
38+int parsecmdline(pid_t pid, char *buf, size_t siz);
39+int parsestat(pid_t pid, struct procstat *ps);
40+int parsestatus(pid_t pid, struct procstatus *pstatus);
41+int proceuid(pid_t pid, uid_t *euid);
42+int procuid(pid_t pid, uid_t *euid);
43+int pidfile(const char *file);
+648, -0
  1@@ -0,0 +1,648 @@
  2+/*	$OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $	*/
  3+/*	$NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $	*/
  4+
  5+/*
  6+ * Copyright (c) 1991, 1993
  7+ *	The Regents of the University of California.  All rights reserved.
  8+ *
  9+ * Redistribution and use in source and binary forms, with or without
 10+ * modification, are permitted provided that the following conditions
 11+ * are met:
 12+ * 1. Redistributions of source code must retain the above copyright
 13+ *    notice, this list of conditions and the following disclaimer.
 14+ * 2. Redistributions in binary form must reproduce the above copyright
 15+ *    notice, this list of conditions and the following disclaimer in the
 16+ *    documentation and/or other materials provided with the distribution.
 17+ * 3. Neither the name of the University nor the names of its contributors
 18+ *    may be used to endorse or promote products derived from this software
 19+ *    without specific prior written permission.
 20+ *
 21+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 22+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 23+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 24+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 25+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 26+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 27+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 28+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 29+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 30+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 31+ * SUCH DAMAGE.
 32+ *
 33+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
 34+ */
 35+
 36+#ifndef	_SYS_QUEUE_H_
 37+#define	_SYS_QUEUE_H_
 38+
 39+/*
 40+ * This file defines five types of data structures: singly-linked lists, 
 41+ * lists, simple queues, tail queues, and circular queues.
 42+ *
 43+ *
 44+ * A singly-linked list is headed by a single forward pointer. The elements
 45+ * are singly linked for minimum space and pointer manipulation overhead at
 46+ * the expense of O(n) removal for arbitrary elements. New elements can be
 47+ * added to the list after an existing element or at the head of the list.
 48+ * Elements being removed from the head of the list should use the explicit
 49+ * macro for this purpose for optimum efficiency. A singly-linked list may
 50+ * only be traversed in the forward direction.  Singly-linked lists are ideal
 51+ * for applications with large datasets and few or no removals or for
 52+ * implementing a LIFO queue.
 53+ *
 54+ * A list is headed by a single forward pointer (or an array of forward
 55+ * pointers for a hash table header). The elements are doubly linked
 56+ * so that an arbitrary element can be removed without a need to
 57+ * traverse the list. New elements can be added to the list before
 58+ * or after an existing element or at the head of the list. A list
 59+ * may only be traversed in the forward direction.
 60+ *
 61+ * A simple queue is headed by a pair of pointers, one the head of the
 62+ * list and the other to the tail of the list. The elements are singly
 63+ * linked to save space, so elements can only be removed from the
 64+ * head of the list. New elements can be added to the list before or after
 65+ * an existing element, at the head of the list, or at the end of the
 66+ * list. A simple queue may only be traversed in the forward direction.
 67+ *
 68+ * A tail queue is headed by a pair of pointers, one to the head of the
 69+ * list and the other to the tail of the list. The elements are doubly
 70+ * linked so that an arbitrary element can be removed without a need to
 71+ * traverse the list. New elements can be added to the list before or
 72+ * after an existing element, at the head of the list, or at the end of
 73+ * the list. A tail queue may be traversed in either direction.
 74+ *
 75+ * A circle queue is headed by a pair of pointers, one to the head of the
 76+ * list and the other to the tail of the list. The elements are doubly
 77+ * linked so that an arbitrary element can be removed without a need to
 78+ * traverse the list. New elements can be added to the list before or after
 79+ * an existing element, at the head of the list, or at the end of the list.
 80+ * A circle queue may be traversed in either direction, but has a more
 81+ * complex end of list detection.
 82+ *
 83+ * For details on the use of these macros, see the queue(3) manual page.
 84+ */
 85+
 86+#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
 87+#define _Q_INVALIDATE(a) (a) = ((void *)-1)
 88+#else
 89+#define _Q_INVALIDATE(a)
 90+#endif
 91+
 92+/*
 93+ * Singly-linked List definitions.
 94+ */
 95+#define SLIST_HEAD(name, type)						\
 96+struct name {								\
 97+	struct type *slh_first;	/* first element */			\
 98+}
 99+ 
100+#define	SLIST_HEAD_INITIALIZER(head)					\
101+	{ NULL }
102+ 
103+#define SLIST_ENTRY(type)						\
104+struct {								\
105+	struct type *sle_next;	/* next element */			\
106+}
107+ 
108+/*
109+ * Singly-linked List access methods.
110+ */
111+#define	SLIST_FIRST(head)	((head)->slh_first)
112+#define	SLIST_END(head)		NULL
113+#define	SLIST_EMPTY(head)	(SLIST_FIRST(head) == SLIST_END(head))
114+#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
115+
116+#define	SLIST_FOREACH(var, head, field)					\
117+	for((var) = SLIST_FIRST(head);					\
118+	    (var) != SLIST_END(head);					\
119+	    (var) = SLIST_NEXT(var, field))
120+
121+#define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\
122+	for ((var) = SLIST_FIRST(head);				\
123+	    (var) && ((tvar) = SLIST_NEXT(var, field), 1);		\
124+	    (var) = (tvar))
125+
126+/*
127+ * Singly-linked List functions.
128+ */
129+#define	SLIST_INIT(head) {						\
130+	SLIST_FIRST(head) = SLIST_END(head);				\
131+}
132+
133+#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
134+	(elm)->field.sle_next = (slistelm)->field.sle_next;		\
135+	(slistelm)->field.sle_next = (elm);				\
136+} while (0)
137+
138+#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
139+	(elm)->field.sle_next = (head)->slh_first;			\
140+	(head)->slh_first = (elm);					\
141+} while (0)
142+
143+#define	SLIST_REMOVE_AFTER(elm, field) do {				\
144+	(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;	\
145+} while (0)
146+
147+#define	SLIST_REMOVE_HEAD(head, field) do {				\
148+	(head)->slh_first = (head)->slh_first->field.sle_next;		\
149+} while (0)
150+
151+#define SLIST_REMOVE(head, elm, type, field) do {			\
152+	if ((head)->slh_first == (elm)) {				\
153+		SLIST_REMOVE_HEAD((head), field);			\
154+	} else {							\
155+		struct type *curelm = (head)->slh_first;		\
156+									\
157+		while (curelm->field.sle_next != (elm))			\
158+			curelm = curelm->field.sle_next;		\
159+		curelm->field.sle_next =				\
160+		    curelm->field.sle_next->field.sle_next;		\
161+		_Q_INVALIDATE((elm)->field.sle_next);			\
162+	}								\
163+} while (0)
164+
165+/*
166+ * List definitions.
167+ */
168+#define LIST_HEAD(name, type)						\
169+struct name {								\
170+	struct type *lh_first;	/* first element */			\
171+}
172+
173+#define LIST_HEAD_INITIALIZER(head)					\
174+	{ NULL }
175+
176+#define LIST_ENTRY(type)						\
177+struct {								\
178+	struct type *le_next;	/* next element */			\
179+	struct type **le_prev;	/* address of previous next element */	\
180+}
181+
182+/*
183+ * List access methods
184+ */
185+#define	LIST_FIRST(head)		((head)->lh_first)
186+#define	LIST_END(head)			NULL
187+#define	LIST_EMPTY(head)		(LIST_FIRST(head) == LIST_END(head))
188+#define	LIST_NEXT(elm, field)		((elm)->field.le_next)
189+
190+#define LIST_FOREACH(var, head, field)					\
191+	for((var) = LIST_FIRST(head);					\
192+	    (var)!= LIST_END(head);					\
193+	    (var) = LIST_NEXT(var, field))
194+
195+#define	LIST_FOREACH_SAFE(var, head, field, tvar)			\
196+	for ((var) = LIST_FIRST(head);				\
197+	    (var) && ((tvar) = LIST_NEXT(var, field), 1);		\
198+	    (var) = (tvar))
199+
200+/*
201+ * List functions.
202+ */
203+#define	LIST_INIT(head) do {						\
204+	LIST_FIRST(head) = LIST_END(head);				\
205+} while (0)
206+
207+#define LIST_INSERT_AFTER(listelm, elm, field) do {			\
208+	if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)	\
209+		(listelm)->field.le_next->field.le_prev =		\
210+		    &(elm)->field.le_next;				\
211+	(listelm)->field.le_next = (elm);				\
212+	(elm)->field.le_prev = &(listelm)->field.le_next;		\
213+} while (0)
214+
215+#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
216+	(elm)->field.le_prev = (listelm)->field.le_prev;		\
217+	(elm)->field.le_next = (listelm);				\
218+	*(listelm)->field.le_prev = (elm);				\
219+	(listelm)->field.le_prev = &(elm)->field.le_next;		\
220+} while (0)
221+
222+#define LIST_INSERT_HEAD(head, elm, field) do {				\
223+	if (((elm)->field.le_next = (head)->lh_first) != NULL)		\
224+		(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
225+	(head)->lh_first = (elm);					\
226+	(elm)->field.le_prev = &(head)->lh_first;			\
227+} while (0)
228+
229+#define LIST_REMOVE(elm, field) do {					\
230+	if ((elm)->field.le_next != NULL)				\
231+		(elm)->field.le_next->field.le_prev =			\
232+		    (elm)->field.le_prev;				\
233+	*(elm)->field.le_prev = (elm)->field.le_next;			\
234+	_Q_INVALIDATE((elm)->field.le_prev);				\
235+	_Q_INVALIDATE((elm)->field.le_next);				\
236+} while (0)
237+
238+#define LIST_REPLACE(elm, elm2, field) do {				\
239+	if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)	\
240+		(elm2)->field.le_next->field.le_prev =			\
241+		    &(elm2)->field.le_next;				\
242+	(elm2)->field.le_prev = (elm)->field.le_prev;			\
243+	*(elm2)->field.le_prev = (elm2);				\
244+	_Q_INVALIDATE((elm)->field.le_prev);				\
245+	_Q_INVALIDATE((elm)->field.le_next);				\
246+} while (0)
247+
248+/*
249+ * Simple queue definitions.
250+ */
251+#define SIMPLEQ_HEAD(name, type)					\
252+struct name {								\
253+	struct type *sqh_first;	/* first element */			\
254+	struct type **sqh_last;	/* addr of last next element */		\
255+}
256+
257+#define SIMPLEQ_HEAD_INITIALIZER(head)					\
258+	{ NULL, &(head).sqh_first }
259+
260+#define SIMPLEQ_ENTRY(type)						\
261+struct {								\
262+	struct type *sqe_next;	/* next element */			\
263+}
264+
265+/*
266+ * Simple queue access methods.
267+ */
268+#define	SIMPLEQ_FIRST(head)	    ((head)->sqh_first)
269+#define	SIMPLEQ_END(head)	    NULL
270+#define	SIMPLEQ_EMPTY(head)	    (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
271+#define	SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)
272+
273+#define SIMPLEQ_FOREACH(var, head, field)				\
274+	for((var) = SIMPLEQ_FIRST(head);				\
275+	    (var) != SIMPLEQ_END(head);					\
276+	    (var) = SIMPLEQ_NEXT(var, field))
277+
278+#define	SIMPLEQ_FOREACH_SAFE(var, head, field, tvar)			\
279+	for ((var) = SIMPLEQ_FIRST(head);				\
280+	    (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1);		\
281+	    (var) = (tvar))
282+
283+/*
284+ * Simple queue functions.
285+ */
286+#define	SIMPLEQ_INIT(head) do {						\
287+	(head)->sqh_first = NULL;					\
288+	(head)->sqh_last = &(head)->sqh_first;				\
289+} while (0)
290+
291+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
292+	if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
293+		(head)->sqh_last = &(elm)->field.sqe_next;		\
294+	(head)->sqh_first = (elm);					\
295+} while (0)
296+
297+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
298+	(elm)->field.sqe_next = NULL;					\
299+	*(head)->sqh_last = (elm);					\
300+	(head)->sqh_last = &(elm)->field.sqe_next;			\
301+} while (0)
302+
303+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
304+	if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
305+		(head)->sqh_last = &(elm)->field.sqe_next;		\
306+	(listelm)->field.sqe_next = (elm);				\
307+} while (0)
308+
309+#define SIMPLEQ_REMOVE_HEAD(head, field) do {			\
310+	if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
311+		(head)->sqh_last = &(head)->sqh_first;			\
312+} while (0)
313+
314+#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\
315+	if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
316+	    == NULL)							\
317+		(head)->sqh_last = &(elm)->field.sqe_next;		\
318+} while (0)
319+
320+/*
321+ * XOR Simple queue definitions.
322+ */
323+#define XSIMPLEQ_HEAD(name, type)					\
324+struct name {								\
325+	struct type *sqx_first;	/* first element */			\
326+	struct type **sqx_last;	/* addr of last next element */		\
327+	unsigned long sqx_cookie;					\
328+}
329+
330+#define XSIMPLEQ_ENTRY(type)						\
331+struct {								\
332+	struct type *sqx_next;	/* next element */			\
333+}
334+
335+/*
336+ * XOR Simple queue access methods.
337+ */
338+#define XSIMPLEQ_XOR(head, ptr)	    ((__typeof(ptr))((head)->sqx_cookie ^ \
339+					(unsigned long)(ptr)))
340+#define	XSIMPLEQ_FIRST(head)	    XSIMPLEQ_XOR(head, ((head)->sqx_first))
341+#define	XSIMPLEQ_END(head)	    NULL
342+#define	XSIMPLEQ_EMPTY(head)	    (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
343+#define	XSIMPLEQ_NEXT(head, elm, field)    XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
344+
345+
346+#define XSIMPLEQ_FOREACH(var, head, field)				\
347+	for ((var) = XSIMPLEQ_FIRST(head);				\
348+	    (var) != XSIMPLEQ_END(head);				\
349+	    (var) = XSIMPLEQ_NEXT(head, var, field))
350+
351+#define	XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar)			\
352+	for ((var) = XSIMPLEQ_FIRST(head);				\
353+	    (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1);	\
354+	    (var) = (tvar))
355+
356+/*
357+ * XOR Simple queue functions.
358+ */
359+#define	XSIMPLEQ_INIT(head) do {					\
360+	arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
361+	(head)->sqx_first = XSIMPLEQ_XOR(head, NULL);			\
362+	(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first);	\
363+} while (0)
364+
365+#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
366+	if (((elm)->field.sqx_next = (head)->sqx_first) ==		\
367+	    XSIMPLEQ_XOR(head, NULL))					\
368+		(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
369+	(head)->sqx_first = XSIMPLEQ_XOR(head, (elm));			\
370+} while (0)
371+
372+#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
373+	(elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL);		\
374+	*(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
375+	(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next);	\
376+} while (0)
377+
378+#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
379+	if (((elm)->field.sqx_next = (listelm)->field.sqx_next) ==	\
380+	    XSIMPLEQ_XOR(head, NULL))					\
381+		(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
382+	(listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm));		\
383+} while (0)
384+
385+#define XSIMPLEQ_REMOVE_HEAD(head, field) do {				\
386+	if (((head)->sqx_first = XSIMPLEQ_XOR(head,			\
387+	    (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
388+		(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
389+} while (0)
390+
391+#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\
392+	if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head,			\
393+	    (elm)->field.sqx_next)->field.sqx_next)			\
394+	    == XSIMPLEQ_XOR(head, NULL))				\
395+		(head)->sqx_last = 					\
396+		    XSIMPLEQ_XOR(head, &(elm)->field.sqx_next);		\
397+} while (0)
398+
399+		    
400+/*
401+ * Tail queue definitions.
402+ */
403+#define TAILQ_HEAD(name, type)						\
404+struct name {								\
405+	struct type *tqh_first;	/* first element */			\
406+	struct type **tqh_last;	/* addr of last next element */		\
407+}
408+
409+#define TAILQ_HEAD_INITIALIZER(head)					\
410+	{ NULL, &(head).tqh_first }
411+
412+#define TAILQ_ENTRY(type)						\
413+struct {								\
414+	struct type *tqe_next;	/* next element */			\
415+	struct type **tqe_prev;	/* address of previous next element */	\
416+}
417+
418+/* 
419+ * tail queue access methods 
420+ */
421+#define	TAILQ_FIRST(head)		((head)->tqh_first)
422+#define	TAILQ_END(head)			NULL
423+#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
424+#define TAILQ_LAST(head, headname)					\
425+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
426+/* XXX */
427+#define TAILQ_PREV(elm, headname, field)				\
428+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
429+#define	TAILQ_EMPTY(head)						\
430+	(TAILQ_FIRST(head) == TAILQ_END(head))
431+
432+#define TAILQ_FOREACH(var, head, field)					\
433+	for((var) = TAILQ_FIRST(head);					\
434+	    (var) != TAILQ_END(head);					\
435+	    (var) = TAILQ_NEXT(var, field))
436+
437+#define	TAILQ_FOREACH_SAFE(var, head, field, tvar)			\
438+	for ((var) = TAILQ_FIRST(head);					\
439+	    (var) != TAILQ_END(head) &&					\
440+	    ((tvar) = TAILQ_NEXT(var, field), 1);			\
441+	    (var) = (tvar))
442+
443+
444+#define TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
445+	for((var) = TAILQ_LAST(head, headname);				\
446+	    (var) != TAILQ_END(head);					\
447+	    (var) = TAILQ_PREV(var, headname, field))
448+
449+#define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
450+	for ((var) = TAILQ_LAST(head, headname);			\
451+	    (var) != TAILQ_END(head) &&					\
452+	    ((tvar) = TAILQ_PREV(var, headname, field), 1);		\
453+	    (var) = (tvar))
454+
455+/*
456+ * Tail queue functions.
457+ */
458+#define	TAILQ_INIT(head) do {						\
459+	(head)->tqh_first = NULL;					\
460+	(head)->tqh_last = &(head)->tqh_first;				\
461+} while (0)
462+
463+#define TAILQ_INSERT_HEAD(head, elm, field) do {			\
464+	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
465+		(head)->tqh_first->field.tqe_prev =			\
466+		    &(elm)->field.tqe_next;				\
467+	else								\
468+		(head)->tqh_last = &(elm)->field.tqe_next;		\
469+	(head)->tqh_first = (elm);					\
470+	(elm)->field.tqe_prev = &(head)->tqh_first;			\
471+} while (0)
472+
473+#define TAILQ_INSERT_TAIL(head, elm, field) do {			\
474+	(elm)->field.tqe_next = NULL;					\
475+	(elm)->field.tqe_prev = (head)->tqh_last;			\
476+	*(head)->tqh_last = (elm);					\
477+	(head)->tqh_last = &(elm)->field.tqe_next;			\
478+} while (0)
479+
480+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
481+	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
482+		(elm)->field.tqe_next->field.tqe_prev =			\
483+		    &(elm)->field.tqe_next;				\
484+	else								\
485+		(head)->tqh_last = &(elm)->field.tqe_next;		\
486+	(listelm)->field.tqe_next = (elm);				\
487+	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
488+} while (0)
489+
490+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
491+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
492+	(elm)->field.tqe_next = (listelm);				\
493+	*(listelm)->field.tqe_prev = (elm);				\
494+	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
495+} while (0)
496+
497+#define TAILQ_REMOVE(head, elm, field) do {				\
498+	if (((elm)->field.tqe_next) != NULL)				\
499+		(elm)->field.tqe_next->field.tqe_prev =			\
500+		    (elm)->field.tqe_prev;				\
501+	else								\
502+		(head)->tqh_last = (elm)->field.tqe_prev;		\
503+	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
504+	_Q_INVALIDATE((elm)->field.tqe_prev);				\
505+	_Q_INVALIDATE((elm)->field.tqe_next);				\
506+} while (0)
507+
508+#define TAILQ_REPLACE(head, elm, elm2, field) do {			\
509+	if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)	\
510+		(elm2)->field.tqe_next->field.tqe_prev =		\
511+		    &(elm2)->field.tqe_next;				\
512+	else								\
513+		(head)->tqh_last = &(elm2)->field.tqe_next;		\
514+	(elm2)->field.tqe_prev = (elm)->field.tqe_prev;			\
515+	*(elm2)->field.tqe_prev = (elm2);				\
516+	_Q_INVALIDATE((elm)->field.tqe_prev);				\
517+	_Q_INVALIDATE((elm)->field.tqe_next);				\
518+} while (0)
519+
520+/*
521+ * Circular queue definitions.
522+ */
523+#define CIRCLEQ_HEAD(name, type)					\
524+struct name {								\
525+	struct type *cqh_first;		/* first element */		\
526+	struct type *cqh_last;		/* last element */		\
527+}
528+
529+#define CIRCLEQ_HEAD_INITIALIZER(head)					\
530+	{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
531+
532+#define CIRCLEQ_ENTRY(type)						\
533+struct {								\
534+	struct type *cqe_next;		/* next element */		\
535+	struct type *cqe_prev;		/* previous element */		\
536+}
537+
538+/*
539+ * Circular queue access methods 
540+ */
541+#define	CIRCLEQ_FIRST(head)		((head)->cqh_first)
542+#define	CIRCLEQ_LAST(head)		((head)->cqh_last)
543+#define	CIRCLEQ_END(head)		((void *)(head))
544+#define	CIRCLEQ_NEXT(elm, field)	((elm)->field.cqe_next)
545+#define	CIRCLEQ_PREV(elm, field)	((elm)->field.cqe_prev)
546+#define	CIRCLEQ_EMPTY(head)						\
547+	(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
548+
549+#define CIRCLEQ_FOREACH(var, head, field)				\
550+	for((var) = CIRCLEQ_FIRST(head);				\
551+	    (var) != CIRCLEQ_END(head);					\
552+	    (var) = CIRCLEQ_NEXT(var, field))
553+
554+#define	CIRCLEQ_FOREACH_SAFE(var, head, field, tvar)			\
555+	for ((var) = CIRCLEQ_FIRST(head);				\
556+	    (var) != CIRCLEQ_END(head) &&				\
557+	    ((tvar) = CIRCLEQ_NEXT(var, field), 1);			\
558+	    (var) = (tvar))
559+
560+#define CIRCLEQ_FOREACH_REVERSE(var, head, field)			\
561+	for((var) = CIRCLEQ_LAST(head);					\
562+	    (var) != CIRCLEQ_END(head);					\
563+	    (var) = CIRCLEQ_PREV(var, field))
564+
565+#define	CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
566+	for ((var) = CIRCLEQ_LAST(head, headname);			\
567+	    (var) != CIRCLEQ_END(head) && 				\
568+	    ((tvar) = CIRCLEQ_PREV(var, headname, field), 1);		\
569+	    (var) = (tvar))
570+
571+/*
572+ * Circular queue functions.
573+ */
574+#define	CIRCLEQ_INIT(head) do {						\
575+	(head)->cqh_first = CIRCLEQ_END(head);				\
576+	(head)->cqh_last = CIRCLEQ_END(head);				\
577+} while (0)
578+
579+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
580+	(elm)->field.cqe_next = (listelm)->field.cqe_next;		\
581+	(elm)->field.cqe_prev = (listelm);				\
582+	if ((listelm)->field.cqe_next == CIRCLEQ_END(head))		\
583+		(head)->cqh_last = (elm);				\
584+	else								\
585+		(listelm)->field.cqe_next->field.cqe_prev = (elm);	\
586+	(listelm)->field.cqe_next = (elm);				\
587+} while (0)
588+
589+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {		\
590+	(elm)->field.cqe_next = (listelm);				\
591+	(elm)->field.cqe_prev = (listelm)->field.cqe_prev;		\
592+	if ((listelm)->field.cqe_prev == CIRCLEQ_END(head))		\
593+		(head)->cqh_first = (elm);				\
594+	else								\
595+		(listelm)->field.cqe_prev->field.cqe_next = (elm);	\
596+	(listelm)->field.cqe_prev = (elm);				\
597+} while (0)
598+
599+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {			\
600+	(elm)->field.cqe_next = (head)->cqh_first;			\
601+	(elm)->field.cqe_prev = CIRCLEQ_END(head);			\
602+	if ((head)->cqh_last == CIRCLEQ_END(head))			\
603+		(head)->cqh_last = (elm);				\
604+	else								\
605+		(head)->cqh_first->field.cqe_prev = (elm);		\
606+	(head)->cqh_first = (elm);					\
607+} while (0)
608+
609+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {			\
610+	(elm)->field.cqe_next = CIRCLEQ_END(head);			\
611+	(elm)->field.cqe_prev = (head)->cqh_last;			\
612+	if ((head)->cqh_first == CIRCLEQ_END(head))			\
613+		(head)->cqh_first = (elm);				\
614+	else								\
615+		(head)->cqh_last->field.cqe_next = (elm);		\
616+	(head)->cqh_last = (elm);					\
617+} while (0)
618+
619+#define	CIRCLEQ_REMOVE(head, elm, field) do {				\
620+	if ((elm)->field.cqe_next == CIRCLEQ_END(head))			\
621+		(head)->cqh_last = (elm)->field.cqe_prev;		\
622+	else								\
623+		(elm)->field.cqe_next->field.cqe_prev =			\
624+		    (elm)->field.cqe_prev;				\
625+	if ((elm)->field.cqe_prev == CIRCLEQ_END(head))			\
626+		(head)->cqh_first = (elm)->field.cqe_next;		\
627+	else								\
628+		(elm)->field.cqe_prev->field.cqe_next =			\
629+		    (elm)->field.cqe_next;				\
630+	_Q_INVALIDATE((elm)->field.cqe_prev);				\
631+	_Q_INVALIDATE((elm)->field.cqe_next);				\
632+} while (0)
633+
634+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do {			\
635+	if (((elm2)->field.cqe_next = (elm)->field.cqe_next) ==		\
636+	    CIRCLEQ_END(head))						\
637+		(head)->cqh_last = (elm2);				\
638+	else								\
639+		(elm2)->field.cqe_next->field.cqe_prev = (elm2);	\
640+	if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) ==		\
641+	    CIRCLEQ_END(head))						\
642+		(head)->cqh_first = (elm2);				\
643+	else								\
644+		(elm2)->field.cqe_prev->field.cqe_next = (elm2);	\
645+	_Q_INVALIDATE((elm)->field.cqe_prev);				\
646+	_Q_INVALIDATE((elm)->field.cqe_next);				\
647+} while (0)
648+
649+#endif	/* !_SYS_QUEUE_H_ */
+32, -0
 1@@ -0,0 +1,32 @@
 2+/*
 3+ * Magic values required to use _reboot() system call.
 4+ */
 5+
 6+#define	LINUX_REBOOT_MAGIC1	0xfee1dead
 7+#define	LINUX_REBOOT_MAGIC2	672274793
 8+#define	LINUX_REBOOT_MAGIC2A	85072278
 9+#define	LINUX_REBOOT_MAGIC2B	369367448
10+#define	LINUX_REBOOT_MAGIC2C	537993216
11+
12+
13+/*
14+ * Commands accepted by the _reboot() system call.
15+ *
16+ * RESTART     Restart system using default command and mode.
17+ * HALT        Stop OS and give system control to ROM monitor, if any.
18+ * CAD_ON      Ctrl-Alt-Del sequence causes RESTART command.
19+ * CAD_OFF     Ctrl-Alt-Del sequence sends SIGINT to init task.
20+ * POWER_OFF   Stop OS and remove all power from system, if possible.
21+ * RESTART2    Restart system using given command string.
22+ * SW_SUSPEND  Suspend system using software suspend if compiled in.
23+ * KEXEC       Restart system using a previously loaded Linux kernel
24+ */
25+
26+#define	LINUX_REBOOT_CMD_RESTART	0x01234567
27+#define	LINUX_REBOOT_CMD_HALT		0xCDEF0123
28+#define	LINUX_REBOOT_CMD_CAD_ON		0x89ABCDEF
29+#define	LINUX_REBOOT_CMD_CAD_OFF	0x00000000
30+#define	LINUX_REBOOT_CMD_POWER_OFF	0x4321FEDC
31+#define	LINUX_REBOOT_CMD_RESTART2	0xA1B2C3D4
32+#define	LINUX_REBOOT_CMD_SW_SUSPEND	0xD000FCE2
33+#define	LINUX_REBOOT_CMD_KEXEC		0x45584543
+20, -0
 1@@ -0,0 +1,20 @@
 2+/*
 3+ * The struct used to pass data via the following ioctl. Similar to the
 4+ * struct tm in <time.h>, but it needs to be here so that the kernel
 5+ * source is self contained, allowing cross-compiles, etc. etc.
 6+ */
 7+
 8+struct rtc_time {
 9+	int tm_sec;
10+	int tm_min;
11+	int tm_hour;
12+	int tm_mday;
13+	int tm_mon;
14+	int tm_year;
15+	int tm_wday;
16+	int tm_yday;
17+	int tm_isdst;
18+};
19+
20+#define RTC_RD_TIME	_IOR('p', 0x09, struct rtc_time) /* Read RTC time   */
21+#define RTC_SET_TIME	_IOW('p', 0x0a, struct rtc_time) /* Set RTC time    */
+18, -0
 1@@ -0,0 +1,18 @@
 2+/* public domain sha1 implementation based on rfc3174 and libtomcrypt */
 3+
 4+struct sha1 {
 5+	uint64_t len;    /* processed message length */
 6+	uint32_t h[5];   /* hash state */
 7+	uint8_t buf[64]; /* message block buffer */
 8+};
 9+
10+enum { SHA1_DIGEST_LENGTH = 20 };
11+
12+/* reset state */
13+void sha1_init(void *ctx);
14+/* process message */
15+void sha1_update(void *ctx, const void *m, unsigned long len);
16+/* get message digest */
17+/* state is ruined after sum, keep a copy if multiple sum is needed */
18+/* part of the message might be left in s, zero it if secrecy is needed */
19+void sha1_sum(void *ctx, uint8_t md[SHA1_DIGEST_LENGTH]);
+16, -0
 1@@ -0,0 +1,16 @@
 2+/* public domain sha224 implementation based on fips180-3 */
 3+
 4+#include "sha256.h"
 5+
 6+#define sha224  sha256  /*struct*/
 7+
 8+enum { SHA224_DIGEST_LENGTH = 28 };
 9+
10+/* reset state */
11+void sha224_init(void *ctx);
12+/* process message */
13+#define sha224_update  sha256_update
14+/* get message digest */
15+/* state is ruined after sum, keep a copy if multiple sum is needed */
16+/* part of the message might be left in s, zero it if secrecy is needed */
17+void sha224_sum(void *ctx, uint8_t md[SHA224_DIGEST_LENGTH]);
+18, -0
 1@@ -0,0 +1,18 @@
 2+/* public domain sha256 implementation based on fips180-3 */
 3+
 4+struct sha256 {
 5+	uint64_t len;    /* processed message length */
 6+	uint32_t h[8];   /* hash state */
 7+	uint8_t buf[64]; /* message block buffer */
 8+};
 9+
10+enum { SHA256_DIGEST_LENGTH = 32 };
11+
12+/* reset state */
13+void sha256_init(void *ctx);
14+/* process message */
15+void sha256_update(void *ctx, const void *m, unsigned long len);
16+/* get message digest */
17+/* state is ruined after sum, keep a copy if multiple sum is needed */
18+/* part of the message might be left in s, zero it if secrecy is needed */
19+void sha256_sum(void *ctx, uint8_t md[SHA256_DIGEST_LENGTH]);
+16, -0
 1@@ -0,0 +1,16 @@
 2+/* public domain sha512 implementation based on fips180-3 */
 3+
 4+#include "sha512.h"
 5+
 6+#define sha384  sha512  /*struct*/
 7+
 8+enum { SHA384_DIGEST_LENGTH = 48 };
 9+
10+/* reset state */
11+void sha384_init(void *ctx);
12+/* process message */
13+#define sha384_update  sha512_update
14+/* get message digest */
15+/* state is ruined after sum, keep a copy if multiple sum is needed */
16+/* part of the message might be left in s, zero it if secrecy is needed */
17+void sha384_sum(void *ctx, uint8_t md[SHA384_DIGEST_LENGTH]);
+16, -0
 1@@ -0,0 +1,16 @@
 2+/* public domain sha512/224 implementation based on fips180-3 */
 3+
 4+#include "sha512.h"
 5+
 6+#define sha512_224  sha512  /*struct*/
 7+
 8+enum { SHA512_224_DIGEST_LENGTH = 28 };
 9+
10+/* reset state */
11+void sha512_224_init(void *ctx);
12+/* process message */
13+#define sha512_224_update  sha512_update
14+/* get message digest */
15+/* state is ruined after sum, keep a copy if multiple sum is needed */
16+/* part of the message might be left in s, zero it if secrecy is needed */
17+void sha512_224_sum(void *ctx, uint8_t md[SHA512_224_DIGEST_LENGTH]);
+16, -0
 1@@ -0,0 +1,16 @@
 2+/* public domain sha512/256 implementation based on fips180-3 */
 3+
 4+#include "sha512.h"
 5+
 6+#define sha512_256  sha512  /*struct*/
 7+
 8+enum { SHA512_256_DIGEST_LENGTH = 32 };
 9+
10+/* reset state */
11+void sha512_256_init(void *ctx);
12+/* process message */
13+#define sha512_256_update  sha512_update
14+/* get message digest */
15+/* state is ruined after sum, keep a copy if multiple sum is needed */
16+/* part of the message might be left in s, zero it if secrecy is needed */
17+void sha512_256_sum(void *ctx, uint8_t md[SHA512_256_DIGEST_LENGTH]);
+18, -0
 1@@ -0,0 +1,18 @@
 2+/* public domain sha512 implementation based on fips180-3 */
 3+
 4+struct sha512 {
 5+	uint64_t len;     /* processed message length */
 6+	uint64_t h[8];    /* hash state */
 7+	uint8_t buf[128]; /* message block buffer */
 8+};
 9+
10+enum { SHA512_DIGEST_LENGTH = 64 };
11+
12+/* reset state */
13+void sha512_init(void *ctx);
14+/* process message */
15+void sha512_update(void *ctx, const void *m, unsigned long len);
16+/* get message digest */
17+/* state is ruined after sum, keep a copy if multiple sum is needed */
18+/* part of the message might be left in s, zero it if secrecy is needed */
19+void sha512_sum(void *ctx, uint8_t md[SHA512_DIGEST_LENGTH]);
+19, -0
 1@@ -0,0 +1,19 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+struct line {
 5+	char *data;
 6+	size_t len;
 7+};
 8+
 9+struct linebuf {
10+	struct line *lines;
11+	size_t nlines;
12+	size_t capacity;
13+};
14+#define EMPTY_LINEBUF {NULL, 0, 0,}
15+void getlines(FILE *, struct linebuf *);
16+
17+int linecmp(struct line *, struct line *);
18+
19+ssize_t agetline(char **, size_t *, FILE *);
20+void fconcat(FILE *, const char *, FILE *, const char *);
+69, -0
 1@@ -0,0 +1,69 @@
 2+/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
 3+ *
 4+ * Permission is hereby granted, free of charge, to any person obtaining a
 5+ * copy of this software and associated documentation files (the "Software"),
 6+ * to deal in the Software without restriction, including without limitation
 7+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 8+ * and/or sell copies of the Software, and to permit persons to whom the
 9+ * Software is furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20+ * DEALINGS IN THE SOFTWARE.
21+ */
22+#include <stdio.h>
23+
24+typedef int Rune;
25+
26+enum {
27+	UTFmax    = 6,       /* maximum bytes per rune */
28+	Runeself  = 0x80,    /* rune and utf are equal (<) */
29+	Runeerror = 0xFFFD,  /* decoding error in utf */
30+	Runemax   = 0x10FFFF /* maximum rune value */
31+};
32+
33+int runetochar(char *, const Rune *);
34+int chartorune(Rune *, const char *);
35+int charntorune(Rune *, const char *, size_t);
36+int runelen(Rune);
37+size_t runenlen(const Rune *, size_t);
38+int fullrune(const char *, size_t);
39+char *utfecpy(char *, char *, const char *);
40+size_t utflen(const char *);
41+size_t utfnlen(const char *, size_t);
42+size_t utfmemlen(const char *, size_t);
43+char *utfrune(const char *, Rune);
44+char *utfrrune(const char *, Rune);
45+char *utfutf(const char *, const char *);
46+
47+int isalnumrune(Rune);
48+int isalpharune(Rune);
49+int isblankrune(Rune);
50+int iscntrlrune(Rune);
51+int isdigitrune(Rune);
52+int isgraphrune(Rune);
53+int islowerrune(Rune);
54+int isprintrune(Rune);
55+int ispunctrune(Rune);
56+int isspacerune(Rune);
57+int istitlerune(Rune);
58+int isupperrune(Rune);
59+int isxdigitrune(Rune);
60+
61+Rune tolowerrune(Rune);
62+Rune toupperrune(Rune);
63+
64+size_t utftorunestr(const char *, Rune *);
65+size_t utfntorunestr(const char *, size_t, Rune *);
66+
67+int fgetrune(Rune *, FILE *);
68+int efgetrune(Rune *, FILE *, const char *);
69+int fputrune(const Rune *, FILE *);
70+int efputrune(const Rune *, FILE *, const char *);
+108, -0
  1@@ -0,0 +1,108 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <sys/types.h>
  4+
  5+#include <regex.h>
  6+#include <stddef.h>
  7+#include <stdio.h>
  8+#include <stdarg.h>
  9+
 10+#include "arg.h"
 11+#include "compat.h"
 12+
 13+#define UTF8_POINT(c) (((c) & 0xc0) != 0x80)
 14+
 15+#undef MIN
 16+#define MIN(x,y)  ((x) < (y) ? (x) : (y))
 17+#undef MAX
 18+#define MAX(x,y)  ((x) > (y) ? (x) : (y))
 19+#undef LIMIT
 20+#define LIMIT(x, a, b)  (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
 21+
 22+#define LEN(x) (sizeof (x) / sizeof *(x))
 23+
 24+extern char *argv0;
 25+
 26+void *ecalloc(size_t, size_t);
 27+void *emalloc(size_t);
 28+void *erealloc(void *, size_t);
 29+#undef reallocarray
 30+void *reallocarray(void *, size_t, size_t);
 31+void *ereallocarray(void *, size_t, size_t);
 32+char *estrdup(const char *);
 33+char *estrndup(const char *, size_t);
 34+void *encalloc(int, size_t, size_t);
 35+void *enmalloc(int, size_t);
 36+void *enrealloc(int, void *, size_t);
 37+void *enreallocarray(int, void *, size_t, size_t);
 38+char *enstrdup(int, const char *);
 39+char *enstrndup(int, const char *, size_t);
 40+
 41+void enfshut(int, FILE *, const char *);
 42+void efshut(FILE *, const char *);
 43+int  fshut(FILE *, const char *);
 44+
 45+void enprintf(int, const char *, ...);
 46+void eprintf(const char *, ...);
 47+void weprintf(const char *, ...);
 48+void xvprintf(const char *, va_list);
 49+
 50+int confirm(const char*, ...);
 51+
 52+double estrtod(const char *);
 53+
 54+#undef strcasestr
 55+#define strcasestr xstrcasestr
 56+char *strcasestr(const char *, const char *);
 57+
 58+#undef strlcat
 59+#define strlcat xstrlcat
 60+size_t strlcat(char *, const char *, size_t);
 61+size_t estrlcat(char *, const char *, size_t);
 62+#undef strlcpy
 63+#define strlcpy xstrlcpy
 64+size_t strlcpy(char *, const char *, size_t);
 65+size_t estrlcpy(char *, const char *, size_t);
 66+
 67+#undef strsep
 68+#define strsep xstrsep
 69+char *strsep(char **, const char *);
 70+
 71+void strnsubst(char **, const char *, const char *, size_t);
 72+
 73+/* regex */
 74+int enregcomp(int, regex_t *, const char *, int);
 75+int eregcomp(regex_t *, const char *, int);
 76+
 77+/* io */
 78+ssize_t writeall(int, const void *, size_t);
 79+int concat(int, const char *, int, const char *);
 80+
 81+/* misc */
 82+void enmasse(int, char **, int (*)(const char *, const char *, int));
 83+void fnck(const char *, const char *, int (*)(const char *, const char *, int), int);
 84+mode_t getumask(void);
 85+char *humansize(off_t);
 86+mode_t parsemode(const char *, mode_t, mode_t);
 87+off_t parseoffset(const char *);
 88+void putword(FILE *, const char *);
 89+#undef strtonum
 90+#define strtonum xstrtonum
 91+long long strtonum(const char *, long long, long long, const char **);
 92+long long enstrtonum(int, const char *, long long, long long);
 93+long long estrtonum(const char *, long long, long long);
 94+size_t unescape(char *);
 95+int mkdirp(const char *, mode_t, mode_t);
 96+#undef memmem
 97+#define memmem xmemmem
 98+void *memmem(const void *, size_t, const void *, size_t);
 99+
100+/* ubase functions */
101+char *agetcwd(void);
102+void apathmax(char **, long *);
103+long estrtol(const char *, int);
104+unsigned long estrtoul(const char *, int);
105+#undef explicit_bzero
106+void explicit_bzero(void *, size_t);
107+void recurse_dir(const char *, void (*)(const char *));
108+void devtotty(int, int *, int *);
109+int ttytostr(int, int, char *, size_t);