mirror of
https://codeberg.org/libreboot/lbmk.git
synced 2026-07-18 14:12:44 +02:00
config/git: import suckless sbase
i currently use the output of sha512sum in several places of xbmk, which is a bit unreliable in case output changes. other cases where i use util outputs in variables are probably reliable, because i'm using mostly posix utilities in those. to mitigate this, i now import suckless sbase, which has a reasonable sha512sum implementation. *every* binary it builds is being placed in build.list, because i'll probably start using more of them. for example, i may start modifying the "date" implementation, adding the GNU-specific options that i need as mentioned on init.sh i'm importing it in util/ because the sha512sum util is needed for verifying project sources, so if sbase itself is a "project source", that means we can into a chicken and egg bootstrapping problem. this is sbase at revision: 055cc1ae1b3a13c3d8f25af0a4a3316590efcd48 Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
@@ -0,0 +1,103 @@
|
|||||||
|
*.o
|
||||||
|
/build
|
||||||
|
/getconf.h
|
||||||
|
/libutf.a
|
||||||
|
/libutil.a
|
||||||
|
/basename
|
||||||
|
/cal
|
||||||
|
/cat
|
||||||
|
/chgrp
|
||||||
|
/chmod
|
||||||
|
/chown
|
||||||
|
/chroot
|
||||||
|
/cksum
|
||||||
|
/cmp
|
||||||
|
/cols
|
||||||
|
/comm
|
||||||
|
/cp
|
||||||
|
/cron
|
||||||
|
/cut
|
||||||
|
/date
|
||||||
|
/dd
|
||||||
|
/dirname
|
||||||
|
/du
|
||||||
|
/echo
|
||||||
|
/ed
|
||||||
|
/env
|
||||||
|
/expand
|
||||||
|
/expr
|
||||||
|
/false
|
||||||
|
/find
|
||||||
|
/flock
|
||||||
|
/fold
|
||||||
|
/getconf
|
||||||
|
/grep
|
||||||
|
/head
|
||||||
|
/hostname
|
||||||
|
/join
|
||||||
|
/kill
|
||||||
|
/link
|
||||||
|
/ln
|
||||||
|
/logger
|
||||||
|
/logname
|
||||||
|
/ls
|
||||||
|
/md5sum
|
||||||
|
/mkdir
|
||||||
|
/mkfifo
|
||||||
|
/mknod
|
||||||
|
/mktemp
|
||||||
|
/mv
|
||||||
|
/nice
|
||||||
|
/nl
|
||||||
|
/nohup
|
||||||
|
/od
|
||||||
|
/paste
|
||||||
|
/pathchk
|
||||||
|
/printenv
|
||||||
|
/printf
|
||||||
|
/pwd
|
||||||
|
/readlink
|
||||||
|
/renice
|
||||||
|
/rev
|
||||||
|
/rm
|
||||||
|
/rmdir
|
||||||
|
/sbase-box
|
||||||
|
/sed
|
||||||
|
/seq
|
||||||
|
/setsid
|
||||||
|
/sha1sum
|
||||||
|
/sha224sum
|
||||||
|
/sha256sum
|
||||||
|
/sha384sum
|
||||||
|
/sha512sum
|
||||||
|
/sha512-224sum
|
||||||
|
/sha512-256sum
|
||||||
|
/sleep
|
||||||
|
/sort
|
||||||
|
/split
|
||||||
|
/sponge
|
||||||
|
/strings
|
||||||
|
/sync
|
||||||
|
/tail
|
||||||
|
/tar
|
||||||
|
/tee
|
||||||
|
/test
|
||||||
|
/tftp
|
||||||
|
/time
|
||||||
|
/touch
|
||||||
|
/tr
|
||||||
|
/true
|
||||||
|
/tsort
|
||||||
|
/tty
|
||||||
|
/uname
|
||||||
|
/unexpand
|
||||||
|
/uniq
|
||||||
|
/unlink
|
||||||
|
/uudecode
|
||||||
|
/uuencode
|
||||||
|
/wc
|
||||||
|
/which
|
||||||
|
/whoami
|
||||||
|
/xargs
|
||||||
|
/xinstall
|
||||||
|
/yes
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
© 2011 Connor Lane Smith <cls@lubutu.com>
|
||||||
|
© 2011-2016 Dimitris Papastamos <sin@2f30.org>
|
||||||
|
© 2014-2016 Laslo Hunhold <dev@frign.de>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
Authors/contributors include:
|
||||||
|
|
||||||
|
© 2011 Kamil Cholewiński <harry666t@gmail.com>
|
||||||
|
© 2011 Rob Pilling <robpilling@gmail.com>
|
||||||
|
© 2011 Hiltjo Posthuma <hiltjo@codemadness.org>
|
||||||
|
© 2011 pancake <pancake@youterm.com>
|
||||||
|
© 2011 Random832 <random832@fastmail.us>
|
||||||
|
© 2012 William Haddon <william@haddonthethird.net>
|
||||||
|
© 2012 Kurt H. Maier <khm@sciops.net>
|
||||||
|
© 2012 Christoph Lohmann <20h@r-36.net>
|
||||||
|
© 2012 David Galos <galosd83@students.rowan.edu>
|
||||||
|
© 2012 Robert Ransom <rransom.8774@gmail.com>
|
||||||
|
© 2013 Jakob Kramer <jakob.kramer@gmx.de>
|
||||||
|
© 2013 Anselm R Garbe <anselm@garbe.us>
|
||||||
|
© 2013 Truls Becken <truls.becken@gmail.com>
|
||||||
|
© 2013 dsp <dsp@2f30.org>
|
||||||
|
© 2013 Markus Teich <markus.teich@stusta.mhn.de>
|
||||||
|
© 2013 Jesse Ogle <jesse.p.ogle@gmail.com>
|
||||||
|
© 2013 Lorenzo Cogotti <miciamail@hotmail.it>
|
||||||
|
© 2013 Federico G. Benavento <benavento@gmail.com>
|
||||||
|
© 2013 Roberto E. Vargas Caballero <k0ga@shike2.com>
|
||||||
|
© 2013 Christian Hesse <mail@eworm.de>
|
||||||
|
© 2013 Markus Wichmann <nullplan@gmx.net>
|
||||||
|
© 2014 Silvan Jegen <s.jegen@gmail.com>
|
||||||
|
© 2014 Daniel Bainton <dpb@driftaway.org>
|
||||||
|
© 2014 Tuukka Kataja <stuge@xor.fi>
|
||||||
|
© 2014 Jeffrey Picard <jeff@jeffreypicard.com>
|
||||||
|
© 2014 Evan Gates <evan.gates@gmail.com>
|
||||||
|
© 2014 Michael Forney <mforney@mforney.org>
|
||||||
|
© 2014 Ari Malinen <ari.malinen@gmail.com>
|
||||||
|
© 2014 Brandon Mulcahy <brandon@jangler.info>
|
||||||
|
© 2014 Adria Garriga <rhaps0dy@installgentoo.com>
|
||||||
|
© 2014-2015 Greg Reagle <greg.reagle@umbc.edu>
|
||||||
|
© 2015 Tai Chi Minh Ralph Eastwood <tcmreastwood@gmail.com>
|
||||||
|
© 2015 Quentin Rameau <quinq@quinq.eu.org>
|
||||||
|
© 2015 Dionysis Grigoropoulos <info@erethon.com>
|
||||||
|
© 2015 Wolfgang Corcoran-Mathe <wcm@sigwinch.xyz>
|
||||||
|
© 2016 Mattias Andrée <maandree@kth.se>
|
||||||
|
© 2016 Eivind Uggedal <eivind@uggedal.com>
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
.POSIX:
|
||||||
|
include config.mk
|
||||||
|
|
||||||
|
.SUFFIXES:
|
||||||
|
.SUFFIXES: .o .c
|
||||||
|
|
||||||
|
CPPFLAGS =\
|
||||||
|
-D_DEFAULT_SOURCE \
|
||||||
|
-D_NETBSD_SOURCE \
|
||||||
|
-D_BSD_SOURCE \
|
||||||
|
-D_XOPEN_SOURCE=700 \
|
||||||
|
-D_FILE_OFFSET_BITS=64
|
||||||
|
|
||||||
|
HDR =\
|
||||||
|
arg.h\
|
||||||
|
compat.h\
|
||||||
|
crypt.h\
|
||||||
|
fs.h\
|
||||||
|
md5.h\
|
||||||
|
queue.h\
|
||||||
|
sha1.h\
|
||||||
|
sha224.h\
|
||||||
|
sha256.h\
|
||||||
|
sha384.h\
|
||||||
|
sha512.h\
|
||||||
|
sha512-224.h\
|
||||||
|
sha512-256.h\
|
||||||
|
text.h\
|
||||||
|
utf.h\
|
||||||
|
util.h
|
||||||
|
|
||||||
|
LIBUTFOBJ =\
|
||||||
|
libutf/fgetrune.o\
|
||||||
|
libutf/fputrune.o\
|
||||||
|
libutf/isalnumrune.o\
|
||||||
|
libutf/isalpharune.o\
|
||||||
|
libutf/isblankrune.o\
|
||||||
|
libutf/iscntrlrune.o\
|
||||||
|
libutf/isdigitrune.o\
|
||||||
|
libutf/isgraphrune.o\
|
||||||
|
libutf/isprintrune.o\
|
||||||
|
libutf/ispunctrune.o\
|
||||||
|
libutf/isspacerune.o\
|
||||||
|
libutf/istitlerune.o\
|
||||||
|
libutf/isxdigitrune.o\
|
||||||
|
libutf/lowerrune.o\
|
||||||
|
libutf/rune.o\
|
||||||
|
libutf/runetype.o\
|
||||||
|
libutf/upperrune.o\
|
||||||
|
libutf/utf.o\
|
||||||
|
libutf/utftorunestr.o
|
||||||
|
|
||||||
|
LIBUTILOBJ =\
|
||||||
|
libutil/concat.o\
|
||||||
|
libutil/cp.o\
|
||||||
|
libutil/crypt.o\
|
||||||
|
libutil/confirm.o\
|
||||||
|
libutil/ealloc.o\
|
||||||
|
libutil/enmasse.o\
|
||||||
|
libutil/eprintf.o\
|
||||||
|
libutil/eregcomp.o\
|
||||||
|
libutil/estrtod.o\
|
||||||
|
libutil/fnck.o\
|
||||||
|
libutil/fshut.o\
|
||||||
|
libutil/getlines.o\
|
||||||
|
libutil/human.o\
|
||||||
|
libutil/linecmp.o\
|
||||||
|
libutil/md5.o\
|
||||||
|
libutil/memmem.o\
|
||||||
|
libutil/mkdirp.o\
|
||||||
|
libutil/mode.o\
|
||||||
|
libutil/parseoffset.o\
|
||||||
|
libutil/putword.o\
|
||||||
|
libutil/reallocarray.o\
|
||||||
|
libutil/recurse.o\
|
||||||
|
libutil/rm.o\
|
||||||
|
libutil/sha1.o\
|
||||||
|
libutil/sha224.o\
|
||||||
|
libutil/sha256.o\
|
||||||
|
libutil/sha384.o\
|
||||||
|
libutil/sha512.o\
|
||||||
|
libutil/sha512-224.o\
|
||||||
|
libutil/sha512-256.o\
|
||||||
|
libutil/strcasestr.o\
|
||||||
|
libutil/strlcat.o\
|
||||||
|
libutil/strlcpy.o\
|
||||||
|
libutil/strsep.o\
|
||||||
|
libutil/strnsubst.o\
|
||||||
|
libutil/strtonum.o\
|
||||||
|
libutil/unescape.o\
|
||||||
|
libutil/writeall.o
|
||||||
|
|
||||||
|
LIB = libutf.a libutil.a
|
||||||
|
|
||||||
|
BIN =\
|
||||||
|
basename\
|
||||||
|
cal\
|
||||||
|
cat\
|
||||||
|
chgrp\
|
||||||
|
chmod\
|
||||||
|
chown\
|
||||||
|
chroot\
|
||||||
|
cksum\
|
||||||
|
cmp\
|
||||||
|
cols\
|
||||||
|
comm\
|
||||||
|
cp\
|
||||||
|
cron\
|
||||||
|
cut\
|
||||||
|
date\
|
||||||
|
dd\
|
||||||
|
dirname\
|
||||||
|
du\
|
||||||
|
echo\
|
||||||
|
ed\
|
||||||
|
env\
|
||||||
|
expand\
|
||||||
|
expr\
|
||||||
|
false\
|
||||||
|
find\
|
||||||
|
flock\
|
||||||
|
fold\
|
||||||
|
getconf\
|
||||||
|
grep\
|
||||||
|
head\
|
||||||
|
hostname\
|
||||||
|
join\
|
||||||
|
kill\
|
||||||
|
link\
|
||||||
|
ln\
|
||||||
|
logger\
|
||||||
|
logname\
|
||||||
|
ls\
|
||||||
|
md5sum\
|
||||||
|
mkdir\
|
||||||
|
mkfifo\
|
||||||
|
mknod\
|
||||||
|
mktemp\
|
||||||
|
mv\
|
||||||
|
nice\
|
||||||
|
nl\
|
||||||
|
nohup\
|
||||||
|
od\
|
||||||
|
paste\
|
||||||
|
pathchk\
|
||||||
|
printenv\
|
||||||
|
printf\
|
||||||
|
pwd\
|
||||||
|
readlink\
|
||||||
|
renice\
|
||||||
|
rev\
|
||||||
|
rm\
|
||||||
|
rmdir\
|
||||||
|
sed\
|
||||||
|
seq\
|
||||||
|
setsid\
|
||||||
|
sha1sum\
|
||||||
|
sha224sum\
|
||||||
|
sha256sum\
|
||||||
|
sha384sum\
|
||||||
|
sha512sum\
|
||||||
|
sha512-224sum\
|
||||||
|
sha512-256sum\
|
||||||
|
sleep\
|
||||||
|
sort\
|
||||||
|
split\
|
||||||
|
sponge\
|
||||||
|
strings\
|
||||||
|
sync\
|
||||||
|
tail\
|
||||||
|
tar\
|
||||||
|
tee\
|
||||||
|
test\
|
||||||
|
tftp\
|
||||||
|
time\
|
||||||
|
touch\
|
||||||
|
tr\
|
||||||
|
true\
|
||||||
|
tsort\
|
||||||
|
tty\
|
||||||
|
uname\
|
||||||
|
unexpand\
|
||||||
|
uniq\
|
||||||
|
unlink\
|
||||||
|
uudecode\
|
||||||
|
uuencode\
|
||||||
|
wc\
|
||||||
|
which\
|
||||||
|
whoami\
|
||||||
|
xargs\
|
||||||
|
xinstall\
|
||||||
|
yes
|
||||||
|
|
||||||
|
OBJ = $(LIBUTFOBJ) $(LIBUTILOBJ)
|
||||||
|
|
||||||
|
all: $(BIN)
|
||||||
|
|
||||||
|
$(BIN): $(LIB)
|
||||||
|
|
||||||
|
$(OBJ) $(BIN): $(HDR)
|
||||||
|
|
||||||
|
.o:
|
||||||
|
$(CC) $(LDFLAGS) -o $@ $< $(LIB)
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
|
.c:
|
||||||
|
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< $(LIB)
|
||||||
|
|
||||||
|
libutf.a: $(LIBUTFOBJ)
|
||||||
|
$(AR) $(ARFLAGS) $@ $?
|
||||||
|
$(RANLIB) $@
|
||||||
|
|
||||||
|
libutil.a: $(LIBUTILOBJ)
|
||||||
|
$(AR) $(ARFLAGS) $@ $?
|
||||||
|
$(RANLIB) $@
|
||||||
|
|
||||||
|
getconf: getconf.h
|
||||||
|
|
||||||
|
getconf.h:
|
||||||
|
scripts/getconf.sh > $@
|
||||||
|
|
||||||
|
proto: $(BIN)
|
||||||
|
scripts/mkproto $(DESTDIR)$(PREFIX) $(DESTDIR)$(MANPREFIX) proto
|
||||||
|
|
||||||
|
install uninstall: proto
|
||||||
|
scripts/$@ proto
|
||||||
|
|
||||||
|
sbase-box-install: sbase-box proto
|
||||||
|
scripts/install proto
|
||||||
|
$(DESTDIR)$(PREFIX)/bin/sbase-box -i $(DESTDIR)$(PREFIX)/bin/
|
||||||
|
|
||||||
|
sbase-box-uninstall: sbase-box proto
|
||||||
|
$(DESTDIR)$(PREFIX)/bin/sbase-box -d $(DESTDIR)$(PREFIX)/bin/
|
||||||
|
scripts/uninstall proto
|
||||||
|
|
||||||
|
dist: clean
|
||||||
|
mkdir -p sbase
|
||||||
|
cp -R LICENSE Makefile README TODO config.mk *.c *.1 *.h libutf libutil sbase
|
||||||
|
mv sbase sbase-$(VERSION)
|
||||||
|
tar -cf sbase-$(VERSION).tar sbase-$(VERSION)
|
||||||
|
gzip sbase-$(VERSION).tar
|
||||||
|
rm -rf sbase-$(VERSION)
|
||||||
|
|
||||||
|
sbase-box: $(BIN)
|
||||||
|
scripts/mkbox
|
||||||
|
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ build/*.c $(LIB)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(BIN) $(OBJ) $(LIB) sbase-box sbase-$(VERSION).tar.gz
|
||||||
|
rm -f getconf.h
|
||||||
|
rm -f proto
|
||||||
|
rm -rf build
|
||||||
|
|
||||||
|
.PHONY: all install uninstall dist sbase-box-install sbase-box-uninstall clean
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
sbase - suckless unix tools
|
||||||
|
===========================
|
||||||
|
|
||||||
|
sbase is a collection of unix tools that are inherently portable across
|
||||||
|
UNIX and UNIX-like systems.
|
||||||
|
|
||||||
|
The complement of sbase is ubase[1] which is Linux-specific and provides
|
||||||
|
all the non-portable tools. Together they are intended to form a base
|
||||||
|
system similar to busybox but much smaller and suckless.
|
||||||
|
|
||||||
|
Building
|
||||||
|
--------
|
||||||
|
|
||||||
|
To build sbase, simply type make. You may have to fiddle with config.mk
|
||||||
|
depending on your system.
|
||||||
|
|
||||||
|
You can also build sbase-box, which generates a single binary containing
|
||||||
|
all the required tools. You can then symlink the individual tools to
|
||||||
|
sbase-box or run: make sbase-box-install
|
||||||
|
|
||||||
|
To run the tools for sbase-box directly use: sbase-box cmd [args]
|
||||||
|
|
||||||
|
Ideally you will want to statically link sbase. If you are on Linux we
|
||||||
|
recommend using musl-libc[2].
|
||||||
|
|
||||||
|
Portability
|
||||||
|
-----------
|
||||||
|
|
||||||
|
sbase has been compiled on a variety of different operating systems,
|
||||||
|
including Linux, *BSD, OSX, Haiku, Solaris, SCO OpenServer and others.
|
||||||
|
|
||||||
|
Various combinations of operating systems and architectures have also
|
||||||
|
been built.
|
||||||
|
|
||||||
|
You can build sbase with gcc, clang, tcc, nwcc and pcc.
|
||||||
|
|
||||||
|
Status
|
||||||
|
------
|
||||||
|
|
||||||
|
The following tools are implemented:
|
||||||
|
|
||||||
|
'#' -> UTF-8 support, '=' -> Implicit UTF-8 support, '*' -> Finished,
|
||||||
|
'|' -> Audited, 'o' -> POSIX 2013 compliant, 'x' -> Non-POSIX,
|
||||||
|
'0' -> NUL handling, '()' -> Petty flag
|
||||||
|
|
||||||
|
UTILITY MISSING
|
||||||
|
------- -------
|
||||||
|
0=*|o basename .
|
||||||
|
0=*|o cal .
|
||||||
|
0=*|o cat .
|
||||||
|
0=*|o chgrp .
|
||||||
|
0=*|o chmod .
|
||||||
|
0=*|o chown .
|
||||||
|
0=*|x chroot .
|
||||||
|
0=*|o cksum .
|
||||||
|
0=*|o cmp .
|
||||||
|
0#*|x cols .
|
||||||
|
0=*|o comm .
|
||||||
|
0=*|o cp .
|
||||||
|
0=*|x cron .
|
||||||
|
0#*|o cut .
|
||||||
|
0=*|o date .
|
||||||
|
0=*|o dd .
|
||||||
|
0=*|o dirname .
|
||||||
|
0=*|o du .
|
||||||
|
0=*|o echo .
|
||||||
|
o ed .
|
||||||
|
0=*|o env .
|
||||||
|
0#*|o expand .
|
||||||
|
0#*|o expr .
|
||||||
|
0=*|o false .
|
||||||
|
0= find .
|
||||||
|
0=* x flock .
|
||||||
|
0#*|o fold .
|
||||||
|
0=*|o getconf (-v)
|
||||||
|
=*|o grep .
|
||||||
|
0=*|o head .
|
||||||
|
0=*|x hostname .
|
||||||
|
0=*|x install .
|
||||||
|
0=* o join .
|
||||||
|
0=*|o kill .
|
||||||
|
0=*|o link .
|
||||||
|
0=*|o ln .
|
||||||
|
0=*|o logger .
|
||||||
|
0=*|o logname .
|
||||||
|
0#* o ls (-C, -k, -m, -p, -s, -x)
|
||||||
|
0=*|x md5sum .
|
||||||
|
0=*|o mkdir .
|
||||||
|
0=*|o mkfifo .
|
||||||
|
0=*|x mknod .
|
||||||
|
0=*|x mktemp .
|
||||||
|
0=*|o mv (-i)
|
||||||
|
0=*|o nice .
|
||||||
|
0#*|o nl .
|
||||||
|
0=*|o nohup .
|
||||||
|
0=*|o od .
|
||||||
|
#*|o paste .
|
||||||
|
0#* o pathchk .
|
||||||
|
0=*|x printenv .
|
||||||
|
0#*|o printf .
|
||||||
|
0=*|o pwd .
|
||||||
|
0=*|x readlink .
|
||||||
|
0=*|o renice .
|
||||||
|
0#* x rev .
|
||||||
|
0=*|o rm .
|
||||||
|
0=*|o rmdir .
|
||||||
|
# sed .
|
||||||
|
0=*|x seq .
|
||||||
|
0=*|x setsid .
|
||||||
|
0=*|x sha1sum .
|
||||||
|
0=* x sha224sum .
|
||||||
|
0=*|x sha256sum .
|
||||||
|
0=* x sha384sum .
|
||||||
|
0=*|x sha512sum .
|
||||||
|
0=* x sha512-224sum .
|
||||||
|
0=* x sha512-256sum .
|
||||||
|
0=*|o sleep .
|
||||||
|
0#*|o sort .
|
||||||
|
0=*|o split .
|
||||||
|
0=*|x sponge .
|
||||||
|
0#*|o strings .
|
||||||
|
0=*|x sync .
|
||||||
|
0=*|o tail .
|
||||||
|
0=*|x tar .
|
||||||
|
0=*|o tee .
|
||||||
|
0=*|o test .
|
||||||
|
0=*|x tftp .
|
||||||
|
0=*|o time .
|
||||||
|
0=*|o touch .
|
||||||
|
0#*|o tr .
|
||||||
|
0=*|o true .
|
||||||
|
0=* o tsort .
|
||||||
|
0=*|o tty .
|
||||||
|
0=*|o uname .
|
||||||
|
0#*|o unexpand .
|
||||||
|
0=*|o uniq .
|
||||||
|
0=*|o unlink .
|
||||||
|
0=*|o uudecode .
|
||||||
|
0=*|o uuencode .
|
||||||
|
0#*|o wc .
|
||||||
|
0=*|x which .
|
||||||
|
0=*|x whoami .
|
||||||
|
0=*|o xargs .
|
||||||
|
0=*|x yes .
|
||||||
|
|
||||||
|
[1] http://git.suckless.org/ubase/
|
||||||
|
[2] http://www.musl-libc.org/
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
The following list of commands is taken from the toybox roadmap[0] and
|
||||||
|
has been stripped down accordingly. Commands that belong to ubase[1]
|
||||||
|
are not listed here as well as commands that fall outside the scope of
|
||||||
|
sbase such as vi and sh are also not listed here.
|
||||||
|
|
||||||
|
at
|
||||||
|
awk
|
||||||
|
bc
|
||||||
|
diff
|
||||||
|
patch
|
||||||
|
stty
|
||||||
|
|
||||||
|
If you are looking for some work to do on sbase, another option is to
|
||||||
|
pick a utility from the list in the README which has missing flags or
|
||||||
|
features noted.
|
||||||
|
|
||||||
|
What also needs to be implemented is the capability of the tools to
|
||||||
|
handle data with NUL-bytes in it.
|
||||||
|
|
||||||
|
The return values of mdcheckline() in crypt.c need to be fixed (0 -> success,
|
||||||
|
1 -> error).
|
||||||
|
|
||||||
|
[0] http://landley.net/toybox/roadmap.html
|
||||||
|
[1] http://git.suckless.org/ubase/
|
||||||
|
|
||||||
|
Bugs
|
||||||
|
====
|
||||||
|
|
||||||
|
ed
|
||||||
|
--
|
||||||
|
* cat <<EOF | ed
|
||||||
|
i
|
||||||
|
LLL
|
||||||
|
.
|
||||||
|
s/$/\\
|
||||||
|
|
||||||
|
* cat <<EOF | ed
|
||||||
|
0a
|
||||||
|
int radix = 16;
|
||||||
|
int Pflag;
|
||||||
|
int Aflag;
|
||||||
|
int vflag;
|
||||||
|
int gflag;
|
||||||
|
int uflag;
|
||||||
|
int arflag;
|
||||||
|
|
||||||
|
.
|
||||||
|
?radix?;/^$/-s/^/static /
|
||||||
|
* cat <<EOF | ed
|
||||||
|
0a
|
||||||
|
Line
|
||||||
|
.
|
||||||
|
s# *##
|
||||||
|
* cat <<EOF | ed
|
||||||
|
0a
|
||||||
|
line
|
||||||
|
.
|
||||||
|
1g/^$/p
|
||||||
|
|
||||||
|
* cat <<EOF | ed
|
||||||
|
0a
|
||||||
|
line1
|
||||||
|
line2
|
||||||
|
line3
|
||||||
|
.
|
||||||
|
g/^$/d
|
||||||
|
,p
|
||||||
|
|
||||||
|
* Editing huge files doesn't work well.
|
||||||
|
|
||||||
|
|
||||||
|
printf
|
||||||
|
------
|
||||||
|
* Flags for string conversion-specifier (%s) are not supported.
|
||||||
|
* Escape sequences that expand to '%' are treated as beginning of
|
||||||
|
conversion specification.
|
||||||
|
* An trailing '%' at the end of a format string causes a read past
|
||||||
|
the end of the string.
|
||||||
|
|
||||||
|
tr
|
||||||
|
--
|
||||||
|
* When a character class is present, all other characters in the
|
||||||
|
string are ignored.
|
||||||
|
|
||||||
|
sbase-box
|
||||||
|
---------
|
||||||
|
* List of commands does not contain `install` (only `xinstall`).
|
||||||
|
|
||||||
|
|
||||||
|
xargs
|
||||||
|
-----
|
||||||
|
* Add -L.
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copy me if you can.
|
||||||
|
* by 20h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ARG_H__
|
||||||
|
#define ARG_H__
|
||||||
|
|
||||||
|
extern char *argv0;
|
||||||
|
|
||||||
|
/* use main(int argc, char *argv[]) */
|
||||||
|
#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
|
||||||
|
argv[0] && argv[0][0] == '-'\
|
||||||
|
&& argv[0][1];\
|
||||||
|
argc--, argv++) {\
|
||||||
|
char argc_;\
|
||||||
|
char **argv_;\
|
||||||
|
int brk_;\
|
||||||
|
if (argv[0][1] == '-' && argv[0][2] == '\0') {\
|
||||||
|
argv++;\
|
||||||
|
argc--;\
|
||||||
|
break;\
|
||||||
|
}\
|
||||||
|
for (brk_ = 0, argv[0]++, argv_ = argv;\
|
||||||
|
argv[0][0] && !brk_;\
|
||||||
|
argv[0]++) {\
|
||||||
|
if (argv_ != argv)\
|
||||||
|
break;\
|
||||||
|
argc_ = argv[0][0];\
|
||||||
|
switch (argc_)
|
||||||
|
|
||||||
|
/* Handles obsolete -NUM syntax */
|
||||||
|
#define ARGNUM case '0':\
|
||||||
|
case '1':\
|
||||||
|
case '2':\
|
||||||
|
case '3':\
|
||||||
|
case '4':\
|
||||||
|
case '5':\
|
||||||
|
case '6':\
|
||||||
|
case '7':\
|
||||||
|
case '8':\
|
||||||
|
case '9'
|
||||||
|
|
||||||
|
#define ARGEND }\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ARGC() argc_
|
||||||
|
|
||||||
|
#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX))
|
||||||
|
|
||||||
|
#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
|
||||||
|
((x), abort(), (char *)0) :\
|
||||||
|
(brk_ = 1, (argv[0][1] != '\0')?\
|
||||||
|
(&argv[0][1]) :\
|
||||||
|
(argc--, argv++, argv[0])))
|
||||||
|
|
||||||
|
#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
|
||||||
|
(char *)0 :\
|
||||||
|
(brk_ = 1, (argv[0][1] != '\0')?\
|
||||||
|
(&argv[0][1]) :\
|
||||||
|
(argc--, argv++, argv[0])))
|
||||||
|
|
||||||
|
#define LNGARG() &argv[0][0]
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt BASENAME 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm basename
|
||||||
|
.Nd strip leading directory components of a path
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Ar path
|
||||||
|
.Op Ar suffix
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
writes
|
||||||
|
.Ar path
|
||||||
|
without leading directory components and
|
||||||
|
.Ar suffix
|
||||||
|
to stdout.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr dirname 1 ,
|
||||||
|
.Xr basename 3
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s path [suffix]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
ssize_t off;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (argc != 1 && argc != 2)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
p = basename(argv[0]);
|
||||||
|
if (argc == 2) {
|
||||||
|
off = strlen(p) - strlen(argv[1]);
|
||||||
|
if (off > 0 && !strcmp(p + off, argv[1]))
|
||||||
|
p[off] = '\0';
|
||||||
|
}
|
||||||
|
puts(p);
|
||||||
|
|
||||||
|
return fshut(stdout, "<stdout>");
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt CAL 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm cal
|
||||||
|
.Nd show calendar
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl 1 | Fl 3 | Fl y | Fl n Ar num
|
||||||
|
.Op Fl s | Fl m | Fl f Ar num
|
||||||
|
.Op Fl c Ar num
|
||||||
|
.Oo Oo Ar month Oc Ar year Oc
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
writes a calendar of
|
||||||
|
.Ar month
|
||||||
|
and
|
||||||
|
.Ar year
|
||||||
|
or the current month to stdout.
|
||||||
|
If
|
||||||
|
.Ar year
|
||||||
|
is given without
|
||||||
|
.Ar month ,
|
||||||
|
.Nm
|
||||||
|
writes a 3-column calendar of the whole
|
||||||
|
year to stdout.
|
||||||
|
The date formatting is according to
|
||||||
|
.Xr localtime 3 .
|
||||||
|
.Pp
|
||||||
|
The Julian calendar is used until Sep 2, 1752.
|
||||||
|
The Gregorian calendar is used starting the next day on Sep 14, 1752.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl 1
|
||||||
|
Print current month.
|
||||||
|
This is the default.
|
||||||
|
.It Fl 3
|
||||||
|
Print previous, current and next month.
|
||||||
|
.It Fl c Ar num
|
||||||
|
Print
|
||||||
|
.Ar num
|
||||||
|
calendars in a row.
|
||||||
|
The default is 3.
|
||||||
|
.It Fl f Ar num
|
||||||
|
Set
|
||||||
|
.Ar num
|
||||||
|
(0 is Sunday, 6 is Saturday) as first day of week.
|
||||||
|
.It Fl m
|
||||||
|
Set Monday as first day of week.
|
||||||
|
.It Fl n Ar num
|
||||||
|
Output
|
||||||
|
.Ar num
|
||||||
|
months starting from and including the current month.
|
||||||
|
.It Fl s
|
||||||
|
Set Sunday as first day of week.
|
||||||
|
.It Fl y
|
||||||
|
Print the entire
|
||||||
|
.Ar year
|
||||||
|
or current year.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr localtime 3
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The flags
|
||||||
|
.Op Fl 13cfmnsy
|
||||||
|
are an extension to that specification.
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
enum { JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };
|
||||||
|
enum caltype { JULIAN, GREGORIAN };
|
||||||
|
enum { TRANS_YEAR = 1752, TRANS_MONTH = SEP, TRANS_DAY = 2 };
|
||||||
|
|
||||||
|
static struct tm *ltime;
|
||||||
|
|
||||||
|
static int
|
||||||
|
isleap(size_t year, enum caltype cal)
|
||||||
|
{
|
||||||
|
if (cal == GREGORIAN) {
|
||||||
|
if (year % 400 == 0)
|
||||||
|
return 1;
|
||||||
|
if (year % 100 == 0)
|
||||||
|
return 0;
|
||||||
|
return (year % 4 == 0);
|
||||||
|
}
|
||||||
|
else { /* cal == Julian */
|
||||||
|
return (year % 4 == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
monthlength(size_t year, int month, enum caltype cal)
|
||||||
|
{
|
||||||
|
int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||||
|
|
||||||
|
return (month == FEB && isleap(year, cal)) ? 29 : mdays[month];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* From http://www.tondering.dk/claus/cal/chrweek.php#calcdow */
|
||||||
|
static int
|
||||||
|
dayofweek(size_t year, int month, int dom, enum caltype cal)
|
||||||
|
{
|
||||||
|
size_t y;
|
||||||
|
int m, a;
|
||||||
|
|
||||||
|
a = (13 - month) / 12;
|
||||||
|
y = year - a;
|
||||||
|
m = month + 12 * a - 1;
|
||||||
|
|
||||||
|
if (cal == GREGORIAN)
|
||||||
|
return (dom + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12) % 7;
|
||||||
|
else /* cal == Julian */
|
||||||
|
return (5 + dom + y + y / 4 + (31 * m) / 12) % 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printgrid(size_t year, int month, int fday, int line)
|
||||||
|
{
|
||||||
|
enum caltype cal;
|
||||||
|
int offset, dom, d = 0, trans; /* are we in the transition from Julian to Gregorian? */
|
||||||
|
int today = 0;
|
||||||
|
|
||||||
|
cal = (year < TRANS_YEAR || (year == TRANS_YEAR && month <= TRANS_MONTH)) ? JULIAN : GREGORIAN;
|
||||||
|
trans = (year == TRANS_YEAR && month == TRANS_MONTH);
|
||||||
|
offset = dayofweek(year, month, 1, cal) - fday;
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
offset += 7;
|
||||||
|
if (line == 1) {
|
||||||
|
for (; d < offset; ++d)
|
||||||
|
printf(" ");
|
||||||
|
dom = 1;
|
||||||
|
} else {
|
||||||
|
dom = 8 - offset + (line - 2) * 7;
|
||||||
|
if (trans && !(line == 2 && fday == 3))
|
||||||
|
dom += 11;
|
||||||
|
}
|
||||||
|
if (ltime && year == ltime->tm_year + 1900 && month == ltime->tm_mon)
|
||||||
|
today = ltime->tm_mday;
|
||||||
|
for (; d < 7 && dom <= monthlength(year, month, cal); ++d, ++dom) {
|
||||||
|
if (dom == today)
|
||||||
|
printf("\x1b[7m%2d\x1b[0m ", dom); /* highlight today's date */
|
||||||
|
else
|
||||||
|
printf("%2d ", dom);
|
||||||
|
if (trans && dom == TRANS_DAY)
|
||||||
|
dom += 11;
|
||||||
|
}
|
||||||
|
for (; d < 7; ++d)
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
drawcal(size_t year, int month, size_t ncols, size_t nmons, int fday)
|
||||||
|
{
|
||||||
|
char *smon[] = { "January", "February", "March", "April",
|
||||||
|
"May", "June", "July", "August",
|
||||||
|
"September", "October", "November", "December" };
|
||||||
|
char *days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", };
|
||||||
|
size_t m, n, col, cur_year, cur_month, dow;
|
||||||
|
int line, pad;
|
||||||
|
char month_year[sizeof("Su Mo Tu We Th Fr Sa")];
|
||||||
|
|
||||||
|
for (m = 0; m < nmons; ) {
|
||||||
|
n = m;
|
||||||
|
for (col = 0; m < nmons && col < ncols; ++col, ++m) {
|
||||||
|
cur_year = year + m / 12;
|
||||||
|
cur_month = month + m % 12;
|
||||||
|
if (cur_month > 11) {
|
||||||
|
cur_month -= 12;
|
||||||
|
cur_year += 1;
|
||||||
|
}
|
||||||
|
snprintf(month_year, sizeof(month_year), "%s %zu", smon[cur_month], cur_year);
|
||||||
|
pad = sizeof(month_year) - 1 - strlen(month_year);
|
||||||
|
printf("%*s%s%*s ", pad / 2 + pad % 2, "", month_year, pad / 2, "");
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
for (col = 0, m = n; m < nmons && col < ncols; ++col, ++m) {
|
||||||
|
for (dow = fday; dow < (fday + 7); ++dow)
|
||||||
|
printf("%s ", days[dow % 7]);
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
for (line = 1; line <= 6; ++line) {
|
||||||
|
for (col = 0, m = n; m < nmons && col < ncols; ++col, ++m) {
|
||||||
|
cur_year = year + m / 12;
|
||||||
|
cur_month = month + m % 12;
|
||||||
|
if (cur_month > 11) {
|
||||||
|
cur_month -= 12;
|
||||||
|
cur_year += 1;
|
||||||
|
}
|
||||||
|
printgrid(cur_year, cur_month, fday, line);
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-1 | -3 | -y | -n num] "
|
||||||
|
"[-s | -m | -f num] [-c num] [[month] year]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
time_t now;
|
||||||
|
size_t year, ncols, nmons;
|
||||||
|
int fday, month;
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
ltime = localtime(&now);
|
||||||
|
year = ltime->tm_year + 1900;
|
||||||
|
month = ltime->tm_mon + 1;
|
||||||
|
fday = 0;
|
||||||
|
|
||||||
|
if (!isatty(STDOUT_FILENO))
|
||||||
|
ltime = NULL; /* don't highlight today's date */
|
||||||
|
|
||||||
|
ncols = 3;
|
||||||
|
nmons = 0;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case '1':
|
||||||
|
nmons = 1;
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
nmons = 3;
|
||||||
|
if (--month == 0) {
|
||||||
|
month = 12;
|
||||||
|
year--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
ncols = estrtonum(EARGF(usage()), 0, MIN(SIZE_MAX, LLONG_MAX));
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
fday = estrtonum(EARGF(usage()), 0, 6);
|
||||||
|
break;
|
||||||
|
case 'm': /* Monday */
|
||||||
|
fday = 1;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
nmons = estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG_MAX));
|
||||||
|
break;
|
||||||
|
case 's': /* Sunday */
|
||||||
|
fday = 0;
|
||||||
|
break;
|
||||||
|
case 'y':
|
||||||
|
month = 1;
|
||||||
|
nmons = 12;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (nmons == 0) {
|
||||||
|
if (argc == 1) {
|
||||||
|
month = 1;
|
||||||
|
nmons = 12;
|
||||||
|
} else {
|
||||||
|
nmons = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (argc) {
|
||||||
|
case 2:
|
||||||
|
month = estrtonum(argv[0], 1, 12);
|
||||||
|
argv++;
|
||||||
|
case 1: /* fallthrough */
|
||||||
|
year = estrtonum(argv[0], 0, INT_MAX);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
drawcal(year, month - 1, ncols, nmons, fday);
|
||||||
|
|
||||||
|
return fshut(stdout, "<stdout>");
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt CAT 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm cat
|
||||||
|
.Nd concatenate files
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl u
|
||||||
|
.Op Ar file ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
reads each
|
||||||
|
.Ar file
|
||||||
|
in sequence and writes it to stdout.
|
||||||
|
If no
|
||||||
|
.Ar file
|
||||||
|
is given
|
||||||
|
.Nm
|
||||||
|
reads from stdin.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl u
|
||||||
|
Unbuffered output.
|
||||||
|
.El
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-u] [file ...]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd, ret = 0;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'u':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (!argc) {
|
||||||
|
if (concat(0, "<stdin>", 1, "<stdout>") < 0)
|
||||||
|
ret = 1;
|
||||||
|
} else {
|
||||||
|
for (; *argv; argc--, argv++) {
|
||||||
|
if (!strcmp(*argv, "-")) {
|
||||||
|
*argv = "<stdin>";
|
||||||
|
fd = 0;
|
||||||
|
} else if ((fd = open(*argv, O_RDONLY)) < 0) {
|
||||||
|
weprintf("open %s:", *argv);
|
||||||
|
ret = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (concat(fd, *argv, 1, "<stdout>")) {
|
||||||
|
case -1:
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
case -2:
|
||||||
|
return 1; /* exit on write error */
|
||||||
|
}
|
||||||
|
if (fd != 0)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt CHGRP 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm chgrp
|
||||||
|
.Nd change file group ownership
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl h
|
||||||
|
.Oo
|
||||||
|
.Fl R
|
||||||
|
.Op Fl H | L | P
|
||||||
|
.Oc
|
||||||
|
.Ar group
|
||||||
|
.Ar file ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
sets the group id of each
|
||||||
|
.Ar file
|
||||||
|
to the gid of
|
||||||
|
.Ar group .
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl h
|
||||||
|
Preserve
|
||||||
|
.Ar file
|
||||||
|
if it is a symbolic link.
|
||||||
|
.It Fl R
|
||||||
|
Change file group ownerships recursively.
|
||||||
|
.It Fl H
|
||||||
|
Dereference
|
||||||
|
.Ar file
|
||||||
|
if it is a symbolic link.
|
||||||
|
.It Fl L
|
||||||
|
Dereference all symbolic links.
|
||||||
|
.It Fl P
|
||||||
|
Preserve symbolic links.
|
||||||
|
This is the default.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr chmod 1 ,
|
||||||
|
.Xr chown 1 ,
|
||||||
|
.Xr chmod 2 ,
|
||||||
|
.Xr chown 2 ,
|
||||||
|
.Xr getgrnam 3
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "fs.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static int hflag = 0;
|
||||||
|
static gid_t gid = -1;
|
||||||
|
static int ret = 0;
|
||||||
|
|
||||||
|
static void
|
||||||
|
chgrp(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
|
||||||
|
{
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
if ((r->maxdepth == 0 && r->follow == 'P') || (r->follow == 'H' && r->depth) || (hflag && !(r->depth)))
|
||||||
|
flags |= AT_SYMLINK_NOFOLLOW;
|
||||||
|
if (fchownat(dirfd, name, -1, gid, flags) < 0) {
|
||||||
|
weprintf("chown %s:", r->path);
|
||||||
|
ret = 1;
|
||||||
|
} else if (S_ISDIR(st->st_mode)) {
|
||||||
|
recurse(dirfd, name, NULL, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-h] [-R [-H | -L | -P]] group file ...\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct group *gr;
|
||||||
|
struct recursor r = { .fn = chgrp, .maxdepth = 1, .follow = 'P' };
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'h':
|
||||||
|
hflag = 1;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
r.maxdepth = 0;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
case 'L':
|
||||||
|
case 'P':
|
||||||
|
r.follow = ARGC();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
if ((gr = getgrnam(argv[0]))) {
|
||||||
|
gid = gr->gr_gid;
|
||||||
|
} else {
|
||||||
|
if (errno)
|
||||||
|
eprintf("getgrnam %s:", argv[0]);
|
||||||
|
gid = estrtonum(argv[0], 0, UINT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (argc--, argv++; *argv; argc--, argv++)
|
||||||
|
recurse(AT_FDCWD, *argv, NULL, &r);
|
||||||
|
|
||||||
|
return ret || recurse_status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
.Dd December 21, 2019
|
||||||
|
.Dt CHMOD 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm chmod
|
||||||
|
.Nd change file modes
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl R
|
||||||
|
.Ar mode
|
||||||
|
.Ar file ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
changes the file mode of each
|
||||||
|
.Ar file
|
||||||
|
to
|
||||||
|
.Ar mode .
|
||||||
|
.Pp
|
||||||
|
If
|
||||||
|
.Ar mode
|
||||||
|
is
|
||||||
|
.Em octal
|
||||||
|
"[sog]e"
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It s
|
||||||
|
.Xr sticky 1 => s += 1
|
||||||
|
.Pp
|
||||||
|
.Xr setgid 2 => s += 2
|
||||||
|
.Pp
|
||||||
|
.Xr setuid 4 => s += 4
|
||||||
|
.It o|g|e
|
||||||
|
owner | group | everyone
|
||||||
|
.Pp
|
||||||
|
.Xr execute 1 => o|g|e += 1
|
||||||
|
.Pp
|
||||||
|
.Xr write 2 => o|g|e += 2
|
||||||
|
.Pp
|
||||||
|
.Xr read 4 => o|g|e += 4
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
Leading zeroes may be omitted.
|
||||||
|
.Pp
|
||||||
|
If
|
||||||
|
.Ar mode
|
||||||
|
is
|
||||||
|
.Em symbolic
|
||||||
|
"[ugoa]*[+-=][rwxXst]*"
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It u|g|o|a
|
||||||
|
owner | group | other (non-group) | everyone
|
||||||
|
.It +|-|=
|
||||||
|
add | remove | set
|
||||||
|
.It r|w|x|s|t
|
||||||
|
read | write | execute | setuid and setgid | sticky
|
||||||
|
.It X
|
||||||
|
execute, if directory or at least one execute bit is already set
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
Symbolic links are followed if they are passed as operands, and ignored
|
||||||
|
if they are encountered during directory traversal.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl R
|
||||||
|
Change modes recursively.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr chgrp 1 ,
|
||||||
|
.Xr umask 1
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Op Fl HLP
|
||||||
|
flags are an extension to that specification.
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "fs.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static char *modestr = "";
|
||||||
|
static mode_t mask = 0;
|
||||||
|
static int ret = 0;
|
||||||
|
|
||||||
|
static void
|
||||||
|
chmodr(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
|
||||||
|
{
|
||||||
|
mode_t m;
|
||||||
|
|
||||||
|
m = parsemode(modestr, st->st_mode, mask);
|
||||||
|
if (!S_ISLNK(st->st_mode) && fchmodat(dirfd, name, m, 0) < 0) {
|
||||||
|
weprintf("chmod %s:", r->path);
|
||||||
|
ret = 1;
|
||||||
|
} else if (S_ISDIR(st->st_mode)) {
|
||||||
|
recurse(dirfd, name, NULL, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-R] mode file ...\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct recursor r = { .fn = chmodr, .maxdepth = 1, .follow = 'H', .flags = DIRFIRST };
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
|
||||||
|
|
||||||
|
for (; *argv && (*argv)[0] == '-'; argc--, argv++) {
|
||||||
|
if (!(*argv)[1])
|
||||||
|
usage();
|
||||||
|
for (i = 1; (*argv)[i]; i++) {
|
||||||
|
switch ((*argv)[i]) {
|
||||||
|
case 'R':
|
||||||
|
r.maxdepth = 0;
|
||||||
|
break;
|
||||||
|
case 'r': case 'w': case 'x': case 'X': case 's': case 't':
|
||||||
|
/* -[rwxXst] are valid modes, so we're done */
|
||||||
|
if (i == 1)
|
||||||
|
goto done;
|
||||||
|
/* fallthrough */
|
||||||
|
case '-':
|
||||||
|
/* -- terminator */
|
||||||
|
if (i == 1 && !(*argv)[i + 1]) {
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* fallthrough */
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
mask = getumask();
|
||||||
|
modestr = *argv;
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
for (--argc, ++argv; *argv; argc--, argv++)
|
||||||
|
recurse(AT_FDCWD, *argv, NULL, &r);
|
||||||
|
|
||||||
|
return ret || recurse_status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt CHOWN 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm chown
|
||||||
|
.Nd change file ownership
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl h
|
||||||
|
.Oo
|
||||||
|
.Fl R
|
||||||
|
.Op Fl H | L | P
|
||||||
|
.Oc
|
||||||
|
.Ar owner Ns Op Pf : Op Ar group
|
||||||
|
.Op Ar file ...
|
||||||
|
.Nm
|
||||||
|
.Op Fl h
|
||||||
|
.Oo
|
||||||
|
.Fl R
|
||||||
|
.Op Fl H | L | P
|
||||||
|
.Oc
|
||||||
|
.Pf : Ar group
|
||||||
|
.Op Ar file ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
sets the user and/or group id of each
|
||||||
|
.Ar file
|
||||||
|
to the uid of
|
||||||
|
.Ar owner
|
||||||
|
and/or the gid of
|
||||||
|
.Ar group
|
||||||
|
respectively.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl h
|
||||||
|
Preserve
|
||||||
|
.Ar file
|
||||||
|
if it is a symbolic link.
|
||||||
|
.It Fl R
|
||||||
|
Change file ownerships recursively.
|
||||||
|
.It Fl H
|
||||||
|
Dereference
|
||||||
|
.Ar file
|
||||||
|
if it is a symbolic link.
|
||||||
|
.It Fl L
|
||||||
|
Dereference all symbolic links.
|
||||||
|
.It Fl P
|
||||||
|
Preserve symbolic links.
|
||||||
|
This is the default.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr chmod 1 ,
|
||||||
|
.Xr chown 2 ,
|
||||||
|
.Xr getgrnam 3 ,
|
||||||
|
.Xr getpwnam 3
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "fs.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static int hflag = 0;
|
||||||
|
static uid_t uid = -1;
|
||||||
|
static gid_t gid = -1;
|
||||||
|
static int ret = 0;
|
||||||
|
|
||||||
|
static void
|
||||||
|
chownpwgr(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
|
||||||
|
{
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
if ((r->maxdepth == 0 && r->follow == 'P') || (r->follow == 'H' && r->depth) || (hflag && !(r->depth)))
|
||||||
|
flags |= AT_SYMLINK_NOFOLLOW;
|
||||||
|
|
||||||
|
if (fchownat(dirfd, name, uid, gid, flags) < 0) {
|
||||||
|
weprintf("chown %s:", r->path);
|
||||||
|
ret = 1;
|
||||||
|
} else if (S_ISDIR(st->st_mode)) {
|
||||||
|
recurse(dirfd, name, NULL, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-h] [-R [-H | -L | -P]] owner[:[group]] file ...\n"
|
||||||
|
" %s [-h] [-R [-H | -L | -P]] :group file ...\n",
|
||||||
|
argv0, argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct group *gr;
|
||||||
|
struct passwd *pw;
|
||||||
|
struct recursor r = { .fn = chownpwgr, .maxdepth = 1, .follow = 'P' };
|
||||||
|
char *owner, *group;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'h':
|
||||||
|
hflag = 1;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
case 'R':
|
||||||
|
r.maxdepth = 0;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
case 'L':
|
||||||
|
case 'P':
|
||||||
|
r.follow = ARGC();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
owner = argv[0];
|
||||||
|
if ((group = strchr(owner, ':')))
|
||||||
|
*group++ = '\0';
|
||||||
|
|
||||||
|
if (owner && *owner) {
|
||||||
|
errno = 0;
|
||||||
|
pw = getpwnam(owner);
|
||||||
|
if (pw) {
|
||||||
|
uid = pw->pw_uid;
|
||||||
|
} else {
|
||||||
|
if (errno)
|
||||||
|
eprintf("getpwnam %s:", owner);
|
||||||
|
uid = estrtonum(owner, 0, UINT_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (group && *group) {
|
||||||
|
errno = 0;
|
||||||
|
gr = getgrnam(group);
|
||||||
|
if (gr) {
|
||||||
|
gid = gr->gr_gid;
|
||||||
|
} else {
|
||||||
|
if (errno)
|
||||||
|
eprintf("getgrnam %s:", group);
|
||||||
|
gid = estrtonum(group, 0, UINT_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uid == (uid_t)-1 && gid == (gid_t)-1)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
for (argc--, argv++; *argv; argc--, argv++)
|
||||||
|
recurse(AT_FDCWD, *argv, NULL, &r);
|
||||||
|
|
||||||
|
return ret || recurse_status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt CHROOT 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm chroot
|
||||||
|
.Nd run a command or shell with a different root directory
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Ar dir
|
||||||
|
.Op Ar cmd Op Ar arg ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
runs
|
||||||
|
.Ar cmd
|
||||||
|
after changing the root directory to
|
||||||
|
.Ar dir
|
||||||
|
with the
|
||||||
|
.Xr chroot 2
|
||||||
|
system call and after changing the working directory to the new root.
|
||||||
|
If
|
||||||
|
.Ar cmd
|
||||||
|
is not specified, an interactive shell is started in the new root.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr chdir 2 ,
|
||||||
|
.Xr chroot 2
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s dir [cmd [arg ...]]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *shell[] = { "/bin/sh", "-i", NULL }, *aux, *cmd;
|
||||||
|
int savederrno;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (!argc)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
if ((aux = getenv("SHELL")))
|
||||||
|
shell[0] = aux;
|
||||||
|
|
||||||
|
if (chroot(argv[0]) < 0)
|
||||||
|
eprintf("chroot %s:", argv[0]);
|
||||||
|
|
||||||
|
if (chdir("/") < 0)
|
||||||
|
eprintf("chdir:");
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
cmd = *shell;
|
||||||
|
execvp(cmd, shell);
|
||||||
|
} else {
|
||||||
|
cmd = argv[1];
|
||||||
|
execvp(cmd, argv + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
savederrno = errno;
|
||||||
|
weprintf("execvp %s:", cmd);
|
||||||
|
|
||||||
|
_exit(126 + (savederrno == ENOENT));
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt CKSUM 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm cksum
|
||||||
|
.Nd compute file checksum
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Ar file ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
calculates a cyclic redundancy check (CRC) of
|
||||||
|
.Ar file
|
||||||
|
according to
|
||||||
|
.St -iso8802-3
|
||||||
|
and writes it, the file size in bytes and path to stdout.
|
||||||
|
.Pp
|
||||||
|
If no
|
||||||
|
.Ar file
|
||||||
|
is given,
|
||||||
|
.Nm
|
||||||
|
reads from stdin.
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static int ret = 0;
|
||||||
|
static const unsigned long crctab[] = { 0x00000000,
|
||||||
|
0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
|
||||||
|
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
|
||||||
|
0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
|
||||||
|
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
|
||||||
|
0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
|
||||||
|
0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
|
||||||
|
0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
|
||||||
|
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
|
||||||
|
0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
|
||||||
|
0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
|
||||||
|
0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
|
||||||
|
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
|
||||||
|
0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
|
||||||
|
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
|
||||||
|
0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
|
||||||
|
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
|
||||||
|
0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
|
||||||
|
0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
|
||||||
|
0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
|
||||||
|
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
|
||||||
|
0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
|
||||||
|
0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
|
||||||
|
0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
|
||||||
|
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
|
||||||
|
0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
|
||||||
|
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
|
||||||
|
0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
|
||||||
|
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
|
||||||
|
0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
|
||||||
|
0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
|
||||||
|
0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
|
||||||
|
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
|
||||||
|
0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
|
||||||
|
0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
|
||||||
|
0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
|
||||||
|
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
|
||||||
|
0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
|
||||||
|
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
|
||||||
|
0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
|
||||||
|
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
|
||||||
|
0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
|
||||||
|
0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
|
||||||
|
0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
|
||||||
|
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
|
||||||
|
0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
|
||||||
|
0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
|
||||||
|
0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
|
||||||
|
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
|
||||||
|
0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
|
||||||
|
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
|
||||||
|
0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
cksum(int fd, const char *s)
|
||||||
|
{
|
||||||
|
ssize_t n;
|
||||||
|
size_t len = 0, i;
|
||||||
|
uint32_t ck = 0;
|
||||||
|
unsigned char buf[BUFSIZ];
|
||||||
|
|
||||||
|
while ((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
ck = (ck << 8) ^ crctab[(ck >> 24) ^ buf[i]];
|
||||||
|
len += n;
|
||||||
|
}
|
||||||
|
if (n < 0) {
|
||||||
|
weprintf("read %s:", s ? s : "<stdin>");
|
||||||
|
ret = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = len; i; i >>= 8)
|
||||||
|
ck = (ck << 8) ^ crctab[(ck >> 24) ^ (i & 0xFF)];
|
||||||
|
|
||||||
|
printf("%"PRIu32" %zu", ~ck, len);
|
||||||
|
if (s) {
|
||||||
|
putchar(' ');
|
||||||
|
fputs(s, stdout);
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [file ...]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (!argc) {
|
||||||
|
cksum(0, NULL);
|
||||||
|
} else {
|
||||||
|
for (; *argv; argc--, argv++) {
|
||||||
|
if (!strcmp(*argv, "-")) {
|
||||||
|
*argv = "<stdin>";
|
||||||
|
fd = 0;
|
||||||
|
} else if ((fd = open(*argv, O_RDONLY)) < 0) {
|
||||||
|
weprintf("open %s:", *argv);
|
||||||
|
ret = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cksum(fd, *argv);
|
||||||
|
if (fd != 0)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret |= fshut(stdout, "<stdout>");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt CMP 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm cmp
|
||||||
|
.Nd compare two files
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl l | Fl s
|
||||||
|
.Ar file1 file2
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
compares
|
||||||
|
.Ar file1
|
||||||
|
and
|
||||||
|
.Ar file2
|
||||||
|
byte by byte.
|
||||||
|
If they differ,
|
||||||
|
.Nm
|
||||||
|
writes the first differing byte- and line-number to stdout.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl l
|
||||||
|
Print byte-number and bytes (in octal) for each difference.
|
||||||
|
.It Fl s
|
||||||
|
Print nothing and only return status.
|
||||||
|
.El
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It 0
|
||||||
|
.Ar file1
|
||||||
|
and
|
||||||
|
.Ar file2
|
||||||
|
are identical.
|
||||||
|
.It 1
|
||||||
|
.Ar file1
|
||||||
|
and
|
||||||
|
.Ar file2
|
||||||
|
are different.
|
||||||
|
.It > 1
|
||||||
|
An error occurred.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr comm 1 ,
|
||||||
|
.Xr diff 1
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The "char" in the default result format has been replaced with "byte".
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
enprintf(2, "usage: %s [-l | -s] file1 file2\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
FILE *fp[2];
|
||||||
|
size_t line = 1, n;
|
||||||
|
int ret = 0, lflag = 0, sflag = 0, same = 1, b[2];
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'l':
|
||||||
|
lflag = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
sflag = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (argc != 2 || (lflag && sflag))
|
||||||
|
usage();
|
||||||
|
|
||||||
|
for (n = 0; n < 2; n++) {
|
||||||
|
if (!strcmp(argv[n], "-")) {
|
||||||
|
argv[n] = "<stdin>";
|
||||||
|
fp[n] = stdin;
|
||||||
|
} else {
|
||||||
|
if (!(fp[n] = fopen(argv[n], "r"))) {
|
||||||
|
if (!sflag)
|
||||||
|
weprintf("fopen %s:", argv[n]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n = 1; ; n++) {
|
||||||
|
b[0] = getc(fp[0]);
|
||||||
|
b[1] = getc(fp[1]);
|
||||||
|
|
||||||
|
if (b[0] == b[1]) {
|
||||||
|
if (b[0] == EOF)
|
||||||
|
break;
|
||||||
|
else if (b[0] == '\n')
|
||||||
|
line++;
|
||||||
|
continue;
|
||||||
|
} else if (b[0] == EOF || b[1] == EOF) {
|
||||||
|
if (!sflag)
|
||||||
|
weprintf("EOF on %s\n", argv[(b[0] != EOF)]);
|
||||||
|
same = 0;
|
||||||
|
break;
|
||||||
|
} else if (!lflag) {
|
||||||
|
if (!sflag)
|
||||||
|
printf("%s %s differ: byte %zu, line %zu\n",
|
||||||
|
argv[0], argv[1], n, line);
|
||||||
|
same = 0;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
printf("%zu %o %o\n", n, b[0], b[1]);
|
||||||
|
same = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
ret = !same;
|
||||||
|
if (fshut(fp[0], argv[0]) | (fp[0] != fp[1] && fshut(fp[1], argv[1])) |
|
||||||
|
fshut(stdout, "<stdout>"))
|
||||||
|
ret = 2;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt COLS 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm cols
|
||||||
|
.Nd columnize output
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl c Ar num
|
||||||
|
.Op Ar file ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
reads each
|
||||||
|
.Ar file
|
||||||
|
in sequence and writes them to stdout, in as many vertical
|
||||||
|
columns as will fit in
|
||||||
|
.Ar num
|
||||||
|
character columns.
|
||||||
|
If no
|
||||||
|
.Ar file
|
||||||
|
is given,
|
||||||
|
.Nm
|
||||||
|
reads from stdin.
|
||||||
|
.Pp
|
||||||
|
By default
|
||||||
|
.Nm cols
|
||||||
|
tries to figure out the width of the output device.
|
||||||
|
If that fails, it defaults to 65 chars.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl c Ar num
|
||||||
|
Set maximum number of character columns to
|
||||||
|
.Ar num ,
|
||||||
|
unless input lines exceed this limit.
|
||||||
|
.El
|
||||||
|
.Sh ENVIRONMENT
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It COLUMNS
|
||||||
|
The width of the output device.
|
||||||
|
.El
|
||||||
|
.Sh HISTORY
|
||||||
|
.Nm
|
||||||
|
is similar to
|
||||||
|
.Xr mc 1
|
||||||
|
in Plan 9. It was renamed to
|
||||||
|
.Nm
|
||||||
|
to avoid the name collision with the popular file manager
|
||||||
|
Midnight Commander.
|
||||||
|
.Sh CAVEATS
|
||||||
|
This implementation of
|
||||||
|
.Nm
|
||||||
|
assumes that each UTF-8 code point occupies one character cell,
|
||||||
|
and thus mishandles TAB characters (among others).
|
||||||
|
.Pp
|
||||||
|
.Nm
|
||||||
|
currently mangles files which contain embedded NULs.
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "text.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-c num] [file ...]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
struct winsize w;
|
||||||
|
struct linebuf b = EMPTY_LINEBUF;
|
||||||
|
size_t chars = 65, maxlen = 0, i, j, k, len, cols, rows;
|
||||||
|
int cflag = 0, ret = 0;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'c':
|
||||||
|
cflag = 1;
|
||||||
|
chars = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (!cflag) {
|
||||||
|
if ((p = getenv("COLUMNS")))
|
||||||
|
chars = estrtonum(p, 1, MIN(LLONG_MAX, SIZE_MAX));
|
||||||
|
else if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) && w.ws_col > 0)
|
||||||
|
chars = w.ws_col;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!argc) {
|
||||||
|
getlines(stdin, &b);
|
||||||
|
} else {
|
||||||
|
for (; *argv; argc--, argv++) {
|
||||||
|
if (!strcmp(*argv, "-")) {
|
||||||
|
*argv = "<stdin>";
|
||||||
|
fp = stdin;
|
||||||
|
} else if (!(fp = fopen(*argv, "r"))) {
|
||||||
|
weprintf("fopen %s:", *argv);
|
||||||
|
ret = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
getlines(fp, &b);
|
||||||
|
if (fp != stdin && fshut(fp, *argv))
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < b.nlines; i++) {
|
||||||
|
for (j = 0, len = 0; j < b.lines[i].len; j++) {
|
||||||
|
if (UTF8_POINT(b.lines[i].data[j]))
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
if (len && b.lines[i].data[b.lines[i].len - 1] == '\n') {
|
||||||
|
b.lines[i].data[--(b.lines[i].len)] = '\0';
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
if (len > maxlen)
|
||||||
|
maxlen = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cols = 1; (cols + 1) * maxlen + cols <= chars; cols++);
|
||||||
|
rows = b.nlines / cols + (b.nlines % cols > 0);
|
||||||
|
|
||||||
|
for (i = 0; i < rows; i++) {
|
||||||
|
for (j = 0; j < cols && i + j * rows < b.nlines; j++) {
|
||||||
|
for (k = 0, len = 0; k < b.lines[i + j * rows].len; k++) {
|
||||||
|
if (UTF8_POINT(b.lines[i + j * rows].data[k]))
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
fwrite(b.lines[i + j * rows].data, 1,
|
||||||
|
b.lines[i + j * rows].len, stdout);
|
||||||
|
if (j < cols - 1)
|
||||||
|
for (k = len; k < maxlen + 1; k++)
|
||||||
|
putchar(' ');
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt COMM 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm comm
|
||||||
|
.Nd select or reject lines common to two files
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl 123
|
||||||
|
.Ar file1
|
||||||
|
.Ar file2
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
reads
|
||||||
|
.Ar file1
|
||||||
|
and
|
||||||
|
.Ar file2 ,
|
||||||
|
which should both be sorted lexically, and writes three text columns
|
||||||
|
to stdout:
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It 1
|
||||||
|
Lines only in
|
||||||
|
.Ar file1 .
|
||||||
|
.It 2
|
||||||
|
Lines only in
|
||||||
|
.Ar file2 .
|
||||||
|
.It 3
|
||||||
|
Common lines.
|
||||||
|
.El
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl 1 | Fl 2 | Fl 3
|
||||||
|
Suppress column 1 | 2 | 3
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr cmp 1 ,
|
||||||
|
.Xr sort 1 ,
|
||||||
|
.Xr uniq 1
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "text.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static int show = 0x07;
|
||||||
|
|
||||||
|
static void
|
||||||
|
printline(int pos, struct line *line)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!(show & (0x1 << pos)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < pos; i++) {
|
||||||
|
if (show & (0x1 << i))
|
||||||
|
putchar('\t');
|
||||||
|
}
|
||||||
|
fwrite(line->data, 1, line->len, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-123] file1 file2\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
FILE *fp[2];
|
||||||
|
static struct line line[2];
|
||||||
|
size_t linecap[2] = { 0, 0 };
|
||||||
|
ssize_t len;
|
||||||
|
int ret = 0, i, diff = 0, seenline = 0;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
show &= 0x07 ^ (1 << (ARGC() - '1'));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (argc != 2)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
if (!strcmp(argv[i], "-")) {
|
||||||
|
argv[i] = "<stdin>";
|
||||||
|
fp[i] = stdin;
|
||||||
|
} else if (!(fp[i] = fopen(argv[i], "r"))) {
|
||||||
|
eprintf("fopen %s:", argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
if (diff && i == (diff < 0))
|
||||||
|
continue;
|
||||||
|
if ((len = getline(&(line[i].data), &linecap[i],
|
||||||
|
fp[i])) > 0) {
|
||||||
|
line[i].len = len;
|
||||||
|
seenline = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ferror(fp[i]))
|
||||||
|
eprintf("getline %s:", argv[i]);
|
||||||
|
if ((diff || seenline) && line[!i].data[0])
|
||||||
|
printline(!i, &line[!i]);
|
||||||
|
while ((len = getline(&(line[!i].data), &linecap[!i],
|
||||||
|
fp[!i])) > 0) {
|
||||||
|
line[!i].len = len;
|
||||||
|
printline(!i, &line[!i]);
|
||||||
|
}
|
||||||
|
if (ferror(fp[!i]))
|
||||||
|
eprintf("getline %s:", argv[!i]);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
diff = linecmp(&line[0], &line[1]);
|
||||||
|
LIMIT(diff, -1, 1);
|
||||||
|
seenline = 0;
|
||||||
|
printline((2 - diff) % 3, &line[MAX(0, diff)]);
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
ret |= fshut(fp[0], argv[0]);
|
||||||
|
ret |= (fp[0] != fp[1]) && fshut(fp[1], argv[1]);
|
||||||
|
ret |= fshut(stdout, "<stdout>");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#ifndef HOST_NAME_MAX
|
||||||
|
#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# sbase version
|
||||||
|
VERSION = 0.1
|
||||||
|
|
||||||
|
# paths
|
||||||
|
PREFIX = /usr/local
|
||||||
|
MANPREFIX = $(PREFIX)/share/man
|
||||||
|
|
||||||
|
# tools
|
||||||
|
#CC =
|
||||||
|
#AR =
|
||||||
|
RANLIB = ranlib
|
||||||
|
|
||||||
|
# -lrt might be needed on some systems
|
||||||
|
# CFLAGS =
|
||||||
|
# LDFLAGS =
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
.Dd April 22, 2025
|
||||||
|
.Dt CP 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm cp
|
||||||
|
.Nd copy files and directories
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl afipv
|
||||||
|
.Oo
|
||||||
|
.Fl R
|
||||||
|
.Op Fl H | L | P
|
||||||
|
.Oc
|
||||||
|
.Ar source ...
|
||||||
|
.Ar dest
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
copies
|
||||||
|
.Ar source
|
||||||
|
to
|
||||||
|
.Ar dest .
|
||||||
|
If more than one
|
||||||
|
.Ar source
|
||||||
|
is given
|
||||||
|
.Ar dest
|
||||||
|
has to be a directory.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl a
|
||||||
|
Preserve block devices, character devices, sockets and FIFOs.
|
||||||
|
Implies
|
||||||
|
.Fl p ,
|
||||||
|
.Fl P
|
||||||
|
and
|
||||||
|
.Fl R .
|
||||||
|
.It Fl f
|
||||||
|
If an existing
|
||||||
|
.Ar dest
|
||||||
|
cannot be opened, remove it and try again.
|
||||||
|
.It Fl i
|
||||||
|
Interactive prompt before overwrite.
|
||||||
|
.It Fl p
|
||||||
|
Preserve mode, timestamp and permissions.
|
||||||
|
.It Fl v
|
||||||
|
Write "'source' -> 'dest'" for each
|
||||||
|
.Ar source
|
||||||
|
to stdout.
|
||||||
|
.It Fl H
|
||||||
|
Dereference
|
||||||
|
.Ar source
|
||||||
|
if it is a symbolic link.
|
||||||
|
.It Fl L
|
||||||
|
Dereference all symbolic links.
|
||||||
|
This is the default without
|
||||||
|
.Fl R .
|
||||||
|
.It Fl P
|
||||||
|
Preserve symbolic links.
|
||||||
|
This is the default with
|
||||||
|
.Fl R .
|
||||||
|
.It Fl R
|
||||||
|
Traverse directories recursively.
|
||||||
|
If this flag is not specified, directories are not copied.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr mv 1
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Op Fl av
|
||||||
|
flags are an extension to that specification.
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "fs.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-afipv] [-R [-H | -L | -P]] source ... dest\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'i':
|
||||||
|
cp_iflag = 1;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
cp_follow = 'P';
|
||||||
|
cp_aflag = cp_pflag = cp_rflag = 1;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
cp_fflag = 1;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
cp_pflag = 1;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
case 'R':
|
||||||
|
cp_rflag = 1;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
cp_vflag = 1;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
case 'L':
|
||||||
|
case 'P':
|
||||||
|
cp_follow = ARGC();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
if (!cp_follow)
|
||||||
|
cp_follow = cp_rflag ? 'P' : 'L';
|
||||||
|
|
||||||
|
if (argc > 2) {
|
||||||
|
if (stat(argv[argc - 1], &st) < 0)
|
||||||
|
eprintf("stat %s:", argv[argc - 1]);
|
||||||
|
if (!S_ISDIR(st.st_mode))
|
||||||
|
eprintf("%s: not a directory\n", argv[argc - 1]);
|
||||||
|
}
|
||||||
|
enmasse(argc, argv, cp);
|
||||||
|
|
||||||
|
return fshut(stdout, "<stdout>") || cp_status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt CRON 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm cron
|
||||||
|
.Nd clock daemon
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl f Ar file
|
||||||
|
.Op Fl n
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
schedules commands to be run at specified dates and times.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl f Ar file
|
||||||
|
Use the specified
|
||||||
|
.Ar file
|
||||||
|
instead of the default
|
||||||
|
.Pa /etc/crontab .
|
||||||
|
.It Fl n
|
||||||
|
Do not daemonize.
|
||||||
|
.El
|
||||||
@@ -0,0 +1,566 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "queue.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
struct field {
|
||||||
|
enum {
|
||||||
|
ERROR,
|
||||||
|
WILDCARD,
|
||||||
|
NUMBER,
|
||||||
|
RANGE,
|
||||||
|
REPEAT,
|
||||||
|
LIST
|
||||||
|
} type;
|
||||||
|
long *val;
|
||||||
|
int len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ctabentry {
|
||||||
|
struct field min;
|
||||||
|
struct field hour;
|
||||||
|
struct field mday;
|
||||||
|
struct field mon;
|
||||||
|
struct field wday;
|
||||||
|
char *cmd;
|
||||||
|
TAILQ_ENTRY(ctabentry) entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jobentry {
|
||||||
|
char *cmd;
|
||||||
|
pid_t pid;
|
||||||
|
TAILQ_ENTRY(jobentry) entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
static sig_atomic_t chldreap;
|
||||||
|
static sig_atomic_t reload;
|
||||||
|
static sig_atomic_t quit;
|
||||||
|
static TAILQ_HEAD(, ctabentry) ctabhead = TAILQ_HEAD_INITIALIZER(ctabhead);
|
||||||
|
static TAILQ_HEAD(, jobentry) jobhead = TAILQ_HEAD_INITIALIZER(jobhead);
|
||||||
|
static char *config = "/etc/crontab";
|
||||||
|
static char *pidfile = "/var/run/crond.pid";
|
||||||
|
static int nflag;
|
||||||
|
|
||||||
|
static void
|
||||||
|
loginfo(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
if (nflag == 0)
|
||||||
|
vsyslog(LOG_INFO, fmt, ap);
|
||||||
|
else
|
||||||
|
vfprintf(stdout, fmt, ap);
|
||||||
|
fflush(stdout);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
logwarn(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
if (nflag == 0)
|
||||||
|
vsyslog(LOG_WARNING, fmt, ap);
|
||||||
|
else
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
logerr(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
if (nflag == 0)
|
||||||
|
vsyslog(LOG_ERR, fmt, ap);
|
||||||
|
else
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
runjob(char *cmd)
|
||||||
|
{
|
||||||
|
struct jobentry *je;
|
||||||
|
time_t t;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
t = time(NULL);
|
||||||
|
|
||||||
|
/* If command is already running, skip it */
|
||||||
|
TAILQ_FOREACH(je, &jobhead, entry) {
|
||||||
|
if (strcmp(je->cmd, cmd) == 0) {
|
||||||
|
loginfo("already running %s pid: %d at %s",
|
||||||
|
je->cmd, je->pid, ctime(&t));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ((pid = fork())) {
|
||||||
|
case -1:
|
||||||
|
logerr("error: failed to fork job: %s time: %s",
|
||||||
|
cmd, ctime(&t));
|
||||||
|
return;
|
||||||
|
case 0:
|
||||||
|
setsid();
|
||||||
|
loginfo("run: %s pid: %d at %s",
|
||||||
|
cmd, getpid(), ctime(&t));
|
||||||
|
execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL);
|
||||||
|
logerr("error: failed to execute job: %s time: %s",
|
||||||
|
cmd, ctime(&t));
|
||||||
|
_exit(1);
|
||||||
|
default:
|
||||||
|
je = emalloc(sizeof(*je));
|
||||||
|
je->cmd = estrdup(cmd);
|
||||||
|
je->pid = pid;
|
||||||
|
TAILQ_INSERT_TAIL(&jobhead, je, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
waitjob(void)
|
||||||
|
{
|
||||||
|
struct jobentry *je, *tmp;
|
||||||
|
int status;
|
||||||
|
time_t t;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
t = time(NULL);
|
||||||
|
|
||||||
|
while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
|
||||||
|
je = NULL;
|
||||||
|
TAILQ_FOREACH(tmp, &jobhead, entry) {
|
||||||
|
if (tmp->pid == pid) {
|
||||||
|
je = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (je) {
|
||||||
|
TAILQ_REMOVE(&jobhead, je, entry);
|
||||||
|
free(je->cmd);
|
||||||
|
free(je);
|
||||||
|
}
|
||||||
|
if (WIFEXITED(status) == 1)
|
||||||
|
loginfo("complete: pid: %d returned: %d time: %s",
|
||||||
|
pid, WEXITSTATUS(status), ctime(&t));
|
||||||
|
else if (WIFSIGNALED(status) == 1)
|
||||||
|
loginfo("complete: pid: %d terminated by signal: %s time: %s",
|
||||||
|
pid, strsignal(WTERMSIG(status)), ctime(&t));
|
||||||
|
else if (WIFSTOPPED(status) == 1)
|
||||||
|
loginfo("complete: pid: %d stopped by signal: %s time: %s",
|
||||||
|
pid, strsignal(WSTOPSIG(status)), ctime(&t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
isleap(int year)
|
||||||
|
{
|
||||||
|
if (year % 400 == 0)
|
||||||
|
return 1;
|
||||||
|
if (year % 100 == 0)
|
||||||
|
return 0;
|
||||||
|
return (year % 4 == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
daysinmon(int mon, int year)
|
||||||
|
{
|
||||||
|
int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||||
|
if (year < 1900)
|
||||||
|
year += 1900;
|
||||||
|
if (isleap(year))
|
||||||
|
days[1] = 29;
|
||||||
|
return days[mon];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
matchentry(struct ctabentry *cte, struct tm *tm)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
struct field *f;
|
||||||
|
int tm;
|
||||||
|
int len;
|
||||||
|
} matchtbl[] = {
|
||||||
|
{ .f = &cte->min, .tm = tm->tm_min, .len = 60 },
|
||||||
|
{ .f = &cte->hour, .tm = tm->tm_hour, .len = 24 },
|
||||||
|
{ .f = &cte->mday, .tm = tm->tm_mday, .len = daysinmon(tm->tm_mon, tm->tm_year) },
|
||||||
|
{ .f = &cte->mon, .tm = tm->tm_mon, .len = 12 },
|
||||||
|
{ .f = &cte->wday, .tm = tm->tm_wday, .len = 7 },
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (i = 0; i < LEN(matchtbl); i++) {
|
||||||
|
switch (matchtbl[i].f->type) {
|
||||||
|
case WILDCARD:
|
||||||
|
continue;
|
||||||
|
case NUMBER:
|
||||||
|
if (matchtbl[i].f->val[0] == matchtbl[i].tm)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case RANGE:
|
||||||
|
if (matchtbl[i].f->val[0] <= matchtbl[i].tm)
|
||||||
|
if (matchtbl[i].f->val[1] >= matchtbl[i].tm)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case REPEAT:
|
||||||
|
if (matchtbl[i].tm > 0) {
|
||||||
|
if (matchtbl[i].tm % matchtbl[i].f->val[0] == 0)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
if (matchtbl[i].len % matchtbl[i].f->val[0] == 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIST:
|
||||||
|
for (j = 0; j < matchtbl[i].f->len; j++)
|
||||||
|
if (matchtbl[i].f->val[j] == matchtbl[i].tm)
|
||||||
|
break;
|
||||||
|
if (j < matchtbl[i].f->len)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i != LEN(matchtbl))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parsefield(const char *field, long low, long high, struct field *f)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *e1, *e2;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
p = field;
|
||||||
|
while (isdigit(*p))
|
||||||
|
p++;
|
||||||
|
|
||||||
|
f->type = ERROR;
|
||||||
|
|
||||||
|
switch (*p) {
|
||||||
|
case '*':
|
||||||
|
if (strcmp(field, "*") == 0) {
|
||||||
|
f->val = NULL;
|
||||||
|
f->len = 0;
|
||||||
|
f->type = WILDCARD;
|
||||||
|
} else if (strncmp(field, "*/", 2) == 0) {
|
||||||
|
f->val = emalloc(sizeof(*f->val));
|
||||||
|
f->len = 1;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
f->val[0] = strtol(field + 2, &e1, 10);
|
||||||
|
if (e1[0] != '\0' || errno != 0 || f->val[0] == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
f->type = REPEAT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\0':
|
||||||
|
f->val = emalloc(sizeof(*f->val));
|
||||||
|
f->len = 1;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
f->val[0] = strtol(field, &e1, 10);
|
||||||
|
if (e1[0] != '\0' || errno != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
f->type = NUMBER;
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
f->val = emalloc(2 * sizeof(*f->val));
|
||||||
|
f->len = 2;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
f->val[0] = strtol(field, &e1, 10);
|
||||||
|
if (e1[0] != '-' || errno != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
f->val[1] = strtol(e1 + 1, &e2, 10);
|
||||||
|
if (e2[0] != '\0' || errno != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
f->type = RANGE;
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
for (i = 1; isdigit(*p) || *p == ','; p++)
|
||||||
|
if (*p == ',')
|
||||||
|
i++;
|
||||||
|
f->val = emalloc(i * sizeof(*f->val));
|
||||||
|
f->len = i;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
f->val[0] = strtol(field, &e1, 10);
|
||||||
|
if (f->val[0] < low || f->val[0] > high)
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (i = 1; *e1 == ',' && errno == 0; i++) {
|
||||||
|
errno = 0;
|
||||||
|
f->val[i] = strtol(e1 + 1, &e2, 10);
|
||||||
|
e1 = e2;
|
||||||
|
}
|
||||||
|
if (e1[0] != '\0' || errno != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
f->type = LIST;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < f->len; i++)
|
||||||
|
if (f->val[i] < low || f->val[i] > high)
|
||||||
|
f->type = ERROR;
|
||||||
|
|
||||||
|
if (f->type == ERROR) {
|
||||||
|
free(f->val);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
freecte(struct ctabentry *cte, int nfields)
|
||||||
|
{
|
||||||
|
switch (nfields) {
|
||||||
|
case 6:
|
||||||
|
free(cte->cmd);
|
||||||
|
case 5:
|
||||||
|
free(cte->wday.val);
|
||||||
|
case 4:
|
||||||
|
free(cte->mon.val);
|
||||||
|
case 3:
|
||||||
|
free(cte->mday.val);
|
||||||
|
case 2:
|
||||||
|
free(cte->hour.val);
|
||||||
|
case 1:
|
||||||
|
free(cte->min.val);
|
||||||
|
}
|
||||||
|
free(cte);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
unloadentries(void)
|
||||||
|
{
|
||||||
|
struct ctabentry *cte, *tmp;
|
||||||
|
|
||||||
|
for (cte = TAILQ_FIRST(&ctabhead); cte; cte = tmp) {
|
||||||
|
tmp = TAILQ_NEXT(cte, entry);
|
||||||
|
TAILQ_REMOVE(&ctabhead, cte, entry);
|
||||||
|
freecte(cte, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loadentries(void)
|
||||||
|
{
|
||||||
|
struct ctabentry *cte;
|
||||||
|
FILE *fp;
|
||||||
|
char *line = NULL, *p, *col;
|
||||||
|
int r = 0, y;
|
||||||
|
size_t size = 0;
|
||||||
|
ssize_t len;
|
||||||
|
struct fieldlimits {
|
||||||
|
char *name;
|
||||||
|
long min;
|
||||||
|
long max;
|
||||||
|
struct field *f;
|
||||||
|
} flim[] = {
|
||||||
|
{ "min", 0, 59, NULL },
|
||||||
|
{ "hour", 0, 23, NULL },
|
||||||
|
{ "mday", 1, 31, NULL },
|
||||||
|
{ "mon", 1, 12, NULL },
|
||||||
|
{ "wday", 0, 6, NULL }
|
||||||
|
};
|
||||||
|
size_t x;
|
||||||
|
|
||||||
|
if ((fp = fopen(config, "r")) == NULL) {
|
||||||
|
logerr("error: can't open %s: %s\n", config, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (y = 0; (len = getline(&line, &size, fp)) != -1; y++) {
|
||||||
|
p = line;
|
||||||
|
if (line[0] == '#' || line[0] == '\n' || line[0] == '\0')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cte = emalloc(sizeof(*cte));
|
||||||
|
flim[0].f = &cte->min;
|
||||||
|
flim[1].f = &cte->hour;
|
||||||
|
flim[2].f = &cte->mday;
|
||||||
|
flim[3].f = &cte->mon;
|
||||||
|
flim[4].f = &cte->wday;
|
||||||
|
|
||||||
|
for (x = 0; x < LEN(flim); x++) {
|
||||||
|
do
|
||||||
|
col = strsep(&p, "\t\n ");
|
||||||
|
while (col && col[0] == '\0');
|
||||||
|
|
||||||
|
if (!col || parsefield(col, flim[x].min, flim[x].max, flim[x].f) < 0) {
|
||||||
|
logerr("error: failed to parse `%s' field on line %d\n",
|
||||||
|
flim[x].name, y + 1);
|
||||||
|
freecte(cte, x);
|
||||||
|
r = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
col = strsep(&p, "\n");
|
||||||
|
if (col)
|
||||||
|
while (col[0] == '\t' || col[0] == ' ')
|
||||||
|
col++;
|
||||||
|
if (!col || col[0] == '\0') {
|
||||||
|
logerr("error: missing `cmd' field on line %d\n",
|
||||||
|
y + 1);
|
||||||
|
freecte(cte, 5);
|
||||||
|
r = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cte->cmd = estrdup(col);
|
||||||
|
|
||||||
|
TAILQ_INSERT_TAIL(&ctabhead, cte, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r < 0)
|
||||||
|
unloadentries();
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
reloadentries(void)
|
||||||
|
{
|
||||||
|
unloadentries();
|
||||||
|
if (loadentries() < 0)
|
||||||
|
logwarn("warning: discarding old crontab entries\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sighandler(int sig)
|
||||||
|
{
|
||||||
|
switch (sig) {
|
||||||
|
case SIGCHLD:
|
||||||
|
chldreap = 1;
|
||||||
|
break;
|
||||||
|
case SIGHUP:
|
||||||
|
reload = 1;
|
||||||
|
break;
|
||||||
|
case SIGTERM:
|
||||||
|
quit = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-f file] [-n]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
struct ctabentry *cte;
|
||||||
|
time_t t;
|
||||||
|
struct tm *tm;
|
||||||
|
struct sigaction sa;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'n':
|
||||||
|
nflag = 1;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
config = EARGF(usage());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (argc > 0)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
if (nflag == 0) {
|
||||||
|
openlog(argv[0], LOG_CONS | LOG_PID, LOG_CRON);
|
||||||
|
if (daemon(1, 0) < 0) {
|
||||||
|
logerr("error: failed to daemonize %s\n", strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ((fp = fopen(pidfile, "w"))) {
|
||||||
|
fprintf(fp, "%d\n", getpid());
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sa.sa_handler = sighandler;
|
||||||
|
sigfillset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
|
sigaction(SIGCHLD, &sa, NULL);
|
||||||
|
sigaction(SIGHUP, &sa, NULL);
|
||||||
|
sigaction(SIGTERM, &sa, NULL);
|
||||||
|
|
||||||
|
loadentries();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
t = time(NULL);
|
||||||
|
sleep(60 - t % 60);
|
||||||
|
|
||||||
|
if (quit == 1) {
|
||||||
|
if (nflag == 0)
|
||||||
|
unlink(pidfile);
|
||||||
|
unloadentries();
|
||||||
|
/* Don't wait or kill forked processes, just exit */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reload == 1 || chldreap == 1) {
|
||||||
|
if (reload == 1) {
|
||||||
|
reloadentries();
|
||||||
|
reload = 0;
|
||||||
|
}
|
||||||
|
if (chldreap == 1) {
|
||||||
|
waitjob();
|
||||||
|
chldreap = 0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_FOREACH(cte, &ctabhead, entry) {
|
||||||
|
t = time(NULL);
|
||||||
|
tm = localtime(&t);
|
||||||
|
if (matchentry(cte, tm) == 1)
|
||||||
|
runjob(cte->cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nflag == 0)
|
||||||
|
closelog();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
struct crypt_ops {
|
||||||
|
void (*init)(void *);
|
||||||
|
void (*update)(void *, const void *, unsigned long);
|
||||||
|
void (*sum)(void *, uint8_t *);
|
||||||
|
void *s;
|
||||||
|
};
|
||||||
|
|
||||||
|
int cryptcheck(int, char **, struct crypt_ops *, uint8_t *, size_t);
|
||||||
|
int cryptmain(int, char **, struct crypt_ops *, uint8_t *, size_t);
|
||||||
|
int cryptsum(struct crypt_ops *, int, const char *, uint8_t *);
|
||||||
|
void mdprint(const uint8_t *, const char *, size_t);
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt CUT 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm cut
|
||||||
|
.Nd extract columns of data
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Fl b Ar list
|
||||||
|
.Op Fl n
|
||||||
|
.Op Ar file ...
|
||||||
|
.Nm
|
||||||
|
.Fl c Ar list
|
||||||
|
.Op Ar file ...
|
||||||
|
.Nm
|
||||||
|
.Fl f Ar list
|
||||||
|
.Op Fl d Ar delim
|
||||||
|
.Op Fl s
|
||||||
|
.Op Ar file ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
out bytes, characters or delimited fields from each line of
|
||||||
|
.Ar file
|
||||||
|
and write to stdout.
|
||||||
|
.Pp
|
||||||
|
If no
|
||||||
|
.Ar file
|
||||||
|
is given or
|
||||||
|
.Ar file
|
||||||
|
is '-',
|
||||||
|
.Nm
|
||||||
|
reads from stdin.
|
||||||
|
.Pp
|
||||||
|
.Ar list
|
||||||
|
is a comma or space separated list of numbers and ranges starting
|
||||||
|
from 1.
|
||||||
|
Ranges have the form 'N-M'. If N or M is missing, beginning or end
|
||||||
|
of line is assumed.
|
||||||
|
Numbers and ranges may be repeated, overlapping and in any order.
|
||||||
|
.Pp
|
||||||
|
Selected input is written in the same order it is read
|
||||||
|
and is written exactly once.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl b Ar list | Fl c Ar list
|
||||||
|
.Ar list
|
||||||
|
specifies byte | character positions.
|
||||||
|
.It Fl d Ar delim
|
||||||
|
Use
|
||||||
|
.Ar delim
|
||||||
|
as field delimiter, which can be an arbitrary string.
|
||||||
|
Default is '\et'.
|
||||||
|
.It Fl f Ar list
|
||||||
|
.Ar list
|
||||||
|
specifies field numbers.
|
||||||
|
Lines not containing field delimiters are passed through, unless
|
||||||
|
.Fl s
|
||||||
|
is specified.
|
||||||
|
.It Fl n
|
||||||
|
Do not split multibyte characters.
|
||||||
|
A character is written when its last byte is selected.
|
||||||
|
.It Fl s
|
||||||
|
Suppress lines not containing field delimiters.
|
||||||
|
.El
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The possibility of separating numbers and ranges with a space and specifying
|
||||||
|
multibyte delimiters of arbitrary length is an extension to that specification.
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "text.h"
|
||||||
|
#include "utf.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
typedef struct Range {
|
||||||
|
size_t min, max;
|
||||||
|
struct Range *next;
|
||||||
|
} Range;
|
||||||
|
|
||||||
|
static Range *list = NULL;
|
||||||
|
static char mode = 0;
|
||||||
|
static char *delim = "\t";
|
||||||
|
static size_t delimlen = 1;
|
||||||
|
static int nflag = 0;
|
||||||
|
static int sflag = 0;
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert(Range *r)
|
||||||
|
{
|
||||||
|
Range *l, *p, *t;
|
||||||
|
|
||||||
|
for (p = NULL, l = list; l; p = l, l = l->next) {
|
||||||
|
if (r->max && r->max + 1 < l->min) {
|
||||||
|
r->next = l;
|
||||||
|
break;
|
||||||
|
} else if (!l->max || r->min < l->max + 2) {
|
||||||
|
l->min = MIN(r->min, l->min);
|
||||||
|
for (p = l, t = l->next; t; p = t, t = t->next)
|
||||||
|
if (r->max && r->max + 1 < t->min)
|
||||||
|
break;
|
||||||
|
l->max = (p->max && r->max) ? MAX(p->max, r->max) : 0;
|
||||||
|
l->next = t;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p)
|
||||||
|
p->next = r;
|
||||||
|
else
|
||||||
|
list = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parselist(char *str)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
size_t n = 1;
|
||||||
|
Range *r;
|
||||||
|
|
||||||
|
if (!*str)
|
||||||
|
eprintf("empty list\n");
|
||||||
|
for (s = str; *s; s++) {
|
||||||
|
if (*s == ' ')
|
||||||
|
*s = ',';
|
||||||
|
if (*s == ',')
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
r = ereallocarray(NULL, n, sizeof(*r));
|
||||||
|
for (s = str; n; n--, s++) {
|
||||||
|
r->min = (*s == '-') ? 1 : strtoul(s, &s, 10);
|
||||||
|
r->max = (*s == '-') ? strtoul(s + 1, &s, 10) : r->min;
|
||||||
|
r->next = NULL;
|
||||||
|
if (!r->min || (r->max && r->max < r->min) || (*s && *s != ','))
|
||||||
|
eprintf("bad list value\n");
|
||||||
|
insert(r++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
seek(struct line *s, size_t pos, size_t *prev, size_t count)
|
||||||
|
{
|
||||||
|
size_t n = pos - *prev, i, j;
|
||||||
|
|
||||||
|
if (mode == 'b') {
|
||||||
|
if (n >= s->len)
|
||||||
|
return s->len;
|
||||||
|
if (nflag)
|
||||||
|
while (n && !UTF8_POINT(s->data[n]))
|
||||||
|
n--;
|
||||||
|
*prev += n;
|
||||||
|
return n;
|
||||||
|
} else if (mode == 'c') {
|
||||||
|
for (n++, i = 0; i < s->len; i++)
|
||||||
|
if (UTF8_POINT(s->data[i]) && !--n)
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
for (i = (count < delimlen + 1) ? 0 : delimlen; n && i < s->len; ) {
|
||||||
|
if ((s->len - i) >= delimlen &&
|
||||||
|
!memcmp(s->data + i, delim, delimlen)) {
|
||||||
|
if (!--n && count)
|
||||||
|
break;
|
||||||
|
i += delimlen;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (j = 1; j + i <= s->len && !fullrune(s->data + i, j); j++);
|
||||||
|
i += j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*prev = pos;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cut(FILE *fp, const char *fname)
|
||||||
|
{
|
||||||
|
Range *r;
|
||||||
|
struct line s;
|
||||||
|
static struct line line;
|
||||||
|
static size_t size;
|
||||||
|
size_t i, n, p;
|
||||||
|
ssize_t len;
|
||||||
|
|
||||||
|
while ((len = getline(&line.data, &size, fp)) > 0) {
|
||||||
|
line.len = len;
|
||||||
|
if (line.data[line.len - 1] == '\n')
|
||||||
|
line.data[--line.len] = '\0';
|
||||||
|
if (mode == 'f' && !memmem(line.data, line.len, delim, delimlen)) {
|
||||||
|
if (!sflag) {
|
||||||
|
fwrite(line.data, 1, line.len, stdout);
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (i = 0, p = 1, s = line, r = list; r; r = r->next) {
|
||||||
|
n = seek(&s, r->min, &p, i);
|
||||||
|
s.data += n;
|
||||||
|
s.len -= n;
|
||||||
|
i += (mode == 'f') ? delimlen : 1;
|
||||||
|
if (!s.len)
|
||||||
|
break;
|
||||||
|
if (!r->max) {
|
||||||
|
fwrite(s.data, 1, s.len, stdout);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n = seek(&s, r->max + 1, &p, i);
|
||||||
|
i += (mode == 'f') ? delimlen : 1;
|
||||||
|
if (fwrite(s.data, 1, n, stdout) != n)
|
||||||
|
eprintf("fwrite <stdout>:");
|
||||||
|
s.data += n;
|
||||||
|
s.len -= n;
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
if (ferror(fp))
|
||||||
|
eprintf("getline %s:", fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s -b list [-n] [file ...]\n"
|
||||||
|
" %s -c list [file ...]\n"
|
||||||
|
" %s -f list [-d delim] [-s] [file ...]\n",
|
||||||
|
argv0, argv0, argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'b':
|
||||||
|
case 'c':
|
||||||
|
case 'f':
|
||||||
|
mode = ARGC();
|
||||||
|
parselist(EARGF(usage()));
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
delim = EARGF(usage());
|
||||||
|
if (!*delim)
|
||||||
|
eprintf("empty delimiter\n");
|
||||||
|
delimlen = unescape(delim);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
nflag = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
sflag = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (!mode)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
if (!argc)
|
||||||
|
cut(stdin, "<stdin>");
|
||||||
|
else {
|
||||||
|
for (; *argv; argc--, argv++) {
|
||||||
|
if (!strcmp(*argv, "-")) {
|
||||||
|
*argv = "<stdin>";
|
||||||
|
fp = stdin;
|
||||||
|
} else if (!(fp = fopen(*argv, "r"))) {
|
||||||
|
weprintf("fopen %s:", *argv);
|
||||||
|
ret = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cut(fp, *argv);
|
||||||
|
if (fp != stdin && fshut(fp, *argv))
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt DATE 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm date
|
||||||
|
.Nd print or set date and time
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl d Ar time
|
||||||
|
.Op Fl u
|
||||||
|
.Oo
|
||||||
|
.Cm + Ns Ar format |
|
||||||
|
.Sm off
|
||||||
|
.Ar mmddHHMM Oo Oo Ar CC Oc Ar yy Oc
|
||||||
|
.Sm on
|
||||||
|
.Oc
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
prints the date and time according to
|
||||||
|
.Xr locale 7
|
||||||
|
or
|
||||||
|
.Ar format
|
||||||
|
using
|
||||||
|
.Xr strftime 3
|
||||||
|
or sets the date.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl d Ar time
|
||||||
|
Print
|
||||||
|
.Ar time
|
||||||
|
given as the number of seconds since the
|
||||||
|
Unix epoch 1970-01-01T00:00:00Z.
|
||||||
|
.It Fl u
|
||||||
|
Print or set UTC time instead of local time.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
An operand with a leading plus
|
||||||
|
.Pq Cm +
|
||||||
|
sign signals a user-defined format string using
|
||||||
|
.Xr strftime 3
|
||||||
|
conversion specifications.
|
||||||
|
.Pp
|
||||||
|
An operand without a leading plus sign is interpreted as a value
|
||||||
|
for setting the system's current date and time.
|
||||||
|
The canonical representation for setting the date and time is:
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width Ds -compact -offset indent
|
||||||
|
.It Ar mm
|
||||||
|
The month of the year, from 01 to 12.
|
||||||
|
.It Ar dd
|
||||||
|
The day of the month, from 01 to 31.
|
||||||
|
.It Ar HH
|
||||||
|
The hour of the day, from 00 to 23.
|
||||||
|
.It Ar MM
|
||||||
|
The minute of the hour, from 00 to 59.
|
||||||
|
.It Ar CC
|
||||||
|
The first two digits of the year (the century).
|
||||||
|
.It Ar yy
|
||||||
|
The second two digits of the year.
|
||||||
|
If
|
||||||
|
.Ar yy
|
||||||
|
is specified, but
|
||||||
|
.Ar CC
|
||||||
|
is not, a value for
|
||||||
|
.Ar yy
|
||||||
|
between 69 and 99 results in a
|
||||||
|
.Ar CC
|
||||||
|
value of 19.
|
||||||
|
Otherwise, a
|
||||||
|
.Ar CC
|
||||||
|
value of 20 is used.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The century and year are optional.
|
||||||
|
The default is the current year.
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Op Fl d
|
||||||
|
flag is an extension to that specification.
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-u] [-d time] [+format | mmddHHMM[[CC]yy]]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
datefield(const char *s, size_t i)
|
||||||
|
{
|
||||||
|
if (!isdigit(s[i]) || !isdigit(s[i+1]))
|
||||||
|
eprintf("invalid date format: %s\n", s);
|
||||||
|
|
||||||
|
return (s[i] - '0') * 10 + (s[i+1] - '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setdate(const char *s, struct tm *now)
|
||||||
|
{
|
||||||
|
struct tm date;
|
||||||
|
struct timespec ts;
|
||||||
|
|
||||||
|
switch (strlen(s)) {
|
||||||
|
case 8:
|
||||||
|
date.tm_year = now->tm_year;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
date.tm_year = datefield(s, 8);
|
||||||
|
if (date.tm_year < 69)
|
||||||
|
date.tm_year += 100;
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
date.tm_year = ((datefield(s, 8) - 19) * 100) + datefield(s, 10);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
eprintf("invalid date format: %s\n", s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
date.tm_mon = datefield(s, 0) - 1;
|
||||||
|
date.tm_mday = datefield(s, 2);
|
||||||
|
date.tm_hour = datefield(s, 4);
|
||||||
|
date.tm_min = datefield(s, 6);
|
||||||
|
date.tm_sec = 0;
|
||||||
|
date.tm_isdst = -1;
|
||||||
|
|
||||||
|
ts.tv_sec = mktime(&date);
|
||||||
|
if (ts.tv_sec == -1)
|
||||||
|
eprintf("mktime:");
|
||||||
|
ts.tv_nsec = 0;
|
||||||
|
|
||||||
|
if (clock_settime(CLOCK_REALTIME, &ts) == -1)
|
||||||
|
eprintf("clock_settime:");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct tm *now;
|
||||||
|
time_t t;
|
||||||
|
char buf[BUFSIZ], *fmt = "%a %b %e %H:%M:%S %Z %Y";
|
||||||
|
|
||||||
|
t = time(NULL);
|
||||||
|
if (t == -1)
|
||||||
|
eprintf("time:");
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'd':
|
||||||
|
t = estrtonum(EARGF(usage()), 0, LLONG_MAX);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
if (setenv("TZ", "UTC0", 1) < 0)
|
||||||
|
eprintf("setenv:");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (!(now = localtime(&t)))
|
||||||
|
eprintf("localtime:");
|
||||||
|
if (argc) {
|
||||||
|
if (argc != 1)
|
||||||
|
usage();
|
||||||
|
if (argv[0][0] != '+') {
|
||||||
|
setdate(argv[0], now);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fmt = &argv[0][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
strftime(buf, sizeof(buf), fmt, now);
|
||||||
|
puts(buf);
|
||||||
|
|
||||||
|
return fshut(stdout, "<stdout>");
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
.Dd April 28, 2020
|
||||||
|
.Dt DD 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm dd
|
||||||
|
.Nd convert and copy a file
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Ar operand Ns ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
copies its input to its output, possibly after conversion, using
|
||||||
|
the specified block sizes,
|
||||||
|
.Pp
|
||||||
|
The following operands are available:
|
||||||
|
.Bl -tag -width ibs=expr
|
||||||
|
.It Cm if= Ns Ar file
|
||||||
|
Read from the file named by
|
||||||
|
.Ar file
|
||||||
|
instead of standard input.
|
||||||
|
.It Cm of= Ns Ar file
|
||||||
|
Write to the file named by
|
||||||
|
.Ar file
|
||||||
|
instead of standard output.
|
||||||
|
.It Cm ibs= Ns Ar expr
|
||||||
|
Set the input block size to
|
||||||
|
.Ar expr
|
||||||
|
(defaults to 512).
|
||||||
|
.It Cm obs= Ns Ar expr
|
||||||
|
Set the output block size to
|
||||||
|
.Ar expr
|
||||||
|
(defaults to 512).
|
||||||
|
.It Cm bs= Ns Ar expr
|
||||||
|
Set the input and output block sizes to
|
||||||
|
.Ar expr .
|
||||||
|
Additionally, if no conversion other than
|
||||||
|
.Cm noerror ,
|
||||||
|
.Cm notrunc ,
|
||||||
|
or
|
||||||
|
.Cm sync
|
||||||
|
is specified, input blocks are copied as single output blocks, even
|
||||||
|
when the input block is short.
|
||||||
|
.It Cm skip= Ns Ar n
|
||||||
|
Skip
|
||||||
|
.Ar n
|
||||||
|
input blocks before starting to copy.
|
||||||
|
.It Cm seek= Ns Ar n
|
||||||
|
Skip
|
||||||
|
.Ar n
|
||||||
|
output blocks before starting to copy.
|
||||||
|
.It Cm count= Ns Ar n
|
||||||
|
Copy at most
|
||||||
|
.Ar n
|
||||||
|
input blocks.
|
||||||
|
.It Cm conv= Ns Ar value Ns Op , Ns Ar value Ns ...
|
||||||
|
Apply the conversions specified by
|
||||||
|
.Ar value .
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Cm lcase
|
||||||
|
Map uppercase characters to the corresponding lowercase character
|
||||||
|
using
|
||||||
|
.Fn tolower .
|
||||||
|
.It Cm ucase
|
||||||
|
Map lowercase characters to the corresponding uppercase character
|
||||||
|
using
|
||||||
|
.Fn toupper .
|
||||||
|
.It Cm swab
|
||||||
|
Swap each pair of bytes in the input block.
|
||||||
|
If there is an odd number of bytes in a block, the last one is
|
||||||
|
unmodified.
|
||||||
|
.It Cm noerror
|
||||||
|
In case of an error reading from the input, do not fail.
|
||||||
|
Instead, print a diagnostic message and a summary of the current
|
||||||
|
status.
|
||||||
|
.It Cm notrunc
|
||||||
|
Do not truncate the output file.
|
||||||
|
.It Cm sync
|
||||||
|
In case of a partial input block, pad with null bytes to form a
|
||||||
|
complete block.
|
||||||
|
.El
|
||||||
|
.El
|
||||||
|
.Sh STANDARDS
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility is compliant with the
|
||||||
|
.St -p1003.1-2008
|
||||||
|
specification, except that it does not implement the
|
||||||
|
.Cm block
|
||||||
|
and
|
||||||
|
.Cm unblock
|
||||||
|
conversions.
|
||||||
+237
@@ -0,0 +1,237 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static off_t ifull, ofull, ipart, opart;
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [operand...]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
parsesize(char *expr)
|
||||||
|
{
|
||||||
|
char *s = expr;
|
||||||
|
size_t n = 1;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
n *= strtoumax(s, &s, 10);
|
||||||
|
switch (*s) {
|
||||||
|
case 'k': n <<= 10; s++; break;
|
||||||
|
case 'b': n <<= 9; s++; break;
|
||||||
|
}
|
||||||
|
if (*s != 'x' || !s[1])
|
||||||
|
break;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
if (*s || n == 0)
|
||||||
|
eprintf("invalid block size expression '%s'\n", expr);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bswap(unsigned char *buf, size_t len)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
for (len &= ~1; len > 0; buf += 2, len -= 2) {
|
||||||
|
c = buf[0];
|
||||||
|
buf[0] = buf[1];
|
||||||
|
buf[1] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lcase(unsigned char *buf, size_t len)
|
||||||
|
{
|
||||||
|
for (; len > 0; buf++, len--)
|
||||||
|
buf[0] = tolower(buf[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ucase(unsigned char *buf, size_t len)
|
||||||
|
{
|
||||||
|
for (; len > 0; buf++, len--)
|
||||||
|
buf[0] = toupper(buf[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
summary(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%"PRIdMAX"+%"PRIdMAX" records in\n", (intmax_t)ifull, (intmax_t)ipart);
|
||||||
|
fprintf(stderr, "%"PRIdMAX"+%"PRIdMAX" records out\n", (intmax_t)ofull, (intmax_t)opart);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
enum {
|
||||||
|
LCASE = 1 << 0,
|
||||||
|
UCASE = 1 << 1,
|
||||||
|
SWAB = 1 << 2,
|
||||||
|
NOERROR = 1 << 3,
|
||||||
|
NOTRUNC = 1 << 4,
|
||||||
|
SYNC = 1 << 5,
|
||||||
|
} conv = 0;
|
||||||
|
char *arg, *val, *end;
|
||||||
|
const char *iname = "-", *oname = "-";
|
||||||
|
int ifd = 0, ofd = 1, eof = 0;
|
||||||
|
size_t len, bs = 0, ibs = 512, obs = 512, ipos = 0, opos = 0;
|
||||||
|
off_t skip = 0, seek = 0, count = -1;
|
||||||
|
ssize_t ret;
|
||||||
|
unsigned char *buf;
|
||||||
|
|
||||||
|
argv0 = argc ? (argc--, *argv++) : "dd";
|
||||||
|
for (; argc > 0; argc--, argv++) {
|
||||||
|
arg = *argv;
|
||||||
|
val = strchr(arg, '=');
|
||||||
|
if (!val)
|
||||||
|
usage();
|
||||||
|
*val++ = '\0';
|
||||||
|
if (strcmp(arg, "if") == 0) {
|
||||||
|
iname = val;
|
||||||
|
} else if (strcmp(arg, "of") == 0) {
|
||||||
|
oname = val;
|
||||||
|
} else if (strcmp(arg, "ibs") == 0) {
|
||||||
|
ibs = parsesize(val);
|
||||||
|
} else if (strcmp(arg, "obs") == 0) {
|
||||||
|
obs = parsesize(val);
|
||||||
|
} else if (strcmp(arg, "bs") == 0) {
|
||||||
|
bs = parsesize(val);
|
||||||
|
} else if (strcmp(arg, "skip") == 0) {
|
||||||
|
skip = estrtonum(val, 0, LLONG_MAX);
|
||||||
|
} else if (strcmp(arg, "seek") == 0) {
|
||||||
|
seek = estrtonum(val, 0, LLONG_MAX);
|
||||||
|
} else if (strcmp(arg, "count") == 0) {
|
||||||
|
count = estrtonum(val, 0, LLONG_MAX);
|
||||||
|
} else if (strcmp(arg, "conv") == 0) {
|
||||||
|
do {
|
||||||
|
end = strchr(val, ',');
|
||||||
|
if (end)
|
||||||
|
*end++ = '\0';
|
||||||
|
if (strcmp(val, "lcase") == 0)
|
||||||
|
conv |= LCASE;
|
||||||
|
else if (strcmp(val, "ucase") == 0)
|
||||||
|
conv |= UCASE;
|
||||||
|
else if (strcmp(val, "swab") == 0)
|
||||||
|
conv |= SWAB;
|
||||||
|
else if (strcmp(val, "noerror") == 0)
|
||||||
|
conv |= NOERROR;
|
||||||
|
else if (strcmp(val, "notrunc") == 0)
|
||||||
|
conv |= NOTRUNC;
|
||||||
|
else if (strcmp(val, "sync") == 0)
|
||||||
|
conv |= SYNC;
|
||||||
|
else
|
||||||
|
eprintf("unknown conv flag '%s'\n", val);
|
||||||
|
val = end;
|
||||||
|
} while (val);
|
||||||
|
} else {
|
||||||
|
weprintf("unknown operand '%s'\n", arg);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bs)
|
||||||
|
ibs = obs = bs;
|
||||||
|
if (strcmp(iname, "-") != 0) {
|
||||||
|
ifd = open(iname, O_RDONLY);
|
||||||
|
if (ifd < 0)
|
||||||
|
eprintf("open %s:", iname);
|
||||||
|
}
|
||||||
|
if (strcmp(oname, "-") != 0) {
|
||||||
|
ofd = open(oname, O_WRONLY | O_CREAT | (conv & NOTRUNC || seek ? 0 : O_TRUNC), 0666);
|
||||||
|
if (ofd < 0)
|
||||||
|
eprintf("open %s:", oname);
|
||||||
|
}
|
||||||
|
|
||||||
|
len = MAX(ibs, obs) + ibs;
|
||||||
|
buf = emalloc(len);
|
||||||
|
if (skip && lseek(ifd, skip * ibs, SEEK_SET) < 0) {
|
||||||
|
while (skip--) {
|
||||||
|
ret = read(ifd, buf, ibs);
|
||||||
|
if (ret < 0)
|
||||||
|
eprintf("read:");
|
||||||
|
if (ret == 0) {
|
||||||
|
eof = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (seek) {
|
||||||
|
if (!(conv & NOTRUNC) && ftruncate(ofd, seek * ibs) != 0)
|
||||||
|
eprintf("ftruncate:");
|
||||||
|
if (lseek(ofd, seek * ibs, SEEK_SET) < 0)
|
||||||
|
eprintf("lseek:");
|
||||||
|
/* XXX: handle non-seekable files */
|
||||||
|
}
|
||||||
|
while (!eof) {
|
||||||
|
while (ipos - opos < obs) {
|
||||||
|
if (ifull + ipart == count) {
|
||||||
|
eof = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = read(ifd, buf + ipos, ibs);
|
||||||
|
if (ret == 0) {
|
||||||
|
eof = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
weprintf("read:");
|
||||||
|
if (!(conv & NOERROR))
|
||||||
|
return 1;
|
||||||
|
summary();
|
||||||
|
if (!(conv & SYNC))
|
||||||
|
continue;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
if (ret < ibs) {
|
||||||
|
ipart++;
|
||||||
|
if (conv & SYNC) {
|
||||||
|
memset(buf + ipos + ret, 0, ibs - ret);
|
||||||
|
ret = ibs;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ifull++;
|
||||||
|
}
|
||||||
|
if (conv & SWAB)
|
||||||
|
bswap(buf + ipos, ret);
|
||||||
|
if (conv & LCASE)
|
||||||
|
lcase(buf + ipos, ret);
|
||||||
|
if (conv & UCASE)
|
||||||
|
ucase(buf + ipos, ret);
|
||||||
|
ipos += ret;
|
||||||
|
if (bs && !(conv & (SWAB | LCASE | UCASE)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ipos == opos)
|
||||||
|
break;
|
||||||
|
do {
|
||||||
|
ret = write(ofd, buf + opos, MIN(obs, ipos - opos));
|
||||||
|
if (ret < 0)
|
||||||
|
eprintf("write:");
|
||||||
|
if (ret == 0)
|
||||||
|
eprintf("write returned 0\n");
|
||||||
|
if (ret < obs)
|
||||||
|
opart++;
|
||||||
|
else
|
||||||
|
ofull++;
|
||||||
|
opos += ret;
|
||||||
|
} while (ipos - opos >= (eof ? 1 : obs));
|
||||||
|
if (opos < ipos)
|
||||||
|
memmove(buf, buf + opos, ipos - opos);
|
||||||
|
ipos -= opos;
|
||||||
|
opos = 0;
|
||||||
|
}
|
||||||
|
summary();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt DIRNAME 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm dirname
|
||||||
|
.Nd strip final path component
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Ar path
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
writes
|
||||||
|
.Ar path
|
||||||
|
with its final path component removed to stdout.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr basename 1 ,
|
||||||
|
.Xr dirname 3
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s path\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
ARGBEGIN {
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (argc != 1)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
puts(dirname(argv[0]));
|
||||||
|
|
||||||
|
return fshut(stdout, "<stdout>");
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt DU 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm du
|
||||||
|
.Nd display disk usage statistics
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl a | s
|
||||||
|
.Op Fl d Ar depth
|
||||||
|
.Op Fl h
|
||||||
|
.Op Fl k
|
||||||
|
.Op Fl H | L | P
|
||||||
|
.Op Fl x
|
||||||
|
.Op Ar file ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
displays the file system block usage for each
|
||||||
|
.Ar file
|
||||||
|
argument and for each directory in the file hierarchy rooted in directory
|
||||||
|
argument.
|
||||||
|
If no
|
||||||
|
.Ar file
|
||||||
|
is specified, the block usage of the hierarchy rooted in the current directory
|
||||||
|
is displayed.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl a
|
||||||
|
Display an entry for each file in the file hierarchy.
|
||||||
|
.It Fl s
|
||||||
|
Display only the grand total for the specified files.
|
||||||
|
.It Fl d Ar depth
|
||||||
|
Maximum directory depth to print files and directories.
|
||||||
|
.It Fl h
|
||||||
|
Enable human-readable output.
|
||||||
|
.It Fl k
|
||||||
|
By default all sizes are reported in 512-byte block counts.
|
||||||
|
The
|
||||||
|
.Fl k
|
||||||
|
option causes the numbers to be reported in kilobyte counts.
|
||||||
|
.It Fl H
|
||||||
|
Only dereference symbolic links that are passed as command line arguments when
|
||||||
|
recursively traversing directories.
|
||||||
|
.It Fl L
|
||||||
|
Always dereference symbolic links while recursively traversing directories.
|
||||||
|
.It Fl P
|
||||||
|
Don't dereference symbolic links.
|
||||||
|
This is the default.
|
||||||
|
.It Fl x
|
||||||
|
Do not traverse file systems mount points.
|
||||||
|
.El
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Op Fl dhP
|
||||||
|
flags are an extension to that specification.
|
||||||
+167
@@ -0,0 +1,167 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <search.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "fs.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static size_t maxdepth = SIZE_MAX;
|
||||||
|
static size_t blksize = 512;
|
||||||
|
|
||||||
|
static int aflag = 0;
|
||||||
|
static int sflag = 0;
|
||||||
|
static int hflag = 0;
|
||||||
|
|
||||||
|
struct file {
|
||||||
|
dev_t devno;
|
||||||
|
ino_t inode;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
printpath(off_t n, const char *path)
|
||||||
|
{
|
||||||
|
if (hflag)
|
||||||
|
printf("%s\t%s\n", humansize(n * blksize), path);
|
||||||
|
else
|
||||||
|
printf("%jd\t%s\n", (intmax_t)n, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static off_t
|
||||||
|
nblks(blkcnt_t blocks)
|
||||||
|
{
|
||||||
|
return (512 * blocks + blksize - 1) / blksize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmp(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
const struct file *f1 = p1, *f2 = p2;
|
||||||
|
|
||||||
|
if (f1->devno > f2->devno)
|
||||||
|
return -1;
|
||||||
|
if (f1->devno < f2->devno)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* f1->devno == f2->devno */
|
||||||
|
if (f1->inode < f2->inode)
|
||||||
|
return -1;
|
||||||
|
if (f1->inode > f2->inode)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
duplicated(dev_t dev, ino_t ino)
|
||||||
|
{
|
||||||
|
static void *tree;
|
||||||
|
struct file **fpp, *fp, file = {dev, ino};
|
||||||
|
|
||||||
|
if ((fpp = tsearch(&file, &tree, cmp)) == NULL)
|
||||||
|
eprintf("%s:", argv0);
|
||||||
|
|
||||||
|
if (*fpp != &file)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* new file added */
|
||||||
|
fp = emalloc(sizeof(*fp));
|
||||||
|
*fp = file;
|
||||||
|
*fpp = fp;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
du(int dirfd, const char *path, struct stat *st, void *data, struct recursor *r)
|
||||||
|
{
|
||||||
|
off_t *total = data, subtotal;
|
||||||
|
|
||||||
|
subtotal = nblks(st->st_blocks);
|
||||||
|
if (S_ISDIR(st->st_mode)) {
|
||||||
|
recurse(dirfd, path, &subtotal, r);
|
||||||
|
} else if (r->follow != 'P' || st->st_nlink > 1) {
|
||||||
|
if (duplicated(st->st_dev, st->st_ino))
|
||||||
|
goto print;
|
||||||
|
}
|
||||||
|
|
||||||
|
*total += subtotal;
|
||||||
|
|
||||||
|
print:
|
||||||
|
if (!r->depth)
|
||||||
|
printpath(*total, r->path);
|
||||||
|
else if (!sflag && r->depth <= maxdepth && (S_ISDIR(st->st_mode) || aflag))
|
||||||
|
printpath(subtotal, r->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-a | -s] [-d depth] [-h] [-k] [-H | -L | -P] [-x] [file ...]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct recursor r = { .fn = du, .follow = 'P' };
|
||||||
|
off_t n = 0;
|
||||||
|
int kflag = 0, dflag = 0;
|
||||||
|
char *bsize;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'a':
|
||||||
|
aflag = 1;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
dflag = 1;
|
||||||
|
maxdepth = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
hflag = 1;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
kflag = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
sflag = 1;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
r.flags |= SAMEDEV;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
case 'L':
|
||||||
|
case 'P':
|
||||||
|
r.follow = ARGC();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if ((aflag && sflag) || (dflag && sflag))
|
||||||
|
usage();
|
||||||
|
|
||||||
|
bsize = getenv("BLOCKSIZE");
|
||||||
|
if (bsize)
|
||||||
|
blksize = estrtonum(bsize, 1, MIN(LLONG_MAX, SIZE_MAX));
|
||||||
|
if (kflag)
|
||||||
|
blksize = 1024;
|
||||||
|
|
||||||
|
if (!argc) {
|
||||||
|
recurse(AT_FDCWD, ".", &n, &r);
|
||||||
|
} else {
|
||||||
|
for (; *argv; argc--, argv++) {
|
||||||
|
n = 0;
|
||||||
|
recurse(AT_FDCWD, *argv, &n, &r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fshut(stdout, "<stdout>") || recurse_status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt ECHO 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm echo
|
||||||
|
.Nd print arguments
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl n
|
||||||
|
.Op Ar string ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
writes each
|
||||||
|
.Ar string
|
||||||
|
to stdout, separated by spaces and terminated by
|
||||||
|
a newline.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl n
|
||||||
|
Do not print the terminating newline.
|
||||||
|
.El
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Op Fl n
|
||||||
|
flag is an extension to that specification.
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int nflag = 0;
|
||||||
|
|
||||||
|
argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
|
||||||
|
|
||||||
|
if (*argv && !strcmp(*argv, "-n")) {
|
||||||
|
nflag = 1;
|
||||||
|
argc--, argv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; *argv; argc--, argv++)
|
||||||
|
putword(stdout, *argv);
|
||||||
|
if (!nflag)
|
||||||
|
putchar('\n');
|
||||||
|
|
||||||
|
return fshut(stdout, "<stdout>");
|
||||||
|
}
|
||||||
+238
@@ -0,0 +1,238 @@
|
|||||||
|
.Dd December 27, 2016
|
||||||
|
.Dt ED 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm ed
|
||||||
|
.Nd text editor
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl s
|
||||||
|
.Op Fl p Ar string
|
||||||
|
.Op Ar file
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
is the standard text editor.
|
||||||
|
It performs line-oriented operations on a buffer; The buffer's contents are
|
||||||
|
manipulated in command mode and text is written to the buffer in input mode.
|
||||||
|
Command mode is the default.
|
||||||
|
To exit input mode enter a dot ('.') on a line of its own.
|
||||||
|
.Pp
|
||||||
|
If
|
||||||
|
.Nm
|
||||||
|
is invoked with a file as an argument, it will simulate an edit command and read
|
||||||
|
the file's contents into a buffer.
|
||||||
|
Changes to this buffer are local to
|
||||||
|
.Nm
|
||||||
|
until a write command is given.
|
||||||
|
.Pp
|
||||||
|
.Nm
|
||||||
|
uses the basic regular expression syntax and allows any character but space and
|
||||||
|
newline to be used as a delimiter in regular expressions.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl s
|
||||||
|
Suppress diagnostic messages
|
||||||
|
.It Fl p Ar string
|
||||||
|
Use
|
||||||
|
.Ar string
|
||||||
|
as a prompt when in command mode
|
||||||
|
.El
|
||||||
|
.Sh EXTENDED DESCRIPTION
|
||||||
|
.Ss Addresses
|
||||||
|
Commands operate on addresses.
|
||||||
|
Addresses are used to refer to lines within the buffer.
|
||||||
|
Address ranges may have spaces before and after the separator.
|
||||||
|
Unless otherwise specified, 0 is an invalid address.
|
||||||
|
The following symbols are valid addresses:
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It n
|
||||||
|
The nth line.
|
||||||
|
.It .
|
||||||
|
The current line, or "dot".
|
||||||
|
.It $
|
||||||
|
The last line.
|
||||||
|
.It +
|
||||||
|
The next line.
|
||||||
|
.It +n
|
||||||
|
The nth next line.
|
||||||
|
.It ^ or -
|
||||||
|
The previous line.
|
||||||
|
.It ^n or -n
|
||||||
|
The nth previous line.
|
||||||
|
.It x,y
|
||||||
|
The range of lines from x to y.
|
||||||
|
The default value of x is 1, and the default value of y is $.
|
||||||
|
.It x;y
|
||||||
|
As above, except that the current line is set to x.
|
||||||
|
Omitting x in this case uses the current line as the default value.
|
||||||
|
.It /re/
|
||||||
|
The next line matching re.
|
||||||
|
.It ?re?
|
||||||
|
The last line matching re.
|
||||||
|
.It 'c
|
||||||
|
The line marked by c. See k below.
|
||||||
|
.El
|
||||||
|
.Ss Commands
|
||||||
|
.Nm
|
||||||
|
expects to see one command per line, with the following exception: commands may
|
||||||
|
be suffixed with either a list, number, or print command.
|
||||||
|
These suffixed commands are run after the command they're suffixed to has
|
||||||
|
executed.
|
||||||
|
.Pp
|
||||||
|
The following is the list of commands that
|
||||||
|
.Nm
|
||||||
|
knows about.
|
||||||
|
The parentheses contain the default addresses that a command uses.
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It (.)a
|
||||||
|
Append text after the addressed line.
|
||||||
|
The dot is set to the last line entered.
|
||||||
|
If no text was entered, the dot is set to the addressed line.
|
||||||
|
An address of 0 appends to the start of the buffer.
|
||||||
|
.It (.,.)c
|
||||||
|
Delete the addressed lines and then accept input to replace them.
|
||||||
|
The dot is set to the last line entered.
|
||||||
|
If no text was entered, the dot is set to the line before the deleted lines.
|
||||||
|
.It (.,.)d
|
||||||
|
Delete the addressed lines.
|
||||||
|
If there is a line after the deleted range, the dot is set to it.
|
||||||
|
Otherwise, the dot is set to the line before the deleted range.
|
||||||
|
.It e Ar file
|
||||||
|
Delete the contents of the buffer and load in
|
||||||
|
.Ar file
|
||||||
|
for editing, printing the bytes read to standard output.
|
||||||
|
If no filename is given,
|
||||||
|
.Nm
|
||||||
|
uses the currently remembered filename.
|
||||||
|
The remembered filename is set to
|
||||||
|
.Ar file
|
||||||
|
for later use.
|
||||||
|
.It E Ar file
|
||||||
|
As above, but without warning if the current buffer has unsaved changes.
|
||||||
|
.It f Ar file
|
||||||
|
Set the currently remembered filename to
|
||||||
|
.Ar file
|
||||||
|
, or print the currently remembered filename if
|
||||||
|
.Ar file
|
||||||
|
is omitted.
|
||||||
|
.It (1,$)g/re/command
|
||||||
|
Apply command to lines matching re.
|
||||||
|
The dot is set to the matching line before command is executed.
|
||||||
|
When each matching line has been operated on, the dot is set to the last line
|
||||||
|
operated on.
|
||||||
|
If no lines match then the dot remains unchanged.
|
||||||
|
The command used may not be g, G, v, or V.
|
||||||
|
.It (1,$)G/re/
|
||||||
|
Interactively edit the range of line addresses that match re.
|
||||||
|
The dot is set to the matching line and printed before a command is input.
|
||||||
|
When each matching line has been operated on, the dot is set to the last line
|
||||||
|
operated on.
|
||||||
|
If no lines match then the dot remains unchanged.
|
||||||
|
The command used may not be a, c, i, g, G, v, or V.
|
||||||
|
.It h
|
||||||
|
Print the reason for the most recent error.
|
||||||
|
.It H
|
||||||
|
Toggle error explanations.
|
||||||
|
If on, the above behaviour is produced on all subsequent errors.
|
||||||
|
.It (.)i
|
||||||
|
Insert text into the buffer before the addressed line.
|
||||||
|
The dot is set to the last line entered.
|
||||||
|
If no text was entered, the dot is set to the addressed line
|
||||||
|
.It (.,.+1)j
|
||||||
|
Join two lines together.
|
||||||
|
If only one address is given, nothing happens.
|
||||||
|
The dot is set to the newly joined line.
|
||||||
|
.It (.)kc
|
||||||
|
Mark the line with the lower case character c. The dot is unchanged.
|
||||||
|
.It (.,.)l
|
||||||
|
Unambiguously print the addressed lines.
|
||||||
|
The dot is set to the last line written.
|
||||||
|
.It (.,.)m(.)
|
||||||
|
Move lines in the buffer to the line address on the right hand side.
|
||||||
|
An address of 0 on the right hand side moves to the start of the buffer.
|
||||||
|
The dot is set to the last line moved.
|
||||||
|
.It (.,.)n
|
||||||
|
Print the addressed lines and their numbers.
|
||||||
|
The dot is set to the last line printed.
|
||||||
|
.It (.,.)p
|
||||||
|
Print the addressed lines.
|
||||||
|
The dot is set to the last line printed.
|
||||||
|
.It P
|
||||||
|
Toggle the prompt.
|
||||||
|
Defaults to off, but is switched on if the -p flag is used.
|
||||||
|
.It q
|
||||||
|
Quit
|
||||||
|
.Nm
|
||||||
|
, warning if there are unsaved changes.
|
||||||
|
.It Q
|
||||||
|
As above, but without warning if the current buffer has unsaved changes.
|
||||||
|
.It ($)r Ar file
|
||||||
|
Read in
|
||||||
|
.Ar file
|
||||||
|
and append it to the current buffer, printing the bytes read to standard output.
|
||||||
|
The currently remembered filename isn't changed unless it's empty.
|
||||||
|
An address of 0 reads the file into the start of the buffer.
|
||||||
|
.It (.,.)s/re/replacement/flags
|
||||||
|
Substitute re for replacement in lines matching re.
|
||||||
|
An & within replacement is replaced with the whole string matched by re.
|
||||||
|
Backrefs can be used with the form \\n, where n is a positive non-zero integer.
|
||||||
|
When % is the only character in replacement, it is substituted for the
|
||||||
|
replacement string from the last substitute command.
|
||||||
|
If a newline is part of replacement then the matched string is split into two
|
||||||
|
lines; this cannot be done as part of a g or v command.
|
||||||
|
If flags contains an integer n, then the nth match is replaced.
|
||||||
|
If flags contains g, all matches are replaced.
|
||||||
|
The dot is set to the last line matched.
|
||||||
|
.It (.,.)t(.)
|
||||||
|
As m, but copying instead of moving.
|
||||||
|
The dot is set to the last line added.
|
||||||
|
.It u
|
||||||
|
Undo the last change.
|
||||||
|
The dot is set to whatever it was before the undone command was performed.
|
||||||
|
.It (1.$)v/re/command
|
||||||
|
As with g, but operating on lines that don't match re.
|
||||||
|
.It (1.$)V/re/
|
||||||
|
As with G, but operating on lines that don't match re.
|
||||||
|
.It (1,$)w Ar file
|
||||||
|
Write the addressed lines to
|
||||||
|
.Ar file
|
||||||
|
, overwriting its previous contents if the file exists, and print the number of
|
||||||
|
bytes written.
|
||||||
|
If no filename is given the currently remembered filename will be used instead.
|
||||||
|
The dot is unchanged.
|
||||||
|
.It (1,$)W Ar file
|
||||||
|
As above, but instead of overwriting the contents of
|
||||||
|
.Ar file
|
||||||
|
the addressed lines are appended to
|
||||||
|
.Ar file
|
||||||
|
instead.
|
||||||
|
.It (.+1)
|
||||||
|
Print the addressed line.
|
||||||
|
Sets the dot to that line.
|
||||||
|
.It ($)=
|
||||||
|
Print the line number of the addressed line.
|
||||||
|
The dot is unchanged.
|
||||||
|
.It &
|
||||||
|
Repeat the last command.
|
||||||
|
.It ! Ar command
|
||||||
|
Execute
|
||||||
|
.Ar command
|
||||||
|
using sh.
|
||||||
|
If the first character of
|
||||||
|
.Ar command
|
||||||
|
is '!' then it is replaced with the text of the previous command.
|
||||||
|
An unescaped % is replaced with the currently remembered filename.
|
||||||
|
! does not process escape characters.
|
||||||
|
When
|
||||||
|
.Ar command
|
||||||
|
returns a '!' is printed.
|
||||||
|
The dot is unchanged.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr sed 1 ,
|
||||||
|
.Xr regexp 3
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
Except where noted here:
|
||||||
|
g and v operate on single commands rather than lists delimited with '\e'.
|
||||||
|
e, E, r, w, and W commands cannot accept shell escapes.
|
||||||
+1650
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt ENV 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm env
|
||||||
|
.Nd modify the environment, then print it or run a command
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl i
|
||||||
|
.Oo Fl u Ar var Oc ...
|
||||||
|
.Oo Ar var Ns = Ns Ar value Oc ...
|
||||||
|
.Oo Ar cmd Oo arg ... Oc Oc
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
unsets each
|
||||||
|
.Ar var ,
|
||||||
|
then adds or sets each
|
||||||
|
.Ar ( var , value )
|
||||||
|
tuple in the environment.
|
||||||
|
.Pp
|
||||||
|
If
|
||||||
|
.Ar cmd
|
||||||
|
is given, it is executed in this new environment;
|
||||||
|
otherwise, the modified environment is printed to stdout.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl i
|
||||||
|
Completely ignore the existing environment and execute
|
||||||
|
.Ar cmd
|
||||||
|
only with each
|
||||||
|
.Ar ( var , value )
|
||||||
|
tuple specified.
|
||||||
|
.It Fl u Ar var
|
||||||
|
Unset
|
||||||
|
.Ar var
|
||||||
|
in the environment.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr printenv 1 ,
|
||||||
|
.Xr putenv 3 ,
|
||||||
|
.Xr environ 7
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Op Fl u
|
||||||
|
flag is an extension to that specification.
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
extern char **environ;
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-i] [-u var] ... [var=value] ... [cmd [arg ...]]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int savederrno;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'i':
|
||||||
|
*environ = NULL;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
if (unsetenv(EARGF(usage())) < 0)
|
||||||
|
eprintf("unsetenv:");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
for (; *argv && strchr(*argv, '='); argc--, argv++)
|
||||||
|
putenv(*argv);
|
||||||
|
|
||||||
|
if (*argv) {
|
||||||
|
execvp(*argv, argv);
|
||||||
|
savederrno = errno;
|
||||||
|
weprintf("execvp %s:", *argv);
|
||||||
|
_exit(126 + (savederrno == ENOENT));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; *environ; environ++)
|
||||||
|
puts(*environ);
|
||||||
|
|
||||||
|
return fshut(stdout, "<stdout>");
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt EXPAND 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm expand
|
||||||
|
.Nd expand tabs to spaces
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl i
|
||||||
|
.Op Fl t Ar tablist
|
||||||
|
.Op Ar file ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
converts tabs to spaces in each
|
||||||
|
.Ar file
|
||||||
|
as specified in
|
||||||
|
.Ar tablist .
|
||||||
|
If no file is given,
|
||||||
|
.Nm
|
||||||
|
reads from stdin.
|
||||||
|
.Pp
|
||||||
|
Backspace characters are preserved and decrement the column count
|
||||||
|
for tab calculations.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl i
|
||||||
|
Only expand tabs at the beginning of lines, i.e. expand each
|
||||||
|
line until a character different from '\et' and ' ' is reached.
|
||||||
|
.It Fl t Ar tablist
|
||||||
|
Specify tab size or tabstops.
|
||||||
|
.Ar tablist
|
||||||
|
is a list of one (in the former case) or multiple (in the latter case)
|
||||||
|
strictly positive integers separated by ' ' or ','.
|
||||||
|
.Pp
|
||||||
|
The default
|
||||||
|
.Ar tablist
|
||||||
|
is "8".
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr fold 1 ,
|
||||||
|
.Xr unexpand 1
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Op Fl i
|
||||||
|
flag is an extension to that specification.
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "utf.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static int iflag = 0;
|
||||||
|
static size_t *tablist = NULL;
|
||||||
|
static size_t tablistlen = 0;
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
parselist(const char *s)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
char *p, *tmp;
|
||||||
|
|
||||||
|
tmp = estrdup(s);
|
||||||
|
for (i = 0; (p = strsep(&tmp, " ,")); i++) {
|
||||||
|
if (*p == '\0')
|
||||||
|
eprintf("empty field in tablist\n");
|
||||||
|
tablist = ereallocarray(tablist, i + 1, sizeof(*tablist));
|
||||||
|
tablist[i] = estrtonum(p, 1, MIN(LLONG_MAX, SIZE_MAX));
|
||||||
|
if (i > 0 && tablist[i - 1] >= tablist[i])
|
||||||
|
eprintf("tablist must be ascending\n");
|
||||||
|
}
|
||||||
|
tablist = ereallocarray(tablist, i + 1, sizeof(*tablist));
|
||||||
|
/* tab length = 1 for the overflowing case later in the matcher */
|
||||||
|
tablist[i] = 1;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
expand(const char *file, FILE *fp)
|
||||||
|
{
|
||||||
|
size_t bol = 1, col = 0, i;
|
||||||
|
Rune r;
|
||||||
|
|
||||||
|
while (efgetrune(&r, fp, file)) {
|
||||||
|
switch (r) {
|
||||||
|
case '\t':
|
||||||
|
if (tablistlen == 1)
|
||||||
|
i = 0;
|
||||||
|
else for (i = 0; i < tablistlen; i++)
|
||||||
|
if (col < tablist[i])
|
||||||
|
break;
|
||||||
|
if (bol || !iflag) {
|
||||||
|
do {
|
||||||
|
col++;
|
||||||
|
putchar(' ');
|
||||||
|
} while (col % tablist[i]);
|
||||||
|
} else {
|
||||||
|
putchar('\t');
|
||||||
|
col = tablist[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\b':
|
||||||
|
bol = 0;
|
||||||
|
if (col)
|
||||||
|
col--;
|
||||||
|
putchar('\b');
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
bol = 1;
|
||||||
|
col = 0;
|
||||||
|
putchar('\n');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
col++;
|
||||||
|
if (r != ' ')
|
||||||
|
bol = 0;
|
||||||
|
efputrune(&r, stdout, "<stdout>");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-i] [-t tablist] [file ...]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
int ret = 0;
|
||||||
|
char *tl = "8";
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'i':
|
||||||
|
iflag = 1;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
tl = EARGF(usage());
|
||||||
|
if (!*tl)
|
||||||
|
eprintf("tablist cannot be empty\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
tablistlen = parselist(tl);
|
||||||
|
|
||||||
|
if (!argc) {
|
||||||
|
expand("<stdin>", stdin);
|
||||||
|
} else {
|
||||||
|
for (; *argv; argc--, argv++) {
|
||||||
|
if (!strcmp(*argv, "-")) {
|
||||||
|
*argv = "<stdin>";
|
||||||
|
fp = stdin;
|
||||||
|
} else if (!(fp = fopen(*argv, "r"))) {
|
||||||
|
weprintf("fopen %s:", *argv);
|
||||||
|
ret = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
expand(*argv, fp);
|
||||||
|
if (fp != stdin && fshut(fp, *argv))
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt EXPR 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm expr
|
||||||
|
.Nd evaluate expression
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Ar expression
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
evaluates
|
||||||
|
.Ar expression
|
||||||
|
and writes the result to stdout.
|
||||||
|
.Pp
|
||||||
|
There are two elemental expressions,
|
||||||
|
.Sy integer
|
||||||
|
and
|
||||||
|
.Sy string .
|
||||||
|
Let
|
||||||
|
.Sy expr
|
||||||
|
be a non-elemental expression and
|
||||||
|
.Sy expr1 ,
|
||||||
|
.Sy expr2
|
||||||
|
arbitrary expressions.
|
||||||
|
Then
|
||||||
|
.Sy expr
|
||||||
|
has the recursive form
|
||||||
|
.Sy expr = [(] expr1 operand expr2 [)] .
|
||||||
|
.Pp
|
||||||
|
With
|
||||||
|
.Sy operand
|
||||||
|
being in order of increasing precedence:
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It |
|
||||||
|
Evaluate to
|
||||||
|
.Sy expr1
|
||||||
|
if it is neither an empty string nor 0; otherwise evaluate to
|
||||||
|
.Sy expr2 .
|
||||||
|
.It &
|
||||||
|
Evaluate to
|
||||||
|
.Sy expr1
|
||||||
|
if
|
||||||
|
.Sy expr1
|
||||||
|
and
|
||||||
|
.Sy expr2
|
||||||
|
are neither empty strings nor 0; otherwise evaluate to 0.
|
||||||
|
.It = > >= < <= !=
|
||||||
|
If
|
||||||
|
.Sy expr1
|
||||||
|
and
|
||||||
|
.Sy expr2
|
||||||
|
are integers, evaluate to 1 if the relation is true and 0 if it is false.
|
||||||
|
If
|
||||||
|
.Sy expr1
|
||||||
|
and
|
||||||
|
.Sy expr2
|
||||||
|
are strings, apply the relation to the return value of
|
||||||
|
.Xr strcmp 3 .
|
||||||
|
.It + -
|
||||||
|
If
|
||||||
|
.Sy expr1
|
||||||
|
and
|
||||||
|
.Sy expr2
|
||||||
|
are integers, evaluate to their sum or subtraction.
|
||||||
|
.It * / %
|
||||||
|
If
|
||||||
|
.Sy expr1
|
||||||
|
and
|
||||||
|
.Sy expr2
|
||||||
|
are integers, evaluate to their multiplication, division or remainder.
|
||||||
|
.It :
|
||||||
|
Evaluate to the number of characters matched in
|
||||||
|
.Sy expr1
|
||||||
|
against
|
||||||
|
.Sy expr2 . expr2
|
||||||
|
is anchored with an implicit '^'.
|
||||||
|
.Pp
|
||||||
|
You can't directly match the empty string, since zero matched characters
|
||||||
|
resolve equally to a failed match.
|
||||||
|
To work around this limitation, use "expr X'' : 'X$' instead of "expr ''
|
||||||
|
: '$'"
|
||||||
|
.El
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It 0
|
||||||
|
.Ar expression
|
||||||
|
is neither an empty string nor 0.
|
||||||
|
.It 1
|
||||||
|
.Ar expression
|
||||||
|
is an empty string or 0.
|
||||||
|
.It 2
|
||||||
|
.Ar expression
|
||||||
|
is invalid.
|
||||||
|
.It > 2
|
||||||
|
An error occurred.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr test 1
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "utf.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/* tokens, one-character operators represent themselves */
|
||||||
|
enum {
|
||||||
|
VAL = CHAR_MAX + 1, GE, LE, NE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct val {
|
||||||
|
char *str;
|
||||||
|
long long num;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
tonum(struct val *v)
|
||||||
|
{
|
||||||
|
const char *errstr;
|
||||||
|
long long d;
|
||||||
|
|
||||||
|
/* check if val is the result of an earlier calculation */
|
||||||
|
if (!v->str)
|
||||||
|
return;
|
||||||
|
|
||||||
|
d = strtonum(v->str, LLONG_MIN, LLONG_MAX, &errstr);
|
||||||
|
if (errstr)
|
||||||
|
enprintf(2, "error: expected integer, got %s\n", v->str);
|
||||||
|
v->num = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ezero(struct val *v)
|
||||||
|
{
|
||||||
|
if (v->num != 0)
|
||||||
|
return;
|
||||||
|
enprintf(2, "division by zero\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
valcmp(struct val *a, struct val *b)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
const char *err1, *err2;
|
||||||
|
long long d1, d2;
|
||||||
|
|
||||||
|
d1 = strtonum(a->str, LLONG_MIN, LLONG_MAX, &err1);
|
||||||
|
d2 = strtonum(b->str, LLONG_MIN, LLONG_MAX, &err2);
|
||||||
|
|
||||||
|
if (!err1 && !err2) {
|
||||||
|
ret = (d1 > d2) - (d1 < d2);
|
||||||
|
} else {
|
||||||
|
ret = strcmp(a->str, b->str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
match(struct val *vstr, struct val *vregx, struct val *ret)
|
||||||
|
{
|
||||||
|
regex_t re;
|
||||||
|
regmatch_t matches[2];
|
||||||
|
size_t anchlen;
|
||||||
|
char *s, *p, *anchreg;
|
||||||
|
char *str = vstr->str, *regx = vregx->str;
|
||||||
|
|
||||||
|
/* anchored regex */
|
||||||
|
anchlen = strlen(regx) + 1 + 1;
|
||||||
|
anchreg = emalloc(anchlen);
|
||||||
|
estrlcpy(anchreg, "^", anchlen);
|
||||||
|
estrlcat(anchreg, regx, anchlen);
|
||||||
|
enregcomp(3, &re, anchreg, 0);
|
||||||
|
free(anchreg);
|
||||||
|
|
||||||
|
if (regexec(&re, str, 2, matches, 0)) {
|
||||||
|
regfree(&re);
|
||||||
|
ret->str = re.re_nsub ? "" : NULL;
|
||||||
|
return;
|
||||||
|
} else if (re.re_nsub) {
|
||||||
|
regfree(&re);
|
||||||
|
|
||||||
|
s = str + matches[1].rm_so;
|
||||||
|
p = str + matches[1].rm_eo;
|
||||||
|
*p = '\0';
|
||||||
|
ret->str = enstrdup(3, s);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
regfree(&re);
|
||||||
|
str += matches[0].rm_so;
|
||||||
|
ret->num = utfnlen(str, matches[0].rm_eo - matches[0].rm_so);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
doop(int *ophead, int *opp, struct val *valhead, struct val *valp)
|
||||||
|
{
|
||||||
|
struct val ret = { .str = NULL, .num = 0 }, *a, *b;
|
||||||
|
int op;
|
||||||
|
|
||||||
|
/* an operation "a op b" needs an operator and two values */
|
||||||
|
if (opp[-1] == '(')
|
||||||
|
enprintf(2, "syntax error: extra (\n");
|
||||||
|
if (valp - valhead < 2)
|
||||||
|
enprintf(2, "syntax error: missing expression or extra operator\n");
|
||||||
|
|
||||||
|
a = valp - 2;
|
||||||
|
b = valp - 1;
|
||||||
|
op = opp[-1];
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case '|':
|
||||||
|
if ( a->str && *a->str) ret.str = a->str;
|
||||||
|
else if (!a->str && a->num) ret.num = a->num;
|
||||||
|
else if ( b->str && *b->str) ret.str = b->str;
|
||||||
|
else ret.num = b->num;
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
if (((a->str && *a->str) || a->num) &&
|
||||||
|
((b->str && *b->str) || b->num)) {
|
||||||
|
ret.str = a->str;
|
||||||
|
ret.num = a->num;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '=': ret.num = (valcmp(a, b) == 0); break;
|
||||||
|
case '>': ret.num = (valcmp(a, b) > 0); break;
|
||||||
|
case GE : ret.num = (valcmp(a, b) >= 0); break;
|
||||||
|
case '<': ret.num = (valcmp(a, b) < 0); break;
|
||||||
|
case LE : ret.num = (valcmp(a, b) <= 0); break;
|
||||||
|
case NE : ret.num = (valcmp(a, b) != 0); break;
|
||||||
|
|
||||||
|
case '+': tonum(a); tonum(b); ret.num = a->num + b->num; break;
|
||||||
|
case '-': tonum(a); tonum(b); ret.num = a->num - b->num; break;
|
||||||
|
case '*': tonum(a); tonum(b); ret.num = a->num * b->num; break;
|
||||||
|
case '/': tonum(a); tonum(b); ezero(b); ret.num = a->num / b->num; break;
|
||||||
|
case '%': tonum(a); tonum(b); ezero(b); ret.num = a->num % b->num; break;
|
||||||
|
|
||||||
|
case ':': match(a, b, &ret); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
valp[-2] = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lex(char *s, struct val *v)
|
||||||
|
{
|
||||||
|
int type = VAL;
|
||||||
|
char *ops = "|&=><+-*/%():";
|
||||||
|
|
||||||
|
if (s[0] && strchr(ops, s[0]) && !s[1]) {
|
||||||
|
/* one-char operand */
|
||||||
|
type = s[0];
|
||||||
|
} else if (s[0] && strchr("><!", s[0]) && s[1] == '=' && !s[2]) {
|
||||||
|
/* two-char operand */
|
||||||
|
type = (s[0] == '>') ? GE : (s[0] == '<') ? LE : NE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse(char *expr[], int numexpr)
|
||||||
|
{
|
||||||
|
struct val *valhead, *valp, v = { .str = NULL, .num = 0 };
|
||||||
|
int *ophead, *opp, type, lasttype = 0;
|
||||||
|
char prec[] = {
|
||||||
|
[ 0 ] = 0, [VAL] = 0, ['('] = 0, [')'] = 0,
|
||||||
|
['|'] = 1,
|
||||||
|
['&'] = 2,
|
||||||
|
['='] = 3, ['>'] = 3, [GE] = 3, ['<'] = 3, [LE] = 3, [NE] = 3,
|
||||||
|
['+'] = 4, ['-'] = 4,
|
||||||
|
['*'] = 5, ['/'] = 5, ['%'] = 5,
|
||||||
|
[':'] = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
valp = valhead = enreallocarray(3, NULL, numexpr, sizeof(*valp));
|
||||||
|
opp = ophead = enreallocarray(3, NULL, numexpr, sizeof(*opp));
|
||||||
|
for (; *expr; expr++) {
|
||||||
|
switch ((type = lex(*expr, &v))) {
|
||||||
|
case VAL:
|
||||||
|
/* treatment of *expr is not known until
|
||||||
|
* doop(); treat as a string for now */
|
||||||
|
valp->str = *expr;
|
||||||
|
valp++;
|
||||||
|
break;
|
||||||
|
case '(':
|
||||||
|
*opp++ = type;
|
||||||
|
break;
|
||||||
|
case ')':
|
||||||
|
if (lasttype == '(')
|
||||||
|
enprintf(2, "syntax error: empty ( )\n");
|
||||||
|
while (opp > ophead && opp[-1] != '(')
|
||||||
|
doop(ophead, opp--, valhead, valp--);
|
||||||
|
if (opp == ophead)
|
||||||
|
enprintf(2, "syntax error: extra )\n");
|
||||||
|
opp--;
|
||||||
|
break;
|
||||||
|
default: /* operator */
|
||||||
|
if (prec[lasttype])
|
||||||
|
enprintf(2, "syntax error: extra operator\n");
|
||||||
|
while (opp > ophead && prec[opp[-1]] >= prec[type])
|
||||||
|
doop(ophead, opp--, valhead, valp--);
|
||||||
|
*opp++ = type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lasttype = type;
|
||||||
|
v.str = NULL;
|
||||||
|
v.num = 0;
|
||||||
|
}
|
||||||
|
while (opp > ophead)
|
||||||
|
doop(ophead, opp--, valhead, valp--);
|
||||||
|
if (valp == valhead)
|
||||||
|
enprintf(2, "syntax error: missing expression\n");
|
||||||
|
if (--valp > valhead)
|
||||||
|
enprintf(2, "syntax error: extra expression\n");
|
||||||
|
|
||||||
|
if (valp->str)
|
||||||
|
puts(valp->str);
|
||||||
|
else
|
||||||
|
printf("%lld\n", valp->num);
|
||||||
|
|
||||||
|
return (valp->str && *valp->str) || valp->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
|
||||||
|
|
||||||
|
ret = !parse(argv, argc);
|
||||||
|
|
||||||
|
if (fshut(stdout, "<stdout>"))
|
||||||
|
ret = 3;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt FALSE 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm false
|
||||||
|
.Nd return failure
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
returns a status code indicating failure.
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
.Dd July 30, 2025
|
||||||
|
.Dt FIND 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm find
|
||||||
|
.Nd find files
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl H | L
|
||||||
|
.Ar path Op ...
|
||||||
|
.Op Ar expression
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
walks a file hierarchy starting at each
|
||||||
|
.Ar path
|
||||||
|
and applies the
|
||||||
|
.Ar expression
|
||||||
|
to each file encountered.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl H
|
||||||
|
Dereference symbolic links provided as
|
||||||
|
.Ar path .
|
||||||
|
.It Fl L
|
||||||
|
Dereference all symbolic links encountered.
|
||||||
|
.El
|
||||||
|
.Sh EXTENDED DESCRIPTION
|
||||||
|
.Ar expression
|
||||||
|
is a combination of the following primaries and boolean operators.
|
||||||
|
In the following descriptions the number n can be replaced by +n, n, or
|
||||||
|
-n, to mean more than, exactly, or less than n respectively.
|
||||||
|
.Ss Primaries
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl name Ar pattern
|
||||||
|
True if the name of the file matches the given pattern.
|
||||||
|
.It Fl path Ar pattern
|
||||||
|
True if the path to the file matches the given pattern.
|
||||||
|
.It Fl nouser
|
||||||
|
True if the file belongs to a user for which
|
||||||
|
.Xr getpwuid 3
|
||||||
|
returns NULL.
|
||||||
|
.It Fl nogroup
|
||||||
|
True if the file belongs to a group for which
|
||||||
|
.Xr getgrgid 3
|
||||||
|
returns NULL.
|
||||||
|
.It Fl xdev
|
||||||
|
True.
|
||||||
|
Do not enter directory on a different device.
|
||||||
|
.It Fl prune
|
||||||
|
True.
|
||||||
|
Do not enter directory.
|
||||||
|
.It Fl perm Ar mode
|
||||||
|
True if permissions on the file match mode.
|
||||||
|
Mode is a symbolic mode as used in chmod.
|
||||||
|
A leading '-' in mode checks that at least all bits in mode are set in
|
||||||
|
permissions for file.
|
||||||
|
Without the leading '-' the permissions for file must exactly match
|
||||||
|
mode.
|
||||||
|
.It Fl type Ar t
|
||||||
|
True if file is of type specified by
|
||||||
|
.Ar t .
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Ar b
|
||||||
|
block special
|
||||||
|
.It Ar c
|
||||||
|
character special
|
||||||
|
.It Ar d
|
||||||
|
directory
|
||||||
|
.It Ar l
|
||||||
|
symbolic link
|
||||||
|
.It Ar p
|
||||||
|
FIFO
|
||||||
|
.It Ar f
|
||||||
|
regular file
|
||||||
|
.It Ar s
|
||||||
|
socket
|
||||||
|
.El
|
||||||
|
.It Fl links Ar n
|
||||||
|
True if file has
|
||||||
|
.Ar n
|
||||||
|
links.
|
||||||
|
.It Fl user Ar name
|
||||||
|
True if file belongs to user
|
||||||
|
.Ar name .
|
||||||
|
.It Fl group Ar name
|
||||||
|
True if file belongs to group
|
||||||
|
.Ar name .
|
||||||
|
.It Fl size Ar n[c]
|
||||||
|
True if file size in 512 byte sectors (rounded up), or bytes (if
|
||||||
|
.Ar c
|
||||||
|
is given), is
|
||||||
|
.Ar n .
|
||||||
|
.It Fl atime n
|
||||||
|
True if file access time is
|
||||||
|
.Ar n
|
||||||
|
days.
|
||||||
|
.It Fl ctime
|
||||||
|
True if file status change time is
|
||||||
|
.Ar n
|
||||||
|
days.
|
||||||
|
.It Fl mtime
|
||||||
|
True if file modified time is
|
||||||
|
.Ar n
|
||||||
|
days.
|
||||||
|
.It Fl exec Ar cmd [arg ...] \&;
|
||||||
|
Execute cmd with given arguments, replacing each {} in argument list
|
||||||
|
with the current file.
|
||||||
|
True if cmd exits with status 0.
|
||||||
|
.It Fl exec Ar cmd [arg ...] {} +
|
||||||
|
True.
|
||||||
|
Add as many files as possible to argument list and execute when the list
|
||||||
|
is full or all files have been found.
|
||||||
|
.It Fl ok Ar cmd [arg ...] \&;
|
||||||
|
Prompt the user on each file encountered whether or not to execute cmd
|
||||||
|
as with -exec.
|
||||||
|
True if the user responds yes and cmd exits with status 0, false
|
||||||
|
otherwise.
|
||||||
|
.It Fl print
|
||||||
|
True.
|
||||||
|
Print the current pathname followed by a newline ('\en') character.
|
||||||
|
.It Fl print0
|
||||||
|
True.
|
||||||
|
Print the current pathname followed by a NUL ('\e0') character.
|
||||||
|
.It Fl newer Ar file
|
||||||
|
True if the modification time of the current file is newer than that of
|
||||||
|
the provided file.
|
||||||
|
.It Fl depth
|
||||||
|
True.
|
||||||
|
Causes find to evaluate files within in a directory before the directory
|
||||||
|
itself.
|
||||||
|
.El
|
||||||
|
.Ss Operators
|
||||||
|
In order of decreasing precedence
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Ar \&( expression \&)
|
||||||
|
True if expression is true.
|
||||||
|
.It Ar \&! expression
|
||||||
|
True if expression if false.
|
||||||
|
.It Ar expression [ Fl a ] Ar expression
|
||||||
|
True if both expressions are true.
|
||||||
|
Second expression is not evaluated if first expression is false.
|
||||||
|
.Fl a
|
||||||
|
is implied if there is no operator between primaries.
|
||||||
|
.It Ar expression Fl o Ar expression
|
||||||
|
True if either expression is true.
|
||||||
|
Second expression is not evaluated if first expression is true.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
If no expression is supplied, -print is used.
|
||||||
|
If an expression is supplied but none of -print, -exec, or -ok is
|
||||||
|
supplied, then -a -print is appended to the expressions.
|
||||||
+1103
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt FLOCK 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm flock
|
||||||
|
.Nd tool to manage locks on files
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl nosux
|
||||||
|
.Ar file
|
||||||
|
.Ar cmd Op arg ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
is used to manage advisory locks on open files.
|
||||||
|
It is commonly used to prevent long running cron jobs from running in
|
||||||
|
parallel.
|
||||||
|
If
|
||||||
|
.Ar file
|
||||||
|
does not exist, it will be created.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl n
|
||||||
|
Set non-blocking mode on the lock.
|
||||||
|
Fail immediately if the lock cannot be acquired.
|
||||||
|
.It Fl o
|
||||||
|
Close the file descriptor before exec to avoid having the exec'ed
|
||||||
|
program holding on to the lock.
|
||||||
|
.It Fl s
|
||||||
|
Acquire a shared lock.
|
||||||
|
.It Fl u
|
||||||
|
Release the lock.
|
||||||
|
.It Fl x
|
||||||
|
Acquire an exclusive lock.
|
||||||
|
This is the default.
|
||||||
|
.El
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-nosux] file cmd [arg ...]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd, status, savederrno, flags = LOCK_EX, nonblk = 0, oflag = 0;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'n':
|
||||||
|
nonblk = LOCK_NB;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
oflag = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
flags = LOCK_SH;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
flags = LOCK_UN;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
flags = LOCK_EX;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
if ((fd = open(*argv, O_RDONLY | O_CREAT, 0644)) < 0)
|
||||||
|
eprintf("open %s:", *argv);
|
||||||
|
|
||||||
|
if (flock(fd, flags | nonblk)) {
|
||||||
|
if (nonblk && errno == EWOULDBLOCK)
|
||||||
|
return 1;
|
||||||
|
eprintf("flock:");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ((pid = fork())) {
|
||||||
|
case -1:
|
||||||
|
eprintf("fork:");
|
||||||
|
case 0:
|
||||||
|
if (oflag && close(fd) < 0)
|
||||||
|
eprintf("close:");
|
||||||
|
argv++;
|
||||||
|
execvp(*argv, argv);
|
||||||
|
savederrno = errno;
|
||||||
|
weprintf("execvp %s:", *argv);
|
||||||
|
_exit(126 + (savederrno == ENOENT));
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (waitpid(pid, &status, 0) < 0)
|
||||||
|
eprintf("waitpid:");
|
||||||
|
|
||||||
|
if (close(fd) < 0)
|
||||||
|
eprintf("close:");
|
||||||
|
|
||||||
|
if (WIFSIGNALED(status))
|
||||||
|
return 128 + WTERMSIG(status);
|
||||||
|
if (WIFEXITED(status))
|
||||||
|
return WEXITSTATUS(status);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt FOLD 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm fold
|
||||||
|
.Nd wrap lines to width
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl bs
|
||||||
|
.Op Fl w Ar num | Fl Ns Ar num
|
||||||
|
.Op Ar file ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
reads each
|
||||||
|
.Ar file
|
||||||
|
and prints its lines wrapped such that no line
|
||||||
|
exceeds a certain width.
|
||||||
|
If no file is given,
|
||||||
|
.Nm
|
||||||
|
reads from stdin.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl b
|
||||||
|
Count bytes rather than characters.
|
||||||
|
.It Fl s
|
||||||
|
If a line contains spaces, break
|
||||||
|
at the last space within width.
|
||||||
|
.It Fl w Ar num | Fl Ns Ar num
|
||||||
|
Break at
|
||||||
|
.Ar num
|
||||||
|
characters.
|
||||||
|
The default is 80.
|
||||||
|
.El
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Op Fl Ns Ar num
|
||||||
|
syntax is an extension to that specification.
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "text.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "utf.h"
|
||||||
|
|
||||||
|
static int bflag = 0;
|
||||||
|
static int sflag = 0;
|
||||||
|
static size_t width = 80;
|
||||||
|
|
||||||
|
static void
|
||||||
|
foldline(struct line *l, const char *fname) {
|
||||||
|
size_t i, col, last, spacesect, len;
|
||||||
|
Rune r;
|
||||||
|
int runelen;
|
||||||
|
|
||||||
|
for (i = 0, last = 0, col = 0, spacesect = 0; i < l->len; i += runelen) {
|
||||||
|
if (col >= width && ((l->data[i] != '\r' && l->data[i] != '\b') || bflag)) {
|
||||||
|
if (bflag && col > width)
|
||||||
|
i -= runelen; /* never split a character */
|
||||||
|
len = ((sflag && spacesect) ? spacesect : i) - last;
|
||||||
|
if (fwrite(l->data + last, 1, len, stdout) != len)
|
||||||
|
eprintf("fwrite <stdout>:");
|
||||||
|
if (l->data[i] != '\n')
|
||||||
|
putchar('\n');
|
||||||
|
if (sflag && spacesect)
|
||||||
|
i = spacesect;
|
||||||
|
last = i;
|
||||||
|
col = 0;
|
||||||
|
spacesect = 0;
|
||||||
|
}
|
||||||
|
runelen = charntorune(&r, l->data + i, l->len - i);
|
||||||
|
if (!runelen || r == Runeerror)
|
||||||
|
eprintf("charntorune: %s: invalid utf\n", fname);
|
||||||
|
if (sflag && isblankrune(r))
|
||||||
|
spacesect = i + runelen;
|
||||||
|
if (!bflag && iscntrl(l->data[i])) {
|
||||||
|
switch(l->data[i]) {
|
||||||
|
case '\b':
|
||||||
|
col -= (col > 0);
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
col = 0;
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
col += (8 - (col % 8));
|
||||||
|
if (col >= width)
|
||||||
|
i--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
col += bflag ? runelen : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (l->len - last)
|
||||||
|
fwrite(l->data + last, 1, l->len - last, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fold(FILE *fp, const char *fname)
|
||||||
|
{
|
||||||
|
static struct line line;
|
||||||
|
static size_t size = 0;
|
||||||
|
ssize_t len;
|
||||||
|
|
||||||
|
while ((len = getline(&line.data, &size, fp)) > 0) {
|
||||||
|
line.len = len;
|
||||||
|
foldline(&line, fname);
|
||||||
|
}
|
||||||
|
if (ferror(fp))
|
||||||
|
eprintf("getline %s:", fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-bs] [-w num | -num] [FILE ...]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'b':
|
||||||
|
bflag = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
sflag = 1;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
width = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
|
||||||
|
break;
|
||||||
|
ARGNUM:
|
||||||
|
if (!(width = ARGNUMF()))
|
||||||
|
eprintf("illegal width value, too small\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (!argc) {
|
||||||
|
fold(stdin, "<stdin>");
|
||||||
|
} else {
|
||||||
|
for (; *argv; argc--, argv++) {
|
||||||
|
if (!strcmp(*argv, "-")) {
|
||||||
|
*argv = "<stdin>";
|
||||||
|
fp = stdin;
|
||||||
|
} else if (!(fp = fopen(*argv, "r"))) {
|
||||||
|
weprintf("fopen %s:", *argv);
|
||||||
|
ret = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fold(fp, *argv);
|
||||||
|
if (fp != stdin && fshut(fp, *argv))
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
struct history {
|
||||||
|
struct history *prev;
|
||||||
|
dev_t dev;
|
||||||
|
ino_t ino;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct recursor {
|
||||||
|
void (*fn)(int, const char *, struct stat *, void *, struct recursor *);
|
||||||
|
char path[PATH_MAX];
|
||||||
|
size_t pathlen;
|
||||||
|
struct history *hist;
|
||||||
|
int depth;
|
||||||
|
int maxdepth;
|
||||||
|
int follow;
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SAMEDEV = 1 << 0,
|
||||||
|
DIRFIRST = 1 << 1,
|
||||||
|
SILENT = 1 << 2,
|
||||||
|
CONFIRM = 1 << 3,
|
||||||
|
IGNORE = 1 << 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int cp_aflag;
|
||||||
|
extern int cp_fflag;
|
||||||
|
extern int cp_iflag;
|
||||||
|
extern int cp_pflag;
|
||||||
|
extern int cp_rflag;
|
||||||
|
extern int cp_vflag;
|
||||||
|
extern int cp_follow;
|
||||||
|
extern int cp_status;
|
||||||
|
|
||||||
|
extern int rm_status;
|
||||||
|
|
||||||
|
extern int recurse_status;
|
||||||
|
|
||||||
|
void recurse(int, const char *, void *, struct recursor *);
|
||||||
|
|
||||||
|
int cp(const char *, const char *, int);
|
||||||
|
void rm(int, const char *, struct stat *st, void *, struct recursor *);
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt GETCONF 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm getconf
|
||||||
|
.Nd get configuration values
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl v Ar spec
|
||||||
|
.Ar var
|
||||||
|
.Ar [path]
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
writes the value of the variable
|
||||||
|
.Ar var
|
||||||
|
to stdout.
|
||||||
|
.sp
|
||||||
|
If
|
||||||
|
.Ar path
|
||||||
|
is given,
|
||||||
|
.Ar var
|
||||||
|
is matched against configuration values from
|
||||||
|
.Xr pathconf 3 .
|
||||||
|
If
|
||||||
|
.Ar path
|
||||||
|
is not given,
|
||||||
|
.Ar var
|
||||||
|
is matched against configuration values from
|
||||||
|
.Xr sysconf 3 ,
|
||||||
|
.Xr confstr 3
|
||||||
|
and limits.h (Minimum and Maximum).
|
||||||
|
.sp
|
||||||
|
If
|
||||||
|
.Ar var
|
||||||
|
is not defined,
|
||||||
|
.Nm
|
||||||
|
writes "undefined" to stdout.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl v Ar spec
|
||||||
|
Ignored.
|
||||||
|
.El
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It 0
|
||||||
|
.Ar var
|
||||||
|
was matched and its value written successfully.
|
||||||
|
.It 1
|
||||||
|
An error occured or
|
||||||
|
.Ar var
|
||||||
|
was invalid.
|
||||||
|
.El
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
Except for the
|
||||||
|
.Op Fl v
|
||||||
|
flag.
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
struct var {
|
||||||
|
const char *k;
|
||||||
|
long v;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "getconf.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-v spec] var [path]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
long res;
|
||||||
|
int i;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'v':
|
||||||
|
/* ignore */
|
||||||
|
EARGF(usage());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
/* sysconf */
|
||||||
|
for (i = 0; i < LEN(sysconf_l); i++) {
|
||||||
|
if (strcmp(argv[0], sysconf_l[i].k))
|
||||||
|
continue;
|
||||||
|
errno = 0;
|
||||||
|
if ((res = sysconf(sysconf_l[i].v)) < 0) {
|
||||||
|
if (errno)
|
||||||
|
eprintf("sysconf %ld:", sysconf_l[i].v);
|
||||||
|
puts("undefined");
|
||||||
|
} else {
|
||||||
|
printf("%ld\n", res);
|
||||||
|
}
|
||||||
|
return fshut(stdout, "<stdout>");
|
||||||
|
}
|
||||||
|
/* confstr */
|
||||||
|
for (i = 0; i < LEN(confstr_l); i++) {
|
||||||
|
if (strcmp(argv[0], confstr_l[i].k))
|
||||||
|
continue;
|
||||||
|
errno = 0;
|
||||||
|
if (!(len = confstr(confstr_l[i].v, NULL, 0))) {
|
||||||
|
if (errno)
|
||||||
|
eprintf("confstr %ld:", confstr_l[i].v);
|
||||||
|
puts("undefined");
|
||||||
|
} else {
|
||||||
|
str = emalloc(len);
|
||||||
|
errno = 0;
|
||||||
|
if (!confstr(confstr_l[i].v, str, len)) {
|
||||||
|
if (errno)
|
||||||
|
eprintf("confstr %ld:", confstr_l[i].v);
|
||||||
|
puts("undefined");
|
||||||
|
} else {
|
||||||
|
puts(str);
|
||||||
|
}
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
return fshut(stdout, "<stdout>");
|
||||||
|
}
|
||||||
|
/* limits */
|
||||||
|
for (i = 0; i < LEN(limits_l); i++) {
|
||||||
|
if (strcmp(argv[0], limits_l[i].k))
|
||||||
|
continue;
|
||||||
|
printf("%ld\n", limits_l[i].v);
|
||||||
|
return fshut(stdout, "<stdout>");
|
||||||
|
}
|
||||||
|
} else if (argc == 2) {
|
||||||
|
/* pathconf */
|
||||||
|
for (i = 0; i < LEN(pathconf_l); i++) {
|
||||||
|
if (strcmp(argv[0], pathconf_l[i].k))
|
||||||
|
continue;
|
||||||
|
errno = 0;
|
||||||
|
if ((res = pathconf(argv[1], pathconf_l[i].v)) < 0) {
|
||||||
|
if (errno)
|
||||||
|
eprintf("pathconf %ld:", pathconf_l[i].v);
|
||||||
|
puts("undefined");
|
||||||
|
} else {
|
||||||
|
printf("%ld\n", res);
|
||||||
|
}
|
||||||
|
return fshut(stdout, "<stdout>");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintf("invalid variable: %s\n", argv[0]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt GREP 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm grep
|
||||||
|
.Nd search files for patterns
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl EFHchilnqsvx
|
||||||
|
.Op Fl e Ar pattern
|
||||||
|
.Op Fl f Ar file
|
||||||
|
.Op Ar pattern
|
||||||
|
.Op Ar file ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
searches the input files for lines that match the
|
||||||
|
.Ar pattern ,
|
||||||
|
a regular expression as defined in
|
||||||
|
.Xr regex 7 or
|
||||||
|
.Xr re_format 7 .
|
||||||
|
By default each matching line is printed to stdout.
|
||||||
|
If no
|
||||||
|
.Ar file
|
||||||
|
is given
|
||||||
|
.Nm
|
||||||
|
reads from stdin.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl E
|
||||||
|
Match using extended regex.
|
||||||
|
.It Fl F
|
||||||
|
Match using fixed strings.
|
||||||
|
Treat each pattern specified as a string instead of a regular
|
||||||
|
expression.
|
||||||
|
.It Fl H
|
||||||
|
Prefix each matching line with its filename in the output.
|
||||||
|
This is the default when there is more than one file specified.
|
||||||
|
.It Fl c
|
||||||
|
Print only a count of matching lines.
|
||||||
|
.It Fl e Ar pattern
|
||||||
|
Specify a pattern used during the search of the input: an input
|
||||||
|
line is selected if it matches any of the specified patterns.
|
||||||
|
This option is most useful when multiple -e options are used to
|
||||||
|
specify multiple patterns, or when a pattern begins with a dash.
|
||||||
|
.It Fl f Ar file
|
||||||
|
Read one or more patterns from the file named by the pathname file.
|
||||||
|
Patterns in file shall be terminated by a <newline>.
|
||||||
|
A null pattern can be specified by an empty line in pattern_file.
|
||||||
|
Unless the -E or -F option is also specified, each pattern shall be
|
||||||
|
treated as a BRE.
|
||||||
|
(`-').
|
||||||
|
.It Fl h
|
||||||
|
Do not prefix each line with 'filename:' prefix.
|
||||||
|
.It Fl i
|
||||||
|
Match lines case insensitively.
|
||||||
|
.It Fl l
|
||||||
|
Print only the names of files with matching lines.
|
||||||
|
.It Fl n
|
||||||
|
Prefix each matching line with its line number in the input.
|
||||||
|
.It Fl q
|
||||||
|
Print nothing, only return status.
|
||||||
|
.It Fl s
|
||||||
|
Suppress the error messages ordinarily written for nonexistent or unreadable
|
||||||
|
files.
|
||||||
|
.It Fl v
|
||||||
|
Select lines which do
|
||||||
|
.Sy not
|
||||||
|
match the pattern.
|
||||||
|
.It Fl w
|
||||||
|
The expression is searched for as a word (as if surrounded by '\\<' and '\\>').
|
||||||
|
.It Fl x
|
||||||
|
Consider only input lines that use all characters in the line excluding the
|
||||||
|
terminating <newline> to match an entire fixed string or regular expression to
|
||||||
|
be matching lines.
|
||||||
|
.El
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It 0
|
||||||
|
One or more lines were matched.
|
||||||
|
.It 1
|
||||||
|
No lines were matched.
|
||||||
|
.It > 1
|
||||||
|
An error occurred.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr sed 1 ,
|
||||||
|
.Xr re_format 7 ,
|
||||||
|
.Xr regex 7
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Op Fl Hhw
|
||||||
|
flags are an extension to that specification.
|
||||||
@@ -0,0 +1,290 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <regex.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
|
#include "queue.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
enum { Match = 0, NoMatch = 1, Error = 2 };
|
||||||
|
|
||||||
|
static void addpattern(const char *, size_t);
|
||||||
|
static void addpatternfile(FILE *);
|
||||||
|
static int grep(FILE *, const char *);
|
||||||
|
|
||||||
|
static int Eflag;
|
||||||
|
static int Fflag;
|
||||||
|
static int Hflag;
|
||||||
|
static int eflag;
|
||||||
|
static int fflag;
|
||||||
|
static int hflag;
|
||||||
|
static int iflag;
|
||||||
|
static int sflag;
|
||||||
|
static int vflag;
|
||||||
|
static int wflag;
|
||||||
|
static int xflag;
|
||||||
|
static int many;
|
||||||
|
static int mode;
|
||||||
|
|
||||||
|
struct pattern {
|
||||||
|
char *pattern;
|
||||||
|
regex_t preg;
|
||||||
|
SLIST_ENTRY(pattern) entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
static SLIST_HEAD(phead, pattern) phead;
|
||||||
|
|
||||||
|
static void
|
||||||
|
addpattern(const char *pattern, size_t patlen)
|
||||||
|
{
|
||||||
|
struct pattern *pnode;
|
||||||
|
char *tmp;
|
||||||
|
int bol, eol;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (!patlen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* a null BRE/ERE matches every line */
|
||||||
|
if (!Fflag)
|
||||||
|
if (pattern[0] == '\0')
|
||||||
|
pattern = "^";
|
||||||
|
|
||||||
|
if (!Fflag && xflag) {
|
||||||
|
tmp = enmalloc(Error, patlen + 3);
|
||||||
|
snprintf(tmp, patlen + 3, "%s%s%s",
|
||||||
|
pattern[0] == '^' ? "" : "^",
|
||||||
|
pattern,
|
||||||
|
pattern[patlen - 1] == '$' ? "" : "$");
|
||||||
|
} else if (!Fflag && wflag) {
|
||||||
|
len = patlen + 5 + (Eflag ? 2 : 4);
|
||||||
|
tmp = enmalloc(Error, len);
|
||||||
|
|
||||||
|
bol = eol = 0;
|
||||||
|
if (pattern[0] == '^')
|
||||||
|
bol = 1;
|
||||||
|
if (pattern[patlen - 1] == '$')
|
||||||
|
eol = 1;
|
||||||
|
|
||||||
|
snprintf(tmp, len, "%s\\<%s%.*s%s\\>%s",
|
||||||
|
bol ? "^" : "",
|
||||||
|
Eflag ? "(" : "\\(",
|
||||||
|
(int)patlen - bol - eol, pattern + bol,
|
||||||
|
Eflag ? ")" : "\\)",
|
||||||
|
eol ? "$" : "");
|
||||||
|
} else {
|
||||||
|
tmp = enstrdup(Error, pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
pnode = enmalloc(Error, sizeof(*pnode));
|
||||||
|
pnode->pattern = tmp;
|
||||||
|
SLIST_INSERT_HEAD(&phead, pnode, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
addpatternfile(FILE *fp)
|
||||||
|
{
|
||||||
|
static char *buf = NULL;
|
||||||
|
static size_t size = 0;
|
||||||
|
ssize_t len = 0;
|
||||||
|
|
||||||
|
while ((len = getline(&buf, &size, fp)) > 0) {
|
||||||
|
if (len > 0 && buf[len - 1] == '\n')
|
||||||
|
buf[len - 1] = '\0';
|
||||||
|
addpattern(buf, (size_t)len);
|
||||||
|
}
|
||||||
|
if (ferror(fp))
|
||||||
|
enprintf(Error, "read error:");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
grep(FILE *fp, const char *str)
|
||||||
|
{
|
||||||
|
static char *buf = NULL;
|
||||||
|
static size_t size = 0;
|
||||||
|
ssize_t len = 0;
|
||||||
|
long c = 0, n;
|
||||||
|
struct pattern *pnode;
|
||||||
|
int match, result = NoMatch;
|
||||||
|
|
||||||
|
for (n = 1; (len = getline(&buf, &size, fp)) > 0; n++) {
|
||||||
|
/* Remove the trailing newline if one is present. */
|
||||||
|
if (len && buf[len - 1] == '\n')
|
||||||
|
buf[len - 1] = '\0';
|
||||||
|
match = 0;
|
||||||
|
SLIST_FOREACH(pnode, &phead, entry) {
|
||||||
|
if (Fflag) {
|
||||||
|
if (xflag) {
|
||||||
|
if (!(iflag ? strcasecmp : strcmp)(buf, pnode->pattern)) {
|
||||||
|
match = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((iflag ? strcasestr : strstr)(buf, pnode->pattern)) {
|
||||||
|
match = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (regexec(&pnode->preg, buf, 0, NULL, 0) == 0) {
|
||||||
|
match = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match != vflag) {
|
||||||
|
result = Match;
|
||||||
|
switch (mode) {
|
||||||
|
case 'c':
|
||||||
|
c++;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
puts(str);
|
||||||
|
goto end;
|
||||||
|
case 'q':
|
||||||
|
exit(Match);
|
||||||
|
default:
|
||||||
|
if (!hflag && (many || Hflag))
|
||||||
|
printf("%s:", str);
|
||||||
|
if (mode == 'n')
|
||||||
|
printf("%ld:", n);
|
||||||
|
puts(buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mode == 'c')
|
||||||
|
printf("%ld\n", c);
|
||||||
|
end:
|
||||||
|
if (ferror(fp)) {
|
||||||
|
weprintf("%s: read error:", str);
|
||||||
|
result = Error;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
enprintf(Error, "usage: %s [-EFHchilnqsvwx] [-e pattern] [-f file] "
|
||||||
|
"[pattern] [file ...]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct pattern *pnode;
|
||||||
|
int m, flags = REG_NOSUB, match = NoMatch;
|
||||||
|
FILE *fp;
|
||||||
|
char *arg;
|
||||||
|
|
||||||
|
SLIST_INIT(&phead);
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'E':
|
||||||
|
Eflag = 1;
|
||||||
|
Fflag = 0;
|
||||||
|
flags |= REG_EXTENDED;
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
Fflag = 1;
|
||||||
|
Eflag = 0;
|
||||||
|
flags &= ~REG_EXTENDED;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
Hflag = 1;
|
||||||
|
hflag = 0;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
arg = EARGF(usage());
|
||||||
|
if (!(fp = fmemopen(arg, strlen(arg) + 1, "r")))
|
||||||
|
eprintf("fmemopen:");
|
||||||
|
addpatternfile(fp);
|
||||||
|
efshut(fp, arg);
|
||||||
|
eflag = 1;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
arg = EARGF(usage());
|
||||||
|
fp = fopen(arg, "r");
|
||||||
|
if (!fp)
|
||||||
|
enprintf(Error, "fopen %s:", arg);
|
||||||
|
addpatternfile(fp);
|
||||||
|
efshut(fp, arg);
|
||||||
|
fflag = 1;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
hflag = 1;
|
||||||
|
Hflag = 0;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
case 'l':
|
||||||
|
case 'n':
|
||||||
|
case 'q':
|
||||||
|
mode = ARGC();
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
flags |= REG_ICASE;
|
||||||
|
iflag = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
sflag = 1;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
vflag = 1;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
wflag = 1;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
xflag = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (argc == 0 && !eflag && !fflag)
|
||||||
|
usage(); /* no pattern */
|
||||||
|
|
||||||
|
/* just add literal pattern to list */
|
||||||
|
if (!eflag && !fflag) {
|
||||||
|
if (!(fp = fmemopen(argv[0], strlen(argv[0]) + 1, "r")))
|
||||||
|
eprintf("fmemopen:");
|
||||||
|
addpatternfile(fp);
|
||||||
|
efshut(fp, argv[0]);
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Fflag)
|
||||||
|
/* Compile regex for all search patterns */
|
||||||
|
SLIST_FOREACH(pnode, &phead, entry)
|
||||||
|
enregcomp(Error, &pnode->preg, pnode->pattern, flags);
|
||||||
|
many = (argc > 1);
|
||||||
|
if (argc == 0) {
|
||||||
|
match = grep(stdin, "<stdin>");
|
||||||
|
} else {
|
||||||
|
for (; *argv; argc--, argv++) {
|
||||||
|
if (!strcmp(*argv, "-")) {
|
||||||
|
*argv = "<stdin>";
|
||||||
|
fp = stdin;
|
||||||
|
} else if (!(fp = fopen(*argv, "r"))) {
|
||||||
|
if (!sflag)
|
||||||
|
weprintf("fopen %s:", *argv);
|
||||||
|
match = Error;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m = grep(fp, *argv);
|
||||||
|
if (m == Error || (match != Error && m == Match))
|
||||||
|
match = m;
|
||||||
|
if (fp != stdin && fshut(fp, *argv))
|
||||||
|
match = Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"))
|
||||||
|
match = Error;
|
||||||
|
|
||||||
|
return match;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt HEAD 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm head
|
||||||
|
.Nd display initial lines of files
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl n Ar num | Fl Ns Ar num
|
||||||
|
.Op Ar file ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
writes
|
||||||
|
.Ar num
|
||||||
|
lines of each
|
||||||
|
.Ar file
|
||||||
|
to stdout.
|
||||||
|
If no
|
||||||
|
.Ar file
|
||||||
|
is given
|
||||||
|
.Nm
|
||||||
|
reads from stdin.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl n Ar num | Fl Ns Ar num
|
||||||
|
Display initial
|
||||||
|
.Ar num
|
||||||
|
|
|
||||||
|
.Sy N
|
||||||
|
lines.
|
||||||
|
Default is 10.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr tail 1
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Op Fl Ns num
|
||||||
|
syntax is an extension to that specification.
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
head(FILE *fp, const char *fname, size_t n)
|
||||||
|
{
|
||||||
|
char *buf = NULL;
|
||||||
|
size_t i = 0, size = 0;
|
||||||
|
ssize_t len;
|
||||||
|
|
||||||
|
while (i < n && (len = getline(&buf, &size, fp)) > 0) {
|
||||||
|
fwrite(buf, 1, len, stdout);
|
||||||
|
i += (len && (buf[len - 1] == '\n'));
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
if (ferror(fp))
|
||||||
|
eprintf("getline %s:", fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-num | -n num] [file ...]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
size_t n = 10;
|
||||||
|
FILE *fp;
|
||||||
|
int ret = 0, newline = 0, many = 0;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'n':
|
||||||
|
n = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
|
||||||
|
break;
|
||||||
|
ARGNUM:
|
||||||
|
n = ARGNUMF();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (!argc) {
|
||||||
|
head(stdin, "<stdin>", n);
|
||||||
|
} else {
|
||||||
|
many = argc > 1;
|
||||||
|
for (newline = 0; *argv; argc--, argv++) {
|
||||||
|
if (!strcmp(*argv, "-")) {
|
||||||
|
*argv = "<stdin>";
|
||||||
|
fp = stdin;
|
||||||
|
} else if (!(fp = fopen(*argv, "r"))) {
|
||||||
|
weprintf("fopen %s:", *argv);
|
||||||
|
ret = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (many) {
|
||||||
|
if (newline)
|
||||||
|
putchar('\n');
|
||||||
|
printf("==> %s <==\n", *argv);
|
||||||
|
}
|
||||||
|
newline = 1;
|
||||||
|
head(fp, *argv, n);
|
||||||
|
if (fp != stdin && fshut(fp, *argv))
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt HOSTNAME 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm hostname
|
||||||
|
.Nd set or print host name
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Ar name
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
sets the current host name to
|
||||||
|
.Ar name .
|
||||||
|
If no
|
||||||
|
.Ar name
|
||||||
|
is given, the current host name is written to stdout.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr hostname 7
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [name]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char host[HOST_NAME_MAX + 1];
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (!argc) {
|
||||||
|
if (gethostname(host, sizeof(host)) < 0)
|
||||||
|
eprintf("gethostname:");
|
||||||
|
puts(host);
|
||||||
|
} else if (argc == 1) {
|
||||||
|
if (sethostname(argv[0], strlen(argv[0])) < 0)
|
||||||
|
eprintf("sethostname:");
|
||||||
|
} else {
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return fshut(stdout, "<stdout>");
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt JOIN 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm join
|
||||||
|
.Nd relational database operator
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl 1 Ar field
|
||||||
|
.Op Fl 2 Ar field
|
||||||
|
.Op Fl o Ar list
|
||||||
|
.Op Fl e Ar string
|
||||||
|
.Op Fl a Ar fileno | Fl v Ar fileno
|
||||||
|
.Op Fl t Ar delim
|
||||||
|
.Ar file1 file2
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
lines from
|
||||||
|
.Ar file1
|
||||||
|
and
|
||||||
|
.Ar file2
|
||||||
|
on a matching field.
|
||||||
|
If one of the input files is '-', standard input is read for that file.
|
||||||
|
.Pp
|
||||||
|
Files are read sequentially and are assumed to be sorted on the join
|
||||||
|
field.
|
||||||
|
.Nm
|
||||||
|
does not check the order of input, and joining two unsorted files will
|
||||||
|
produce unexpected output.
|
||||||
|
.Pp
|
||||||
|
By default, input lines are matched on the first blank-separated
|
||||||
|
field; output lines are space-separated and consist of the join field
|
||||||
|
followed by the remaining fields from
|
||||||
|
.Ar file1 ,
|
||||||
|
then the remaining fields from
|
||||||
|
.Ar file2 .
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl 1 Ar field
|
||||||
|
Join on the
|
||||||
|
.Ar field Ns th
|
||||||
|
field of file 1.
|
||||||
|
.It Fl 2 Ar field
|
||||||
|
Join on the
|
||||||
|
.Ar field Ns th
|
||||||
|
field of file 2.
|
||||||
|
.It Fl a Ar fileno
|
||||||
|
Print unpairable lines from file
|
||||||
|
.Ar fileno
|
||||||
|
in addition to normal output.
|
||||||
|
.It Fl e Ar string
|
||||||
|
When used with
|
||||||
|
.Fl o ,
|
||||||
|
replace empty fields in the output list with
|
||||||
|
.Ar string .
|
||||||
|
.It Fl o Ar list
|
||||||
|
Format output according to the string
|
||||||
|
.Ar list .
|
||||||
|
Each element of
|
||||||
|
.Ar list
|
||||||
|
may be either
|
||||||
|
.Ar fileno.field
|
||||||
|
or 0 (representing the join field).
|
||||||
|
Elements in
|
||||||
|
.Ar list
|
||||||
|
may be separated by blanks or commas.
|
||||||
|
For example,
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
join -o "0 2.1 1.3"
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
would print the join field, the first field of
|
||||||
|
.Ar file2 ,
|
||||||
|
then the third field of
|
||||||
|
.Ar file1 .
|
||||||
|
.Pp
|
||||||
|
Only paired lines are formatted with the
|
||||||
|
.Fl o
|
||||||
|
option.
|
||||||
|
Unpairable lines (selected with
|
||||||
|
.Fl a
|
||||||
|
or
|
||||||
|
.Fl v )
|
||||||
|
are printed raw.
|
||||||
|
.It Fl t Ar delim
|
||||||
|
Use the arbitrary string
|
||||||
|
.Ar delim
|
||||||
|
as field delimiter for both input and output.
|
||||||
|
.It Fl v Ar fileno
|
||||||
|
Print unpairable lines from file
|
||||||
|
.Ar fileno
|
||||||
|
instead of normal output.
|
||||||
|
.El
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
With the following exception:
|
||||||
|
.Bl -bullet -offset indent
|
||||||
|
.It
|
||||||
|
Unpairable lines ignore formatting specified with
|
||||||
|
.Fl o .
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The possibility of specifying multibyte delimiters of arbitrary
|
||||||
|
length is an extension to the specification.
|
||||||
@@ -0,0 +1,529 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "text.h"
|
||||||
|
#include "utf.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
INIT = 1,
|
||||||
|
GROW = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EXPAND = 0,
|
||||||
|
RESET = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { FIELD_ERROR = -2, };
|
||||||
|
|
||||||
|
struct field {
|
||||||
|
char *s;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jline {
|
||||||
|
struct line text;
|
||||||
|
size_t nf;
|
||||||
|
size_t maxf;
|
||||||
|
struct field *fields;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct spec {
|
||||||
|
size_t fileno;
|
||||||
|
size_t fldno;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct outlist {
|
||||||
|
size_t ns;
|
||||||
|
size_t maxs;
|
||||||
|
struct spec **specs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct span {
|
||||||
|
size_t nl;
|
||||||
|
size_t maxl;
|
||||||
|
struct jline **lines;
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *sep = NULL;
|
||||||
|
static char *replace = NULL;
|
||||||
|
static const char defaultofs = ' ';
|
||||||
|
static const int jfield = 1; /* POSIX default join field */
|
||||||
|
static int unpairsa = 0, unpairsb = 0;
|
||||||
|
static int oflag = 0;
|
||||||
|
static int pairs = 1;
|
||||||
|
static size_t seplen;
|
||||||
|
static struct outlist output;
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-1 field] [-2 field] [-o list] [-e string] "
|
||||||
|
"[-a | -v fileno] [-t delim] file1 file2\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
prfield(struct field *fp)
|
||||||
|
{
|
||||||
|
if (fwrite(fp->s, 1, fp->len, stdout) != fp->len)
|
||||||
|
eprintf("fwrite:");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
prsep(void)
|
||||||
|
{
|
||||||
|
if (sep)
|
||||||
|
fwrite(sep, 1, seplen, stdout);
|
||||||
|
else
|
||||||
|
putchar(defaultofs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
swaplines(struct jline *la, struct jline *lb)
|
||||||
|
{
|
||||||
|
struct jline tmp;
|
||||||
|
|
||||||
|
tmp = *la;
|
||||||
|
*la = *lb;
|
||||||
|
*lb = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
prjoin(struct jline *la, struct jline *lb, size_t jfa, size_t jfb)
|
||||||
|
{
|
||||||
|
struct spec *sp;
|
||||||
|
struct field *joinfield;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (jfa >= la->nf || jfb >= lb->nf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
joinfield = &la->fields[jfa];
|
||||||
|
|
||||||
|
if (oflag) {
|
||||||
|
for (i = 0; i < output.ns; i++) {
|
||||||
|
sp = output.specs[i];
|
||||||
|
|
||||||
|
if (sp->fileno == 1) {
|
||||||
|
if (sp->fldno < la->nf)
|
||||||
|
prfield(&la->fields[sp->fldno]);
|
||||||
|
else if (replace)
|
||||||
|
fputs(replace, stdout);
|
||||||
|
} else if (sp->fileno == 2) {
|
||||||
|
if (sp->fldno < lb->nf)
|
||||||
|
prfield(&lb->fields[sp->fldno]);
|
||||||
|
else if (replace)
|
||||||
|
fputs(replace, stdout);
|
||||||
|
} else if (sp->fileno == 0) {
|
||||||
|
prfield(joinfield);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < output.ns - 1)
|
||||||
|
prsep();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
prfield(joinfield);
|
||||||
|
prsep();
|
||||||
|
|
||||||
|
for (i = 0; i < la->nf; i++) {
|
||||||
|
if (i != jfa) {
|
||||||
|
prfield(&la->fields[i]);
|
||||||
|
prsep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < lb->nf; i++) {
|
||||||
|
if (i != jfb) {
|
||||||
|
prfield(&lb->fields[i]);
|
||||||
|
if (i < lb->nf - 1)
|
||||||
|
prsep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
prline(struct jline *lp)
|
||||||
|
{
|
||||||
|
if (fwrite(lp->text.data, 1, lp->text.len, stdout) != lp->text.len)
|
||||||
|
eprintf("fwrite:");
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jlinecmp(struct jline *la, struct jline *lb, size_t jfa, size_t jfb)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
/* return FIELD_ERROR if both lines are short */
|
||||||
|
if (jfa >= la->nf) {
|
||||||
|
status = (jfb >= lb->nf) ? FIELD_ERROR : -1;
|
||||||
|
} else if (jfb >= lb->nf) {
|
||||||
|
status = 1;
|
||||||
|
} else {
|
||||||
|
status = memcmp(la->fields[jfa].s, lb->fields[jfb].s,
|
||||||
|
MAX(la->fields[jfa].len, lb->fields[jfb].len));
|
||||||
|
LIMIT(status, -1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
addfield(struct jline *lp, char *sp, size_t len)
|
||||||
|
{
|
||||||
|
if (lp->nf >= lp->maxf) {
|
||||||
|
lp->fields = ereallocarray(lp->fields, (GROW * lp->maxf),
|
||||||
|
sizeof(struct field));
|
||||||
|
lp->maxf *= GROW;
|
||||||
|
}
|
||||||
|
lp->fields[lp->nf].s = sp;
|
||||||
|
lp->fields[lp->nf].len = len;
|
||||||
|
lp->nf++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
prspanjoin(struct span *spa, struct span *spb, size_t jfa, size_t jfb)
|
||||||
|
{
|
||||||
|
size_t i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < (spa->nl - 1); i++)
|
||||||
|
for (j = 0; j < (spb->nl - 1); j++)
|
||||||
|
prjoin(spa->lines[i], spb->lines[j], jfa, jfb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct jline *
|
||||||
|
makeline(char *s, size_t len)
|
||||||
|
{
|
||||||
|
struct jline *lp;
|
||||||
|
char *tmp;
|
||||||
|
size_t i, end;
|
||||||
|
|
||||||
|
if (s[len - 1] == '\n')
|
||||||
|
s[--len] = '\0';
|
||||||
|
|
||||||
|
lp = ereallocarray(NULL, INIT, sizeof(struct jline));
|
||||||
|
lp->text.data = s;
|
||||||
|
lp->text.len = len;
|
||||||
|
lp->fields = ereallocarray(NULL, INIT, sizeof(struct field));
|
||||||
|
lp->nf = 0;
|
||||||
|
lp->maxf = INIT;
|
||||||
|
|
||||||
|
for (i = 0; i < lp->text.len && isblank(lp->text.data[i]); i++)
|
||||||
|
;
|
||||||
|
while (i < lp->text.len) {
|
||||||
|
if (sep) {
|
||||||
|
if ((lp->text.len - i) < seplen ||
|
||||||
|
!(tmp = memmem(lp->text.data + i,
|
||||||
|
lp->text.len - i, sep, seplen))) {
|
||||||
|
goto eol;
|
||||||
|
}
|
||||||
|
end = tmp - lp->text.data;
|
||||||
|
addfield(lp, lp->text.data + i, end - i);
|
||||||
|
i = end + seplen;
|
||||||
|
} else {
|
||||||
|
for (end = i; !(isblank(lp->text.data[end])); end++) {
|
||||||
|
if (end + 1 == lp->text.len)
|
||||||
|
goto eol;
|
||||||
|
}
|
||||||
|
addfield(lp, lp->text.data + i, end - i);
|
||||||
|
for (i = end; isblank(lp->text.data[i]); i++)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eol:
|
||||||
|
addfield(lp, lp->text.data + i, lp->text.len - i);
|
||||||
|
|
||||||
|
return lp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addtospan(struct span *sp, FILE *fp, int reset)
|
||||||
|
{
|
||||||
|
char *newl = NULL;
|
||||||
|
ssize_t len;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
if ((len = getline(&newl, &size, fp)) < 0) {
|
||||||
|
if (ferror(fp))
|
||||||
|
eprintf("getline:");
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reset)
|
||||||
|
sp->nl = 0;
|
||||||
|
|
||||||
|
if (sp->nl >= sp->maxl) {
|
||||||
|
sp->lines = ereallocarray(sp->lines, (GROW * sp->maxl),
|
||||||
|
sizeof(struct jline *));
|
||||||
|
sp->maxl *= GROW;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp->lines[sp->nl] = makeline(newl, len);
|
||||||
|
sp->nl++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
initspan(struct span *sp)
|
||||||
|
{
|
||||||
|
sp->nl = 0;
|
||||||
|
sp->maxl = INIT;
|
||||||
|
sp->lines = ereallocarray(NULL, INIT, sizeof(struct jline *));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
freespan(struct span *sp)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < sp->nl; i++) {
|
||||||
|
free(sp->lines[i]->fields);
|
||||||
|
free(sp->lines[i]->text.data);
|
||||||
|
}
|
||||||
|
free(sp->lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
initolist(struct outlist *olp)
|
||||||
|
{
|
||||||
|
olp->ns = 0;
|
||||||
|
olp->maxs = 1;
|
||||||
|
olp->specs = ereallocarray(NULL, INIT, sizeof(struct spec *));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
addspec(struct outlist *olp, struct spec *sp)
|
||||||
|
{
|
||||||
|
if (olp->ns >= olp->maxs) {
|
||||||
|
olp->specs = ereallocarray(olp->specs, (GROW * olp->maxs),
|
||||||
|
sizeof(struct spec *));
|
||||||
|
olp->maxs *= GROW;
|
||||||
|
}
|
||||||
|
olp->specs[olp->ns] = sp;
|
||||||
|
olp->ns++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct spec *
|
||||||
|
makespec(char *s)
|
||||||
|
{
|
||||||
|
struct spec *sp;
|
||||||
|
int fileno;
|
||||||
|
size_t fldno;
|
||||||
|
|
||||||
|
if (!strcmp(s, "0")) { /* join field must be 0 and nothing else */
|
||||||
|
fileno = 0;
|
||||||
|
fldno = 0;
|
||||||
|
} else if ((s[0] == '1' || s[0] == '2') && s[1] == '.') {
|
||||||
|
fileno = s[0] - '0';
|
||||||
|
fldno = estrtonum(&s[2], 1, MIN(LLONG_MAX, SIZE_MAX)) - 1;
|
||||||
|
} else {
|
||||||
|
eprintf("%s: invalid format\n", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
sp = ereallocarray(NULL, INIT, sizeof(struct spec));
|
||||||
|
sp->fileno = fileno;
|
||||||
|
sp->fldno = fldno;
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
makeolist(struct outlist *olp, char *s)
|
||||||
|
{
|
||||||
|
char *item, *sp;
|
||||||
|
sp = s;
|
||||||
|
|
||||||
|
while (sp) {
|
||||||
|
item = sp;
|
||||||
|
sp = strpbrk(sp, ", \t");
|
||||||
|
if (sp)
|
||||||
|
*sp++ = '\0';
|
||||||
|
addspec(olp, makespec(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
freespecs(struct outlist *olp)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < olp->ns; i++)
|
||||||
|
free(olp->specs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
join(FILE *fa, FILE *fb, size_t jfa, size_t jfb)
|
||||||
|
{
|
||||||
|
struct span spa, spb;
|
||||||
|
int cmp, eofa, eofb;
|
||||||
|
|
||||||
|
initspan(&spa);
|
||||||
|
initspan(&spb);
|
||||||
|
cmp = eofa = eofb = 0;
|
||||||
|
|
||||||
|
addtospan(&spa, fa, RESET);
|
||||||
|
addtospan(&spb, fb, RESET);
|
||||||
|
|
||||||
|
while (spa.nl && spb.nl) {
|
||||||
|
if ((cmp = jlinecmp(spa.lines[0], spb.lines[0], jfa, jfb)) < 0) {
|
||||||
|
if (unpairsa)
|
||||||
|
prline(spa.lines[0]);
|
||||||
|
if (!addtospan(&spa, fa, RESET)) {
|
||||||
|
if (unpairsb) { /* a is EOF'd; print the rest of b */
|
||||||
|
do
|
||||||
|
prline(spb.lines[0]);
|
||||||
|
while (addtospan(&spb, fb, RESET));
|
||||||
|
}
|
||||||
|
eofa = eofb = 1;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (cmp > 0) {
|
||||||
|
if (unpairsb)
|
||||||
|
prline(spb.lines[0]);
|
||||||
|
if (!addtospan(&spb, fb, RESET)) {
|
||||||
|
if (unpairsa) { /* b is EOF'd; print the rest of a */
|
||||||
|
do
|
||||||
|
prline(spa.lines[0]);
|
||||||
|
while (addtospan(&spa, fa, RESET));
|
||||||
|
}
|
||||||
|
eofa = eofb = 1;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (cmp == 0) {
|
||||||
|
/* read all consecutive matching lines from a */
|
||||||
|
do {
|
||||||
|
if (!addtospan(&spa, fa, EXPAND)) {
|
||||||
|
eofa = 1;
|
||||||
|
spa.nl++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (jlinecmp(spa.lines[spa.nl-1], spb.lines[0], jfa, jfb) == 0);
|
||||||
|
|
||||||
|
/* read all consecutive matching lines from b */
|
||||||
|
do {
|
||||||
|
if (!addtospan(&spb, fb, EXPAND)) {
|
||||||
|
eofb = 1;
|
||||||
|
spb.nl++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (jlinecmp(spa.lines[0], spb.lines[spb.nl-1], jfa, jfb) == 0);
|
||||||
|
|
||||||
|
if (pairs)
|
||||||
|
prspanjoin(&spa, &spb, jfa, jfb);
|
||||||
|
|
||||||
|
} else { /* FIELD_ERROR: both lines lacked join fields */
|
||||||
|
if (unpairsa)
|
||||||
|
prline(spa.lines[0]);
|
||||||
|
if (unpairsb)
|
||||||
|
prline(spb.lines[0]);
|
||||||
|
eofa = addtospan(&spa, fa, RESET) ? 0 : 1;
|
||||||
|
eofb = addtospan(&spb, fb, RESET) ? 0 : 1;
|
||||||
|
if (!eofa && !eofb)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eofa) {
|
||||||
|
spa.nl = 0;
|
||||||
|
} else {
|
||||||
|
swaplines(spa.lines[0], spa.lines[spa.nl - 1]); /* ugly */
|
||||||
|
spa.nl = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eofb) {
|
||||||
|
spb.nl = 0;
|
||||||
|
} else {
|
||||||
|
swaplines(spb.lines[0], spb.lines[spb.nl - 1]); /* ugly */
|
||||||
|
spb.nl = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freespan(&spa);
|
||||||
|
freespan(&spb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
size_t jf[2] = { jfield, jfield, };
|
||||||
|
FILE *fp[2];
|
||||||
|
int ret = 0, n;
|
||||||
|
char *fno;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case '1':
|
||||||
|
jf[0] = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
jf[1] = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
fno = EARGF(usage());
|
||||||
|
if (strcmp(fno, "1") == 0)
|
||||||
|
unpairsa = 1;
|
||||||
|
else if (strcmp(fno, "2") == 0)
|
||||||
|
unpairsb = 1;
|
||||||
|
else
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
replace = EARGF(usage());
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
oflag = 1;
|
||||||
|
initolist(&output);
|
||||||
|
makeolist(&output, EARGF(usage()));
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
sep = EARGF(usage());
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
pairs = 0;
|
||||||
|
fno = EARGF(usage());
|
||||||
|
if (strcmp(fno, "1") == 0)
|
||||||
|
unpairsa = 1;
|
||||||
|
else if (strcmp(fno, "2") == 0)
|
||||||
|
unpairsb = 1;
|
||||||
|
else
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND
|
||||||
|
|
||||||
|
if (sep)
|
||||||
|
seplen = unescape(sep);
|
||||||
|
|
||||||
|
if (argc != 2)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
for (n = 0; n < 2; n++) {
|
||||||
|
if (!strcmp(argv[n], "-")) {
|
||||||
|
argv[n] = "<stdin>";
|
||||||
|
fp[n] = stdin;
|
||||||
|
} else if (!(fp[n] = fopen(argv[n], "r"))) {
|
||||||
|
eprintf("fopen %s:", argv[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jf[0]--;
|
||||||
|
jf[1]--;
|
||||||
|
|
||||||
|
join(fp[0], fp[1], jf[0], jf[1]);
|
||||||
|
|
||||||
|
if (oflag)
|
||||||
|
freespecs(&output);
|
||||||
|
|
||||||
|
if (fshut(fp[0], argv[0]) | (fp[0] != fp[1] && fshut(fp[1], argv[1])) |
|
||||||
|
fshut(stdout, "<stdout>"))
|
||||||
|
ret = 2;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
.Dd October 8, 2015
|
||||||
|
.Dt KILL 1
|
||||||
|
.Os sbase
|
||||||
|
.Sh NAME
|
||||||
|
.Nm kill
|
||||||
|
.Nd signal processes
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl s Ar signame | Fl num | Fl signame
|
||||||
|
.Ar pid ...
|
||||||
|
.Nm
|
||||||
|
.Fl l Op Ar num
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
signals TERM to each process or process group specified by
|
||||||
|
.Ar pid .
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl l Op Ar num
|
||||||
|
List all available signals or the signal name of
|
||||||
|
.Ar num .
|
||||||
|
.It Fl s Ar signame | Fl num | Fl signame
|
||||||
|
Send signal corresponding to
|
||||||
|
.Ar signame
|
||||||
|
|
|
||||||
|
.Ar num .
|
||||||
|
The default is TERM.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr kill 2 ,
|
||||||
|
.Xr signal 7
|
||||||
|
.Sh STANDARDS
|
||||||
|
POSIX.1-2013.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Fl Ar signame
|
||||||
|
and
|
||||||
|
.Fl Ar num
|
||||||
|
syntax is marked by POSIX.1-2013 as an X/OPEN System Interfaces option.
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
struct {
|
||||||
|
const char *name;
|
||||||
|
const int sig;
|
||||||
|
} sigs[] = {
|
||||||
|
{ "0", 0 },
|
||||||
|
#define SIG(n) { #n, SIG##n }
|
||||||
|
SIG(ABRT), SIG(ALRM), SIG(BUS), SIG(CHLD), SIG(CONT), SIG(FPE), SIG(HUP),
|
||||||
|
SIG(ILL), SIG(INT), SIG(KILL), SIG(PIPE), SIG(QUIT), SIG(SEGV), SIG(STOP),
|
||||||
|
SIG(TERM), SIG(TRAP), SIG(TSTP), SIG(TTIN), SIG(TTOU), SIG(USR1), SIG(USR2),
|
||||||
|
SIG(URG),
|
||||||
|
#undef SIG
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *
|
||||||
|
sig2name(const int sig)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < LEN(sigs); i++)
|
||||||
|
if (sigs[i].sig == sig)
|
||||||
|
return sigs[i].name;
|
||||||
|
eprintf("%d: bad signal number\n", sig);
|
||||||
|
|
||||||
|
return NULL; /* not reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
name2sig(const char *name)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < LEN(sigs); i++)
|
||||||
|
if (!strcasecmp(sigs[i].name, name))
|
||||||
|
return sigs[i].sig;
|
||||||
|
eprintf("%s: bad signal name\n", name);
|
||||||
|
|
||||||
|
return -1; /* not reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-s signame | -num | -signame] pid ...\n"
|
||||||
|
" %s -l [num]\n", argv0, argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
size_t i;
|
||||||
|
int ret = 0, sig = SIGTERM;
|
||||||
|
|
||||||
|
argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
|
||||||
|
|
||||||
|
if (!argc)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
if ((*argv)[0] == '-') {
|
||||||
|
switch ((*argv)[1]) {
|
||||||
|
case 'l':
|
||||||
|
if ((*argv)[2])
|
||||||
|
goto longopt;
|
||||||
|
argc--, argv++;
|
||||||
|
if (!argc) {
|
||||||
|
for (i = 0; i < LEN(sigs); i++)
|
||||||
|
puts(sigs[i].name);
|
||||||
|
} else if (argc == 1) {
|
||||||
|
sig = estrtonum(*argv, 0, INT_MAX);
|
||||||
|
if (sig > 128)
|
||||||
|
sig = WTERMSIG(sig);
|
||||||
|
puts(sig2name(sig));
|
||||||
|
} else {
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
return fshut(stdout, "<stdout>");
|
||||||
|
case 's':
|
||||||
|
if ((*argv)[2])
|
||||||
|
goto longopt;
|
||||||
|
argc--, argv++;
|
||||||
|
if (!argc)
|
||||||
|
usage();
|
||||||
|
sig = name2sig(*argv);
|
||||||
|
argc--, argv++;
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
if ((*argv)[2])
|
||||||
|
goto longopt;
|
||||||
|
argc--, argv++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
longopt:
|
||||||
|
/* XSI-extensions -argnum and -argname*/
|
||||||
|
if (isdigit((*argv)[1])) {
|
||||||
|
sig = estrtonum((*argv) + 1, 0, INT_MAX);
|
||||||
|
sig2name(sig);
|
||||||
|
} else {
|
||||||
|
sig = name2sig((*argv) + 1);
|
||||||
|
}
|
||||||
|
argc--, argv++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc && !strcmp(*argv, "--"))
|
||||||
|
argc--, argv++;
|
||||||
|
|
||||||
|
if (!argc)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
for (; *argv; argc--, argv++) {
|
||||||
|
pid = estrtonum(*argv, INT_MIN, INT_MAX);
|
||||||
|
if (kill(pid, sig) < 0) {
|
||||||
|
weprintf("kill %d:", pid);
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
AWK = awk
|
||||||
|
UNICODE = http://unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
|
||||||
|
|
||||||
|
default:
|
||||||
|
@echo Downloading and parsing $(UNICODE)
|
||||||
|
@curl -\# $(UNICODE) | $(AWK) -f mkrunetype.awk
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../utf.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
fgetrune(Rune *r, FILE *fp)
|
||||||
|
{
|
||||||
|
char buf[UTFmax];
|
||||||
|
int i = 0, c;
|
||||||
|
|
||||||
|
while (i < UTFmax && (c = fgetc(fp)) != EOF) {
|
||||||
|
buf[i++] = c;
|
||||||
|
if (charntorune(r, buf, i) > 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ferror(fp))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
efgetrune(Rune *r, FILE *fp, const char *file)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((ret = fgetrune(r, fp)) < 0) {
|
||||||
|
fprintf(stderr, "fgetrune %s: %s\n", file, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../utf.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
fputrune(const Rune *r, FILE *fp)
|
||||||
|
{
|
||||||
|
char buf[UTFmax];
|
||||||
|
|
||||||
|
return fwrite(buf, runetochar(buf, r), 1, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
efputrune(const Rune *r, FILE *fp, const char *file)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((ret = fputrune(r, fp)) < 0) {
|
||||||
|
fprintf(stderr, "fputrune %s: %s\n", file, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/* Automatically generated by mkrunetype.awk */
|
||||||
|
#include "../utf.h"
|
||||||
|
#include "runetype.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
isalnumrune(Rune r)
|
||||||
|
{
|
||||||
|
return isalpharune(r) || isdigitrune(r);
|
||||||
|
}
|
||||||
@@ -0,0 +1,830 @@
|
|||||||
|
/* Automatically generated by mkrunetype.awk */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "../utf.h"
|
||||||
|
#include "runetype.h"
|
||||||
|
|
||||||
|
static const Rune alpha3[][2] = {
|
||||||
|
{ 0x00D6, 0x00D8 },
|
||||||
|
{ 0x00F6, 0x00F8 },
|
||||||
|
{ 0x02EC, 0x02EE },
|
||||||
|
{ 0x0374, 0x0376 },
|
||||||
|
{ 0x037D, 0x037F },
|
||||||
|
{ 0x0386, 0x0388 },
|
||||||
|
{ 0x038A, 0x038E },
|
||||||
|
{ 0x03A1, 0x03A3 },
|
||||||
|
{ 0x03F5, 0x03F7 },
|
||||||
|
{ 0x052F, 0x0531 },
|
||||||
|
{ 0x066F, 0x0671 },
|
||||||
|
{ 0x06D3, 0x06D5 },
|
||||||
|
{ 0x0710, 0x0712 },
|
||||||
|
{ 0x0887, 0x0889 },
|
||||||
|
{ 0x09A8, 0x09AA },
|
||||||
|
{ 0x09B0, 0x09B2 },
|
||||||
|
{ 0x09DD, 0x09DF },
|
||||||
|
{ 0x0A28, 0x0A2A },
|
||||||
|
{ 0x0A30, 0x0A32 },
|
||||||
|
{ 0x0A33, 0x0A35 },
|
||||||
|
{ 0x0A36, 0x0A38 },
|
||||||
|
{ 0x0A5C, 0x0A5E },
|
||||||
|
{ 0x0A8D, 0x0A8F },
|
||||||
|
{ 0x0A91, 0x0A93 },
|
||||||
|
{ 0x0AA8, 0x0AAA },
|
||||||
|
{ 0x0AB0, 0x0AB2 },
|
||||||
|
{ 0x0AB3, 0x0AB5 },
|
||||||
|
{ 0x0B28, 0x0B2A },
|
||||||
|
{ 0x0B30, 0x0B32 },
|
||||||
|
{ 0x0B33, 0x0B35 },
|
||||||
|
{ 0x0B5D, 0x0B5F },
|
||||||
|
{ 0x0B83, 0x0B85 },
|
||||||
|
{ 0x0B90, 0x0B92 },
|
||||||
|
{ 0x0B9A, 0x0B9E },
|
||||||
|
{ 0x0C0C, 0x0C0E },
|
||||||
|
{ 0x0C10, 0x0C12 },
|
||||||
|
{ 0x0C28, 0x0C2A },
|
||||||
|
{ 0x0C8C, 0x0C8E },
|
||||||
|
{ 0x0C90, 0x0C92 },
|
||||||
|
{ 0x0CA8, 0x0CAA },
|
||||||
|
{ 0x0CB3, 0x0CB5 },
|
||||||
|
{ 0x0CDE, 0x0CE0 },
|
||||||
|
{ 0x0D0C, 0x0D0E },
|
||||||
|
{ 0x0D10, 0x0D12 },
|
||||||
|
{ 0x0DB1, 0x0DB3 },
|
||||||
|
{ 0x0DBB, 0x0DBD },
|
||||||
|
{ 0x0E30, 0x0E32 },
|
||||||
|
{ 0x0E82, 0x0E86 },
|
||||||
|
{ 0x0E8A, 0x0E8C },
|
||||||
|
{ 0x0EA3, 0x0EA7 },
|
||||||
|
{ 0x0EB0, 0x0EB2 },
|
||||||
|
{ 0x0EC4, 0x0EC6 },
|
||||||
|
{ 0x0F47, 0x0F49 },
|
||||||
|
{ 0x10C5, 0x10C7 },
|
||||||
|
{ 0x10FA, 0x10FC },
|
||||||
|
{ 0x1248, 0x124A },
|
||||||
|
{ 0x1256, 0x125A },
|
||||||
|
{ 0x1288, 0x128A },
|
||||||
|
{ 0x12B0, 0x12B2 },
|
||||||
|
{ 0x12BE, 0x12C2 },
|
||||||
|
{ 0x12D6, 0x12D8 },
|
||||||
|
{ 0x1310, 0x1312 },
|
||||||
|
{ 0x167F, 0x1681 },
|
||||||
|
{ 0x176C, 0x176E },
|
||||||
|
{ 0x18A8, 0x18AA },
|
||||||
|
{ 0x1CEC, 0x1CEE },
|
||||||
|
{ 0x1CF3, 0x1CF5 },
|
||||||
|
{ 0x1F57, 0x1F5F },
|
||||||
|
{ 0x1FB4, 0x1FB6 },
|
||||||
|
{ 0x1FBC, 0x1FBE },
|
||||||
|
{ 0x1FC4, 0x1FC6 },
|
||||||
|
{ 0x1FF4, 0x1FF6 },
|
||||||
|
{ 0x2113, 0x2115 },
|
||||||
|
{ 0x2124, 0x212A },
|
||||||
|
{ 0x212D, 0x212F },
|
||||||
|
{ 0x2D25, 0x2D27 },
|
||||||
|
{ 0x2DA6, 0x2DA8 },
|
||||||
|
{ 0x2DAE, 0x2DB0 },
|
||||||
|
{ 0x2DB6, 0x2DB8 },
|
||||||
|
{ 0x2DBE, 0x2DC0 },
|
||||||
|
{ 0x2DC6, 0x2DC8 },
|
||||||
|
{ 0x2DCE, 0x2DD0 },
|
||||||
|
{ 0x2DD6, 0x2DD8 },
|
||||||
|
{ 0x309F, 0x30A1 },
|
||||||
|
{ 0x30FA, 0x30FC },
|
||||||
|
{ 0x312F, 0x3131 },
|
||||||
|
{ 0xA7D1, 0xA7D5 },
|
||||||
|
{ 0xA801, 0xA803 },
|
||||||
|
{ 0xA805, 0xA807 },
|
||||||
|
{ 0xA80A, 0xA80C },
|
||||||
|
{ 0xA8FB, 0xA8FD },
|
||||||
|
{ 0xA9E4, 0xA9E6 },
|
||||||
|
{ 0xA9FE, 0xAA00 },
|
||||||
|
{ 0xAA42, 0xAA44 },
|
||||||
|
{ 0xAAAF, 0xAAB1 },
|
||||||
|
{ 0xAAC0, 0xAAC2 },
|
||||||
|
{ 0xAB26, 0xAB28 },
|
||||||
|
{ 0xAB2E, 0xAB30 },
|
||||||
|
{ 0xAB5A, 0xAB5C },
|
||||||
|
{ 0xFB1D, 0xFB1F },
|
||||||
|
{ 0xFB28, 0xFB2A },
|
||||||
|
{ 0xFB36, 0xFB38 },
|
||||||
|
{ 0xFB3C, 0xFB40 },
|
||||||
|
{ 0xFB41, 0xFB43 },
|
||||||
|
{ 0xFB44, 0xFB46 },
|
||||||
|
{ 0xFE74, 0xFE76 },
|
||||||
|
{ 0x1000B, 0x1000D },
|
||||||
|
{ 0x10026, 0x10028 },
|
||||||
|
{ 0x1003A, 0x1003C },
|
||||||
|
{ 0x1003D, 0x1003F },
|
||||||
|
{ 0x10340, 0x10342 },
|
||||||
|
{ 0x1057A, 0x1057C },
|
||||||
|
{ 0x1058A, 0x1058C },
|
||||||
|
{ 0x10592, 0x10594 },
|
||||||
|
{ 0x10595, 0x10597 },
|
||||||
|
{ 0x105A1, 0x105A3 },
|
||||||
|
{ 0x105B1, 0x105B3 },
|
||||||
|
{ 0x105B9, 0x105BB },
|
||||||
|
{ 0x10785, 0x10787 },
|
||||||
|
{ 0x107B0, 0x107B2 },
|
||||||
|
{ 0x10808, 0x1080A },
|
||||||
|
{ 0x10835, 0x10837 },
|
||||||
|
{ 0x108F2, 0x108F4 },
|
||||||
|
{ 0x10A13, 0x10A15 },
|
||||||
|
{ 0x10A17, 0x10A19 },
|
||||||
|
{ 0x10AC7, 0x10AC9 },
|
||||||
|
{ 0x111DA, 0x111DC },
|
||||||
|
{ 0x11211, 0x11213 },
|
||||||
|
{ 0x11286, 0x1128A },
|
||||||
|
{ 0x1128D, 0x1128F },
|
||||||
|
{ 0x1129D, 0x1129F },
|
||||||
|
{ 0x11328, 0x1132A },
|
||||||
|
{ 0x11330, 0x11332 },
|
||||||
|
{ 0x11333, 0x11335 },
|
||||||
|
{ 0x114C5, 0x114C7 },
|
||||||
|
{ 0x11913, 0x11915 },
|
||||||
|
{ 0x11916, 0x11918 },
|
||||||
|
{ 0x1193F, 0x11941 },
|
||||||
|
{ 0x119E1, 0x119E3 },
|
||||||
|
{ 0x11C08, 0x11C0A },
|
||||||
|
{ 0x11D06, 0x11D08 },
|
||||||
|
{ 0x11D09, 0x11D0B },
|
||||||
|
{ 0x11D65, 0x11D67 },
|
||||||
|
{ 0x11D68, 0x11D6A },
|
||||||
|
{ 0x11F02, 0x11F04 },
|
||||||
|
{ 0x11F10, 0x11F12 },
|
||||||
|
{ 0x16FE1, 0x16FE3 },
|
||||||
|
{ 0x1AFF3, 0x1AFF5 },
|
||||||
|
{ 0x1AFFB, 0x1AFFD },
|
||||||
|
{ 0x1AFFE, 0x1B000 },
|
||||||
|
{ 0x1D454, 0x1D456 },
|
||||||
|
{ 0x1D49C, 0x1D49E },
|
||||||
|
{ 0x1D4AC, 0x1D4AE },
|
||||||
|
{ 0x1D4B9, 0x1D4BD },
|
||||||
|
{ 0x1D4C3, 0x1D4C5 },
|
||||||
|
{ 0x1D505, 0x1D507 },
|
||||||
|
{ 0x1D514, 0x1D516 },
|
||||||
|
{ 0x1D51C, 0x1D51E },
|
||||||
|
{ 0x1D539, 0x1D53B },
|
||||||
|
{ 0x1D53E, 0x1D540 },
|
||||||
|
{ 0x1D544, 0x1D546 },
|
||||||
|
{ 0x1D550, 0x1D552 },
|
||||||
|
{ 0x1D6C0, 0x1D6C2 },
|
||||||
|
{ 0x1D6DA, 0x1D6DC },
|
||||||
|
{ 0x1D6FA, 0x1D6FC },
|
||||||
|
{ 0x1D714, 0x1D716 },
|
||||||
|
{ 0x1D734, 0x1D736 },
|
||||||
|
{ 0x1D74E, 0x1D750 },
|
||||||
|
{ 0x1D76E, 0x1D770 },
|
||||||
|
{ 0x1D788, 0x1D78A },
|
||||||
|
{ 0x1D7A8, 0x1D7AA },
|
||||||
|
{ 0x1D7C2, 0x1D7C4 },
|
||||||
|
{ 0x1E7E6, 0x1E7E8 },
|
||||||
|
{ 0x1E7EB, 0x1E7ED },
|
||||||
|
{ 0x1E7EE, 0x1E7F0 },
|
||||||
|
{ 0x1E7FE, 0x1E800 },
|
||||||
|
{ 0x1EE03, 0x1EE05 },
|
||||||
|
{ 0x1EE1F, 0x1EE21 },
|
||||||
|
{ 0x1EE22, 0x1EE24 },
|
||||||
|
{ 0x1EE27, 0x1EE29 },
|
||||||
|
{ 0x1EE32, 0x1EE34 },
|
||||||
|
{ 0x1EE37, 0x1EE3B },
|
||||||
|
{ 0x1EE47, 0x1EE4D },
|
||||||
|
{ 0x1EE4F, 0x1EE51 },
|
||||||
|
{ 0x1EE52, 0x1EE54 },
|
||||||
|
{ 0x1EE57, 0x1EE61 },
|
||||||
|
{ 0x1EE62, 0x1EE64 },
|
||||||
|
{ 0x1EE6A, 0x1EE6C },
|
||||||
|
{ 0x1EE72, 0x1EE74 },
|
||||||
|
{ 0x1EE77, 0x1EE79 },
|
||||||
|
{ 0x1EE7C, 0x1EE80 },
|
||||||
|
{ 0x1EE89, 0x1EE8B },
|
||||||
|
{ 0x1EEA3, 0x1EEA5 },
|
||||||
|
{ 0x1EEA9, 0x1EEAB },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Rune alpha2[][2] = {
|
||||||
|
{ 0x0041, 0x005A },
|
||||||
|
{ 0x0061, 0x007A },
|
||||||
|
{ 0x00C0, 0x00D6 },
|
||||||
|
{ 0x00D8, 0x00F6 },
|
||||||
|
{ 0x00F8, 0x02C1 },
|
||||||
|
{ 0x02C6, 0x02D1 },
|
||||||
|
{ 0x02E0, 0x02E4 },
|
||||||
|
{ 0x0370, 0x0374 },
|
||||||
|
{ 0x0376, 0x0377 },
|
||||||
|
{ 0x037A, 0x037D },
|
||||||
|
{ 0x0388, 0x038A },
|
||||||
|
{ 0x038E, 0x03A1 },
|
||||||
|
{ 0x03A3, 0x03F5 },
|
||||||
|
{ 0x03F7, 0x0481 },
|
||||||
|
{ 0x048A, 0x052F },
|
||||||
|
{ 0x0531, 0x0556 },
|
||||||
|
{ 0x0560, 0x0588 },
|
||||||
|
{ 0x05D0, 0x05EA },
|
||||||
|
{ 0x05EF, 0x05F2 },
|
||||||
|
{ 0x0620, 0x064A },
|
||||||
|
{ 0x066E, 0x066F },
|
||||||
|
{ 0x0671, 0x06D3 },
|
||||||
|
{ 0x06E5, 0x06E6 },
|
||||||
|
{ 0x06EE, 0x06EF },
|
||||||
|
{ 0x06FA, 0x06FC },
|
||||||
|
{ 0x0712, 0x072F },
|
||||||
|
{ 0x074D, 0x07A5 },
|
||||||
|
{ 0x07CA, 0x07EA },
|
||||||
|
{ 0x07F4, 0x07F5 },
|
||||||
|
{ 0x0800, 0x0815 },
|
||||||
|
{ 0x0840, 0x0858 },
|
||||||
|
{ 0x0860, 0x086A },
|
||||||
|
{ 0x0870, 0x0887 },
|
||||||
|
{ 0x0889, 0x088E },
|
||||||
|
{ 0x08A0, 0x08C9 },
|
||||||
|
{ 0x0904, 0x0939 },
|
||||||
|
{ 0x0958, 0x0961 },
|
||||||
|
{ 0x0971, 0x0980 },
|
||||||
|
{ 0x0985, 0x098C },
|
||||||
|
{ 0x098F, 0x0990 },
|
||||||
|
{ 0x0993, 0x09A8 },
|
||||||
|
{ 0x09AA, 0x09B0 },
|
||||||
|
{ 0x09B6, 0x09B9 },
|
||||||
|
{ 0x09DC, 0x09DD },
|
||||||
|
{ 0x09DF, 0x09E1 },
|
||||||
|
{ 0x09F0, 0x09F1 },
|
||||||
|
{ 0x0A05, 0x0A0A },
|
||||||
|
{ 0x0A0F, 0x0A10 },
|
||||||
|
{ 0x0A13, 0x0A28 },
|
||||||
|
{ 0x0A2A, 0x0A30 },
|
||||||
|
{ 0x0A32, 0x0A33 },
|
||||||
|
{ 0x0A35, 0x0A36 },
|
||||||
|
{ 0x0A38, 0x0A39 },
|
||||||
|
{ 0x0A59, 0x0A5C },
|
||||||
|
{ 0x0A72, 0x0A74 },
|
||||||
|
{ 0x0A85, 0x0A8D },
|
||||||
|
{ 0x0A8F, 0x0A91 },
|
||||||
|
{ 0x0A93, 0x0AA8 },
|
||||||
|
{ 0x0AAA, 0x0AB0 },
|
||||||
|
{ 0x0AB2, 0x0AB3 },
|
||||||
|
{ 0x0AB5, 0x0AB9 },
|
||||||
|
{ 0x0AE0, 0x0AE1 },
|
||||||
|
{ 0x0B05, 0x0B0C },
|
||||||
|
{ 0x0B0F, 0x0B10 },
|
||||||
|
{ 0x0B13, 0x0B28 },
|
||||||
|
{ 0x0B2A, 0x0B30 },
|
||||||
|
{ 0x0B32, 0x0B33 },
|
||||||
|
{ 0x0B35, 0x0B39 },
|
||||||
|
{ 0x0B5C, 0x0B5D },
|
||||||
|
{ 0x0B5F, 0x0B61 },
|
||||||
|
{ 0x0B85, 0x0B8A },
|
||||||
|
{ 0x0B8E, 0x0B90 },
|
||||||
|
{ 0x0B92, 0x0B95 },
|
||||||
|
{ 0x0B99, 0x0B9A },
|
||||||
|
{ 0x0B9E, 0x0B9F },
|
||||||
|
{ 0x0BA3, 0x0BA4 },
|
||||||
|
{ 0x0BA8, 0x0BAA },
|
||||||
|
{ 0x0BAE, 0x0BB9 },
|
||||||
|
{ 0x0C05, 0x0C0C },
|
||||||
|
{ 0x0C0E, 0x0C10 },
|
||||||
|
{ 0x0C12, 0x0C28 },
|
||||||
|
{ 0x0C2A, 0x0C39 },
|
||||||
|
{ 0x0C58, 0x0C5A },
|
||||||
|
{ 0x0C60, 0x0C61 },
|
||||||
|
{ 0x0C85, 0x0C8C },
|
||||||
|
{ 0x0C8E, 0x0C90 },
|
||||||
|
{ 0x0C92, 0x0CA8 },
|
||||||
|
{ 0x0CAA, 0x0CB3 },
|
||||||
|
{ 0x0CB5, 0x0CB9 },
|
||||||
|
{ 0x0CDD, 0x0CDE },
|
||||||
|
{ 0x0CE0, 0x0CE1 },
|
||||||
|
{ 0x0CF1, 0x0CF2 },
|
||||||
|
{ 0x0D04, 0x0D0C },
|
||||||
|
{ 0x0D0E, 0x0D10 },
|
||||||
|
{ 0x0D12, 0x0D3A },
|
||||||
|
{ 0x0D54, 0x0D56 },
|
||||||
|
{ 0x0D5F, 0x0D61 },
|
||||||
|
{ 0x0D7A, 0x0D7F },
|
||||||
|
{ 0x0D85, 0x0D96 },
|
||||||
|
{ 0x0D9A, 0x0DB1 },
|
||||||
|
{ 0x0DB3, 0x0DBB },
|
||||||
|
{ 0x0DC0, 0x0DC6 },
|
||||||
|
{ 0x0E01, 0x0E30 },
|
||||||
|
{ 0x0E32, 0x0E33 },
|
||||||
|
{ 0x0E40, 0x0E46 },
|
||||||
|
{ 0x0E81, 0x0E82 },
|
||||||
|
{ 0x0E86, 0x0E8A },
|
||||||
|
{ 0x0E8C, 0x0EA3 },
|
||||||
|
{ 0x0EA7, 0x0EB0 },
|
||||||
|
{ 0x0EB2, 0x0EB3 },
|
||||||
|
{ 0x0EC0, 0x0EC4 },
|
||||||
|
{ 0x0EDC, 0x0EDF },
|
||||||
|
{ 0x0F40, 0x0F47 },
|
||||||
|
{ 0x0F49, 0x0F6C },
|
||||||
|
{ 0x0F88, 0x0F8C },
|
||||||
|
{ 0x1000, 0x102A },
|
||||||
|
{ 0x1050, 0x1055 },
|
||||||
|
{ 0x105A, 0x105D },
|
||||||
|
{ 0x1065, 0x1066 },
|
||||||
|
{ 0x106E, 0x1070 },
|
||||||
|
{ 0x1075, 0x1081 },
|
||||||
|
{ 0x10A0, 0x10C5 },
|
||||||
|
{ 0x10D0, 0x10FA },
|
||||||
|
{ 0x10FC, 0x1248 },
|
||||||
|
{ 0x124A, 0x124D },
|
||||||
|
{ 0x1250, 0x1256 },
|
||||||
|
{ 0x125A, 0x125D },
|
||||||
|
{ 0x1260, 0x1288 },
|
||||||
|
{ 0x128A, 0x128D },
|
||||||
|
{ 0x1290, 0x12B0 },
|
||||||
|
{ 0x12B2, 0x12B5 },
|
||||||
|
{ 0x12B8, 0x12BE },
|
||||||
|
{ 0x12C2, 0x12C5 },
|
||||||
|
{ 0x12C8, 0x12D6 },
|
||||||
|
{ 0x12D8, 0x1310 },
|
||||||
|
{ 0x1312, 0x1315 },
|
||||||
|
{ 0x1318, 0x135A },
|
||||||
|
{ 0x1380, 0x138F },
|
||||||
|
{ 0x13A0, 0x13F5 },
|
||||||
|
{ 0x13F8, 0x13FD },
|
||||||
|
{ 0x1401, 0x166C },
|
||||||
|
{ 0x166F, 0x167F },
|
||||||
|
{ 0x1681, 0x169A },
|
||||||
|
{ 0x16A0, 0x16EA },
|
||||||
|
{ 0x16F1, 0x16F8 },
|
||||||
|
{ 0x1700, 0x1711 },
|
||||||
|
{ 0x171F, 0x1731 },
|
||||||
|
{ 0x1740, 0x1751 },
|
||||||
|
{ 0x1760, 0x176C },
|
||||||
|
{ 0x176E, 0x1770 },
|
||||||
|
{ 0x1780, 0x17B3 },
|
||||||
|
{ 0x1820, 0x1878 },
|
||||||
|
{ 0x1880, 0x1884 },
|
||||||
|
{ 0x1887, 0x18A8 },
|
||||||
|
{ 0x18B0, 0x18F5 },
|
||||||
|
{ 0x1900, 0x191E },
|
||||||
|
{ 0x1950, 0x196D },
|
||||||
|
{ 0x1970, 0x1974 },
|
||||||
|
{ 0x1980, 0x19AB },
|
||||||
|
{ 0x19B0, 0x19C9 },
|
||||||
|
{ 0x1A00, 0x1A16 },
|
||||||
|
{ 0x1A20, 0x1A54 },
|
||||||
|
{ 0x1B05, 0x1B33 },
|
||||||
|
{ 0x1B45, 0x1B4C },
|
||||||
|
{ 0x1B83, 0x1BA0 },
|
||||||
|
{ 0x1BAE, 0x1BAF },
|
||||||
|
{ 0x1BBA, 0x1BE5 },
|
||||||
|
{ 0x1C00, 0x1C23 },
|
||||||
|
{ 0x1C4D, 0x1C4F },
|
||||||
|
{ 0x1C5A, 0x1C7D },
|
||||||
|
{ 0x1C80, 0x1C88 },
|
||||||
|
{ 0x1C90, 0x1CBA },
|
||||||
|
{ 0x1CBD, 0x1CBF },
|
||||||
|
{ 0x1CE9, 0x1CEC },
|
||||||
|
{ 0x1CEE, 0x1CF3 },
|
||||||
|
{ 0x1CF5, 0x1CF6 },
|
||||||
|
{ 0x1D00, 0x1DBF },
|
||||||
|
{ 0x1E00, 0x1F15 },
|
||||||
|
{ 0x1F18, 0x1F1D },
|
||||||
|
{ 0x1F20, 0x1F45 },
|
||||||
|
{ 0x1F48, 0x1F4D },
|
||||||
|
{ 0x1F50, 0x1F57 },
|
||||||
|
{ 0x1F5F, 0x1F7D },
|
||||||
|
{ 0x1F80, 0x1FB4 },
|
||||||
|
{ 0x1FB6, 0x1FBC },
|
||||||
|
{ 0x1FC2, 0x1FC4 },
|
||||||
|
{ 0x1FC6, 0x1FCC },
|
||||||
|
{ 0x1FD0, 0x1FD3 },
|
||||||
|
{ 0x1FD6, 0x1FDB },
|
||||||
|
{ 0x1FE0, 0x1FEC },
|
||||||
|
{ 0x1FF2, 0x1FF4 },
|
||||||
|
{ 0x1FF6, 0x1FFC },
|
||||||
|
{ 0x2090, 0x209C },
|
||||||
|
{ 0x210A, 0x2113 },
|
||||||
|
{ 0x2119, 0x211D },
|
||||||
|
{ 0x212A, 0x212D },
|
||||||
|
{ 0x212F, 0x2139 },
|
||||||
|
{ 0x213C, 0x213F },
|
||||||
|
{ 0x2145, 0x2149 },
|
||||||
|
{ 0x2183, 0x2184 },
|
||||||
|
{ 0x2C00, 0x2CE4 },
|
||||||
|
{ 0x2CEB, 0x2CEE },
|
||||||
|
{ 0x2CF2, 0x2CF3 },
|
||||||
|
{ 0x2D00, 0x2D25 },
|
||||||
|
{ 0x2D30, 0x2D67 },
|
||||||
|
{ 0x2D80, 0x2D96 },
|
||||||
|
{ 0x2DA0, 0x2DA6 },
|
||||||
|
{ 0x2DA8, 0x2DAE },
|
||||||
|
{ 0x2DB0, 0x2DB6 },
|
||||||
|
{ 0x2DB8, 0x2DBE },
|
||||||
|
{ 0x2DC0, 0x2DC6 },
|
||||||
|
{ 0x2DC8, 0x2DCE },
|
||||||
|
{ 0x2DD0, 0x2DD6 },
|
||||||
|
{ 0x2DD8, 0x2DDE },
|
||||||
|
{ 0x3005, 0x3006 },
|
||||||
|
{ 0x3031, 0x3035 },
|
||||||
|
{ 0x303B, 0x303C },
|
||||||
|
{ 0x3041, 0x3096 },
|
||||||
|
{ 0x309D, 0x309F },
|
||||||
|
{ 0x30A1, 0x30FA },
|
||||||
|
{ 0x30FC, 0x30FF },
|
||||||
|
{ 0x3105, 0x312F },
|
||||||
|
{ 0x3131, 0x318E },
|
||||||
|
{ 0x31A0, 0x31BF },
|
||||||
|
{ 0x31F0, 0x31FF },
|
||||||
|
{ 0x9FFF, 0xA48C },
|
||||||
|
{ 0xA4D0, 0xA4FD },
|
||||||
|
{ 0xA500, 0xA60C },
|
||||||
|
{ 0xA610, 0xA61F },
|
||||||
|
{ 0xA62A, 0xA62B },
|
||||||
|
{ 0xA640, 0xA66E },
|
||||||
|
{ 0xA67F, 0xA69D },
|
||||||
|
{ 0xA6A0, 0xA6E5 },
|
||||||
|
{ 0xA717, 0xA71F },
|
||||||
|
{ 0xA722, 0xA788 },
|
||||||
|
{ 0xA78B, 0xA7CA },
|
||||||
|
{ 0xA7D0, 0xA7D1 },
|
||||||
|
{ 0xA7D5, 0xA7D9 },
|
||||||
|
{ 0xA7F2, 0xA801 },
|
||||||
|
{ 0xA803, 0xA805 },
|
||||||
|
{ 0xA807, 0xA80A },
|
||||||
|
{ 0xA80C, 0xA822 },
|
||||||
|
{ 0xA840, 0xA873 },
|
||||||
|
{ 0xA882, 0xA8B3 },
|
||||||
|
{ 0xA8F2, 0xA8F7 },
|
||||||
|
{ 0xA8FD, 0xA8FE },
|
||||||
|
{ 0xA90A, 0xA925 },
|
||||||
|
{ 0xA930, 0xA946 },
|
||||||
|
{ 0xA960, 0xA97C },
|
||||||
|
{ 0xA984, 0xA9B2 },
|
||||||
|
{ 0xA9E0, 0xA9E4 },
|
||||||
|
{ 0xA9E6, 0xA9EF },
|
||||||
|
{ 0xA9FA, 0xA9FE },
|
||||||
|
{ 0xAA00, 0xAA28 },
|
||||||
|
{ 0xAA40, 0xAA42 },
|
||||||
|
{ 0xAA44, 0xAA4B },
|
||||||
|
{ 0xAA60, 0xAA76 },
|
||||||
|
{ 0xAA7E, 0xAAAF },
|
||||||
|
{ 0xAAB5, 0xAAB6 },
|
||||||
|
{ 0xAAB9, 0xAABD },
|
||||||
|
{ 0xAADB, 0xAADD },
|
||||||
|
{ 0xAAE0, 0xAAEA },
|
||||||
|
{ 0xAAF2, 0xAAF4 },
|
||||||
|
{ 0xAB01, 0xAB06 },
|
||||||
|
{ 0xAB09, 0xAB0E },
|
||||||
|
{ 0xAB11, 0xAB16 },
|
||||||
|
{ 0xAB20, 0xAB26 },
|
||||||
|
{ 0xAB28, 0xAB2E },
|
||||||
|
{ 0xAB30, 0xAB5A },
|
||||||
|
{ 0xAB5C, 0xAB69 },
|
||||||
|
{ 0xAB70, 0xABE2 },
|
||||||
|
{ 0xD7B0, 0xD7C6 },
|
||||||
|
{ 0xD7CB, 0xD7FB },
|
||||||
|
{ 0xF900, 0xFA6D },
|
||||||
|
{ 0xFA70, 0xFAD9 },
|
||||||
|
{ 0xFB00, 0xFB06 },
|
||||||
|
{ 0xFB13, 0xFB17 },
|
||||||
|
{ 0xFB1F, 0xFB28 },
|
||||||
|
{ 0xFB2A, 0xFB36 },
|
||||||
|
{ 0xFB38, 0xFB3C },
|
||||||
|
{ 0xFB40, 0xFB41 },
|
||||||
|
{ 0xFB43, 0xFB44 },
|
||||||
|
{ 0xFB46, 0xFBB1 },
|
||||||
|
{ 0xFBD3, 0xFD3D },
|
||||||
|
{ 0xFD50, 0xFD8F },
|
||||||
|
{ 0xFD92, 0xFDC7 },
|
||||||
|
{ 0xFDF0, 0xFDFB },
|
||||||
|
{ 0xFE70, 0xFE74 },
|
||||||
|
{ 0xFE76, 0xFEFC },
|
||||||
|
{ 0xFF21, 0xFF3A },
|
||||||
|
{ 0xFF41, 0xFF5A },
|
||||||
|
{ 0xFF66, 0xFFBE },
|
||||||
|
{ 0xFFC2, 0xFFC7 },
|
||||||
|
{ 0xFFCA, 0xFFCF },
|
||||||
|
{ 0xFFD2, 0xFFD7 },
|
||||||
|
{ 0xFFDA, 0xFFDC },
|
||||||
|
{ 0x10000, 0x1000B },
|
||||||
|
{ 0x1000D, 0x10026 },
|
||||||
|
{ 0x10028, 0x1003A },
|
||||||
|
{ 0x1003C, 0x1003D },
|
||||||
|
{ 0x1003F, 0x1004D },
|
||||||
|
{ 0x10050, 0x1005D },
|
||||||
|
{ 0x10080, 0x100FA },
|
||||||
|
{ 0x10280, 0x1029C },
|
||||||
|
{ 0x102A0, 0x102D0 },
|
||||||
|
{ 0x10300, 0x1031F },
|
||||||
|
{ 0x1032D, 0x10340 },
|
||||||
|
{ 0x10342, 0x10349 },
|
||||||
|
{ 0x10350, 0x10375 },
|
||||||
|
{ 0x10380, 0x1039D },
|
||||||
|
{ 0x103A0, 0x103C3 },
|
||||||
|
{ 0x103C8, 0x103CF },
|
||||||
|
{ 0x10400, 0x1049D },
|
||||||
|
{ 0x104B0, 0x104D3 },
|
||||||
|
{ 0x104D8, 0x104FB },
|
||||||
|
{ 0x10500, 0x10527 },
|
||||||
|
{ 0x10530, 0x10563 },
|
||||||
|
{ 0x10570, 0x1057A },
|
||||||
|
{ 0x1057C, 0x1058A },
|
||||||
|
{ 0x1058C, 0x10592 },
|
||||||
|
{ 0x10594, 0x10595 },
|
||||||
|
{ 0x10597, 0x105A1 },
|
||||||
|
{ 0x105A3, 0x105B1 },
|
||||||
|
{ 0x105B3, 0x105B9 },
|
||||||
|
{ 0x105BB, 0x105BC },
|
||||||
|
{ 0x10600, 0x10736 },
|
||||||
|
{ 0x10740, 0x10755 },
|
||||||
|
{ 0x10760, 0x10767 },
|
||||||
|
{ 0x10780, 0x10785 },
|
||||||
|
{ 0x10787, 0x107B0 },
|
||||||
|
{ 0x107B2, 0x107BA },
|
||||||
|
{ 0x10800, 0x10805 },
|
||||||
|
{ 0x1080A, 0x10835 },
|
||||||
|
{ 0x10837, 0x10838 },
|
||||||
|
{ 0x1083F, 0x10855 },
|
||||||
|
{ 0x10860, 0x10876 },
|
||||||
|
{ 0x10880, 0x1089E },
|
||||||
|
{ 0x108E0, 0x108F2 },
|
||||||
|
{ 0x108F4, 0x108F5 },
|
||||||
|
{ 0x10900, 0x10915 },
|
||||||
|
{ 0x10920, 0x10939 },
|
||||||
|
{ 0x10980, 0x109B7 },
|
||||||
|
{ 0x109BE, 0x109BF },
|
||||||
|
{ 0x10A10, 0x10A13 },
|
||||||
|
{ 0x10A15, 0x10A17 },
|
||||||
|
{ 0x10A19, 0x10A35 },
|
||||||
|
{ 0x10A60, 0x10A7C },
|
||||||
|
{ 0x10A80, 0x10A9C },
|
||||||
|
{ 0x10AC0, 0x10AC7 },
|
||||||
|
{ 0x10AC9, 0x10AE4 },
|
||||||
|
{ 0x10B00, 0x10B35 },
|
||||||
|
{ 0x10B40, 0x10B55 },
|
||||||
|
{ 0x10B60, 0x10B72 },
|
||||||
|
{ 0x10B80, 0x10B91 },
|
||||||
|
{ 0x10C00, 0x10C48 },
|
||||||
|
{ 0x10C80, 0x10CB2 },
|
||||||
|
{ 0x10CC0, 0x10CF2 },
|
||||||
|
{ 0x10D00, 0x10D23 },
|
||||||
|
{ 0x10E80, 0x10EA9 },
|
||||||
|
{ 0x10EB0, 0x10EB1 },
|
||||||
|
{ 0x10F00, 0x10F1C },
|
||||||
|
{ 0x10F30, 0x10F45 },
|
||||||
|
{ 0x10F70, 0x10F81 },
|
||||||
|
{ 0x10FB0, 0x10FC4 },
|
||||||
|
{ 0x10FE0, 0x10FF6 },
|
||||||
|
{ 0x11003, 0x11037 },
|
||||||
|
{ 0x11071, 0x11072 },
|
||||||
|
{ 0x11083, 0x110AF },
|
||||||
|
{ 0x110D0, 0x110E8 },
|
||||||
|
{ 0x11103, 0x11126 },
|
||||||
|
{ 0x11150, 0x11172 },
|
||||||
|
{ 0x11183, 0x111B2 },
|
||||||
|
{ 0x111C1, 0x111C4 },
|
||||||
|
{ 0x11200, 0x11211 },
|
||||||
|
{ 0x11213, 0x1122B },
|
||||||
|
{ 0x1123F, 0x11240 },
|
||||||
|
{ 0x11280, 0x11286 },
|
||||||
|
{ 0x1128A, 0x1128D },
|
||||||
|
{ 0x1128F, 0x1129D },
|
||||||
|
{ 0x1129F, 0x112A8 },
|
||||||
|
{ 0x112B0, 0x112DE },
|
||||||
|
{ 0x11305, 0x1130C },
|
||||||
|
{ 0x1130F, 0x11310 },
|
||||||
|
{ 0x11313, 0x11328 },
|
||||||
|
{ 0x1132A, 0x11330 },
|
||||||
|
{ 0x11332, 0x11333 },
|
||||||
|
{ 0x11335, 0x11339 },
|
||||||
|
{ 0x1135D, 0x11361 },
|
||||||
|
{ 0x11400, 0x11434 },
|
||||||
|
{ 0x11447, 0x1144A },
|
||||||
|
{ 0x1145F, 0x11461 },
|
||||||
|
{ 0x11480, 0x114AF },
|
||||||
|
{ 0x114C4, 0x114C5 },
|
||||||
|
{ 0x11580, 0x115AE },
|
||||||
|
{ 0x115D8, 0x115DB },
|
||||||
|
{ 0x11600, 0x1162F },
|
||||||
|
{ 0x11680, 0x116AA },
|
||||||
|
{ 0x11700, 0x1171A },
|
||||||
|
{ 0x11740, 0x11746 },
|
||||||
|
{ 0x11800, 0x1182B },
|
||||||
|
{ 0x118A0, 0x118DF },
|
||||||
|
{ 0x118FF, 0x11906 },
|
||||||
|
{ 0x1190C, 0x11913 },
|
||||||
|
{ 0x11915, 0x11916 },
|
||||||
|
{ 0x11918, 0x1192F },
|
||||||
|
{ 0x119A0, 0x119A7 },
|
||||||
|
{ 0x119AA, 0x119D0 },
|
||||||
|
{ 0x11A0B, 0x11A32 },
|
||||||
|
{ 0x11A5C, 0x11A89 },
|
||||||
|
{ 0x11AB0, 0x11AF8 },
|
||||||
|
{ 0x11C00, 0x11C08 },
|
||||||
|
{ 0x11C0A, 0x11C2E },
|
||||||
|
{ 0x11C72, 0x11C8F },
|
||||||
|
{ 0x11D00, 0x11D06 },
|
||||||
|
{ 0x11D08, 0x11D09 },
|
||||||
|
{ 0x11D0B, 0x11D30 },
|
||||||
|
{ 0x11D60, 0x11D65 },
|
||||||
|
{ 0x11D67, 0x11D68 },
|
||||||
|
{ 0x11D6A, 0x11D89 },
|
||||||
|
{ 0x11EE0, 0x11EF2 },
|
||||||
|
{ 0x11F04, 0x11F10 },
|
||||||
|
{ 0x11F12, 0x11F33 },
|
||||||
|
{ 0x12000, 0x12399 },
|
||||||
|
{ 0x12480, 0x12543 },
|
||||||
|
{ 0x12F90, 0x12FF0 },
|
||||||
|
{ 0x13000, 0x1342F },
|
||||||
|
{ 0x13441, 0x13446 },
|
||||||
|
{ 0x14400, 0x14646 },
|
||||||
|
{ 0x16800, 0x16A38 },
|
||||||
|
{ 0x16A40, 0x16A5E },
|
||||||
|
{ 0x16A70, 0x16ABE },
|
||||||
|
{ 0x16AD0, 0x16AED },
|
||||||
|
{ 0x16B00, 0x16B2F },
|
||||||
|
{ 0x16B40, 0x16B43 },
|
||||||
|
{ 0x16B63, 0x16B77 },
|
||||||
|
{ 0x16B7D, 0x16B8F },
|
||||||
|
{ 0x16E40, 0x16E7F },
|
||||||
|
{ 0x16F00, 0x16F4A },
|
||||||
|
{ 0x16F93, 0x16F9F },
|
||||||
|
{ 0x16FE0, 0x16FE1 },
|
||||||
|
{ 0x18800, 0x18CD5 },
|
||||||
|
{ 0x1AFF0, 0x1AFF3 },
|
||||||
|
{ 0x1AFF5, 0x1AFFB },
|
||||||
|
{ 0x1AFFD, 0x1AFFE },
|
||||||
|
{ 0x1B000, 0x1B122 },
|
||||||
|
{ 0x1B150, 0x1B152 },
|
||||||
|
{ 0x1B164, 0x1B167 },
|
||||||
|
{ 0x1B170, 0x1B2FB },
|
||||||
|
{ 0x1BC00, 0x1BC6A },
|
||||||
|
{ 0x1BC70, 0x1BC7C },
|
||||||
|
{ 0x1BC80, 0x1BC88 },
|
||||||
|
{ 0x1BC90, 0x1BC99 },
|
||||||
|
{ 0x1D400, 0x1D454 },
|
||||||
|
{ 0x1D456, 0x1D49C },
|
||||||
|
{ 0x1D49E, 0x1D49F },
|
||||||
|
{ 0x1D4A5, 0x1D4A6 },
|
||||||
|
{ 0x1D4A9, 0x1D4AC },
|
||||||
|
{ 0x1D4AE, 0x1D4B9 },
|
||||||
|
{ 0x1D4BD, 0x1D4C3 },
|
||||||
|
{ 0x1D4C5, 0x1D505 },
|
||||||
|
{ 0x1D507, 0x1D50A },
|
||||||
|
{ 0x1D50D, 0x1D514 },
|
||||||
|
{ 0x1D516, 0x1D51C },
|
||||||
|
{ 0x1D51E, 0x1D539 },
|
||||||
|
{ 0x1D53B, 0x1D53E },
|
||||||
|
{ 0x1D540, 0x1D544 },
|
||||||
|
{ 0x1D54A, 0x1D550 },
|
||||||
|
{ 0x1D552, 0x1D6A5 },
|
||||||
|
{ 0x1D6A8, 0x1D6C0 },
|
||||||
|
{ 0x1D6C2, 0x1D6DA },
|
||||||
|
{ 0x1D6DC, 0x1D6FA },
|
||||||
|
{ 0x1D6FC, 0x1D714 },
|
||||||
|
{ 0x1D716, 0x1D734 },
|
||||||
|
{ 0x1D736, 0x1D74E },
|
||||||
|
{ 0x1D750, 0x1D76E },
|
||||||
|
{ 0x1D770, 0x1D788 },
|
||||||
|
{ 0x1D78A, 0x1D7A8 },
|
||||||
|
{ 0x1D7AA, 0x1D7C2 },
|
||||||
|
{ 0x1D7C4, 0x1D7CB },
|
||||||
|
{ 0x1DF00, 0x1DF1E },
|
||||||
|
{ 0x1DF25, 0x1DF2A },
|
||||||
|
{ 0x1E030, 0x1E06D },
|
||||||
|
{ 0x1E100, 0x1E12C },
|
||||||
|
{ 0x1E137, 0x1E13D },
|
||||||
|
{ 0x1E290, 0x1E2AD },
|
||||||
|
{ 0x1E2C0, 0x1E2EB },
|
||||||
|
{ 0x1E4D0, 0x1E4EB },
|
||||||
|
{ 0x1E7E0, 0x1E7E6 },
|
||||||
|
{ 0x1E7E8, 0x1E7EB },
|
||||||
|
{ 0x1E7ED, 0x1E7EE },
|
||||||
|
{ 0x1E7F0, 0x1E7FE },
|
||||||
|
{ 0x1E800, 0x1E8C4 },
|
||||||
|
{ 0x1E900, 0x1E943 },
|
||||||
|
{ 0x1EE00, 0x1EE03 },
|
||||||
|
{ 0x1EE05, 0x1EE1F },
|
||||||
|
{ 0x1EE21, 0x1EE22 },
|
||||||
|
{ 0x1EE29, 0x1EE32 },
|
||||||
|
{ 0x1EE34, 0x1EE37 },
|
||||||
|
{ 0x1EE4D, 0x1EE4F },
|
||||||
|
{ 0x1EE51, 0x1EE52 },
|
||||||
|
{ 0x1EE61, 0x1EE62 },
|
||||||
|
{ 0x1EE67, 0x1EE6A },
|
||||||
|
{ 0x1EE6C, 0x1EE72 },
|
||||||
|
{ 0x1EE74, 0x1EE77 },
|
||||||
|
{ 0x1EE79, 0x1EE7C },
|
||||||
|
{ 0x1EE80, 0x1EE89 },
|
||||||
|
{ 0x1EE8B, 0x1EE9B },
|
||||||
|
{ 0x1EEA1, 0x1EEA3 },
|
||||||
|
{ 0x1EEA5, 0x1EEA9 },
|
||||||
|
{ 0x1EEAB, 0x1EEBB },
|
||||||
|
{ 0x2F800, 0x2FA1D },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Rune alpha1[] = {
|
||||||
|
0x00AA,
|
||||||
|
0x00B5,
|
||||||
|
0x00BA,
|
||||||
|
0x0559,
|
||||||
|
0x06FF,
|
||||||
|
0x07B1,
|
||||||
|
0x07FA,
|
||||||
|
0x081A,
|
||||||
|
0x0824,
|
||||||
|
0x0828,
|
||||||
|
0x093D,
|
||||||
|
0x0950,
|
||||||
|
0x09BD,
|
||||||
|
0x09CE,
|
||||||
|
0x09FC,
|
||||||
|
0x0ABD,
|
||||||
|
0x0AD0,
|
||||||
|
0x0AF9,
|
||||||
|
0x0B3D,
|
||||||
|
0x0B71,
|
||||||
|
0x0BD0,
|
||||||
|
0x0C3D,
|
||||||
|
0x0C5D,
|
||||||
|
0x0C80,
|
||||||
|
0x0CBD,
|
||||||
|
0x0D3D,
|
||||||
|
0x0D4E,
|
||||||
|
0x0EBD,
|
||||||
|
0x0F00,
|
||||||
|
0x103F,
|
||||||
|
0x1061,
|
||||||
|
0x108E,
|
||||||
|
0x10CD,
|
||||||
|
0x17D7,
|
||||||
|
0x17DC,
|
||||||
|
0x1AA7,
|
||||||
|
0x1CFA,
|
||||||
|
0x2071,
|
||||||
|
0x207F,
|
||||||
|
0x2102,
|
||||||
|
0x2107,
|
||||||
|
0x214E,
|
||||||
|
0x2D2D,
|
||||||
|
0x2D6F,
|
||||||
|
0x2E2F,
|
||||||
|
0x3400,
|
||||||
|
0x4DBF,
|
||||||
|
0x4E00,
|
||||||
|
0xA9CF,
|
||||||
|
0xAA7A,
|
||||||
|
0xAC00,
|
||||||
|
0xD7A3,
|
||||||
|
0x1083C,
|
||||||
|
0x10A00,
|
||||||
|
0x10F27,
|
||||||
|
0x11075,
|
||||||
|
0x11144,
|
||||||
|
0x11147,
|
||||||
|
0x11176,
|
||||||
|
0x1133D,
|
||||||
|
0x11350,
|
||||||
|
0x11644,
|
||||||
|
0x116B8,
|
||||||
|
0x11909,
|
||||||
|
0x11A00,
|
||||||
|
0x11A3A,
|
||||||
|
0x11A50,
|
||||||
|
0x11A9D,
|
||||||
|
0x11C40,
|
||||||
|
0x11D46,
|
||||||
|
0x11D98,
|
||||||
|
0x11FB0,
|
||||||
|
0x16F50,
|
||||||
|
0x17000,
|
||||||
|
0x187F7,
|
||||||
|
0x18D00,
|
||||||
|
0x18D08,
|
||||||
|
0x1B132,
|
||||||
|
0x1B155,
|
||||||
|
0x1D4A2,
|
||||||
|
0x1E14E,
|
||||||
|
0x1E94B,
|
||||||
|
0x1EE42,
|
||||||
|
0x20000,
|
||||||
|
0x2A6DF,
|
||||||
|
0x2A700,
|
||||||
|
0x2B739,
|
||||||
|
0x2B740,
|
||||||
|
0x2B81D,
|
||||||
|
0x2B820,
|
||||||
|
0x2CEA1,
|
||||||
|
0x2CEB0,
|
||||||
|
0x2EBE0,
|
||||||
|
0x30000,
|
||||||
|
0x3134A,
|
||||||
|
0x31350,
|
||||||
|
0x323AF,
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
isalpharune(Rune r)
|
||||||
|
{
|
||||||
|
const Rune *match;
|
||||||
|
|
||||||
|
if((match = bsearch(&r, alpha3, nelem(alpha3), sizeof *alpha3, &rune2cmp)))
|
||||||
|
return !((r - match[0]) % 2);
|
||||||
|
if(bsearch(&r, alpha2, nelem(alpha2), sizeof *alpha2, &rune2cmp))
|
||||||
|
return 1;
|
||||||
|
if(bsearch(&r, alpha1, nelem(alpha1), sizeof *alpha1, &rune1cmp))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/* Automatically generated by mkrunetype.awk */
|
||||||
|
#include "../utf.h"
|
||||||
|
#include "runetype.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
isblankrune(Rune r)
|
||||||
|
{
|
||||||
|
return r == ' ' || r == '\t';
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/* Automatically generated by mkrunetype.awk */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "../utf.h"
|
||||||
|
#include "runetype.h"
|
||||||
|
|
||||||
|
static const Rune cntrl2[][2] = {
|
||||||
|
{ 0x0000, 0x001F },
|
||||||
|
{ 0x007F, 0x009F },
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
iscntrlrune(Rune r)
|
||||||
|
{
|
||||||
|
if(bsearch(&r, cntrl2, nelem(cntrl2), sizeof *cntrl2, &rune2cmp))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/* Automatically generated by mkrunetype.awk */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "../utf.h"
|
||||||
|
#include "runetype.h"
|
||||||
|
|
||||||
|
static const Rune digit2[][2] = {
|
||||||
|
{ 0x0030, 0x0039 },
|
||||||
|
{ 0x0660, 0x0669 },
|
||||||
|
{ 0x06F0, 0x06F9 },
|
||||||
|
{ 0x07C0, 0x07C9 },
|
||||||
|
{ 0x0966, 0x096F },
|
||||||
|
{ 0x09E6, 0x09EF },
|
||||||
|
{ 0x0A66, 0x0A6F },
|
||||||
|
{ 0x0AE6, 0x0AEF },
|
||||||
|
{ 0x0B66, 0x0B6F },
|
||||||
|
{ 0x0BE6, 0x0BEF },
|
||||||
|
{ 0x0C66, 0x0C6F },
|
||||||
|
{ 0x0CE6, 0x0CEF },
|
||||||
|
{ 0x0D66, 0x0D6F },
|
||||||
|
{ 0x0DE6, 0x0DEF },
|
||||||
|
{ 0x0E50, 0x0E59 },
|
||||||
|
{ 0x0ED0, 0x0ED9 },
|
||||||
|
{ 0x0F20, 0x0F29 },
|
||||||
|
{ 0x1040, 0x1049 },
|
||||||
|
{ 0x1090, 0x1099 },
|
||||||
|
{ 0x17E0, 0x17E9 },
|
||||||
|
{ 0x1810, 0x1819 },
|
||||||
|
{ 0x1946, 0x194F },
|
||||||
|
{ 0x19D0, 0x19D9 },
|
||||||
|
{ 0x1A80, 0x1A89 },
|
||||||
|
{ 0x1A90, 0x1A99 },
|
||||||
|
{ 0x1B50, 0x1B59 },
|
||||||
|
{ 0x1BB0, 0x1BB9 },
|
||||||
|
{ 0x1C40, 0x1C49 },
|
||||||
|
{ 0x1C50, 0x1C59 },
|
||||||
|
{ 0xA620, 0xA629 },
|
||||||
|
{ 0xA8D0, 0xA8D9 },
|
||||||
|
{ 0xA900, 0xA909 },
|
||||||
|
{ 0xA9D0, 0xA9D9 },
|
||||||
|
{ 0xA9F0, 0xA9F9 },
|
||||||
|
{ 0xAA50, 0xAA59 },
|
||||||
|
{ 0xABF0, 0xABF9 },
|
||||||
|
{ 0xFF10, 0xFF19 },
|
||||||
|
{ 0x104A0, 0x104A9 },
|
||||||
|
{ 0x10D30, 0x10D39 },
|
||||||
|
{ 0x11066, 0x1106F },
|
||||||
|
{ 0x110F0, 0x110F9 },
|
||||||
|
{ 0x11136, 0x1113F },
|
||||||
|
{ 0x111D0, 0x111D9 },
|
||||||
|
{ 0x112F0, 0x112F9 },
|
||||||
|
{ 0x11450, 0x11459 },
|
||||||
|
{ 0x114D0, 0x114D9 },
|
||||||
|
{ 0x11650, 0x11659 },
|
||||||
|
{ 0x116C0, 0x116C9 },
|
||||||
|
{ 0x11730, 0x11739 },
|
||||||
|
{ 0x118E0, 0x118E9 },
|
||||||
|
{ 0x11950, 0x11959 },
|
||||||
|
{ 0x11C50, 0x11C59 },
|
||||||
|
{ 0x11D50, 0x11D59 },
|
||||||
|
{ 0x11DA0, 0x11DA9 },
|
||||||
|
{ 0x11F50, 0x11F59 },
|
||||||
|
{ 0x16A60, 0x16A69 },
|
||||||
|
{ 0x16AC0, 0x16AC9 },
|
||||||
|
{ 0x16B50, 0x16B59 },
|
||||||
|
{ 0x1D7CE, 0x1D7FF },
|
||||||
|
{ 0x1E140, 0x1E149 },
|
||||||
|
{ 0x1E2F0, 0x1E2F9 },
|
||||||
|
{ 0x1E4F0, 0x1E4F9 },
|
||||||
|
{ 0x1E950, 0x1E959 },
|
||||||
|
{ 0x1FBF0, 0x1FBF9 },
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
isdigitrune(Rune r)
|
||||||
|
{
|
||||||
|
if(bsearch(&r, digit2, nelem(digit2), sizeof *digit2, &rune2cmp))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/* Automatically generated by mkrunetype.awk */
|
||||||
|
#include "../utf.h"
|
||||||
|
#include "runetype.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
isgraphrune(Rune r)
|
||||||
|
{
|
||||||
|
return !isspacerune(r) && isprintrune(r);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/* Automatically generated by mkrunetype.awk */
|
||||||
|
#include "../utf.h"
|
||||||
|
#include "runetype.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
isprintrune(Rune r)
|
||||||
|
{
|
||||||
|
return !iscntrlrune(r) && (r != 0x2028) && (r != 0x2029) &&
|
||||||
|
((r < 0xFFF9) || (r > 0xFFFB));
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/* Automatically generated by mkrunetype.awk */
|
||||||
|
#include "../utf.h"
|
||||||
|
#include "runetype.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
ispunctrune(Rune r)
|
||||||
|
{
|
||||||
|
return isgraphrune(r) && !isalnumrune(r);
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/* Automatically generated by mkrunetype.awk */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "../utf.h"
|
||||||
|
#include "runetype.h"
|
||||||
|
|
||||||
|
static const Rune space2[][2] = {
|
||||||
|
{ 0x0009, 0x000D },
|
||||||
|
{ 0x001C, 0x0020 },
|
||||||
|
{ 0x2000, 0x200A },
|
||||||
|
{ 0x2028, 0x2029 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Rune space1[] = {
|
||||||
|
0x0085,
|
||||||
|
0x00A0,
|
||||||
|
0x1680,
|
||||||
|
0x202F,
|
||||||
|
0x205F,
|
||||||
|
0x3000,
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
isspacerune(Rune r)
|
||||||
|
{
|
||||||
|
if(bsearch(&r, space2, nelem(space2), sizeof *space2, &rune2cmp))
|
||||||
|
return 1;
|
||||||
|
if(bsearch(&r, space1, nelem(space1), sizeof *space1, &rune1cmp))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/* Automatically generated by mkrunetype.awk */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "../utf.h"
|
||||||
|
#include "runetype.h"
|
||||||
|
|
||||||
|
static const Rune title2[][2] = {
|
||||||
|
{ 0x1F88, 0x1F8F },
|
||||||
|
{ 0x1F98, 0x1F9F },
|
||||||
|
{ 0x1FA8, 0x1FAF },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Rune title1[] = {
|
||||||
|
0x01C5,
|
||||||
|
0x01C8,
|
||||||
|
0x01CB,
|
||||||
|
0x01F2,
|
||||||
|
0x1FBC,
|
||||||
|
0x1FCC,
|
||||||
|
0x1FFC,
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
istitlerune(Rune r)
|
||||||
|
{
|
||||||
|
if(bsearch(&r, title2, nelem(title2), sizeof *title2, &rune2cmp))
|
||||||
|
return 1;
|
||||||
|
if(bsearch(&r, title1, nelem(title1), sizeof *title1, &rune1cmp))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/* Automatically generated by mkrunetype.awk */
|
||||||
|
#include "../utf.h"
|
||||||
|
#include "runetype.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
isxdigitrune(Rune r)
|
||||||
|
{
|
||||||
|
return (r >= '0' && (r - '0') < 10) || (r >= 'a' && (r - 'a') < 6);
|
||||||
|
}
|
||||||
@@ -0,0 +1,356 @@
|
|||||||
|
/* Automatically generated by mkrunetype.awk */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "../utf.h"
|
||||||
|
#include "runetype.h"
|
||||||
|
|
||||||
|
static const Rune lower4[][2] = {
|
||||||
|
{ 0x0101, 0x012F },
|
||||||
|
{ 0x0133, 0x0137 },
|
||||||
|
{ 0x013A, 0x0148 },
|
||||||
|
{ 0x014B, 0x0177 },
|
||||||
|
{ 0x017A, 0x017E },
|
||||||
|
{ 0x0183, 0x0185 },
|
||||||
|
{ 0x01A1, 0x01A5 },
|
||||||
|
{ 0x01B4, 0x01B6 },
|
||||||
|
{ 0x01CE, 0x01DC },
|
||||||
|
{ 0x01DF, 0x01EF },
|
||||||
|
{ 0x01F9, 0x021F },
|
||||||
|
{ 0x0223, 0x0233 },
|
||||||
|
{ 0x0247, 0x024F },
|
||||||
|
{ 0x0371, 0x0373 },
|
||||||
|
{ 0x03D9, 0x03EF },
|
||||||
|
{ 0x0461, 0x0481 },
|
||||||
|
{ 0x048B, 0x04BF },
|
||||||
|
{ 0x04C2, 0x04CE },
|
||||||
|
{ 0x04D1, 0x052F },
|
||||||
|
{ 0x1E01, 0x1E95 },
|
||||||
|
{ 0x1EA1, 0x1EFF },
|
||||||
|
{ 0x2C68, 0x2C6C },
|
||||||
|
{ 0x2C81, 0x2CE3 },
|
||||||
|
{ 0x2CEC, 0x2CEE },
|
||||||
|
{ 0xA641, 0xA66D },
|
||||||
|
{ 0xA681, 0xA69B },
|
||||||
|
{ 0xA723, 0xA72F },
|
||||||
|
{ 0xA733, 0xA76F },
|
||||||
|
{ 0xA77A, 0xA77C },
|
||||||
|
{ 0xA77F, 0xA787 },
|
||||||
|
{ 0xA791, 0xA793 },
|
||||||
|
{ 0xA797, 0xA7A9 },
|
||||||
|
{ 0xA7B5, 0xA7C3 },
|
||||||
|
{ 0xA7C8, 0xA7CA },
|
||||||
|
{ 0xA7D7, 0xA7D9 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Rune lower2[][3] = {
|
||||||
|
{ 0x0061, 0x007A, 0x0041 },
|
||||||
|
{ 0x00E0, 0x00F6, 0x00C0 },
|
||||||
|
{ 0x00F8, 0x00FE, 0x00D8 },
|
||||||
|
{ 0x01AA, 0x01AB, 0x01AA },
|
||||||
|
{ 0x0234, 0x0239, 0x0234 },
|
||||||
|
{ 0x023F, 0x0240, 0x2C7E },
|
||||||
|
{ 0x0256, 0x0257, 0x0189 },
|
||||||
|
{ 0x025D, 0x025F, 0x025D },
|
||||||
|
{ 0x026D, 0x026E, 0x026D },
|
||||||
|
{ 0x0273, 0x0274, 0x0273 },
|
||||||
|
{ 0x0276, 0x027C, 0x0276 },
|
||||||
|
{ 0x027E, 0x027F, 0x027E },
|
||||||
|
{ 0x0284, 0x0286, 0x0284 },
|
||||||
|
{ 0x028A, 0x028B, 0x01B1 },
|
||||||
|
{ 0x028D, 0x0291, 0x028D },
|
||||||
|
{ 0x0295, 0x029C, 0x0295 },
|
||||||
|
{ 0x029F, 0x02AF, 0x029F },
|
||||||
|
{ 0x037B, 0x037D, 0x03FD },
|
||||||
|
{ 0x03AD, 0x03AF, 0x0388 },
|
||||||
|
{ 0x03B1, 0x03C1, 0x0391 },
|
||||||
|
{ 0x03C3, 0x03CB, 0x03A3 },
|
||||||
|
{ 0x03CD, 0x03CE, 0x038E },
|
||||||
|
{ 0x0430, 0x044F, 0x0410 },
|
||||||
|
{ 0x0450, 0x045F, 0x0400 },
|
||||||
|
{ 0x0561, 0x0586, 0x0531 },
|
||||||
|
{ 0x0587, 0x0588, 0x0587 },
|
||||||
|
{ 0x10D0, 0x10FA, 0x1C90 },
|
||||||
|
{ 0x10FD, 0x10FF, 0x1CBD },
|
||||||
|
{ 0x13F8, 0x13FD, 0x13F0 },
|
||||||
|
{ 0x1C83, 0x1C84, 0x0421 },
|
||||||
|
{ 0x1D00, 0x1D2B, 0x1D00 },
|
||||||
|
{ 0x1D6B, 0x1D77, 0x1D6B },
|
||||||
|
{ 0x1D7A, 0x1D7C, 0x1D7A },
|
||||||
|
{ 0x1D7E, 0x1D8D, 0x1D7E },
|
||||||
|
{ 0x1D8F, 0x1D9A, 0x1D8F },
|
||||||
|
{ 0x1E96, 0x1E9A, 0x1E96 },
|
||||||
|
{ 0x1E9C, 0x1E9D, 0x1E9C },
|
||||||
|
{ 0x1F00, 0x1F07, 0x1F08 },
|
||||||
|
{ 0x1F10, 0x1F15, 0x1F18 },
|
||||||
|
{ 0x1F20, 0x1F27, 0x1F28 },
|
||||||
|
{ 0x1F30, 0x1F37, 0x1F38 },
|
||||||
|
{ 0x1F40, 0x1F45, 0x1F48 },
|
||||||
|
{ 0x1F60, 0x1F67, 0x1F68 },
|
||||||
|
{ 0x1F70, 0x1F71, 0x1FBA },
|
||||||
|
{ 0x1F72, 0x1F75, 0x1FC8 },
|
||||||
|
{ 0x1F76, 0x1F77, 0x1FDA },
|
||||||
|
{ 0x1F78, 0x1F79, 0x1FF8 },
|
||||||
|
{ 0x1F7A, 0x1F7B, 0x1FEA },
|
||||||
|
{ 0x1F7C, 0x1F7D, 0x1FFA },
|
||||||
|
{ 0x1F80, 0x1F87, 0x1F88 },
|
||||||
|
{ 0x1F90, 0x1F97, 0x1F98 },
|
||||||
|
{ 0x1FA0, 0x1FA7, 0x1FA8 },
|
||||||
|
{ 0x1FB0, 0x1FB1, 0x1FB8 },
|
||||||
|
{ 0x1FB6, 0x1FB7, 0x1FB6 },
|
||||||
|
{ 0x1FC6, 0x1FC7, 0x1FC6 },
|
||||||
|
{ 0x1FD0, 0x1FD1, 0x1FD8 },
|
||||||
|
{ 0x1FD2, 0x1FD3, 0x1FD2 },
|
||||||
|
{ 0x1FD6, 0x1FD7, 0x1FD6 },
|
||||||
|
{ 0x1FE0, 0x1FE1, 0x1FE8 },
|
||||||
|
{ 0x1FE2, 0x1FE4, 0x1FE2 },
|
||||||
|
{ 0x1FE6, 0x1FE7, 0x1FE6 },
|
||||||
|
{ 0x1FF6, 0x1FF7, 0x1FF6 },
|
||||||
|
{ 0x210E, 0x210F, 0x210E },
|
||||||
|
{ 0x213C, 0x213D, 0x213C },
|
||||||
|
{ 0x2146, 0x2149, 0x2146 },
|
||||||
|
{ 0x2C30, 0x2C5F, 0x2C00 },
|
||||||
|
{ 0x2C77, 0x2C7B, 0x2C77 },
|
||||||
|
{ 0x2D00, 0x2D25, 0x10A0 },
|
||||||
|
{ 0xA730, 0xA731, 0xA730 },
|
||||||
|
{ 0xA771, 0xA778, 0xA771 },
|
||||||
|
{ 0xAB30, 0xAB52, 0xAB30 },
|
||||||
|
{ 0xAB54, 0xAB5A, 0xAB54 },
|
||||||
|
{ 0xAB60, 0xAB68, 0xAB60 },
|
||||||
|
{ 0xAB70, 0xABBF, 0x13A0 },
|
||||||
|
{ 0xFB00, 0xFB06, 0xFB00 },
|
||||||
|
{ 0xFB13, 0xFB17, 0xFB13 },
|
||||||
|
{ 0xFF41, 0xFF5A, 0xFF21 },
|
||||||
|
{ 0x10428, 0x1044F, 0x10400 },
|
||||||
|
{ 0x104D8, 0x104FB, 0x104B0 },
|
||||||
|
{ 0x10597, 0x105A1, 0x10570 },
|
||||||
|
{ 0x105A3, 0x105B1, 0x1057C },
|
||||||
|
{ 0x105B3, 0x105B9, 0x1058C },
|
||||||
|
{ 0x105BB, 0x105BC, 0x10594 },
|
||||||
|
{ 0x10CC0, 0x10CF2, 0x10C80 },
|
||||||
|
{ 0x118C0, 0x118DF, 0x118A0 },
|
||||||
|
{ 0x16E60, 0x16E7F, 0x16E40 },
|
||||||
|
{ 0x1D41A, 0x1D433, 0x1D41A },
|
||||||
|
{ 0x1D44E, 0x1D454, 0x1D44E },
|
||||||
|
{ 0x1D456, 0x1D467, 0x1D456 },
|
||||||
|
{ 0x1D482, 0x1D49B, 0x1D482 },
|
||||||
|
{ 0x1D4B6, 0x1D4B9, 0x1D4B6 },
|
||||||
|
{ 0x1D4BD, 0x1D4C3, 0x1D4BD },
|
||||||
|
{ 0x1D4C5, 0x1D4CF, 0x1D4C5 },
|
||||||
|
{ 0x1D4EA, 0x1D503, 0x1D4EA },
|
||||||
|
{ 0x1D51E, 0x1D537, 0x1D51E },
|
||||||
|
{ 0x1D552, 0x1D56B, 0x1D552 },
|
||||||
|
{ 0x1D586, 0x1D59F, 0x1D586 },
|
||||||
|
{ 0x1D5BA, 0x1D5D3, 0x1D5BA },
|
||||||
|
{ 0x1D5EE, 0x1D607, 0x1D5EE },
|
||||||
|
{ 0x1D622, 0x1D63B, 0x1D622 },
|
||||||
|
{ 0x1D656, 0x1D66F, 0x1D656 },
|
||||||
|
{ 0x1D68A, 0x1D6A5, 0x1D68A },
|
||||||
|
{ 0x1D6C2, 0x1D6DA, 0x1D6C2 },
|
||||||
|
{ 0x1D6DC, 0x1D6E1, 0x1D6DC },
|
||||||
|
{ 0x1D6FC, 0x1D714, 0x1D6FC },
|
||||||
|
{ 0x1D716, 0x1D71B, 0x1D716 },
|
||||||
|
{ 0x1D736, 0x1D74E, 0x1D736 },
|
||||||
|
{ 0x1D750, 0x1D755, 0x1D750 },
|
||||||
|
{ 0x1D770, 0x1D788, 0x1D770 },
|
||||||
|
{ 0x1D78A, 0x1D78F, 0x1D78A },
|
||||||
|
{ 0x1D7AA, 0x1D7C2, 0x1D7AA },
|
||||||
|
{ 0x1D7C4, 0x1D7C9, 0x1D7C4 },
|
||||||
|
{ 0x1DF00, 0x1DF09, 0x1DF00 },
|
||||||
|
{ 0x1DF0B, 0x1DF1E, 0x1DF0B },
|
||||||
|
{ 0x1DF25, 0x1DF2A, 0x1DF25 },
|
||||||
|
{ 0x1E922, 0x1E943, 0x1E900 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Rune lower1[][2] = {
|
||||||
|
{ 0x00B5, 0x039C },
|
||||||
|
{ 0x00DF, 0x00DF },
|
||||||
|
{ 0x00FF, 0x0178 },
|
||||||
|
{ 0x0131, 0x0049 },
|
||||||
|
{ 0x0138, 0x0138 },
|
||||||
|
{ 0x0149, 0x0149 },
|
||||||
|
{ 0x017F, 0x0053 },
|
||||||
|
{ 0x0180, 0x0243 },
|
||||||
|
{ 0x0188, 0x0187 },
|
||||||
|
{ 0x018C, 0x018B },
|
||||||
|
{ 0x018D, 0x018D },
|
||||||
|
{ 0x0192, 0x0191 },
|
||||||
|
{ 0x0195, 0x01F6 },
|
||||||
|
{ 0x0199, 0x0198 },
|
||||||
|
{ 0x019A, 0x023D },
|
||||||
|
{ 0x019B, 0x019B },
|
||||||
|
{ 0x019E, 0x0220 },
|
||||||
|
{ 0x01A8, 0x01A7 },
|
||||||
|
{ 0x01AD, 0x01AC },
|
||||||
|
{ 0x01B0, 0x01AF },
|
||||||
|
{ 0x01B9, 0x01B8 },
|
||||||
|
{ 0x01BA, 0x01BA },
|
||||||
|
{ 0x01BD, 0x01BC },
|
||||||
|
{ 0x01BE, 0x01BE },
|
||||||
|
{ 0x01BF, 0x01F7 },
|
||||||
|
{ 0x01C6, 0x01C4 },
|
||||||
|
{ 0x01C9, 0x01C7 },
|
||||||
|
{ 0x01CC, 0x01CA },
|
||||||
|
{ 0x01DD, 0x018E },
|
||||||
|
{ 0x01F0, 0x01F0 },
|
||||||
|
{ 0x01F3, 0x01F1 },
|
||||||
|
{ 0x01F5, 0x01F4 },
|
||||||
|
{ 0x0221, 0x0221 },
|
||||||
|
{ 0x023C, 0x023B },
|
||||||
|
{ 0x0242, 0x0241 },
|
||||||
|
{ 0x0250, 0x2C6F },
|
||||||
|
{ 0x0251, 0x2C6D },
|
||||||
|
{ 0x0252, 0x2C70 },
|
||||||
|
{ 0x0253, 0x0181 },
|
||||||
|
{ 0x0254, 0x0186 },
|
||||||
|
{ 0x0255, 0x0255 },
|
||||||
|
{ 0x0258, 0x0258 },
|
||||||
|
{ 0x0259, 0x018F },
|
||||||
|
{ 0x025A, 0x025A },
|
||||||
|
{ 0x025B, 0x0190 },
|
||||||
|
{ 0x025C, 0xA7AB },
|
||||||
|
{ 0x0260, 0x0193 },
|
||||||
|
{ 0x0261, 0xA7AC },
|
||||||
|
{ 0x0262, 0x0262 },
|
||||||
|
{ 0x0263, 0x0194 },
|
||||||
|
{ 0x0264, 0x0264 },
|
||||||
|
{ 0x0265, 0xA78D },
|
||||||
|
{ 0x0266, 0xA7AA },
|
||||||
|
{ 0x0267, 0x0267 },
|
||||||
|
{ 0x0268, 0x0197 },
|
||||||
|
{ 0x0269, 0x0196 },
|
||||||
|
{ 0x026A, 0xA7AE },
|
||||||
|
{ 0x026B, 0x2C62 },
|
||||||
|
{ 0x026C, 0xA7AD },
|
||||||
|
{ 0x026F, 0x019C },
|
||||||
|
{ 0x0270, 0x0270 },
|
||||||
|
{ 0x0271, 0x2C6E },
|
||||||
|
{ 0x0272, 0x019D },
|
||||||
|
{ 0x0275, 0x019F },
|
||||||
|
{ 0x027D, 0x2C64 },
|
||||||
|
{ 0x0280, 0x01A6 },
|
||||||
|
{ 0x0281, 0x0281 },
|
||||||
|
{ 0x0282, 0xA7C5 },
|
||||||
|
{ 0x0283, 0x01A9 },
|
||||||
|
{ 0x0287, 0xA7B1 },
|
||||||
|
{ 0x0288, 0x01AE },
|
||||||
|
{ 0x0289, 0x0244 },
|
||||||
|
{ 0x028C, 0x0245 },
|
||||||
|
{ 0x0292, 0x01B7 },
|
||||||
|
{ 0x0293, 0x0293 },
|
||||||
|
{ 0x029D, 0xA7B2 },
|
||||||
|
{ 0x029E, 0xA7B0 },
|
||||||
|
{ 0x0377, 0x0376 },
|
||||||
|
{ 0x0390, 0x0390 },
|
||||||
|
{ 0x03AC, 0x0386 },
|
||||||
|
{ 0x03B0, 0x03B0 },
|
||||||
|
{ 0x03C2, 0x03A3 },
|
||||||
|
{ 0x03CC, 0x038C },
|
||||||
|
{ 0x03D0, 0x0392 },
|
||||||
|
{ 0x03D1, 0x0398 },
|
||||||
|
{ 0x03D5, 0x03A6 },
|
||||||
|
{ 0x03D6, 0x03A0 },
|
||||||
|
{ 0x03D7, 0x03CF },
|
||||||
|
{ 0x03F0, 0x039A },
|
||||||
|
{ 0x03F1, 0x03A1 },
|
||||||
|
{ 0x03F2, 0x03F9 },
|
||||||
|
{ 0x03F3, 0x037F },
|
||||||
|
{ 0x03F5, 0x0395 },
|
||||||
|
{ 0x03F8, 0x03F7 },
|
||||||
|
{ 0x03FB, 0x03FA },
|
||||||
|
{ 0x03FC, 0x03FC },
|
||||||
|
{ 0x04CF, 0x04C0 },
|
||||||
|
{ 0x0560, 0x0560 },
|
||||||
|
{ 0x1C80, 0x0412 },
|
||||||
|
{ 0x1C81, 0x0414 },
|
||||||
|
{ 0x1C82, 0x041E },
|
||||||
|
{ 0x1C85, 0x0422 },
|
||||||
|
{ 0x1C86, 0x042A },
|
||||||
|
{ 0x1C87, 0x0462 },
|
||||||
|
{ 0x1C88, 0xA64A },
|
||||||
|
{ 0x1D79, 0xA77D },
|
||||||
|
{ 0x1D7D, 0x2C63 },
|
||||||
|
{ 0x1D8E, 0xA7C6 },
|
||||||
|
{ 0x1E9B, 0x1E60 },
|
||||||
|
{ 0x1E9F, 0x1E9F },
|
||||||
|
{ 0x1F50, 0x1F50 },
|
||||||
|
{ 0x1F51, 0x1F59 },
|
||||||
|
{ 0x1F52, 0x1F52 },
|
||||||
|
{ 0x1F53, 0x1F5B },
|
||||||
|
{ 0x1F54, 0x1F54 },
|
||||||
|
{ 0x1F55, 0x1F5D },
|
||||||
|
{ 0x1F56, 0x1F56 },
|
||||||
|
{ 0x1F57, 0x1F5F },
|
||||||
|
{ 0x1FB2, 0x1FB2 },
|
||||||
|
{ 0x1FB3, 0x1FBC },
|
||||||
|
{ 0x1FB4, 0x1FB4 },
|
||||||
|
{ 0x1FBE, 0x0399 },
|
||||||
|
{ 0x1FC2, 0x1FC2 },
|
||||||
|
{ 0x1FC3, 0x1FCC },
|
||||||
|
{ 0x1FC4, 0x1FC4 },
|
||||||
|
{ 0x1FE5, 0x1FEC },
|
||||||
|
{ 0x1FF2, 0x1FF2 },
|
||||||
|
{ 0x1FF3, 0x1FFC },
|
||||||
|
{ 0x1FF4, 0x1FF4 },
|
||||||
|
{ 0x210A, 0x210A },
|
||||||
|
{ 0x2113, 0x2113 },
|
||||||
|
{ 0x212F, 0x212F },
|
||||||
|
{ 0x2134, 0x2134 },
|
||||||
|
{ 0x2139, 0x2139 },
|
||||||
|
{ 0x214E, 0x2132 },
|
||||||
|
{ 0x2184, 0x2183 },
|
||||||
|
{ 0x2C61, 0x2C60 },
|
||||||
|
{ 0x2C65, 0x023A },
|
||||||
|
{ 0x2C66, 0x023E },
|
||||||
|
{ 0x2C71, 0x2C71 },
|
||||||
|
{ 0x2C73, 0x2C72 },
|
||||||
|
{ 0x2C74, 0x2C74 },
|
||||||
|
{ 0x2C76, 0x2C75 },
|
||||||
|
{ 0x2CE4, 0x2CE4 },
|
||||||
|
{ 0x2CF3, 0x2CF2 },
|
||||||
|
{ 0x2D27, 0x10C7 },
|
||||||
|
{ 0x2D2D, 0x10CD },
|
||||||
|
{ 0xA78C, 0xA78B },
|
||||||
|
{ 0xA78E, 0xA78E },
|
||||||
|
{ 0xA794, 0xA7C4 },
|
||||||
|
{ 0xA795, 0xA795 },
|
||||||
|
{ 0xA7AF, 0xA7AF },
|
||||||
|
{ 0xA7D1, 0xA7D0 },
|
||||||
|
{ 0xA7D3, 0xA7D3 },
|
||||||
|
{ 0xA7D5, 0xA7D5 },
|
||||||
|
{ 0xA7F6, 0xA7F5 },
|
||||||
|
{ 0xA7FA, 0xA7FA },
|
||||||
|
{ 0xAB53, 0xA7B3 },
|
||||||
|
{ 0x1D4BB, 0x1D4BB },
|
||||||
|
{ 0x1D7CB, 0x1D7CB },
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
islowerrune(Rune r)
|
||||||
|
{
|
||||||
|
const Rune *match;
|
||||||
|
|
||||||
|
if((match = bsearch(&r, lower4, nelem(lower4), sizeof *lower4, &rune2cmp)))
|
||||||
|
return !((r - match[0]) % 2);
|
||||||
|
if(bsearch(&r, lower2, nelem(lower2), sizeof *lower2, &rune2cmp))
|
||||||
|
return 1;
|
||||||
|
if(bsearch(&r, lower1, nelem(lower1), sizeof *lower1, &rune1cmp))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
toupperrune(Rune r)
|
||||||
|
{
|
||||||
|
Rune *match;
|
||||||
|
|
||||||
|
match = bsearch(&r, lower4, nelem(lower4), sizeof *lower4, &rune2cmp);
|
||||||
|
if (match)
|
||||||
|
return ((r - match[0]) % 2) ? r : r - 1;
|
||||||
|
match = bsearch(&r, lower2, nelem(lower2), sizeof *lower2, &rune2cmp);
|
||||||
|
if (match)
|
||||||
|
return match[2] + (r - match[0]);
|
||||||
|
match = bsearch(&r, lower1, nelem(lower1), sizeof *lower1, &rune1cmp);
|
||||||
|
if (match)
|
||||||
|
return match[1];
|
||||||
|
return r;
|
||||||
|
}
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
# See LICENSE file for copyright and license details.
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
FS = ";"
|
||||||
|
# set up hexadecimal lookup table
|
||||||
|
for(i = 0; i < 16; i++)
|
||||||
|
hex[sprintf("%X",i)] = i;
|
||||||
|
HEADER = "/* Automatically generated by mkrunetype.awk */\n#include <stdlib.h>\n\n#include \"../utf.h\"\n#include \"runetype.h\"\n"
|
||||||
|
HEADER_OTHER = "/* Automatically generated by mkrunetype.awk */\n#include \"../utf.h\"\n#include \"runetype.h\"\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
$3 ~ /^L/ { alphav[alphac++] = $1; }
|
||||||
|
($3 ~ /^Z/) || ($5 == "WS") || ($5 == "S") || ($5 == "B") { spacev[spacec++] = $1; }
|
||||||
|
$3 == "Cc" { cntrlv[cntrlc++] = $1; }
|
||||||
|
$3 == "Lu" { upperv[upperc++] = $1; tolowerv[uppercc++] = ($14 == "") ? $1 : $14; }
|
||||||
|
$3 == "Ll" { lowerv[lowerc++] = $1; toupperv[lowercc++] = ($13 == "") ? $1 : $13; }
|
||||||
|
$3 == "Lt" { titlev[titlec++] = $1; }
|
||||||
|
$3 == "Nd" { digitv[digitc++] = $1; }
|
||||||
|
|
||||||
|
END {
|
||||||
|
system("rm -f isalpharune.c isspacerune.c iscntrlrune.c upperrune.c lowerrune.c istitlerune.c isdigitrune.c");
|
||||||
|
|
||||||
|
mkis("alpha", alphav, alphac, "isalpharune.c", q, "");
|
||||||
|
mkis("space", spacev, spacec, "isspacerune.c", q, "");
|
||||||
|
mkis("cntrl", cntrlv, cntrlc, "iscntrlrune.c", q, "");
|
||||||
|
mkis("upper", upperv, upperc, "upperrune.c", tolowerv, "lower");
|
||||||
|
mkis("lower", lowerv, lowerc, "lowerrune.c", toupperv, "upper");
|
||||||
|
mkis("title", titlev, titlec, "istitlerune.c", q, "");
|
||||||
|
mkis("digit", digitv, digitc, "isdigitrune.c", q, "");
|
||||||
|
|
||||||
|
system("rm -f isalnumrune.c isblankrune.c isprintrune.c isgraphrune.c ispunctrune.c isxdigitrune.c");
|
||||||
|
|
||||||
|
otheris();
|
||||||
|
}
|
||||||
|
|
||||||
|
# parse hexadecimal rune index to int
|
||||||
|
function code(s) {
|
||||||
|
x = 0;
|
||||||
|
for(i = 1; i <= length(s); i++) {
|
||||||
|
c = substr(s, i, 1);
|
||||||
|
x = (x*16) + hex[c];
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate 'is<name>rune' unicode lookup function
|
||||||
|
function mkis(name, runev, runec, file, casev, casename) {
|
||||||
|
rune1c = 0;
|
||||||
|
rune2c = 0;
|
||||||
|
rune3c = 0;
|
||||||
|
rune4c = 0;
|
||||||
|
mode = 1;
|
||||||
|
|
||||||
|
#sort rune groups into singletons, ranges and laces
|
||||||
|
for(j = 0; j < runec; j++) {
|
||||||
|
# range
|
||||||
|
if(code(runev[j+1]) == code(runev[j])+1 && ((length(casev) == 0) ||
|
||||||
|
code(casev[j+1]) == code(casev[j])+1) && j+1 < runec) {
|
||||||
|
if (mode == 2) {
|
||||||
|
continue;
|
||||||
|
} else if (mode == 3) {
|
||||||
|
rune3v1[rune3c] = runev[j];
|
||||||
|
rune3c++;
|
||||||
|
} else if (mode == 4) {
|
||||||
|
rune4v1[rune4c] = runev[j];
|
||||||
|
rune4c++;
|
||||||
|
}
|
||||||
|
mode = 2;
|
||||||
|
rune2v0[rune2c] = runev[j];
|
||||||
|
if(length(casev) > 0) {
|
||||||
|
case2v[rune2c] = casev[j];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
# lace 1
|
||||||
|
if(code(runev[j+1]) == code(runev[j])+2 && ((length(casev) == 0) ||
|
||||||
|
(code(casev[j+1]) == code(runev[j+1])+1 && code(casev[j]) == code(runev[j])+1)) &&
|
||||||
|
j+1 < runec) {
|
||||||
|
if (mode == 3) {
|
||||||
|
continue;
|
||||||
|
} else if (mode == 2) {
|
||||||
|
rune2v1[rune2c] = runev[j];
|
||||||
|
rune2c++;
|
||||||
|
} else if (mode == 4) {
|
||||||
|
rune4v1[rune2c] = runev[j];
|
||||||
|
rune4c++;
|
||||||
|
}
|
||||||
|
mode = 3;
|
||||||
|
rune3v0[rune3c] = runev[j];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
# lace 2
|
||||||
|
if(code(runev[j+1]) == code(runev[j])+2 && ((length(casev) == 0) ||
|
||||||
|
(code(casev[j+1]) == code(runev[j+1])-1 && code(casev[j]) == code(runev[j])-1)) &&
|
||||||
|
j+1 < runec) {
|
||||||
|
if (mode == 4) {
|
||||||
|
continue;
|
||||||
|
} else if (mode == 2) {
|
||||||
|
rune2v1[rune2c] = runev[j];
|
||||||
|
rune2c++;
|
||||||
|
} else if (mode == 3) {
|
||||||
|
rune3v1[rune2c] = runev[j];
|
||||||
|
rune3c++;
|
||||||
|
}
|
||||||
|
mode = 4;
|
||||||
|
rune4v0[rune4c] = runev[j];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
# terminating case
|
||||||
|
if (mode == 1) {
|
||||||
|
rune1v[rune1c] = runev[j];
|
||||||
|
if (length(casev) > 0) {
|
||||||
|
case1v[rune1c] = casev[j];
|
||||||
|
}
|
||||||
|
rune1c++;
|
||||||
|
} else if (mode == 2) {
|
||||||
|
rune2v1[rune2c] = runev[j];
|
||||||
|
rune2c++;
|
||||||
|
} else if (mode == 3) {
|
||||||
|
rune3v1[rune3c] = runev[j];
|
||||||
|
rune3c++;
|
||||||
|
} else { #lace 2
|
||||||
|
rune4v1[rune4c] = runev[j];
|
||||||
|
rune4c++;
|
||||||
|
}
|
||||||
|
mode = 1;
|
||||||
|
}
|
||||||
|
print HEADER > file;
|
||||||
|
|
||||||
|
#generate list of laces 1
|
||||||
|
if(rune3c > 0) {
|
||||||
|
print "static const Rune "name"3[][2] = {" > file;
|
||||||
|
for(j = 0; j < rune3c; j++) {
|
||||||
|
print "\t{ 0x"rune3v0[j]", 0x"rune3v1[j]" }," > file;
|
||||||
|
}
|
||||||
|
print "};\n" > file;
|
||||||
|
}
|
||||||
|
|
||||||
|
#generate list of laces 2
|
||||||
|
if(rune4c > 0) {
|
||||||
|
print "static const Rune "name"4[][2] = {" > file;
|
||||||
|
for(j = 0; j < rune4c; j++) {
|
||||||
|
print "\t{ 0x"rune4v0[j]", 0x"rune4v1[j]" }," > file;
|
||||||
|
}
|
||||||
|
print "};\n" > file;
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate list of ranges
|
||||||
|
if(rune2c > 0) {
|
||||||
|
if(length(casev) > 0) {
|
||||||
|
print "static const Rune "name"2[][3] = {" > file;
|
||||||
|
for(j = 0; j < rune2c; j++) {
|
||||||
|
print "\t{ 0x"rune2v0[j]", 0x"rune2v1[j]", 0x"case2v[j]" }," > file;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print "static const Rune "name"2[][2] = {" > file
|
||||||
|
for(j = 0; j < rune2c; j++) {
|
||||||
|
print "\t{ 0x"rune2v0[j]", 0x"rune2v1[j]" }," > file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print "};\n" > file;
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate list of singletons
|
||||||
|
if(rune1c > 0) {
|
||||||
|
if(length(casev) > 0) {
|
||||||
|
print "static const Rune "name"1[][2] = {" > file;
|
||||||
|
for(j = 0; j < rune1c; j++) {
|
||||||
|
print "\t{ 0x"rune1v[j]", 0x"case1v[j]" }," > file;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print "static const Rune "name"1[] = {" > file;
|
||||||
|
for(j = 0; j < rune1c; j++) {
|
||||||
|
print "\t0x"rune1v[j]"," > file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print "};\n" > file;
|
||||||
|
}
|
||||||
|
# generate lookup function
|
||||||
|
print "int\nis"name"rune(Rune r)\n{" > file;
|
||||||
|
if(rune4c > 0 || rune3c > 0)
|
||||||
|
print "\tconst Rune *match;\n" > file;
|
||||||
|
if(rune4c > 0) {
|
||||||
|
print "\tif((match = bsearch(&r, "name"4, nelem("name"4), sizeof *"name"4, &rune2cmp)))" > file;
|
||||||
|
print "\t\treturn !((r - match[0]) % 2);" > file;
|
||||||
|
}
|
||||||
|
if(rune3c > 0) {
|
||||||
|
print "\tif((match = bsearch(&r, "name"3, nelem("name"3), sizeof *"name"3, &rune2cmp)))" > file;
|
||||||
|
print "\t\treturn !((r - match[0]) % 2);" > file;
|
||||||
|
}
|
||||||
|
if(rune2c > 0) {
|
||||||
|
print "\tif(bsearch(&r, "name"2, nelem("name"2), sizeof *"name"2, &rune2cmp))\n\t\treturn 1;" > file;
|
||||||
|
}
|
||||||
|
if(rune1c > 0) {
|
||||||
|
print "\tif(bsearch(&r, "name"1, nelem("name"1), sizeof *"name"1, &rune1cmp))\n\t\treturn 1;" > file;
|
||||||
|
}
|
||||||
|
print "\treturn 0;\n}" > file;
|
||||||
|
|
||||||
|
# generate case conversion function
|
||||||
|
if(length(casev) > 0) {
|
||||||
|
print "\nint\nto"casename"rune(Rune r)\n{\n\tRune *match;\n" > file;
|
||||||
|
if(rune4c > 0) {
|
||||||
|
print "\tmatch = bsearch(&r, "name"4, nelem("name"4), sizeof *"name"4, &rune2cmp);" > file;
|
||||||
|
print "\tif (match)" > file;
|
||||||
|
print "\t\treturn ((r - match[0]) % 2) ? r : r - 1;" > file;
|
||||||
|
}
|
||||||
|
if(rune3c > 0) {
|
||||||
|
print "\tmatch = bsearch(&r, "name"3, nelem("name"3), sizeof *"name"3, &rune2cmp);" > file;
|
||||||
|
print "\tif (match)" > file;
|
||||||
|
print "\t\treturn ((r - match[0]) % 2) ? r : r + 1;" > file;
|
||||||
|
}
|
||||||
|
if(rune2c > 0) {
|
||||||
|
print "\tmatch = bsearch(&r, "name"2, nelem("name"2), sizeof *"name"2, &rune2cmp);" > file;
|
||||||
|
print "\tif (match)" > file;
|
||||||
|
print "\t\treturn match[2] + (r - match[0]);" > file;
|
||||||
|
}
|
||||||
|
if(rune1c > 0) {
|
||||||
|
print "\tmatch = bsearch(&r, "name"1, nelem("name"1), sizeof *"name"1, &rune1cmp);" > file;
|
||||||
|
print "\tif (match)" > file;
|
||||||
|
print "\t\treturn match[1];" > file;
|
||||||
|
}
|
||||||
|
print "\treturn r;\n}" > file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function otheris() {
|
||||||
|
print HEADER_OTHER > "isalnumrune.c";
|
||||||
|
print "int\nisalnumrune(Rune r)\n{\n\treturn isalpharune(r) || isdigitrune(r);\n}" > "isalnumrune.c";
|
||||||
|
print HEADER_OTHER > "isblankrune.c";
|
||||||
|
print "int\nisblankrune(Rune r)\n{\n\treturn r == ' ' || r == '\\t';\n}" > "isblankrune.c";
|
||||||
|
print HEADER_OTHER > "isprintrune.c";
|
||||||
|
print "int\nisprintrune(Rune r)\n{\n\treturn !iscntrlrune(r) && (r != 0x2028) && (r != 0x2029) &&" > "isprintrune.c";
|
||||||
|
print "\t ((r < 0xFFF9) || (r > 0xFFFB));\n}" > "isprintrune.c";
|
||||||
|
print HEADER_OTHER > "isgraphrune.c";
|
||||||
|
print "int\nisgraphrune(Rune r)\n{\n\treturn !isspacerune(r) && isprintrune(r);\n}" > "isgraphrune.c";
|
||||||
|
print HEADER_OTHER > "ispunctrune.c";
|
||||||
|
print "int\nispunctrune(Rune r)\n{\n\treturn isgraphrune(r) && !isalnumrune(r);\n}" > "ispunctrune.c";
|
||||||
|
print HEADER_OTHER > "isxdigitrune.c";
|
||||||
|
print "int\nisxdigitrune(Rune r)\n{\n\treturn (r >= '0' && (r - '0') < 10) || (r >= 'a' && (r - 'a') < 6);\n}" > "isxdigitrune.c";
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "../utf.h"
|
||||||
|
|
||||||
|
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
||||||
|
|
||||||
|
#define UTFSEQ(x) ((((x) & 0x80) == 0x00) ? 1 /* 0xxxxxxx */ \
|
||||||
|
: (((x) & 0xC0) == 0x80) ? 0 /* 10xxxxxx */ \
|
||||||
|
: (((x) & 0xE0) == 0xC0) ? 2 /* 110xxxxx */ \
|
||||||
|
: (((x) & 0xF0) == 0xE0) ? 3 /* 1110xxxx */ \
|
||||||
|
: (((x) & 0xF8) == 0xF0) ? 4 /* 11110xxx */ \
|
||||||
|
: (((x) & 0xFC) == 0xF8) ? 5 /* 111110xx */ \
|
||||||
|
: (((x) & 0xFE) == 0xFC) ? 6 /* 1111110x */ \
|
||||||
|
: 0 )
|
||||||
|
|
||||||
|
#define BADRUNE(x) ((x) < 0 || (x) > Runemax \
|
||||||
|
|| ((x) & 0xFFFE) == 0xFFFE \
|
||||||
|
|| ((x) >= 0xD800 && (x) <= 0xDFFF) \
|
||||||
|
|| ((x) >= 0xFDD0 && (x) <= 0xFDEF))
|
||||||
|
|
||||||
|
int
|
||||||
|
runetochar(char *s, const Rune *p)
|
||||||
|
{
|
||||||
|
Rune r = *p;
|
||||||
|
|
||||||
|
switch(runelen(r)) {
|
||||||
|
case 1: /* 0aaaaaaa */
|
||||||
|
s[0] = r;
|
||||||
|
return 1;
|
||||||
|
case 2: /* 00000aaa aabbbbbb */
|
||||||
|
s[0] = 0xC0 | ((r & 0x0007C0) >> 6); /* 110aaaaa */
|
||||||
|
s[1] = 0x80 | (r & 0x00003F); /* 10bbbbbb */
|
||||||
|
return 2;
|
||||||
|
case 3: /* aaaabbbb bbcccccc */
|
||||||
|
s[0] = 0xE0 | ((r & 0x00F000) >> 12); /* 1110aaaa */
|
||||||
|
s[1] = 0x80 | ((r & 0x000FC0) >> 6); /* 10bbbbbb */
|
||||||
|
s[2] = 0x80 | (r & 0x00003F); /* 10cccccc */
|
||||||
|
return 3;
|
||||||
|
case 4: /* 000aaabb bbbbcccc ccdddddd */
|
||||||
|
s[0] = 0xF0 | ((r & 0x1C0000) >> 18); /* 11110aaa */
|
||||||
|
s[1] = 0x80 | ((r & 0x03F000) >> 12); /* 10bbbbbb */
|
||||||
|
s[2] = 0x80 | ((r & 0x000FC0) >> 6); /* 10cccccc */
|
||||||
|
s[3] = 0x80 | (r & 0x00003F); /* 10dddddd */
|
||||||
|
return 4;
|
||||||
|
default:
|
||||||
|
return 0; /* error */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
chartorune(Rune *p, const char *s)
|
||||||
|
{
|
||||||
|
return charntorune(p, s, UTFmax);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
charntorune(Rune *p, const char *s, size_t len)
|
||||||
|
{
|
||||||
|
unsigned int i, n;
|
||||||
|
Rune r;
|
||||||
|
|
||||||
|
if(len == 0) /* can't even look at s[0] */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch((n = UTFSEQ(s[0]))) {
|
||||||
|
case 1: r = s[0]; break; /* 0xxxxxxx */
|
||||||
|
case 2: r = s[0] & 0x1F; break; /* 110xxxxx */
|
||||||
|
case 3: r = s[0] & 0x0F; break; /* 1110xxxx */
|
||||||
|
case 4: r = s[0] & 0x07; break; /* 11110xxx */
|
||||||
|
case 5: r = s[0] & 0x03; break; /* 111110xx */
|
||||||
|
case 6: r = s[0] & 0x01; break; /* 1111110x */
|
||||||
|
default: /* invalid sequence */
|
||||||
|
*p = Runeerror;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* add values from continuation bytes */
|
||||||
|
for(i = 1; i < MIN(n, len); i++)
|
||||||
|
if((s[i] & 0xC0) == 0x80) {
|
||||||
|
/* add bits from continuation byte to rune value
|
||||||
|
* cannot overflow: 6 byte sequences contain 31 bits */
|
||||||
|
r = (r << 6) | (s[i] & 0x3F); /* 10xxxxxx */
|
||||||
|
}
|
||||||
|
else { /* expected continuation */
|
||||||
|
*p = Runeerror;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i < n) /* must have reached len limit */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* reject invalid or overlong sequences */
|
||||||
|
if(BADRUNE(r) || runelen(r) < (int)n)
|
||||||
|
r = Runeerror;
|
||||||
|
|
||||||
|
*p = r;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
runelen(Rune r)
|
||||||
|
{
|
||||||
|
if(BADRUNE(r))
|
||||||
|
return 0; /* error */
|
||||||
|
else if(r <= 0x7F)
|
||||||
|
return 1;
|
||||||
|
else if(r <= 0x07FF)
|
||||||
|
return 2;
|
||||||
|
else if(r <= 0xFFFF)
|
||||||
|
return 3;
|
||||||
|
else
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
runenlen(const Rune *p, size_t len)
|
||||||
|
{
|
||||||
|
size_t i, n = 0;
|
||||||
|
|
||||||
|
for(i = 0; i < len; i++)
|
||||||
|
n += runelen(p[i]);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fullrune(const char *s, size_t len)
|
||||||
|
{
|
||||||
|
Rune r;
|
||||||
|
|
||||||
|
return charntorune(&r, s, len) > 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
|
||||||
|
* (c) 2015 Laslo Hunhold <dev@frign.de>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "../utf.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
rune1cmp(const void *v1, const void *v2)
|
||||||
|
{
|
||||||
|
Rune r1 = *(Rune *)v1, r2 = *(Rune *)v2;
|
||||||
|
|
||||||
|
return r1 - r2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rune2cmp(const void *v1, const void *v2)
|
||||||
|
{
|
||||||
|
Rune r = *(Rune *)v1, *p = (Rune *)v2;
|
||||||
|
|
||||||
|
if(r >= p[0] && r <= p[1])
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return r - p[0];
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
|
||||||
|
* (c) 2015 Laslo Hunhold <dev@frign.de>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define nelem(x) (sizeof (x) / sizeof *(x))
|
||||||
|
|
||||||
|
int rune1cmp(const void *, const void *);
|
||||||
|
int rune2cmp(const void *, const void *);
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
/* Automatically generated by mkrunetype.awk */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "../utf.h"
|
||||||
|
#include "runetype.h"
|
||||||
|
|
||||||
|
static const Rune upper3[][2] = {
|
||||||
|
{ 0x0100, 0x012E },
|
||||||
|
{ 0x0132, 0x0136 },
|
||||||
|
{ 0x0139, 0x0147 },
|
||||||
|
{ 0x014A, 0x0176 },
|
||||||
|
{ 0x0179, 0x017D },
|
||||||
|
{ 0x0182, 0x0184 },
|
||||||
|
{ 0x01A0, 0x01A4 },
|
||||||
|
{ 0x01B3, 0x01B5 },
|
||||||
|
{ 0x01CD, 0x01DB },
|
||||||
|
{ 0x01DE, 0x01EE },
|
||||||
|
{ 0x01F8, 0x021E },
|
||||||
|
{ 0x0222, 0x0232 },
|
||||||
|
{ 0x0246, 0x024E },
|
||||||
|
{ 0x0370, 0x0372 },
|
||||||
|
{ 0x03D8, 0x03EE },
|
||||||
|
{ 0x0460, 0x0480 },
|
||||||
|
{ 0x048A, 0x04BE },
|
||||||
|
{ 0x04C1, 0x04CD },
|
||||||
|
{ 0x04D0, 0x052E },
|
||||||
|
{ 0x1E00, 0x1E94 },
|
||||||
|
{ 0x1EA0, 0x1EFE },
|
||||||
|
{ 0x2C67, 0x2C6B },
|
||||||
|
{ 0x2C80, 0x2CE2 },
|
||||||
|
{ 0x2CEB, 0x2CED },
|
||||||
|
{ 0xA640, 0xA66C },
|
||||||
|
{ 0xA680, 0xA69A },
|
||||||
|
{ 0xA722, 0xA72E },
|
||||||
|
{ 0xA732, 0xA76E },
|
||||||
|
{ 0xA779, 0xA77B },
|
||||||
|
{ 0xA77E, 0xA786 },
|
||||||
|
{ 0xA790, 0xA792 },
|
||||||
|
{ 0xA796, 0xA7A8 },
|
||||||
|
{ 0xA7B4, 0xA7C2 },
|
||||||
|
{ 0xA7C7, 0xA7C9 },
|
||||||
|
{ 0xA7D6, 0xA7D8 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Rune upper2[][3] = {
|
||||||
|
{ 0x0041, 0x005A, 0x0061 },
|
||||||
|
{ 0x00C0, 0x00D6, 0x00E0 },
|
||||||
|
{ 0x00D8, 0x00DE, 0x00F8 },
|
||||||
|
{ 0x0189, 0x018A, 0x0256 },
|
||||||
|
{ 0x01B1, 0x01B2, 0x028A },
|
||||||
|
{ 0x0388, 0x038A, 0x03AD },
|
||||||
|
{ 0x038E, 0x038F, 0x03CD },
|
||||||
|
{ 0x0391, 0x03A1, 0x03B1 },
|
||||||
|
{ 0x03A3, 0x03AB, 0x03C3 },
|
||||||
|
{ 0x03D2, 0x03D4, 0x03D2 },
|
||||||
|
{ 0x03FD, 0x03FF, 0x037B },
|
||||||
|
{ 0x0400, 0x040F, 0x0450 },
|
||||||
|
{ 0x0410, 0x042F, 0x0430 },
|
||||||
|
{ 0x0531, 0x0556, 0x0561 },
|
||||||
|
{ 0x10A0, 0x10C5, 0x2D00 },
|
||||||
|
{ 0x13A0, 0x13EF, 0xAB70 },
|
||||||
|
{ 0x13F0, 0x13F5, 0x13F8 },
|
||||||
|
{ 0x1C90, 0x1CBA, 0x10D0 },
|
||||||
|
{ 0x1CBD, 0x1CBF, 0x10FD },
|
||||||
|
{ 0x1F08, 0x1F0F, 0x1F00 },
|
||||||
|
{ 0x1F18, 0x1F1D, 0x1F10 },
|
||||||
|
{ 0x1F28, 0x1F2F, 0x1F20 },
|
||||||
|
{ 0x1F38, 0x1F3F, 0x1F30 },
|
||||||
|
{ 0x1F48, 0x1F4D, 0x1F40 },
|
||||||
|
{ 0x1F68, 0x1F6F, 0x1F60 },
|
||||||
|
{ 0x1FB8, 0x1FB9, 0x1FB0 },
|
||||||
|
{ 0x1FBA, 0x1FBB, 0x1F70 },
|
||||||
|
{ 0x1FC8, 0x1FCB, 0x1F72 },
|
||||||
|
{ 0x1FD8, 0x1FD9, 0x1FD0 },
|
||||||
|
{ 0x1FDA, 0x1FDB, 0x1F76 },
|
||||||
|
{ 0x1FE8, 0x1FE9, 0x1FE0 },
|
||||||
|
{ 0x1FEA, 0x1FEB, 0x1F7A },
|
||||||
|
{ 0x1FF8, 0x1FF9, 0x1F78 },
|
||||||
|
{ 0x1FFA, 0x1FFB, 0x1F7C },
|
||||||
|
{ 0x210B, 0x210D, 0x210B },
|
||||||
|
{ 0x2110, 0x2112, 0x2110 },
|
||||||
|
{ 0x2119, 0x211D, 0x2119 },
|
||||||
|
{ 0x212C, 0x212D, 0x212C },
|
||||||
|
{ 0x2130, 0x2131, 0x2130 },
|
||||||
|
{ 0x213E, 0x213F, 0x213E },
|
||||||
|
{ 0x2C00, 0x2C2F, 0x2C30 },
|
||||||
|
{ 0x2C7E, 0x2C7F, 0x023F },
|
||||||
|
{ 0xFF21, 0xFF3A, 0xFF41 },
|
||||||
|
{ 0x10400, 0x10427, 0x10428 },
|
||||||
|
{ 0x104B0, 0x104D3, 0x104D8 },
|
||||||
|
{ 0x10570, 0x1057A, 0x10597 },
|
||||||
|
{ 0x1057C, 0x1058A, 0x105A3 },
|
||||||
|
{ 0x1058C, 0x10592, 0x105B3 },
|
||||||
|
{ 0x10594, 0x10595, 0x105BB },
|
||||||
|
{ 0x10C80, 0x10CB2, 0x10CC0 },
|
||||||
|
{ 0x118A0, 0x118BF, 0x118C0 },
|
||||||
|
{ 0x16E40, 0x16E5F, 0x16E60 },
|
||||||
|
{ 0x1D400, 0x1D419, 0x1D400 },
|
||||||
|
{ 0x1D434, 0x1D44D, 0x1D434 },
|
||||||
|
{ 0x1D468, 0x1D481, 0x1D468 },
|
||||||
|
{ 0x1D49E, 0x1D49F, 0x1D49E },
|
||||||
|
{ 0x1D4A5, 0x1D4A6, 0x1D4A5 },
|
||||||
|
{ 0x1D4A9, 0x1D4AC, 0x1D4A9 },
|
||||||
|
{ 0x1D4AE, 0x1D4B5, 0x1D4AE },
|
||||||
|
{ 0x1D4D0, 0x1D4E9, 0x1D4D0 },
|
||||||
|
{ 0x1D504, 0x1D505, 0x1D504 },
|
||||||
|
{ 0x1D507, 0x1D50A, 0x1D507 },
|
||||||
|
{ 0x1D50D, 0x1D514, 0x1D50D },
|
||||||
|
{ 0x1D516, 0x1D51C, 0x1D516 },
|
||||||
|
{ 0x1D538, 0x1D539, 0x1D538 },
|
||||||
|
{ 0x1D53B, 0x1D53E, 0x1D53B },
|
||||||
|
{ 0x1D540, 0x1D544, 0x1D540 },
|
||||||
|
{ 0x1D54A, 0x1D550, 0x1D54A },
|
||||||
|
{ 0x1D56C, 0x1D585, 0x1D56C },
|
||||||
|
{ 0x1D5A0, 0x1D5B9, 0x1D5A0 },
|
||||||
|
{ 0x1D5D4, 0x1D5ED, 0x1D5D4 },
|
||||||
|
{ 0x1D608, 0x1D621, 0x1D608 },
|
||||||
|
{ 0x1D63C, 0x1D655, 0x1D63C },
|
||||||
|
{ 0x1D670, 0x1D689, 0x1D670 },
|
||||||
|
{ 0x1D6A8, 0x1D6C0, 0x1D6A8 },
|
||||||
|
{ 0x1D6E2, 0x1D6FA, 0x1D6E2 },
|
||||||
|
{ 0x1D71C, 0x1D734, 0x1D71C },
|
||||||
|
{ 0x1D756, 0x1D76E, 0x1D756 },
|
||||||
|
{ 0x1D790, 0x1D7A8, 0x1D790 },
|
||||||
|
{ 0x1E900, 0x1E921, 0x1E922 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Rune upper1[][2] = {
|
||||||
|
{ 0x0130, 0x0069 },
|
||||||
|
{ 0x0178, 0x00FF },
|
||||||
|
{ 0x0181, 0x0253 },
|
||||||
|
{ 0x0186, 0x0254 },
|
||||||
|
{ 0x0187, 0x0188 },
|
||||||
|
{ 0x018B, 0x018C },
|
||||||
|
{ 0x018E, 0x01DD },
|
||||||
|
{ 0x018F, 0x0259 },
|
||||||
|
{ 0x0190, 0x025B },
|
||||||
|
{ 0x0191, 0x0192 },
|
||||||
|
{ 0x0193, 0x0260 },
|
||||||
|
{ 0x0194, 0x0263 },
|
||||||
|
{ 0x0196, 0x0269 },
|
||||||
|
{ 0x0197, 0x0268 },
|
||||||
|
{ 0x0198, 0x0199 },
|
||||||
|
{ 0x019C, 0x026F },
|
||||||
|
{ 0x019D, 0x0272 },
|
||||||
|
{ 0x019F, 0x0275 },
|
||||||
|
{ 0x01A6, 0x0280 },
|
||||||
|
{ 0x01A7, 0x01A8 },
|
||||||
|
{ 0x01A9, 0x0283 },
|
||||||
|
{ 0x01AC, 0x01AD },
|
||||||
|
{ 0x01AE, 0x0288 },
|
||||||
|
{ 0x01AF, 0x01B0 },
|
||||||
|
{ 0x01B7, 0x0292 },
|
||||||
|
{ 0x01B8, 0x01B9 },
|
||||||
|
{ 0x01BC, 0x01BD },
|
||||||
|
{ 0x01C4, 0x01C6 },
|
||||||
|
{ 0x01C7, 0x01C9 },
|
||||||
|
{ 0x01CA, 0x01CC },
|
||||||
|
{ 0x01F1, 0x01F3 },
|
||||||
|
{ 0x01F4, 0x01F5 },
|
||||||
|
{ 0x01F6, 0x0195 },
|
||||||
|
{ 0x01F7, 0x01BF },
|
||||||
|
{ 0x0220, 0x019E },
|
||||||
|
{ 0x023A, 0x2C65 },
|
||||||
|
{ 0x023B, 0x023C },
|
||||||
|
{ 0x023D, 0x019A },
|
||||||
|
{ 0x023E, 0x2C66 },
|
||||||
|
{ 0x0241, 0x0242 },
|
||||||
|
{ 0x0243, 0x0180 },
|
||||||
|
{ 0x0244, 0x0289 },
|
||||||
|
{ 0x0245, 0x028C },
|
||||||
|
{ 0x0376, 0x0377 },
|
||||||
|
{ 0x037F, 0x03F3 },
|
||||||
|
{ 0x0386, 0x03AC },
|
||||||
|
{ 0x038C, 0x03CC },
|
||||||
|
{ 0x03CF, 0x03D7 },
|
||||||
|
{ 0x03F4, 0x03B8 },
|
||||||
|
{ 0x03F7, 0x03F8 },
|
||||||
|
{ 0x03F9, 0x03F2 },
|
||||||
|
{ 0x03FA, 0x03FB },
|
||||||
|
{ 0x04C0, 0x04CF },
|
||||||
|
{ 0x10C7, 0x2D27 },
|
||||||
|
{ 0x10CD, 0x2D2D },
|
||||||
|
{ 0x1E9E, 0x00DF },
|
||||||
|
{ 0x1F59, 0x1F51 },
|
||||||
|
{ 0x1F5B, 0x1F53 },
|
||||||
|
{ 0x1F5D, 0x1F55 },
|
||||||
|
{ 0x1F5F, 0x1F57 },
|
||||||
|
{ 0x1FEC, 0x1FE5 },
|
||||||
|
{ 0x2102, 0x2102 },
|
||||||
|
{ 0x2107, 0x2107 },
|
||||||
|
{ 0x2115, 0x2115 },
|
||||||
|
{ 0x2124, 0x2124 },
|
||||||
|
{ 0x2126, 0x03C9 },
|
||||||
|
{ 0x2128, 0x2128 },
|
||||||
|
{ 0x212A, 0x006B },
|
||||||
|
{ 0x212B, 0x00E5 },
|
||||||
|
{ 0x2132, 0x214E },
|
||||||
|
{ 0x2133, 0x2133 },
|
||||||
|
{ 0x2145, 0x2145 },
|
||||||
|
{ 0x2183, 0x2184 },
|
||||||
|
{ 0x2C60, 0x2C61 },
|
||||||
|
{ 0x2C62, 0x026B },
|
||||||
|
{ 0x2C63, 0x1D7D },
|
||||||
|
{ 0x2C64, 0x027D },
|
||||||
|
{ 0x2C6D, 0x0251 },
|
||||||
|
{ 0x2C6E, 0x0271 },
|
||||||
|
{ 0x2C6F, 0x0250 },
|
||||||
|
{ 0x2C70, 0x0252 },
|
||||||
|
{ 0x2C72, 0x2C73 },
|
||||||
|
{ 0x2C75, 0x2C76 },
|
||||||
|
{ 0x2CF2, 0x2CF3 },
|
||||||
|
{ 0xA77D, 0x1D79 },
|
||||||
|
{ 0xA78B, 0xA78C },
|
||||||
|
{ 0xA78D, 0x0265 },
|
||||||
|
{ 0xA7AA, 0x0266 },
|
||||||
|
{ 0xA7AB, 0x025C },
|
||||||
|
{ 0xA7AC, 0x0261 },
|
||||||
|
{ 0xA7AD, 0x026C },
|
||||||
|
{ 0xA7AE, 0x026A },
|
||||||
|
{ 0xA7B0, 0x029E },
|
||||||
|
{ 0xA7B1, 0x0287 },
|
||||||
|
{ 0xA7B2, 0x029D },
|
||||||
|
{ 0xA7B3, 0xAB53 },
|
||||||
|
{ 0xA7C4, 0xA794 },
|
||||||
|
{ 0xA7C5, 0x0282 },
|
||||||
|
{ 0xA7C6, 0x1D8E },
|
||||||
|
{ 0xA7D0, 0xA7D1 },
|
||||||
|
{ 0xA7F5, 0xA7F6 },
|
||||||
|
{ 0x1D49C, 0x1D49C },
|
||||||
|
{ 0x1D4A2, 0x1D4A2 },
|
||||||
|
{ 0x1D546, 0x1D546 },
|
||||||
|
{ 0x1D7CA, 0x1D7CA },
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
isupperrune(Rune r)
|
||||||
|
{
|
||||||
|
const Rune *match;
|
||||||
|
|
||||||
|
if((match = bsearch(&r, upper3, nelem(upper3), sizeof *upper3, &rune2cmp)))
|
||||||
|
return !((r - match[0]) % 2);
|
||||||
|
if(bsearch(&r, upper2, nelem(upper2), sizeof *upper2, &rune2cmp))
|
||||||
|
return 1;
|
||||||
|
if(bsearch(&r, upper1, nelem(upper1), sizeof *upper1, &rune1cmp))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
tolowerrune(Rune r)
|
||||||
|
{
|
||||||
|
Rune *match;
|
||||||
|
|
||||||
|
match = bsearch(&r, upper3, nelem(upper3), sizeof *upper3, &rune2cmp);
|
||||||
|
if (match)
|
||||||
|
return ((r - match[0]) % 2) ? r : r + 1;
|
||||||
|
match = bsearch(&r, upper2, nelem(upper2), sizeof *upper2, &rune2cmp);
|
||||||
|
if (match)
|
||||||
|
return match[2] + (r - match[0]);
|
||||||
|
match = bsearch(&r, upper1, nelem(upper1), sizeof *upper1, &rune1cmp);
|
||||||
|
if (match)
|
||||||
|
return match[1];
|
||||||
|
return r;
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include "../utf.h"
|
||||||
|
|
||||||
|
char *
|
||||||
|
utfecpy(char *to, char *end, const char *from)
|
||||||
|
{
|
||||||
|
Rune r = Runeerror;
|
||||||
|
size_t i, n;
|
||||||
|
|
||||||
|
/* seek through to find final full rune */
|
||||||
|
for(i = 0; r != '\0' && (n = charntorune(&r, &from[i], end - &to[i])); i += n)
|
||||||
|
;
|
||||||
|
memcpy(to, from, i); /* copy over bytes up to this rune */
|
||||||
|
|
||||||
|
if(i > 0 && r != '\0')
|
||||||
|
to[i] = '\0'; /* terminate if unterminated */
|
||||||
|
return &to[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
utflen(const char *s)
|
||||||
|
{
|
||||||
|
const char *p = s;
|
||||||
|
size_t i;
|
||||||
|
Rune r;
|
||||||
|
|
||||||
|
for(i = 0; *p != '\0'; i++)
|
||||||
|
p += chartorune(&r, p);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
utfnlen(const char *s, size_t len)
|
||||||
|
{
|
||||||
|
const char *p = s;
|
||||||
|
size_t i;
|
||||||
|
Rune r;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for(i = 0; (n = charntorune(&r, p, len-(p-s))) && r != '\0'; i++)
|
||||||
|
p += n;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
utfmemlen(const char *s, size_t len)
|
||||||
|
{
|
||||||
|
const char *p = s;
|
||||||
|
size_t i;
|
||||||
|
Rune r;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for(i = 0; (n = charntorune(&r, p, len-(p-s))); i++)
|
||||||
|
p += n;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
utfrune(const char *s, Rune r)
|
||||||
|
{
|
||||||
|
if(r < Runeself) {
|
||||||
|
return strchr(s, r);
|
||||||
|
}
|
||||||
|
else if(r == Runeerror) {
|
||||||
|
Rune r0;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for(; *s != '\0'; s += n) {
|
||||||
|
n = chartorune(&r0, s);
|
||||||
|
if(r == r0)
|
||||||
|
return (char *)s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char buf[UTFmax+1];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if(!(n = runetochar(buf, &r)))
|
||||||
|
return NULL;
|
||||||
|
buf[n] = '\0';
|
||||||
|
return strstr(s, buf);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
utfrrune(const char *s, Rune r)
|
||||||
|
{
|
||||||
|
const char *p = NULL;
|
||||||
|
Rune r0;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if(r < Runeself)
|
||||||
|
return strrchr(s, r);
|
||||||
|
|
||||||
|
for(; *s != '\0'; s += n) {
|
||||||
|
n = chartorune(&r0, s);
|
||||||
|
if(r == r0)
|
||||||
|
p = s;
|
||||||
|
}
|
||||||
|
return (char *)p;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
utfutf(const char *s, const char *t)
|
||||||
|
{
|
||||||
|
const char *p, *q;
|
||||||
|
Rune r0, r1, r2;
|
||||||
|
int n, m;
|
||||||
|
|
||||||
|
for(chartorune(&r0, t); (s = utfrune(s, r0)); s++) {
|
||||||
|
for(p = s, q = t; *q && *p; p += n, q += m) {
|
||||||
|
n = chartorune(&r1, p);
|
||||||
|
m = chartorune(&r2, q);
|
||||||
|
if(r1 != r2)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!*q)
|
||||||
|
return (char *)s;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include "../utf.h"
|
||||||
|
|
||||||
|
size_t
|
||||||
|
utftorunestr(const char *str, Rune *r)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (i = 0; (n = chartorune(&r[i], str)) && r[i]; i++)
|
||||||
|
str += n;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
utfntorunestr(const char *str, size_t len, Rune *r)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
int n;
|
||||||
|
const char *end = str + len;
|
||||||
|
|
||||||
|
for (i = 0; (n = charntorune(&r[i], str, end - str)); i++)
|
||||||
|
str += n;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "../util.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
concat(int f1, const char *s1, int f2, const char *s2)
|
||||||
|
{
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
while ((n = read(f1, buf, sizeof(buf))) > 0) {
|
||||||
|
if (writeall(f2, buf, n) < 0) {
|
||||||
|
weprintf("write %s:", s2);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n < 0) {
|
||||||
|
weprintf("read %s:", s1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "../util.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
confirm(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int c, ans;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
xvprintf(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
c = getchar();
|
||||||
|
ans = (c == 'y' || c == 'Y');
|
||||||
|
while (c != '\n' && c != EOF)
|
||||||
|
c = getchar();
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user