mirror of
https://codeberg.org/libreboot/lbmk.git
synced 2026-07-11 05:52:36 +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