From 9e959120f4d32826f43b93d4d7b6d31087ed6c2f Mon Sep 17 00:00:00 2001 From: Michael Phipps Date: Mon, 1 Mar 2004 02:43:35 +0000 Subject: [PATCH] Check in the source for coreutils git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6837 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/bin/coreutils-5.0/src/Jamfile | 113 + src/apps/bin/coreutils-5.0/src/Makefile | 1577 ++ src/apps/bin/coreutils-5.0/src/Makefile.am | 242 + src/apps/bin/coreutils-5.0/src/Makefile.in | 1575 ++ src/apps/bin/coreutils-5.0/src/Makefile.mod | 1212 ++ src/apps/bin/coreutils-5.0/src/basename.c | 128 + src/apps/bin/coreutils-5.0/src/cat.c | 864 + src/apps/bin/coreutils-5.0/src/checksum.h | 15 + src/apps/bin/coreutils-5.0/src/chgrp.c | 237 + src/apps/bin/coreutils-5.0/src/chmod.c | 372 + src/apps/bin/coreutils-5.0/src/chown-core.c | 362 + src/apps/bin/coreutils-5.0/src/chown-core.h | 89 + src/apps/bin/coreutils-5.0/src/chown.c | 249 + src/apps/bin/coreutils-5.0/src/chroot.c | 112 + src/apps/bin/coreutils-5.0/src/cksum.c | 341 + src/apps/bin/coreutils-5.0/src/comm.c | 268 + src/apps/bin/coreutils-5.0/src/config.h | 1431 ++ src/apps/bin/coreutils-5.0/src/copy.c | 1629 ++ src/apps/bin/coreutils-5.0/src/copy.h | 211 + src/apps/bin/coreutils-5.0/src/cp-hash.c | 173 + src/apps/bin/coreutils-5.0/src/cp-hash.h | 5 + src/apps/bin/coreutils-5.0/src/cp.c | 1062 + src/apps/bin/coreutils-5.0/src/csplit.c | 1537 ++ src/apps/bin/coreutils-5.0/src/cut.c | 752 + src/apps/bin/coreutils-5.0/src/date.c | 552 + src/apps/bin/coreutils-5.0/src/dcgen | 70 + src/apps/bin/coreutils-5.0/src/dd.c | 1233 ++ src/apps/bin/coreutils-5.0/src/df.c | 933 + src/apps/bin/coreutils-5.0/src/dircolors.c | 542 + src/apps/bin/coreutils-5.0/src/dircolors.h | 121 + src/apps/bin/coreutils-5.0/src/dircolors.hin | 106 + src/apps/bin/coreutils-5.0/src/dirname.c | 107 + src/apps/bin/coreutils-5.0/src/du.c | 735 + src/apps/bin/coreutils-5.0/src/echo.c | 248 + src/apps/bin/coreutils-5.0/src/env.c | 207 + src/apps/bin/coreutils-5.0/src/expand.c | 412 + src/apps/bin/coreutils-5.0/src/expr.c | 753 + src/apps/bin/coreutils-5.0/src/factor.c | 223 + src/apps/bin/coreutils-5.0/src/false.c | 71 + src/apps/bin/coreutils-5.0/src/fmt.c | 1003 + src/apps/bin/coreutils-5.0/src/fold.c | 319 + src/apps/bin/coreutils-5.0/src/foo | 18991 +++++++++++++++++ src/apps/bin/coreutils-5.0/src/fs.h | 36 + src/apps/bin/coreutils-5.0/src/groups.sh | 62 + src/apps/bin/coreutils-5.0/src/head.c | 421 + src/apps/bin/coreutils-5.0/src/hostid.c | 87 + src/apps/bin/coreutils-5.0/src/hostname.c | 127 + src/apps/bin/coreutils-5.0/src/id.c | 400 + src/apps/bin/coreutils-5.0/src/install.c | 651 + src/apps/bin/coreutils-5.0/src/join.c | 877 + src/apps/bin/coreutils-5.0/src/kill.c | 374 + src/apps/bin/coreutils-5.0/src/link.c | 102 + src/apps/bin/coreutils-5.0/src/ln.c | 575 + src/apps/bin/coreutils-5.0/src/logname.c | 101 + src/apps/bin/coreutils-5.0/src/ls-dir.c | 2 + src/apps/bin/coreutils-5.0/src/ls-ls.c | 2 + src/apps/bin/coreutils-5.0/src/ls-vdir.c | 2 + src/apps/bin/coreutils-5.0/src/ls.c | 3894 ++++ src/apps/bin/coreutils-5.0/src/ls.h | 10 + src/apps/bin/coreutils-5.0/src/md5.c | 7 + src/apps/bin/coreutils-5.0/src/md5sum.c | 684 + src/apps/bin/coreutils-5.0/src/mkdir.c | 200 + src/apps/bin/coreutils-5.0/src/mkfifo.c | 152 + src/apps/bin/coreutils-5.0/src/mknod.c | 236 + src/apps/bin/coreutils-5.0/src/mv.c | 505 + src/apps/bin/coreutils-5.0/src/nice.c | 201 + src/apps/bin/coreutils-5.0/src/nl.c | 629 + src/apps/bin/coreutils-5.0/src/nohup.sh | 79 + src/apps/bin/coreutils-5.0/src/od.c | 2004 ++ src/apps/bin/coreutils-5.0/src/paste.c | 486 + src/apps/bin/coreutils-5.0/src/pathchk.c | 387 + src/apps/bin/coreutils-5.0/src/pinky.c | 585 + src/apps/bin/coreutils-5.0/src/pr.c | 2865 +++ src/apps/bin/coreutils-5.0/src/printenv.c | 139 + src/apps/bin/coreutils-5.0/src/printf.c | 598 + src/apps/bin/coreutils-5.0/src/ptx.c | 2212 ++ src/apps/bin/coreutils-5.0/src/pwd.c | 82 + src/apps/bin/coreutils-5.0/src/readlink.c | 157 + src/apps/bin/coreutils-5.0/src/remove.c | 1146 + src/apps/bin/coreutils-5.0/src/remove.h | 51 + src/apps/bin/coreutils-5.0/src/rm.c | 215 + src/apps/bin/coreutils-5.0/src/rmdir.c | 237 + src/apps/bin/coreutils-5.0/src/seq.c | 466 + src/apps/bin/coreutils-5.0/src/sha1sum.c | 7 + src/apps/bin/coreutils-5.0/src/shred.c | 1629 ++ src/apps/bin/coreutils-5.0/src/sleep.c | 169 + src/apps/bin/coreutils-5.0/src/sort.c | 2496 +++ src/apps/bin/coreutils-5.0/src/split.c | 550 + src/apps/bin/coreutils-5.0/src/stat.c | 815 + src/apps/bin/coreutils-5.0/src/stty.c | 1948 ++ src/apps/bin/coreutils-5.0/src/su.c | 583 + src/apps/bin/coreutils-5.0/src/sum.c | 273 + src/apps/bin/coreutils-5.0/src/sync.c | 74 + src/apps/bin/coreutils-5.0/src/sys2.h | 658 + src/apps/bin/coreutils-5.0/src/system.h | 298 + src/apps/bin/coreutils-5.0/src/tac-pipe.c | 248 + src/apps/bin/coreutils-5.0/src/tac.c | 715 + src/apps/bin/coreutils-5.0/src/tail.c | 1668 ++ src/apps/bin/coreutils-5.0/src/tee.c | 236 + src/apps/bin/coreutils-5.0/src/test.c | 1128 + src/apps/bin/coreutils-5.0/src/touch.c | 407 + src/apps/bin/coreutils-5.0/src/tr.c | 2030 ++ src/apps/bin/coreutils-5.0/src/true.c | 71 + src/apps/bin/coreutils-5.0/src/tsort.c | 588 + src/apps/bin/coreutils-5.0/src/tty.c | 124 + src/apps/bin/coreutils-5.0/src/uname.c | 293 + src/apps/bin/coreutils-5.0/src/unexpand.c | 496 + src/apps/bin/coreutils-5.0/src/uniq.c | 545 + src/apps/bin/coreutils-5.0/src/unlink.c | 102 + src/apps/bin/coreutils-5.0/src/uptime.c | 249 + src/apps/bin/coreutils-5.0/src/users.c | 174 + src/apps/bin/coreutils-5.0/src/wc.c | 598 + src/apps/bin/coreutils-5.0/src/wheel-gen.pl | 97 + src/apps/bin/coreutils-5.0/src/wheel-size.h | 1 + src/apps/bin/coreutils-5.0/src/wheel.h | 491 + src/apps/bin/coreutils-5.0/src/who.c | 769 + src/apps/bin/coreutils-5.0/src/whoami.c | 107 + src/apps/bin/coreutils-5.0/src/yes.c | 113 + 118 files changed, 83978 insertions(+) create mode 100644 src/apps/bin/coreutils-5.0/src/Jamfile create mode 100644 src/apps/bin/coreutils-5.0/src/Makefile create mode 100644 src/apps/bin/coreutils-5.0/src/Makefile.am create mode 100644 src/apps/bin/coreutils-5.0/src/Makefile.in create mode 100644 src/apps/bin/coreutils-5.0/src/Makefile.mod create mode 100644 src/apps/bin/coreutils-5.0/src/basename.c create mode 100644 src/apps/bin/coreutils-5.0/src/cat.c create mode 100644 src/apps/bin/coreutils-5.0/src/checksum.h create mode 100644 src/apps/bin/coreutils-5.0/src/chgrp.c create mode 100644 src/apps/bin/coreutils-5.0/src/chmod.c create mode 100644 src/apps/bin/coreutils-5.0/src/chown-core.c create mode 100644 src/apps/bin/coreutils-5.0/src/chown-core.h create mode 100644 src/apps/bin/coreutils-5.0/src/chown.c create mode 100644 src/apps/bin/coreutils-5.0/src/chroot.c create mode 100644 src/apps/bin/coreutils-5.0/src/cksum.c create mode 100644 src/apps/bin/coreutils-5.0/src/comm.c create mode 100644 src/apps/bin/coreutils-5.0/src/config.h create mode 100644 src/apps/bin/coreutils-5.0/src/copy.c create mode 100644 src/apps/bin/coreutils-5.0/src/copy.h create mode 100644 src/apps/bin/coreutils-5.0/src/cp-hash.c create mode 100644 src/apps/bin/coreutils-5.0/src/cp-hash.h create mode 100644 src/apps/bin/coreutils-5.0/src/cp.c create mode 100644 src/apps/bin/coreutils-5.0/src/csplit.c create mode 100644 src/apps/bin/coreutils-5.0/src/cut.c create mode 100644 src/apps/bin/coreutils-5.0/src/date.c create mode 100755 src/apps/bin/coreutils-5.0/src/dcgen create mode 100644 src/apps/bin/coreutils-5.0/src/dd.c create mode 100644 src/apps/bin/coreutils-5.0/src/df.c create mode 100644 src/apps/bin/coreutils-5.0/src/dircolors.c create mode 100644 src/apps/bin/coreutils-5.0/src/dircolors.h create mode 100644 src/apps/bin/coreutils-5.0/src/dircolors.hin create mode 100644 src/apps/bin/coreutils-5.0/src/dirname.c create mode 100644 src/apps/bin/coreutils-5.0/src/du.c create mode 100644 src/apps/bin/coreutils-5.0/src/echo.c create mode 100644 src/apps/bin/coreutils-5.0/src/env.c create mode 100644 src/apps/bin/coreutils-5.0/src/expand.c create mode 100644 src/apps/bin/coreutils-5.0/src/expr.c create mode 100644 src/apps/bin/coreutils-5.0/src/factor.c create mode 100644 src/apps/bin/coreutils-5.0/src/false.c create mode 100644 src/apps/bin/coreutils-5.0/src/fmt.c create mode 100644 src/apps/bin/coreutils-5.0/src/fold.c create mode 100644 src/apps/bin/coreutils-5.0/src/foo create mode 100644 src/apps/bin/coreutils-5.0/src/fs.h create mode 100755 src/apps/bin/coreutils-5.0/src/groups.sh create mode 100644 src/apps/bin/coreutils-5.0/src/head.c create mode 100644 src/apps/bin/coreutils-5.0/src/hostid.c create mode 100644 src/apps/bin/coreutils-5.0/src/hostname.c create mode 100644 src/apps/bin/coreutils-5.0/src/id.c create mode 100644 src/apps/bin/coreutils-5.0/src/install.c create mode 100644 src/apps/bin/coreutils-5.0/src/join.c create mode 100644 src/apps/bin/coreutils-5.0/src/kill.c create mode 100644 src/apps/bin/coreutils-5.0/src/link.c create mode 100644 src/apps/bin/coreutils-5.0/src/ln.c create mode 100644 src/apps/bin/coreutils-5.0/src/logname.c create mode 100644 src/apps/bin/coreutils-5.0/src/ls-dir.c create mode 100644 src/apps/bin/coreutils-5.0/src/ls-ls.c create mode 100644 src/apps/bin/coreutils-5.0/src/ls-vdir.c create mode 100644 src/apps/bin/coreutils-5.0/src/ls.c create mode 100644 src/apps/bin/coreutils-5.0/src/ls.h create mode 100644 src/apps/bin/coreutils-5.0/src/md5.c create mode 100644 src/apps/bin/coreutils-5.0/src/md5sum.c create mode 100644 src/apps/bin/coreutils-5.0/src/mkdir.c create mode 100644 src/apps/bin/coreutils-5.0/src/mkfifo.c create mode 100644 src/apps/bin/coreutils-5.0/src/mknod.c create mode 100644 src/apps/bin/coreutils-5.0/src/mv.c create mode 100644 src/apps/bin/coreutils-5.0/src/nice.c create mode 100644 src/apps/bin/coreutils-5.0/src/nl.c create mode 100755 src/apps/bin/coreutils-5.0/src/nohup.sh create mode 100644 src/apps/bin/coreutils-5.0/src/od.c create mode 100644 src/apps/bin/coreutils-5.0/src/paste.c create mode 100644 src/apps/bin/coreutils-5.0/src/pathchk.c create mode 100644 src/apps/bin/coreutils-5.0/src/pinky.c create mode 100644 src/apps/bin/coreutils-5.0/src/pr.c create mode 100644 src/apps/bin/coreutils-5.0/src/printenv.c create mode 100644 src/apps/bin/coreutils-5.0/src/printf.c create mode 100644 src/apps/bin/coreutils-5.0/src/ptx.c create mode 100644 src/apps/bin/coreutils-5.0/src/pwd.c create mode 100644 src/apps/bin/coreutils-5.0/src/readlink.c create mode 100644 src/apps/bin/coreutils-5.0/src/remove.c create mode 100644 src/apps/bin/coreutils-5.0/src/remove.h create mode 100644 src/apps/bin/coreutils-5.0/src/rm.c create mode 100644 src/apps/bin/coreutils-5.0/src/rmdir.c create mode 100644 src/apps/bin/coreutils-5.0/src/seq.c create mode 100644 src/apps/bin/coreutils-5.0/src/sha1sum.c create mode 100644 src/apps/bin/coreutils-5.0/src/shred.c create mode 100644 src/apps/bin/coreutils-5.0/src/sleep.c create mode 100644 src/apps/bin/coreutils-5.0/src/sort.c create mode 100644 src/apps/bin/coreutils-5.0/src/split.c create mode 100644 src/apps/bin/coreutils-5.0/src/stat.c create mode 100644 src/apps/bin/coreutils-5.0/src/stty.c create mode 100644 src/apps/bin/coreutils-5.0/src/su.c create mode 100644 src/apps/bin/coreutils-5.0/src/sum.c create mode 100644 src/apps/bin/coreutils-5.0/src/sync.c create mode 100644 src/apps/bin/coreutils-5.0/src/sys2.h create mode 100644 src/apps/bin/coreutils-5.0/src/system.h create mode 100644 src/apps/bin/coreutils-5.0/src/tac-pipe.c create mode 100644 src/apps/bin/coreutils-5.0/src/tac.c create mode 100644 src/apps/bin/coreutils-5.0/src/tail.c create mode 100644 src/apps/bin/coreutils-5.0/src/tee.c create mode 100644 src/apps/bin/coreutils-5.0/src/test.c create mode 100644 src/apps/bin/coreutils-5.0/src/touch.c create mode 100644 src/apps/bin/coreutils-5.0/src/tr.c create mode 100644 src/apps/bin/coreutils-5.0/src/true.c create mode 100644 src/apps/bin/coreutils-5.0/src/tsort.c create mode 100644 src/apps/bin/coreutils-5.0/src/tty.c create mode 100644 src/apps/bin/coreutils-5.0/src/uname.c create mode 100644 src/apps/bin/coreutils-5.0/src/unexpand.c create mode 100644 src/apps/bin/coreutils-5.0/src/uniq.c create mode 100644 src/apps/bin/coreutils-5.0/src/unlink.c create mode 100644 src/apps/bin/coreutils-5.0/src/uptime.c create mode 100644 src/apps/bin/coreutils-5.0/src/users.c create mode 100644 src/apps/bin/coreutils-5.0/src/wc.c create mode 100755 src/apps/bin/coreutils-5.0/src/wheel-gen.pl create mode 100644 src/apps/bin/coreutils-5.0/src/wheel-size.h create mode 100644 src/apps/bin/coreutils-5.0/src/wheel.h create mode 100644 src/apps/bin/coreutils-5.0/src/who.c create mode 100644 src/apps/bin/coreutils-5.0/src/whoami.c create mode 100644 src/apps/bin/coreutils-5.0/src/yes.c diff --git a/src/apps/bin/coreutils-5.0/src/Jamfile b/src/apps/bin/coreutils-5.0/src/Jamfile new file mode 100644 index 0000000000..605de7a7ec --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/Jamfile @@ -0,0 +1,113 @@ +SubDir OBOS_TOP src apps bin coreutils-5.0 src ; + +SubDirCcFlags -DHAVE_CONFIG_H -DLOCALEDIR=\'\"/share/locale\"\' ; + +StdBinCommands + basename.c + cat.c + chmod.c + cksum.c + comm.c + csplit.c + cut.c + date.c + dd.c + dircolors.c + dirname.c + du.c + echo.c + env.c + expand.c + expr.c + factor.c + false.c + fmt.c + fold.c + head.c + hostname.c + id.c + join.c + kill.c + link.c + ln.c + logname.c + mkdir.c + mkfifo.c + mknod.c + nl.c + od.c + paste.c + pathchk.c + pr.c + printenv.c + printf.c + ptx.c + pwd.c + readlink.c + rmdir.c + seq.c + shred.c + sleep.c + sort.c + split.c + stty.c + su.c + sum.c + sync.c + tac.c + tail.c + tee.c + test.c + touch.c + tr.c + true.c + tsort.c + tty.c + uname.c + unexpand.c + uniq.c + unlink.c + wc.c + whoami.c + yes.c + : root libfetish.a ; + +# stat.c +# chroot.c +# df.c +# hostid.c +# nice.c +# pinky.c +# uptime.c +# users.c +# who.c + + +BinCommand ls : + ls.c ls-dir.c : root libfetish.a ; + +BinCommand rm : + rm.c remove.c : root libfetish.a ; + +BinCommand chgroup : + chgrp.c chown-core.c : root libfetish.a ; + +BinCommand chmod : + chmod.c chown-core.c : root libfetish.a ; + +BinCommand cp : + cp.c copy.c cp-hash.c : root libfetish.a ; + +BinCommand md5sum : + md5sum.c md5.c : root libfetish.a ; + +BinCommand mv : + mv.c copy.c cp-hash.c remove.c : root libfetish.a ; + +BinCommand sha1sum : + md5sum.c sha1sum.c : root libfetish.a ; + +BinCommand vdir : + ls.c ls-vdir.c : root libfetish.a ; + + diff --git a/src/apps/bin/coreutils-5.0/src/Makefile b/src/apps/bin/coreutils-5.0/src/Makefile new file mode 100644 index 0000000000..811954828e --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/Makefile @@ -0,0 +1,1577 @@ +# Makefile.in generated by automake 1.7.3 from Makefile.am. +# src/Makefile. Generated from Makefile.in by configure. + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +srcdir = . +top_srcdir = .. + +pkgdatadir = $(datadir)/coreutils +pkglibdir = $(libdir)/coreutils +pkgincludedir = $(includedir)/coreutils +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = /bin/install -c +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_triplet = i586-pc-beos + + +# Use `ginstall' in the definition of PROGRAMS and in dependencies to avoid +# confusion with the `install' target. The install rule transforms `ginstall' +# to install before applying any user-specified name transformations. +transform = s/ginstall/install/; s,x,x, +ACLOCAL = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run aclocal-1.7 +ALLOCA = +AMDEP_FALSE = # +AMDEP_TRUE = +AMTAR = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run tar +AUTOCONF = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run autoconf +AUTOHEADER = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run autoheader +AUTOMAKE = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run automake-1.7 +AWK = gawk +CC = gcc +CCDEPMODE = depmode=gcc +CFLAGS = -g -O2 -pipe +CPP = gcc -E +CPPFLAGS = +CYGPATH_W = echo +DEFS = -DLOCALEDIR=\"$(localedir)\" -DSHAREDIR=\"$(datadir)\" -DHAVE_CONFIG_H +DEPDIR = .deps +DF_PROG = +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = grep -E +EXEEXT = +FESETROUND_LIBM = +GETLOADAVG_LIBS = +GLIBC21 = no +GMSGFMT = : +GNU_PACKAGE = GNU coreutils +HELP2MAN = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run help2man +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s +INTLLIBS = +KMEM_GROUP = +LDFLAGS = +LIBICONV = +LIBINTL = +LIBOBJS = fileblocks$U.o mkdir$U.o fnmatch$U.o strnlen$U.o ftw$U.o tsearch$U.o lchown$U.o chown$U.o mktime$U.o nanosleep$U.o group-member$U.o putenv$U.o error$U.o __fpending$U.o rename$U.o getcwd$U.o canonicalize$U.o regex$U.o getloadavg$U.o getusershell$U.o sig2str$U.o euidaccess$U.o rpmatch$U.o strndup$U.o strverscmp$U.o getpass$U.o memrchr$U.o fchdir-stub$U.o +LIBS = +LIB_CLOCK_GETTIME = +LIB_CRYPT = +LIB_NANOSLEEP = +LN_S = ln -s +LTLIBICONV = +LTLIBINTL = +LTLIBOBJS = fileblocks$U.lo mkdir$U.lo fnmatch$U.lo strnlen$U.lo ftw$U.lo tsearch$U.lo lchown$U.lo chown$U.lo mktime$U.lo nanosleep$U.lo group-member$U.lo putenv$U.lo error$U.lo __fpending$U.lo rename$U.lo getcwd$U.lo canonicalize$U.lo regex$U.lo getloadavg$U.lo getusershell$U.lo sig2str$U.lo euidaccess$U.lo rpmatch$U.lo strndup$U.lo strverscmp$U.lo getpass$U.lo memrchr$U.lo fchdir-stub$U.lo +MAKEINFO = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run makeinfo +MAN = uname.1 stty.1 +MKINSTALLDIRS = config/mkinstalldirs +MSGFMT = : +MSGMERGE = : +NEED_SETGID = false +OBJEXT = o +OPTIONAL_BIN_PROGS = uname$(EXEEXT) stty$(EXEEXT) +OPTIONAL_BIN_ZCRIPTS = +PACKAGE = coreutils +PACKAGE_BUGREPORT = bug-coreutils@gnu.org +PACKAGE_NAME = GNU coreutils +PACKAGE_STRING = GNU coreutils 5.0 +PACKAGE_TARNAME = coreutils +PACKAGE_VERSION = 5.0 +PATH_SEPARATOR = : + +PERL = perl +POSUB = +POW_LIB = +RANLIB = ranlib +SEQ_LIBM = +SET_MAKE = +SHELL = /bin/sh +SQRT_LIBM = +STRIP = +U = +USE_NLS = no +VERSION = 5.0 +XGETTEXT = : +YACC = bison -y +ac_ct_CC = gcc +ac_ct_RANLIB = ranlib +ac_ct_STRIP = +am__fastdepCC_FALSE = +am__fastdepCC_TRUE = # +am__include = include +am__leading_dot = . +am__quote = +bindir = ${exec_prefix}/bin +build = i586-pc-beos +build_alias = +build_cpu = i586 +build_os = beos +build_vendor = pc +datadir = ${prefix}/share +exec_prefix = ${prefix} +host = i586-pc-beos +host_alias = +host_cpu = i586 +host_os = beos +host_vendor = pc +includedir = ${prefix}/include +infodir = ${prefix}/info +install_sh = /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localstatedir = ${prefix}/var +mandir = ${prefix}/man +oldincludedir = /usr/include +prefix = /usr/local +program_transform_name = s,x,x, +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +sysconfdir = ${prefix}/etc +target_alias = + +EXTRA_PROGRAMS = chroot df hostid nice pinky stty su uname uptime users who +EXTRA_SCRIPTS = nohup + +bin_SCRIPTS = groups +bin_PROGRAMS = chgrp chown chmod cp dd dircolors du \ + ginstall link ln dir vdir ls mkdir \ + mkfifo mknod mv readlink rm rmdir shred sync touch unlink \ + cat cksum comm csplit cut expand fmt fold head join md5sum \ + nl od paste pr ptx sha1sum sort split sum tac tail tr tsort unexpand uniq wc \ + basename date dirname echo env expr factor false \ + hostname id kill logname pathchk printenv printf pwd seq sleep tee \ + test true tty whoami yes \ + uname$(EXEEXT) stty$(EXEEXT) +# stat + + +localedir = $(datadir)/locale + +noinst_HEADERS = \ + system.h sys2.h checksum.h copy.h cp-hash.h ls.h dircolors.h remove.h \ + chown-core.h fs.h \ + wheel.h wheel-size.h + +EXTRA_DIST = dcgen dircolors.hin tac-pipe.c \ + groups.sh nohup.sh wheel-gen.pl + +CLEANFILES = $(SCRIPTS) su + +INCLUDES = -I.. -I$(srcdir) -I$(top_srcdir)/lib -I../lib + +# Sometimes, the expansion of includes -lc which may +# include modules defining variables like `optind', so libfetish.a +# must precede in order to ensure we use GNU getopt. +# But libfetish.a must also follow , since libintl uses +# replacement functions defined in libfetish.a. +LDADD = ../lib/libfetish.a ../lib/libfetish.a + +dir_LDADD = $(LDADD) +ls_LDADD = $(LDADD) +shred_LDADD = $(LDADD) +vdir_LDADD = $(LDADD) + +sort_LDADD = $(LDADD) + +# for clock_gettime +date_LDADD = $(LDADD) + +# For sqrt +factor_LDADD = $(LDADD) + +# If necessary, add -lm to resolve use of pow in lib/strtod.c. +# If necessary, add -liconv to resolve use of iconv in lib/unicodeio.c. +printf_LDADD = $(LDADD) + +# If necessary, add -lm to resolve use of floor, rint, modf. +seq_LDADD = $(LDADD) + +# If necessary, add -lm to resolve the `pow' reference in lib/strtod.c +# or for the fesetround reference in programs using nanosec.c. +nanosec_libs = \ + $(LDADD) + + +sleep_LDADD = $(nanosec_libs) +tail_LDADD = $(nanosec_libs) + +uptime_LDADD = $(LDADD) + +su_LDADD = $(LDADD) + +SUFFIXES = .sh + +installed_su = $(DESTDIR)$(bindir)/`echo su|sed '$(transform)'` + +setuid_root_mode = a=rx,u+s + +INSTALL_SU = \ + p=su; \ + echo " $(INSTALL_PROGRAM) $$p $(installed_su)"; \ + $(INSTALL_PROGRAM) $$p $(installed_su); \ + echo " chown root $(installed_su)"; \ + chown root $(installed_su); \ + echo " chmod $(setuid_root_mode) $(installed_su)"; \ + chmod $(setuid_root_mode) $(installed_su) + +ginstall_SOURCES = install.c copy.c cp-hash.c + +cp_SOURCES = cp.c copy.c cp-hash.c +dir_SOURCES = ls.c ls-dir.c +vdir_SOURCES = ls.c ls-vdir.c +ls_SOURCES = ls.c ls-ls.c +chown_SOURCES = chown.c chown-core.c +chgrp_SOURCES = chgrp.c chown-core.c + +mv_SOURCES = mv.c copy.c cp-hash.c remove.c +rm_SOURCES = rm.c remove.c + +md5sum_SOURCES = md5sum.c md5.c +sha1sum_SOURCES = md5sum.c sha1sum.c +editpl = sed -e 's,@''PERL''@,$(PERL),g' + +MAINTAINERCLEANFILES = dircolors.h \ + wheel.h wheel-size.h + + +wheel_size = 5 + +BUILT_SOURCES = dircolors.h false.c wheel.h wheel-size.h + +# false exits nonzero even with --help or --version. +# Tell automake to exempt it from that installcheck test. +AM_INSTALLCHECK_STD_OPTIONS_EXEMPT = false + +all_programs = \ + $(bin_PROGRAMS) \ + $(bin_SCRIPTS) \ + $(EXTRA_PROGRAMS) \ + $(EXTRA_SCRIPTS) + + +pm = progs-makefile +pr = progs-readme + +# Extract the list of authors from each file. +sed_filter = s/^ *//;s/N_ (//;s/^"//;s/")*$$// +# Sometimes the string is on the same line as the #define... +s1 = '/^\#define AUTHORS \([^\\]\)/{;s//\1/;$(sed_filter);p;q;}' +# Sometimes the string is on the backslash-continued line after the #define. +s2 = '/^\#define AUTHORS \\\\/{;n;$(sed_filter);p;q;}' +subdir = src +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +EXTRA_PROGRAMS = chroot$(EXEEXT) df$(EXEEXT) hostid$(EXEEXT) \ + nice$(EXEEXT) pinky$(EXEEXT) stty$(EXEEXT) su$(EXEEXT) \ + uname$(EXEEXT) uptime$(EXEEXT) users$(EXEEXT) who$(EXEEXT) +bin_PROGRAMS = chgrp$(EXEEXT) chown$(EXEEXT) chmod$(EXEEXT) cp$(EXEEXT) \ + dd$(EXEEXT) dircolors$(EXEEXT) du$(EXEEXT) ginstall$(EXEEXT) \ + link$(EXEEXT) ln$(EXEEXT) dir$(EXEEXT) vdir$(EXEEXT) \ + ls$(EXEEXT) mkdir$(EXEEXT) mkfifo$(EXEEXT) mknod$(EXEEXT) \ + mv$(EXEEXT) readlink$(EXEEXT) rm$(EXEEXT) rmdir$(EXEEXT) \ + shred$(EXEEXT) sync$(EXEEXT) touch$(EXEEXT) \ + unlink$(EXEEXT) cat$(EXEEXT) cksum$(EXEEXT) comm$(EXEEXT) \ + csplit$(EXEEXT) cut$(EXEEXT) expand$(EXEEXT) fmt$(EXEEXT) \ + fold$(EXEEXT) head$(EXEEXT) join$(EXEEXT) md5sum$(EXEEXT) \ + nl$(EXEEXT) od$(EXEEXT) paste$(EXEEXT) pr$(EXEEXT) ptx$(EXEEXT) \ + sha1sum$(EXEEXT) sort$(EXEEXT) split$(EXEEXT) sum$(EXEEXT) \ + tac$(EXEEXT) tail$(EXEEXT) tr$(EXEEXT) tsort$(EXEEXT) \ + unexpand$(EXEEXT) uniq$(EXEEXT) wc$(EXEEXT) basename$(EXEEXT) \ + date$(EXEEXT) dirname$(EXEEXT) echo$(EXEEXT) env$(EXEEXT) \ + expr$(EXEEXT) factor$(EXEEXT) false$(EXEEXT) hostname$(EXEEXT) \ + id$(EXEEXT) kill$(EXEEXT) logname$(EXEEXT) pathchk$(EXEEXT) \ + printenv$(EXEEXT) printf$(EXEEXT) pwd$(EXEEXT) seq$(EXEEXT) \ + sleep$(EXEEXT) tee$(EXEEXT) test$(EXEEXT) true$(EXEEXT) \ + tty$(EXEEXT) whoami$(EXEEXT) yes$(EXEEXT) uname$(EXEEXT) stty$(EXEEXT) \ + +PROGRAMS = $(bin_PROGRAMS) +# stat$(EXEEXT) + +basename_SOURCES = basename.c +basename_OBJECTS = basename.$(OBJEXT) +basename_LDADD = $(LDADD) +basename_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +basename_LDFLAGS = +cat_SOURCES = cat.c +cat_OBJECTS = cat.$(OBJEXT) +cat_LDADD = $(LDADD) +cat_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +cat_LDFLAGS = +am_chgrp_OBJECTS = chgrp.$(OBJEXT) chown-core.$(OBJEXT) +chgrp_OBJECTS = $(am_chgrp_OBJECTS) +chgrp_LDADD = $(LDADD) +chgrp_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +chgrp_LDFLAGS = +chmod_SOURCES = chmod.c +chmod_OBJECTS = chmod.$(OBJEXT) +chmod_LDADD = $(LDADD) +chmod_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +chmod_LDFLAGS = +am_chown_OBJECTS = chown.$(OBJEXT) chown-core.$(OBJEXT) +chown_OBJECTS = $(am_chown_OBJECTS) +chown_LDADD = $(LDADD) +chown_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +chown_LDFLAGS = +chroot_SOURCES = chroot.c +chroot_OBJECTS = chroot.$(OBJEXT) +chroot_LDADD = $(LDADD) +chroot_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +chroot_LDFLAGS = +cksum_SOURCES = cksum.c +cksum_OBJECTS = cksum.$(OBJEXT) +cksum_LDADD = $(LDADD) +cksum_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +cksum_LDFLAGS = +comm_SOURCES = comm.c +comm_OBJECTS = comm.$(OBJEXT) +comm_LDADD = $(LDADD) +comm_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +comm_LDFLAGS = +am_cp_OBJECTS = cp.$(OBJEXT) copy.$(OBJEXT) cp-hash.$(OBJEXT) +cp_OBJECTS = $(am_cp_OBJECTS) +cp_LDADD = $(LDADD) +cp_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +cp_LDFLAGS = +csplit_SOURCES = csplit.c +csplit_OBJECTS = csplit.$(OBJEXT) +csplit_LDADD = $(LDADD) +csplit_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +csplit_LDFLAGS = +cut_SOURCES = cut.c +cut_OBJECTS = cut.$(OBJEXT) +cut_LDADD = $(LDADD) +cut_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +cut_LDFLAGS = +date_SOURCES = date.c +date_OBJECTS = date.$(OBJEXT) +date_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +date_LDFLAGS = +dd_SOURCES = dd.c +dd_OBJECTS = dd.$(OBJEXT) +dd_LDADD = $(LDADD) +dd_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +dd_LDFLAGS = +df_SOURCES = df.c +df_OBJECTS = df.$(OBJEXT) +df_LDADD = $(LDADD) +df_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +df_LDFLAGS = +am_dir_OBJECTS = ls.$(OBJEXT) ls-dir.$(OBJEXT) +dir_OBJECTS = $(am_dir_OBJECTS) +dir_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +dir_LDFLAGS = +dircolors_SOURCES = dircolors.c +dircolors_OBJECTS = dircolors.$(OBJEXT) +dircolors_LDADD = $(LDADD) +dircolors_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +dircolors_LDFLAGS = +dirname_SOURCES = dirname.c +dirname_OBJECTS = dirname.$(OBJEXT) +dirname_LDADD = $(LDADD) +dirname_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +dirname_LDFLAGS = +du_SOURCES = du.c +du_OBJECTS = du.$(OBJEXT) +du_LDADD = $(LDADD) +du_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +du_LDFLAGS = +echo_SOURCES = echo.c +echo_OBJECTS = echo.$(OBJEXT) +echo_LDADD = $(LDADD) +echo_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +echo_LDFLAGS = +env_SOURCES = env.c +env_OBJECTS = env.$(OBJEXT) +env_LDADD = $(LDADD) +env_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +env_LDFLAGS = +expand_SOURCES = expand.c +expand_OBJECTS = expand.$(OBJEXT) +expand_LDADD = $(LDADD) +expand_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +expand_LDFLAGS = +expr_SOURCES = expr.c +expr_OBJECTS = expr.$(OBJEXT) +expr_LDADD = $(LDADD) +expr_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +expr_LDFLAGS = +factor_SOURCES = factor.c +factor_OBJECTS = factor.$(OBJEXT) +factor_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +factor_LDFLAGS = +false_SOURCES = false.c +false_OBJECTS = false.$(OBJEXT) +false_LDADD = $(LDADD) +false_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +false_LDFLAGS = +fmt_SOURCES = fmt.c +fmt_OBJECTS = fmt.$(OBJEXT) +fmt_LDADD = $(LDADD) +fmt_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +fmt_LDFLAGS = +fold_SOURCES = fold.c +fold_OBJECTS = fold.$(OBJEXT) +fold_LDADD = $(LDADD) +fold_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +fold_LDFLAGS = +am_ginstall_OBJECTS = install.$(OBJEXT) copy.$(OBJEXT) cp-hash.$(OBJEXT) +ginstall_OBJECTS = $(am_ginstall_OBJECTS) +ginstall_LDADD = $(LDADD) +ginstall_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +ginstall_LDFLAGS = +head_SOURCES = head.c +head_OBJECTS = head.$(OBJEXT) +head_LDADD = $(LDADD) +head_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +head_LDFLAGS = +hostid_SOURCES = hostid.c +hostid_OBJECTS = hostid.$(OBJEXT) +hostid_LDADD = $(LDADD) +hostid_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +hostid_LDFLAGS = +hostname_SOURCES = hostname.c +hostname_OBJECTS = hostname.$(OBJEXT) +hostname_LDADD = $(LDADD) +hostname_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +hostname_LDFLAGS = +id_SOURCES = id.c +id_OBJECTS = id.$(OBJEXT) +id_LDADD = $(LDADD) +id_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +id_LDFLAGS = +join_SOURCES = join.c +join_OBJECTS = join.$(OBJEXT) +join_LDADD = $(LDADD) +join_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +join_LDFLAGS = +kill_SOURCES = kill.c +kill_OBJECTS = kill.$(OBJEXT) +kill_LDADD = $(LDADD) +kill_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +kill_LDFLAGS = +link_SOURCES = link.c +link_OBJECTS = link.$(OBJEXT) +link_LDADD = $(LDADD) +link_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +link_LDFLAGS = +ln_SOURCES = ln.c +ln_OBJECTS = ln.$(OBJEXT) +ln_LDADD = $(LDADD) +ln_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +ln_LDFLAGS = +logname_SOURCES = logname.c +logname_OBJECTS = logname.$(OBJEXT) +logname_LDADD = $(LDADD) +logname_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +logname_LDFLAGS = +am_ls_OBJECTS = ls.$(OBJEXT) ls-ls.$(OBJEXT) +ls_OBJECTS = $(am_ls_OBJECTS) +ls_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +ls_LDFLAGS = +am_md5sum_OBJECTS = md5sum.$(OBJEXT) md5.$(OBJEXT) +md5sum_OBJECTS = $(am_md5sum_OBJECTS) +md5sum_LDADD = $(LDADD) +md5sum_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +md5sum_LDFLAGS = +mkdir_SOURCES = mkdir.c +mkdir_OBJECTS = mkdir.$(OBJEXT) +mkdir_LDADD = $(LDADD) +mkdir_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +mkdir_LDFLAGS = +mkfifo_SOURCES = mkfifo.c +mkfifo_OBJECTS = mkfifo.$(OBJEXT) +mkfifo_LDADD = $(LDADD) +mkfifo_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +mkfifo_LDFLAGS = +mknod_SOURCES = mknod.c +mknod_OBJECTS = mknod.$(OBJEXT) +mknod_LDADD = $(LDADD) +mknod_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +mknod_LDFLAGS = +am_mv_OBJECTS = mv.$(OBJEXT) copy.$(OBJEXT) cp-hash.$(OBJEXT) \ + remove.$(OBJEXT) +mv_OBJECTS = $(am_mv_OBJECTS) +mv_LDADD = $(LDADD) +mv_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +mv_LDFLAGS = +nice_SOURCES = nice.c +nice_OBJECTS = nice.$(OBJEXT) +nice_LDADD = $(LDADD) +nice_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +nice_LDFLAGS = +nl_SOURCES = nl.c +nl_OBJECTS = nl.$(OBJEXT) +nl_LDADD = $(LDADD) +nl_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +nl_LDFLAGS = +od_SOURCES = od.c +od_OBJECTS = od.$(OBJEXT) +od_LDADD = $(LDADD) +od_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +od_LDFLAGS = +paste_SOURCES = paste.c +paste_OBJECTS = paste.$(OBJEXT) +paste_LDADD = $(LDADD) +paste_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +paste_LDFLAGS = +pathchk_SOURCES = pathchk.c +pathchk_OBJECTS = pathchk.$(OBJEXT) +pathchk_LDADD = $(LDADD) +pathchk_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +pathchk_LDFLAGS = +pinky_SOURCES = pinky.c +pinky_OBJECTS = pinky.$(OBJEXT) +pinky_LDADD = $(LDADD) +pinky_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +pinky_LDFLAGS = +pr_SOURCES = pr.c +pr_OBJECTS = pr.$(OBJEXT) +pr_LDADD = $(LDADD) +pr_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +pr_LDFLAGS = +printenv_SOURCES = printenv.c +printenv_OBJECTS = printenv.$(OBJEXT) +printenv_LDADD = $(LDADD) +printenv_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +printenv_LDFLAGS = +printf_SOURCES = printf.c +printf_OBJECTS = printf.$(OBJEXT) +printf_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +printf_LDFLAGS = +ptx_SOURCES = ptx.c +ptx_OBJECTS = ptx.$(OBJEXT) +ptx_LDADD = $(LDADD) +ptx_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +ptx_LDFLAGS = +pwd_SOURCES = pwd.c +pwd_OBJECTS = pwd.$(OBJEXT) +pwd_LDADD = $(LDADD) +pwd_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +pwd_LDFLAGS = +readlink_SOURCES = readlink.c +readlink_OBJECTS = readlink.$(OBJEXT) +readlink_LDADD = $(LDADD) +readlink_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +readlink_LDFLAGS = +am_rm_OBJECTS = rm.$(OBJEXT) remove.$(OBJEXT) +rm_OBJECTS = $(am_rm_OBJECTS) +rm_LDADD = $(LDADD) +rm_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +rm_LDFLAGS = +rmdir_SOURCES = rmdir.c +rmdir_OBJECTS = rmdir.$(OBJEXT) +rmdir_LDADD = $(LDADD) +rmdir_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +rmdir_LDFLAGS = +seq_SOURCES = seq.c +seq_OBJECTS = seq.$(OBJEXT) +seq_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +seq_LDFLAGS = +am_sha1sum_OBJECTS = md5sum.$(OBJEXT) sha1sum.$(OBJEXT) +sha1sum_OBJECTS = $(am_sha1sum_OBJECTS) +sha1sum_LDADD = $(LDADD) +sha1sum_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +sha1sum_LDFLAGS = +shred_SOURCES = shred.c +shred_OBJECTS = shred.$(OBJEXT) +shred_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +shred_LDFLAGS = +sleep_SOURCES = sleep.c +sleep_OBJECTS = sleep.$(OBJEXT) +sleep_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +sleep_LDFLAGS = +sort_SOURCES = sort.c +sort_OBJECTS = sort.$(OBJEXT) +sort_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +sort_LDFLAGS = +split_SOURCES = split.c +split_OBJECTS = split.$(OBJEXT) +split_LDADD = $(LDADD) +split_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +split_LDFLAGS = +stat_SOURCES = stat.c +stat_OBJECTS = stat.$(OBJEXT) +stat_LDADD = $(LDADD) +stat_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +stat_LDFLAGS = +stty_SOURCES = stty.c +stty_OBJECTS = stty.$(OBJEXT) +stty_LDADD = $(LDADD) +stty_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +stty_LDFLAGS = +su_SOURCES = su.c +su_OBJECTS = su.$(OBJEXT) +su_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +su_LDFLAGS = +sum_SOURCES = sum.c +sum_OBJECTS = sum.$(OBJEXT) +sum_LDADD = $(LDADD) +sum_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +sum_LDFLAGS = +sync_SOURCES = sync.c +sync_OBJECTS = sync.$(OBJEXT) +sync_LDADD = $(LDADD) +sync_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +sync_LDFLAGS = +tac_SOURCES = tac.c +tac_OBJECTS = tac.$(OBJEXT) +tac_LDADD = $(LDADD) +tac_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +tac_LDFLAGS = +tail_SOURCES = tail.c +tail_OBJECTS = tail.$(OBJEXT) +tail_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +tail_LDFLAGS = +tee_SOURCES = tee.c +tee_OBJECTS = tee.$(OBJEXT) +tee_LDADD = $(LDADD) +tee_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +tee_LDFLAGS = +test_SOURCES = test.c +test_OBJECTS = test.$(OBJEXT) +test_LDADD = $(LDADD) +test_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +test_LDFLAGS = +touch_SOURCES = touch.c +touch_OBJECTS = touch.$(OBJEXT) +touch_LDADD = $(LDADD) +touch_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +touch_LDFLAGS = +tr_SOURCES = tr.c +tr_OBJECTS = tr.$(OBJEXT) +tr_LDADD = $(LDADD) +tr_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +tr_LDFLAGS = +true_SOURCES = true.c +true_OBJECTS = true.$(OBJEXT) +true_LDADD = $(LDADD) +true_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +true_LDFLAGS = +tsort_SOURCES = tsort.c +tsort_OBJECTS = tsort.$(OBJEXT) +tsort_LDADD = $(LDADD) +tsort_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +tsort_LDFLAGS = +tty_SOURCES = tty.c +tty_OBJECTS = tty.$(OBJEXT) +tty_LDADD = $(LDADD) +tty_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +tty_LDFLAGS = +uname_SOURCES = uname.c +uname_OBJECTS = uname.$(OBJEXT) +uname_LDADD = $(LDADD) +uname_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +uname_LDFLAGS = +unexpand_SOURCES = unexpand.c +unexpand_OBJECTS = unexpand.$(OBJEXT) +unexpand_LDADD = $(LDADD) +unexpand_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +unexpand_LDFLAGS = +uniq_SOURCES = uniq.c +uniq_OBJECTS = uniq.$(OBJEXT) +uniq_LDADD = $(LDADD) +uniq_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +uniq_LDFLAGS = +unlink_SOURCES = unlink.c +unlink_OBJECTS = unlink.$(OBJEXT) +unlink_LDADD = $(LDADD) +unlink_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +unlink_LDFLAGS = +uptime_SOURCES = uptime.c +uptime_OBJECTS = uptime.$(OBJEXT) +uptime_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +uptime_LDFLAGS = +users_SOURCES = users.c +users_OBJECTS = users.$(OBJEXT) +users_LDADD = $(LDADD) +users_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +users_LDFLAGS = +am_vdir_OBJECTS = ls.$(OBJEXT) ls-vdir.$(OBJEXT) +vdir_OBJECTS = $(am_vdir_OBJECTS) +vdir_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +vdir_LDFLAGS = +wc_SOURCES = wc.c +wc_OBJECTS = wc.$(OBJEXT) +wc_LDADD = $(LDADD) +wc_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +wc_LDFLAGS = +who_SOURCES = who.c +who_OBJECTS = who.$(OBJEXT) +who_LDADD = $(LDADD) +who_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +who_LDFLAGS = +whoami_SOURCES = whoami.c +whoami_OBJECTS = whoami.$(OBJEXT) +whoami_LDADD = $(LDADD) +whoami_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +whoami_LDFLAGS = +yes_SOURCES = yes.c +yes_OBJECTS = yes.$(OBJEXT) +yes_LDADD = $(LDADD) +yes_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +yes_LDFLAGS = +SCRIPTS = $(bin_SCRIPTS) + + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +DEP_FILES = ./$(DEPDIR)/basename.Po ./$(DEPDIR)/cat.Po \ + ./$(DEPDIR)/chgrp.Po ./$(DEPDIR)/chmod.Po \ + ./$(DEPDIR)/chown-core.Po ./$(DEPDIR)/chown.Po \ + ./$(DEPDIR)/chroot.Po ./$(DEPDIR)/cksum.Po \ + ./$(DEPDIR)/comm.Po ./$(DEPDIR)/copy.Po \ + ./$(DEPDIR)/cp-hash.Po ./$(DEPDIR)/cp.Po \ + ./$(DEPDIR)/csplit.Po ./$(DEPDIR)/cut.Po \ + ./$(DEPDIR)/date.Po ./$(DEPDIR)/dd.Po \ + ./$(DEPDIR)/df.Po ./$(DEPDIR)/dircolors.Po \ + ./$(DEPDIR)/dirname.Po ./$(DEPDIR)/du.Po \ + ./$(DEPDIR)/echo.Po ./$(DEPDIR)/env.Po \ + ./$(DEPDIR)/expand.Po ./$(DEPDIR)/expr.Po \ + ./$(DEPDIR)/factor.Po ./$(DEPDIR)/false.Po \ + ./$(DEPDIR)/fmt.Po ./$(DEPDIR)/fold.Po \ + ./$(DEPDIR)/head.Po ./$(DEPDIR)/hostid.Po \ + ./$(DEPDIR)/hostname.Po ./$(DEPDIR)/id.Po \ + ./$(DEPDIR)/install.Po ./$(DEPDIR)/join.Po \ + ./$(DEPDIR)/kill.Po ./$(DEPDIR)/link.Po \ + ./$(DEPDIR)/ln.Po ./$(DEPDIR)/logname.Po \ + ./$(DEPDIR)/ls-dir.Po ./$(DEPDIR)/ls-ls.Po \ + ./$(DEPDIR)/ls-vdir.Po ./$(DEPDIR)/ls.Po \ + ./$(DEPDIR)/md5.Po ./$(DEPDIR)/md5sum.Po \ + ./$(DEPDIR)/mkdir.Po ./$(DEPDIR)/mkfifo.Po \ + ./$(DEPDIR)/mknod.Po ./$(DEPDIR)/mv.Po \ + ./$(DEPDIR)/nice.Po ./$(DEPDIR)/nl.Po \ + ./$(DEPDIR)/od.Po ./$(DEPDIR)/paste.Po \ + ./$(DEPDIR)/pathchk.Po ./$(DEPDIR)/pinky.Po \ + ./$(DEPDIR)/pr.Po ./$(DEPDIR)/printenv.Po \ + ./$(DEPDIR)/printf.Po ./$(DEPDIR)/ptx.Po \ + ./$(DEPDIR)/pwd.Po ./$(DEPDIR)/readlink.Po \ + ./$(DEPDIR)/remove.Po ./$(DEPDIR)/rm.Po \ + ./$(DEPDIR)/rmdir.Po ./$(DEPDIR)/seq.Po \ + ./$(DEPDIR)/sha1sum.Po ./$(DEPDIR)/shred.Po \ + ./$(DEPDIR)/sleep.Po ./$(DEPDIR)/sort.Po \ + ./$(DEPDIR)/split.Po ./$(DEPDIR)/stat.Po \ + ./$(DEPDIR)/stty.Po ./$(DEPDIR)/su.Po \ + ./$(DEPDIR)/sum.Po ./$(DEPDIR)/sync.Po \ + ./$(DEPDIR)/tac.Po ./$(DEPDIR)/tail.Po \ + ./$(DEPDIR)/tee.Po ./$(DEPDIR)/test.Po \ + ./$(DEPDIR)/touch.Po ./$(DEPDIR)/tr.Po \ + ./$(DEPDIR)/true.Po ./$(DEPDIR)/tsort.Po \ + ./$(DEPDIR)/tty.Po ./$(DEPDIR)/uname.Po \ + ./$(DEPDIR)/unexpand.Po ./$(DEPDIR)/uniq.Po \ + ./$(DEPDIR)/unlink.Po ./$(DEPDIR)/uptime.Po \ + ./$(DEPDIR)/users.Po ./$(DEPDIR)/wc.Po \ + ./$(DEPDIR)/who.Po ./$(DEPDIR)/whoami.Po \ + ./$(DEPDIR)/yes.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = basename.c cat.c $(chgrp_SOURCES) chmod.c \ + $(chown_SOURCES) chroot.c cksum.c comm.c $(cp_SOURCES) csplit.c \ + cut.c date.c dd.c df.c $(dir_SOURCES) dircolors.c dirname.c \ + du.c echo.c env.c expand.c expr.c factor.c false.c fmt.c fold.c \ + $(ginstall_SOURCES) head.c hostid.c hostname.c id.c join.c \ + kill.c link.c ln.c logname.c $(ls_SOURCES) $(md5sum_SOURCES) \ + mkdir.c mkfifo.c mknod.c $(mv_SOURCES) nice.c nl.c od.c paste.c \ + pathchk.c pinky.c pr.c printenv.c printf.c ptx.c pwd.c \ + readlink.c $(rm_SOURCES) rmdir.c seq.c $(sha1sum_SOURCES) \ + shred.c sleep.c sort.c split.c stat.c stty.c su.c sum.c sync.c \ + tac.c tail.c tee.c test.c touch.c tr.c true.c tsort.c tty.c \ + uname.c unexpand.c uniq.c unlink.c uptime.c users.c \ + $(vdir_SOURCES) wc.c who.c whoami.c yes.c +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = $(noinst_HEADERS) Makefile.am Makefile.in +SOURCES = basename.c cat.c $(chgrp_SOURCES) chmod.c $(chown_SOURCES) chroot.c cksum.c comm.c $(cp_SOURCES) csplit.c cut.c date.c dd.c df.c $(dir_SOURCES) dircolors.c dirname.c du.c echo.c env.c expand.c expr.c factor.c false.c fmt.c fold.c $(ginstall_SOURCES) head.c hostid.c hostname.c id.c join.c kill.c link.c ln.c logname.c $(ls_SOURCES) $(md5sum_SOURCES) mkdir.c mkfifo.c mknod.c $(mv_SOURCES) nice.c nl.c od.c paste.c pathchk.c pinky.c pr.c printenv.c printf.c ptx.c pwd.c readlink.c $(rm_SOURCES) rmdir.c seq.c $(sha1sum_SOURCES) shred.c sleep.c sort.c split.c stat.c stty.c su.c sum.c sync.c tac.c tail.c tee.c test.c touch.c tr.c true.c tsort.c tty.c uname.c unexpand.c uniq.c unlink.c uptime.c users.c $(vdir_SOURCES) wc.c who.c whoami.c yes.c + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .sh .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnits src/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) > /dev/null 2>&1 || /bin/rm -f $(bin_PROGRAMS) + +installcheck-binPROGRAMS: $(bin_PROGRAMS) + bad=0; pid=$$$$; list="$(bin_PROGRAMS)"; for p in $$list; do \ + case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \ + *" $$p "* | *" $(srcdir)/$$p "*) continue;; \ + esac; \ + f=`echo "$$p" | \ + sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + for opt in --help --version; do \ + if $(DESTDIR)$(bindir)/$$f $$opt > c$${pid}_.out 2> c$${pid}_.err \ + && test -n "`cat c$${pid}_.out`" \ + && test -z "`cat c$${pid}_.err`"; then :; \ + else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \ + done; \ + done; rm -f c$${pid}_.???; exit $$bad +basename$(EXEEXT): $(basename_OBJECTS) $(basename_DEPENDENCIES) + @rm -f basename$(EXEEXT) + $(LINK) $(basename_LDFLAGS) $(basename_OBJECTS) $(basename_LDADD) $(LIBS) +cat$(EXEEXT): $(cat_OBJECTS) $(cat_DEPENDENCIES) + @rm -f cat$(EXEEXT) + $(LINK) $(cat_LDFLAGS) $(cat_OBJECTS) $(cat_LDADD) $(LIBS) +chgrp$(EXEEXT): $(chgrp_OBJECTS) $(chgrp_DEPENDENCIES) + @rm -f chgrp$(EXEEXT) + $(LINK) $(chgrp_LDFLAGS) $(chgrp_OBJECTS) $(chgrp_LDADD) $(LIBS) +chmod$(EXEEXT): $(chmod_OBJECTS) $(chmod_DEPENDENCIES) + @rm -f chmod$(EXEEXT) + $(LINK) $(chmod_LDFLAGS) $(chmod_OBJECTS) $(chmod_LDADD) $(LIBS) +chown$(EXEEXT): $(chown_OBJECTS) $(chown_DEPENDENCIES) + @rm -f chown$(EXEEXT) + $(LINK) $(chown_LDFLAGS) $(chown_OBJECTS) $(chown_LDADD) $(LIBS) +chroot$(EXEEXT): $(chroot_OBJECTS) $(chroot_DEPENDENCIES) + @rm -f chroot$(EXEEXT) + $(LINK) $(chroot_LDFLAGS) $(chroot_OBJECTS) $(chroot_LDADD) $(LIBS) +cksum$(EXEEXT): $(cksum_OBJECTS) $(cksum_DEPENDENCIES) + @rm -f cksum$(EXEEXT) + $(LINK) $(cksum_LDFLAGS) $(cksum_OBJECTS) $(cksum_LDADD) $(LIBS) +comm$(EXEEXT): $(comm_OBJECTS) $(comm_DEPENDENCIES) + @rm -f comm$(EXEEXT) + $(LINK) $(comm_LDFLAGS) $(comm_OBJECTS) $(comm_LDADD) $(LIBS) +cp$(EXEEXT): $(cp_OBJECTS) $(cp_DEPENDENCIES) + @rm -f cp$(EXEEXT) + $(LINK) $(cp_LDFLAGS) $(cp_OBJECTS) $(cp_LDADD) $(LIBS) +csplit$(EXEEXT): $(csplit_OBJECTS) $(csplit_DEPENDENCIES) + @rm -f csplit$(EXEEXT) + $(LINK) $(csplit_LDFLAGS) $(csplit_OBJECTS) $(csplit_LDADD) $(LIBS) +cut$(EXEEXT): $(cut_OBJECTS) $(cut_DEPENDENCIES) + @rm -f cut$(EXEEXT) + $(LINK) $(cut_LDFLAGS) $(cut_OBJECTS) $(cut_LDADD) $(LIBS) +date$(EXEEXT): $(date_OBJECTS) $(date_DEPENDENCIES) + @rm -f date$(EXEEXT) + $(LINK) $(date_LDFLAGS) $(date_OBJECTS) $(date_LDADD) $(LIBS) +dd$(EXEEXT): $(dd_OBJECTS) $(dd_DEPENDENCIES) + @rm -f dd$(EXEEXT) + $(LINK) $(dd_LDFLAGS) $(dd_OBJECTS) $(dd_LDADD) $(LIBS) +df$(EXEEXT): $(df_OBJECTS) $(df_DEPENDENCIES) + @rm -f df$(EXEEXT) + $(LINK) $(df_LDFLAGS) $(df_OBJECTS) $(df_LDADD) $(LIBS) +dir$(EXEEXT): $(dir_OBJECTS) $(dir_DEPENDENCIES) + @rm -f dir$(EXEEXT) + $(LINK) $(dir_LDFLAGS) $(dir_OBJECTS) $(dir_LDADD) $(LIBS) +dircolors$(EXEEXT): $(dircolors_OBJECTS) $(dircolors_DEPENDENCIES) + @rm -f dircolors$(EXEEXT) + $(LINK) $(dircolors_LDFLAGS) $(dircolors_OBJECTS) $(dircolors_LDADD) $(LIBS) +dirname$(EXEEXT): $(dirname_OBJECTS) $(dirname_DEPENDENCIES) + @rm -f dirname$(EXEEXT) + $(LINK) $(dirname_LDFLAGS) $(dirname_OBJECTS) $(dirname_LDADD) $(LIBS) +du$(EXEEXT): $(du_OBJECTS) $(du_DEPENDENCIES) + @rm -f du$(EXEEXT) + $(LINK) $(du_LDFLAGS) $(du_OBJECTS) $(du_LDADD) $(LIBS) +echo$(EXEEXT): $(echo_OBJECTS) $(echo_DEPENDENCIES) + @rm -f echo$(EXEEXT) + $(LINK) $(echo_LDFLAGS) $(echo_OBJECTS) $(echo_LDADD) $(LIBS) +env$(EXEEXT): $(env_OBJECTS) $(env_DEPENDENCIES) + @rm -f env$(EXEEXT) + $(LINK) $(env_LDFLAGS) $(env_OBJECTS) $(env_LDADD) $(LIBS) +expand$(EXEEXT): $(expand_OBJECTS) $(expand_DEPENDENCIES) + @rm -f expand$(EXEEXT) + $(LINK) $(expand_LDFLAGS) $(expand_OBJECTS) $(expand_LDADD) $(LIBS) +expr$(EXEEXT): $(expr_OBJECTS) $(expr_DEPENDENCIES) + @rm -f expr$(EXEEXT) + $(LINK) $(expr_LDFLAGS) $(expr_OBJECTS) $(expr_LDADD) $(LIBS) +factor$(EXEEXT): $(factor_OBJECTS) $(factor_DEPENDENCIES) + @rm -f factor$(EXEEXT) + $(LINK) $(factor_LDFLAGS) $(factor_OBJECTS) $(factor_LDADD) $(LIBS) +false$(EXEEXT): $(false_OBJECTS) $(false_DEPENDENCIES) + @rm -f false$(EXEEXT) + $(LINK) $(false_LDFLAGS) $(false_OBJECTS) $(false_LDADD) $(LIBS) +fmt$(EXEEXT): $(fmt_OBJECTS) $(fmt_DEPENDENCIES) + @rm -f fmt$(EXEEXT) + $(LINK) $(fmt_LDFLAGS) $(fmt_OBJECTS) $(fmt_LDADD) $(LIBS) +fold$(EXEEXT): $(fold_OBJECTS) $(fold_DEPENDENCIES) + @rm -f fold$(EXEEXT) + $(LINK) $(fold_LDFLAGS) $(fold_OBJECTS) $(fold_LDADD) $(LIBS) +ginstall$(EXEEXT): $(ginstall_OBJECTS) $(ginstall_DEPENDENCIES) + @rm -f ginstall$(EXEEXT) + $(LINK) $(ginstall_LDFLAGS) $(ginstall_OBJECTS) $(ginstall_LDADD) $(LIBS) +head$(EXEEXT): $(head_OBJECTS) $(head_DEPENDENCIES) + @rm -f head$(EXEEXT) + $(LINK) $(head_LDFLAGS) $(head_OBJECTS) $(head_LDADD) $(LIBS) +hostid$(EXEEXT): $(hostid_OBJECTS) $(hostid_DEPENDENCIES) + @rm -f hostid$(EXEEXT) + $(LINK) $(hostid_LDFLAGS) $(hostid_OBJECTS) $(hostid_LDADD) $(LIBS) +hostname$(EXEEXT): $(hostname_OBJECTS) $(hostname_DEPENDENCIES) + @rm -f hostname$(EXEEXT) + $(LINK) $(hostname_LDFLAGS) $(hostname_OBJECTS) $(hostname_LDADD) $(LIBS) +id$(EXEEXT): $(id_OBJECTS) $(id_DEPENDENCIES) + @rm -f id$(EXEEXT) + $(LINK) $(id_LDFLAGS) $(id_OBJECTS) $(id_LDADD) $(LIBS) +join$(EXEEXT): $(join_OBJECTS) $(join_DEPENDENCIES) + @rm -f join$(EXEEXT) + $(LINK) $(join_LDFLAGS) $(join_OBJECTS) $(join_LDADD) $(LIBS) +kill$(EXEEXT): $(kill_OBJECTS) $(kill_DEPENDENCIES) + @rm -f kill$(EXEEXT) + $(LINK) $(kill_LDFLAGS) $(kill_OBJECTS) $(kill_LDADD) $(LIBS) +link$(EXEEXT): $(link_OBJECTS) $(link_DEPENDENCIES) + @rm -f link$(EXEEXT) + $(LINK) $(link_LDFLAGS) $(link_OBJECTS) $(link_LDADD) $(LIBS) +ln$(EXEEXT): $(ln_OBJECTS) $(ln_DEPENDENCIES) + @rm -f ln$(EXEEXT) + $(LINK) $(ln_LDFLAGS) $(ln_OBJECTS) $(ln_LDADD) $(LIBS) +logname$(EXEEXT): $(logname_OBJECTS) $(logname_DEPENDENCIES) + @rm -f logname$(EXEEXT) + $(LINK) $(logname_LDFLAGS) $(logname_OBJECTS) $(logname_LDADD) $(LIBS) +ls$(EXEEXT): $(ls_OBJECTS) $(ls_DEPENDENCIES) + @rm -f ls$(EXEEXT) + $(LINK) $(ls_LDFLAGS) $(ls_OBJECTS) $(ls_LDADD) $(LIBS) +md5sum$(EXEEXT): $(md5sum_OBJECTS) $(md5sum_DEPENDENCIES) + @rm -f md5sum$(EXEEXT) + $(LINK) $(md5sum_LDFLAGS) $(md5sum_OBJECTS) $(md5sum_LDADD) $(LIBS) +mkdir$(EXEEXT): $(mkdir_OBJECTS) $(mkdir_DEPENDENCIES) + @rm -f mkdir$(EXEEXT) + $(LINK) $(mkdir_LDFLAGS) $(mkdir_OBJECTS) $(mkdir_LDADD) $(LIBS) +mkfifo$(EXEEXT): $(mkfifo_OBJECTS) $(mkfifo_DEPENDENCIES) + @rm -f mkfifo$(EXEEXT) + $(LINK) $(mkfifo_LDFLAGS) $(mkfifo_OBJECTS) $(mkfifo_LDADD) $(LIBS) +mknod$(EXEEXT): $(mknod_OBJECTS) $(mknod_DEPENDENCIES) + @rm -f mknod$(EXEEXT) + $(LINK) $(mknod_LDFLAGS) $(mknod_OBJECTS) $(mknod_LDADD) $(LIBS) +mv$(EXEEXT): $(mv_OBJECTS) $(mv_DEPENDENCIES) + @rm -f mv$(EXEEXT) + $(LINK) $(mv_LDFLAGS) $(mv_OBJECTS) $(mv_LDADD) $(LIBS) +nice$(EXEEXT): $(nice_OBJECTS) $(nice_DEPENDENCIES) + @rm -f nice$(EXEEXT) + $(LINK) $(nice_LDFLAGS) $(nice_OBJECTS) $(nice_LDADD) $(LIBS) +nl$(EXEEXT): $(nl_OBJECTS) $(nl_DEPENDENCIES) + @rm -f nl$(EXEEXT) + $(LINK) $(nl_LDFLAGS) $(nl_OBJECTS) $(nl_LDADD) $(LIBS) +od$(EXEEXT): $(od_OBJECTS) $(od_DEPENDENCIES) + @rm -f od$(EXEEXT) + $(LINK) $(od_LDFLAGS) $(od_OBJECTS) $(od_LDADD) $(LIBS) +paste$(EXEEXT): $(paste_OBJECTS) $(paste_DEPENDENCIES) + @rm -f paste$(EXEEXT) + $(LINK) $(paste_LDFLAGS) $(paste_OBJECTS) $(paste_LDADD) $(LIBS) +pathchk$(EXEEXT): $(pathchk_OBJECTS) $(pathchk_DEPENDENCIES) + @rm -f pathchk$(EXEEXT) + $(LINK) $(pathchk_LDFLAGS) $(pathchk_OBJECTS) $(pathchk_LDADD) $(LIBS) +pinky$(EXEEXT): $(pinky_OBJECTS) $(pinky_DEPENDENCIES) + @rm -f pinky$(EXEEXT) + $(LINK) $(pinky_LDFLAGS) $(pinky_OBJECTS) $(pinky_LDADD) $(LIBS) +pr$(EXEEXT): $(pr_OBJECTS) $(pr_DEPENDENCIES) + @rm -f pr$(EXEEXT) + $(LINK) $(pr_LDFLAGS) $(pr_OBJECTS) $(pr_LDADD) $(LIBS) +printenv$(EXEEXT): $(printenv_OBJECTS) $(printenv_DEPENDENCIES) + @rm -f printenv$(EXEEXT) + $(LINK) $(printenv_LDFLAGS) $(printenv_OBJECTS) $(printenv_LDADD) $(LIBS) +printf$(EXEEXT): $(printf_OBJECTS) $(printf_DEPENDENCIES) + @rm -f printf$(EXEEXT) + $(LINK) $(printf_LDFLAGS) $(printf_OBJECTS) $(printf_LDADD) $(LIBS) +ptx$(EXEEXT): $(ptx_OBJECTS) $(ptx_DEPENDENCIES) + @rm -f ptx$(EXEEXT) + $(LINK) $(ptx_LDFLAGS) $(ptx_OBJECTS) $(ptx_LDADD) $(LIBS) +pwd$(EXEEXT): $(pwd_OBJECTS) $(pwd_DEPENDENCIES) + @rm -f pwd$(EXEEXT) + $(LINK) $(pwd_LDFLAGS) $(pwd_OBJECTS) $(pwd_LDADD) $(LIBS) +readlink$(EXEEXT): $(readlink_OBJECTS) $(readlink_DEPENDENCIES) + @rm -f readlink$(EXEEXT) + $(LINK) $(readlink_LDFLAGS) $(readlink_OBJECTS) $(readlink_LDADD) $(LIBS) +rm$(EXEEXT): $(rm_OBJECTS) $(rm_DEPENDENCIES) + @rm -f rm$(EXEEXT) + $(LINK) $(rm_LDFLAGS) $(rm_OBJECTS) $(rm_LDADD) $(LIBS) +rmdir$(EXEEXT): $(rmdir_OBJECTS) $(rmdir_DEPENDENCIES) + @rm -f rmdir$(EXEEXT) + $(LINK) $(rmdir_LDFLAGS) $(rmdir_OBJECTS) $(rmdir_LDADD) $(LIBS) +seq$(EXEEXT): $(seq_OBJECTS) $(seq_DEPENDENCIES) + @rm -f seq$(EXEEXT) + $(LINK) $(seq_LDFLAGS) $(seq_OBJECTS) $(seq_LDADD) $(LIBS) +sha1sum$(EXEEXT): $(sha1sum_OBJECTS) $(sha1sum_DEPENDENCIES) + @rm -f sha1sum$(EXEEXT) + $(LINK) $(sha1sum_LDFLAGS) $(sha1sum_OBJECTS) $(sha1sum_LDADD) $(LIBS) +shred$(EXEEXT): $(shred_OBJECTS) $(shred_DEPENDENCIES) + @rm -f shred$(EXEEXT) + $(LINK) $(shred_LDFLAGS) $(shred_OBJECTS) $(shred_LDADD) $(LIBS) +sleep$(EXEEXT): $(sleep_OBJECTS) $(sleep_DEPENDENCIES) + @rm -f sleep$(EXEEXT) + $(LINK) $(sleep_LDFLAGS) $(sleep_OBJECTS) $(sleep_LDADD) $(LIBS) +sort$(EXEEXT): $(sort_OBJECTS) $(sort_DEPENDENCIES) + @rm -f sort$(EXEEXT) + $(LINK) $(sort_LDFLAGS) $(sort_OBJECTS) $(sort_LDADD) $(LIBS) +split$(EXEEXT): $(split_OBJECTS) $(split_DEPENDENCIES) + @rm -f split$(EXEEXT) + $(LINK) $(split_LDFLAGS) $(split_OBJECTS) $(split_LDADD) $(LIBS) +stat$(EXEEXT): $(stat_OBJECTS) $(stat_DEPENDENCIES) + @rm -f stat$(EXEEXT) + $(LINK) $(stat_LDFLAGS) $(stat_OBJECTS) $(stat_LDADD) $(LIBS) +stty$(EXEEXT): $(stty_OBJECTS) $(stty_DEPENDENCIES) + @rm -f stty$(EXEEXT) + $(LINK) $(stty_LDFLAGS) $(stty_OBJECTS) $(stty_LDADD) $(LIBS) +su$(EXEEXT): $(su_OBJECTS) $(su_DEPENDENCIES) + @rm -f su$(EXEEXT) + $(LINK) $(su_LDFLAGS) $(su_OBJECTS) $(su_LDADD) $(LIBS) +sum$(EXEEXT): $(sum_OBJECTS) $(sum_DEPENDENCIES) + @rm -f sum$(EXEEXT) + $(LINK) $(sum_LDFLAGS) $(sum_OBJECTS) $(sum_LDADD) $(LIBS) +sync$(EXEEXT): $(sync_OBJECTS) $(sync_DEPENDENCIES) + @rm -f sync$(EXEEXT) + $(LINK) $(sync_LDFLAGS) $(sync_OBJECTS) $(sync_LDADD) $(LIBS) +tac$(EXEEXT): $(tac_OBJECTS) $(tac_DEPENDENCIES) + @rm -f tac$(EXEEXT) + $(LINK) $(tac_LDFLAGS) $(tac_OBJECTS) $(tac_LDADD) $(LIBS) +tail$(EXEEXT): $(tail_OBJECTS) $(tail_DEPENDENCIES) + @rm -f tail$(EXEEXT) + $(LINK) $(tail_LDFLAGS) $(tail_OBJECTS) $(tail_LDADD) $(LIBS) +tee$(EXEEXT): $(tee_OBJECTS) $(tee_DEPENDENCIES) + @rm -f tee$(EXEEXT) + $(LINK) $(tee_LDFLAGS) $(tee_OBJECTS) $(tee_LDADD) $(LIBS) +test$(EXEEXT): $(test_OBJECTS) $(test_DEPENDENCIES) + @rm -f test$(EXEEXT) + $(LINK) $(test_LDFLAGS) $(test_OBJECTS) $(test_LDADD) $(LIBS) +touch$(EXEEXT): $(touch_OBJECTS) $(touch_DEPENDENCIES) + @rm -f touch$(EXEEXT) + $(LINK) $(touch_LDFLAGS) $(touch_OBJECTS) $(touch_LDADD) $(LIBS) +tr$(EXEEXT): $(tr_OBJECTS) $(tr_DEPENDENCIES) + @rm -f tr$(EXEEXT) + $(LINK) $(tr_LDFLAGS) $(tr_OBJECTS) $(tr_LDADD) $(LIBS) +true$(EXEEXT): $(true_OBJECTS) $(true_DEPENDENCIES) + @rm -f true$(EXEEXT) + $(LINK) $(true_LDFLAGS) $(true_OBJECTS) $(true_LDADD) $(LIBS) +tsort$(EXEEXT): $(tsort_OBJECTS) $(tsort_DEPENDENCIES) + @rm -f tsort$(EXEEXT) + $(LINK) $(tsort_LDFLAGS) $(tsort_OBJECTS) $(tsort_LDADD) $(LIBS) +tty$(EXEEXT): $(tty_OBJECTS) $(tty_DEPENDENCIES) + @rm -f tty$(EXEEXT) + $(LINK) $(tty_LDFLAGS) $(tty_OBJECTS) $(tty_LDADD) $(LIBS) +uname$(EXEEXT): $(uname_OBJECTS) $(uname_DEPENDENCIES) + @rm -f uname$(EXEEXT) + $(LINK) $(uname_LDFLAGS) $(uname_OBJECTS) $(uname_LDADD) $(LIBS) +unexpand$(EXEEXT): $(unexpand_OBJECTS) $(unexpand_DEPENDENCIES) + @rm -f unexpand$(EXEEXT) + $(LINK) $(unexpand_LDFLAGS) $(unexpand_OBJECTS) $(unexpand_LDADD) $(LIBS) +uniq$(EXEEXT): $(uniq_OBJECTS) $(uniq_DEPENDENCIES) + @rm -f uniq$(EXEEXT) + $(LINK) $(uniq_LDFLAGS) $(uniq_OBJECTS) $(uniq_LDADD) $(LIBS) +unlink$(EXEEXT): $(unlink_OBJECTS) $(unlink_DEPENDENCIES) + @rm -f unlink$(EXEEXT) + $(LINK) $(unlink_LDFLAGS) $(unlink_OBJECTS) $(unlink_LDADD) $(LIBS) +uptime$(EXEEXT): $(uptime_OBJECTS) $(uptime_DEPENDENCIES) + @rm -f uptime$(EXEEXT) + $(LINK) $(uptime_LDFLAGS) $(uptime_OBJECTS) $(uptime_LDADD) $(LIBS) +users$(EXEEXT): $(users_OBJECTS) $(users_DEPENDENCIES) + @rm -f users$(EXEEXT) + $(LINK) $(users_LDFLAGS) $(users_OBJECTS) $(users_LDADD) $(LIBS) +vdir$(EXEEXT): $(vdir_OBJECTS) $(vdir_DEPENDENCIES) + @rm -f vdir$(EXEEXT) + $(LINK) $(vdir_LDFLAGS) $(vdir_OBJECTS) $(vdir_LDADD) $(LIBS) +wc$(EXEEXT): $(wc_OBJECTS) $(wc_DEPENDENCIES) + @rm -f wc$(EXEEXT) + $(LINK) $(wc_LDFLAGS) $(wc_OBJECTS) $(wc_LDADD) $(LIBS) +who$(EXEEXT): $(who_OBJECTS) $(who_DEPENDENCIES) + @rm -f who$(EXEEXT) + $(LINK) $(who_LDFLAGS) $(who_OBJECTS) $(who_LDADD) $(LIBS) +whoami$(EXEEXT): $(whoami_OBJECTS) $(whoami_DEPENDENCIES) + @rm -f whoami$(EXEEXT) + $(LINK) $(whoami_LDFLAGS) $(whoami_OBJECTS) $(whoami_LDADD) $(LIBS) +yes$(EXEEXT): $(yes_OBJECTS) $(yes_DEPENDENCIES) + @rm -f yes$(EXEEXT) + $(LINK) $(yes_LDFLAGS) $(yes_OBJECTS) $(yes_LDADD) $(LIBS) +binSCRIPT_INSTALL = $(INSTALL_SCRIPT) +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f $$d$$p; then \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " $(binSCRIPT_INSTALL) $$d$$p $(DESTDIR)$(bindir)/$$f"; \ + $(binSCRIPT_INSTALL) $$d$$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done + +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +installcheck-binSCRIPTS: $(bin_SCRIPTS) + bad=0; pid=$$$$; list="$(bin_SCRIPTS)"; for p in $$list; do \ + case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \ + *" $$p "* | *" $(srcdir)/$$p "*) continue;; \ + esac; \ + f=`echo "$$p" | sed 's,^.*/,,;$(transform)'`; \ + for opt in --help --version; do \ + if $(DESTDIR)$(bindir)/$$f $$opt > c$${pid}_.out 2> c$${pid}_.err \ + && test -n "`cat c$${pid}_.out`" \ + && test -z "`cat c$${pid}_.err`"; then :; \ + else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \ + done; \ + done; rm -f c$${pid}_.???; exit $$bad + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +include ./$(DEPDIR)/basename.Po +include ./$(DEPDIR)/cat.Po +include ./$(DEPDIR)/chgrp.Po +include ./$(DEPDIR)/chmod.Po +include ./$(DEPDIR)/chown-core.Po +include ./$(DEPDIR)/chown.Po +include ./$(DEPDIR)/chroot.Po +include ./$(DEPDIR)/cksum.Po +include ./$(DEPDIR)/comm.Po +include ./$(DEPDIR)/copy.Po +include ./$(DEPDIR)/cp-hash.Po +include ./$(DEPDIR)/cp.Po +include ./$(DEPDIR)/csplit.Po +include ./$(DEPDIR)/cut.Po +include ./$(DEPDIR)/date.Po +include ./$(DEPDIR)/dd.Po +include ./$(DEPDIR)/df.Po +include ./$(DEPDIR)/dircolors.Po +include ./$(DEPDIR)/dirname.Po +include ./$(DEPDIR)/du.Po +include ./$(DEPDIR)/echo.Po +include ./$(DEPDIR)/env.Po +include ./$(DEPDIR)/expand.Po +include ./$(DEPDIR)/expr.Po +include ./$(DEPDIR)/factor.Po +include ./$(DEPDIR)/false.Po +include ./$(DEPDIR)/fmt.Po +include ./$(DEPDIR)/fold.Po +include ./$(DEPDIR)/head.Po +include ./$(DEPDIR)/hostid.Po +include ./$(DEPDIR)/hostname.Po +include ./$(DEPDIR)/id.Po +include ./$(DEPDIR)/install.Po +include ./$(DEPDIR)/join.Po +include ./$(DEPDIR)/kill.Po +include ./$(DEPDIR)/link.Po +include ./$(DEPDIR)/ln.Po +include ./$(DEPDIR)/logname.Po +include ./$(DEPDIR)/ls-dir.Po +include ./$(DEPDIR)/ls-ls.Po +include ./$(DEPDIR)/ls-vdir.Po +include ./$(DEPDIR)/ls.Po +include ./$(DEPDIR)/md5.Po +include ./$(DEPDIR)/md5sum.Po +include ./$(DEPDIR)/mkdir.Po +include ./$(DEPDIR)/mkfifo.Po +include ./$(DEPDIR)/mknod.Po +include ./$(DEPDIR)/mv.Po +include ./$(DEPDIR)/nice.Po +include ./$(DEPDIR)/nl.Po +include ./$(DEPDIR)/od.Po +include ./$(DEPDIR)/paste.Po +include ./$(DEPDIR)/pathchk.Po +include ./$(DEPDIR)/pinky.Po +include ./$(DEPDIR)/pr.Po +include ./$(DEPDIR)/printenv.Po +include ./$(DEPDIR)/printf.Po +include ./$(DEPDIR)/ptx.Po +include ./$(DEPDIR)/pwd.Po +include ./$(DEPDIR)/readlink.Po +include ./$(DEPDIR)/remove.Po +include ./$(DEPDIR)/rm.Po +include ./$(DEPDIR)/rmdir.Po +include ./$(DEPDIR)/seq.Po +include ./$(DEPDIR)/sha1sum.Po +include ./$(DEPDIR)/shred.Po +include ./$(DEPDIR)/sleep.Po +include ./$(DEPDIR)/sort.Po +include ./$(DEPDIR)/split.Po +include ./$(DEPDIR)/stat.Po +include ./$(DEPDIR)/stty.Po +include ./$(DEPDIR)/su.Po +include ./$(DEPDIR)/sum.Po +include ./$(DEPDIR)/sync.Po +include ./$(DEPDIR)/tac.Po +include ./$(DEPDIR)/tail.Po +include ./$(DEPDIR)/tee.Po +include ./$(DEPDIR)/test.Po +include ./$(DEPDIR)/touch.Po +include ./$(DEPDIR)/tr.Po +include ./$(DEPDIR)/true.Po +include ./$(DEPDIR)/tsort.Po +include ./$(DEPDIR)/tty.Po +include ./$(DEPDIR)/uname.Po +include ./$(DEPDIR)/unexpand.Po +include ./$(DEPDIR)/uniq.Po +include ./$(DEPDIR)/unlink.Po +include ./$(DEPDIR)/uptime.Po +include ./$(DEPDIR)/users.Po +include ./$(DEPDIR)/wc.Po +include ./$(DEPDIR)/who.Po +include ./$(DEPDIR)/whoami.Po +include ./$(DEPDIR)/yes.Po + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +# if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +# -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +# then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +# else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +# fi + source='$<' object='$@' libtool=no \ + depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' \ + $(CCDEPMODE) $(depcomp) \ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +# if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +# -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +# then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +# else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +# fi + source='$<' object='$@' libtool=no \ + depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' \ + $(CCDEPMODE) $(depcomp) \ + $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` +uninstall-info-am: + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(HEADERS) all-local + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(bindir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS install-binSCRIPTS \ + install-exec-local + +install-info: install-info-am + +install-man: + +installcheck-am: installcheck-binPROGRAMS installcheck-binSCRIPTS + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ + uninstall-info-am uninstall-local + +.PHONY: CTAGS GTAGS all all-am all-local check check-am clean \ + clean-binPROGRAMS clean-generic ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-binPROGRAMS install-binSCRIPTS install-data \ + install-data-am install-exec install-exec-am install-exec-local \ + install-info install-info-am install-man install-strip \ + installcheck installcheck-am installcheck-binPROGRAMS \ + installcheck-binSCRIPTS installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-binSCRIPTS \ + uninstall-info-am uninstall-local + + +$(PROGRAMS): ../lib/libfetish.a + +$(SCRIPTS): Makefile + +.sh: + rm -f $@ $@-t + sed \ + -e 's!@''bindir''@!$(bindir)!' \ + -e 's/@''GNU_PACKAGE''@/GNU coreutils/' \ + -e 's/@''PACKAGE_BUGREPORT''@/bug-coreutils@gnu.org/' \ + -e 's/@''VERSION''@/5.0/' $< > $@-t + chmod +x $@-t + mv $@-t $@ + +all-local: su$(EXEEXT) + +install-root: su$(EXEEXT) + @$(INSTALL_SU) + +install-exec-local: su$(EXEEXT) + @TMPFILE=$(DESTDIR)$(bindir)/.su-$$$$; \ + rm -f $$TMPFILE; \ + echo > $$TMPFILE; \ + can_create_suid_root_executable=no; \ + chown root $$TMPFILE > /dev/null 2>&1 \ + && chmod $(setuid_root_mode) $$TMPFILE > /dev/null 2>&1 \ + && can_create_suid_root_executable=yes; \ + rm -f $$TMPFILE; \ + if test $$can_create_suid_root_executable = yes; then \ + $(INSTALL_SU); \ + else \ + echo "WARNING: insufficient access; not installing su"; \ + echo "NOTE: to install su, run 'make install-root' as root"; \ + fi + +uninstall-local: +# Remove su only if it's one we installed. + @if grep 'GNU coreutils' $(installed_su) > /dev/null 2>&1; then \ + echo " rm -f $(installed_su)"; \ + rm -f $(installed_su); \ + else :; fi + +dircolors.h: dcgen dircolors.hin + $(PERL) -w -- $(srcdir)/dcgen $(srcdir)/dircolors.hin > $@-t + mv $@-t $@ + +wheel-size.h: Makefile.am + echo '#define WHEEL_SIZE $(wheel_size)' > $@-t + mv $@-t $@ + +wheel.h: wheel-gen.pl Makefile.am + $(srcdir)/wheel-gen.pl $(wheel_size) \ + > $@-t + mv $@-t $@ + +false.c: true.c + rm -f $@ + sed \ + -e s/true/false/g \ + -e s/success/failure/g \ + -e 's/(EXIT_SUCCESS)/(EXIT_FAILURE)/g' \ + $(srcdir)/true.c > $@-t + chmod a-w $@-t + mv $@-t $@ +# Ensure that the list of programs in README matches the list +# of programs we can build. +check: check-README check-misc +.PHONY: check-README +check-README: + rm -rf $(pr) $(pm) + echo $(all_programs) \ + | tr -s ' ' '\n' | sort -u > $(pm) + sed -n '/^The programs .* are:/,/^[a-zA-Z]/p' $(top_srcdir)/README \ + | sed -n '/^ */s///p' | tr -s ' ' '\n' > $(pr) + diff $(pm) $(pr) && rm -rf $(pr) $(pm) + +# Make sure we don't define any S_IS* macros in src/*.c files. +# Not a big deal, but they're already defined via system.h. +# +# Also make sure we don't use st_blocks. Use ST_NBLOCKS instead. +# This is a bit of a kludge, since it prevents use of the string +# even in comments, but for now it does the job with no false positives. +.PHONY: check-misc +check-misc: + cd $(srcdir); grep '^# *define *S_IS' $(SOURCES) && exit 1 || : + cd $(srcdir); grep st_blocks $(SOURCES) && exit 1 || : + cd $(srcdir); grep '^# *define .*defined' $(SOURCES) && exit 1 || : +# FIXME: handle *.sh; and use $(all_programs), not $(SOURCES) +../AUTHORS: $(SOURCES) + rm -f $@-t + ( \ + set -e; \ + echo "Here are the names of the programs in this package,"; \ + echo "each followed by the name(s) of its author(s)."; \ + echo; \ + for i in $(SOURCES); do \ + a=`sed -n $(s1) $$i`; \ + test "$$a" && : \ + || a=`sed -n $(s2) $$i`; \ + if test "$$a"; then \ + prog=`echo $$i|sed 's/\.c$$//'`; \ + echo "$$prog: $$a"; \ + fi; \ + done | sort -u ) > $@-t + chmod a-w $@-t + mv $@-t $@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/apps/bin/coreutils-5.0/src/Makefile.am b/src/apps/bin/coreutils-5.0/src/Makefile.am new file mode 100644 index 0000000000..815980e179 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/Makefile.am @@ -0,0 +1,242 @@ +## Process this file with automake to produce Makefile.in -*-Makefile-*- + +EXTRA_PROGRAMS = chroot df hostid nice pinky stty su uname uptime users who +EXTRA_SCRIPTS = nohup + +bin_SCRIPTS = groups @OPTIONAL_BIN_ZCRIPTS@ +bin_PROGRAMS = chgrp chown chmod cp dd dircolors du \ + ginstall link ln dir vdir ls mkdir \ + mkfifo mknod mv readlink rm rmdir shred stat sync touch unlink \ + cat cksum comm csplit cut expand fmt fold head join md5sum \ + nl od paste pr ptx sha1sum sort split sum tac tail tr tsort unexpand uniq wc \ + basename date dirname echo env expr factor false \ + hostname id kill logname pathchk printenv printf pwd seq sleep tee \ + test true tty whoami yes \ + @OPTIONAL_BIN_PROGS@ @DF_PROG@ + +localedir = $(datadir)/locale + +noinst_HEADERS = \ + system.h sys2.h checksum.h copy.h cp-hash.h ls.h dircolors.h remove.h \ + chown-core.h fs.h \ + wheel.h wheel-size.h +EXTRA_DIST = dcgen dircolors.hin tac-pipe.c \ + groups.sh nohup.sh wheel-gen.pl +CLEANFILES = $(SCRIPTS) su + +INCLUDES = -I.. -I$(srcdir) -I$(top_srcdir)/lib -I../lib +DEFS = -DLOCALEDIR=\"$(localedir)\" -DSHAREDIR=\"$(datadir)\" @DEFS@ + +# Sometimes, the expansion of @LIBINTL@ includes -lc which may +# include modules defining variables like `optind', so libfetish.a +# must precede @LIBINTL@ in order to ensure we use GNU getopt. +# But libfetish.a must also follow @LIBINTL@, since libintl uses +# replacement functions defined in libfetish.a. +LDADD = ../lib/libfetish.a @LIBINTL@ ../lib/libfetish.a + +dir_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@ +ls_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@ +shred_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@ +vdir_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@ + +## If necessary, add -lm to resolve use of pow in lib/strtod.c. +sort_LDADD = $(LDADD) @POW_LIB@ + +# for clock_gettime +date_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@ + +# For sqrt +factor_LDADD = $(LDADD) @SQRT_LIBM@ + +# If necessary, add -lm to resolve use of pow in lib/strtod.c. +# If necessary, add -liconv to resolve use of iconv in lib/unicodeio.c. +printf_LDADD = $(LDADD) @POW_LIB@ @LIBICONV@ + +# If necessary, add -lm to resolve use of floor, rint, modf. +seq_LDADD = $(LDADD) @SEQ_LIBM@ + +# If necessary, add -lm to resolve the `pow' reference in lib/strtod.c +# or for the fesetround reference in programs using nanosec.c. +nanosec_libs = \ + $(LDADD) @FESETROUND_LIBM@ @POW_LIB@ @LIB_CLOCK_GETTIME@ @LIB_NANOSLEEP@ + +sleep_LDADD = $(nanosec_libs) +tail_LDADD = $(nanosec_libs) + +uptime_LDADD = $(LDADD) @GETLOADAVG_LIBS@ + +su_LDADD = $(LDADD) @LIB_CRYPT@ + +$(PROGRAMS): ../lib/libfetish.a + +$(SCRIPTS): Makefile + +SUFFIXES = .sh + +.sh: + rm -f $@ $@-t + sed \ + -e 's!@''bindir''@!$(bindir)!' \ + -e 's/@''GNU_PACKAGE''@/@GNU_PACKAGE@/' \ + -e 's/@''PACKAGE_BUGREPORT''@/@PACKAGE_BUGREPORT@/' \ + -e 's/@''VERSION''@/@VERSION@/' $< > $@-t + chmod +x $@-t + mv $@-t $@ + +all-local: su$(EXEEXT) + +installed_su = $(DESTDIR)$(bindir)/`echo su|sed '$(transform)'` + +setuid_root_mode = a=rx,u+s + +INSTALL_SU = \ + p=su; \ + echo " $(INSTALL_PROGRAM) $$p $(installed_su)"; \ + $(INSTALL_PROGRAM) $$p $(installed_su); \ + echo " chown root $(installed_su)"; \ + chown root $(installed_su); \ + echo " chmod $(setuid_root_mode) $(installed_su)"; \ + chmod $(setuid_root_mode) $(installed_su) + +install-root: su$(EXEEXT) + @$(INSTALL_SU) + +install-exec-local: su$(EXEEXT) + @TMPFILE=$(DESTDIR)$(bindir)/.su-$$$$; \ + rm -f $$TMPFILE; \ + echo > $$TMPFILE; \ +## See if we can create a setuid root executable in $(bindir). +## If not, then don't even try to install su. + can_create_suid_root_executable=no; \ + chown root $$TMPFILE > /dev/null 2>&1 \ + && chmod $(setuid_root_mode) $$TMPFILE > /dev/null 2>&1 \ + && can_create_suid_root_executable=yes; \ + rm -f $$TMPFILE; \ + if test $$can_create_suid_root_executable = yes; then \ + $(INSTALL_SU); \ + else \ + echo "WARNING: insufficient access; not installing su"; \ + echo "NOTE: to install su, run 'make install-root' as root"; \ + fi + +uninstall-local: +# Remove su only if it's one we installed. + @if grep '@GNU_PACKAGE@' $(installed_su) > /dev/null 2>&1; then \ + echo " rm -f $(installed_su)"; \ + rm -f $(installed_su); \ + else :; fi + +# Use `ginstall' in the definition of PROGRAMS and in dependencies to avoid +# confusion with the `install' target. The install rule transforms `ginstall' +# to install before applying any user-specified name transformations. + +transform = s/ginstall/install/; @program_transform_name@ +ginstall_SOURCES = install.c copy.c cp-hash.c + +cp_SOURCES = cp.c copy.c cp-hash.c +dir_SOURCES = ls.c ls-dir.c +vdir_SOURCES = ls.c ls-vdir.c +ls_SOURCES = ls.c ls-ls.c +chown_SOURCES = chown.c chown-core.c +chgrp_SOURCES = chgrp.c chown-core.c + +mv_SOURCES = mv.c copy.c cp-hash.c remove.c +rm_SOURCES = rm.c remove.c + +md5sum_SOURCES = md5sum.c md5.c +sha1sum_SOURCES = md5sum.c sha1sum.c + +PERL = @PERL@ +editpl = sed -e 's,@''PERL''@,$(PERL),g' + +MAINTAINERCLEANFILES = dircolors.h \ + wheel.h wheel-size.h + +dircolors.h: dcgen dircolors.hin + $(PERL) -w -- $(srcdir)/dcgen $(srcdir)/dircolors.hin > $@-t + mv $@-t $@ + +wheel_size = 5 + +wheel-size.h: Makefile.am + echo '#define WHEEL_SIZE $(wheel_size)' > $@-t + mv $@-t $@ + +wheel.h: wheel-gen.pl Makefile.am + $(srcdir)/wheel-gen.pl $(wheel_size) \ + > $@-t + mv $@-t $@ + +BUILT_SOURCES = dircolors.h false.c wheel.h wheel-size.h + +# false exits nonzero even with --help or --version. +# Tell automake to exempt it from that installcheck test. +AM_INSTALLCHECK_STD_OPTIONS_EXEMPT = false + +false.c: true.c + rm -f $@ + sed \ + -e s/true/false/g \ + -e s/success/failure/g \ + -e 's/(EXIT_SUCCESS)/(EXIT_FAILURE)/g' \ + $(srcdir)/true.c > $@-t + chmod a-w $@-t + mv $@-t $@ + +all_programs = \ + $(bin_PROGRAMS) \ + $(bin_SCRIPTS) \ + $(EXTRA_PROGRAMS) \ + $(EXTRA_SCRIPTS) + +pm = progs-makefile +pr = progs-readme +# Ensure that the list of programs in README matches the list +# of programs we can build. +check: check-README check-misc +.PHONY: check-README +check-README: + rm -rf $(pr) $(pm) + echo $(all_programs) \ + | tr -s ' ' '\n' | sort -u > $(pm) + sed -n '/^The programs .* are:/,/^[a-zA-Z]/p' $(top_srcdir)/README \ + | sed -n '/^ */s///p' | tr -s ' ' '\n' > $(pr) + diff $(pm) $(pr) && rm -rf $(pr) $(pm) + +# Make sure we don't define any S_IS* macros in src/*.c files. +# Not a big deal, but they're already defined via system.h. +# +# Also make sure we don't use st_blocks. Use ST_NBLOCKS instead. +# This is a bit of a kludge, since it prevents use of the string +# even in comments, but for now it does the job with no false positives. +.PHONY: check-misc +check-misc: + cd $(srcdir); grep '^# *define *S_IS' $(SOURCES) && exit 1 || : + cd $(srcdir); grep st_blocks $(SOURCES) && exit 1 || : + cd $(srcdir); grep '^# *define .*defined' $(SOURCES) && exit 1 || : + +# Extract the list of authors from each file. +sed_filter = s/^ *//;s/N_ (//;s/^"//;s/")*$$// +# Sometimes the string is on the same line as the #define... +s1 = '/^\#define AUTHORS \([^\\]\)/{;s//\1/;$(sed_filter);p;q;}' +# Sometimes the string is on the backslash-continued line after the #define. +s2 = '/^\#define AUTHORS \\\\/{;n;$(sed_filter);p;q;}' +# FIXME: handle *.sh; and use $(all_programs), not $(SOURCES) +../AUTHORS: $(SOURCES) + rm -f $@-t + ( \ + set -e; \ + echo "Here are the names of the programs in this package,"; \ + echo "each followed by the name(s) of its author(s)."; \ + echo; \ + for i in $(SOURCES); do \ + a=`sed -n $(s1) $$i`; \ + test "$$a" && : \ + || a=`sed -n $(s2) $$i`; \ + if test "$$a"; then \ + prog=`echo $$i|sed 's/\.c$$//'`; \ + echo "$$prog: $$a"; \ + fi; \ + done | sort -u ) > $@-t + chmod a-w $@-t + mv $@-t $@ diff --git a/src/apps/bin/coreutils-5.0/src/Makefile.in b/src/apps/bin/coreutils-5.0/src/Makefile.in new file mode 100644 index 0000000000..c9154c67dc --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/Makefile.in @@ -0,0 +1,1575 @@ +# Makefile.in generated by automake 1.7.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_triplet = @host@ + + +# Use `ginstall' in the definition of PROGRAMS and in dependencies to avoid +# confusion with the `install' target. The install rule transforms `ginstall' +# to install before applying any user-specified name transformations. +transform = s/ginstall/install/; @program_transform_name@ +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = -DLOCALEDIR=\"$(localedir)\" -DSHAREDIR=\"$(datadir)\" @DEFS@ +DEPDIR = @DEPDIR@ +DF_PROG = @DF_PROG@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FESETROUND_LIBM = @FESETROUND_LIBM@ +GETLOADAVG_LIBS = @GETLOADAVG_LIBS@ +GLIBC21 = @GLIBC21@ +GMSGFMT = @GMSGFMT@ +GNU_PACKAGE = @GNU_PACKAGE@ +HELP2MAN = @HELP2MAN@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +KMEM_GROUP = @KMEM_GROUP@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ +LIB_CRYPT = @LIB_CRYPT@ +LIB_NANOSLEEP = @LIB_NANOSLEEP@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MAN = @MAN@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGMERGE = @MSGMERGE@ +NEED_SETGID = @NEED_SETGID@ +OBJEXT = @OBJEXT@ +OPTIONAL_BIN_PROGS = @OPTIONAL_BIN_PROGS@ +OPTIONAL_BIN_ZCRIPTS = @OPTIONAL_BIN_ZCRIPTS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ + +PERL = @PERL@ +POSUB = @POSUB@ +POW_LIB = @POW_LIB@ +RANLIB = @RANLIB@ +SEQ_LIBM = @SEQ_LIBM@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQRT_LIBM = @SQRT_LIBM@ +STRIP = @STRIP@ +U = @U@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ + +EXTRA_PROGRAMS = chroot df hostid nice pinky stty su uname uptime users who +EXTRA_SCRIPTS = nohup + +bin_SCRIPTS = groups @OPTIONAL_BIN_ZCRIPTS@ +bin_PROGRAMS = chgrp chown chmod cp dd dircolors du \ + ginstall link ln dir vdir ls mkdir \ + mkfifo mknod mv readlink rm rmdir shred stat sync touch unlink \ + cat cksum comm csplit cut expand fmt fold head join md5sum \ + nl od paste pr ptx sha1sum sort split sum tac tail tr tsort unexpand uniq wc \ + basename date dirname echo env expr factor false \ + hostname id kill logname pathchk printenv printf pwd seq sleep tee \ + test true tty whoami yes \ + @OPTIONAL_BIN_PROGS@ @DF_PROG@ + + +localedir = $(datadir)/locale + +noinst_HEADERS = \ + system.h sys2.h checksum.h copy.h cp-hash.h ls.h dircolors.h remove.h \ + chown-core.h fs.h \ + wheel.h wheel-size.h + +EXTRA_DIST = dcgen dircolors.hin tac-pipe.c \ + groups.sh nohup.sh wheel-gen.pl + +CLEANFILES = $(SCRIPTS) su + +INCLUDES = -I.. -I$(srcdir) -I$(top_srcdir)/lib -I../lib + +# Sometimes, the expansion of @LIBINTL@ includes -lc which may +# include modules defining variables like `optind', so libfetish.a +# must precede @LIBINTL@ in order to ensure we use GNU getopt. +# But libfetish.a must also follow @LIBINTL@, since libintl uses +# replacement functions defined in libfetish.a. +LDADD = ../lib/libfetish.a @LIBINTL@ ../lib/libfetish.a + +dir_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@ +ls_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@ +shred_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@ +vdir_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@ + +sort_LDADD = $(LDADD) @POW_LIB@ + +# for clock_gettime +date_LDADD = $(LDADD) @LIB_CLOCK_GETTIME@ + +# For sqrt +factor_LDADD = $(LDADD) @SQRT_LIBM@ + +# If necessary, add -lm to resolve use of pow in lib/strtod.c. +# If necessary, add -liconv to resolve use of iconv in lib/unicodeio.c. +printf_LDADD = $(LDADD) @POW_LIB@ @LIBICONV@ + +# If necessary, add -lm to resolve use of floor, rint, modf. +seq_LDADD = $(LDADD) @SEQ_LIBM@ + +# If necessary, add -lm to resolve the `pow' reference in lib/strtod.c +# or for the fesetround reference in programs using nanosec.c. +nanosec_libs = \ + $(LDADD) @FESETROUND_LIBM@ @POW_LIB@ @LIB_CLOCK_GETTIME@ @LIB_NANOSLEEP@ + + +sleep_LDADD = $(nanosec_libs) +tail_LDADD = $(nanosec_libs) + +uptime_LDADD = $(LDADD) @GETLOADAVG_LIBS@ + +su_LDADD = $(LDADD) @LIB_CRYPT@ + +SUFFIXES = .sh + +installed_su = $(DESTDIR)$(bindir)/`echo su|sed '$(transform)'` + +setuid_root_mode = a=rx,u+s + +INSTALL_SU = \ + p=su; \ + echo " $(INSTALL_PROGRAM) $$p $(installed_su)"; \ + $(INSTALL_PROGRAM) $$p $(installed_su); \ + echo " chown root $(installed_su)"; \ + chown root $(installed_su); \ + echo " chmod $(setuid_root_mode) $(installed_su)"; \ + chmod $(setuid_root_mode) $(installed_su) + +ginstall_SOURCES = install.c copy.c cp-hash.c + +cp_SOURCES = cp.c copy.c cp-hash.c +dir_SOURCES = ls.c ls-dir.c +vdir_SOURCES = ls.c ls-vdir.c +ls_SOURCES = ls.c ls-ls.c +chown_SOURCES = chown.c chown-core.c +chgrp_SOURCES = chgrp.c chown-core.c + +mv_SOURCES = mv.c copy.c cp-hash.c remove.c +rm_SOURCES = rm.c remove.c + +md5sum_SOURCES = md5sum.c md5.c +sha1sum_SOURCES = md5sum.c sha1sum.c +editpl = sed -e 's,@''PERL''@,$(PERL),g' + +MAINTAINERCLEANFILES = dircolors.h \ + wheel.h wheel-size.h + + +wheel_size = 5 + +BUILT_SOURCES = dircolors.h false.c wheel.h wheel-size.h + +# false exits nonzero even with --help or --version. +# Tell automake to exempt it from that installcheck test. +AM_INSTALLCHECK_STD_OPTIONS_EXEMPT = false + +all_programs = \ + $(bin_PROGRAMS) \ + $(bin_SCRIPTS) \ + $(EXTRA_PROGRAMS) \ + $(EXTRA_SCRIPTS) + + +pm = progs-makefile +pr = progs-readme + +# Extract the list of authors from each file. +sed_filter = s/^ *//;s/N_ (//;s/^"//;s/")*$$// +# Sometimes the string is on the same line as the #define... +s1 = '/^\#define AUTHORS \([^\\]\)/{;s//\1/;$(sed_filter);p;q;}' +# Sometimes the string is on the backslash-continued line after the #define. +s2 = '/^\#define AUTHORS \\\\/{;n;$(sed_filter);p;q;}' +subdir = src +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +EXTRA_PROGRAMS = chroot$(EXEEXT) df$(EXEEXT) hostid$(EXEEXT) \ + nice$(EXEEXT) pinky$(EXEEXT) stty$(EXEEXT) su$(EXEEXT) \ + uname$(EXEEXT) uptime$(EXEEXT) users$(EXEEXT) who$(EXEEXT) +bin_PROGRAMS = chgrp$(EXEEXT) chown$(EXEEXT) chmod$(EXEEXT) cp$(EXEEXT) \ + dd$(EXEEXT) dircolors$(EXEEXT) du$(EXEEXT) ginstall$(EXEEXT) \ + link$(EXEEXT) ln$(EXEEXT) dir$(EXEEXT) vdir$(EXEEXT) \ + ls$(EXEEXT) mkdir$(EXEEXT) mkfifo$(EXEEXT) mknod$(EXEEXT) \ + mv$(EXEEXT) readlink$(EXEEXT) rm$(EXEEXT) rmdir$(EXEEXT) \ + shred$(EXEEXT) stat$(EXEEXT) sync$(EXEEXT) touch$(EXEEXT) \ + unlink$(EXEEXT) cat$(EXEEXT) cksum$(EXEEXT) comm$(EXEEXT) \ + csplit$(EXEEXT) cut$(EXEEXT) expand$(EXEEXT) fmt$(EXEEXT) \ + fold$(EXEEXT) head$(EXEEXT) join$(EXEEXT) md5sum$(EXEEXT) \ + nl$(EXEEXT) od$(EXEEXT) paste$(EXEEXT) pr$(EXEEXT) ptx$(EXEEXT) \ + sha1sum$(EXEEXT) sort$(EXEEXT) split$(EXEEXT) sum$(EXEEXT) \ + tac$(EXEEXT) tail$(EXEEXT) tr$(EXEEXT) tsort$(EXEEXT) \ + unexpand$(EXEEXT) uniq$(EXEEXT) wc$(EXEEXT) basename$(EXEEXT) \ + date$(EXEEXT) dirname$(EXEEXT) echo$(EXEEXT) env$(EXEEXT) \ + expr$(EXEEXT) factor$(EXEEXT) false$(EXEEXT) hostname$(EXEEXT) \ + id$(EXEEXT) kill$(EXEEXT) logname$(EXEEXT) pathchk$(EXEEXT) \ + printenv$(EXEEXT) printf$(EXEEXT) pwd$(EXEEXT) seq$(EXEEXT) \ + sleep$(EXEEXT) tee$(EXEEXT) test$(EXEEXT) true$(EXEEXT) \ + tty$(EXEEXT) whoami$(EXEEXT) yes$(EXEEXT) @OPTIONAL_BIN_PROGS@ \ + @DF_PROG@ +PROGRAMS = $(bin_PROGRAMS) + +basename_SOURCES = basename.c +basename_OBJECTS = basename.$(OBJEXT) +basename_LDADD = $(LDADD) +basename_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +basename_LDFLAGS = +cat_SOURCES = cat.c +cat_OBJECTS = cat.$(OBJEXT) +cat_LDADD = $(LDADD) +cat_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +cat_LDFLAGS = +am_chgrp_OBJECTS = chgrp.$(OBJEXT) chown-core.$(OBJEXT) +chgrp_OBJECTS = $(am_chgrp_OBJECTS) +chgrp_LDADD = $(LDADD) +chgrp_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +chgrp_LDFLAGS = +chmod_SOURCES = chmod.c +chmod_OBJECTS = chmod.$(OBJEXT) +chmod_LDADD = $(LDADD) +chmod_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +chmod_LDFLAGS = +am_chown_OBJECTS = chown.$(OBJEXT) chown-core.$(OBJEXT) +chown_OBJECTS = $(am_chown_OBJECTS) +chown_LDADD = $(LDADD) +chown_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +chown_LDFLAGS = +chroot_SOURCES = chroot.c +chroot_OBJECTS = chroot.$(OBJEXT) +chroot_LDADD = $(LDADD) +chroot_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +chroot_LDFLAGS = +cksum_SOURCES = cksum.c +cksum_OBJECTS = cksum.$(OBJEXT) +cksum_LDADD = $(LDADD) +cksum_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +cksum_LDFLAGS = +comm_SOURCES = comm.c +comm_OBJECTS = comm.$(OBJEXT) +comm_LDADD = $(LDADD) +comm_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +comm_LDFLAGS = +am_cp_OBJECTS = cp.$(OBJEXT) copy.$(OBJEXT) cp-hash.$(OBJEXT) +cp_OBJECTS = $(am_cp_OBJECTS) +cp_LDADD = $(LDADD) +cp_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +cp_LDFLAGS = +csplit_SOURCES = csplit.c +csplit_OBJECTS = csplit.$(OBJEXT) +csplit_LDADD = $(LDADD) +csplit_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +csplit_LDFLAGS = +cut_SOURCES = cut.c +cut_OBJECTS = cut.$(OBJEXT) +cut_LDADD = $(LDADD) +cut_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +cut_LDFLAGS = +date_SOURCES = date.c +date_OBJECTS = date.$(OBJEXT) +date_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +date_LDFLAGS = +dd_SOURCES = dd.c +dd_OBJECTS = dd.$(OBJEXT) +dd_LDADD = $(LDADD) +dd_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +dd_LDFLAGS = +df_SOURCES = df.c +df_OBJECTS = df.$(OBJEXT) +df_LDADD = $(LDADD) +df_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +df_LDFLAGS = +am_dir_OBJECTS = ls.$(OBJEXT) ls-dir.$(OBJEXT) +dir_OBJECTS = $(am_dir_OBJECTS) +dir_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +dir_LDFLAGS = +dircolors_SOURCES = dircolors.c +dircolors_OBJECTS = dircolors.$(OBJEXT) +dircolors_LDADD = $(LDADD) +dircolors_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +dircolors_LDFLAGS = +dirname_SOURCES = dirname.c +dirname_OBJECTS = dirname.$(OBJEXT) +dirname_LDADD = $(LDADD) +dirname_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +dirname_LDFLAGS = +du_SOURCES = du.c +du_OBJECTS = du.$(OBJEXT) +du_LDADD = $(LDADD) +du_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +du_LDFLAGS = +echo_SOURCES = echo.c +echo_OBJECTS = echo.$(OBJEXT) +echo_LDADD = $(LDADD) +echo_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +echo_LDFLAGS = +env_SOURCES = env.c +env_OBJECTS = env.$(OBJEXT) +env_LDADD = $(LDADD) +env_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +env_LDFLAGS = +expand_SOURCES = expand.c +expand_OBJECTS = expand.$(OBJEXT) +expand_LDADD = $(LDADD) +expand_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +expand_LDFLAGS = +expr_SOURCES = expr.c +expr_OBJECTS = expr.$(OBJEXT) +expr_LDADD = $(LDADD) +expr_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +expr_LDFLAGS = +factor_SOURCES = factor.c +factor_OBJECTS = factor.$(OBJEXT) +factor_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +factor_LDFLAGS = +false_SOURCES = false.c +false_OBJECTS = false.$(OBJEXT) +false_LDADD = $(LDADD) +false_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +false_LDFLAGS = +fmt_SOURCES = fmt.c +fmt_OBJECTS = fmt.$(OBJEXT) +fmt_LDADD = $(LDADD) +fmt_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +fmt_LDFLAGS = +fold_SOURCES = fold.c +fold_OBJECTS = fold.$(OBJEXT) +fold_LDADD = $(LDADD) +fold_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +fold_LDFLAGS = +am_ginstall_OBJECTS = install.$(OBJEXT) copy.$(OBJEXT) cp-hash.$(OBJEXT) +ginstall_OBJECTS = $(am_ginstall_OBJECTS) +ginstall_LDADD = $(LDADD) +ginstall_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +ginstall_LDFLAGS = +head_SOURCES = head.c +head_OBJECTS = head.$(OBJEXT) +head_LDADD = $(LDADD) +head_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +head_LDFLAGS = +hostid_SOURCES = hostid.c +hostid_OBJECTS = hostid.$(OBJEXT) +hostid_LDADD = $(LDADD) +hostid_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +hostid_LDFLAGS = +hostname_SOURCES = hostname.c +hostname_OBJECTS = hostname.$(OBJEXT) +hostname_LDADD = $(LDADD) +hostname_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +hostname_LDFLAGS = +id_SOURCES = id.c +id_OBJECTS = id.$(OBJEXT) +id_LDADD = $(LDADD) +id_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +id_LDFLAGS = +join_SOURCES = join.c +join_OBJECTS = join.$(OBJEXT) +join_LDADD = $(LDADD) +join_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +join_LDFLAGS = +kill_SOURCES = kill.c +kill_OBJECTS = kill.$(OBJEXT) +kill_LDADD = $(LDADD) +kill_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +kill_LDFLAGS = +link_SOURCES = link.c +link_OBJECTS = link.$(OBJEXT) +link_LDADD = $(LDADD) +link_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +link_LDFLAGS = +ln_SOURCES = ln.c +ln_OBJECTS = ln.$(OBJEXT) +ln_LDADD = $(LDADD) +ln_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +ln_LDFLAGS = +logname_SOURCES = logname.c +logname_OBJECTS = logname.$(OBJEXT) +logname_LDADD = $(LDADD) +logname_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +logname_LDFLAGS = +am_ls_OBJECTS = ls.$(OBJEXT) ls-ls.$(OBJEXT) +ls_OBJECTS = $(am_ls_OBJECTS) +ls_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +ls_LDFLAGS = +am_md5sum_OBJECTS = md5sum.$(OBJEXT) md5.$(OBJEXT) +md5sum_OBJECTS = $(am_md5sum_OBJECTS) +md5sum_LDADD = $(LDADD) +md5sum_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +md5sum_LDFLAGS = +mkdir_SOURCES = mkdir.c +mkdir_OBJECTS = mkdir.$(OBJEXT) +mkdir_LDADD = $(LDADD) +mkdir_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +mkdir_LDFLAGS = +mkfifo_SOURCES = mkfifo.c +mkfifo_OBJECTS = mkfifo.$(OBJEXT) +mkfifo_LDADD = $(LDADD) +mkfifo_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +mkfifo_LDFLAGS = +mknod_SOURCES = mknod.c +mknod_OBJECTS = mknod.$(OBJEXT) +mknod_LDADD = $(LDADD) +mknod_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +mknod_LDFLAGS = +am_mv_OBJECTS = mv.$(OBJEXT) copy.$(OBJEXT) cp-hash.$(OBJEXT) \ + remove.$(OBJEXT) +mv_OBJECTS = $(am_mv_OBJECTS) +mv_LDADD = $(LDADD) +mv_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +mv_LDFLAGS = +nice_SOURCES = nice.c +nice_OBJECTS = nice.$(OBJEXT) +nice_LDADD = $(LDADD) +nice_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +nice_LDFLAGS = +nl_SOURCES = nl.c +nl_OBJECTS = nl.$(OBJEXT) +nl_LDADD = $(LDADD) +nl_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +nl_LDFLAGS = +od_SOURCES = od.c +od_OBJECTS = od.$(OBJEXT) +od_LDADD = $(LDADD) +od_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +od_LDFLAGS = +paste_SOURCES = paste.c +paste_OBJECTS = paste.$(OBJEXT) +paste_LDADD = $(LDADD) +paste_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +paste_LDFLAGS = +pathchk_SOURCES = pathchk.c +pathchk_OBJECTS = pathchk.$(OBJEXT) +pathchk_LDADD = $(LDADD) +pathchk_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +pathchk_LDFLAGS = +pinky_SOURCES = pinky.c +pinky_OBJECTS = pinky.$(OBJEXT) +pinky_LDADD = $(LDADD) +pinky_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +pinky_LDFLAGS = +pr_SOURCES = pr.c +pr_OBJECTS = pr.$(OBJEXT) +pr_LDADD = $(LDADD) +pr_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +pr_LDFLAGS = +printenv_SOURCES = printenv.c +printenv_OBJECTS = printenv.$(OBJEXT) +printenv_LDADD = $(LDADD) +printenv_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +printenv_LDFLAGS = +printf_SOURCES = printf.c +printf_OBJECTS = printf.$(OBJEXT) +printf_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +printf_LDFLAGS = +ptx_SOURCES = ptx.c +ptx_OBJECTS = ptx.$(OBJEXT) +ptx_LDADD = $(LDADD) +ptx_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +ptx_LDFLAGS = +pwd_SOURCES = pwd.c +pwd_OBJECTS = pwd.$(OBJEXT) +pwd_LDADD = $(LDADD) +pwd_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +pwd_LDFLAGS = +readlink_SOURCES = readlink.c +readlink_OBJECTS = readlink.$(OBJEXT) +readlink_LDADD = $(LDADD) +readlink_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +readlink_LDFLAGS = +am_rm_OBJECTS = rm.$(OBJEXT) remove.$(OBJEXT) +rm_OBJECTS = $(am_rm_OBJECTS) +rm_LDADD = $(LDADD) +rm_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +rm_LDFLAGS = +rmdir_SOURCES = rmdir.c +rmdir_OBJECTS = rmdir.$(OBJEXT) +rmdir_LDADD = $(LDADD) +rmdir_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +rmdir_LDFLAGS = +seq_SOURCES = seq.c +seq_OBJECTS = seq.$(OBJEXT) +seq_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +seq_LDFLAGS = +am_sha1sum_OBJECTS = md5sum.$(OBJEXT) sha1sum.$(OBJEXT) +sha1sum_OBJECTS = $(am_sha1sum_OBJECTS) +sha1sum_LDADD = $(LDADD) +sha1sum_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +sha1sum_LDFLAGS = +shred_SOURCES = shred.c +shred_OBJECTS = shred.$(OBJEXT) +shred_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +shred_LDFLAGS = +sleep_SOURCES = sleep.c +sleep_OBJECTS = sleep.$(OBJEXT) +sleep_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +sleep_LDFLAGS = +sort_SOURCES = sort.c +sort_OBJECTS = sort.$(OBJEXT) +sort_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +sort_LDFLAGS = +split_SOURCES = split.c +split_OBJECTS = split.$(OBJEXT) +split_LDADD = $(LDADD) +split_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +split_LDFLAGS = +stat_SOURCES = stat.c +stat_OBJECTS = stat.$(OBJEXT) +stat_LDADD = $(LDADD) +stat_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +stat_LDFLAGS = +stty_SOURCES = stty.c +stty_OBJECTS = stty.$(OBJEXT) +stty_LDADD = $(LDADD) +stty_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +stty_LDFLAGS = +su_SOURCES = su.c +su_OBJECTS = su.$(OBJEXT) +su_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +su_LDFLAGS = +sum_SOURCES = sum.c +sum_OBJECTS = sum.$(OBJEXT) +sum_LDADD = $(LDADD) +sum_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +sum_LDFLAGS = +sync_SOURCES = sync.c +sync_OBJECTS = sync.$(OBJEXT) +sync_LDADD = $(LDADD) +sync_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +sync_LDFLAGS = +tac_SOURCES = tac.c +tac_OBJECTS = tac.$(OBJEXT) +tac_LDADD = $(LDADD) +tac_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +tac_LDFLAGS = +tail_SOURCES = tail.c +tail_OBJECTS = tail.$(OBJEXT) +tail_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +tail_LDFLAGS = +tee_SOURCES = tee.c +tee_OBJECTS = tee.$(OBJEXT) +tee_LDADD = $(LDADD) +tee_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +tee_LDFLAGS = +test_SOURCES = test.c +test_OBJECTS = test.$(OBJEXT) +test_LDADD = $(LDADD) +test_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +test_LDFLAGS = +touch_SOURCES = touch.c +touch_OBJECTS = touch.$(OBJEXT) +touch_LDADD = $(LDADD) +touch_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +touch_LDFLAGS = +tr_SOURCES = tr.c +tr_OBJECTS = tr.$(OBJEXT) +tr_LDADD = $(LDADD) +tr_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +tr_LDFLAGS = +true_SOURCES = true.c +true_OBJECTS = true.$(OBJEXT) +true_LDADD = $(LDADD) +true_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +true_LDFLAGS = +tsort_SOURCES = tsort.c +tsort_OBJECTS = tsort.$(OBJEXT) +tsort_LDADD = $(LDADD) +tsort_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +tsort_LDFLAGS = +tty_SOURCES = tty.c +tty_OBJECTS = tty.$(OBJEXT) +tty_LDADD = $(LDADD) +tty_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +tty_LDFLAGS = +uname_SOURCES = uname.c +uname_OBJECTS = uname.$(OBJEXT) +uname_LDADD = $(LDADD) +uname_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +uname_LDFLAGS = +unexpand_SOURCES = unexpand.c +unexpand_OBJECTS = unexpand.$(OBJEXT) +unexpand_LDADD = $(LDADD) +unexpand_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +unexpand_LDFLAGS = +uniq_SOURCES = uniq.c +uniq_OBJECTS = uniq.$(OBJEXT) +uniq_LDADD = $(LDADD) +uniq_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +uniq_LDFLAGS = +unlink_SOURCES = unlink.c +unlink_OBJECTS = unlink.$(OBJEXT) +unlink_LDADD = $(LDADD) +unlink_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +unlink_LDFLAGS = +uptime_SOURCES = uptime.c +uptime_OBJECTS = uptime.$(OBJEXT) +uptime_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +uptime_LDFLAGS = +users_SOURCES = users.c +users_OBJECTS = users.$(OBJEXT) +users_LDADD = $(LDADD) +users_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +users_LDFLAGS = +am_vdir_OBJECTS = ls.$(OBJEXT) ls-vdir.$(OBJEXT) +vdir_OBJECTS = $(am_vdir_OBJECTS) +vdir_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +vdir_LDFLAGS = +wc_SOURCES = wc.c +wc_OBJECTS = wc.$(OBJEXT) +wc_LDADD = $(LDADD) +wc_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +wc_LDFLAGS = +who_SOURCES = who.c +who_OBJECTS = who.$(OBJEXT) +who_LDADD = $(LDADD) +who_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +who_LDFLAGS = +whoami_SOURCES = whoami.c +whoami_OBJECTS = whoami.$(OBJEXT) +whoami_LDADD = $(LDADD) +whoami_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +whoami_LDFLAGS = +yes_SOURCES = yes.c +yes_OBJECTS = yes.$(OBJEXT) +yes_LDADD = $(LDADD) +yes_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +yes_LDFLAGS = +SCRIPTS = $(bin_SCRIPTS) + + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/basename.Po ./$(DEPDIR)/cat.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/chgrp.Po ./$(DEPDIR)/chmod.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/chown-core.Po ./$(DEPDIR)/chown.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/chroot.Po ./$(DEPDIR)/cksum.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/comm.Po ./$(DEPDIR)/copy.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/cp-hash.Po ./$(DEPDIR)/cp.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/csplit.Po ./$(DEPDIR)/cut.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/date.Po ./$(DEPDIR)/dd.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/df.Po ./$(DEPDIR)/dircolors.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/dirname.Po ./$(DEPDIR)/du.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/echo.Po ./$(DEPDIR)/env.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/expand.Po ./$(DEPDIR)/expr.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/factor.Po ./$(DEPDIR)/false.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/fmt.Po ./$(DEPDIR)/fold.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/head.Po ./$(DEPDIR)/hostid.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/hostname.Po ./$(DEPDIR)/id.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/install.Po ./$(DEPDIR)/join.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/kill.Po ./$(DEPDIR)/link.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ln.Po ./$(DEPDIR)/logname.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ls-dir.Po ./$(DEPDIR)/ls-ls.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ls-vdir.Po ./$(DEPDIR)/ls.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/md5.Po ./$(DEPDIR)/md5sum.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/mkdir.Po ./$(DEPDIR)/mkfifo.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/mknod.Po ./$(DEPDIR)/mv.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/nice.Po ./$(DEPDIR)/nl.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/od.Po ./$(DEPDIR)/paste.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/pathchk.Po ./$(DEPDIR)/pinky.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/pr.Po ./$(DEPDIR)/printenv.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/printf.Po ./$(DEPDIR)/ptx.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/pwd.Po ./$(DEPDIR)/readlink.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/remove.Po ./$(DEPDIR)/rm.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/rmdir.Po ./$(DEPDIR)/seq.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/sha1sum.Po ./$(DEPDIR)/shred.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/sleep.Po ./$(DEPDIR)/sort.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/split.Po ./$(DEPDIR)/stat.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/stty.Po ./$(DEPDIR)/su.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/sum.Po ./$(DEPDIR)/sync.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/tac.Po ./$(DEPDIR)/tail.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/tee.Po ./$(DEPDIR)/test.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/touch.Po ./$(DEPDIR)/tr.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/true.Po ./$(DEPDIR)/tsort.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/tty.Po ./$(DEPDIR)/uname.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/unexpand.Po ./$(DEPDIR)/uniq.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/unlink.Po ./$(DEPDIR)/uptime.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/users.Po ./$(DEPDIR)/wc.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/who.Po ./$(DEPDIR)/whoami.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/yes.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = basename.c cat.c $(chgrp_SOURCES) chmod.c \ + $(chown_SOURCES) chroot.c cksum.c comm.c $(cp_SOURCES) csplit.c \ + cut.c date.c dd.c df.c $(dir_SOURCES) dircolors.c dirname.c \ + du.c echo.c env.c expand.c expr.c factor.c false.c fmt.c fold.c \ + $(ginstall_SOURCES) head.c hostid.c hostname.c id.c join.c \ + kill.c link.c ln.c logname.c $(ls_SOURCES) $(md5sum_SOURCES) \ + mkdir.c mkfifo.c mknod.c $(mv_SOURCES) nice.c nl.c od.c paste.c \ + pathchk.c pinky.c pr.c printenv.c printf.c ptx.c pwd.c \ + readlink.c $(rm_SOURCES) rmdir.c seq.c $(sha1sum_SOURCES) \ + shred.c sleep.c sort.c split.c stat.c stty.c su.c sum.c sync.c \ + tac.c tail.c tee.c test.c touch.c tr.c true.c tsort.c tty.c \ + uname.c unexpand.c uniq.c unlink.c uptime.c users.c \ + $(vdir_SOURCES) wc.c who.c whoami.c yes.c +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = $(noinst_HEADERS) Makefile.am Makefile.in +SOURCES = basename.c cat.c $(chgrp_SOURCES) chmod.c $(chown_SOURCES) chroot.c cksum.c comm.c $(cp_SOURCES) csplit.c cut.c date.c dd.c df.c $(dir_SOURCES) dircolors.c dirname.c du.c echo.c env.c expand.c expr.c factor.c false.c fmt.c fold.c $(ginstall_SOURCES) head.c hostid.c hostname.c id.c join.c kill.c link.c ln.c logname.c $(ls_SOURCES) $(md5sum_SOURCES) mkdir.c mkfifo.c mknod.c $(mv_SOURCES) nice.c nl.c od.c paste.c pathchk.c pinky.c pr.c printenv.c printf.c ptx.c pwd.c readlink.c $(rm_SOURCES) rmdir.c seq.c $(sha1sum_SOURCES) shred.c sleep.c sort.c split.c stat.c stty.c su.c sum.c sync.c tac.c tail.c tee.c test.c touch.c tr.c true.c tsort.c tty.c uname.c unexpand.c uniq.c unlink.c uptime.c users.c $(vdir_SOURCES) wc.c who.c whoami.c yes.c + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .sh .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnits src/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) > /dev/null 2>&1 || /bin/rm -f $(bin_PROGRAMS) + +installcheck-binPROGRAMS: $(bin_PROGRAMS) + bad=0; pid=$$$$; list="$(bin_PROGRAMS)"; for p in $$list; do \ + case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \ + *" $$p "* | *" $(srcdir)/$$p "*) continue;; \ + esac; \ + f=`echo "$$p" | \ + sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + for opt in --help --version; do \ + if $(DESTDIR)$(bindir)/$$f $$opt > c$${pid}_.out 2> c$${pid}_.err \ + && test -n "`cat c$${pid}_.out`" \ + && test -z "`cat c$${pid}_.err`"; then :; \ + else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \ + done; \ + done; rm -f c$${pid}_.???; exit $$bad +basename$(EXEEXT): $(basename_OBJECTS) $(basename_DEPENDENCIES) + @rm -f basename$(EXEEXT) + $(LINK) $(basename_LDFLAGS) $(basename_OBJECTS) $(basename_LDADD) $(LIBS) +cat$(EXEEXT): $(cat_OBJECTS) $(cat_DEPENDENCIES) + @rm -f cat$(EXEEXT) + $(LINK) $(cat_LDFLAGS) $(cat_OBJECTS) $(cat_LDADD) $(LIBS) +chgrp$(EXEEXT): $(chgrp_OBJECTS) $(chgrp_DEPENDENCIES) + @rm -f chgrp$(EXEEXT) + $(LINK) $(chgrp_LDFLAGS) $(chgrp_OBJECTS) $(chgrp_LDADD) $(LIBS) +chmod$(EXEEXT): $(chmod_OBJECTS) $(chmod_DEPENDENCIES) + @rm -f chmod$(EXEEXT) + $(LINK) $(chmod_LDFLAGS) $(chmod_OBJECTS) $(chmod_LDADD) $(LIBS) +chown$(EXEEXT): $(chown_OBJECTS) $(chown_DEPENDENCIES) + @rm -f chown$(EXEEXT) + $(LINK) $(chown_LDFLAGS) $(chown_OBJECTS) $(chown_LDADD) $(LIBS) +chroot$(EXEEXT): $(chroot_OBJECTS) $(chroot_DEPENDENCIES) + @rm -f chroot$(EXEEXT) + $(LINK) $(chroot_LDFLAGS) $(chroot_OBJECTS) $(chroot_LDADD) $(LIBS) +cksum$(EXEEXT): $(cksum_OBJECTS) $(cksum_DEPENDENCIES) + @rm -f cksum$(EXEEXT) + $(LINK) $(cksum_LDFLAGS) $(cksum_OBJECTS) $(cksum_LDADD) $(LIBS) +comm$(EXEEXT): $(comm_OBJECTS) $(comm_DEPENDENCIES) + @rm -f comm$(EXEEXT) + $(LINK) $(comm_LDFLAGS) $(comm_OBJECTS) $(comm_LDADD) $(LIBS) +cp$(EXEEXT): $(cp_OBJECTS) $(cp_DEPENDENCIES) + @rm -f cp$(EXEEXT) + $(LINK) $(cp_LDFLAGS) $(cp_OBJECTS) $(cp_LDADD) $(LIBS) +csplit$(EXEEXT): $(csplit_OBJECTS) $(csplit_DEPENDENCIES) + @rm -f csplit$(EXEEXT) + $(LINK) $(csplit_LDFLAGS) $(csplit_OBJECTS) $(csplit_LDADD) $(LIBS) +cut$(EXEEXT): $(cut_OBJECTS) $(cut_DEPENDENCIES) + @rm -f cut$(EXEEXT) + $(LINK) $(cut_LDFLAGS) $(cut_OBJECTS) $(cut_LDADD) $(LIBS) +date$(EXEEXT): $(date_OBJECTS) $(date_DEPENDENCIES) + @rm -f date$(EXEEXT) + $(LINK) $(date_LDFLAGS) $(date_OBJECTS) $(date_LDADD) $(LIBS) +dd$(EXEEXT): $(dd_OBJECTS) $(dd_DEPENDENCIES) + @rm -f dd$(EXEEXT) + $(LINK) $(dd_LDFLAGS) $(dd_OBJECTS) $(dd_LDADD) $(LIBS) +df$(EXEEXT): $(df_OBJECTS) $(df_DEPENDENCIES) + @rm -f df$(EXEEXT) + $(LINK) $(df_LDFLAGS) $(df_OBJECTS) $(df_LDADD) $(LIBS) +dir$(EXEEXT): $(dir_OBJECTS) $(dir_DEPENDENCIES) + @rm -f dir$(EXEEXT) + $(LINK) $(dir_LDFLAGS) $(dir_OBJECTS) $(dir_LDADD) $(LIBS) +dircolors$(EXEEXT): $(dircolors_OBJECTS) $(dircolors_DEPENDENCIES) + @rm -f dircolors$(EXEEXT) + $(LINK) $(dircolors_LDFLAGS) $(dircolors_OBJECTS) $(dircolors_LDADD) $(LIBS) +dirname$(EXEEXT): $(dirname_OBJECTS) $(dirname_DEPENDENCIES) + @rm -f dirname$(EXEEXT) + $(LINK) $(dirname_LDFLAGS) $(dirname_OBJECTS) $(dirname_LDADD) $(LIBS) +du$(EXEEXT): $(du_OBJECTS) $(du_DEPENDENCIES) + @rm -f du$(EXEEXT) + $(LINK) $(du_LDFLAGS) $(du_OBJECTS) $(du_LDADD) $(LIBS) +echo$(EXEEXT): $(echo_OBJECTS) $(echo_DEPENDENCIES) + @rm -f echo$(EXEEXT) + $(LINK) $(echo_LDFLAGS) $(echo_OBJECTS) $(echo_LDADD) $(LIBS) +env$(EXEEXT): $(env_OBJECTS) $(env_DEPENDENCIES) + @rm -f env$(EXEEXT) + $(LINK) $(env_LDFLAGS) $(env_OBJECTS) $(env_LDADD) $(LIBS) +expand$(EXEEXT): $(expand_OBJECTS) $(expand_DEPENDENCIES) + @rm -f expand$(EXEEXT) + $(LINK) $(expand_LDFLAGS) $(expand_OBJECTS) $(expand_LDADD) $(LIBS) +expr$(EXEEXT): $(expr_OBJECTS) $(expr_DEPENDENCIES) + @rm -f expr$(EXEEXT) + $(LINK) $(expr_LDFLAGS) $(expr_OBJECTS) $(expr_LDADD) $(LIBS) +factor$(EXEEXT): $(factor_OBJECTS) $(factor_DEPENDENCIES) + @rm -f factor$(EXEEXT) + $(LINK) $(factor_LDFLAGS) $(factor_OBJECTS) $(factor_LDADD) $(LIBS) +false$(EXEEXT): $(false_OBJECTS) $(false_DEPENDENCIES) + @rm -f false$(EXEEXT) + $(LINK) $(false_LDFLAGS) $(false_OBJECTS) $(false_LDADD) $(LIBS) +fmt$(EXEEXT): $(fmt_OBJECTS) $(fmt_DEPENDENCIES) + @rm -f fmt$(EXEEXT) + $(LINK) $(fmt_LDFLAGS) $(fmt_OBJECTS) $(fmt_LDADD) $(LIBS) +fold$(EXEEXT): $(fold_OBJECTS) $(fold_DEPENDENCIES) + @rm -f fold$(EXEEXT) + $(LINK) $(fold_LDFLAGS) $(fold_OBJECTS) $(fold_LDADD) $(LIBS) +ginstall$(EXEEXT): $(ginstall_OBJECTS) $(ginstall_DEPENDENCIES) + @rm -f ginstall$(EXEEXT) + $(LINK) $(ginstall_LDFLAGS) $(ginstall_OBJECTS) $(ginstall_LDADD) $(LIBS) +head$(EXEEXT): $(head_OBJECTS) $(head_DEPENDENCIES) + @rm -f head$(EXEEXT) + $(LINK) $(head_LDFLAGS) $(head_OBJECTS) $(head_LDADD) $(LIBS) +hostid$(EXEEXT): $(hostid_OBJECTS) $(hostid_DEPENDENCIES) + @rm -f hostid$(EXEEXT) + $(LINK) $(hostid_LDFLAGS) $(hostid_OBJECTS) $(hostid_LDADD) $(LIBS) +hostname$(EXEEXT): $(hostname_OBJECTS) $(hostname_DEPENDENCIES) + @rm -f hostname$(EXEEXT) + $(LINK) $(hostname_LDFLAGS) $(hostname_OBJECTS) $(hostname_LDADD) $(LIBS) +id$(EXEEXT): $(id_OBJECTS) $(id_DEPENDENCIES) + @rm -f id$(EXEEXT) + $(LINK) $(id_LDFLAGS) $(id_OBJECTS) $(id_LDADD) $(LIBS) +join$(EXEEXT): $(join_OBJECTS) $(join_DEPENDENCIES) + @rm -f join$(EXEEXT) + $(LINK) $(join_LDFLAGS) $(join_OBJECTS) $(join_LDADD) $(LIBS) +kill$(EXEEXT): $(kill_OBJECTS) $(kill_DEPENDENCIES) + @rm -f kill$(EXEEXT) + $(LINK) $(kill_LDFLAGS) $(kill_OBJECTS) $(kill_LDADD) $(LIBS) +link$(EXEEXT): $(link_OBJECTS) $(link_DEPENDENCIES) + @rm -f link$(EXEEXT) + $(LINK) $(link_LDFLAGS) $(link_OBJECTS) $(link_LDADD) $(LIBS) +ln$(EXEEXT): $(ln_OBJECTS) $(ln_DEPENDENCIES) + @rm -f ln$(EXEEXT) + $(LINK) $(ln_LDFLAGS) $(ln_OBJECTS) $(ln_LDADD) $(LIBS) +logname$(EXEEXT): $(logname_OBJECTS) $(logname_DEPENDENCIES) + @rm -f logname$(EXEEXT) + $(LINK) $(logname_LDFLAGS) $(logname_OBJECTS) $(logname_LDADD) $(LIBS) +ls$(EXEEXT): $(ls_OBJECTS) $(ls_DEPENDENCIES) + @rm -f ls$(EXEEXT) + $(LINK) $(ls_LDFLAGS) $(ls_OBJECTS) $(ls_LDADD) $(LIBS) +md5sum$(EXEEXT): $(md5sum_OBJECTS) $(md5sum_DEPENDENCIES) + @rm -f md5sum$(EXEEXT) + $(LINK) $(md5sum_LDFLAGS) $(md5sum_OBJECTS) $(md5sum_LDADD) $(LIBS) +mkdir$(EXEEXT): $(mkdir_OBJECTS) $(mkdir_DEPENDENCIES) + @rm -f mkdir$(EXEEXT) + $(LINK) $(mkdir_LDFLAGS) $(mkdir_OBJECTS) $(mkdir_LDADD) $(LIBS) +mkfifo$(EXEEXT): $(mkfifo_OBJECTS) $(mkfifo_DEPENDENCIES) + @rm -f mkfifo$(EXEEXT) + $(LINK) $(mkfifo_LDFLAGS) $(mkfifo_OBJECTS) $(mkfifo_LDADD) $(LIBS) +mknod$(EXEEXT): $(mknod_OBJECTS) $(mknod_DEPENDENCIES) + @rm -f mknod$(EXEEXT) + $(LINK) $(mknod_LDFLAGS) $(mknod_OBJECTS) $(mknod_LDADD) $(LIBS) +mv$(EXEEXT): $(mv_OBJECTS) $(mv_DEPENDENCIES) + @rm -f mv$(EXEEXT) + $(LINK) $(mv_LDFLAGS) $(mv_OBJECTS) $(mv_LDADD) $(LIBS) +nice$(EXEEXT): $(nice_OBJECTS) $(nice_DEPENDENCIES) + @rm -f nice$(EXEEXT) + $(LINK) $(nice_LDFLAGS) $(nice_OBJECTS) $(nice_LDADD) $(LIBS) +nl$(EXEEXT): $(nl_OBJECTS) $(nl_DEPENDENCIES) + @rm -f nl$(EXEEXT) + $(LINK) $(nl_LDFLAGS) $(nl_OBJECTS) $(nl_LDADD) $(LIBS) +od$(EXEEXT): $(od_OBJECTS) $(od_DEPENDENCIES) + @rm -f od$(EXEEXT) + $(LINK) $(od_LDFLAGS) $(od_OBJECTS) $(od_LDADD) $(LIBS) +paste$(EXEEXT): $(paste_OBJECTS) $(paste_DEPENDENCIES) + @rm -f paste$(EXEEXT) + $(LINK) $(paste_LDFLAGS) $(paste_OBJECTS) $(paste_LDADD) $(LIBS) +pathchk$(EXEEXT): $(pathchk_OBJECTS) $(pathchk_DEPENDENCIES) + @rm -f pathchk$(EXEEXT) + $(LINK) $(pathchk_LDFLAGS) $(pathchk_OBJECTS) $(pathchk_LDADD) $(LIBS) +pinky$(EXEEXT): $(pinky_OBJECTS) $(pinky_DEPENDENCIES) + @rm -f pinky$(EXEEXT) + $(LINK) $(pinky_LDFLAGS) $(pinky_OBJECTS) $(pinky_LDADD) $(LIBS) +pr$(EXEEXT): $(pr_OBJECTS) $(pr_DEPENDENCIES) + @rm -f pr$(EXEEXT) + $(LINK) $(pr_LDFLAGS) $(pr_OBJECTS) $(pr_LDADD) $(LIBS) +printenv$(EXEEXT): $(printenv_OBJECTS) $(printenv_DEPENDENCIES) + @rm -f printenv$(EXEEXT) + $(LINK) $(printenv_LDFLAGS) $(printenv_OBJECTS) $(printenv_LDADD) $(LIBS) +printf$(EXEEXT): $(printf_OBJECTS) $(printf_DEPENDENCIES) + @rm -f printf$(EXEEXT) + $(LINK) $(printf_LDFLAGS) $(printf_OBJECTS) $(printf_LDADD) $(LIBS) +ptx$(EXEEXT): $(ptx_OBJECTS) $(ptx_DEPENDENCIES) + @rm -f ptx$(EXEEXT) + $(LINK) $(ptx_LDFLAGS) $(ptx_OBJECTS) $(ptx_LDADD) $(LIBS) +pwd$(EXEEXT): $(pwd_OBJECTS) $(pwd_DEPENDENCIES) + @rm -f pwd$(EXEEXT) + $(LINK) $(pwd_LDFLAGS) $(pwd_OBJECTS) $(pwd_LDADD) $(LIBS) +readlink$(EXEEXT): $(readlink_OBJECTS) $(readlink_DEPENDENCIES) + @rm -f readlink$(EXEEXT) + $(LINK) $(readlink_LDFLAGS) $(readlink_OBJECTS) $(readlink_LDADD) $(LIBS) +rm$(EXEEXT): $(rm_OBJECTS) $(rm_DEPENDENCIES) + @rm -f rm$(EXEEXT) + $(LINK) $(rm_LDFLAGS) $(rm_OBJECTS) $(rm_LDADD) $(LIBS) +rmdir$(EXEEXT): $(rmdir_OBJECTS) $(rmdir_DEPENDENCIES) + @rm -f rmdir$(EXEEXT) + $(LINK) $(rmdir_LDFLAGS) $(rmdir_OBJECTS) $(rmdir_LDADD) $(LIBS) +seq$(EXEEXT): $(seq_OBJECTS) $(seq_DEPENDENCIES) + @rm -f seq$(EXEEXT) + $(LINK) $(seq_LDFLAGS) $(seq_OBJECTS) $(seq_LDADD) $(LIBS) +sha1sum$(EXEEXT): $(sha1sum_OBJECTS) $(sha1sum_DEPENDENCIES) + @rm -f sha1sum$(EXEEXT) + $(LINK) $(sha1sum_LDFLAGS) $(sha1sum_OBJECTS) $(sha1sum_LDADD) $(LIBS) +shred$(EXEEXT): $(shred_OBJECTS) $(shred_DEPENDENCIES) + @rm -f shred$(EXEEXT) + $(LINK) $(shred_LDFLAGS) $(shred_OBJECTS) $(shred_LDADD) $(LIBS) +sleep$(EXEEXT): $(sleep_OBJECTS) $(sleep_DEPENDENCIES) + @rm -f sleep$(EXEEXT) + $(LINK) $(sleep_LDFLAGS) $(sleep_OBJECTS) $(sleep_LDADD) $(LIBS) +sort$(EXEEXT): $(sort_OBJECTS) $(sort_DEPENDENCIES) + @rm -f sort$(EXEEXT) + $(LINK) $(sort_LDFLAGS) $(sort_OBJECTS) $(sort_LDADD) $(LIBS) +split$(EXEEXT): $(split_OBJECTS) $(split_DEPENDENCIES) + @rm -f split$(EXEEXT) + $(LINK) $(split_LDFLAGS) $(split_OBJECTS) $(split_LDADD) $(LIBS) +stat$(EXEEXT): $(stat_OBJECTS) $(stat_DEPENDENCIES) + @rm -f stat$(EXEEXT) + $(LINK) $(stat_LDFLAGS) $(stat_OBJECTS) $(stat_LDADD) $(LIBS) +stty$(EXEEXT): $(stty_OBJECTS) $(stty_DEPENDENCIES) + @rm -f stty$(EXEEXT) + $(LINK) $(stty_LDFLAGS) $(stty_OBJECTS) $(stty_LDADD) $(LIBS) +su$(EXEEXT): $(su_OBJECTS) $(su_DEPENDENCIES) + @rm -f su$(EXEEXT) + $(LINK) $(su_LDFLAGS) $(su_OBJECTS) $(su_LDADD) $(LIBS) +sum$(EXEEXT): $(sum_OBJECTS) $(sum_DEPENDENCIES) + @rm -f sum$(EXEEXT) + $(LINK) $(sum_LDFLAGS) $(sum_OBJECTS) $(sum_LDADD) $(LIBS) +sync$(EXEEXT): $(sync_OBJECTS) $(sync_DEPENDENCIES) + @rm -f sync$(EXEEXT) + $(LINK) $(sync_LDFLAGS) $(sync_OBJECTS) $(sync_LDADD) $(LIBS) +tac$(EXEEXT): $(tac_OBJECTS) $(tac_DEPENDENCIES) + @rm -f tac$(EXEEXT) + $(LINK) $(tac_LDFLAGS) $(tac_OBJECTS) $(tac_LDADD) $(LIBS) +tail$(EXEEXT): $(tail_OBJECTS) $(tail_DEPENDENCIES) + @rm -f tail$(EXEEXT) + $(LINK) $(tail_LDFLAGS) $(tail_OBJECTS) $(tail_LDADD) $(LIBS) +tee$(EXEEXT): $(tee_OBJECTS) $(tee_DEPENDENCIES) + @rm -f tee$(EXEEXT) + $(LINK) $(tee_LDFLAGS) $(tee_OBJECTS) $(tee_LDADD) $(LIBS) +test$(EXEEXT): $(test_OBJECTS) $(test_DEPENDENCIES) + @rm -f test$(EXEEXT) + $(LINK) $(test_LDFLAGS) $(test_OBJECTS) $(test_LDADD) $(LIBS) +touch$(EXEEXT): $(touch_OBJECTS) $(touch_DEPENDENCIES) + @rm -f touch$(EXEEXT) + $(LINK) $(touch_LDFLAGS) $(touch_OBJECTS) $(touch_LDADD) $(LIBS) +tr$(EXEEXT): $(tr_OBJECTS) $(tr_DEPENDENCIES) + @rm -f tr$(EXEEXT) + $(LINK) $(tr_LDFLAGS) $(tr_OBJECTS) $(tr_LDADD) $(LIBS) +true$(EXEEXT): $(true_OBJECTS) $(true_DEPENDENCIES) + @rm -f true$(EXEEXT) + $(LINK) $(true_LDFLAGS) $(true_OBJECTS) $(true_LDADD) $(LIBS) +tsort$(EXEEXT): $(tsort_OBJECTS) $(tsort_DEPENDENCIES) + @rm -f tsort$(EXEEXT) + $(LINK) $(tsort_LDFLAGS) $(tsort_OBJECTS) $(tsort_LDADD) $(LIBS) +tty$(EXEEXT): $(tty_OBJECTS) $(tty_DEPENDENCIES) + @rm -f tty$(EXEEXT) + $(LINK) $(tty_LDFLAGS) $(tty_OBJECTS) $(tty_LDADD) $(LIBS) +uname$(EXEEXT): $(uname_OBJECTS) $(uname_DEPENDENCIES) + @rm -f uname$(EXEEXT) + $(LINK) $(uname_LDFLAGS) $(uname_OBJECTS) $(uname_LDADD) $(LIBS) +unexpand$(EXEEXT): $(unexpand_OBJECTS) $(unexpand_DEPENDENCIES) + @rm -f unexpand$(EXEEXT) + $(LINK) $(unexpand_LDFLAGS) $(unexpand_OBJECTS) $(unexpand_LDADD) $(LIBS) +uniq$(EXEEXT): $(uniq_OBJECTS) $(uniq_DEPENDENCIES) + @rm -f uniq$(EXEEXT) + $(LINK) $(uniq_LDFLAGS) $(uniq_OBJECTS) $(uniq_LDADD) $(LIBS) +unlink$(EXEEXT): $(unlink_OBJECTS) $(unlink_DEPENDENCIES) + @rm -f unlink$(EXEEXT) + $(LINK) $(unlink_LDFLAGS) $(unlink_OBJECTS) $(unlink_LDADD) $(LIBS) +uptime$(EXEEXT): $(uptime_OBJECTS) $(uptime_DEPENDENCIES) + @rm -f uptime$(EXEEXT) + $(LINK) $(uptime_LDFLAGS) $(uptime_OBJECTS) $(uptime_LDADD) $(LIBS) +users$(EXEEXT): $(users_OBJECTS) $(users_DEPENDENCIES) + @rm -f users$(EXEEXT) + $(LINK) $(users_LDFLAGS) $(users_OBJECTS) $(users_LDADD) $(LIBS) +vdir$(EXEEXT): $(vdir_OBJECTS) $(vdir_DEPENDENCIES) + @rm -f vdir$(EXEEXT) + $(LINK) $(vdir_LDFLAGS) $(vdir_OBJECTS) $(vdir_LDADD) $(LIBS) +wc$(EXEEXT): $(wc_OBJECTS) $(wc_DEPENDENCIES) + @rm -f wc$(EXEEXT) + $(LINK) $(wc_LDFLAGS) $(wc_OBJECTS) $(wc_LDADD) $(LIBS) +who$(EXEEXT): $(who_OBJECTS) $(who_DEPENDENCIES) + @rm -f who$(EXEEXT) + $(LINK) $(who_LDFLAGS) $(who_OBJECTS) $(who_LDADD) $(LIBS) +whoami$(EXEEXT): $(whoami_OBJECTS) $(whoami_DEPENDENCIES) + @rm -f whoami$(EXEEXT) + $(LINK) $(whoami_LDFLAGS) $(whoami_OBJECTS) $(whoami_LDADD) $(LIBS) +yes$(EXEEXT): $(yes_OBJECTS) $(yes_DEPENDENCIES) + @rm -f yes$(EXEEXT) + $(LINK) $(yes_LDFLAGS) $(yes_OBJECTS) $(yes_LDADD) $(LIBS) +binSCRIPT_INSTALL = $(INSTALL_SCRIPT) +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f $$d$$p; then \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " $(binSCRIPT_INSTALL) $$d$$p $(DESTDIR)$(bindir)/$$f"; \ + $(binSCRIPT_INSTALL) $$d$$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done + +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +installcheck-binSCRIPTS: $(bin_SCRIPTS) + bad=0; pid=$$$$; list="$(bin_SCRIPTS)"; for p in $$list; do \ + case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \ + *" $$p "* | *" $(srcdir)/$$p "*) continue;; \ + esac; \ + f=`echo "$$p" | sed 's,^.*/,,;$(transform)'`; \ + for opt in --help --version; do \ + if $(DESTDIR)$(bindir)/$$f $$opt > c$${pid}_.out 2> c$${pid}_.err \ + && test -n "`cat c$${pid}_.out`" \ + && test -z "`cat c$${pid}_.err`"; then :; \ + else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \ + done; \ + done; rm -f c$${pid}_.???; exit $$bad + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basename.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chgrp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chmod.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chown-core.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chown.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chroot.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cksum.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/comm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cp-hash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csplit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cut.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/date.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/df.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dircolors.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirname.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/du.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/echo.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/env.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/expand.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/expr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/factor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/false.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fold.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/head.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hostid.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hostname.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/install.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/join.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kill.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/link.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ln.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logname.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ls-dir.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ls-ls.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ls-vdir.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ls.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5sum.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkdir.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkfifo.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mknod.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nice.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/od.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/paste.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pathchk.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pinky.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/printenv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/printf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ptx.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pwd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readlink.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remove.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rmdir.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1sum.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shred.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sleep.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sort.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/split.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stty.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/su.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sum.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sync.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tac.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tail.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tee.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/touch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/true.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsort.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tty.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uname.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unexpand.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uniq.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unlink.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uptime.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/users.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/who.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/whoami.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yes.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCC_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCC_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` +uninstall-info-am: + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(HEADERS) all-local + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(bindir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS install-binSCRIPTS \ + install-exec-local + +install-info: install-info-am + +install-man: + +installcheck-am: installcheck-binPROGRAMS installcheck-binSCRIPTS + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ + uninstall-info-am uninstall-local + +.PHONY: CTAGS GTAGS all all-am all-local check check-am clean \ + clean-binPROGRAMS clean-generic ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-binPROGRAMS install-binSCRIPTS install-data \ + install-data-am install-exec install-exec-am install-exec-local \ + install-info install-info-am install-man install-strip \ + installcheck installcheck-am installcheck-binPROGRAMS \ + installcheck-binSCRIPTS installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-binSCRIPTS \ + uninstall-info-am uninstall-local + + +$(PROGRAMS): ../lib/libfetish.a + +$(SCRIPTS): Makefile + +.sh: + rm -f $@ $@-t + sed \ + -e 's!@''bindir''@!$(bindir)!' \ + -e 's/@''GNU_PACKAGE''@/@GNU_PACKAGE@/' \ + -e 's/@''PACKAGE_BUGREPORT''@/@PACKAGE_BUGREPORT@/' \ + -e 's/@''VERSION''@/@VERSION@/' $< > $@-t + chmod +x $@-t + mv $@-t $@ + +all-local: su$(EXEEXT) + +install-root: su$(EXEEXT) + @$(INSTALL_SU) + +install-exec-local: su$(EXEEXT) + @TMPFILE=$(DESTDIR)$(bindir)/.su-$$$$; \ + rm -f $$TMPFILE; \ + echo > $$TMPFILE; \ + can_create_suid_root_executable=no; \ + chown root $$TMPFILE > /dev/null 2>&1 \ + && chmod $(setuid_root_mode) $$TMPFILE > /dev/null 2>&1 \ + && can_create_suid_root_executable=yes; \ + rm -f $$TMPFILE; \ + if test $$can_create_suid_root_executable = yes; then \ + $(INSTALL_SU); \ + else \ + echo "WARNING: insufficient access; not installing su"; \ + echo "NOTE: to install su, run 'make install-root' as root"; \ + fi + +uninstall-local: +# Remove su only if it's one we installed. + @if grep '@GNU_PACKAGE@' $(installed_su) > /dev/null 2>&1; then \ + echo " rm -f $(installed_su)"; \ + rm -f $(installed_su); \ + else :; fi + +dircolors.h: dcgen dircolors.hin + $(PERL) -w -- $(srcdir)/dcgen $(srcdir)/dircolors.hin > $@-t + mv $@-t $@ + +wheel-size.h: Makefile.am + echo '#define WHEEL_SIZE $(wheel_size)' > $@-t + mv $@-t $@ + +wheel.h: wheel-gen.pl Makefile.am + $(srcdir)/wheel-gen.pl $(wheel_size) \ + > $@-t + mv $@-t $@ + +false.c: true.c + rm -f $@ + sed \ + -e s/true/false/g \ + -e s/success/failure/g \ + -e 's/(EXIT_SUCCESS)/(EXIT_FAILURE)/g' \ + $(srcdir)/true.c > $@-t + chmod a-w $@-t + mv $@-t $@ +# Ensure that the list of programs in README matches the list +# of programs we can build. +check: check-README check-misc +.PHONY: check-README +check-README: + rm -rf $(pr) $(pm) + echo $(all_programs) \ + | tr -s ' ' '\n' | sort -u > $(pm) + sed -n '/^The programs .* are:/,/^[a-zA-Z]/p' $(top_srcdir)/README \ + | sed -n '/^ */s///p' | tr -s ' ' '\n' > $(pr) + diff $(pm) $(pr) && rm -rf $(pr) $(pm) + +# Make sure we don't define any S_IS* macros in src/*.c files. +# Not a big deal, but they're already defined via system.h. +# +# Also make sure we don't use st_blocks. Use ST_NBLOCKS instead. +# This is a bit of a kludge, since it prevents use of the string +# even in comments, but for now it does the job with no false positives. +.PHONY: check-misc +check-misc: + cd $(srcdir); grep '^# *define *S_IS' $(SOURCES) && exit 1 || : + cd $(srcdir); grep st_blocks $(SOURCES) && exit 1 || : + cd $(srcdir); grep '^# *define .*defined' $(SOURCES) && exit 1 || : +# FIXME: handle *.sh; and use $(all_programs), not $(SOURCES) +../AUTHORS: $(SOURCES) + rm -f $@-t + ( \ + set -e; \ + echo "Here are the names of the programs in this package,"; \ + echo "each followed by the name(s) of its author(s)."; \ + echo; \ + for i in $(SOURCES); do \ + a=`sed -n $(s1) $$i`; \ + test "$$a" && : \ + || a=`sed -n $(s2) $$i`; \ + if test "$$a"; then \ + prog=`echo $$i|sed 's/\.c$$//'`; \ + echo "$$prog: $$a"; \ + fi; \ + done | sort -u ) > $@-t + chmod a-w $@-t + mv $@-t $@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/apps/bin/coreutils-5.0/src/Makefile.mod b/src/apps/bin/coreutils-5.0/src/Makefile.mod new file mode 100644 index 0000000000..f9b2fd0f85 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/Makefile.mod @@ -0,0 +1,1212 @@ +# Makefile.in generated by automake 1.7.3 from Makefile.am. +# src/Makefile. Generated from Makefile.in by configure. + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +srcdir = . +top_srcdir = .. + +pkgdatadir = $(datadir)/coreutils +pkglibdir = $(libdir)/coreutils +pkgincludedir = $(includedir)/coreutils +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = /bin/install -c +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_triplet = i586-pc-beos + + +# Use `ginstall' in the definition of PROGRAMS and in dependencies to avoid +# confusion with the `install' target. The install rule transforms `ginstall' +# to install before applying any user-specified name transformations. +transform = s/ginstall/install/; s,x,x, +ACLOCAL = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run aclocal-1.7 +ALLOCA = +AMDEP_FALSE = # +AMDEP_TRUE = +AMTAR = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run tar +AUTOCONF = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run autoconf +AUTOHEADER = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run autoheader +AUTOMAKE = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run automake-1.7 +AWK = gawk +CC = gcc +CCDEPMODE = depmode=gcc +CFLAGS = -g -O2 -pipe +CPP = gcc -E +CPPFLAGS = +CYGPATH_W = echo +DEFS = -DLOCALEDIR=\"$(localedir)\" -DSHAREDIR=\"$(datadir)\" -DHAVE_CONFIG_H +DEPDIR = .deps +DF_PROG = +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = grep -E +EXEEXT = +FESETROUND_LIBM = +GETLOADAVG_LIBS = +GLIBC21 = no +GMSGFMT = : +GNU_PACKAGE = GNU coreutils +HELP2MAN = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run help2man +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s +INTLLIBS = +KMEM_GROUP = +LDFLAGS = +LIBICONV = +LIBINTL = +LIBOBJS = fileblocks$U.o mkdir$U.o fnmatch$U.o strnlen$U.o ftw$U.o tsearch$U.o lchown$U.o chown$U.o mktime$U.o nanosleep$U.o group-member$U.o putenv$U.o error$U.o __fpending$U.o rename$U.o getcwd$U.o canonicalize$U.o regex$U.o getloadavg$U.o getusershell$U.o sig2str$U.o euidaccess$U.o rpmatch$U.o strndup$U.o strverscmp$U.o getpass$U.o memrchr$U.o fchdir-stub$U.o +LIBS = +LIB_CLOCK_GETTIME = +LIB_CRYPT = +LIB_NANOSLEEP = +LN_S = ln -s +LTLIBICONV = +LTLIBINTL = +LTLIBOBJS = fileblocks$U.lo mkdir$U.lo fnmatch$U.lo strnlen$U.lo ftw$U.lo tsearch$U.lo lchown$U.lo chown$U.lo mktime$U.lo nanosleep$U.lo group-member$U.lo putenv$U.lo error$U.lo __fpending$U.lo rename$U.lo getcwd$U.lo canonicalize$U.lo regex$U.lo getloadavg$U.lo getusershell$U.lo sig2str$U.lo euidaccess$U.lo rpmatch$U.lo strndup$U.lo strverscmp$U.lo getpass$U.lo memrchr$U.lo fchdir-stub$U.lo +MAKEINFO = ${SHELL} /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/missing --run makeinfo +MAN = uname.1 stty.1 +MKINSTALLDIRS = config/mkinstalldirs +MSGFMT = : +MSGMERGE = : +NEED_SETGID = false +OBJEXT = o +OPTIONAL_BIN_PROGS = uname$(EXEEXT) stty$(EXEEXT) +OPTIONAL_BIN_ZCRIPTS = +PACKAGE = coreutils +PACKAGE_BUGREPORT = bug-coreutils@gnu.org +PACKAGE_NAME = GNU coreutils +PACKAGE_STRING = GNU coreutils 5.0 +PACKAGE_TARNAME = coreutils +PACKAGE_VERSION = 5.0 +PATH_SEPARATOR = : + +PERL = perl +POSUB = +POW_LIB = +RANLIB = ranlib +SEQ_LIBM = +SET_MAKE = +SHELL = /bin/sh +SQRT_LIBM = +STRIP = +U = +USE_NLS = no +VERSION = 5.0 +XGETTEXT = : +YACC = bison -y +ac_ct_CC = gcc +ac_ct_RANLIB = ranlib +ac_ct_STRIP = +am__fastdepCC_FALSE = +am__fastdepCC_TRUE = # +am__include = include +am__leading_dot = . +am__quote = +bindir = ${exec_prefix}/bin +build = i586-pc-beos +build_alias = +build_cpu = i586 +build_os = beos +build_vendor = pc +datadir = ${prefix}/share +exec_prefix = ${prefix} +host = i586-pc-beos +host_alias = +host_cpu = i586 +host_os = beos +host_vendor = pc +includedir = ${prefix}/include +infodir = ${prefix}/info +install_sh = /boot/home/Development/current/src/apps/bin/coreutils-5.0/config/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localstatedir = ${prefix}/var +mandir = ${prefix}/man +oldincludedir = /usr/include +prefix = /usr/local +program_transform_name = s,x,x, +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +sysconfdir = ${prefix}/etc +target_alias = + +EXTRA_PROGRAMS = chroot df hostid nice pinky stty su uname uptime users who +EXTRA_SCRIPTS = nohup + +bin_SCRIPTS = groups +bin_PROGRAMS = chgrp chown chmod cp dd dircolors du \ + ginstall link ln dir vdir ls mkdir \ + mkfifo mknod mv readlink rm rmdir shred sync touch unlink \ + cat cksum comm csplit cut expand fmt fold head join md5sum \ + nl od paste pr ptx sha1sum sort split sum tac tail tr tsort unexpand uniq wc \ + basename date dirname echo env expr factor false \ + hostname id kill logname pathchk printenv printf pwd seq sleep tee \ + test true tty whoami yes \ + uname$(EXEEXT) stty$(EXEEXT) +# stat + + +localedir = $(datadir)/locale + +noinst_HEADERS = \ + system.h sys2.h checksum.h copy.h cp-hash.h ls.h dircolors.h remove.h \ + chown-core.h fs.h \ + wheel.h wheel-size.h + +EXTRA_DIST = dcgen dircolors.hin tac-pipe.c \ + groups.sh nohup.sh wheel-gen.pl + +CLEANFILES = $(SCRIPTS) su + +INCLUDES = -I.. -I$(srcdir) -I$(top_srcdir)/lib -I../lib + +# Sometimes, the expansion of includes -lc which may +# include modules defining variables like `optind', so libfetish.a +# must precede in order to ensure we use GNU getopt. +# But libfetish.a must also follow , since libintl uses +# replacement functions defined in libfetish.a. +LDADD = ../lib/libfetish.a ../lib/libfetish.a + +dir_LDADD = $(LDADD) +ls_LDADD = $(LDADD) +shred_LDADD = $(LDADD) +vdir_LDADD = $(LDADD) + +sort_LDADD = $(LDADD) + +# for clock_gettime +date_LDADD = $(LDADD) + +# For sqrt +factor_LDADD = $(LDADD) + +# If necessary, add -lm to resolve use of pow in lib/strtod.c. +# If necessary, add -liconv to resolve use of iconv in lib/unicodeio.c. +printf_LDADD = $(LDADD) + +# If necessary, add -lm to resolve use of floor, rint, modf. +seq_LDADD = $(LDADD) + +# If necessary, add -lm to resolve the `pow' reference in lib/strtod.c +# or for the fesetround reference in programs using nanosec.c. +nanosec_libs = \ + $(LDADD) + + +sleep_LDADD = $(nanosec_libs) +tail_LDADD = $(nanosec_libs) + +uptime_LDADD = $(LDADD) + +su_LDADD = $(LDADD) + +SUFFIXES = .sh + +installed_su = $(DESTDIR)$(bindir)/`echo su|sed '$(transform)'` + +setuid_root_mode = a=rx,u+s + +INSTALL_SU = \ + p=su; \ + echo " $(INSTALL_PROGRAM) $$p $(installed_su)"; \ + $(INSTALL_PROGRAM) $$p $(installed_su); \ + echo " chown root $(installed_su)"; \ + chown root $(installed_su); \ + echo " chmod $(setuid_root_mode) $(installed_su)"; \ + chmod $(setuid_root_mode) $(installed_su) + +ginstall_SOURCES = install.c copy.c cp-hash.c + +cp_SOURCES = cp.c copy.c cp-hash.c +dir_SOURCES = ls.c ls-dir.c +vdir_SOURCES = ls.c ls-vdir.c +ls_SOURCES = ls.c ls-ls.c +chown_SOURCES = chown.c chown-core.c +chgrp_SOURCES = chgrp.c chown-core.c + +mv_SOURCES = mv.c copy.c cp-hash.c remove.c +rm_SOURCES = rm.c remove.c + +md5sum_SOURCES = md5sum.c md5.c +sha1sum_SOURCES = md5sum.c sha1sum.c +editpl = sed -e 's,@''PERL''@,$(PERL),g' + +MAINTAINERCLEANFILES = dircolors.h \ + wheel.h wheel-size.h + + +wheel_size = 5 + +BUILT_SOURCES = dircolors.h false.c wheel.h wheel-size.h + +# false exits nonzero even with --help or --version. +# Tell automake to exempt it from that installcheck test. +AM_INSTALLCHECK_STD_OPTIONS_EXEMPT = false + +all_programs = \ + $(bin_PROGRAMS) \ + $(bin_SCRIPTS) \ + $(EXTRA_PROGRAMS) \ + $(EXTRA_SCRIPTS) + + +pm = progs-makefile +pr = progs-readme + +# Extract the list of authors from each file. +sed_filter = s/^ *//;s/N_ (//;s/^"//;s/")*$$// +# Sometimes the string is on the same line as the #define... +s1 = '/^\#define AUTHORS \([^\\]\)/{;s//\1/;$(sed_filter);p;q;}' +# Sometimes the string is on the backslash-continued line after the #define. +s2 = '/^\#define AUTHORS \\\\/{;n;$(sed_filter);p;q;}' +subdir = src +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +EXTRA_PROGRAMS = chroot$(EXEEXT) df$(EXEEXT) hostid$(EXEEXT) \ + nice$(EXEEXT) pinky$(EXEEXT) stty$(EXEEXT) su$(EXEEXT) \ + uname$(EXEEXT) uptime$(EXEEXT) users$(EXEEXT) who$(EXEEXT) +bin_PROGRAMS = chgrp$(EXEEXT) chown$(EXEEXT) chmod$(EXEEXT) cp$(EXEEXT) \ + dd$(EXEEXT) dircolors$(EXEEXT) du$(EXEEXT) ginstall$(EXEEXT) \ + link$(EXEEXT) ln$(EXEEXT) dir$(EXEEXT) vdir$(EXEEXT) \ + ls$(EXEEXT) mkdir$(EXEEXT) mkfifo$(EXEEXT) mknod$(EXEEXT) \ + mv$(EXEEXT) readlink$(EXEEXT) rm$(EXEEXT) rmdir$(EXEEXT) \ + shred$(EXEEXT) sync$(EXEEXT) touch$(EXEEXT) \ + unlink$(EXEEXT) cat$(EXEEXT) cksum$(EXEEXT) comm$(EXEEXT) \ + csplit$(EXEEXT) cut$(EXEEXT) expand$(EXEEXT) fmt$(EXEEXT) \ + fold$(EXEEXT) head$(EXEEXT) join$(EXEEXT) md5sum$(EXEEXT) \ + nl$(EXEEXT) od$(EXEEXT) paste$(EXEEXT) pr$(EXEEXT) ptx$(EXEEXT) \ + sha1sum$(EXEEXT) sort$(EXEEXT) split$(EXEEXT) sum$(EXEEXT) \ + tac$(EXEEXT) tail$(EXEEXT) tr$(EXEEXT) tsort$(EXEEXT) \ + unexpand$(EXEEXT) uniq$(EXEEXT) wc$(EXEEXT) basename$(EXEEXT) \ + date$(EXEEXT) dirname$(EXEEXT) echo$(EXEEXT) env$(EXEEXT) \ + expr$(EXEEXT) factor$(EXEEXT) false$(EXEEXT) hostname$(EXEEXT) \ + id$(EXEEXT) kill$(EXEEXT) logname$(EXEEXT) pathchk$(EXEEXT) \ + printenv$(EXEEXT) printf$(EXEEXT) pwd$(EXEEXT) seq$(EXEEXT) \ + sleep$(EXEEXT) tee$(EXEEXT) test$(EXEEXT) true$(EXEEXT) \ + tty$(EXEEXT) whoami$(EXEEXT) yes$(EXEEXT) uname$(EXEEXT) stty$(EXEEXT) \ + +PROGRAMS = $(bin_PROGRAMS) +# stat$(EXEEXT) + +am_chgrp_OBJECTS = chgrp.$(OBJEXT) chown-core.$(OBJEXT) +chgrp_OBJECTS = $(am_chgrp_OBJECTS) +chgrp_LDADD = $(LDADD) +chgrp_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +chgrp_LDFLAGS = +am_chown_OBJECTS = chown.$(OBJEXT) chown-core.$(OBJEXT) +chown_OBJECTS = $(am_chown_OBJECTS) +chown_LDADD = $(LDADD) +chown_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +chown_LDFLAGS = +am_cp_OBJECTS = cp.$(OBJEXT) copy.$(OBJEXT) cp-hash.$(OBJEXT) +cp_OBJECTS = $(am_cp_OBJECTS) +cp_LDADD = $(LDADD) +cp_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +cp_LDFLAGS = +am_dir_OBJECTS = ls.$(OBJEXT) ls-dir.$(OBJEXT) +dir_OBJECTS = $(am_dir_OBJECTS) +dir_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +dir_LDFLAGS = +am_ginstall_OBJECTS = install.$(OBJEXT) copy.$(OBJEXT) cp-hash.$(OBJEXT) +ginstall_OBJECTS = $(am_ginstall_OBJECTS) +ginstall_LDADD = $(LDADD) +ginstall_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +ginstall_LDFLAGS = +am_ls_OBJECTS = ls.$(OBJEXT) ls-ls.$(OBJEXT) +ls_OBJECTS = $(am_ls_OBJECTS) +ls_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +ls_LDFLAGS = +am_md5sum_OBJECTS = md5sum.$(OBJEXT) md5.$(OBJEXT) +md5sum_OBJECTS = $(am_md5sum_OBJECTS) +md5sum_LDADD = $(LDADD) +md5sum_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +md5sum_LDFLAGS = +am_mv_OBJECTS = mv.$(OBJEXT) copy.$(OBJEXT) cp-hash.$(OBJEXT) \ + remove.$(OBJEXT) +mv_OBJECTS = $(am_mv_OBJECTS) +mv_LDADD = $(LDADD) +mv_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +mv_LDFLAGS = +am_rm_OBJECTS = rm.$(OBJEXT) remove.$(OBJEXT) +rm_OBJECTS = $(am_rm_OBJECTS) +rm_LDADD = $(LDADD) +rm_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +rm_LDFLAGS = +am_sha1sum_OBJECTS = md5sum.$(OBJEXT) sha1sum.$(OBJEXT) +sha1sum_OBJECTS = $(am_sha1sum_OBJECTS) +sha1sum_LDADD = $(LDADD) +sha1sum_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +sha1sum_LDFLAGS = +am_vdir_OBJECTS = ls.$(OBJEXT) ls-vdir.$(OBJEXT) +vdir_OBJECTS = $(am_vdir_OBJECTS) +vdir_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +vdir_LDFLAGS = +yes_SOURCES = yes.c +yes_OBJECTS = yes.$(OBJEXT) +yes_LDADD = $(LDADD) +yes_DEPENDENCIES = ../lib/libfetish.a ../lib/libfetish.a +yes_LDFLAGS = +SCRIPTS = $(bin_SCRIPTS) + + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +DEP_FILES = ./$(DEPDIR)/basename.Po ./$(DEPDIR)/cat.Po \ + ./$(DEPDIR)/chgrp.Po ./$(DEPDIR)/chmod.Po \ + ./$(DEPDIR)/chown-core.Po ./$(DEPDIR)/chown.Po \ + ./$(DEPDIR)/chroot.Po ./$(DEPDIR)/cksum.Po \ + ./$(DEPDIR)/comm.Po ./$(DEPDIR)/copy.Po \ + ./$(DEPDIR)/cp-hash.Po ./$(DEPDIR)/cp.Po \ + ./$(DEPDIR)/csplit.Po ./$(DEPDIR)/cut.Po \ + ./$(DEPDIR)/date.Po ./$(DEPDIR)/dd.Po \ + ./$(DEPDIR)/df.Po ./$(DEPDIR)/dircolors.Po \ + ./$(DEPDIR)/dirname.Po ./$(DEPDIR)/du.Po \ + ./$(DEPDIR)/echo.Po ./$(DEPDIR)/env.Po \ + ./$(DEPDIR)/expand.Po ./$(DEPDIR)/expr.Po \ + ./$(DEPDIR)/factor.Po ./$(DEPDIR)/false.Po \ + ./$(DEPDIR)/fmt.Po ./$(DEPDIR)/fold.Po \ + ./$(DEPDIR)/head.Po ./$(DEPDIR)/hostid.Po \ + ./$(DEPDIR)/hostname.Po ./$(DEPDIR)/id.Po \ + ./$(DEPDIR)/install.Po ./$(DEPDIR)/join.Po \ + ./$(DEPDIR)/kill.Po ./$(DEPDIR)/link.Po \ + ./$(DEPDIR)/ln.Po ./$(DEPDIR)/logname.Po \ + ./$(DEPDIR)/ls-dir.Po ./$(DEPDIR)/ls-ls.Po \ + ./$(DEPDIR)/ls-vdir.Po ./$(DEPDIR)/ls.Po \ + ./$(DEPDIR)/md5.Po ./$(DEPDIR)/md5sum.Po \ + ./$(DEPDIR)/mkdir.Po ./$(DEPDIR)/mkfifo.Po \ + ./$(DEPDIR)/mknod.Po ./$(DEPDIR)/mv.Po \ + ./$(DEPDIR)/nice.Po ./$(DEPDIR)/nl.Po \ + ./$(DEPDIR)/od.Po ./$(DEPDIR)/paste.Po \ + ./$(DEPDIR)/pathchk.Po ./$(DEPDIR)/pinky.Po \ + ./$(DEPDIR)/pr.Po ./$(DEPDIR)/printenv.Po \ + ./$(DEPDIR)/printf.Po ./$(DEPDIR)/ptx.Po \ + ./$(DEPDIR)/pwd.Po ./$(DEPDIR)/readlink.Po \ + ./$(DEPDIR)/remove.Po ./$(DEPDIR)/rm.Po \ + ./$(DEPDIR)/rmdir.Po ./$(DEPDIR)/seq.Po \ + ./$(DEPDIR)/sha1sum.Po ./$(DEPDIR)/shred.Po \ + ./$(DEPDIR)/sleep.Po ./$(DEPDIR)/sort.Po \ + ./$(DEPDIR)/split.Po ./$(DEPDIR)/stat.Po \ + ./$(DEPDIR)/stty.Po ./$(DEPDIR)/su.Po \ + ./$(DEPDIR)/sum.Po ./$(DEPDIR)/sync.Po \ + ./$(DEPDIR)/tac.Po ./$(DEPDIR)/tail.Po \ + ./$(DEPDIR)/tee.Po ./$(DEPDIR)/test.Po \ + ./$(DEPDIR)/touch.Po ./$(DEPDIR)/tr.Po \ + ./$(DEPDIR)/true.Po ./$(DEPDIR)/tsort.Po \ + ./$(DEPDIR)/tty.Po ./$(DEPDIR)/uname.Po \ + ./$(DEPDIR)/unexpand.Po ./$(DEPDIR)/uniq.Po \ + ./$(DEPDIR)/unlink.Po ./$(DEPDIR)/uptime.Po \ + ./$(DEPDIR)/users.Po ./$(DEPDIR)/wc.Po \ + ./$(DEPDIR)/who.Po ./$(DEPDIR)/whoami.Po \ + ./$(DEPDIR)/yes.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = basename.c cat.c $(chgrp_SOURCES) chmod.c \ + $(chown_SOURCES) chroot.c cksum.c comm.c $(cp_SOURCES) csplit.c \ + cut.c date.c dd.c df.c $(dir_SOURCES) dircolors.c dirname.c \ + du.c echo.c env.c expand.c expr.c factor.c false.c fmt.c fold.c \ + $(ginstall_SOURCES) head.c hostid.c hostname.c id.c join.c \ + kill.c link.c ln.c logname.c $(ls_SOURCES) $(md5sum_SOURCES) \ + mkdir.c mkfifo.c mknod.c $(mv_SOURCES) nice.c nl.c od.c paste.c \ + pathchk.c pinky.c pr.c printenv.c printf.c ptx.c pwd.c \ + readlink.c $(rm_SOURCES) rmdir.c seq.c $(sha1sum_SOURCES) \ + shred.c sleep.c sort.c split.c stat.c stty.c su.c sum.c sync.c \ + tac.c tail.c tee.c test.c touch.c tr.c true.c tsort.c tty.c \ + uname.c unexpand.c uniq.c unlink.c uptime.c users.c \ + $(vdir_SOURCES) wc.c who.c whoami.c yes.c +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = $(noinst_HEADERS) Makefile.am Makefile.in +SOURCES = basename.c cat.c $(chgrp_SOURCES) chmod.c $(chown_SOURCES) chroot.c cksum.c comm.c $(cp_SOURCES) csplit.c cut.c date.c dd.c df.c $(dir_SOURCES) dircolors.c dirname.c du.c echo.c env.c expand.c expr.c factor.c false.c fmt.c fold.c $(ginstall_SOURCES) head.c hostid.c hostname.c id.c join.c kill.c link.c ln.c logname.c $(ls_SOURCES) $(md5sum_SOURCES) mkdir.c mkfifo.c mknod.c $(mv_SOURCES) nice.c nl.c od.c paste.c pathchk.c pinky.c pr.c printenv.c printf.c ptx.c pwd.c readlink.c $(rm_SOURCES) rmdir.c seq.c $(sha1sum_SOURCES) shred.c sleep.c sort.c split.c stat.c stty.c su.c sum.c sync.c tac.c tail.c tee.c test.c touch.c tr.c true.c tsort.c tty.c uname.c unexpand.c uniq.c unlink.c uptime.c users.c $(vdir_SOURCES) wc.c who.c whoami.c yes.c + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .sh .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnits src/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) > /dev/null 2>&1 || /bin/rm -f $(bin_PROGRAMS) + +installcheck-binPROGRAMS: $(bin_PROGRAMS) + bad=0; pid=$$$$; list="$(bin_PROGRAMS)"; for p in $$list; do \ + case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \ + *" $$p "* | *" $(srcdir)/$$p "*) continue;; \ + esac; \ + f=`echo "$$p" | \ + sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + for opt in --help --version; do \ + if $(DESTDIR)$(bindir)/$$f $$opt > c$${pid}_.out 2> c$${pid}_.err \ + && test -n "`cat c$${pid}_.out`" \ + && test -z "`cat c$${pid}_.err`"; then :; \ + else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \ + done; \ + done; rm -f c$${pid}_.???; exit $$bad +basename$(EXEEXT): $(basename_OBJECTS) $(basename_DEPENDENCIES) + @rm -f basename$(EXEEXT) + $(LINK) $(basename_LDFLAGS) $(basename_OBJECTS) $(basename_LDADD) $(LIBS) +cat$(EXEEXT): $(cat_OBJECTS) $(cat_DEPENDENCIES) + @rm -f cat$(EXEEXT) + $(LINK) $(cat_LDFLAGS) $(cat_OBJECTS) $(cat_LDADD) $(LIBS) +chgrp$(EXEEXT): $(chgrp_OBJECTS) $(chgrp_DEPENDENCIES) + @rm -f chgrp$(EXEEXT) + $(LINK) $(chgrp_LDFLAGS) $(chgrp_OBJECTS) $(chgrp_LDADD) $(LIBS) +chmod$(EXEEXT): $(chmod_OBJECTS) $(chmod_DEPENDENCIES) + @rm -f chmod$(EXEEXT) + $(LINK) $(chmod_LDFLAGS) $(chmod_OBJECTS) $(chmod_LDADD) $(LIBS) +chown$(EXEEXT): $(chown_OBJECTS) $(chown_DEPENDENCIES) + @rm -f chown$(EXEEXT) + $(LINK) $(chown_LDFLAGS) $(chown_OBJECTS) $(chown_LDADD) $(LIBS) +chroot$(EXEEXT): $(chroot_OBJECTS) $(chroot_DEPENDENCIES) + @rm -f chroot$(EXEEXT) + $(LINK) $(chroot_LDFLAGS) $(chroot_OBJECTS) $(chroot_LDADD) $(LIBS) +cksum$(EXEEXT): $(cksum_OBJECTS) $(cksum_DEPENDENCIES) + @rm -f cksum$(EXEEXT) + $(LINK) $(cksum_LDFLAGS) $(cksum_OBJECTS) $(cksum_LDADD) $(LIBS) +comm$(EXEEXT): $(comm_OBJECTS) $(comm_DEPENDENCIES) + @rm -f comm$(EXEEXT) + $(LINK) $(comm_LDFLAGS) $(comm_OBJECTS) $(comm_LDADD) $(LIBS) +cp$(EXEEXT): $(cp_OBJECTS) $(cp_DEPENDENCIES) + @rm -f cp$(EXEEXT) + $(LINK) $(cp_LDFLAGS) $(cp_OBJECTS) $(cp_LDADD) $(LIBS) +csplit$(EXEEXT): $(csplit_OBJECTS) $(csplit_DEPENDENCIES) + @rm -f csplit$(EXEEXT) + $(LINK) $(csplit_LDFLAGS) $(csplit_OBJECTS) $(csplit_LDADD) $(LIBS) +cut$(EXEEXT): $(cut_OBJECTS) $(cut_DEPENDENCIES) + @rm -f cut$(EXEEXT) + $(LINK) $(cut_LDFLAGS) $(cut_OBJECTS) $(cut_LDADD) $(LIBS) +date$(EXEEXT): $(date_OBJECTS) $(date_DEPENDENCIES) + @rm -f date$(EXEEXT) + $(LINK) $(date_LDFLAGS) $(date_OBJECTS) $(date_LDADD) $(LIBS) +dd$(EXEEXT): $(dd_OBJECTS) $(dd_DEPENDENCIES) + @rm -f dd$(EXEEXT) + $(LINK) $(dd_LDFLAGS) $(dd_OBJECTS) $(dd_LDADD) $(LIBS) +df$(EXEEXT): $(df_OBJECTS) $(df_DEPENDENCIES) + @rm -f df$(EXEEXT) + $(LINK) $(df_LDFLAGS) $(df_OBJECTS) $(df_LDADD) $(LIBS) +dir$(EXEEXT): $(dir_OBJECTS) $(dir_DEPENDENCIES) + @rm -f dir$(EXEEXT) + $(LINK) $(dir_LDFLAGS) $(dir_OBJECTS) $(dir_LDADD) $(LIBS) +dircolors$(EXEEXT): $(dircolors_OBJECTS) $(dircolors_DEPENDENCIES) + @rm -f dircolors$(EXEEXT) + $(LINK) $(dircolors_LDFLAGS) $(dircolors_OBJECTS) $(dircolors_LDADD) $(LIBS) +dirname$(EXEEXT): $(dirname_OBJECTS) $(dirname_DEPENDENCIES) + @rm -f dirname$(EXEEXT) + $(LINK) $(dirname_LDFLAGS) $(dirname_OBJECTS) $(dirname_LDADD) $(LIBS) +du$(EXEEXT): $(du_OBJECTS) $(du_DEPENDENCIES) + @rm -f du$(EXEEXT) + $(LINK) $(du_LDFLAGS) $(du_OBJECTS) $(du_LDADD) $(LIBS) +echo$(EXEEXT): $(echo_OBJECTS) $(echo_DEPENDENCIES) + @rm -f echo$(EXEEXT) + $(LINK) $(echo_LDFLAGS) $(echo_OBJECTS) $(echo_LDADD) $(LIBS) +env$(EXEEXT): $(env_OBJECTS) $(env_DEPENDENCIES) + @rm -f env$(EXEEXT) + $(LINK) $(env_LDFLAGS) $(env_OBJECTS) $(env_LDADD) $(LIBS) +expand$(EXEEXT): $(expand_OBJECTS) $(expand_DEPENDENCIES) + @rm -f expand$(EXEEXT) + $(LINK) $(expand_LDFLAGS) $(expand_OBJECTS) $(expand_LDADD) $(LIBS) +expr$(EXEEXT): $(expr_OBJECTS) $(expr_DEPENDENCIES) + @rm -f expr$(EXEEXT) + $(LINK) $(expr_LDFLAGS) $(expr_OBJECTS) $(expr_LDADD) $(LIBS) +factor$(EXEEXT): $(factor_OBJECTS) $(factor_DEPENDENCIES) + @rm -f factor$(EXEEXT) + $(LINK) $(factor_LDFLAGS) $(factor_OBJECTS) $(factor_LDADD) $(LIBS) +false$(EXEEXT): $(false_OBJECTS) $(false_DEPENDENCIES) + @rm -f false$(EXEEXT) + $(LINK) $(false_LDFLAGS) $(false_OBJECTS) $(false_LDADD) $(LIBS) +fmt$(EXEEXT): $(fmt_OBJECTS) $(fmt_DEPENDENCIES) + @rm -f fmt$(EXEEXT) + $(LINK) $(fmt_LDFLAGS) $(fmt_OBJECTS) $(fmt_LDADD) $(LIBS) +fold$(EXEEXT): $(fold_OBJECTS) $(fold_DEPENDENCIES) + @rm -f fold$(EXEEXT) + $(LINK) $(fold_LDFLAGS) $(fold_OBJECTS) $(fold_LDADD) $(LIBS) +ginstall$(EXEEXT): $(ginstall_OBJECTS) $(ginstall_DEPENDENCIES) + @rm -f ginstall$(EXEEXT) + $(LINK) $(ginstall_LDFLAGS) $(ginstall_OBJECTS) $(ginstall_LDADD) $(LIBS) +head$(EXEEXT): $(head_OBJECTS) $(head_DEPENDENCIES) + @rm -f head$(EXEEXT) + $(LINK) $(head_LDFLAGS) $(head_OBJECTS) $(head_LDADD) $(LIBS) +hostid$(EXEEXT): $(hostid_OBJECTS) $(hostid_DEPENDENCIES) + @rm -f hostid$(EXEEXT) + $(LINK) $(hostid_LDFLAGS) $(hostid_OBJECTS) $(hostid_LDADD) $(LIBS) +hostname$(EXEEXT): $(hostname_OBJECTS) $(hostname_DEPENDENCIES) + @rm -f hostname$(EXEEXT) + $(LINK) $(hostname_LDFLAGS) $(hostname_OBJECTS) $(hostname_LDADD) $(LIBS) +id$(EXEEXT): $(id_OBJECTS) $(id_DEPENDENCIES) + @rm -f id$(EXEEXT) + $(LINK) $(id_LDFLAGS) $(id_OBJECTS) $(id_LDADD) $(LIBS) +join$(EXEEXT): $(join_OBJECTS) $(join_DEPENDENCIES) + @rm -f join$(EXEEXT) + $(LINK) $(join_LDFLAGS) $(join_OBJECTS) $(join_LDADD) $(LIBS) +kill$(EXEEXT): $(kill_OBJECTS) $(kill_DEPENDENCIES) + @rm -f kill$(EXEEXT) + $(LINK) $(kill_LDFLAGS) $(kill_OBJECTS) $(kill_LDADD) $(LIBS) +link$(EXEEXT): $(link_OBJECTS) $(link_DEPENDENCIES) + @rm -f link$(EXEEXT) + $(LINK) $(link_LDFLAGS) $(link_OBJECTS) $(link_LDADD) $(LIBS) +ln$(EXEEXT): $(ln_OBJECTS) $(ln_DEPENDENCIES) + @rm -f ln$(EXEEXT) + $(LINK) $(ln_LDFLAGS) $(ln_OBJECTS) $(ln_LDADD) $(LIBS) +logname$(EXEEXT): $(logname_OBJECTS) $(logname_DEPENDENCIES) + @rm -f logname$(EXEEXT) + $(LINK) $(logname_LDFLAGS) $(logname_OBJECTS) $(logname_LDADD) $(LIBS) +ls$(EXEEXT): $(ls_OBJECTS) $(ls_DEPENDENCIES) + @rm -f ls$(EXEEXT) + $(LINK) $(ls_LDFLAGS) $(ls_OBJECTS) $(ls_LDADD) $(LIBS) +md5sum$(EXEEXT): $(md5sum_OBJECTS) $(md5sum_DEPENDENCIES) + @rm -f md5sum$(EXEEXT) + $(LINK) $(md5sum_LDFLAGS) $(md5sum_OBJECTS) $(md5sum_LDADD) $(LIBS) +mkdir$(EXEEXT): $(mkdir_OBJECTS) $(mkdir_DEPENDENCIES) + @rm -f mkdir$(EXEEXT) + $(LINK) $(mkdir_LDFLAGS) $(mkdir_OBJECTS) $(mkdir_LDADD) $(LIBS) +mkfifo$(EXEEXT): $(mkfifo_OBJECTS) $(mkfifo_DEPENDENCIES) + @rm -f mkfifo$(EXEEXT) + $(LINK) $(mkfifo_LDFLAGS) $(mkfifo_OBJECTS) $(mkfifo_LDADD) $(LIBS) +mknod$(EXEEXT): $(mknod_OBJECTS) $(mknod_DEPENDENCIES) + @rm -f mknod$(EXEEXT) + $(LINK) $(mknod_LDFLAGS) $(mknod_OBJECTS) $(mknod_LDADD) $(LIBS) +mv$(EXEEXT): $(mv_OBJECTS) $(mv_DEPENDENCIES) + @rm -f mv$(EXEEXT) + $(LINK) $(mv_LDFLAGS) $(mv_OBJECTS) $(mv_LDADD) $(LIBS) +nice$(EXEEXT): $(nice_OBJECTS) $(nice_DEPENDENCIES) + @rm -f nice$(EXEEXT) + $(LINK) $(nice_LDFLAGS) $(nice_OBJECTS) $(nice_LDADD) $(LIBS) +nl$(EXEEXT): $(nl_OBJECTS) $(nl_DEPENDENCIES) + @rm -f nl$(EXEEXT) + $(LINK) $(nl_LDFLAGS) $(nl_OBJECTS) $(nl_LDADD) $(LIBS) +od$(EXEEXT): $(od_OBJECTS) $(od_DEPENDENCIES) + @rm -f od$(EXEEXT) + $(LINK) $(od_LDFLAGS) $(od_OBJECTS) $(od_LDADD) $(LIBS) +paste$(EXEEXT): $(paste_OBJECTS) $(paste_DEPENDENCIES) + @rm -f paste$(EXEEXT) + $(LINK) $(paste_LDFLAGS) $(paste_OBJECTS) $(paste_LDADD) $(LIBS) +pathchk$(EXEEXT): $(pathchk_OBJECTS) $(pathchk_DEPENDENCIES) + @rm -f pathchk$(EXEEXT) + $(LINK) $(pathchk_LDFLAGS) $(pathchk_OBJECTS) $(pathchk_LDADD) $(LIBS) +pinky$(EXEEXT): $(pinky_OBJECTS) $(pinky_DEPENDENCIES) + @rm -f pinky$(EXEEXT) + $(LINK) $(pinky_LDFLAGS) $(pinky_OBJECTS) $(pinky_LDADD) $(LIBS) +pr$(EXEEXT): $(pr_OBJECTS) $(pr_DEPENDENCIES) + @rm -f pr$(EXEEXT) + $(LINK) $(pr_LDFLAGS) $(pr_OBJECTS) $(pr_LDADD) $(LIBS) +printenv$(EXEEXT): $(printenv_OBJECTS) $(printenv_DEPENDENCIES) + @rm -f printenv$(EXEEXT) + $(LINK) $(printenv_LDFLAGS) $(printenv_OBJECTS) $(printenv_LDADD) $(LIBS) +printf$(EXEEXT): $(printf_OBJECTS) $(printf_DEPENDENCIES) + @rm -f printf$(EXEEXT) + $(LINK) $(printf_LDFLAGS) $(printf_OBJECTS) $(printf_LDADD) $(LIBS) +ptx$(EXEEXT): $(ptx_OBJECTS) $(ptx_DEPENDENCIES) + @rm -f ptx$(EXEEXT) + $(LINK) $(ptx_LDFLAGS) $(ptx_OBJECTS) $(ptx_LDADD) $(LIBS) +pwd$(EXEEXT): $(pwd_OBJECTS) $(pwd_DEPENDENCIES) + @rm -f pwd$(EXEEXT) + $(LINK) $(pwd_LDFLAGS) $(pwd_OBJECTS) $(pwd_LDADD) $(LIBS) +readlink$(EXEEXT): $(readlink_OBJECTS) $(readlink_DEPENDENCIES) + @rm -f readlink$(EXEEXT) + $(LINK) $(readlink_LDFLAGS) $(readlink_OBJECTS) $(readlink_LDADD) $(LIBS) +rm$(EXEEXT): $(rm_OBJECTS) $(rm_DEPENDENCIES) + @rm -f rm$(EXEEXT) + $(LINK) $(rm_LDFLAGS) $(rm_OBJECTS) $(rm_LDADD) $(LIBS) +rmdir$(EXEEXT): $(rmdir_OBJECTS) $(rmdir_DEPENDENCIES) + @rm -f rmdir$(EXEEXT) + $(LINK) $(rmdir_LDFLAGS) $(rmdir_OBJECTS) $(rmdir_LDADD) $(LIBS) +seq$(EXEEXT): $(seq_OBJECTS) $(seq_DEPENDENCIES) + @rm -f seq$(EXEEXT) + $(LINK) $(seq_LDFLAGS) $(seq_OBJECTS) $(seq_LDADD) $(LIBS) +sha1sum$(EXEEXT): $(sha1sum_OBJECTS) $(sha1sum_DEPENDENCIES) + @rm -f sha1sum$(EXEEXT) + $(LINK) $(sha1sum_LDFLAGS) $(sha1sum_OBJECTS) $(sha1sum_LDADD) $(LIBS) +shred$(EXEEXT): $(shred_OBJECTS) $(shred_DEPENDENCIES) + @rm -f shred$(EXEEXT) + $(LINK) $(shred_LDFLAGS) $(shred_OBJECTS) $(shred_LDADD) $(LIBS) +sleep$(EXEEXT): $(sleep_OBJECTS) $(sleep_DEPENDENCIES) + @rm -f sleep$(EXEEXT) + $(LINK) $(sleep_LDFLAGS) $(sleep_OBJECTS) $(sleep_LDADD) $(LIBS) +sort$(EXEEXT): $(sort_OBJECTS) $(sort_DEPENDENCIES) + @rm -f sort$(EXEEXT) + $(LINK) $(sort_LDFLAGS) $(sort_OBJECTS) $(sort_LDADD) $(LIBS) +split$(EXEEXT): $(split_OBJECTS) $(split_DEPENDENCIES) + @rm -f split$(EXEEXT) + $(LINK) $(split_LDFLAGS) $(split_OBJECTS) $(split_LDADD) $(LIBS) +stat$(EXEEXT): $(stat_OBJECTS) $(stat_DEPENDENCIES) + @rm -f stat$(EXEEXT) + $(LINK) $(stat_LDFLAGS) $(stat_OBJECTS) $(stat_LDADD) $(LIBS) +stty$(EXEEXT): $(stty_OBJECTS) $(stty_DEPENDENCIES) + @rm -f stty$(EXEEXT) + $(LINK) $(stty_LDFLAGS) $(stty_OBJECTS) $(stty_LDADD) $(LIBS) +su$(EXEEXT): $(su_OBJECTS) $(su_DEPENDENCIES) + @rm -f su$(EXEEXT) + $(LINK) $(su_LDFLAGS) $(su_OBJECTS) $(su_LDADD) $(LIBS) +sum$(EXEEXT): $(sum_OBJECTS) $(sum_DEPENDENCIES) + @rm -f sum$(EXEEXT) + $(LINK) $(sum_LDFLAGS) $(sum_OBJECTS) $(sum_LDADD) $(LIBS) +sync$(EXEEXT): $(sync_OBJECTS) $(sync_DEPENDENCIES) + @rm -f sync$(EXEEXT) + $(LINK) $(sync_LDFLAGS) $(sync_OBJECTS) $(sync_LDADD) $(LIBS) +tac$(EXEEXT): $(tac_OBJECTS) $(tac_DEPENDENCIES) + @rm -f tac$(EXEEXT) + $(LINK) $(tac_LDFLAGS) $(tac_OBJECTS) $(tac_LDADD) $(LIBS) +tail$(EXEEXT): $(tail_OBJECTS) $(tail_DEPENDENCIES) + @rm -f tail$(EXEEXT) + $(LINK) $(tail_LDFLAGS) $(tail_OBJECTS) $(tail_LDADD) $(LIBS) +tee$(EXEEXT): $(tee_OBJECTS) $(tee_DEPENDENCIES) + @rm -f tee$(EXEEXT) + $(LINK) $(tee_LDFLAGS) $(tee_OBJECTS) $(tee_LDADD) $(LIBS) +test$(EXEEXT): $(test_OBJECTS) $(test_DEPENDENCIES) + @rm -f test$(EXEEXT) + $(LINK) $(test_LDFLAGS) $(test_OBJECTS) $(test_LDADD) $(LIBS) +touch$(EXEEXT): $(touch_OBJECTS) $(touch_DEPENDENCIES) + @rm -f touch$(EXEEXT) + $(LINK) $(touch_LDFLAGS) $(touch_OBJECTS) $(touch_LDADD) $(LIBS) +tr$(EXEEXT): $(tr_OBJECTS) $(tr_DEPENDENCIES) + @rm -f tr$(EXEEXT) + $(LINK) $(tr_LDFLAGS) $(tr_OBJECTS) $(tr_LDADD) $(LIBS) +true$(EXEEXT): $(true_OBJECTS) $(true_DEPENDENCIES) + @rm -f true$(EXEEXT) + $(LINK) $(true_LDFLAGS) $(true_OBJECTS) $(true_LDADD) $(LIBS) +tsort$(EXEEXT): $(tsort_OBJECTS) $(tsort_DEPENDENCIES) + @rm -f tsort$(EXEEXT) + $(LINK) $(tsort_LDFLAGS) $(tsort_OBJECTS) $(tsort_LDADD) $(LIBS) +tty$(EXEEXT): $(tty_OBJECTS) $(tty_DEPENDENCIES) + @rm -f tty$(EXEEXT) + $(LINK) $(tty_LDFLAGS) $(tty_OBJECTS) $(tty_LDADD) $(LIBS) +uname$(EXEEXT): $(uname_OBJECTS) $(uname_DEPENDENCIES) + @rm -f uname$(EXEEXT) + $(LINK) $(uname_LDFLAGS) $(uname_OBJECTS) $(uname_LDADD) $(LIBS) +unexpand$(EXEEXT): $(unexpand_OBJECTS) $(unexpand_DEPENDENCIES) + @rm -f unexpand$(EXEEXT) + $(LINK) $(unexpand_LDFLAGS) $(unexpand_OBJECTS) $(unexpand_LDADD) $(LIBS) +uniq$(EXEEXT): $(uniq_OBJECTS) $(uniq_DEPENDENCIES) + @rm -f uniq$(EXEEXT) + $(LINK) $(uniq_LDFLAGS) $(uniq_OBJECTS) $(uniq_LDADD) $(LIBS) +unlink$(EXEEXT): $(unlink_OBJECTS) $(unlink_DEPENDENCIES) + @rm -f unlink$(EXEEXT) + $(LINK) $(unlink_LDFLAGS) $(unlink_OBJECTS) $(unlink_LDADD) $(LIBS) +uptime$(EXEEXT): $(uptime_OBJECTS) $(uptime_DEPENDENCIES) + @rm -f uptime$(EXEEXT) + $(LINK) $(uptime_LDFLAGS) $(uptime_OBJECTS) $(uptime_LDADD) $(LIBS) +users$(EXEEXT): $(users_OBJECTS) $(users_DEPENDENCIES) + @rm -f users$(EXEEXT) + $(LINK) $(users_LDFLAGS) $(users_OBJECTS) $(users_LDADD) $(LIBS) +vdir$(EXEEXT): $(vdir_OBJECTS) $(vdir_DEPENDENCIES) + @rm -f vdir$(EXEEXT) + $(LINK) $(vdir_LDFLAGS) $(vdir_OBJECTS) $(vdir_LDADD) $(LIBS) +wc$(EXEEXT): $(wc_OBJECTS) $(wc_DEPENDENCIES) + @rm -f wc$(EXEEXT) + $(LINK) $(wc_LDFLAGS) $(wc_OBJECTS) $(wc_LDADD) $(LIBS) +who$(EXEEXT): $(who_OBJECTS) $(who_DEPENDENCIES) + @rm -f who$(EXEEXT) + $(LINK) $(who_LDFLAGS) $(who_OBJECTS) $(who_LDADD) $(LIBS) +whoami$(EXEEXT): $(whoami_OBJECTS) $(whoami_DEPENDENCIES) + @rm -f whoami$(EXEEXT) + $(LINK) $(whoami_LDFLAGS) $(whoami_OBJECTS) $(whoami_LDADD) $(LIBS) +yes$(EXEEXT): $(yes_OBJECTS) $(yes_DEPENDENCIES) + @rm -f yes$(EXEEXT) + $(LINK) $(yes_LDFLAGS) $(yes_OBJECTS) $(yes_LDADD) $(LIBS) +binSCRIPT_INSTALL = $(INSTALL_SCRIPT) +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f $$d$$p; then \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " $(binSCRIPT_INSTALL) $$d$$p $(DESTDIR)$(bindir)/$$f"; \ + $(binSCRIPT_INSTALL) $$d$$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done + +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +installcheck-binSCRIPTS: $(bin_SCRIPTS) + bad=0; pid=$$$$; list="$(bin_SCRIPTS)"; for p in $$list; do \ + case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \ + *" $$p "* | *" $(srcdir)/$$p "*) continue;; \ + esac; \ + f=`echo "$$p" | sed 's,^.*/,,;$(transform)'`; \ + for opt in --help --version; do \ + if $(DESTDIR)$(bindir)/$$f $$opt > c$${pid}_.out 2> c$${pid}_.err \ + && test -n "`cat c$${pid}_.out`" \ + && test -z "`cat c$${pid}_.err`"; then :; \ + else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \ + done; \ + done; rm -f c$${pid}_.???; exit $$bad + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +include ./$(DEPDIR)/basename.Po +include ./$(DEPDIR)/cat.Po +include ./$(DEPDIR)/chgrp.Po +include ./$(DEPDIR)/chmod.Po +include ./$(DEPDIR)/chown-core.Po +include ./$(DEPDIR)/chown.Po +include ./$(DEPDIR)/chroot.Po +include ./$(DEPDIR)/cksum.Po +include ./$(DEPDIR)/comm.Po +include ./$(DEPDIR)/copy.Po +include ./$(DEPDIR)/cp-hash.Po +include ./$(DEPDIR)/cp.Po +include ./$(DEPDIR)/csplit.Po +include ./$(DEPDIR)/cut.Po +include ./$(DEPDIR)/date.Po +include ./$(DEPDIR)/dd.Po +include ./$(DEPDIR)/df.Po +include ./$(DEPDIR)/dircolors.Po +include ./$(DEPDIR)/dirname.Po +include ./$(DEPDIR)/du.Po +include ./$(DEPDIR)/echo.Po +include ./$(DEPDIR)/env.Po +include ./$(DEPDIR)/expand.Po +include ./$(DEPDIR)/expr.Po +include ./$(DEPDIR)/factor.Po +include ./$(DEPDIR)/false.Po +include ./$(DEPDIR)/fmt.Po +include ./$(DEPDIR)/fold.Po +include ./$(DEPDIR)/head.Po +include ./$(DEPDIR)/hostid.Po +include ./$(DEPDIR)/hostname.Po +include ./$(DEPDIR)/id.Po +include ./$(DEPDIR)/install.Po +include ./$(DEPDIR)/join.Po +include ./$(DEPDIR)/kill.Po +include ./$(DEPDIR)/link.Po +include ./$(DEPDIR)/ln.Po +include ./$(DEPDIR)/logname.Po +include ./$(DEPDIR)/ls-dir.Po +include ./$(DEPDIR)/ls-ls.Po +include ./$(DEPDIR)/ls-vdir.Po +include ./$(DEPDIR)/ls.Po +include ./$(DEPDIR)/md5.Po +include ./$(DEPDIR)/md5sum.Po +include ./$(DEPDIR)/mkdir.Po +include ./$(DEPDIR)/mkfifo.Po +include ./$(DEPDIR)/mknod.Po +include ./$(DEPDIR)/mv.Po +include ./$(DEPDIR)/nice.Po +include ./$(DEPDIR)/nl.Po +include ./$(DEPDIR)/od.Po +include ./$(DEPDIR)/paste.Po +include ./$(DEPDIR)/pathchk.Po +include ./$(DEPDIR)/pinky.Po +include ./$(DEPDIR)/pr.Po +include ./$(DEPDIR)/printenv.Po +include ./$(DEPDIR)/printf.Po +include ./$(DEPDIR)/ptx.Po +include ./$(DEPDIR)/pwd.Po +include ./$(DEPDIR)/readlink.Po +include ./$(DEPDIR)/remove.Po +include ./$(DEPDIR)/rm.Po +include ./$(DEPDIR)/rmdir.Po +include ./$(DEPDIR)/seq.Po +include ./$(DEPDIR)/sha1sum.Po +include ./$(DEPDIR)/shred.Po +include ./$(DEPDIR)/sleep.Po +include ./$(DEPDIR)/sort.Po +include ./$(DEPDIR)/split.Po +include ./$(DEPDIR)/stat.Po +include ./$(DEPDIR)/stty.Po +include ./$(DEPDIR)/su.Po +include ./$(DEPDIR)/sum.Po +include ./$(DEPDIR)/sync.Po +include ./$(DEPDIR)/tac.Po +include ./$(DEPDIR)/tail.Po +include ./$(DEPDIR)/tee.Po +include ./$(DEPDIR)/test.Po +include ./$(DEPDIR)/touch.Po +include ./$(DEPDIR)/tr.Po +include ./$(DEPDIR)/true.Po +include ./$(DEPDIR)/tsort.Po +include ./$(DEPDIR)/tty.Po +include ./$(DEPDIR)/uname.Po +include ./$(DEPDIR)/unexpand.Po +include ./$(DEPDIR)/uniq.Po +include ./$(DEPDIR)/unlink.Po +include ./$(DEPDIR)/uptime.Po +include ./$(DEPDIR)/users.Po +include ./$(DEPDIR)/wc.Po +include ./$(DEPDIR)/who.Po +include ./$(DEPDIR)/whoami.Po +include ./$(DEPDIR)/yes.Po + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +# if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +# -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +# then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +# else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +# fi + source='$<' object='$@' libtool=no \ + depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' \ + $(CCDEPMODE) $(depcomp) \ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +# if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +# -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +# then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +# else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +# fi + source='$<' object='$@' libtool=no \ + depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' \ + $(CCDEPMODE) $(depcomp) \ + $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` +uninstall-info-am: + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(HEADERS) all-local + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(bindir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS install-binSCRIPTS \ + install-exec-local + +install-info: install-info-am + +install-man: + +installcheck-am: installcheck-binPROGRAMS installcheck-binSCRIPTS + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ + uninstall-info-am uninstall-local + +.PHONY: CTAGS GTAGS all all-am all-local check check-am clean \ + clean-binPROGRAMS clean-generic ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-binPROGRAMS install-binSCRIPTS install-data \ + install-data-am install-exec install-exec-am install-exec-local \ + install-info install-info-am install-man install-strip \ + installcheck installcheck-am installcheck-binPROGRAMS \ + installcheck-binSCRIPTS installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-binSCRIPTS \ + uninstall-info-am uninstall-local + + +$(PROGRAMS): ../lib/libfetish.a + +$(SCRIPTS): Makefile + +.sh: + rm -f $@ $@-t + sed \ + -e 's!@''bindir''@!$(bindir)!' \ + -e 's/@''GNU_PACKAGE''@/GNU coreutils/' \ + -e 's/@''PACKAGE_BUGREPORT''@/bug-coreutils@gnu.org/' \ + -e 's/@''VERSION''@/5.0/' $< > $@-t + chmod +x $@-t + mv $@-t $@ + +all-local: su$(EXEEXT) + +install-root: su$(EXEEXT) + @$(INSTALL_SU) + +install-exec-local: su$(EXEEXT) + @TMPFILE=$(DESTDIR)$(bindir)/.su-$$$$; \ + rm -f $$TMPFILE; \ + echo > $$TMPFILE; \ + can_create_suid_root_executable=no; \ + chown root $$TMPFILE > /dev/null 2>&1 \ + && chmod $(setuid_root_mode) $$TMPFILE > /dev/null 2>&1 \ + && can_create_suid_root_executable=yes; \ + rm -f $$TMPFILE; \ + if test $$can_create_suid_root_executable = yes; then \ + $(INSTALL_SU); \ + else \ + echo "WARNING: insufficient access; not installing su"; \ + echo "NOTE: to install su, run 'make install-root' as root"; \ + fi + +uninstall-local: +# Remove su only if it's one we installed. + @if grep 'GNU coreutils' $(installed_su) > /dev/null 2>&1; then \ + echo " rm -f $(installed_su)"; \ + rm -f $(installed_su); \ + else :; fi + +dircolors.h: dcgen dircolors.hin + $(PERL) -w -- $(srcdir)/dcgen $(srcdir)/dircolors.hin > $@-t + mv $@-t $@ + +wheel-size.h: Makefile.am + echo '#define WHEEL_SIZE $(wheel_size)' > $@-t + mv $@-t $@ + +wheel.h: wheel-gen.pl Makefile.am + $(srcdir)/wheel-gen.pl $(wheel_size) \ + > $@-t + mv $@-t $@ + +false.c: true.c + rm -f $@ + sed \ + -e s/true/false/g \ + -e s/success/failure/g \ + -e 's/(EXIT_SUCCESS)/(EXIT_FAILURE)/g' \ + $(srcdir)/true.c > $@-t + chmod a-w $@-t + mv $@-t $@ +# Ensure that the list of programs in README matches the list +# of programs we can build. +check: check-README check-misc +.PHONY: check-README +check-README: + rm -rf $(pr) $(pm) + echo $(all_programs) \ + | tr -s ' ' '\n' | sort -u > $(pm) + sed -n '/^The programs .* are:/,/^[a-zA-Z]/p' $(top_srcdir)/README \ + | sed -n '/^ */s///p' | tr -s ' ' '\n' > $(pr) + diff $(pm) $(pr) && rm -rf $(pr) $(pm) + +# Make sure we don't define any S_IS* macros in src/*.c files. +# Not a big deal, but they're already defined via system.h. +# +# Also make sure we don't use st_blocks. Use ST_NBLOCKS instead. +# This is a bit of a kludge, since it prevents use of the string +# even in comments, but for now it does the job with no false positives. +.PHONY: check-misc +check-misc: + cd $(srcdir); grep '^# *define *S_IS' $(SOURCES) && exit 1 || : + cd $(srcdir); grep st_blocks $(SOURCES) && exit 1 || : + cd $(srcdir); grep '^# *define .*defined' $(SOURCES) && exit 1 || : +# FIXME: handle *.sh; and use $(all_programs), not $(SOURCES) +../AUTHORS: $(SOURCES) + rm -f $@-t + ( \ + set -e; \ + echo "Here are the names of the programs in this package,"; \ + echo "each followed by the name(s) of its author(s)."; \ + echo; \ + for i in $(SOURCES); do \ + a=`sed -n $(s1) $$i`; \ + test "$$a" && : \ + || a=`sed -n $(s2) $$i`; \ + if test "$$a"; then \ + prog=`echo $$i|sed 's/\.c$$//'`; \ + echo "$$prog: $$a"; \ + fi; \ + done | sort -u ) > $@-t + chmod a-w $@-t + mv $@-t $@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/apps/bin/coreutils-5.0/src/basename.c b/src/apps/bin/coreutils-5.0/src/basename.c new file mode 100644 index 0000000000..aa0e14161a --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/basename.c @@ -0,0 +1,128 @@ +/* basename -- strip directory and suffix from filenames + Copyright (C) 1990-1997, 1999-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Usage: basename name [suffix] + NAME is a pathname; SUFFIX is a suffix to strip from it. + + basename /usr/foo/lossage/functions.l + => functions.l + basename /usr/foo/lossage/functions.l .l + => functions + basename functions.lisp p + => functions.lis */ + +#include +#include +#include + +#include "system.h" +#include "long-options.h" +#include "dirname.h" +#include "error.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "basename" + +#define AUTHORS "FIXME unknown" + +/* The name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s NAME [SUFFIX]\n\ + or: %s OPTION\n\ +"), + program_name, program_name); + fputs (_("\ +Print NAME with any leading directory components removed.\n\ +If specified, also remove a trailing SUFFIX.\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +/* Remove SUFFIX from the end of NAME if it is there, unless NAME + consists entirely of SUFFIX. */ + +static void +remove_suffix (char *name, const char *suffix) +{ + char *np; + const char *sp; + + np = name + strlen (name); + sp = suffix + strlen (suffix); + + while (np > name && sp > suffix) + if (*--np != *--sp) + return; + if (np > name) + *np = '\0'; +} + +int +main (int argc, char **argv) +{ + char *name; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + /* The above handles --help and --version. + Since there is no other invocation of getopt, handle `--' here. */ + if (argc > 1 && STREQ (argv[1], "--")) + { + --argc; + ++argv; + } + + if (argc == 1 || argc > 3) + { + error (0, 0, (argc == 1 ? _("too few arguments") + : _("too many arguments"))); + usage (EXIT_FAILURE); + } + + name = base_name (argv[1]); + name[base_len (name)] = '\0'; + + if (argc == 3) + remove_suffix (name, argv[2]); + + puts (name); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/cat.c b/src/apps/bin/coreutils-5.0/src/cat.c new file mode 100644 index 0000000000..9845e58124 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/cat.c @@ -0,0 +1,864 @@ +/* cat -- concatenate files and print on the standard output. + Copyright (C) 88, 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Differences from the Unix cat: + * Always unbuffered, -u is ignored. + * Usually much faster than other versions of cat, the difference + is especially apparent when using the -v option. + + By tege@sics.se, Torbjorn Granlund, advised by rms, Richard Stallman. */ + +#include + +#include +#include +#include +#ifndef _POSIX_SOURCE +# include +#endif +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "full-write.h" +#include "safe-read.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "cat" + +#define AUTHORS N_ ("Torbjorn Granlund and Richard M. Stallman") + +/* Undefine, to avoid warning about redefinition on some systems. */ +#undef max +#define max(h,i) ((h) > (i) ? (h) : (i)) + +/* Name under which this program was invoked. */ +char *program_name; + +/* Name of input file. May be "-". */ +static char *infile; + +/* Descriptor on which input file is open. */ +static int input_desc; + +/* Buffer for line numbers. + An 11 digit counter may overflow within an hour on a P2/466, + an 18 digit counter needs about 1000y */ +#define LINE_COUNTER_BUF_LEN 20 +static char line_buf[LINE_COUNTER_BUF_LEN] = + { + ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '0', + '\t', '\0' + }; + +/* Position in `line_buf' where printing starts. This will not change + unless the number of lines is larger than 999999. */ +static char *line_num_print = line_buf + LINE_COUNTER_BUF_LEN - 8; + +/* Position of the first digit in `line_buf'. */ +static char *line_num_start = line_buf + LINE_COUNTER_BUF_LEN - 3; + +/* Position of the last digit in `line_buf'. */ +static char *line_num_end = line_buf + LINE_COUNTER_BUF_LEN - 3; + +/* Preserves the `cat' function's local `newlines' between invocations. */ +static int newlines2 = 0; + +/* Count of non-fatal error conditions. */ +static int exit_status = 0; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION] [FILE]...\n\ +"), + program_name); + fputs (_("\ +Concatenate FILE(s), or standard input, to standard output.\n\ +\n\ + -A, --show-all equivalent to -vET\n\ + -b, --number-nonblank number nonblank output lines\n\ + -e equivalent to -vE\n\ + -E, --show-ends display $ at end of each line\n\ + -n, --number number all output lines\n\ + -s, --squeeze-blank never more than one single blank line\n\ +"), stdout); + fputs (_("\ + -t equivalent to -vT\n\ + -T, --show-tabs display TAB characters as ^I\n\ + -u (ignored)\n\ + -v, --show-nonprinting use ^ and M- notation, except for LFD and TAB\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +With no FILE, or when FILE is -, read standard input.\n\ +"), stdout); +#if O_BINARY + fputs (_("\ +\n\ + -B, --binary use binary writes to the console device.\n\n\ +"), stdout); +#endif + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Compute the next line number. */ + +static void +next_line_num (void) +{ + char *endp = line_num_end; + do + { + if ((*endp)++ < '9') + return; + *endp-- = '0'; + } + while (endp >= line_num_start); + if (line_num_start > line_buf) + *--line_num_start = '1'; + else + *line_buf = '>'; + if (line_num_start < line_num_print) + line_num_print--; +} + +/* Plain cat. Copies the file behind `input_desc' to STDOUT_FILENO. */ + +static void +simple_cat ( + /* Pointer to the buffer, used by reads and writes. */ + char *buf, + + /* Number of characters preferably read or written by each read and write + call. */ + int bufsize) +{ + /* Actual number of characters read, and therefore written. */ + size_t n_read; + + /* Loop until the end of the file. */ + + for (;;) + { + /* Read a block of input. */ + + n_read = safe_read (input_desc, buf, bufsize); + if (n_read == SAFE_READ_ERROR) + { + error (0, errno, "%s", infile); + exit_status = 1; + return; + } + + /* End of this file? */ + + if (n_read == 0) + break; + + /* Write this block out. */ + + { + /* The following is ok, since we know that 0 < n_read. */ + size_t n = n_read; + if (full_write (STDOUT_FILENO, buf, n) != n) + error (EXIT_FAILURE, errno, _("write error")); + } + } +} + +/* Cat the file behind INPUT_DESC to the file behind OUTPUT_DESC. + Called if any option more than -u was specified. + + A newline character is always put at the end of the buffer, to make + an explicit test for buffer end unnecessary. */ + +static void +cat ( + /* Pointer to the beginning of the input buffer. */ + char *inbuf, + + /* Number of characters read in each read call. */ + size_t insize, + + /* Pointer to the beginning of the output buffer. */ + char *outbuf, + + /* Number of characters written by each write call. */ + size_t outsize, + + /* Variables that have values according to the specified options. */ + int quote, + int output_tabs, + int numbers, + int numbers_at_empty_lines, + int mark_line_ends, + int squeeze_empty_lines) +{ + /* Last character read from the input buffer. */ + unsigned char ch; + + /* Pointer to the next character in the input buffer. */ + char *bpin; + + /* Pointer to the first non-valid byte in the input buffer, i.e. the + current end of the buffer. */ + char *eob; + + /* Pointer to the position where the next character shall be written. */ + char *bpout; + + /* Number of characters read by the last read call. */ + size_t n_read; + + /* Determines how many consecutive newlines there have been in the + input. 0 newlines makes NEWLINES -1, 1 newline makes NEWLINES 1, + etc. Initially 0 to indicate that we are at the beginning of a + new line. The "state" of the procedure is determined by + NEWLINES. */ + int newlines = newlines2; + +#ifdef FIONREAD + /* If nonzero, use the FIONREAD ioctl, as an optimization. + (On Ultrix, it is not supported on NFS filesystems.) */ + int use_fionread = 1; +#endif + + /* The inbuf pointers are initialized so that BPIN > EOB, and thereby input + is read immediately. */ + + eob = inbuf; + bpin = eob + 1; + + bpout = outbuf; + + for (;;) + { + do + { + /* Write if there are at least OUTSIZE bytes in OUTBUF. */ + + if (outbuf + outsize <= bpout) + { + char *wp = outbuf; + size_t remaining_bytes; + do + { + if (full_write (STDOUT_FILENO, wp, outsize) != outsize) + error (EXIT_FAILURE, errno, _("write error")); + wp += outsize; + remaining_bytes = bpout - wp; + } + while (outsize <= remaining_bytes); + + /* Move the remaining bytes to the beginning of the + buffer. */ + + memmove (outbuf, wp, remaining_bytes); + bpout = outbuf + remaining_bytes; + } + + /* Is INBUF empty? */ + + if (bpin > eob) + { +#ifdef FIONREAD + int n_to_read = 0; + + /* Is there any input to read immediately? + If not, we are about to wait, + so write all buffered output before waiting. */ + + if (use_fionread + && ioctl (input_desc, FIONREAD, &n_to_read) < 0) + { + /* Ultrix returns EOPNOTSUPP on NFS; + HP-UX returns ENOTTY on pipes. + SunOS returns EINVAL and + More/BSD returns ENODEV on special files + like /dev/null. + Irix-5 returns ENOSYS on pipes. */ + if (errno == EOPNOTSUPP || errno == ENOTTY + || errno == EINVAL || errno == ENODEV +# ifdef ENOSYS + || errno == ENOSYS +# endif + ) + use_fionread = 0; + else + { + error (0, errno, _("cannot do ioctl on `%s'"), infile); + exit_status = 1; + newlines2 = newlines; + return; + } + } + if (n_to_read == 0) +#endif + { + size_t n_write = bpout - outbuf; + + if (full_write (STDOUT_FILENO, outbuf, n_write) != n_write) + error (EXIT_FAILURE, errno, _("write error")); + bpout = outbuf; + } + + /* Read more input into INBUF. */ + + n_read = safe_read (input_desc, inbuf, insize); + if (n_read == SAFE_READ_ERROR) + { + error (0, errno, "%s", infile); + exit_status = 1; + newlines2 = newlines; + return; + } + if (n_read == 0) + { + newlines2 = newlines; + return; + } + + /* Update the pointers and insert a sentinel at the buffer + end. */ + + bpin = inbuf; + eob = bpin + n_read; + *eob = '\n'; + } + else + { + /* It was a real (not a sentinel) newline. */ + + /* Was the last line empty? + (i.e. have two or more consecutive newlines been read?) */ + + if (++newlines > 0) + { + if (newlines >= 2) + { + /* Limit this to 2 here. Otherwise, with lots of + consecutive newlines, the counter could wrap + around at INT_MAX. */ + newlines = 2; + + /* Are multiple adjacent empty lines to be substituted + by single ditto (-s), and this was the second empty + line? */ + if (squeeze_empty_lines) + { + ch = *bpin++; + continue; + } + } + + /* Are line numbers to be written at empty lines (-n)? */ + + if (numbers && numbers_at_empty_lines) + { + next_line_num (); + bpout = stpcpy (bpout, line_num_print); + } + } + + /* Output a currency symbol if requested (-e). */ + + if (mark_line_ends) + *bpout++ = '$'; + + /* Output the newline. */ + + *bpout++ = '\n'; + } + ch = *bpin++; + } + while (ch == '\n'); + + /* Are we at the beginning of a line, and line numbers are requested? */ + + if (newlines >= 0 && numbers) + { + next_line_num (); + bpout = stpcpy (bpout, line_num_print); + } + + /* Here CH cannot contain a newline character. */ + + /* The loops below continue until a newline character is found, + which means that the buffer is empty or that a proper newline + has been found. */ + + /* If quoting, i.e. at least one of -v, -e, or -t specified, + scan for chars that need conversion. */ + if (quote) + { + for (;;) + { + if (ch >= 32) + { + if (ch < 127) + *bpout++ = ch; + else if (ch == 127) + { + *bpout++ = '^'; + *bpout++ = '?'; + } + else + { + *bpout++ = 'M'; + *bpout++ = '-'; + if (ch >= 128 + 32) + { + if (ch < 128 + 127) + *bpout++ = ch - 128; + else + { + *bpout++ = '^'; + *bpout++ = '?'; + } + } + else + { + *bpout++ = '^'; + *bpout++ = ch - 128 + 64; + } + } + } + else if (ch == '\t' && output_tabs) + *bpout++ = '\t'; + else if (ch == '\n') + { + newlines = -1; + break; + } + else + { + *bpout++ = '^'; + *bpout++ = ch + 64; + } + + ch = *bpin++; + } + } + else + { + /* Not quoting, neither of -v, -e, or -t specified. */ + for (;;) + { + if (ch == '\t' && !output_tabs) + { + *bpout++ = '^'; + *bpout++ = ch + 64; + } + else if (ch != '\n') + *bpout++ = ch; + else + { + newlines = -1; + break; + } + + ch = *bpin++; + } + } + } +} + +/* This is gross, but necessary, because of the way close_stdout + works and because this program closes STDOUT_FILENO directly. */ +static void (*closeout_func) (void) = close_stdout; + +static void +close_stdout_wrapper (void) +{ + if (closeout_func) + (*closeout_func) (); +} + +int +main (int argc, char **argv) +{ + /* Optimal size of i/o operations of output. */ + size_t outsize; + + /* Optimal size of i/o operations of input. */ + size_t insize; + + /* Pointer to the input buffer. */ + char *inbuf; + + /* Pointer to the output buffer. */ + char *outbuf; + + int c; + + /* Index in argv to processed argument. */ + int argind; + + /* Device number of the output (file or whatever). */ + dev_t out_dev; + + /* I-node number of the output. */ + ino_t out_ino; + + /* Nonzero if the output file should not be the same as any input file. */ + int check_redirection = 1; + + /* Nonzero if we have ever read standard input. */ + int have_read_stdin = 0; + + struct stat stat_buf; + + /* Variables that are set according to the specified options. */ + int numbers = 0; + int numbers_at_empty_lines = 1; + int squeeze_empty_lines = 0; + int mark_line_ends = 0; + int quote = 0; + int output_tabs = 1; +#if O_BINARY + int binary_files = 0; + int binary_output = 0; +#endif + int file_open_mode = O_RDONLY; + +/* If nonzero, call cat, otherwise call simple_cat to do the actual work. */ + int options = 0; + + static struct option const long_options[] = + { + {"number-nonblank", no_argument, NULL, 'b'}, + {"number", no_argument, NULL, 'n'}, + {"squeeze-blank", no_argument, NULL, 's'}, + {"show-nonprinting", no_argument, NULL, 'v'}, + {"show-ends", no_argument, NULL, 'E'}, + {"show-tabs", no_argument, NULL, 'T'}, + {"show-all", no_argument, NULL, 'A'}, +#if O_BINARY + {"binary", no_argument, NULL, 'B'}, +#endif + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} + }; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + /* Arrange to close stdout if we exit via the + case_GETOPT_HELP_CHAR or case_GETOPT_VERSION_CHAR code. */ + atexit (close_stdout_wrapper); + + /* Parse command line options. */ + + while ((c = getopt_long (argc, argv, +#if O_BINARY + "benstuvABET" +#else + "benstuvAET" +#endif + , long_options, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + case 'b': + ++options; + numbers = 1; + numbers_at_empty_lines = 0; + break; + + case 'e': + ++options; + mark_line_ends = 1; + quote = 1; + break; + + case 'n': + ++options; + numbers = 1; + break; + + case 's': + ++options; + squeeze_empty_lines = 1; + break; + + case 't': + ++options; + output_tabs = 0; + quote = 1; + break; + + case 'u': + /* We provide the -u feature unconditionally. */ + break; + + case 'v': + ++options; + quote = 1; + break; + + case 'A': + ++options; + quote = 1; + mark_line_ends = 1; + output_tabs = 0; + break; + +#if O_BINARY + case 'B': + ++options; + binary_files = 1; + break; +#endif + + case 'E': + ++options; + mark_line_ends = 1; + break; + + case 'T': + ++options; + output_tabs = 0; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + /* Don't close stdout on exit from here on. */ + closeout_func = NULL; + + /* Get device, i-node number, and optimal blocksize of output. */ + + if (fstat (STDOUT_FILENO, &stat_buf) < 0) + error (EXIT_FAILURE, errno, _("standard output")); + + outsize = ST_BLKSIZE (stat_buf); + /* Input file can be output file for non-regular files. + fstat on pipes returns S_IFSOCK on some systems, S_IFIFO + on others, so the checking should not be done for those types, + and to allow things like cat < /dev/tty > /dev/tty, checking + is not done for device files either. */ + + if (S_ISREG (stat_buf.st_mode)) + { + out_dev = stat_buf.st_dev; + out_ino = stat_buf.st_ino; + } + else + { + check_redirection = 0; +#ifdef lint /* Suppress `used before initialized' warning. */ + out_dev = 0; + out_ino = 0; +#endif + } + +#if O_BINARY + /* We always read and write in BINARY mode, since this is the + best way to copy the files verbatim. Exceptions are when + they request line numbering, squeezing of empty lines or + marking lines' ends: then we use text I/O, because otherwise + -b, -s and -E would surprise users on DOS/Windows where a line + with only CR-LF is an empty line. (Besides, if they ask for + one of these options, they don't care much about the original + file contents anyway). */ + if ((!isatty (STDOUT_FILENO) + && !(numbers || squeeze_empty_lines || mark_line_ends)) + || binary_files) + { + /* Switch stdout to BINARY mode. */ + binary_output = 1; + SET_BINARY (STDOUT_FILENO); + /* When stdout is in binary mode, make sure all input files are + also read in binary mode. */ + file_open_mode |= O_BINARY; + } + else if (quote) + { + /* If they want to see the non-printables, let's show them + those CR characters as well, so make the input binary. + But keep console output in text mode, so that LF causes + both CR and LF on output, and the output is readable. */ + file_open_mode |= O_BINARY; + SET_BINARY (0); + + /* Setting stdin to binary switches the console device to + raw I/O, which also affects stdout to console. Undo that. */ + if (isatty (STDOUT_FILENO)) + setmode (STDOUT_FILENO, O_TEXT); + } +#endif + + /* Check if any of the input files are the same as the output file. */ + + /* Main loop. */ + + infile = "-"; + argind = optind; + + do + { + if (argind < argc) + infile = argv[argind]; + + if (infile[0] == '-' && infile[1] == 0) + { + have_read_stdin = 1; + input_desc = 0; + +#if O_BINARY + /* Switch stdin to BINARY mode if needed. */ + if (binary_output) + { + int tty_in = isatty (input_desc); + + /* If stdin is a terminal device, and it is the ONLY + input file (i.e. we didn't write anything to the + output yet), switch the output back to TEXT mode. + This is so "cat > xyzzy" creates a DOS-style text + file, like people expect. */ + if (tty_in && optind <= argc) + setmode (STDOUT_FILENO, O_TEXT); + else + { + SET_BINARY (input_desc); +# ifdef __DJGPP__ + /* This is DJGPP-specific. By default, switching console + to binary mode disables SIGINT. But we want terminal + reads to be interruptible. */ + if (tty_in) + __djgpp_set_ctrl_c (1); +# endif + } + } +#endif + } + else + { + input_desc = open (infile, file_open_mode); + if (input_desc < 0) + { + error (0, errno, "%s", infile); + exit_status = 1; + continue; + } + } + + if (fstat (input_desc, &stat_buf) < 0) + { + error (0, errno, "%s", infile); + exit_status = 1; + goto contin; + } + insize = ST_BLKSIZE (stat_buf); + + /* Compare the device and i-node numbers of this input file with + the corresponding values of the (output file associated with) + stdout, and skip this input file if they coincide. Input + files cannot be redirected to themselves. */ + + if (check_redirection + && stat_buf.st_dev == out_dev && stat_buf.st_ino == out_ino + && (input_desc != STDIN_FILENO)) + { + error (0, 0, _("%s: input file is output file"), infile); + exit_status = 1; + goto contin; + } + + /* Select which version of `cat' to use. If any options (more than -u, + --version, or --help) were specified, use `cat', otherwise use + `simple_cat'. */ + + if (options == 0) + { + insize = max (insize, outsize); + inbuf = xmalloc (insize); + + simple_cat (inbuf, insize); + } + else + { + inbuf = xmalloc (insize + 1); + + /* Why are (OUTSIZE - 1 + INSIZE * 4 + LINE_COUNTER_BUF_LEN) + bytes allocated for the output buffer? + + A test whether output needs to be written is done when the input + buffer empties or when a newline appears in the input. After + output is written, at most (OUTSIZE - 1) bytes will remain in the + buffer. Now INSIZE bytes of input is read. Each input character + may grow by a factor of 4 (by the prepending of M-^). If all + characters do, and no newlines appear in this block of input, we + will have at most (OUTSIZE - 1 + INSIZE * 4) bytes in the buffer. + If the last character in the preceding block of input was a + newline, a line number may be written (according to the given + options) as the first thing in the output buffer. (Done after the + new input is read, but before processing of the input begins.) + A line number requires seldom more than LINE_COUNTER_BUF_LEN + positions. */ + + outbuf = xmalloc (outsize - 1 + insize * 4 + LINE_COUNTER_BUF_LEN); + + cat (inbuf, insize, outbuf, outsize, quote, + output_tabs, numbers, numbers_at_empty_lines, mark_line_ends, + squeeze_empty_lines); + + free (outbuf); + } + + free (inbuf); + + contin: + if (!STREQ (infile, "-") && close (input_desc) < 0) + { + error (0, errno, "%s", infile); + exit_status = 1; + } + } + while (++argind < argc); + + if (have_read_stdin && close (STDIN_FILENO) < 0) + error (EXIT_FAILURE, errno, _("closing standard input")); + + if (close (STDOUT_FILENO) < 0) + error (EXIT_FAILURE, errno, _("closing standard output")); + + exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/checksum.h b/src/apps/bin/coreutils-5.0/src/checksum.h new file mode 100644 index 0000000000..f3978bdfbb --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/checksum.h @@ -0,0 +1,15 @@ +#include + +#include +#include + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + ALG_UNSPECIFIED = 0, + ALG_MD5 = CHAR_MAX + 1, + ALG_SHA1 +}; + +extern int algorithm; diff --git a/src/apps/bin/coreutils-5.0/src/chgrp.c b/src/apps/bin/coreutils-5.0/src/chgrp.c new file mode 100644 index 0000000000..5727b27207 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/chgrp.c @@ -0,0 +1,237 @@ +/* chgrp -- change group ownership of files + Copyright (C) 89, 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie . */ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "lchown.h" +#include "group-member.h" +#include "quote.h" +#include "xstrtol.h" +#include "chown-core.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "chgrp" + +#define AUTHORS "David MacKenzie" + +/* MAXUID may come from limits.h *or* sys/params.h (via system.h) above. */ +#ifndef MAXUID +# define MAXUID UID_T_MAX +#endif +#ifndef MAXGID +# define MAXGID GID_T_MAX +#endif + +#ifndef _POSIX_VERSION +struct group *getgrnam (); +#endif + +#if ! HAVE_ENDGRENT +# define endgrent() ((void) 0) +#endif + +/* The name the program was run with. */ +char *program_name; + +/* The argument to the --reference option. Use the group ID of this file. + This file must exist. */ +static char *reference_file; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + REFERENCE_FILE_OPTION = CHAR_MAX + 1, + DEREFERENCE_OPTION +}; + +static struct option const long_options[] = +{ + {"recursive", no_argument, 0, 'R'}, + {"changes", no_argument, 0, 'c'}, + {"dereference", no_argument, 0, DEREFERENCE_OPTION}, + {"no-dereference", no_argument, 0, 'h'}, + {"quiet", no_argument, 0, 'f'}, + {"silent", no_argument, 0, 'f'}, + {"reference", required_argument, 0, REFERENCE_FILE_OPTION}, + {"verbose", no_argument, 0, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0} +}; + +/* Set *G according to NAME. */ + +static void +parse_group (const char *name, gid_t *g) +{ + struct group *grp; + + if (*name == '\0') + error (EXIT_FAILURE, 0, _("cannot change to null group")); + + grp = getgrnam (name); + if (grp == NULL) + { + strtol_error s_err; + unsigned long int tmp_long; + + if (!ISDIGIT (*name)) + error (EXIT_FAILURE, 0, _("invalid group name %s"), quote (name)); + + s_err = xstrtoul (name, NULL, 0, &tmp_long, NULL); + if (s_err != LONGINT_OK) + STRTOL_FATAL_ERROR (name, _("group number"), s_err); + + if (tmp_long > MAXGID) + error (EXIT_FAILURE, 0, _("invalid group number %s"), quote (name)); + + *g = tmp_long; + } + else + *g = grp->gr_gid; + endgrent (); /* Save a file descriptor. */ +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... GROUP FILE...\n\ + or: %s [OPTION]... --reference=RFILE FILE...\n\ +"), + program_name, program_name); + fputs (_("\ +Change the group membership of each FILE to GROUP.\n\ +\n\ + -c, --changes like verbose but report only when a change is made\n\ + --dereference affect the referent of each symbolic link, rather\n\ + than the symbolic link itself\n\ +"), stdout); + fputs (_("\ + -h, --no-dereference affect symbolic links instead of any referenced file\n\ + (available only on systems that can change the\n\ + ownership of a symlink)\n\ +"), stdout); + fputs (_("\ + -f, --silent, --quiet suppress most error messages\n\ + --reference=RFILE use RFILE's group rather than the specified\n\ + GROUP value\n\ + -R, --recursive operate on files and directories recursively\n\ + -v, --verbose output a diagnostic for every file processed\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + gid_t gid; + int errors = 0; + int optc; + struct Chown_option chopt; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + chopt_init (&chopt); + + while ((optc = getopt_long (argc, argv, "Rcfhv", long_options, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + case REFERENCE_FILE_OPTION: + reference_file = optarg; + break; + case DEREFERENCE_OPTION: + chopt.dereference = DEREF_ALWAYS; + break; + case 'R': + chopt.recurse = 1; + break; + case 'c': + chopt.verbosity = V_changes_only; + break; + case 'f': + chopt.force_silent = 1; + break; + case 'h': + chopt.dereference = DEREF_NEVER; + break; + case 'v': + chopt.verbosity = V_high; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + } + + if (argc - optind + (reference_file ? 1 : 0) <= 1) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + if (reference_file) + { + struct stat ref_stats; + if (stat (reference_file, &ref_stats)) + error (EXIT_FAILURE, errno, _("failed to get attributes of %s"), + quote (reference_file)); + + chopt.group_name = gid_to_name (ref_stats.st_gid); + gid = ref_stats.st_gid; + } + else + { + chopt.group_name = argv[optind++]; + parse_group (chopt.group_name, &gid); + } + + for (; optind < argc; ++optind) + errors |= change_file_owner (1, argv[optind], (uid_t) -1, gid, + (uid_t) -1, (gid_t) -1, &chopt); + + chopt_free (&chopt); + + exit (errors); +} diff --git a/src/apps/bin/coreutils-5.0/src/chmod.c b/src/apps/bin/coreutils-5.0/src/chmod.c new file mode 100644 index 0000000000..be8262b855 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/chmod.c @@ -0,0 +1,372 @@ +/* chmod -- change permission modes of files + Copyright (C) 89, 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie */ + +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "filemode.h" +#include "modechange.h" +#include "quote.h" +#include "savedir.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "chmod" + +#define AUTHORS "David MacKenzie" + +enum Change_status +{ + CH_SUCCEEDED, + CH_FAILED, + CH_NO_CHANGE_REQUESTED +}; + +enum Verbosity +{ + /* Print a message for each file that is processed. */ + V_high, + + /* Print a message for each file whose attributes we change. */ + V_changes_only, + + /* Do not be verbose. This is the default. */ + V_off +}; + +static int change_dir_mode (const char *dir, const struct mode_change *changes); + +/* The name the program was run with. */ +char *program_name; + +/* If nonzero, change the modes of directories recursively. */ +static int recurse; + +/* If nonzero, force silence (no error messages). */ +static int force_silent; + +/* Level of verbosity. */ +static enum Verbosity verbosity = V_off; + +/* The argument to the --reference option. Use the owner and group IDs + of this file. This file must exist. */ +static char *reference_file; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + REFERENCE_FILE_OPTION = CHAR_MAX + 1 +}; + +static struct option const long_options[] = +{ + {"recursive", no_argument, 0, 'R'}, + {"changes", no_argument, 0, 'c'}, + {"silent", no_argument, 0, 'f'}, + {"quiet", no_argument, 0, 'f'}, + {"reference", required_argument, 0, REFERENCE_FILE_OPTION}, + {"verbose", no_argument, 0, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0} +}; + +static int +mode_changed (const char *file, mode_t old_mode) +{ + struct stat new_stats; + + if (stat (file, &new_stats)) + { + if (force_silent == 0) + error (0, errno, _("getting new attributes of %s"), quote (file)); + return 0; + } + + return old_mode != new_stats.st_mode; +} + +/* Tell the user how/if the MODE of FILE has been changed. + CHANGED describes what (if anything) has happened. */ + +static void +describe_change (const char *file, mode_t mode, + enum Change_status changed) +{ + char perms[11]; /* "-rwxrwxrwx" ls-style modes. */ + const char *fmt; + + mode_string (mode, perms); + perms[10] = '\0'; /* `mode_string' does not null terminate. */ + switch (changed) + { + case CH_SUCCEEDED: + fmt = _("mode of %s changed to %04lo (%s)\n"); + break; + case CH_FAILED: + fmt = _("failed to change mode of %s to %04lo (%s)\n"); + break; + case CH_NO_CHANGE_REQUESTED: + fmt = _("mode of %s retained as %04lo (%s)\n"); + break; + default: + abort (); + } + printf (fmt, quote (file), + (unsigned long) (mode & CHMOD_MODE_BITS), &perms[1]); +} + +/* Change the mode of FILE according to the list of operations CHANGES. + If DEREF_SYMLINK is nonzero and FILE is a symbolic link, change the + mode of the referenced file. If DEREF_SYMLINK is zero, ignore symbolic + links. Return 0 if successful, 1 if errors occurred. */ + +static int +change_file_mode (const char *file, const struct mode_change *changes, + const int deref_symlink) +{ + struct stat file_stats; + mode_t newmode; + int errors = 0; + int fail; + int saved_errno; + + if (deref_symlink ? stat (file, &file_stats) : lstat (file, &file_stats)) + { + if (force_silent == 0) + error (0, errno, _("failed to get attributes of %s"), quote (file)); + return 1; + } + +#ifdef S_ISLNK + if (S_ISLNK (file_stats.st_mode)) + return 0; +#endif + + newmode = mode_adjust (file_stats.st_mode, changes); + + fail = chmod (file, newmode); + saved_errno = errno; + + if (verbosity == V_high + || (verbosity == V_changes_only + && !fail && mode_changed (file, file_stats.st_mode))) + describe_change (file, newmode, (fail ? CH_FAILED : CH_SUCCEEDED)); + + if (fail) + { + if (force_silent == 0) + error (0, saved_errno, _("changing permissions of %s"), + quote (file)); + errors = 1; + } + + if (recurse && S_ISDIR (file_stats.st_mode)) + errors |= change_dir_mode (file, changes); + return errors; +} + +/* Recursively change the modes of the files in directory DIR + according to the list of operations CHANGES. + Return 0 if successful, 1 if errors occurred. */ + +static int +change_dir_mode (const char *dir, const struct mode_change *changes) +{ + char *name_space, *namep; + char *path; /* Full path of each entry to process. */ + unsigned dirlength; /* Length of DIR and '\0'. */ + unsigned filelength; /* Length of each pathname to process. */ + unsigned pathlength; /* Bytes allocated for `path'. */ + int errors = 0; + + name_space = savedir (dir); + if (name_space == NULL) + { + if (force_silent == 0) + error (0, errno, "%s", quote (dir)); + return 1; + } + + dirlength = strlen (dir) + 1; /* + 1 is for the trailing '/'. */ + pathlength = dirlength + 1; + /* Give `path' a dummy value; it will be reallocated before first use. */ + path = xmalloc (pathlength); + strcpy (path, dir); + path[dirlength - 1] = '/'; + + for (namep = name_space; *namep; namep += filelength - dirlength) + { + filelength = dirlength + strlen (namep) + 1; + if (filelength > pathlength) + { + pathlength = filelength * 2; + path = xrealloc (path, pathlength); + } + strcpy (path + dirlength, namep); + errors |= change_file_mode (path, changes, 0); + } + free (path); + free (name_space); + return errors; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... MODE[,MODE]... FILE...\n\ + or: %s [OPTION]... OCTAL-MODE FILE...\n\ + or: %s [OPTION]... --reference=RFILE FILE...\n\ +"), + program_name, program_name, program_name); + fputs (_("\ +Change the mode of each FILE to MODE.\n\ +\n\ + -c, --changes like verbose but report only when a change is made\n\ + -f, --silent, --quiet suppress most error messages\n\ + -v, --verbose output a diagnostic for every file processed\n\ + --reference=RFILE use RFILE's mode instead of MODE values\n\ + -R, --recursive change files and directories recursively\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +Each MODE is one or more of the letters ugoa, one of the symbols +-= and\n\ +one or more of the letters rwxXstugo.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +/* Parse the ASCII mode given on the command line into a linked list + of `struct mode_change' and apply that to each file argument. */ + +int +main (int argc, char **argv) +{ + struct mode_change *changes; + int errors = 0; + int modeind = 0; /* Index of the mode argument in `argv'. */ + int thisind; + int c; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + recurse = force_silent = 0; + + while (1) + { + thisind = optind ? optind : 1; + + c = getopt_long (argc, argv, "RcfvrwxXstugoa,+-=", long_options, NULL); + if (c == -1) + break; + + switch (c) + { + case 0: + break; + case 'r': + case 'w': + case 'x': + case 'X': + case 's': + case 't': + case 'u': + case 'g': + case 'o': + case 'a': + case ',': + case '+': + case '-': + case '=': + if (modeind != 0 && modeind != thisind) + { + static char char_string[2] = {0, 0}; + char_string[0] = c; + error (EXIT_FAILURE, 0, _("invalid character %s in mode string %s"), + quote_n (0, char_string), quote_n (1, argv[thisind])); + } + modeind = thisind; + break; + case REFERENCE_FILE_OPTION: + reference_file = optarg; + break; + case 'R': + recurse = 1; + break; + case 'c': + verbosity = V_changes_only; + break; + case 'f': + force_silent = 1; + break; + case 'v': + verbosity = V_high; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + } + + if (modeind == 0 && reference_file == NULL) + modeind = optind++; + + if (optind >= argc) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + changes = (reference_file ? mode_create_from_ref (reference_file) + : mode_compile (argv[modeind], MODE_MASK_ALL)); + + if (changes == MODE_INVALID) + error (EXIT_FAILURE, 0, + _("invalid mode string: %s"), quote (argv[modeind])); + else if (changes == MODE_MEMORY_EXHAUSTED) + xalloc_die (); + else if (changes == MODE_BAD_REFERENCE) + error (EXIT_FAILURE, errno, _("failed to get attributes of %s"), + quote (reference_file)); + + for (; optind < argc; ++optind) + errors |= change_file_mode (argv[optind], changes, 1); + + exit (errors); +} diff --git a/src/apps/bin/coreutils-5.0/src/chown-core.c b/src/apps/bin/coreutils-5.0/src/chown-core.c new file mode 100644 index 0000000000..b38efaa895 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/chown-core.c @@ -0,0 +1,362 @@ +/* chown-core.c -- core functions for changing ownership. + Copyright (C) 2000, 2002 Free Software Foundation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Extracted from chown.c/chgrp.c and librarified by Jim Meyering. */ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "lchown.h" +#include "quote.h" +#include "savedir.h" +#include "chown-core.h" + +/* The number of decimal digits required to represent the largest value of + type `unsigned int'. This is enough for an 8-byte unsigned int type. */ +#define UINT_MAX_DECIMAL_DIGITS 20 + +#ifndef _POSIX_VERSION +struct group *getgrnam (); +struct group *getgrgid (); +#endif + +int lstat (); + +void +chopt_init (struct Chown_option *chopt) +{ + chopt->verbosity = V_off; + chopt->dereference = DEREF_NEVER; + chopt->recurse = 0; + chopt->force_silent = 0; + chopt->user_name = 0; + chopt->group_name = 0; +} + +void +chopt_free (struct Chown_option *chopt) +{ + /* Deliberately do not free chopt->user_name or ->group_name. + They're not always allocated. */ +} + +/* Convert N to a string, and return a pointer to that string in memory + allocated from the heap. */ + +static char * +uint_to_string (unsigned int n) +{ + char buf[UINT_MAX_DECIMAL_DIGITS + 1]; + char *p = buf + sizeof buf; + + *--p = '\0'; + + do + *--p = '0' + (n % 10); + while ((n /= 10) != 0); + + return xstrdup (p); +} + +/* Convert the numeric group-id, GID, to a string stored in xmalloc'd memory, + and return it. If there's no corresponding group name, use the decimal + representation of the ID. */ + +char * +gid_to_name (gid_t gid) +{ + struct group *grp = getgrgid (gid); + return grp ? xstrdup (grp->gr_name) : uint_to_string (gid); +} + +/* Convert the numeric user-id, UID, to a string stored in xmalloc'd memory, + and return it. If there's no corresponding user name, use the decimal + representation of the ID. */ + +char * +uid_to_name (uid_t uid) +{ + struct passwd *pwd = getpwuid (uid); + return pwd ? xstrdup (pwd->pw_name) : uint_to_string (uid); +} + +/* Tell the user how/if the user and group of FILE have been changed. + If USER is NULL, give the group-oriented messages. + CHANGED describes what (if anything) has happened. */ + +static void +describe_change (const char *file, enum Change_status changed, + char const *user, char const *group) +{ + const char *fmt; + char *spec; + int spec_allocated = 0; + + if (changed == CH_NOT_APPLIED) + { + printf (_("neither symbolic link %s nor referent has been changed\n"), + quote (file)); + return; + } + + if (user) + { + if (group) + { + spec = xmalloc (strlen (user) + 1 + strlen (group) + 1); + stpcpy (stpcpy (stpcpy (spec, user), ":"), group); + spec_allocated = 1; + } + else + { + spec = (char *) user; + } + } + else + { + spec = (char *) group; + } + + switch (changed) + { + case CH_SUCCEEDED: + fmt = (user + ? _("changed ownership of %s to %s\n") + : _("changed group of %s to %s\n")); + break; + case CH_FAILED: + fmt = (user + ? _("failed to change ownership of %s to %s\n") + : _("failed to change group of %s to %s\n")); + break; + case CH_NO_CHANGE_REQUESTED: + fmt = (user + ? _("ownership of %s retained as %s\n") + : _("group of %s retained as %s\n")); + break; + default: + abort (); + } + + printf (fmt, quote (file), spec); + + if (spec_allocated) + free (spec); +} + +/* Recursively change the ownership of the files in directory DIR to user-id, + UID, and group-id, GID, according to the options specified by CHOPT. + Return 0 if successful, 1 if errors occurred. */ + +static int +change_dir_owner (const char *dir, uid_t uid, gid_t gid, + uid_t old_uid, gid_t old_gid, + struct Chown_option const *chopt) +{ + char *name_space, *namep; + char *path; /* Full path of each entry to process. */ + unsigned dirlength; /* Length of `dir' and '\0'. */ + unsigned filelength; /* Length of each pathname to process. */ + unsigned pathlength; /* Bytes allocated for `path'. */ + int errors = 0; + + name_space = savedir (dir); + if (name_space == NULL) + { + if (chopt->force_silent == 0) + error (0, errno, "%s", quote (dir)); + return 1; + } + + dirlength = strlen (dir) + 1; /* + 1 is for the trailing '/'. */ + pathlength = dirlength + 1; + /* Give `path' a dummy value; it will be reallocated before first use. */ + path = xmalloc (pathlength); + strcpy (path, dir); + path[dirlength - 1] = '/'; + + for (namep = name_space; *namep; namep += filelength - dirlength) + { + filelength = dirlength + strlen (namep) + 1; + if (filelength > pathlength) + { + pathlength = filelength * 2; + path = xrealloc (path, pathlength); + } + strcpy (path + dirlength, namep); + errors |= change_file_owner (0, path, uid, gid, old_uid, old_gid, + chopt); + } + free (path); + free (name_space); + return errors; +} + +/* Change the ownership of FILE to user-id, UID, and group-id, GID, + provided it presently has owner OLD_UID and group OLD_GID. + Honor the options specified by CHOPT. + If FILE is a directory and -R is given, recurse. + Return 0 if successful, 1 if errors occurred. */ + +int +change_file_owner (int cmdline_arg, const char *file, uid_t uid, gid_t gid, + uid_t old_uid, gid_t old_gid, + struct Chown_option const *chopt) +{ + struct stat file_stats; + uid_t new_uid; + gid_t new_gid; + int errors = 0; + int is_symlink; + int is_directory; + + if (lstat (file, &file_stats)) + { + if (chopt->force_silent == 0) + error (0, errno, _("failed to get attributes of %s"), quote (file)); + return 1; + } + + /* If it's a symlink and we're dereferencing, then use stat + to get the attributes of the referent. */ + if (S_ISLNK (file_stats.st_mode)) + { + if (chopt->dereference == DEREF_ALWAYS + && stat (file, &file_stats)) + { + if (chopt->force_silent == 0) + error (0, errno, _("failed to get attributes of %s"), quote (file)); + return 1; + } + + is_symlink = 1; + + /* With -R, don't traverse through symlinks-to-directories. + But of course, this will all change with POSIX's new + -H, -L, -P options. */ + is_directory = 0; + } + else + { + is_symlink = 0; + is_directory = S_ISDIR (file_stats.st_mode); + } + + if ((old_uid == (uid_t) -1 || file_stats.st_uid == old_uid) + && (old_gid == (gid_t) -1 || file_stats.st_gid == old_gid)) + { + new_uid = (uid == (uid_t) -1 ? file_stats.st_uid : uid); + new_gid = (gid == (gid_t) -1 ? file_stats.st_gid : gid); + if (new_uid != file_stats.st_uid || new_gid != file_stats.st_gid) + { + int fail; + int symlink_changed = 1; + int saved_errno; + int called_lchown = 0; + + if (is_symlink) + { + if (chopt->dereference == DEREF_NEVER) + { + called_lchown = 1; + fail = lchown (file, new_uid, new_gid); + + /* Ignore the failure if it's due to lack of support (ENOSYS) + and this is not a command line argument. */ + if (!cmdline_arg && fail && errno == ENOSYS) + { + fail = 0; + symlink_changed = 0; + } + } + else if (chopt->dereference == DEREF_ALWAYS) + { + /* Applying chown to a symlink and expecting it to affect + the referent is not portable. So instead, open the + file and use fchown on the resulting descriptor. */ + int fd = open (file, O_RDONLY | O_NONBLOCK | O_NOCTTY); + fail = (fd == -1 ? 1 : fchown (fd, new_uid, new_gid)); + } + else + { + /* FIXME */ + abort (); + } + } + else + { + fail = chown (file, new_uid, new_gid); + } + saved_errno = errno; + + if (chopt->verbosity == V_high + || (chopt->verbosity == V_changes_only && !fail)) + { + enum Change_status ch_status = (! symlink_changed + ? CH_NOT_APPLIED + : (fail + ? CH_FAILED : CH_SUCCEEDED)); + describe_change (file, ch_status, + chopt->user_name, chopt->group_name); + } + + if (fail) + { + if (chopt->force_silent == 0) + error (0, saved_errno, (uid != (uid_t) -1 + ? _("changing ownership of %s") + : _("changing group of %s")), + quote (file)); + errors = 1; + } + else + { + /* The change succeeded. On some systems, the chown function + resets the `special' permission bits. When run by a + `privileged' user, this program must ensure that at least + the set-uid and set-group ones are still set. */ + if (file_stats.st_mode & ~(S_IFMT | S_IRWXUGO) + /* If we called lchown above (which means this is a symlink), + then skip it. */ + && ! called_lchown) + { + if (chmod (file, file_stats.st_mode)) + { + error (0, saved_errno, + _("unable to restore permissions of %s"), + quote (file)); + fail = 1; + } + } + } + } + else if (chopt->verbosity == V_high) + { + describe_change (file, CH_NO_CHANGE_REQUESTED, + chopt->user_name, chopt->group_name); + } + } + + if (chopt->recurse && is_directory) + errors |= change_dir_owner (file, uid, gid, old_uid, old_gid, chopt); + return errors; +} diff --git a/src/apps/bin/coreutils-5.0/src/chown-core.h b/src/apps/bin/coreutils-5.0/src/chown-core.h new file mode 100644 index 0000000000..0e2a17e9b4 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/chown-core.h @@ -0,0 +1,89 @@ +/* chown-core.h -- types and prototypes shared by chown and chgrp. + Copyright (C) 2000, 2003 Free Software Foundation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef CHOWN_CORE_H +# define CHOWN_CORE_H + +enum Change_status +{ + CH_NOT_APPLIED = 1, + CH_SUCCEEDED, + CH_FAILED, + CH_NO_CHANGE_REQUESTED +}; + +enum Verbosity +{ + /* Print a message for each file that is processed. */ + V_high, + + /* Print a message for each file whose attributes we change. */ + V_changes_only, + + /* Do not be verbose. This is the default. */ + V_off +}; + +enum Dereference_symlink +{ + DEREF_UNDEFINED = 1, + DEREF_NEVER, /* -P */ + DEREF_COMMAND_LINE_ARGUMENTS, /* -H */ + DEREF_ALWAYS /* -L */ +}; + +struct Chown_option +{ + /* Level of verbosity. */ + enum Verbosity verbosity; + + /* If nonzero, change the ownership of directories recursively. */ + int recurse; + + /* This is useful only on systems with support for changing the + ownership of symbolic links. */ + enum Dereference_symlink dereference; + + /* If nonzero, force silence (no error messages). */ + int force_silent; + + /* The name of the user to which ownership of the files is being given. */ + char *user_name; + + /* The name of the group to which ownership of the files is being given. */ + char *group_name; +}; + +void +chopt_init (struct Chown_option *); + +void +chopt_free (struct Chown_option *); + +char * +gid_to_name (gid_t); + +char * +uid_to_name (uid_t); + +int +change_file_owner (int, const char *, + uid_t, gid_t, + uid_t, gid_t, + struct Chown_option const *); + +#endif /* CHOWN_CORE_H */ diff --git a/src/apps/bin/coreutils-5.0/src/chown.c b/src/apps/bin/coreutils-5.0/src/chown.c new file mode 100644 index 0000000000..0a56096206 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/chown.c @@ -0,0 +1,249 @@ +/* chown -- change user and group ownership of files + Copyright (C) 89, 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + | user + | unchanged explicit + -------------|-------------------------+-------------------------| + g unchanged | --- | chown u | + r |-------------------------+-------------------------| + o explicit | chgrp g or chown .g | chown u.g | + u |-------------------------+-------------------------| + p from passwd| --- | chown u. | + |-------------------------+-------------------------| + + Written by David MacKenzie . */ + +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "lchown.h" +#include "quote.h" +#include "chown-core.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "chown" + +#define AUTHORS "David MacKenzie" + +#ifndef _POSIX_VERSION +struct passwd *getpwnam (); +struct group *getgrnam (); +struct group *getgrgid (); +#endif + +#if ! HAVE_ENDPWENT +# define endpwent() ((void) 0) +#endif + +char *parse_user_spec (); + +/* The name the program was run with. */ +char *program_name; + +/* The argument to the --reference option. Use the owner and group IDs + of this file. This file must exist. */ +static char *reference_file; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + REFERENCE_FILE_OPTION = CHAR_MAX + 1, + DEREFERENCE_OPTION, + FROM_OPTION +}; + +static struct option const long_options[] = +{ + {"recursive", no_argument, 0, 'R'}, + {"changes", no_argument, 0, 'c'}, + {"dereference", no_argument, 0, DEREFERENCE_OPTION}, + {"from", required_argument, 0, FROM_OPTION}, + {"no-dereference", no_argument, 0, 'h'}, + {"quiet", no_argument, 0, 'f'}, + {"silent", no_argument, 0, 'f'}, + {"reference", required_argument, 0, REFERENCE_FILE_OPTION}, + {"verbose", no_argument, 0, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... OWNER[:[GROUP]] FILE...\n\ + or: %s [OPTION]... :GROUP FILE...\n\ + or: %s [OPTION]... --reference=RFILE FILE...\n\ +"), + program_name, program_name, program_name); + fputs (_("\ +Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\ +\n\ + -c, --changes like verbose but report only when a change is made\n\ + --dereference affect the referent of each symbolic link, rather\n\ + than the symbolic link itself\n\ +"), stdout); + fputs (_("\ + -h, --no-dereference affect symbolic links instead of any referenced file\n\ + (available only on systems that can change the\n\ + ownership of a symlink)\n\ +"), stdout); + fputs (_("\ + --from=CURRENT_OWNER:CURRENT_GROUP\n\ + change the owner and/or group of each file only if\n\ + its current owner and/or group match those specified\n\ + here. Either may be omitted, in which case a match\n\ + is not required for the omitted attribute.\n\ +"), stdout); + fputs (_("\ + -f, --silent, --quiet suppress most error messages\n\ + --reference=RFILE use RFILE's owner and group rather than\n\ + the specified OWNER:GROUP values\n\ + -R, --recursive operate on files and directories recursively\n\ + -v, --verbose output a diagnostic for every file processed\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +Owner is unchanged if missing. Group is unchanged if missing, but changed\n\ +to login group if implied by a `:'. OWNER and GROUP may be numeric as well\n\ +as symbolic.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + uid_t uid = (uid_t) -1; /* New uid; -1 if not to be changed. */ + gid_t gid = (uid_t) -1; /* New gid; -1 if not to be changed. */ + uid_t old_uid = (uid_t) -1; /* Old uid; -1 if unrestricted. */ + gid_t old_gid = (uid_t) -1; /* Old gid; -1 if unrestricted. */ + struct Chown_option chopt; + + int errors = 0; + int optc; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + chopt_init (&chopt); + + while ((optc = getopt_long (argc, argv, "Rcfhv", long_options, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + case REFERENCE_FILE_OPTION: + reference_file = optarg; + break; + case DEREFERENCE_OPTION: + chopt.dereference = DEREF_ALWAYS; + break; + case FROM_OPTION: + { + char *u_dummy, *g_dummy; + const char *e = parse_user_spec (optarg, + &old_uid, &old_gid, + &u_dummy, &g_dummy); + if (e) + error (EXIT_FAILURE, 0, "%s: %s", quote (optarg), e); + break; + } + case 'R': + chopt.recurse = 1; + break; + case 'c': + chopt.verbosity = V_changes_only; + break; + case 'f': + chopt.force_silent = 1; + break; + case 'h': + chopt.dereference = DEREF_NEVER; + break; + case 'v': + chopt.verbosity = V_high; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + } + + if (argc - optind + (reference_file ? 1 : 0) <= 1) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + if (reference_file) + { + struct stat ref_stats; + + if (stat (reference_file, &ref_stats)) + error (EXIT_FAILURE, errno, _("failed to get attributes of %s"), + quote (reference_file)); + + uid = ref_stats.st_uid; + gid = ref_stats.st_gid; + chopt.user_name = uid_to_name (ref_stats.st_uid); + chopt.group_name = gid_to_name (ref_stats.st_gid); + } + else + { + const char *e = parse_user_spec (argv[optind], &uid, &gid, + &chopt.user_name, &chopt.group_name); + if (e) + error (EXIT_FAILURE, 0, "%s: %s", quote (argv[optind]), e); + + /* FIXME: set it to the empty string? */ + if (chopt.user_name == NULL) + chopt.user_name = ""; + + optind++; + } + + for (; optind < argc; ++optind) + errors |= change_file_owner (1, argv[optind], uid, gid, + old_uid, old_gid, &chopt); + + chopt_free (&chopt); + + exit (errors); +} diff --git a/src/apps/bin/coreutils-5.0/src/chroot.c b/src/apps/bin/coreutils-5.0/src/chroot.c new file mode 100644 index 0000000000..cbec705c2d --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/chroot.c @@ -0,0 +1,112 @@ +/* chroot -- run command or shell with special root directory + Copyright (C) 95, 96, 1997, 1999-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Roland McGrath. */ + +#include +#include +#include + +#include "system.h" +#include "long-options.h" +#include "error.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "chroot" + +#define AUTHORS "Roland McGrath" + +/* The name this program was run with, for error messages. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s NEWROOT [COMMAND...]\n\ + or: %s OPTION\n\ +"), program_name, program_name); + fputs (_("\ +Run COMMAND with root directory set to NEWROOT.\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +If no command is given, run ``${SHELL} -i'' (default: /bin/sh).\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + if (argc == 1) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + if (chroot (argv[1])) + error (EXIT_FAILURE, errno, + _("cannot change root directory to %s"), argv[1]); + + if (chdir ("/")) + error (EXIT_FAILURE, errno, _("cannot chdir to root directory")); + + if (argc == 2) + { + /* No command. Run an interactive shell. */ + char *shell = getenv ("SHELL"); + if (shell == NULL) + shell = "/bin/sh"; + argv[0] = shell; + argv[1] = "-i"; + } + else + { + /* The following arguments give the command. */ + argv += 2; + } + + /* Execute the given command. */ + execvp (argv[0], argv); + + { + int exit_status = (errno == ENOENT ? 127 : 126); + error (0, errno, "%s", argv[0]); + exit (exit_status); + } +} diff --git a/src/apps/bin/coreutils-5.0/src/cksum.c b/src/apps/bin/coreutils-5.0/src/cksum.c new file mode 100644 index 0000000000..0bbba3a3c3 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/cksum.c @@ -0,0 +1,341 @@ +/* cksum -- calculate and print POSIX checksums and sizes of files + Copyright (C) 92, 1995-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Q. Frank Xia, qx@math.columbia.edu. + Cosmetic changes and reorganization by David MacKenzie, djm@gnu.ai.mit.edu. + + Usage: cksum [file...] + + The code segment between "#ifdef CRCTAB" and "#else" is the code + which calculates the "crctab". It is included for those who want + verify the correctness of the "crctab". To recreate the "crctab", + do following: + + cc -DCRCTAB -o crctab cksum.c + crctab > crctab.h + + As Bruce Evans pointed out to me, the crctab in the sample C code + in 4.9.10 Rationale of P1003.2/D11.2 is represented in reversed order. + Namely, 0x01 is represented as 0x80, 0x02 is represented as 0x40, etc. + The generating polynomial is crctab[0x80]=0xedb88320 instead of + crctab[1]=0x04C11DB7. But the code works only for a non-reverse order + crctab. Therefore, the sample implementation is wrong. + + This software is compatible with neither the System V nor the BSD + `sum' program. It is supposed to conform to P1003.2/D11.2, + except foreign language interface (4.9.5.3 of P1003.2/D11.2) support. + Any inconsistency with the standard except 4.9.5.3 is a bug. */ + +#include + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "cksum" + +#define AUTHORS "Q. Frank Xia" + +#include +#include +#include "system.h" + +#if !defined UINT_FAST32_MAX && !defined uint_fast32_t +# define uint_fast32_t unsigned int +#endif + +#ifdef CRCTAB + +# define BIT(x) ((uint_fast32_t) 1 << (x)) +# define SBIT BIT (31) + +/* The generating polynomial is + + 32 26 23 22 16 12 11 10 8 7 5 4 2 1 + G(X)=X + X + X + X + X + X + X + X + X + X + X + X + X + X + 1 + + The i bit in GEN is set if X^i is a summand of G(X) except X^32. */ + +# define GEN (BIT (26) | BIT (23) | BIT (22) | BIT (16) | BIT (12) \ + | BIT (11) | BIT (10) | BIT (8) | BIT (7) | BIT (5) \ + | BIT (4) | BIT (2) | BIT (1) | BIT (0)) + +static uint_fast32_t r[8]; + +static void +fill_r (void) +{ + int i; + + r[0] = GEN; + for (i = 1; i < 8; i++) + r[i] = (r[i - 1] << 1) ^ ((r[i - 1] & SBIT) ? GEN : 0); +} + +static uint_fast32_t +remainder (int m) +{ + uint_fast32_t rem = 0; + int i; + + for (i = 0; i < 8; i++) + if (BIT (i) & m) + rem ^= r[i]; + + return rem & 0xFFFFFFFF; /* Make it run on 64-bit machine. */ +} + +int +main (void) +{ + int i; + + fill_r (); + printf ("static uint_fast32_t crctab[256] =\n{\n 0x0"); + for (i = 0; i < 51; i++) + { + printf (",\n 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X", + remainder (i * 5 + 1), remainder (i * 5 + 2), + remainder (i * 5 + 3), remainder (i * 5 + 4), + remainder (i * 5 + 5)); + } + printf ("\n};\n"); + exit (EXIT_SUCCESS); +} + +#else /* !CRCTAB */ + +# include +# include "closeout.h" +# include "long-options.h" +# include "error.h" +# include "inttostr.h" + +/* Number of bytes to read at once. */ +# define BUFLEN (1 << 16) + +/* The name this program was run with. */ +char *program_name; + +static struct option const long_options[] = +{ + {0, 0, 0, 0} +}; + +static uint_fast32_t crctab[256] = +{ + 0x0, + 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 +}; + +/* Nonzero if any of the files read were the standard input. */ +static int have_read_stdin; + +/* Calculate and print the checksum and length in bytes + of file FILE, or of the standard input if FILE is "-". + If PRINT_NAME is nonzero, print FILE next to the checksum and size. + Return 0 if successful, -1 if an error occurs. */ + +static int +cksum (const char *file, int print_name) +{ + unsigned char buf[BUFLEN]; + uint_fast32_t crc = 0; + uintmax_t length = 0; + size_t bytes_read; + register FILE *fp; + char length_buf[INT_BUFSIZE_BOUND (uintmax_t)]; + char const *hp; + + if (STREQ (file, "-")) + { + fp = stdin; + have_read_stdin = 1; + } + else + { + fp = fopen (file, "r"); + if (fp == NULL) + { + error (0, errno, "%s", file); + return -1; + } + } + + /* Read input in BINARY mode, unless it is a console device. */ + SET_BINARY (fileno (fp)); + + while ((bytes_read = fread (buf, 1, BUFLEN, fp)) > 0) + { + unsigned char *cp = buf; + + if (length + bytes_read < length) + error (EXIT_FAILURE, 0, _("%s: file too long"), file); + length += bytes_read; + while (bytes_read--) + crc = (crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF]; + if (feof (fp)) + break; + } + + if (ferror (fp)) + { + error (0, errno, "%s", file); + if (!STREQ (file, "-")) + fclose (fp); + return -1; + } + + if (!STREQ (file, "-") && fclose (fp) == EOF) + { + error (0, errno, "%s", file); + return -1; + } + + hp = umaxtostr (length, length_buf); + + for (; length; length >>= 8) + crc = (crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF]; + + crc = ~crc & 0xFFFFFFFF; + + if (print_name) + printf ("%u %s %s\n", (unsigned) crc, hp, file); + else + printf ("%u %s\n", (unsigned) crc, hp); + + if (ferror (stdout)) + error (EXIT_FAILURE, errno, "-: %s", _("write error")); + + return 0; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [FILE]...\n\ + or: %s [OPTION]\n\ +"), + program_name, program_name); + fputs (_("\ +Print CRC checksum and byte counts of each FILE.\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +int +main (int argc, char **argv) +{ + int i, c; + int errors = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION, + AUTHORS, usage); + + have_read_stdin = 0; + + while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + default: + usage (EXIT_FAILURE); + } + } + + if (optind == argc) + errors |= cksum ("-", 0); + else + { + for (i = optind; i < argc; i++) + errors |= cksum (argv[i], 1); + } + + if (have_read_stdin && fclose (stdin) == EOF) + error (EXIT_FAILURE, errno, "-"); + exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +#endif /* !CRCTAB */ diff --git a/src/apps/bin/coreutils-5.0/src/comm.c b/src/apps/bin/coreutils-5.0/src/comm.c new file mode 100644 index 0000000000..00b14357cc --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/comm.c @@ -0,0 +1,268 @@ +/* comm -- compare two sorted files line by line. + Copyright (C) 86, 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Richard Stallman and David MacKenzie. */ + +#include + +#include +#include +#include +#include "system.h" +#include "closeout.h" +#include "linebuffer.h" +#include "error.h" +#include "hard-locale.h" +#include "xmemcoll.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "comm" + +#define AUTHORS N_ ("Richard Stallman and David MacKenzie") + +/* Undefine, to avoid warning about redefinition on some systems. */ +#undef min +#define min(x, y) ((x) < (y) ? (x) : (y)) + +/* The name this program was run with. */ +char *program_name; + +/* Nonzero if the LC_COLLATE locale is hard. */ +static int hard_LC_COLLATE; + +/* If nonzero, print lines that are found only in file 1. */ +static int only_file_1; + +/* If nonzero, print lines that are found only in file 2. */ +static int only_file_2; + +/* If nonzero, print lines that are found in both files. */ +static int both; + +static struct option const long_options[] = +{ + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0} +}; + + + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... LEFT_FILE RIGHT_FILE\n\ +"), + program_name); + fputs (_("\ +Compare sorted files LEFT_FILE and RIGHT_FILE line by line.\n\ +\n\ + -1 suppress lines unique to left file\n\ + -2 suppress lines unique to right file\n\ + -3 suppress lines that appear in both files\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Output the line in linebuffer LINE to stream STREAM + provided the switches say it should be output. + CLASS is 1 for a line found only in file 1, + 2 for a line only in file 2, 3 for a line in both. */ + +static void +writeline (const struct linebuffer *line, FILE *stream, int class) +{ + switch (class) + { + case 1: + if (!only_file_1) + return; + break; + + case 2: + if (!only_file_2) + return; + /* Print a TAB if we are printing lines from file 1. */ + if (only_file_1) + putc ('\t', stream); + break; + + case 3: + if (!both) + return; + /* Print a TAB if we are printing lines from file 1. */ + if (only_file_1) + putc ('\t', stream); + /* Print a TAB if we are printing lines from file 2. */ + if (only_file_2) + putc ('\t', stream); + break; + } + + fwrite (line->buffer, sizeof (char), line->length, stream); +} + +/* Compare INFILES[0] and INFILES[1]. + If either is "-", use the standard input for that file. + Assume that each input file is sorted; + merge them and output the result. + Return 0 if successful, 1 if any errors occur. */ + +static int +compare_files (char **infiles) +{ + /* For each file, we have one linebuffer in lb1. */ + struct linebuffer lb1[2]; + + /* thisline[i] points to the linebuffer holding the next available line + in file i, or is NULL if there are no lines left in that file. */ + struct linebuffer *thisline[2]; + + /* streams[i] holds the input stream for file i. */ + FILE *streams[2]; + + int i, ret = 0; + + /* Initialize the storage. */ + for (i = 0; i < 2; i++) + { + initbuffer (&lb1[i]); + thisline[i] = &lb1[i]; + streams[i] = (STREQ (infiles[i], "-") ? stdin : fopen (infiles[i], "r")); + if (!streams[i]) + { + error (0, errno, "%s", infiles[i]); + return 1; + } + + thisline[i] = readline (thisline[i], streams[i]); + } + + while (thisline[0] || thisline[1]) + { + int order; + + /* Compare the next available lines of the two files. */ + + if (!thisline[0]) + order = 1; + else if (!thisline[1]) + order = -1; + else + { + if (HAVE_SETLOCALE && hard_LC_COLLATE) + order = xmemcoll (thisline[0]->buffer, thisline[0]->length - 1, + thisline[1]->buffer, thisline[1]->length - 1); + else + { + size_t len = min (thisline[0]->length, thisline[1]->length) - 1; + order = memcmp (thisline[0]->buffer, thisline[1]->buffer, len); + if (order == 0) + order = (thisline[0]->length < thisline[1]->length + ? -1 + : thisline[0]->length != thisline[1]->length); + } + } + + /* Output the line that is lesser. */ + if (order == 0) + writeline (thisline[1], stdout, 3); + else if (order > 0) + writeline (thisline[1], stdout, 2); + else + writeline (thisline[0], stdout, 1); + + /* Step the file the line came from. + If the files match, step both files. */ + if (order >= 0) + thisline[1] = readline (thisline[1], streams[1]); + if (order <= 0) + thisline[0] = readline (thisline[0], streams[0]); + } + + /* Free all storage and close all input streams. */ + for (i = 0; i < 2; i++) + { + free (lb1[i].buffer); + if (ferror (streams[i]) || fclose (streams[i]) == EOF) + { + error (0, errno, "%s", infiles[i]); + ret = 1; + } + } + return ret; +} + +int +main (int argc, char **argv) +{ + int c; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + hard_LC_COLLATE = hard_locale (LC_COLLATE); + + atexit (close_stdout); + + only_file_1 = 1; + only_file_2 = 1; + both = 1; + + while ((c = getopt_long (argc, argv, "123", long_options, NULL)) != -1) + switch (c) + { + case 0: + break; + + case '1': + only_file_1 = 0; + break; + + case '2': + only_file_2 = 0; + break; + + case '3': + both = 0; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + + if (optind + 2 != argc) + usage (EXIT_FAILURE); + + exit (compare_files (argv + optind) == 0 + ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/config.h b/src/apps/bin/coreutils-5.0/src/config.h new file mode 100644 index 0000000000..a7e1d8f750 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/config.h @@ -0,0 +1,1431 @@ +/* config.h. Generated by configure. */ +/* config.hin. Generated from configure.ac by autoheader. */ + +/* Define if you have the Andrew File System. */ +/* #undef AFS */ + +/* Define to the function xargmatch calls on failures. */ +#define ARGMATCH_DIE usage (1) + +/* Define to the declaration of the xargmatch failure function. */ +#define ARGMATCH_DIE_DECL extern void usage () + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +/* #undef CLOSEDIR_VOID */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if using `getloadavg.c'. */ +#define C_GETLOADAVG 1 + +/* Define to 1 for DGUX with . */ +/* #undef DGUX */ + +/* the name of the file descriptor member of DIR */ +/* #undef DIR_FD_MEMBER_NAME */ + +#ifdef DIR_FD_MEMBER_NAME +# define DIR_TO_FD(Dir_p) ((Dir_p)->DIR_FD_MEMBER_NAME) +#else +# define DIR_TO_FD(Dir_p) -1 +#endif + +#define getpagesize() 4096 + +/* Define if there is a member named d_ino in the struct describing directory + headers. */ +#define D_INO_IN_DIRENT 1 + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +/* #undef ENABLE_NLS */ + +/* Define on systems for which file names may have a so-called `drive letter' + prefix, define this to compute the length of that prefix, including the + colon. */ +#define FILESYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX 0 + +/* Define if the backslash character may also serve as a file name component + separator. */ +#define FILESYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR 0 + +#if FILESYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX +# define FILESYSTEM_PREFIX_LEN(Filename) \ + ((Filename)[0] && (Filename)[1] == ':' ? 2 : 0) +#else +# define FILESYSTEM_PREFIX_LEN(Filename) 0 +#endif + +/* Define to the type of elements in the array set by `getgroups'. Usually + this is either `int' or `gid_t'. */ +#define GETGROUPS_T gid_t + +/* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. + */ +/* #undef GETLOADAVG_PRIVILEGED */ + +/* Define if gettimeofday clobbers localtime's static buffer. */ +/* #undef GETTIMEOFDAY_CLOBBERS_LOCALTIME_BUFFER */ + +/* The concatenation of the strings `GNU ', and PACKAGE. */ +#define GNU_PACKAGE "GNU coreutils" + +/* Define if your system defines TIOCGWINSZ in sys/ioctl.h. */ +/* #undef GWINSZ_IN_SYS_IOCTL */ + +/* Define if your system defines TIOCGWINSZ in sys/pty.h. */ +/* #undef GWINSZ_IN_SYS_PTY */ + +/* Define to 1 if you have the `acl' function. */ +/* #undef HAVE_ACL */ + +/* Define to 1 if you have the `alarm' function. */ +#define HAVE_ALARM 1 + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ARPA_INET_H */ + +/* Define to 1 if you have the `atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Define to 1 if you have the `bcopy' function. */ +#define HAVE_BCOPY 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BP_SYM_H */ + +/* Define to 1 if you have the `btowc' function. */ +#define HAVE_BTOWC 1 + +/* Define to 1 if you have the `chroot' function. */ +/* #undef HAVE_CHROOT */ + +/* Define to 1 if you have the `chsize' function. */ +/* #undef HAVE_CHSIZE */ + +/* Define to 1 if you have the `clock_gettime' function. */ +/* #undef HAVE_CLOCK_GETTIME */ + +/* Define to 1 if you have the `clock_settime' function. */ +/* #undef HAVE_CLOCK_SETTIME */ + +/* Define if backslash-a works in C strings. */ +#define HAVE_C_BACKSLASH_A 1 + +/* FIXME */ +#define HAVE_C_LINE 1 + +/* Define if the GNU dcgettext() function is already present or preinstalled. + */ +/* #undef HAVE_DCGETTEXT */ + +/* Define to 1 if you have the declaration of `clearerr_unlocked', and to 0 if + you don't. */ +#define HAVE_DECL_CLEARERR_UNLOCKED 1 + +/* Define to 1 if you have the declaration of `dirfd', and to 0 if you don't. + */ +#define HAVE_DECL_DIRFD 0 + +/* Define to 1 if you have the declaration of `euidaccess', and to 0 if you + don't. */ +#define HAVE_DECL_EUIDACCESS 0 + +/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you + don't. */ +#define HAVE_DECL_FEOF_UNLOCKED 1 + +/* Define to 1 if you have the declaration of `ferror_unlocked', and to 0 if + you don't. */ +#define HAVE_DECL_FERROR_UNLOCKED 1 + +/* Define to 1 if you have the declaration of `fflush_unlocked', and to 0 if + you don't. */ +#define HAVE_DECL_FFLUSH_UNLOCKED 1 + +/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if + you don't. */ +#define HAVE_DECL_FGETS_UNLOCKED 0 + +/* Define to 1 if you have the declaration of `fputc_unlocked', and to 0 if + you don't. */ +#define HAVE_DECL_FPUTC_UNLOCKED 1 + +/* Define to 1 if you have the declaration of `fputs_unlocked', and to 0 if + you don't. */ +#define HAVE_DECL_FPUTS_UNLOCKED 0 + +/* Define to 1 if you have the declaration of `fread_unlocked', and to 0 if + you don't. */ +#define HAVE_DECL_FREAD_UNLOCKED 1 + +/* Define to 1 if you have the declaration of `free', and to 0 if you don't. + */ +#define HAVE_DECL_FREE 1 + +/* Define to 1 if you have the declaration of `fwrite_unlocked', and to 0 if + you don't. */ +#define HAVE_DECL_FWRITE_UNLOCKED 1 + +/* Define to 1 if you have the declaration of `getchar_unlocked', and to 0 if + you don't. */ +#define HAVE_DECL_GETCHAR_UNLOCKED 1 + +/* Define to 1 if you have the declaration of `getcwd', and to 0 if you don't. + */ +#define HAVE_DECL_GETCWD 1 + +/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you + don't. */ +#define HAVE_DECL_GETC_UNLOCKED 1 + +/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't. + */ +#define HAVE_DECL_GETENV 1 + +/* Define to 1 if you have the declaration of `geteuid', and to 0 if you + don't. */ +#define HAVE_DECL_GETEUID 1 + +/* Define to 1 if you have the declaration of `getgrgid', and to 0 if you + don't. */ +#define HAVE_DECL_GETGRGID 1 + +/* Define to 1 if you have the declaration of `getlogin', and to 0 if you + don't. */ +#define HAVE_DECL_GETLOGIN 1 + +/* Define to 1 if you have the declaration of `getpwuid', and to 0 if you + don't. */ +#define HAVE_DECL_GETPWUID 1 + +/* Define to 1 if you have the declaration of `getuid', and to 0 if you don't. + */ +#define HAVE_DECL_GETUID 1 + +/* Define to 1 if you have the declaration of `getutent', and to 0 if you + don't. */ +#define HAVE_DECL_GETUTENT 0 + +/* Define to 1 if you have the declaration of `lseek', and to 0 if you don't. + */ +#define HAVE_DECL_LSEEK 1 + +/* Define to 1 if you have the declaration of `malloc', and to 0 if you don't. + */ +#define HAVE_DECL_MALLOC 1 + +/* Define to 1 if you have the declaration of `memchr', and to 0 if you don't. + */ +#define HAVE_DECL_MEMCHR 1 + +/* Define to 1 if you have the declaration of `memrchr', and to 0 if you + don't. */ +#define HAVE_DECL_MEMRCHR 0 + +/* Define to 1 if you have the declaration of `nanosleep', and to 0 if you + don't. */ +#define HAVE_DECL_NANOSLEEP 0 + +/* Define to 1 if you have the declaration of `putchar_unlocked', and to 0 if + you don't. */ +#define HAVE_DECL_PUTCHAR_UNLOCKED 1 + +/* Define to 1 if you have the declaration of `putc_unlocked', and to 0 if you + don't. */ +#define HAVE_DECL_PUTC_UNLOCKED 1 + +/* Define to 1 if you have the declaration of `realloc', and to 0 if you + don't. */ +#define HAVE_DECL_REALLOC 1 + +/* Define to 1 if you have the declaration of `stpcpy', and to 0 if you don't. + */ +#define HAVE_DECL_STPCPY 1 + +/* Define to 1 if you have the declaration of `strerror', and to 0 if you + don't. */ +#define HAVE_DECL_STRERROR 1 + +/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you + don't. */ +#define HAVE_DECL_STRERROR_R 1 + +/* Define to 1 if you have the declaration of `strndup', and to 0 if you + don't. */ +#define HAVE_DECL_STRNDUP 0 + +/* Define to 1 if you have the declaration of `strnlen', and to 0 if you + don't. */ +#define HAVE_DECL_STRNLEN 0 + +/* Define to 1 if you have the declaration of `strsignal', and to 0 if you + don't. */ +#define HAVE_DECL_STRSIGNAL 1 + +/* Define to 1 if you have the declaration of `strstr', and to 0 if you don't. + */ +#define HAVE_DECL_STRSTR 1 + +/* Define to 1 if you have the declaration of `strtoimax', and to 0 if you + don't. */ +#define HAVE_DECL_STRTOIMAX 1 + +/* Define to 1 if you have the declaration of `strtol', and to 0 if you don't. + */ +#define HAVE_DECL_STRTOL 1 + +/* Define to 1 if you have the declaration of `strtoll', and to 0 if you + don't. */ +#define HAVE_DECL_STRTOLL 1 + +/* Define to 1 if you have the declaration of `strtoul', and to 0 if you + don't. */ +#define HAVE_DECL_STRTOUL 1 + +/* Define to 1 if you have the declaration of `strtoull', and to 0 if you + don't. */ +#define HAVE_DECL_STRTOULL 1 + +/* Define to 1 if you have the declaration of `strtoumax', and to 0 if you + don't. */ +#define HAVE_DECL_STRTOUMAX 1 + +/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_SIGLIST 0 + +/* Define to 1 if you have the declaration of `ttyname', and to 0 if you + don't. */ +#define HAVE_DECL_TTYNAME 1 + +/* Define to 1 if you have the declaration of wcwidth(), and to 0 otherwise. + */ +#define HAVE_DECL_WCWIDTH 0 + +/* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL__SYS_SIGLIST 0 + +/* Define to 1 if you have the declaration of `__fpending', and to 0 if you + don't. */ +#define HAVE_DECL___FPENDING 0 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the `dirfd' function. */ +#define HAVE_DIRFD 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the `endgrent' function. */ +#define HAVE_ENDGRENT 1 + +/* Define to 1 if you have the `endpwent' function. */ +#define HAVE_ENDPWENT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `euidaccess' function. */ +/* #undef HAVE_EUIDACCESS */ + +/* Define to 1 if you have the `fchdir' function. */ +/* #undef HAVE_FCHDIR */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdatasync' function. */ +/* #undef HAVE_FDATASYNC */ + +/* Define to 1 if you have the `fesetround' function. */ +#define HAVE_FESETROUND 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FLOAT_H 1 + +/* Define to 1 if you have the `floor' function. */ +/* #undef HAVE_FLOOR */ + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +/* #undef HAVE_FSEEKO */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FS_INFO_H 1 + +/* Define to 1 if you have the `fs_stat_dev' function. */ +#define HAVE_FS_STAT_DEV 1 + +/* Define to 1 if you have the `ftime' function. */ +#define HAVE_FTIME 1 + +/* Define to 1 if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE 1 + +/* Define if struct statfs has the f_fstypename member. */ +/* #undef HAVE_F_FSTYPENAME_IN_STATFS */ + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define if getcwd (NULL, 0) allocates memory for result. */ +#define HAVE_GETCWD_NULL 1 + +/* Define to 1 if you have the `getdelim' function. */ +/* #undef HAVE_GETDELIM */ + +/* Define to 1 if your system has a working `getgroups' function. */ +#define HAVE_GETGROUPS 1 + +/* Define to 1 if you have the `gethostbyaddr' function. */ +#define HAVE_GETHOSTBYADDR 1 + +/* Define to 1 if you have the `gethostbyname' function. */ +#define HAVE_GETHOSTBYNAME 1 + +/* Define to 1 if you have the `gethostid' function. */ +/* #undef HAVE_GETHOSTID */ + +/* Define to 1 if you have the `gethostname' function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have the `gethrtime' function. */ +/* #undef HAVE_GETHRTIME */ + +/* Define to 1 if you have the `getloadavg' function. */ +/* #undef HAVE_GETLOADAVG */ + +/* Define to 1 if you have the `getmntent' function. */ +/* #undef HAVE_GETMNTENT */ + +/* Define to 1 if you have the `getmntinfo' function. */ +/* #undef HAVE_GETMNTINFO */ + +/* Define to 1 if you have the `getpagesize' function. */ +/* #undef HAVE_GETPAGESIZE */ + +/* Define to 1 if you have the `getpass' function. */ +/* #undef HAVE_GETPASS */ + +/* Define to 1 if you have the `getspnam' function. */ +/* #undef HAVE_GETSPNAM */ + +/* Define to 1 if you have the `getsysinfo' function. */ +/* #undef HAVE_GETSYSINFO */ + +/* Define if the GNU gettext() function is already present or preinstalled. */ +/* #undef HAVE_GETTEXT */ + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `getusershell' function. */ +/* #undef HAVE_GETUSERSHELL */ + +/* Define to 1 if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define to 1 if you have the `hasmntopt' function. */ +/* #undef HAVE_HASMNTOPT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_HURD_H */ + +/* Define if you have the iconv() function. */ +/* #undef HAVE_ICONV */ + +/* Define to 1 if you have the `inet_ntoa' function. */ +#define HAVE_INET_NTOA 1 + +/* Define to 1 if you have the `initgroups' function. */ +/* #undef HAVE_INITGROUPS */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `isascii' function. */ +#define HAVE_ISASCII 1 + +/* Define to 1 if you have the `iswcntrl' function. */ +#define HAVE_ISWCNTRL 1 + +/* Define to 1 if you have the `iswprint' function. */ +#define HAVE_ISWPRINT 1 + +/* Define to 1 if you have the `iswspace' function. */ +#define HAVE_ISWSPACE 1 + +/* Define if you have and nl_langinfo(CODESET). */ +/* #undef HAVE_LANGINFO_CODESET */ + +/* Define to 1 if you have the `lchown' function. */ +/* #undef HAVE_LCHOWN */ + +/* Define to 1 if you have the `dgc' library (-ldgc). */ +/* #undef HAVE_LIBDGC */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBINTL_H */ + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ + +/* Define to 1 if you have the `ldgc' library (-lldgc). */ +/* #undef HAVE_LIBLDGC */ + +/* Define to 1 if you have the `os' library (-los). */ +/* #undef HAVE_LIBOS */ + +/* Define to 1 if you have the `ypsec' library (-lypsec). */ +/* #undef HAVE_LIBYPSEC */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the `listmntent' function. */ +/* #undef HAVE_LISTMNTENT */ + +/* Define to 1 if you have the `localeconv' function. */ +#define HAVE_LOCALECONV 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `localtime_r' function. */ +#define HAVE_LOCALTIME_R 1 + +/* Define to 1 if long double works and has more range or precision than + double. */ +/* #undef HAVE_LONG_DOUBLE */ + +/* Define to 1 if you support file names longer than 14 characters. */ +#define HAVE_LONG_FILE_NAMES 1 + +/* Define if you have the long long type. */ +#define HAVE_LONG_LONG 1 + +/* Define if lstat has the bug that it succeeds when given the zero-length + file name argument. The lstat from SunOS4.1.4 and the Hurd as of + 1998-11-01) do this. */ +/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACHINE_HAL_SYSINFO_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the `mblen' function. */ +#define HAVE_MBLEN 1 + +/* Define to 1 if you have the `mbrlen' function. */ +#define HAVE_MBRLEN 1 + +/* Define to 1 if mbrtowc and mbstate_t are properly declared. */ +/* #undef HAVE_MBRTOWC */ + +/* Define to 1 if you have the `mbsinit' function. */ +#define HAVE_MBSINIT 1 + +/* Define to 1 if you have the `mbsrtowcs' function. */ +#define HAVE_MBSRTOWCS 1 + +/* Define to 1 if declares mbstate_t. */ +/* #undef HAVE_MBSTATE_T */ + +/* Define to 1 if you have the `memchr' function. */ +#define HAVE_MEMCHR 1 + +/* Define to 1 if you have the `memcmp' function. */ +#define HAVE_MEMCMP 1 + +/* Define to 1 if you have the `memcpy' function. */ +#define HAVE_MEMCPY 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mempcpy' function. */ +/* #undef HAVE_MEMPCPY */ + +/* Define to 1 if you have the `memrchr' function. */ +/* #undef HAVE_MEMRCHR */ + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the `mkfifo' function. */ +#define HAVE_MKFIFO 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MNTENT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MNTTAB_H */ + +/* Define to 1 if you have the `modf' function. */ +/* #undef HAVE_MODF */ + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the `next_dev' function. */ +#define HAVE_NEXT_DEV 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NLIST_H */ + +/* Define to 1 if libc includes obstacks. */ +#define HAVE_OBSTACK 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_OS_H 1 + +/* Define to 1 if you have the `pathconf' function. */ +#define HAVE_PATHCONF 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PATHS_H */ + +/* Define if your system has the /proc/uptime special file. */ +/* #undef HAVE_PROC_UPTIME */ + +/* Define to 1 if you have the `pstat_getdynamic' function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define to 1 if you have the `pstat_getstatic' function. */ +/* #undef HAVE_PSTAT_GETSTATIC */ + +/* Define to 1 if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define to 1 if you have the `raise' function. */ +#define HAVE_RAISE 1 + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC 1 + +/* Define to 1 if you have the `realpath' function. */ +/* #undef HAVE_REALPATH */ + +/* Define to 1 if you have the `resolvepath' function. */ +/* #undef HAVE_RESOLVEPATH */ + +/* Define to 1 if you have the `rint' function. */ +/* #undef HAVE_RINT */ + +/* Define to 1 if you have the `rmdir' function. */ +#define HAVE_RMDIR 1 + +/* Define to 1 if you have the `rpmatch' function. */ +/* #undef HAVE_RPMATCH */ + +/* Define to 1 if you have the `sethostname' function. */ +/* #undef HAVE_SETHOSTNAME */ + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `setregid' function. */ +/* #undef HAVE_SETREGID */ + +/* Define to 1 if you have the `setreuid' function. */ +/* #undef HAVE_SETREUID */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHADOW_H */ + +/* Define to 1 if you have the `sig2str' function. */ +/* #undef HAVE_SIG2STR */ + +/* Define to 1 if you have the `sqrt' function. */ +#define HAVE_SQRT 1 + +/* Define to 1 if you have the `statvfs' function. */ +#define HAVE_STATVFS 1 + +/* Define if stat has the bug that it succeeds when given the zero-length file + name argument. The stat from SunOS4.1.4 and the Hurd as of 1998-11-01) do + this. */ +/* #undef HAVE_STAT_EMPTY_STRING_BUG */ + +/* Define to 1 if stdbool.h conforms to C99. */ +// #define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STDIO_EXT_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `stpcpy' function. */ +#define HAVE_STPCPY 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strcspn' function. */ +#define HAVE_STRCSPN 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strerror_r' function. */ +#define HAVE_STRERROR_R 1 + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strncasecmp' function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the `strndup' function. */ +/* #undef HAVE_STRNDUP */ + +/* Define to 1 if you have the `strpbrk' function. */ +#define HAVE_STRPBRK 1 + +/* Define to 1 if you have the `strrchr' function. */ +#define HAVE_STRRCHR 1 + +/* Define to 1 if you have the `strstr' function. */ +#define HAVE_STRSTR 1 + +/* Define to 1 if you have the `strtoimax' function. */ +#define HAVE_STRTOIMAX 1 + +/* Define to 1 if you have the `strtol' function. */ +#define HAVE_STRTOL 1 + +/* Define to 1 if you have the `strtoll' function. */ +/* #undef HAVE_STRTOLL */ + +/* Define to 1 if you have the `strtoul' function. */ +#define HAVE_STRTOUL 1 + +/* Define to 1 if you have the `strtoull' function. */ +/* #undef HAVE_STRTOULL */ + +/* Define to 1 if you have the `strtoumax' function. */ +#define HAVE_STRTOUMAX 1 + +/* Define if there is a member named d_type in the struct describing directory + headers. */ +/* #undef HAVE_STRUCT_DIRENT_D_TYPE */ + +/* Define to 1 if `f_fstypename' is member of `struct fsstat'. */ +/* #undef HAVE_STRUCT_FSSTAT_F_FSTYPENAME */ + +/* Define to 1 if `n_un.n_name' is member of `struct nlist'. */ +/* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ + +/* Define to 1 if `sp_pwdp' is member of `struct spwd'. */ +/* #undef HAVE_STRUCT_SPWD_SP_PWDP */ + +/* Define to 1 if `f_basetype' is member of `struct statfs'. */ +/* #undef HAVE_STRUCT_STATFS_F_BASETYPE */ + +/* Define to 1 if `f_fsid.__val' is member of `struct statfs'. */ +/* #undef HAVE_STRUCT_STATFS_F_FSID___VAL */ + +/* Define to 1 if `f_fstypename' is member of `struct statfs'. */ +/* #undef HAVE_STRUCT_STATFS_F_FSTYPENAME */ + +/* Define to 1 if `f_namelen' is member of `struct statfs'. */ +/* #undef HAVE_STRUCT_STATFS_F_NAMELEN */ + +/* Define to 1 if `f_namemax' is member of `struct statfs'. */ +/* #undef HAVE_STRUCT_STATFS_F_NAMEMAX */ + +/* Define to 1 if `f_type' is member of `struct statfs'. */ +/* #undef HAVE_STRUCT_STATFS_F_TYPE */ + +/* Define to 1 if `f_basetype' is member of `struct statvfs'. */ +/* #undef HAVE_STRUCT_STATVFS_F_BASETYPE */ + +/* Define to 1 if `f_fsid.__val' is member of `struct statvfs'. */ +/* #undef HAVE_STRUCT_STATVFS_F_FSID___VAL */ + +/* Define to 1 if `f_namelen' is member of `struct statvfs'. */ +/* #undef HAVE_STRUCT_STATVFS_F_NAMELEN */ + +/* Define to 1 if `f_namemax' is member of `struct statvfs'. */ +#define HAVE_STRUCT_STATVFS_F_NAMEMAX 1 + +/* Define to 1 if `f_type' is member of `struct statvfs'. */ +/* #undef HAVE_STRUCT_STATVFS_F_TYPE */ + +/* Define to 1 if `st_author' is member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_AUTHOR */ + +/* Define to 1 if `st_blksize' is member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 + +/* Define to 1 if `st_blocks' is member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_BLOCKS */ + +/* Define if struct timespec is declared in . */ +#define HAVE_STRUCT_TIMESPEC 1 + +/* Define to 1 if `tm_zone' is member of `struct tm'. */ +#define HAVE_STRUCT_TM_TM_ZONE 1 + +/* Define if struct utimbuf is declared -- usually in . Some systems + have utime.h but don't declare the struct anywhere. */ +#define HAVE_STRUCT_UTIMBUF 1 + +/* Define to 1 if `ut_exit.e_exit' is member of `struct utmpx'. */ +/* #undef HAVE_STRUCT_UTMPX_UT_EXIT_E_EXIT */ + +/* Define to 1 if `ut_exit.e_termination' is member of `struct utmpx'. */ +/* #undef HAVE_STRUCT_UTMPX_UT_EXIT_E_TERMINATION */ + +/* Define to 1 if `ut_exit.ut_exit' is member of `struct utmpx'. */ +/* #undef HAVE_STRUCT_UTMPX_UT_EXIT_UT_EXIT */ + +/* Define to 1 if `ut_exit.ut_termination' is member of `struct utmpx'. */ +/* #undef HAVE_STRUCT_UTMPX_UT_EXIT_UT_TERMINATION */ + +/* Define to 1 if `ut_id' is member of `struct utmpx'. */ +/* #undef HAVE_STRUCT_UTMPX_UT_ID */ + +/* Define to 1 if `ut_name' is member of `struct utmpx'. */ +/* #undef HAVE_STRUCT_UTMPX_UT_NAME */ + +/* Define to 1 if `ut_pid' is member of `struct utmpx'. */ +/* #undef HAVE_STRUCT_UTMPX_UT_PID */ + +/* Define to 1 if `ut_type' is member of `struct utmpx'. */ +/* #undef HAVE_STRUCT_UTMPX_UT_TYPE */ + +/* Define to 1 if `ut_user' is member of `struct utmpx'. */ +/* #undef HAVE_STRUCT_UTMPX_UT_USER */ + +/* Define to 1 if `ut_exit.e_exit' is member of `struct utmp'. */ +/* #undef HAVE_STRUCT_UTMP_UT_EXIT_E_EXIT */ + +/* Define to 1 if `ut_exit.e_termination' is member of `struct utmp'. */ +/* #undef HAVE_STRUCT_UTMP_UT_EXIT_E_TERMINATION */ + +/* Define to 1 if `ut_exit.ut_exit' is member of `struct utmp'. */ +/* #undef HAVE_STRUCT_UTMP_UT_EXIT_UT_EXIT */ + +/* Define to 1 if `ut_exit.ut_termination' is member of `struct utmp'. */ +/* #undef HAVE_STRUCT_UTMP_UT_EXIT_UT_TERMINATION */ + +/* Define to 1 if `ut_id' is member of `struct utmp'. */ +/* #undef HAVE_STRUCT_UTMP_UT_ID */ + +/* Define to 1 if `ut_name' is member of `struct utmp'. */ +/* #undef HAVE_STRUCT_UTMP_UT_NAME */ + +/* Define to 1 if `ut_pid' is member of `struct utmp'. */ +/* #undef HAVE_STRUCT_UTMP_UT_PID */ + +/* Define to 1 if `ut_type' is member of `struct utmp'. */ +/* #undef HAVE_STRUCT_UTMP_UT_TYPE */ + +/* Define to 1 if `ut_user' is member of `struct utmp'. */ +/* #undef HAVE_STRUCT_UTMP_UT_USER */ + +/* Define to 1 if you have the `strverscmp' function. */ +/* #undef HAVE_STRVERSCMP */ + +/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use + `HAVE_STRUCT_STAT_ST_BLOCKS' instead. */ +/* #undef HAVE_ST_BLOCKS */ + +/* Define if struct stat has an st_dm_mode member. */ +/* #undef HAVE_ST_DM_MODE */ + +/* Define to 1 if you have the `sysctl' function. */ +/* #undef HAVE_SYSCTL */ + +/* Define to 1 if you have the `sysinfo' function. */ +/* #undef HAVE_SYSINFO */ + +/* FIXME */ +/* #undef HAVE_SYSLOG */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define to 1 if you have the `sysmp' function. */ +/* #undef HAVE_SYSMP */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ACL_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_FILSYS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_FSTYP_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_FS_S5PARAM_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_FS_TYPES_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MNTENT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MOUNT_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_PSTAT_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_STATFS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STATVFS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSCTL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSINFO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SYSMACROS_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSMP_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSTEMCFG_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSTEMINFO_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_TABLE_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_UCRED_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_VFS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the `table' function. */ +/* #undef HAVE_TABLE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if struct tm has the tm_gmtoff member. */ +#define HAVE_TM_GMTOFF 1 + +/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use + `HAVE_STRUCT_TM_TM_ZONE' instead. */ +#define HAVE_TM_ZONE 1 + +/* Define to 1 if you don't have `tm_zone' but do have the external array + `tzname'. */ +/* #undef HAVE_TZNAME */ + +/* Define to 1 if you have the `tzset' function. */ +#define HAVE_TZSET 1 + +/* Define to 1 if you have the `uname' function. */ +#define HAVE_UNAME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the unsigned long long type. */ +#define HAVE_UNSIGNED_LONG_LONG 1 + +/* Define to 1 if you have the `utime' function. */ +/* #undef HAVE_UTIME */ +#define HAVE_UTIME 1 + +/* Define if utimes accepts a null argument */ +/* #undef HAVE_UTIMES_NULL */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UTIME_H 1 + +/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */ +#define HAVE_UTIME_NULL 1 + +/* Define to 1 if you have the `utmpname' function. */ +/* #undef HAVE_UTMPNAME */ + +/* Define to 1 if you have the `utmpxname' function. */ +/* #undef HAVE_UTMPXNAME */ + +/* FIXME */ +/* #undef HAVE_UTMPX_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UTMP_H */ + +/* FIXME */ +/* #undef HAVE_UT_HOST */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VALUES_H */ + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if you have the `wcrtomb' function. */ +#define HAVE_WCRTOMB 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WCTYPE_H */ + +/* Define to 1 if you have the `wcwidth' function. */ +/* #undef HAVE_WCWIDTH */ + +/* Define to 1 if you have the `wmempcpy' function. */ +/* #undef HAVE_WMEMPCPY */ + +/* Define to 1 if you have the external variable, _system_configuration with a + member named physmem. */ +/* #undef HAVE__SYSTEM_CONFIGURATION */ + +/* Define to 1 if you have the `__fpending' function. */ +/* #undef HAVE___FPENDING */ + +/* Define to 1 if you have the `__secure_getenv' function. */ +/* #undef HAVE___SECURE_GETENV */ + +/* The host operating system. */ +#define HOST_OPERATING_SYSTEM "BeOS" + +/* Define as const if the declaration of iconv() needs const. */ +/* #undef ICONV_CONST */ + +#if FILESYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR +# define ISSLASH(C) ((C) == '/' || (C) == '\\') +#else +# define ISSLASH(C) ((C) == '/') +#endif + +/* Define if `link(2)' dereferences symbolic links. */ +/* #undef LINK_FOLLOWS_SYMLINKS */ + +/* FIXME */ +#define LOCALTIME_CACHE 1 + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 + +/* Define to 1 if `major', `minor', and `makedev' are declared in . + */ +/* #undef MAJOR_IN_MKDEV */ + +/* Define to 1 if `major', `minor', and `makedev' are declared in + . */ +#define MAJOR_IN_SYSMACROS 1 + +/* Define if there is no specific function for reading the list of mounted + filesystems. fread will be used to read /etc/mnttab. (SVR2) */ +/* #undef MOUNTED_FREAD */ + +/* Define if (like SVR2) there is no specific function for reading the list of + mounted filesystems, and your system has these header files: + and . (SVR3) */ +/* #undef MOUNTED_FREAD_FSTYP */ + +/* Define if there are functions named next_dev and fs_stat_dev for reading + the list of mounted filesystems. (BeOS) */ +#define MOUNTED_FS_STAT_DEV 1 + +/* Define if there is a function named getfsstat for reading the list of + mounted filesystems. (DEC Alpha running OSF/1) */ +/* #undef MOUNTED_GETFSSTAT */ + +/* Define if there is a function named getmnt for reading the list of mounted + filesystems. (Ultrix) */ +/* #undef MOUNTED_GETMNT */ + +/* Define if there is a function named getmntent for reading the list of + mounted filesystems, and that function takes a single argument. (4.3BSD, + SunOS, HP-UX, Dynix, Irix) */ +/* #undef MOUNTED_GETMNTENT1 */ + +/* Define if there is a function named getmntent for reading the list of + mounted filesystems, and that function takes two arguments. (SVR4) */ +/* #undef MOUNTED_GETMNTENT2 */ + +/* Define if there is a function named getmntinfo for reading the list of + mounted filesystems. (4.4BSD, Darwin) */ +/* #undef MOUNTED_GETMNTINFO */ + +/* Define if there is a function named listmntent that can be used to list all + mounted filesystems. (UNICOS) */ +/* #undef MOUNTED_LISTMNTENT */ + +/* Define if there is a function named mntctl that can be used to read the + list of mounted filesystems, and there is a system header file that + declares `struct vmount.' (AIX) */ +/* #undef MOUNTED_VMOUNT */ + +/* Define to 1 if assertions should be disabled. */ +/* #undef NDEBUG */ + +/* FIXME */ +/* #undef NICE_PRIORITY */ + +/* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend + on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ +/* #undef NLIST_NAME_UNION */ + +/* Name of package */ +#define PACKAGE "coreutils" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-coreutils@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "GNU coreutils" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "GNU coreutils 5.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "coreutils" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "5.0" + +/* the number of pending output bytes on stream `fp' */ +#define PENDING_OUTPUT_N_BYTES fp->_IO_write_ptr - fp->_IO_write_base + +/* Define if exists and defines unusable PRI* macros. */ +/* #undef PRI_MACROS_BROKEN */ + +/* Define to 1 if the C compiler supports function prototypes. */ +#define PROTOTYPES 1 + +/* Define if rename does not work for source paths with a trailing slash, like + the one from SunOS 4.1.1_U1. */ +#define RENAME_TRAILING_SLASH_BUG 1 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* the value to which errno is set when rmdir fails on a nonempty directory */ +#define RMDIR_ERRNO_NOT_EMPTY -2147459066 + +/* Define to 1 if the `setvbuf' function takes the buffering type as its + second argument and the buffer pointer as the third, as on System V before + release 3. */ +/* #undef SETVBUF_REVERSED */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define if the block counts reported by statfs may be truncated to 2GB and + the correct values may be stored in the f_spare array. (SunOS 4.1.2, 4.1.3, + and 4.1.3_U1 are reported to have this problem. SunOS 4.1.1 seems not to be + affected.) */ +/* #undef STATFS_TRUNCATES_BLOCK_COUNTS */ + +/* Define to 1 if the `S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define if there is no specific function for reading filesystems usage + information and you have the header file. (SVR2) */ +/* #undef STAT_READ_FILSYS */ + +/* Define if statfs takes 2 args and struct statfs has a field named f_bsize. + (4.3BSD, SunOS 4, HP-UX, AIX PS/2) */ +/* #undef STAT_STATFS2_BSIZE */ + +/* Define if statfs takes 2 args and struct statfs has a field named f_fsize. + (4.4BSD, NetBSD) */ +/* #undef STAT_STATFS2_FSIZE */ + +/* Define if statfs takes 2 args and the second argument has type struct + fs_data. (Ultrix) */ +/* #undef STAT_STATFS2_FS_DATA */ + +/* Define if statfs takes 3 args. (DEC Alpha running OSF/1) */ +/* #undef STAT_STATFS3_OSF1 */ + +/* Define if statfs takes 4 args. (SVR3, Dynix, Irix, Dolphin) */ +/* #undef STAT_STATFS4 */ + +/* Define if there is a function named statvfs. (SVR4) */ +#define STAT_STATVFS 1 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if strerror_r returns char *. */ +#define STRERROR_R_CHAR_P 1 + +/* Define to be the nanoseconds member of struct stat's st_mtim, if it exists. + */ +/* #undef ST_MTIM_NSEC */ + +/* Define to 1 on System V Release 4. */ +/* #undef SVR4 */ + +/* FIXME */ +/* #undef TERMIOS_NEEDS_XOPEN_SOURCE */ + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 if your declares `struct tm'. */ +/* #undef TM_IN_SYS_TIME */ + +/* Define to 1 for Encore UMAX. */ +/* #undef UMAX */ + +/* Define to 1 for Encore UMAX 4.3 that has instead of + . */ +/* #undef UMAX4_3 */ + +/* the maximum number of simultaneously open files per process */ +#define UTILS_OPEN_MAX 122 + +/* Version number of package */ +#define VERSION "5.0" + +/* Define if sys/ptem.h is required for struct winsize. */ +/* #undef WINSIZE_IN_PTEM */ + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to 1 if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +/* #undef _LARGEFILE_SOURCE */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define like PROTOTYPES; this can be used by system headers. */ +#define __PROTOTYPES 1 + +/* Define to rpl_chown if the replacement function should be used. */ +#define chown rpl_chown + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to rpl_fnmatch if the replacement function should be used. */ +#define fnmatch rpl_fnmatch + +/* Define to rpl_getcwd if the wrapper function should be used. */ +#define getcwd rpl_getcwd + +/* Define as rpl_getgroups if getgroups doesn't work right. */ +/* #undef getgroups */ + +/* Define to rpl_gettimeofday if the replacement function should be used. */ +/* #undef gettimeofday */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define as `__inline' if that's what the C compiler calls it, or to nothing + if it is not supported. */ +/* #undef inline */ + +/* Define to `unsigned long' if does not define. */ +/* #undef ino_t */ + +/* Define to widest signed type if doesn't define. */ +/* #undef intmax_t */ + +/* Define to rpl_localtime if the replacement function should be used. */ +/* #undef localtime */ + +/* Define to `unsigned int' if does not define. */ +#define major_t unsigned int + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to a type if does not define. */ +#define mbstate_t int + +/* Define to rpl_memcmp if the replacement function should be used. */ +/* #undef memcmp */ + +/* Define to `unsigned int' if does not define. */ +#define minor_t unsigned int + +/* Define to rpl_mkdir if the replacement function should be used. */ +#define mkdir rpl_mkdir + +/* Define to rpl_mkstemp if the replacement function should be used. */ +/* #undef mkstemp */ + +/* Define to rpl_mktime if the replacement function should be used. */ +#define mktime rpl_mktime + +/* Define to `int' if does not define. */ +/* #undef mode_t */ + +/* Define to the name of the strftime replacement function. */ +#define my_strftime nstrftime + +/* Define to rpl_nanosleep if the replacement function should be used. */ +#define nanosleep rpl_nanosleep + +/* Define to `long' if does not define. */ +/* #undef off_t */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to rpl_putenv if the replacement function should be used. */ +#define putenv rpl_putenv + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to equivalent of C99 restrict keyword, or to nothing if this is not + supported. Do not define if restrict is supported directly. */ +#define restrict __restrict__ + +/* Define to `unsigned' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if does not define. */ +/* #undef ssize_t */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define to widest unsigned type if doesn't define. */ +/* #undef uintmax_t */ + +/* Define to empty if the keyword `volatile' does not work. Warning: valid + code using `volatile' can become incorrect without. Disable with care. */ +/* #undef volatile */ diff --git a/src/apps/bin/coreutils-5.0/src/copy.c b/src/apps/bin/coreutils-5.0/src/copy.c new file mode 100644 index 0000000000..91ae106f5d --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/copy.c @@ -0,0 +1,1629 @@ +/* copy.c -- core functions for copying files and directories + Copyright (C) 89, 90, 91, 1995-2003 Free Software Foundation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Extracted from cp.c and librarified by Jim Meyering. */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include +#include +#include + +#if HAVE_HURD_H +# include +#endif + +#include "system.h" +#include "error.h" +#include "backupfile.h" +#include "savedir.h" +#include "copy.h" +#include "cp-hash.h" +#include "hash.h" +#include "hash-pjw.h" +#include "same.h" +#include "dirname.h" +#include "full-write.h" +#include "path-concat.h" +#include "quote.h" +#include "same.h" +#include "xreadlink.h" + +#define DO_CHOWN(Chown, File, New_uid, New_gid) \ + (Chown (File, New_uid, New_gid) \ + /* If non-root uses -p, it's ok if we can't preserve ownership. \ + But root probably wants to know, e.g. if NFS disallows it, \ + or if the target system doesn't support file ownership. */ \ + && ((errno != EPERM && errno != EINVAL) || x->myeuid == 0)) + +#define SAME_OWNER(A, B) ((A).st_uid == (B).st_uid) +#define SAME_GROUP(A, B) ((A).st_gid == (B).st_gid) +#define SAME_OWNER_AND_GROUP(A, B) (SAME_OWNER (A, B) && SAME_GROUP (A, B)) + +#define UNWRITABLE(File_name, File_mode) \ + ( /* euidaccess is not meaningful for symlinks */ \ + ! S_ISLNK (File_mode) \ + && euidaccess (File_name, W_OK) != 0) + +struct dir_list +{ + struct dir_list *parent; + ino_t ino; + dev_t dev; +}; + +/* Describe a just-created or just-renamed destination file. */ +struct F_triple +{ + char const* name; + ino_t st_ino; + dev_t st_dev; +}; + +/* Initial size of the above hash table. */ +#define DEST_INFO_INITIAL_CAPACITY 61 + +int euidaccess (); +int yesno (); + +static int copy_internal (const char *src_path, const char *dst_path, + int new_dst, dev_t device, + struct dir_list *ancestors, + const struct cp_options *x, + int command_line_arg, + int *copy_into_self, + int *rename_succeeded); + +/* Pointers to the file names: they're used in the diagnostic that is issued + when we detect the user is trying to copy a directory into itself. */ +static char const *top_level_src_path; +static char const *top_level_dst_path; + +/* The invocation name of this program. */ +extern char *program_name; + +/* Encapsulate selection of the file mode to be applied to + new non-directories. */ + +static mode_t +get_dest_mode (const struct cp_options *option, mode_t mode) +{ + /* In some applications (e.g., install), use precisely the + specified mode. */ + if (option->set_mode) + return option->mode; + + /* Honor the umask for `cp', but not for `mv' or `cp -p'. + In addition, `cp' without -p must clear the set-user-ID and set-group-ID + bits. POSIX requires it do that when creating new files. */ + if (!option->move_mode && !option->preserve_mode) + mode &= (option->umask_kill & ~(S_ISUID | S_ISGID)); + + return mode; +} + +/* FIXME: describe */ +/* FIXME: rewrite this to use a hash table so we avoid the quadratic + performance hit that's probably noticeable only on trees deeper + than a few hundred levels. See use of active_dir_map in remove.c */ + +static int +is_ancestor (const struct stat *sb, const struct dir_list *ancestors) +{ + while (ancestors != 0) + { + if (ancestors->ino == sb->st_ino && ancestors->dev == sb->st_dev) + return 1; + ancestors = ancestors->parent; + } + return 0; +} + +/* Read the contents of the directory SRC_PATH_IN, and recursively + copy the contents to DST_PATH_IN. NEW_DST is nonzero if + DST_PATH_IN is a directory that was created previously in the + recursion. SRC_SB and ANCESTORS describe SRC_PATH_IN. + Set *COPY_INTO_SELF to nonzero if SRC_PATH_IN is a parent of + (or the same as) DST_PATH_IN; otherwise, set it to zero. + Return 0 if successful, -1 if an error occurs. */ + +static int +copy_dir (const char *src_path_in, const char *dst_path_in, int new_dst, + const struct stat *src_sb, struct dir_list *ancestors, + const struct cp_options *x, int *copy_into_self) +{ + char *name_space; + char *namep; + struct cp_options non_command_line_options = *x; + int ret = 0; + + name_space = savedir (src_path_in); + if (name_space == NULL) + { + /* This diagnostic is a bit vague because savedir can fail in + several different ways. */ + error (0, errno, _("cannot access %s"), quote (src_path_in)); + return -1; + } + + /* For cp's -H option, dereference command line arguments, but do not + dereference symlinks that are found via recursive traversal. */ + if (x->dereference == DEREF_COMMAND_LINE_ARGUMENTS) + non_command_line_options.xstat = lstat; + + namep = name_space; + while (*namep != '\0') + { + int local_copy_into_self; + char *src_path = path_concat (src_path_in, namep, NULL); + char *dst_path = path_concat (dst_path_in, namep, NULL); + + if (dst_path == NULL || src_path == NULL) + xalloc_die (); + + ret |= copy_internal (src_path, dst_path, new_dst, src_sb->st_dev, + ancestors, &non_command_line_options, 0, + &local_copy_into_self, NULL); + *copy_into_self |= local_copy_into_self; + + free (dst_path); + free (src_path); + + namep += strlen (namep) + 1; + } + free (name_space); + return -ret; +} + +/* Copy a regular file from SRC_PATH to DST_PATH. + If the source file contains holes, copies holes and blocks of zeros + in the source file as holes in the destination file. + (Holes are read as zeroes by the `read' system call.) + Use DST_MODE as the 3rd argument in the call to open. + X provides many option settings. + Return 0 if successful, -1 if an error occurred. + *NEW_DST is as in copy_internal. SRC_SB is the result + of calling xstat (aka stat in this case) on SRC_PATH. */ + +static int +copy_reg (const char *src_path, const char *dst_path, + const struct cp_options *x, mode_t dst_mode, int *new_dst, + struct stat const *src_sb) +{ + char *buf; + int buf_size; + int dest_desc; + int source_desc; + struct stat sb; + struct stat src_open_sb; + char *cp; + int *ip; + int return_val = 0; + off_t n_read_total = 0; + int last_write_made_hole = 0; + int make_holes = (x->sparse_mode == SPARSE_ALWAYS); + + source_desc = open (src_path, O_RDONLY); + if (source_desc < 0) + { + error (0, errno, _("cannot open %s for reading"), quote (src_path)); + return -1; + } + + if (fstat (source_desc, &src_open_sb)) + { + error (0, errno, _("cannot fstat %s"), quote (src_path)); + return_val = -1; + goto close_src_desc; + } + + /* Compare the source dev/ino from the open file to the incoming, + saved ones obtained via a previous call to stat. */ + if (! SAME_INODE (*src_sb, src_open_sb)) + { + error (0, 0, + _("skipping file %s, as it was replaced while being copied"), + quote (src_path)); + return_val = -1; + goto close_src_desc; + } + + /* These semantics are required for cp. + The if-block will be taken in move_mode. */ + if (*new_dst) + { + dest_desc = open (dst_path, O_WRONLY | O_CREAT, dst_mode); + } + else + { + dest_desc = open (dst_path, O_WRONLY | O_TRUNC, dst_mode); + + if (dest_desc < 0 && x->unlink_dest_after_failed_open) + { + if (unlink (dst_path)) + { + error (0, errno, _("cannot remove %s"), quote (dst_path)); + return_val = -1; + goto close_src_desc; + } + + /* Tell caller that the destination file was unlinked. */ + *new_dst = 1; + + /* Try the open again, but this time with different flags. */ + dest_desc = open (dst_path, O_WRONLY | O_CREAT, dst_mode); + } + } + + if (dest_desc < 0) + { + error (0, errno, _("cannot create regular file %s"), quote (dst_path)); + return_val = -1; + goto close_src_desc; + } + + /* Determine the optimal buffer size. */ + + if (fstat (dest_desc, &sb)) + { + error (0, errno, _("cannot fstat %s"), quote (dst_path)); + return_val = -1; + goto close_src_and_dst_desc; + } + + buf_size = ST_BLKSIZE (sb); + +#if HAVE_STRUCT_STAT_ST_BLOCKS + if (x->sparse_mode == SPARSE_AUTO && S_ISREG (sb.st_mode)) + { + /* Use a heuristic to determine whether SRC_PATH contains any + sparse blocks. */ + + if (fstat (source_desc, &sb)) + { + error (0, errno, _("cannot fstat %s"), quote (src_path)); + return_val = -1; + goto close_src_and_dst_desc; + } + + /* If the file has fewer blocks than would normally + be needed for a file of its size, then + at least one of the blocks in the file is a hole. */ + if (S_ISREG (sb.st_mode) + && sb.st_size / ST_NBLOCKSIZE > ST_NBLOCKS (sb)) + make_holes = 1; + } +#endif + + /* Make a buffer with space for a sentinel at the end. */ + + buf = (char *) alloca (buf_size + sizeof (int)); + + for (;;) + { + ssize_t n_read = read (source_desc, buf, buf_size); + if (n_read < 0) + { +#ifdef EINTR + if (errno == EINTR) + continue; +#endif + error (0, errno, _("reading %s"), quote (src_path)); + return_val = -1; + goto close_src_and_dst_desc; + } + if (n_read == 0) + break; + + n_read_total += n_read; + + ip = 0; + if (make_holes) + { + buf[n_read] = 1; /* Sentinel to stop loop. */ + + /* Find first nonzero *word*, or the word with the sentinel. */ + + ip = (int *) buf; + while (*ip++ == 0) + ; + + /* Find the first nonzero *byte*, or the sentinel. */ + + cp = (char *) (ip - 1); + while (*cp++ == 0) + ; + + /* If we found the sentinel, the whole input block was zero, + and we can make a hole. */ + + if (cp > buf + n_read) + { + /* Make a hole. */ + if (lseek (dest_desc, (off_t) n_read, SEEK_CUR) < 0L) + { + error (0, errno, _("cannot lseek %s"), quote (dst_path)); + return_val = -1; + goto close_src_and_dst_desc; + } + last_write_made_hole = 1; + } + else + /* Clear to indicate that a normal write is needed. */ + ip = 0; + } + if (ip == 0) + { + size_t n = n_read; + if (full_write (dest_desc, buf, n) != n) + { + error (0, errno, _("writing %s"), quote (dst_path)); + return_val = -1; + goto close_src_and_dst_desc; + } + last_write_made_hole = 0; + } + } + + /* If the file ends with a `hole', something needs to be written at + the end. Otherwise the kernel would truncate the file at the end + of the last write operation. */ + + if (last_write_made_hole) + { +#if HAVE_FTRUNCATE + /* Write a null character and truncate it again. */ + if (full_write (dest_desc, "", 1) != 1 + || ftruncate (dest_desc, n_read_total) < 0) +#else + /* Seek backwards one character and write a null. */ + if (lseek (dest_desc, (off_t) -1, SEEK_CUR) < 0L + || full_write (dest_desc, "", 1) != 1) +#endif + { + error (0, errno, _("writing %s"), quote (dst_path)); + return_val = -1; + } + } + +close_src_and_dst_desc: + if (close (dest_desc) < 0) + { + error (0, errno, _("closing %s"), quote (dst_path)); + return_val = -1; + } +close_src_desc: + if (close (source_desc) < 0) + { + error (0, errno, _("closing %s"), quote (src_path)); + return_val = -1; + } + + return return_val; +} + +/* Return nonzero if it's ok that the source and destination + files are the `same' by some measure. The goal is to avoid + making the `copy' operation remove both copies of the file + in that case, while still allowing the user to e.g., move or + copy a regular file onto a symlink that points to it. + Try to minimize the cost of this function in the common case. */ + +static int +same_file_ok (const char *src_path, const struct stat *src_sb, + const char *dst_path, const struct stat *dst_sb, + const struct cp_options *x, int *return_now) +{ + const struct stat *src_sb_link; + const struct stat *dst_sb_link; + struct stat tmp_dst_sb; + struct stat tmp_src_sb; + + int same_link; + int same = (SAME_INODE (*src_sb, *dst_sb)); + + *return_now = 0; + + /* FIXME: this should (at the very least) be moved into the following + if-block. More likely, it should be removed, because it inhibits + making backups. But removing it will result in a change in behavior + that will probably have to be documented -- and tests will have to + be updated. */ + if (same && x->hard_link) + { + *return_now = 1; + return 1; + } + + if (x->xstat == lstat) + { + same_link = same; + + /* If both the source and destination files are symlinks (and we'll + know this here IFF preserving symlinks (aka xstat == lstat), + then it's ok -- as long as they are distinct. */ + if (S_ISLNK (src_sb->st_mode) && S_ISLNK (dst_sb->st_mode)) + return ! same_name (src_path, dst_path); + + src_sb_link = src_sb; + dst_sb_link = dst_sb; + } + else + { + if (!same) + return 1; + + if (lstat (dst_path, &tmp_dst_sb) + || lstat (src_path, &tmp_src_sb)) + return 1; + + src_sb_link = &tmp_src_sb; + dst_sb_link = &tmp_dst_sb; + + same_link = SAME_INODE (*src_sb_link, *dst_sb_link); + + /* If both are symlinks, then it's ok, but only if the destination + will be unlinked before being opened. This is like the test + above, but with the addition of the unlink_dest_before_opening + conjunct because otherwise, with two symlinks to the same target, + we'd end up truncating the source file. */ + if (S_ISLNK (src_sb_link->st_mode) && S_ISLNK (dst_sb_link->st_mode) + && x->unlink_dest_before_opening) + return 1; + } + + /* The backup code ensures there's a copy, so it's usually ok to + remove any destination file. One exception is when both + source and destination are the same directory entry. In that + case, moving the destination file aside (in making the backup) + would also rename the source file and result in an error. */ + if (x->backup_type != none) + { + if (!same_link) + { + /* In copy mode when dereferencing symlinks, if the source is a + symlink and the dest is not, then backing up the destination + (moving it aside) would make it a dangling symlink, and the + subsequent attempt to open it in copy_reg would fail with + a misleading diagnostic. Avoid that by returning zero in + that case so the caller can make cp (or mv when it has to + resort to reading the source file) fail now. */ + + /* FIXME-note: even with the following kludge, we can still provoke + the offending diagnostic. It's just a little harder to do :-) + $ rm -f a b c; touch c; ln -s c b; ln -s b a; cp -b a b + cp: cannot open `a' for reading: No such file or directory + That's misleading, since a subsequent `ls' shows that `a' + is still there. + One solution would be to open the source file *before* moving + aside the destination, but that'd involve a big rewrite. */ + if ( ! x->move_mode + && x->dereference != DEREF_NEVER + && S_ISLNK (src_sb_link->st_mode) + && ! S_ISLNK (dst_sb_link->st_mode)) + return 0; + + return 1; + } + + return ! same_name (src_path, dst_path); + } + +#if 0 + /* FIXME: use or remove */ + + /* If we're making a backup, we'll detect the problem case in + copy_reg because SRC_PATH will no longer exist. Allowing + the test to be deferred lets cp do some useful things. + But when creating hardlinks and SRC_PATH is a symlink + but DST_PATH is not we must test anyway. */ + if (x->hard_link + || !S_ISLNK (src_sb_link->st_mode) + || S_ISLNK (dst_sb_link->st_mode)) + return 1; + + if (x->dereference != DEREF_NEVER) + return 1; +#endif + + /* They may refer to the same file if we're in move mode and the + target is a symlink. That is ok, since we remove any existing + destination file before opening it -- via `rename' if they're on + the same file system, via `unlink (DST_PATH)' otherwise. + It's also ok if they're distinct hard links to the same file. */ + if ((x->move_mode || x->unlink_dest_before_opening) + && (S_ISLNK (dst_sb_link->st_mode) + || (same_link && !same_name (src_path, dst_path)))) + return 1; + + /* If neither is a symlink, then it's ok as long as they aren't + hard links to the same file. */ + if (!S_ISLNK (src_sb_link->st_mode) && !S_ISLNK (dst_sb_link->st_mode)) + { + if (!SAME_INODE (*src_sb_link, *dst_sb_link)) + return 1; + + /* If they are the same file, it's ok if we're making hard links. */ + if (x->hard_link) + { + *return_now = 1; + return 1; + } + } + + /* It's ok to remove a destination symlink. But that works only when we + unlink before opening the destination and when the source and destination + files are on the same partition. */ + if (x->unlink_dest_before_opening + && S_ISLNK (dst_sb_link->st_mode)) + return dst_sb_link->st_dev == src_sb_link->st_dev; + + if (x->xstat == lstat) + { + if ( ! S_ISLNK (src_sb_link->st_mode)) + tmp_src_sb = *src_sb_link; + else if (stat (src_path, &tmp_src_sb)) + return 1; + + if ( ! S_ISLNK (dst_sb_link->st_mode)) + tmp_dst_sb = *dst_sb_link; + else if (stat (dst_path, &tmp_dst_sb)) + return 1; + + if ( ! SAME_INODE (tmp_src_sb, tmp_dst_sb)) + return 1; + + /* FIXME: shouldn't this be testing whether we're making symlinks? */ + if (x->hard_link) + { + *return_now = 1; + return 1; + } + } + + return 0; +} + +static void +overwrite_prompt (char const *dst_path, struct stat const *dst_sb) +{ + if (euidaccess (dst_path, W_OK) != 0) + { + fprintf (stderr, + _("%s: overwrite %s, overriding mode %04lo? "), + program_name, quote (dst_path), + (unsigned long) (dst_sb->st_mode & CHMOD_MODE_BITS)); + } + else + { + fprintf (stderr, _("%s: overwrite %s? "), + program_name, quote (dst_path)); + } +} + +/* Hash an F_triple. */ +static unsigned int +triple_hash (void const *x, unsigned int table_size) +{ + struct F_triple const *p = x; + + /* Also take the name into account, so that when moving N hard links to the + same file (all listed on the command line) all into the same directory, + we don't experience any N^2 behavior. */ + /* FIXME-maybe: is it worth the overhead of doing this + just to avoid N^2 in such an unusual case? N would have + to be very large to make the N^2 factor noticable, and + one would probably encounter a limit on the length of + a command line before it became a problem. */ + unsigned int tmp = hash_pjw (p->name, table_size); + + /* Ignoring the device number here should be fine. */ + return (tmp | p->st_ino) % table_size; +} + +/* Hash an F_triple. */ +static unsigned int +triple_hash_no_name (void const *x, unsigned int table_size) +{ + struct F_triple const *p = x; + + /* Ignoring the device number here should be fine. */ + return p->st_ino % table_size; +} + +/* Compare two F_triple structs. */ +static bool +triple_compare (void const *x, void const *y) +{ + struct F_triple const *a = x; + struct F_triple const *b = y; + return (SAME_INODE (*a, *b) && same_name (a->name, b->name)) ? true : false; +} + +/* Free an F_triple. */ +static void +triple_free (void *x) +{ + struct F_triple *a = x; + free ((char *) (a->name)); + free (a); +} + +/* Initialize the hash table implementing a set of F_triple entries + corresponding to destination files. */ +void +dest_info_init (struct cp_options *x) +{ + x->dest_info + = hash_initialize (DEST_INFO_INITIAL_CAPACITY, + NULL, + triple_hash, + triple_compare, + triple_free); +} + +/* Initialize the hash table implementing a set of F_triple entries + corresponding to source files listed on the command line. */ +void +src_info_init (struct cp_options *x) +{ + + /* Note that we use triple_hash_no_name here. + Contrast with the use of triple_hash above. + That is necessary because a source file may be specified + in many different ways. We want to warn about this + cp a a d/ + as well as this: + cp a ./a d/ + */ + x->src_info + = hash_initialize (DEST_INFO_INITIAL_CAPACITY, + NULL, + triple_hash_no_name, + triple_compare, + triple_free); +} + +/* Return nonzero if there is an entry in hash table, HT, + for the file described by FILENAME and STATS. + Otherwise, return zero. */ +static int +seen_file (Hash_table const *ht, char const *filename, + struct stat const *stats) +{ + struct F_triple new_ent; + + if (ht == NULL) + return 0; + + new_ent.name = filename; + new_ent.st_ino = stats->st_ino; + new_ent.st_dev = stats->st_dev; + + return !!hash_lookup (ht, &new_ent); +} + +/* Record destination filename, FILENAME, and dev/ino from *STATS, + in the hash table, HT. If HT is NULL, return immediately. + If STATS is NULL, call lstat on FILENAME to get the device + and inode numbers. If that lstat fails, simply return. + If memory allocation fails, exit immediately. */ +static void +record_file (Hash_table *ht, char const *filename, + struct stat const *stats) +{ + struct F_triple *ent; + + if (ht == NULL) + return; + + ent = (struct F_triple *) xmalloc (sizeof *ent); + ent->name = xstrdup (filename); + if (stats) + { + ent->st_ino = stats->st_ino; + ent->st_dev = stats->st_dev; + } + else + { + struct stat sb; + if (lstat (filename, &sb)) + return; + ent->st_ino = sb.st_ino; + ent->st_dev = sb.st_dev; + } + + { + struct F_triple *ent_from_table = hash_insert (ht, ent); + if (ent_from_table == NULL) + { + /* Insertion failed due to lack of memory. */ + xalloc_die (); + } + + if (ent_from_table != ent) + { + /* There was alread a matching entry in the table, so ENT was + not inserted. Free it. */ + triple_free (ent); + } + } +} + +/* Copy the file SRC_PATH to the file DST_PATH. The files may be of + any type. NEW_DST should be nonzero if the file DST_PATH cannot + exist because its parent directory was just created; NEW_DST should + be zero if DST_PATH might already exist. DEVICE is the device + number of the parent directory, or 0 if the parent of this file is + not known. ANCESTORS points to a linked, null terminated list of + devices and inodes of parent directories of SRC_PATH. COMMAND_LINE_ARG + is nonzero iff SRC_PATH was specified on the command line. + Set *COPY_INTO_SELF to nonzero if SRC_PATH is a parent of (or the + same as) DST_PATH; otherwise, set it to zero. + Return 0 if successful, 1 if an error occurs. */ + +static int +copy_internal (const char *src_path, const char *dst_path, + int new_dst, + dev_t device, + struct dir_list *ancestors, + const struct cp_options *x, + int command_line_arg, + int *copy_into_self, + int *rename_succeeded) +{ + struct stat src_sb; + struct stat dst_sb; + mode_t src_mode; + mode_t src_type; + char *earlier_file = NULL; + char *dst_backup = NULL; + int backup_succeeded = 0; + int delayed_fail; + int copied_as_regular = 0; + int ran_chown = 0; + int preserve_metadata; + + if (x->move_mode && rename_succeeded) + *rename_succeeded = 0; + + *copy_into_self = 0; + if ((*(x->xstat)) (src_path, &src_sb)) + { + error (0, errno, _("cannot stat %s"), quote (src_path)); + return 1; + } + + src_type = src_sb.st_mode; + + src_mode = src_sb.st_mode; + + if (S_ISDIR (src_type) && !x->recursive) + { + error (0, 0, _("omitting directory %s"), quote (src_path)); + return 1; + } + + /* Detect the case in which the same source file appears more than + once on the command line and no backup option has been selected. + If so, simply warn and don't copy it the second time. + This check is enabled only if x->src_info is non-NULL. */ + if (command_line_arg) + { + if ( ! S_ISDIR (src_sb.st_mode) + && x->backup_type == none + && seen_file (x->src_info, src_path, &src_sb)) + { + error (0, 0, _("warning: source file %s specified more than once"), + quote (src_path)); + return 0; + } + + record_file (x->src_info, src_path, &src_sb); + } + + if (!new_dst) + { + if ((*(x->xstat)) (dst_path, &dst_sb)) + { + if (errno != ENOENT) + { + error (0, errno, _("cannot stat %s"), quote (dst_path)); + return 1; + } + else + { + new_dst = 1; + } + } + else + { + int return_now; + int ok = same_file_ok (src_path, &src_sb, dst_path, &dst_sb, + x, &return_now); + if (return_now) + return 0; + + if (! ok) + { + error (0, 0, _("%s and %s are the same file"), + quote_n (0, src_path), quote_n (1, dst_path)); + return 1; + } + + if (!S_ISDIR (dst_sb.st_mode)) + { + if (S_ISDIR (src_type)) + { + error (0, 0, + _("cannot overwrite non-directory %s with directory %s"), + quote_n (0, dst_path), quote_n (1, src_path)); + return 1; + } + + /* Don't let the user destroy their data, even if they try hard: + This mv command must fail (likewise for cp): + rm -rf a b c; mkdir a b c; touch a/f b/f; mv a/f b/f c + Otherwise, the contents of b/f would be lost. + In the case of `cp', b/f would be lost if the user simulated + a move using cp and rm. + Note that it works fine if you use --backup=numbered. */ + if (command_line_arg + && x->backup_type != numbered + && seen_file (x->dest_info, dst_path, &dst_sb)) + { + error (0, 0, + _("will not overwrite just-created %s with %s"), + quote_n (0, dst_path), quote_n (1, src_path)); + return 1; + } + } + + if (!S_ISDIR (src_type)) + { + if (S_ISDIR (dst_sb.st_mode)) + { + error (0, 0, + _("cannot overwrite directory %s with non-directory"), + quote (dst_path)); + return 1; + } + + if (x->update && MTIME_CMP (src_sb, dst_sb) <= 0) + { + /* We're using --update and the source file is older + than the destination file, so there is no need to + copy or move. */ + /* Pretend the rename succeeded, so the caller (mv) + doesn't end up removing the source file. */ + if (rename_succeeded) + *rename_succeeded = 1; + return 0; + } + } + + /* When there is an existing destination file, we may end up + returning early, and hence not copying/moving the file. + This may be due to an interactive `negative' reply to the + prompt about the existing file. It may also be due to the + use of the --reply=no option. */ + if (!S_ISDIR (src_type)) + { + /* cp and mv treat -i and -f differently. */ + if (x->move_mode) + { + if ((x->interactive == I_ALWAYS_NO + && UNWRITABLE (dst_path, dst_sb.st_mode)) + || ((x->interactive == I_ASK_USER + || (x->interactive == I_UNSPECIFIED + && x->stdin_tty + && UNWRITABLE (dst_path, dst_sb.st_mode))) + && (overwrite_prompt (dst_path, &dst_sb), 1) + && ! yesno ())) + { + /* Pretend the rename succeeded, so the caller (mv) + doesn't end up removing the source file. */ + if (rename_succeeded) + *rename_succeeded = 1; + return 0; + } + } + else + { + if (x->interactive == I_ALWAYS_NO + || (x->interactive == I_ASK_USER + && (overwrite_prompt (dst_path, &dst_sb), 1) + && ! yesno ())) + { + return 0; + } + } + } + + if (x->move_mode) + { + /* In move_mode, DEST may not be an existing directory. */ + if (S_ISDIR (dst_sb.st_mode)) + { + error (0, 0, _("cannot overwrite directory %s"), + quote (dst_path)); + return 1; + } + + /* Don't allow user to move a directory onto a non-directory. */ + if (S_ISDIR (src_sb.st_mode) && !S_ISDIR (dst_sb.st_mode)) + { + error (0, 0, + _("cannot move directory onto non-directory: %s -> %s"), + quote_n (0, src_path), quote_n (0, dst_path)); + return 1; + } + } + + if (x->backup_type != none && !S_ISDIR (dst_sb.st_mode)) + { + char *tmp_backup = find_backup_file_name (dst_path, + x->backup_type); + if (tmp_backup == NULL) + xalloc_die (); + + /* Detect (and fail) when creating the backup file would + destroy the source file. Before, running the commands + cd /tmp; rm -f a a~; : > a; echo A > a~; cp --b=simple a~ a + would leave two zero-length files: a and a~. */ + /* FIXME: but simply change e.g., the final a~ to `./a~' + and the source will still be destroyed. */ + if (STREQ (tmp_backup, src_path)) + { + const char *fmt; + fmt = (x->move_mode + ? _("backing up %s would destroy source; %s not moved") + : _("backing up %s would destroy source; %s not copied")); + error (0, 0, fmt, + quote_n (0, dst_path), + quote_n (1, src_path)); + free (tmp_backup); + return 1; + } + + dst_backup = (char *) alloca (strlen (tmp_backup) + 1); + strcpy (dst_backup, tmp_backup); + free (tmp_backup); + if (rename (dst_path, dst_backup)) + { + if (errno != ENOENT) + { + error (0, errno, _("cannot backup %s"), quote (dst_path)); + return 1; + } + else + { + dst_backup = NULL; + } + } + else + { + backup_succeeded = 1; + } + new_dst = 1; + } + else if (! S_ISDIR (dst_sb.st_mode) + && (x->unlink_dest_before_opening + || (x->xstat == lstat + && ! S_ISREG (src_sb.st_mode)))) + { + if (unlink (dst_path) && errno != ENOENT) + { + error (0, errno, _("cannot remove %s"), quote (dst_path)); + return 1; + } + new_dst = 1; + } + } + } + + /* If the source is a directory, we don't always create the destination + directory. So --verbose should not announce anything until we're + sure we'll create a directory. */ + if (x->verbose && !S_ISDIR (src_type)) + { + printf ("%s -> %s", quote_n (0, src_path), quote_n (1, dst_path)); + if (backup_succeeded) + printf (_(" (backup: %s)"), quote (dst_backup)); + putchar ('\n'); + } + + /* Associate the destination path with the source device and inode + so that if we encounter a matching dev/ino pair in the source tree + we can arrange to create a hard link between the corresponding names + in the destination tree. + + Sometimes, when preserving links, we have to record dev/ino even + though st_nlink == 1: + - when using -H and processing a command line argument; + that command line argument could be a symlink pointing to another + command line argument. With `cp -H --preserve=link', we hard-link + those two destination files. + - likewise for -L except that it applies to all files, not just + command line arguments. + + Also record directory dev/ino when using --recursive. We'll use that + info to detect this problem: cp -R dir dir. FIXME-maybe: ideally, + directory info would be recorded in a separate hash table, since + such entries are useful only while a single command line hierarchy + is being copied -- so that separate table could be cleared between + command line args. Using the same hash table to preserve hard + links means that it may not be cleared. */ + + if ((x->preserve_links + && (1 < src_sb.st_nlink + || (command_line_arg + && x->dereference == DEREF_COMMAND_LINE_ARGUMENTS) + || x->dereference == DEREF_ALWAYS)) + || (x->recursive && S_ISDIR (src_type))) + { + earlier_file = remember_copied (dst_path, src_sb.st_ino, src_sb.st_dev); + } + + /* Did we copy this inode somewhere else (in this command line argument) + and therefore this is a second hard link to the inode? */ + + if (earlier_file) + { + /* Avoid damaging the destination filesystem by refusing to preserve + hard-linked directories (which are found at least in Netapp snapshot + directories). */ + if (S_ISDIR (src_type)) + { + /* If src_path and earlier_file refer to the same directory entry, + then warn about copying a directory into itself. */ + if (same_name (src_path, earlier_file)) + { + error (0, 0, _("cannot copy a directory, %s, into itself, %s"), + quote_n (0, top_level_src_path), + quote_n (1, top_level_dst_path)); + *copy_into_self = 1; + } + else + { + error (0, 0, _("will not create hard link %s to directory %s"), + quote_n (0, dst_path), quote_n (1, earlier_file)); + } + + goto un_backup; + } + + { + int link_failed; + + link_failed = link (earlier_file, dst_path); + + /* If the link failed because of an existing destination, + remove that file and then call link again. */ + if (link_failed && errno == EEXIST) + { + if (unlink (dst_path)) + { + error (0, errno, _("cannot remove %s"), quote (dst_path)); + goto un_backup; + } + link_failed = link (earlier_file, dst_path); + } + + if (link_failed) + { + error (0, errno, _("cannot create hard link %s to %s"), + quote_n (0, dst_path), quote_n (1, earlier_file)); + goto un_backup; + } + + return 0; + } + } + + if (x->move_mode) + { + if (rename (src_path, dst_path) == 0) + { + if (x->verbose && S_ISDIR (src_type)) + printf ("%s -> %s\n", quote_n (0, src_path), quote_n (1, dst_path)); + if (rename_succeeded) + *rename_succeeded = 1; + + if (command_line_arg) + { + /* Record destination dev/ino/filename, so that if we are asked + to overwrite that file again, we can detect it and fail. */ + /* It's fine to use the _source_ stat buffer (src_sb) to get the + _destination_ dev/ino, since the rename above can't have + changed those, and `mv' always uses lstat. + We could limit it further by operating + only on non-directories. */ + record_file (x->dest_info, dst_path, &src_sb); + } + + return 0; + } + + /* FIXME: someday, consider what to do when moving a directory into + itself but when source and destination are on different devices. */ + + /* This happens when attempting to rename a directory to a + subdirectory of itself. */ + if (errno == EINVAL + + /* When src_path is on an NFS file system, some types of + clients, e.g., SunOS4.1.4 and IRIX-5.3, set errno to EIO + instead. Testing for this here risks misinterpreting a real + I/O error as an attempt to move a directory into itself, so + FIXME: consider not doing this. */ + || errno == EIO + + /* And with SunOS-4.1.4 client and OpenBSD-2.3 server, + we get ENOTEMPTY. */ + || errno == ENOTEMPTY) + { + /* FIXME: this is a little fragile in that it relies on rename(2) + failing with a specific errno value. Expect problems on + non-POSIX systems. */ + error (0, 0, _("cannot move %s to a subdirectory of itself, %s"), + quote_n (0, top_level_src_path), + quote_n (1, top_level_dst_path)); + + /* Note that there is no need to call forget_created here, + (compare with the other calls in this file) since the + destination directory didn't exist before. */ + + *copy_into_self = 1; + /* FIXME-cleanup: Don't return zero here; adjust mv.c accordingly. + The only caller that uses this code (mv.c) ends up setting its + exit status to nonzero when copy_into_self is nonzero. */ + return 0; + } + + /* WARNING: there probably exist systems for which an inter-device + rename fails with a value of errno not handled here. + If/as those are reported, add them to the condition below. + If this happens to you, please do the following and send the output + to the bug-reporting address (e.g., in the output of cp --help): + touch k; perl -e 'rename "k","/tmp/k" or print "$!(",$!+0,")\n"' + where your current directory is on one partion and /tmp is the other. + Also, please try to find the E* errno macro name corresponding to + the diagnostic and parenthesized integer, and include that in your + e-mail. One way to do that is to run a command like this + find /usr/include/. -type f \ + | xargs grep 'define.*\.*\<18\>' /dev/null + where you'd replace `18' with the integer in parentheses that + was output from the perl one-liner above. + If necessary, of course, change `/tmp' to some other directory. */ + if (errno != EXDEV) + { + /* There are many ways this can happen due to a race condition. + When something happens between the initial xstat and the + subsequent rename, we can get many different types of errors. + For example, if the destination is initially a non-directory + or non-existent, but it is created as a directory, the rename + fails. If two `mv' commands try to rename the same file at + about the same time, one will succeed and the other will fail. + If the permissions on the directory containing the source or + destination file are made too restrictive, the rename will + fail. Etc. */ + error (0, errno, + _("cannot move %s to %s"), + quote_n (0, src_path), quote_n (1, dst_path)); + forget_created (src_sb.st_ino, src_sb.st_dev); + return 1; + } + + /* The rename attempt has failed. Remove any existing destination + file so that a cross-device `mv' acts as if it were really using + the rename syscall. */ + if (unlink (dst_path) && errno != ENOENT) + { + error (0, errno, + _("inter-device move failed: %s to %s; unable to remove target"), + quote_n (0, src_path), quote_n (1, dst_path)); + forget_created (src_sb.st_ino, src_sb.st_dev); + return 1; + } + + new_dst = 1; + } + + delayed_fail = 0; + + /* In certain modes (cp's --symbolic-link), and for certain file types + (symlinks and hard links) it doesn't make sense to preserve metadata, + or it's possible to preserve only some of it. + In such cases, set this variable to zero. */ + preserve_metadata = 1; + + if (S_ISDIR (src_type)) + { + struct dir_list *dir; + + /* If this directory has been copied before during the + recursion, there is a symbolic link to an ancestor + directory of the symbolic link. It is impossible to + continue to copy this, unless we've got an infinite disk. */ + + if (is_ancestor (&src_sb, ancestors)) + { + error (0, 0, _("cannot copy cyclic symbolic link %s"), + quote (src_path)); + goto un_backup; + } + + /* Insert the current directory in the list of parents. */ + + dir = (struct dir_list *) alloca (sizeof (struct dir_list)); + dir->parent = ancestors; + dir->ino = src_sb.st_ino; + dir->dev = src_sb.st_dev; + + if (new_dst || !S_ISDIR (dst_sb.st_mode)) + { + /* Create the new directory writable and searchable, so + we can create new entries in it. */ + + if (mkdir (dst_path, (src_mode & x->umask_kill) | S_IRWXU)) + { + error (0, errno, _("cannot create directory %s"), + quote (dst_path)); + goto un_backup; + } + + /* Insert the created directory's inode and device + numbers into the search structure, so that we can + avoid copying it again. */ + + if (remember_created (dst_path)) + goto un_backup; + + if (x->verbose) + printf ("%s -> %s\n", quote_n (0, src_path), quote_n (1, dst_path)); + } + + /* Are we crossing a file system boundary? */ + if (x->one_file_system && device != 0 && device != src_sb.st_dev) + return 0; + + /* Copy the contents of the directory. */ + + if (copy_dir (src_path, dst_path, new_dst, &src_sb, dir, x, + copy_into_self)) + { + /* Don't just return here -- otherwise, the failure to read a + single file in a source directory would cause the containing + destination directory not to have owner/perms set properly. */ + delayed_fail = 1; + } + } +#ifdef S_ISLNK + else if (x->symbolic_link) + { + preserve_metadata = 0; + + if (*src_path != '/') + { + /* Check that DST_PATH denotes a file in the current directory. */ + struct stat dot_sb; + struct stat dst_parent_sb; + char *dst_parent; + int in_current_dir; + + dst_parent = dir_name (dst_path); + + in_current_dir = (STREQ (".", dst_parent) + /* If either stat call fails, it's ok not to report + the failure and say dst_path is in the current + directory. Other things will fail later. */ + || stat (".", &dot_sb) + || stat (dst_parent, &dst_parent_sb) + || SAME_INODE (dot_sb, dst_parent_sb)); + free (dst_parent); + + if (! in_current_dir) + { + error (0, 0, + _("%s: can make relative symbolic links only in current directory"), + quote (dst_path)); + goto un_backup; + } + } + if (symlink (src_path, dst_path)) + { + error (0, errno, _("cannot create symbolic link %s to %s"), + quote_n (0, dst_path), quote_n (1, src_path)); + goto un_backup; + } + } +#endif + else if (x->hard_link) + { + preserve_metadata = 0; + if (link (src_path, dst_path)) + { + error (0, errno, _("cannot create link %s"), quote (dst_path)); + goto un_backup; + } + } + else if (S_ISREG (src_type) + || (x->copy_as_regular && !S_ISDIR (src_type) +#ifdef S_ISLNK + && !S_ISLNK (src_type) +#endif + )) + { + copied_as_regular = 1; + /* POSIX says the permission bits of the source file must be + used as the 3rd argument in the open call, but that's not consistent + with historical practice. */ + if (copy_reg (src_path, dst_path, x, + get_dest_mode (x, src_mode), &new_dst, &src_sb)) + goto un_backup; + } + else +#ifdef S_ISFIFO + if (S_ISFIFO (src_type)) + { + if (mkfifo (dst_path, get_dest_mode (x, src_mode))) + { + error (0, errno, _("cannot create fifo %s"), quote (dst_path)); + goto un_backup; + } + } + else +#endif + if (S_ISBLK (src_type) || S_ISCHR (src_type) +#ifdef S_ISSOCK + || S_ISSOCK (src_type) +#endif + ) + { + if (mknod (dst_path, get_dest_mode (x, src_mode), src_sb.st_rdev)) + { + error (0, errno, _("cannot create special file %s"), + quote (dst_path)); + goto un_backup; + } + } + else +#ifdef S_ISLNK + if (S_ISLNK (src_type)) + { + char *src_link_val = xreadlink (src_path); + if (src_link_val == NULL) + { + error (0, errno, _("cannot read symbolic link %s"), quote (src_path)); + goto un_backup; + } + + if (!symlink (src_link_val, dst_path)) + free (src_link_val); + else + { + int saved_errno = errno; + int same_link = 0; + if (x->update && !new_dst && S_ISLNK (dst_sb.st_mode)) + { + /* See if the destination is already the desired symlink. */ + size_t src_link_len = strlen (src_link_val); + char *dest_link_val = (char *) alloca (src_link_len + 1); + int dest_link_len = readlink (dst_path, dest_link_val, + src_link_len + 1); + if ((size_t) dest_link_len == src_link_len + && strncmp (dest_link_val, src_link_val, src_link_len) == 0) + same_link = 1; + } + free (src_link_val); + + if (! same_link) + { + error (0, saved_errno, _("cannot create symbolic link %s"), + quote (dst_path)); + goto un_backup; + } + } + + /* There's no need to preserve timestamps or permissions. */ + preserve_metadata = 0; + + if (x->preserve_ownership) + { + /* Preserve the owner and group of the just-`copied' + symbolic link, if possible. */ +# if HAVE_LCHOWN + if (DO_CHOWN (lchown, dst_path, src_sb.st_uid, src_sb.st_gid)) + { + error (0, errno, _("failed to preserve ownership for %s"), + dst_path); + goto un_backup; + } +# else + /* Can't preserve ownership of symlinks. + FIXME: maybe give a warning or even error for symlinks + in directories with the sticky bit set -- there, not + preserving owner/group is a potential security problem. */ +# endif + } + } + else +#endif + { + error (0, 0, _("%s has unknown file type"), quote (src_path)); + goto un_backup; + } + + if (command_line_arg) + record_file (x->dest_info, dst_path, NULL); + + if ( ! preserve_metadata) + return 0; + + /* POSIX says that `cp -p' must restore the following: + - permission bits + - setuid, setgid bits + - owner and group + If it fails to restore any of those, we may give a warning but + the destination must not be removed. + FIXME: implement the above. */ + + /* Adjust the times (and if possible, ownership) for the copy. + chown turns off set[ug]id bits for non-root, + so do the chmod last. */ + + if (x->preserve_timestamps) + { + struct utimbuf utb; + + /* There's currently no interface to set file timestamps with + better than 1-second resolution, so discard any fractional + part of the source timestamp. */ + + utb.actime = src_sb.st_atime; + utb.modtime = src_sb.st_mtime; + + if (utime (dst_path, &utb)) + { + error (0, errno, _("preserving times for %s"), quote (dst_path)); + if (x->require_preserve) + return 1; + } + } + + /* Avoid calling chown if we know it's not necessary. */ + if (x->preserve_ownership + && (new_dst || !SAME_OWNER_AND_GROUP (src_sb, dst_sb))) + { + ran_chown = 1; + if (DO_CHOWN (chown, dst_path, src_sb.st_uid, src_sb.st_gid)) + { + error (0, errno, _("failed to preserve ownership for %s"), + quote (dst_path)); + if (x->require_preserve) + return 1; + } + } + +#if HAVE_STRUCT_STAT_ST_AUTHOR + /* Preserve the st_author field. */ + { + file_t file = file_name_lookup (dst_path, 0, 0); + if (file_chauthor (file, src_sb.st_author)) + error (0, errno, _("failed to preserve authorship for %s"), + quote (dst_path)); + mach_port_deallocate (mach_task_self (), file); + } +#endif + + /* Permissions of newly-created regular files were set upon `open' in + copy_reg. But don't return early if there were any special bits and + we had to run chown, because the chown must have reset those bits. */ + if ((new_dst && copied_as_regular) + && !(ran_chown && (src_mode & ~S_IRWXUGO))) + return delayed_fail; + + if ((x->preserve_mode || new_dst) + && (x->copy_as_regular || S_ISREG (src_type) || S_ISDIR (src_type))) + { + if (chmod (dst_path, get_dest_mode (x, src_mode))) + { + error (0, errno, _("setting permissions for %s"), quote (dst_path)); + if (x->set_mode || x->require_preserve) + return 1; + } + } + + return delayed_fail; + +un_backup: + + /* We have failed to create the destination file. + If we've just added a dev/ino entry via the remember_copied + call above (i.e., unless we've just failed to create a hard link), + remove the entry associating the source dev/ino with the + destination file name, so we don't try to `preserve' a link + to a file we didn't create. */ + if (earlier_file == NULL) + forget_created (src_sb.st_ino, src_sb.st_dev); + + if (dst_backup) + { + if (rename (dst_backup, dst_path)) + error (0, errno, _("cannot un-backup %s"), quote (dst_path)); + else + { + if (x->verbose) + printf (_("%s -> %s (unbackup)\n"), + quote_n (0, dst_backup), quote_n (1, dst_path)); + } + } + return 1; +} + +static int +valid_options (const struct cp_options *co) +{ + assert (co != NULL); + + assert (VALID_BACKUP_TYPE (co->backup_type)); + + /* FIXME: for some reason this assertion always fails, + at least on Solaris2.5.1. Just disable it for now. */ + /* assert (co->xstat == lstat || co->xstat == stat); */ + + /* Make sure xstat and dereference are consistent. */ + /* FIXME */ + + assert (VALID_SPARSE_MODE (co->sparse_mode)); + + return 1; +} + +/* Copy the file SRC_PATH to the file DST_PATH. The files may be of + any type. NONEXISTENT_DST should be nonzero if the file DST_PATH + is known not to exist (e.g., because its parent directory was just + created); NONEXISTENT_DST should be zero if DST_PATH might already + exist. OPTIONS is ... FIXME-describe + Set *COPY_INTO_SELF to nonzero if SRC_PATH is a parent of (or the + same as) DST_PATH; otherwise, set it to zero. + Return 0 if successful, 1 if an error occurs. */ + +int +copy (const char *src_path, const char *dst_path, + int nonexistent_dst, const struct cp_options *options, + int *copy_into_self, int *rename_succeeded) +{ + assert (valid_options (options)); + + /* Record the file names: they're used in case of error, when copying + a directory into itself. I don't like to make these tools do *any* + extra work in the common case when that work is solely to handle + exceptional cases, but in this case, I don't see a way to derive the + top level source and destination directory names where they're used. + An alternative is to use COPY_INTO_SELF and print the diagnostic + from every caller -- but I don't want to do that. */ + top_level_src_path = src_path; + top_level_dst_path = dst_path; + + return copy_internal (src_path, dst_path, nonexistent_dst, 0, NULL, + options, 1, copy_into_self, rename_succeeded); +} diff --git a/src/apps/bin/coreutils-5.0/src/copy.h b/src/apps/bin/coreutils-5.0/src/copy.h new file mode 100644 index 0000000000..10cdce9796 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/copy.h @@ -0,0 +1,211 @@ +#ifndef COPY_H +# define COPY_H + +# include "hash.h" + +/* Control creation of sparse files (files with holes). */ +enum Sparse_type +{ + SPARSE_UNUSED, + + /* Never create holes in DEST. */ + SPARSE_NEVER, + + /* This is the default. Use a crude (and sometimes inaccurate) + heuristic to determine if SOURCE has holes. If so, try to create + holes in DEST. */ + SPARSE_AUTO, + + /* For every sufficiently long sequence of bytes in SOURCE, try to + create a corresponding hole in DEST. There is a performance penalty + here because CP has to search for holes in SRC. But if the holes are + big enough, that penalty can be offset by the decrease in the amount + of data written to disk. */ + SPARSE_ALWAYS +}; + +/* This type is used to help mv (via copy.c) distinguish these cases. */ +enum Interactive +{ + I_ALWAYS_YES = 1, + I_ALWAYS_NO, + I_ASK_USER, + I_UNSPECIFIED +}; + +/* How to handle symbolic links. */ +enum Dereference_symlink +{ + DEREF_UNDEFINED = 1, + + /* Copy the symbolic link itself. -P */ + DEREF_NEVER, + + /* If the symbolic is a command line argument, then copy + its referent. Otherwise, copy the symbolic link itself. -H */ + DEREF_COMMAND_LINE_ARGUMENTS, + + /* Copy the referent of the symbolic link. -L */ + DEREF_ALWAYS +}; + +# define VALID_SPARSE_MODE(Mode) \ + ((Mode) == SPARSE_NEVER \ + || (Mode) == SPARSE_AUTO \ + || (Mode) == SPARSE_ALWAYS) + +/* These options control how files are copied by at least the + following programs: mv (when rename doesn't work), cp, install. + So, if you add a new member, be sure to initialize it in + mv.c, cp.c, and install.c. */ +struct cp_options +{ + enum backup_type backup_type; + + /* If nonzero, copy all files except (directories and, if not dereferencing + them, symbolic links,) as if they were regular files. */ + int copy_as_regular; + + /* How to handle symlinks. */ + enum Dereference_symlink dereference; + + /* If nonzero, remove each existing destination nondirectory before + trying to open it. */ + int unlink_dest_before_opening; + + /* If nonzero, first try to open each existing destination nondirectory, + then, if the open fails, unlink and try again. + This option must be set for `cp -f', in case the destination file + exists when the open is attempted. It is irrelevant to `mv' since + any destination is sure to be removed before the open. */ + int unlink_dest_after_failed_open; + + /* If nonzero, create hard links instead of copying files. + Create destination directories as usual. */ + int hard_link; + + /* This value is used to determine whether to prompt before removing + each existing destination file. It works differently depending on + whether move_mode is set. See code/comments in copy.c. */ + enum Interactive interactive; + + /* If nonzero, rather than copying, first attempt to use rename. + If that fails, then resort to copying. */ + int move_mode; + + /* This process's effective user ID. */ + uid_t myeuid; + + /* If nonzero, when copying recursively, skip any subdirectories that are + on different filesystems from the one we started on. */ + int one_file_system; + + /* If nonzero, attempt to give the copies the original files' permissions, + owner, group, and timestamps. */ + int preserve_ownership; + int preserve_mode; + int preserve_timestamps; + + /* Enabled for mv, and for cp by the --preserve=links option. + If nonzero, attempt to preserve in the destination files any + logical hard links between the source files. If used with cp's + --no-dereference option, and copying two hard-linked files, + the two corresponding destination files will also be hard linked. + + If used with cp's --dereference (-L) option, then, as that option implies, + hard links are *not* preserved. However, when copying a file F and + a symlink S to F, the resulting S and F in the destination directory + will be hard links to the same file (a copy of F). */ + int preserve_links; + + /* If nonzero and any of the above (for preserve) file attributes cannot + be applied to a destination file, treat it as a failure and return + nonzero immediately. E.g. cp -p requires this be nonzero, mv requires + it be zero. */ + int require_preserve; + + /* If nonzero, copy directories recursively and copy special files + as themselves rather than copying their contents. */ + int recursive; + + /* If nonzero, set file mode to value of MODE. Otherwise, + set it based on current umask modified by UMASK_KILL. */ + int set_mode; + + /* Set the mode of the destination file to exactly this value + if USE_MODE is nonzero. */ + mode_t mode; + + /* Control creation of sparse files. */ + enum Sparse_type sparse_mode; + + /* If nonzero, create symbolic links instead of copying files. + Create destination directories as usual. */ + int symbolic_link; + + /* The bits to preserve in created files' modes. */ + mode_t umask_kill; + + /* If nonzero, do not copy a nondirectory that has an existing destination + with the same or newer modification time. */ + int update; + + /* If nonzero, display the names of the files before copying them. */ + int verbose; + + /* A pointer to either lstat or stat, depending on + whether the copy should dereference symlinks. */ + int (*xstat) (); + + /* If nonzero, stdin is a tty. */ + int stdin_tty; + + /* This is a set of destination name/inode/dev triples. Each such triple + represents a file we have created corresponding to a source file name + that was specified on the command line. Use it to avoid clobbering + source files in commands like this: + rm -rf a b c; mkdir a b c; touch a/f b/f; mv a/f b/f c + For now, it protects only regular files when copying (i.e. not renaming). + When renaming, it protects all non-directories. + Use dest_info_init to initialize it, or set it to NULL to disable + this feature. */ + Hash_table *dest_info; + + /* FIXME */ + Hash_table *src_info; +}; + +int stat (); +int lstat (); + +/* Arrange to make lstat calls go through the wrapper function + on systems with an lstat function that does not dereference symlinks + that are specified with a trailing slash. */ +# if ! LSTAT_FOLLOWS_SLASHED_SYMLINK +int rpl_lstat (const char *, struct stat *); +# undef lstat +# define lstat rpl_lstat +# endif + +int rename (); + +/* Arrange to make rename calls go through the wrapper function + on systems with a rename function that fails for a source path + specified with a trailing slash. */ +# if RENAME_TRAILING_SLASH_BUG +int rpl_rename (const char *, const char *); +# undef rename +# define rename rpl_rename +# endif + +int +copy (const char *src_path, const char *dst_path, + int nonexistent_dst, const struct cp_options *options, + int *copy_into_self, int *rename_succeeded); + +void +dest_info_init (struct cp_options *); +void +src_info_init (struct cp_options *); + +#endif diff --git a/src/apps/bin/coreutils-5.0/src/cp-hash.c b/src/apps/bin/coreutils-5.0/src/cp-hash.c new file mode 100644 index 0000000000..396fed182e --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/cp-hash.c @@ -0,0 +1,173 @@ +/* cp-hash.c -- file copying (hash search routines) + Copyright (C) 89, 90, 91, 1995-2002 Free Software Foundation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Written by Torbjorn Granlund, Sweden (tege@sics.se). + Rewritten to use lib/hash.c by Jim Meyering. */ + +#include + +#include +#include +#include "system.h" + +#include "same.h" +#include "quote.h" +#include "hash.h" +#include "error.h" +#include "cp-hash.h" + +/* Use ST_DEV and ST_INO as the key, FILENAME as the value. + These are used e.g., in copy.c to associate the destination path with + the source device/inode pair so that if we encounter a matching dev/ino + pair in the source tree we can arrange to create a hard link between + the corresponding names in the destination tree. */ +struct Src_to_dest +{ + ino_t st_ino; + dev_t st_dev; + /* Destination path name (of non-directory or pre-existing directory) + corresponding to the dev/ino of a copied file, or the destination path + name corresponding to a dev/ino pair for a newly-created directory. */ + char const* name; +}; + +/* This table maps source dev/ino to destination file name. + We use it to preserve hard links when copying. */ +static Hash_table *src_to_dest; + +/* Initial size of the above hash table. */ +#define INITIAL_TABLE_SIZE 103 + +static unsigned int +src_to_dest_hash (void const *x, unsigned int table_size) +{ + struct Src_to_dest const *p = x; + + /* Ignoring the device number here should be fine. */ + /* The cast to uintmax_t prevents negative remainders + if st_ino is negative. */ + return (uintmax_t) p->st_ino % table_size; +} + +/* Compare two Src_to_dest entries. + Return true if their keys are judged `equal'. */ +static bool +src_to_dest_compare (void const *x, void const *y) +{ + struct Src_to_dest const *a = x; + struct Src_to_dest const *b = y; + return SAME_INODE (*a, *b) ? true : false; +} + +static void +src_to_dest_free (void *x) +{ + struct Src_to_dest *a = x; + free ((char *) (a->name)); + free (x); +} + +/* Remove the entry matching INO/DEV from the table + that maps source ino/dev to destination file name. */ +void +forget_created (ino_t ino, dev_t dev) +{ + struct Src_to_dest probe; + struct Src_to_dest *ent; + + probe.st_ino = ino; + probe.st_dev = dev; + probe.name = NULL; + + ent = hash_delete (src_to_dest, &probe); + if (ent) + src_to_dest_free (ent); +} + +/* Add PATH to the list of files that we have created. + Return 1 if we can't stat PATH, otherwise 0. */ + +int +remember_created (const char *path) +{ + struct stat sb; + + if (stat (path, &sb) < 0) + { + error (0, errno, "%s", quote (path)); + return 1; + } + + remember_copied (path, sb.st_ino, sb.st_dev); + return 0; +} + +/* Add path NAME, copied from inode number INO and device number DEV, + to the list of files we have copied. + Return NULL if inserted, otherwise non-NULL. */ + +char * +remember_copied (const char *name, ino_t ino, dev_t dev) +{ + struct Src_to_dest *ent; + struct Src_to_dest *ent_from_table; + + ent = (struct Src_to_dest *) xmalloc (sizeof *ent); + ent->name = xstrdup (name); + ent->st_ino = ino; + ent->st_dev = dev; + + ent_from_table = hash_insert (src_to_dest, ent); + if (ent_from_table == NULL) + { + /* Insertion failed due to lack of memory. */ + xalloc_die (); + } + + /* Determine whether there was already an entry in the table + with a matching key. If so, free ENT (it wasn't inserted) and + return the `name' from the table entry. */ + if (ent_from_table != ent) + { + src_to_dest_free (ent); + return (char *) ent_from_table->name; + } + + /* New key; insertion succeeded. */ + return NULL; +} + +/* Initialize the hash table. */ +void +hash_init (void) +{ + src_to_dest = hash_initialize (INITIAL_TABLE_SIZE, NULL, + src_to_dest_hash, + src_to_dest_compare, + src_to_dest_free); + if (src_to_dest == NULL) + xalloc_die (); +} + +/* Reset the hash structure in the global variable `htab' to + contain no entries. */ + +void +forget_all (void) +{ + hash_free (src_to_dest); +} diff --git a/src/apps/bin/coreutils-5.0/src/cp-hash.h b/src/apps/bin/coreutils-5.0/src/cp-hash.h new file mode 100644 index 0000000000..1f376e1617 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/cp-hash.h @@ -0,0 +1,5 @@ +void hash_init (void); +void forget_all (void); +void forget_created (ino_t ino, dev_t dev); +char *remember_copied (const char *node, ino_t ino, dev_t dev); +int remember_created (const char *path); diff --git a/src/apps/bin/coreutils-5.0/src/cp.c b/src/apps/bin/coreutils-5.0/src/cp.c new file mode 100644 index 0000000000..1f8a975aa3 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/cp.c @@ -0,0 +1,1062 @@ +/* cp.c -- file copying (main routines) + Copyright (C) 89, 90, 91, 1995-2003 Free Software Foundation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Written by Torbjorn Granlund, David MacKenzie, and Jim Meyering. */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include +#include +#include +#include + +#include "system.h" +#include "argmatch.h" +#include "backupfile.h" +#include "copy.h" +#include "cp-hash.h" +#include "error.h" +#include "dirname.h" +#include "path-concat.h" +#include "quote.h" + +#define ASSIGN_BASENAME_STRDUPA(Dest, File_name) \ + do \ + { \ + char *tmp_abns_; \ + ASSIGN_STRDUPA (tmp_abns_, (File_name)); \ + strip_trailing_slashes (tmp_abns_); \ + Dest = base_name (tmp_abns_); \ + } \ + while (0) + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "cp" + +#define AUTHORS N_ ("Torbjorn Granlund, David MacKenzie, and Jim Meyering") + +#ifndef _POSIX_VERSION +uid_t geteuid (); +#endif + +/* Used by do_copy, make_path_private, and re_protect + to keep a list of leading directories whose protections + need to be fixed after copying. */ +struct dir_attr +{ + int is_new_dir; + int slash_offset; + struct dir_attr *next; +}; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + COPY_CONTENTS_OPTION = CHAR_MAX + 1, + NO_PRESERVE_ATTRIBUTES_OPTION, + PARENTS_OPTION, + PRESERVE_ATTRIBUTES_OPTION, + REPLY_OPTION, + SPARSE_OPTION, + STRIP_TRAILING_SLASHES_OPTION, + TARGET_DIRECTORY_OPTION, + UNLINK_DEST_BEFORE_OPENING +}; + +/* Initial number of entries in each hash table entry's table of inodes. */ +#define INITIAL_HASH_MODULE 100 + +/* Initial number of entries in the inode hash table. */ +#define INITIAL_ENTRY_TAB_SIZE 70 + +/* The invocation name of this program. */ +char *program_name; + +/* If nonzero, the command "cp x/e_file e_dir" uses "e_dir/x/e_file" + as its destination instead of the usual "e_dir/e_file." */ +static int flag_path = 0; + +/* Remove any trailing slashes from each SOURCE argument. */ +static int remove_trailing_slashes; + +static char const *const sparse_type_string[] = +{ + "never", "auto", "always", 0 +}; + +static enum Sparse_type const sparse_type[] = +{ + SPARSE_NEVER, SPARSE_AUTO, SPARSE_ALWAYS +}; + +/* Valid arguments to the `--reply' option. */ +static char const* const reply_args[] = +{ + "yes", "no", "query", 0 +}; + +/* The values that correspond to the above strings. */ +static int const reply_vals[] = +{ + I_ALWAYS_YES, I_ALWAYS_NO, I_ASK_USER +}; + +/* The error code to return to the system. */ +static int exit_status = 0; + +static struct option const long_opts[] = +{ + {"archive", no_argument, NULL, 'a'}, + {"backup", optional_argument, NULL, 'b'}, + {"copy-contents", no_argument, NULL, COPY_CONTENTS_OPTION}, + {"dereference", no_argument, NULL, 'L'}, + {"force", no_argument, NULL, 'f'}, + {"interactive", no_argument, NULL, 'i'}, + {"link", no_argument, NULL, 'l'}, + {"no-dereference", no_argument, NULL, 'P'}, + {"no-preserve", required_argument, NULL, NO_PRESERVE_ATTRIBUTES_OPTION}, + {"one-file-system", no_argument, NULL, 'x'}, + {"parents", no_argument, NULL, PARENTS_OPTION}, + {"path", no_argument, NULL, PARENTS_OPTION}, /* Deprecated. */ + {"preserve", optional_argument, NULL, PRESERVE_ATTRIBUTES_OPTION}, + {"recursive", no_argument, NULL, 'R'}, + {"remove-destination", no_argument, NULL, UNLINK_DEST_BEFORE_OPENING}, + {"reply", required_argument, NULL, REPLY_OPTION}, + {"sparse", required_argument, NULL, SPARSE_OPTION}, + {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION}, + {"suffix", required_argument, NULL, 'S'}, + {"symbolic-link", no_argument, NULL, 's'}, + {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION}, + {"update", no_argument, NULL, 'u'}, + {"verbose", no_argument, NULL, 'v'}, + {"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */ + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... SOURCE DEST\n\ + or: %s [OPTION]... SOURCE... DIRECTORY\n\ + or: %s [OPTION]... --target-directory=DIRECTORY SOURCE...\n\ +"), + program_name, program_name, program_name); + fputs (_("\ +Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -a, --archive same as -dpR\n\ + --backup[=CONTROL] make a backup of each existing destination file\n\ + -b like --backup but does not accept an argument\n\ + --copy-contents copy contents of special files when recursive\n\ + -d same as --no-dereference --preserve=link\n\ +"), stdout); + fputs (_("\ + --no-dereference never follow symbolic links\n\ + -f, --force if an existing destination file cannot be\n\ + opened, remove it and try again\n\ + -i, --interactive prompt before overwrite\n\ + -H follow command-line symbolic links\n\ +"), stdout); + fputs (_("\ + -l, --link link files instead of copying\n\ + -L, --dereference always follow symbolic links\n\ + -p same as --preserve=mode,ownership,timestamps\n\ + --preserve[=ATTR_LIST] preserve the specified attributes (default:\n\ + mode,ownership,timestamps), if possible\n\ + additional attributes: links, all\n\ +"), stdout); + fputs (_("\ + --no-preserve=ATTR_LIST don't preserve the specified attributes\n\ + --parents append source path to DIRECTORY\n\ + -P same as `--no-dereference'\n\ +"), stdout); + fputs (_("\ + -R, -r, --recursive copy directories recursively\n\ + --remove-destination remove each existing destination file before\n\ + attempting to open it (contrast with --force)\n\ +"), stdout); + fputs (_("\ + --reply={yes,no,query} specify how to handle the prompt about an\n\ + existing destination file\n\ + --sparse=WHEN control creation of sparse files\n\ + --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\ + argument\n\ +"), stdout); + fputs (_("\ + -s, --symbolic-link make symbolic links instead of copying\n\ + -S, --suffix=SUFFIX override the usual backup suffix\n\ + --target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY\n\ +"), stdout); + fputs (_("\ + -u, --update copy only when the SOURCE file is newer\n\ + than the destination file or when the\n\ + destination file is missing\n\ + -v, --verbose explain what is being done\n\ + -x, --one-file-system stay on this file system\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +By default, sparse SOURCE files are detected by a crude heuristic and the\n\ +corresponding DEST file is made sparse as well. That is the behavior\n\ +selected by --sparse=auto. Specify --sparse=always to create a sparse DEST\n\ +file whenever the SOURCE file contains a long enough sequence of zero bytes.\n\ +Use --sparse=never to inhibit creation of sparse files.\n\ +\n\ +"), stdout); + fputs (_("\ +The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ +The version control method may be selected via the --backup option or through\n\ +the VERSION_CONTROL environment variable. Here are the values:\n\ +\n\ +"), stdout); + fputs (_("\ + none, off never make backups (even if --backup is given)\n\ + numbered, t make numbered backups\n\ + existing, nil numbered if numbered backups exist, simple otherwise\n\ + simple, never always make simple backups\n\ +"), stdout); + fputs (_("\ +\n\ +As a special case, cp makes a backup of SOURCE when the force and backup\n\ +options are given and SOURCE and DEST are the same name for an existing,\n\ +regular file.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +/* Ensure that the parent directories of CONST_DST_PATH have the + correct protections, for the --parents option. This is done + after all copying has been completed, to allow permissions + that don't include user write/execute. + + SRC_OFFSET is the index in CONST_DST_PATH of the beginning of the + source directory name. + + ATTR_LIST is a null-terminated linked list of structures that + indicates the end of the filename of each intermediate directory + in CONST_DST_PATH that may need to have its attributes changed. + The command `cp --parents --preserve a/b/c d/e_dir' changes the + attributes of the directories d/e_dir/a and d/e_dir/a/b to match + the corresponding source directories regardless of whether they + existed before the `cp' command was given. + + Return 0 if the parent of CONST_DST_PATH and any intermediate + directories specified by ATTR_LIST have the proper permissions + when done, otherwise 1. */ + +static int +re_protect (const char *const_dst_path, int src_offset, + struct dir_attr *attr_list, const struct cp_options *x) +{ + struct dir_attr *p; + char *dst_path; /* A copy of CONST_DST_PATH we can change. */ + char *src_path; /* The source name in `dst_path'. */ + uid_t myeuid = geteuid (); + + dst_path = (char *) alloca (strlen (const_dst_path) + 1); + strcpy (dst_path, const_dst_path); + src_path = dst_path + src_offset; + + for (p = attr_list; p; p = p->next) + { + struct stat src_sb; + + dst_path[p->slash_offset] = '\0'; + + if ((*(x->xstat)) (src_path, &src_sb)) + { + error (0, errno, _("failed to get attributes of %s"), + quote (src_path)); + return 1; + } + + /* Adjust the times (and if possible, ownership) for the copy. + chown turns off set[ug]id bits for non-root, + so do the chmod last. */ + + if (x->preserve_timestamps) + { + struct utimbuf utb; + + /* There's currently no interface to set file timestamps with + better than 1-second resolution, so discard any fractional + part of the source timestamp. */ + + utb.actime = src_sb.st_atime; + utb.modtime = src_sb.st_mtime; + + if (utime (dst_path, &utb)) + { + error (0, errno, _("failed to preserve times for %s"), + quote (dst_path)); + return 1; + } + } + + if (x->preserve_ownership) + { + /* If non-root uses -p, it's ok if we can't preserve ownership. + But root probably wants to know, e.g. if NFS disallows it, + or if the target system doesn't support file ownership. */ + if (chown (dst_path, src_sb.st_uid, src_sb.st_gid) + && ((errno != EPERM && errno != EINVAL) || myeuid == 0)) + { + error (0, errno, _("failed to preserve ownership for %s"), + quote (dst_path)); + return 1; + } + } + + if (x->preserve_mode || p->is_new_dir) + { + if (chmod (dst_path, src_sb.st_mode & x->umask_kill)) + { + error (0, errno, _("failed to preserve permissions for %s"), + quote (dst_path)); + return 1; + } + } + + dst_path[p->slash_offset] = '/'; + } + return 0; +} + +/* Ensure that the parent directory of CONST_DIRPATH exists, for + the --parents option. + + SRC_OFFSET is the index in CONST_DIRPATH (which is a destination + path) of the beginning of the source directory name. + Create any leading directories that don't already exist, + giving them permissions MODE. + If VERBOSE_FMT_STRING is nonzero, use it as a printf format + string for printing a message after successfully making a directory. + The format should take two string arguments: the names of the + source and destination directories. + Creates a linked list of attributes of intermediate directories, + *ATTR_LIST, for re_protect to use after calling copy. + Sets *NEW_DST to 1 if this function creates parent of CONST_DIRPATH. + + Return 0 if parent of CONST_DIRPATH exists as a directory with the proper + permissions when done, otherwise 1. */ + +/* FIXME: find a way to synch this function with the one in lib/makepath.c. */ + +static int +make_path_private (const char *const_dirpath, int src_offset, int mode, + const char *verbose_fmt_string, struct dir_attr **attr_list, + int *new_dst, int (*xstat)()) +{ + struct stat stats; + char *dirpath; /* A copy of CONST_DIRPATH we can change. */ + char *src; /* Source name in `dirpath'. */ + char *dst_dirname; /* Leading path of `dirpath'. */ + size_t dirlen; /* Length of leading path of `dirpath'. */ + + dirpath = (char *) alloca (strlen (const_dirpath) + 1); + strcpy (dirpath, const_dirpath); + + src = dirpath + src_offset; + + dirlen = dir_len (dirpath); + dst_dirname = (char *) alloca (dirlen + 1); + memcpy (dst_dirname, dirpath, dirlen); + dst_dirname[dirlen] = '\0'; + + *attr_list = NULL; + + if ((*xstat) (dst_dirname, &stats)) + { + /* Parent of CONST_DIRNAME does not exist. + Make all missing intermediate directories. */ + char *slash; + + slash = src; + while (*slash == '/') + slash++; + while ((slash = strchr (slash, '/'))) + { + /* Add this directory to the list of directories whose modes need + fixing later. */ + struct dir_attr *new = + (struct dir_attr *) xmalloc (sizeof (struct dir_attr)); + new->slash_offset = slash - dirpath; + new->next = *attr_list; + *attr_list = new; + + *slash = '\0'; + if ((*xstat) (dirpath, &stats)) + { + /* This element of the path does not exist. We must set + *new_dst and new->is_new_dir inside this loop because, + for example, in the command `cp --parents ../a/../b/c e_dir', + make_path_private creates only e_dir/../a if ./b already + exists. */ + *new_dst = 1; + new->is_new_dir = 1; + if (mkdir (dirpath, mode)) + { + error (0, errno, _("cannot make directory %s"), + quote (dirpath)); + return 1; + } + else + { + if (verbose_fmt_string != NULL) + printf (verbose_fmt_string, src, dirpath); + } + } + else if (!S_ISDIR (stats.st_mode)) + { + error (0, 0, _("%s exists but is not a directory"), + quote (dirpath)); + return 1; + } + else + { + new->is_new_dir = 0; + *new_dst = 0; + } + *slash++ = '/'; + + /* Avoid unnecessary calls to `stat' when given + pathnames containing multiple adjacent slashes. */ + while (*slash == '/') + slash++; + } + } + + /* We get here if the parent of `dirpath' already exists. */ + + else if (!S_ISDIR (stats.st_mode)) + { + error (0, 0, _("%s exists but is not a directory"), quote (dst_dirname)); + return 1; + } + else + { + *new_dst = 0; + } + return 0; +} + +/* Scan the arguments, and copy each by calling copy. + Return 0 if successful, 1 if any errors occur. */ + +static int +do_copy (int n_files, char **file, const char *target_directory, + struct cp_options *x) +{ + const char *dest; + struct stat sb; + int new_dst = 0; + int ret = 0; + int dest_is_dir = 0; + + if (n_files <= 0) + { + error (0, 0, _("missing file argument")); + usage (EXIT_FAILURE); + } + if (n_files == 1 && !target_directory) + { + error (0, 0, _("missing destination file")); + usage (EXIT_FAILURE); + } + + if (target_directory) + dest = target_directory; + else + { + dest = file[n_files - 1]; + --n_files; + } + + /* Initialize these hash tables only if we'll need them. + The problems they're used to detect can arise only if + there are two or more files to copy. */ + if (n_files >= 2) + { + dest_info_init (x); + src_info_init (x); + } + + if (lstat (dest, &sb)) + { + if (errno != ENOENT) + { + error (0, errno, _("accessing %s"), quote (dest)); + return 1; + } + + new_dst = 1; + } + else + { + struct stat sbx; + + /* If `dest' is not a symlink to a nonexistent file, use + the results of stat instead of lstat, so we can copy files + into symlinks to directories. */ + if (stat (dest, &sbx) == 0) + sb = sbx; + + dest_is_dir = S_ISDIR (sb.st_mode); + } + + if (!dest_is_dir) + { + if (target_directory) + { + error (0, 0, _("%s: specified target is not a directory"), + quote (dest)); + usage (EXIT_FAILURE); + } + + if (n_files > 1) + { + error (0, 0, + _("copying multiple files, but last argument %s is not a directory"), + quote (dest)); + usage (EXIT_FAILURE); + } + } + + if (dest_is_dir) + { + /* cp file1...filen edir + Copy the files `file1' through `filen' + to the existing directory `edir'. */ + int i; + + for (i = 0; i < n_files; i++) + { + char *dst_path; + int parent_exists = 1; /* True if dir_name (dst_path) exists. */ + struct dir_attr *attr_list; + char *arg_in_concat = NULL; + char *arg = file[i]; + + /* Trailing slashes are meaningful (i.e., maybe worth preserving) + only in the source file names. */ + if (remove_trailing_slashes) + strip_trailing_slashes (arg); + + if (flag_path) + { + char *arg_no_trailing_slash; + + /* Use `arg' without trailing slashes in constructing destination + file names. Otherwise, we can end up trying to create a + directory via `mkdir ("dst/foo/"...', which is not portable. + It fails, due to the trailing slash, on at least + NetBSD 1.[34] systems. */ + ASSIGN_STRDUPA (arg_no_trailing_slash, arg); + strip_trailing_slashes (arg_no_trailing_slash); + + /* Append all of `arg' (minus any trailing slash) to `dest'. */ + dst_path = path_concat (dest, arg_no_trailing_slash, + &arg_in_concat); + if (dst_path == NULL) + xalloc_die (); + + /* For --parents, we have to make sure that the directory + dir_name (dst_path) exists. We may have to create a few + leading directories. */ + parent_exists = !make_path_private (dst_path, + arg_in_concat - dst_path, + S_IRWXU, + (x->verbose + ? "%s -> %s\n" : NULL), + &attr_list, &new_dst, + x->xstat); + } + else + { + char *arg_base; + /* Append the last component of `arg' to `dest'. */ + + ASSIGN_BASENAME_STRDUPA (arg_base, arg); + /* For `cp -R source/.. dest', don't copy into `dest/..'. */ + dst_path = (STREQ (arg_base, "..") + ? xstrdup (dest) + : path_concat (dest, arg_base, NULL)); + } + + if (!parent_exists) + { + /* make_path_private failed, so don't even attempt the copy. */ + ret = 1; + } + else + { + int copy_into_self; + ret |= copy (arg, dst_path, new_dst, x, ©_into_self, NULL); + + if (flag_path) + { + ret |= re_protect (dst_path, arg_in_concat - dst_path, + attr_list, x); + } + } + + free (dst_path); + } + return ret; + } + else /* if (n_files == 1) */ + { + char *new_dest; + char *source; + int unused; + struct stat source_stats; + + if (flag_path) + { + error (0, 0, + _("when preserving paths, the destination must be a directory")); + usage (EXIT_FAILURE); + } + + source = file[0]; + + /* When the force and backup options have been specified and + the source and destination are the same name for an existing + regular file, convert the user's command, e.g., + `cp --force --backup foo foo' to `cp --force foo fooSUFFIX' + where SUFFIX is determined by any version control options used. */ + + if (x->unlink_dest_after_failed_open + && x->backup_type != none + && STREQ (source, dest) + && !new_dst && S_ISREG (sb.st_mode)) + { + static struct cp_options x_tmp; + + new_dest = find_backup_file_name (dest, x->backup_type); + /* Set x->backup_type to `none' so that the normal backup + mechanism is not used when performing the actual copy. + backup_type must be set to `none' only *after* the above + call to find_backup_file_name -- that function uses + backup_type to determine the suffix it applies. */ + x_tmp = *x; + x_tmp.backup_type = none; + x = &x_tmp; + + if (new_dest == NULL) + xalloc_die (); + } + + /* When the destination is specified with a trailing slash and the + source exists but is not a directory, convert the user's command + `cp source dest/' to `cp source dest/basename(source)'. Doing + this ensures that the command `cp non-directory file/' will now + fail rather than performing the copy. COPY diagnoses the case of + `cp directory non-directory'. */ + + else if (dest[strlen (dest) - 1] == '/' + && lstat (source, &source_stats) == 0 + && !S_ISDIR (source_stats.st_mode)) + { + char *source_base; + + ASSIGN_BASENAME_STRDUPA (source_base, source); + new_dest = (char *) alloca (strlen (dest) + + strlen (source_base) + 1); + stpcpy (stpcpy (new_dest, dest), source_base); + } + else + { + new_dest = (char *) dest; + } + + return copy (source, new_dest, new_dst, x, &unused, NULL); + } + + /* unreachable */ +} + +static void +cp_option_init (struct cp_options *x) +{ + x->copy_as_regular = 1; + x->dereference = DEREF_UNDEFINED; + x->unlink_dest_before_opening = 0; + x->unlink_dest_after_failed_open = 0; + x->hard_link = 0; + x->interactive = I_UNSPECIFIED; + x->myeuid = geteuid (); + x->move_mode = 0; + x->one_file_system = 0; + + x->preserve_ownership = 0; + x->preserve_links = 0; + x->preserve_mode = 0; + x->preserve_timestamps = 0; + + x->require_preserve = 0; + x->recursive = 0; + x->sparse_mode = SPARSE_AUTO; + x->symbolic_link = 0; + x->set_mode = 0; + x->mode = 0; + + /* Not used. */ + x->stdin_tty = 0; + + /* Find out the current file creation mask, to knock the right bits + when using chmod. The creation mask is set to be liberal, so + that created directories can be written, even if it would not + have been allowed with the mask this process was started with. */ + x->umask_kill = ~ umask (0); + + x->update = 0; + x->verbose = 0; + x->dest_info = NULL; + x->src_info = NULL; +} + +/* Given a string, ARG, containing a comma-separated list of arguments + to the --preserve option, set the appropriate fields of X to ON_OFF. */ +static void +decode_preserve_arg (char const *arg, struct cp_options *x, int on_off) +{ + enum File_attribute + { + PRESERVE_MODE, + PRESERVE_TIMESTAMPS, + PRESERVE_OWNERSHIP, + PRESERVE_LINK, + PRESERVE_ALL + }; + static enum File_attribute const preserve_vals[] = + { + PRESERVE_MODE, PRESERVE_TIMESTAMPS, + PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_ALL + }; + + /* Valid arguments to the `--preserve' option. */ + static char const* const preserve_args[] = + { + "mode", "timestamps", + "ownership", "links", "all", 0 + }; + + char *arg_writable = xstrdup (arg); + char *s = arg_writable; + do + { + /* find next comma */ + char *comma = strchr (s, ','); + enum File_attribute val; + + /* If we found a comma, put a NUL in its place and advance. */ + if (comma) + *comma++ = 0; + + /* process S. */ + val = XARGMATCH ("--preserve", s, preserve_args, preserve_vals); + switch (val) + { + case PRESERVE_MODE: + x->preserve_mode = on_off; + break; + + case PRESERVE_TIMESTAMPS: + x->preserve_timestamps = on_off; + break; + + case PRESERVE_OWNERSHIP: + x->preserve_ownership = on_off; + break; + + case PRESERVE_LINK: + x->preserve_links = on_off; + break; + + case PRESERVE_ALL: + x->preserve_mode = on_off; + x->preserve_timestamps = on_off; + x->preserve_ownership = on_off; + x->preserve_links = on_off; + break; + + default: + abort (); + } + s = comma; + } + while (s); + + free (arg_writable); +} + +int +main (int argc, char **argv) +{ + int c; + int make_backups = 0; + char *backup_suffix_string; + char *version_control_string = NULL; + struct cp_options x; + int copy_contents = 0; + char *target_directory = NULL; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + cp_option_init (&x); + + /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + + while ((c = getopt_long (argc, argv, "abdfHilLprsuvxPRS:V:", long_opts, NULL)) + != -1) + { + switch (c) + { + case 0: + break; + + case SPARSE_OPTION: + x.sparse_mode = XARGMATCH ("--sparse", optarg, + sparse_type_string, sparse_type); + break; + + case 'a': /* Like -dpPR. */ + x.dereference = DEREF_NEVER; + x.preserve_links = 1; + x.preserve_ownership = 1; + x.preserve_mode = 1; + x.preserve_timestamps = 1; + x.require_preserve = 1; + x.recursive = 1; + break; + + case 'V': /* FIXME: this is deprecated. Remove it in 2001. */ + error (0, 0, + _("warning: --version-control (-V) is obsolete; support for\ + it\nwill be removed in some future release. Use --backup=%s instead." + ), optarg); + /* Fall through. */ + + case 'b': + make_backups = 1; + if (optarg) + version_control_string = optarg; + break; + + case COPY_CONTENTS_OPTION: + copy_contents = 1; + break; + + case 'd': + x.preserve_links = 1; + x.dereference = DEREF_NEVER; + break; + + case 'f': + x.unlink_dest_after_failed_open = 1; + break; + + case 'H': + x.dereference = DEREF_COMMAND_LINE_ARGUMENTS; + break; + + case 'i': + x.interactive = I_ASK_USER; + break; + + case 'l': + x.hard_link = 1; + break; + + case 'L': + x.dereference = DEREF_ALWAYS; + break; + + case 'P': + x.dereference = DEREF_NEVER; + break; + + case NO_PRESERVE_ATTRIBUTES_OPTION: + decode_preserve_arg (optarg, &x, 0); + break; + + case PRESERVE_ATTRIBUTES_OPTION: + if (optarg == NULL) + { + /* Fall through to the case for `p' below. */ + } + else + { + decode_preserve_arg (optarg, &x, 1); + x.require_preserve = 1; + break; + } + + case 'p': + x.preserve_ownership = 1; + x.preserve_mode = 1; + x.preserve_timestamps = 1; + x.require_preserve = 1; + break; + + case PARENTS_OPTION: + flag_path = 1; + break; + + case 'r': + case 'R': + x.recursive = 1; + break; + + case REPLY_OPTION: + x.interactive = XARGMATCH ("--reply", optarg, + reply_args, reply_vals); + break; + + case UNLINK_DEST_BEFORE_OPENING: + x.unlink_dest_before_opening = 1; + break; + + case STRIP_TRAILING_SLASHES_OPTION: + remove_trailing_slashes = 1; + break; + + case 's': +#ifdef S_ISLNK + x.symbolic_link = 1; +#else + error (EXIT_FAILURE, 0, + _("symbolic links are not supported on this system")); +#endif + break; + + case TARGET_DIRECTORY_OPTION: + target_directory = optarg; + break; + + case 'u': + x.update = 1; + break; + + case 'v': + x.verbose = 1; + break; + + case 'x': + x.one_file_system = 1; + break; + + case 'S': + make_backups = 1; + backup_suffix_string = optarg; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (x.hard_link && x.symbolic_link) + { + error (0, 0, _("cannot make both hard and symbolic links")); + usage (EXIT_FAILURE); + } + + if (backup_suffix_string) + simple_backup_suffix = xstrdup (backup_suffix_string); + + x.backup_type = (make_backups + ? xget_version (_("backup type"), + version_control_string) + : none); + + if (x.preserve_mode == 1) + x.umask_kill = ~ (mode_t) 0; + + if (x.dereference == DEREF_UNDEFINED) + { + if (x.recursive) + /* This is compatible with FreeBSD. */ + x.dereference = DEREF_NEVER; + else + x.dereference = DEREF_ALWAYS; + } + + /* The key difference between -d (--no-dereference) and not is the version + of `stat' to call. */ + + if (x.dereference == DEREF_NEVER) + x.xstat = lstat; + else + { + /* For DEREF_COMMAND_LINE_ARGUMENTS, x.xstat must be stat for + each command line argument, but must later be `lstat' for + any symlinks that are found via recursive traversal. */ + x.xstat = stat; + } + + if (x.recursive) + x.copy_as_regular = copy_contents; + + /* If --force (-f) was specified and we're in link-creation mode, + first remove any existing destination file. */ + if (x.unlink_dest_after_failed_open && (x.hard_link || x.symbolic_link)) + x.unlink_dest_before_opening = 1; + + /* Allocate space for remembering copied and created files. */ + + hash_init (); + + exit_status |= do_copy (argc - optind, argv + optind, target_directory, &x); + + forget_all (); + + exit (exit_status); +} diff --git a/src/apps/bin/coreutils-5.0/src/csplit.c b/src/apps/bin/coreutils-5.0/src/csplit.c new file mode 100644 index 0000000000..4419319661 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/csplit.c @@ -0,0 +1,1537 @@ +/* csplit - split a file into sections determined by context lines + Copyright (C) 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Stuart Kemp, cpsrk@groper.jcu.edu.au. + Modified by David MacKenzie, djm@gnu.ai.mit.edu. */ + +#include + +#include +#include +#include +#include + +#include "system.h" +#include "closeout.h" + +#include + +#include "error.h" +#include "inttostr.h" +#include "safe-read.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "csplit" + +#define AUTHORS N_ ("Stuart Kemp and David MacKenzie") + +#ifndef TRUE +# define FALSE 0 +# define TRUE 1 +#endif + +/* Increment size of area for control records. */ +#define ALLOC_SIZE 20 + +/* The default prefix for output file names. */ +#define DEFAULT_PREFIX "xx" + +typedef int boolean; + +/* A compiled pattern arg. */ +struct control +{ + char *regexpr; /* Non-compiled regular expression. */ + struct re_pattern_buffer re_compiled; /* Compiled regular expression. */ + int offset; /* Offset from regexp to split at. */ + uintmax_t lines_required; /* Number of lines required. */ + uintmax_t repeat; /* Repeat count. */ + int repeat_forever; /* Non-zero if `*' used as a repeat count. */ + int argnum; /* ARGV index. */ + boolean ignore; /* If true, produce no output (for regexp). */ +}; + +/* Initial size of data area in buffers. */ +#define START_SIZE 8191 + +/* Increment size for data area. */ +#define INCR_SIZE 2048 + +/* Number of lines kept in each node in line list. */ +#define CTRL_SIZE 80 + +#ifdef DEBUG +/* Some small values to test the algorithms. */ +# define START_SIZE 200 +# define INCR_SIZE 10 +# define CTRL_SIZE 1 +#endif + +/* A string with a length count. */ +struct cstring +{ + unsigned int len; + char *str; +}; + +/* Pointers to the beginnings of lines in the buffer area. + These structures are linked together if needed. */ +struct line +{ + unsigned used; /* Number of offsets used in this struct. */ + unsigned insert_index; /* Next offset to use when inserting line. */ + unsigned retrieve_index; /* Next index to use when retrieving line. */ + struct cstring starts[CTRL_SIZE]; /* Lines in the data area. */ + struct line *next; /* Next in linked list. */ +}; + +/* The structure to hold the input lines. + Contains a pointer to the data area and a list containing + pointers to the individual lines. */ +struct buffer_record +{ + unsigned bytes_alloc; /* Size of the buffer area. */ + unsigned bytes_used; /* Bytes used in the buffer area. */ + unsigned start_line; /* First line number in this buffer. */ + unsigned first_available; /* First line that can be retrieved. */ + unsigned num_lines; /* Number of complete lines in this buffer. */ + char *buffer; /* Data area. */ + struct line *line_start; /* Head of list of pointers to lines. */ + struct line *curr_line; /* The line start record currently in use. */ + struct buffer_record *next; +}; + +static void close_output_file (void); +static void create_output_file (void); +static void delete_all_files (void); +static void save_line_to_file (const struct cstring *line); +void usage (int status); + +/* The name this program was run with. */ +char *program_name; + +/* Convert the number of 8-bit bytes of a binary representation to + the number of characters required to represent the same quantity + as an unsigned octal. For example, a 32-bit (4-byte) quantity may + require a field width as wide as 11 characters. */ +static const unsigned int bytes_to_octal_digits[] = +{0, 3, 6, 8, 11, 14, 16, 19, 22, 25, 27, 30, 32, 35, 38, 41, 43}; + +/* Input file descriptor. */ +static int input_desc = 0; + +/* List of available buffers. */ +static struct buffer_record *free_list = NULL; + +/* Start of buffer list. */ +static struct buffer_record *head = NULL; + +/* Partially read line. */ +static char *hold_area = NULL; + +/* Number of chars in `hold_area'. */ +static unsigned hold_count = 0; + +/* Number of the last line in the buffers. */ +static unsigned last_line_number = 0; + +/* Number of the line currently being examined. */ +static unsigned current_line = 0; + +/* If TRUE, we have read EOF. */ +static boolean have_read_eof = FALSE; + +/* Name of output files. */ +static char *filename_space = NULL; + +/* Prefix part of output file names. */ +static char *prefix = NULL; + +/* Suffix part of output file names. */ +static char *suffix = NULL; + +/* Number of digits to use in output file names. */ +static int digits = 2; + +/* Number of files created so far. */ +static unsigned int files_created = 0; + +/* Number of bytes written to current file. */ +static unsigned int bytes_written; + +/* Output file pointer. */ +static FILE *output_stream = NULL; + +/* Output file name. */ +static char *output_filename = NULL; + +/* Perhaps it would be cleaner to pass arg values instead of indexes. */ +static char **global_argv; + +/* If TRUE, do not print the count of bytes in each output file. */ +static boolean suppress_count; + +/* If TRUE, remove output files on error. */ +static boolean remove_files; + +/* If TRUE, remove all output files which have a zero length. */ +static boolean elide_empty_files; + +/* The compiled pattern arguments, which determine how to split + the input file. */ +static struct control *controls; + +/* Number of elements in `controls'. */ +static unsigned int control_used; + +static struct option const longopts[] = +{ + {"digits", required_argument, NULL, 'n'}, + {"quiet", no_argument, NULL, 'q'}, + {"silent", no_argument, NULL, 's'}, + {"keep-files", no_argument, NULL, 'k'}, + {"elide-empty-files", no_argument, NULL, 'z'}, + {"prefix", required_argument, NULL, 'f'}, + {"suffix-format", required_argument, NULL, 'b'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +/* Optionally remove files created so far; then exit. + Called when an error detected. */ + +static void +cleanup (void) +{ + if (output_stream) + close_output_file (); + + if (remove_files) + delete_all_files (); +} + +static void +cleanup_fatal (void) +{ + cleanup (); + exit (EXIT_FAILURE); +} + +static RETSIGTYPE +interrupt_handler (int sig) +{ +#ifdef SA_NOCLDSTOP + struct sigaction sigact; + + sigact.sa_handler = SIG_DFL; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (sig, &sigact, NULL); +#else + signal (sig, SIG_DFL); +#endif + cleanup (); + raise (sig); +} + +/* Keep track of NUM chars of a partial line in buffer START. + These chars will be retrieved later when another large buffer is read. + It is not necessary to create a new buffer for these chars; instead, + we keep a pointer to the existing buffer. This buffer *is* on the + free list, and when the next buffer is obtained from this list + (even if it is this one), these chars will be placed at the + start of the new buffer. */ + +static void +save_to_hold_area (char *start, unsigned int num) +{ + hold_area = start; + hold_count = num; +} + +/* Read up to MAX_N_BYTES chars from the input stream into DEST. + Return the number of chars read. */ +/* FIXME: MAX_N_BYTES should be of type size_t, but if you pull + that thread, you'll find there are many other `unsigned' types + in this file that should also be changed. */ + +static size_t +read_input (char *dest, int max_n_bytes) +{ + size_t bytes_read; + + if (max_n_bytes == 0) + return 0; + + bytes_read = safe_read (input_desc, dest, max_n_bytes); + + if (bytes_read == 0) + have_read_eof = TRUE; + + if (bytes_read == SAFE_READ_ERROR) + { + error (0, errno, _("read error")); + cleanup_fatal (); + } + + return bytes_read; +} + +/* Initialize existing line record P. */ + +static void +clear_line_control (struct line *p) +{ + p->used = 0; + p->insert_index = 0; + p->retrieve_index = 0; +} + +/* Initialize all line records in B. */ + +static void +clear_all_line_control (struct buffer_record *b) +{ + struct line *l; + + for (l = b->line_start; l; l = l->next) + clear_line_control (l); +} + +/* Return a new, initialized line record. */ + +static struct line * +new_line_control (void) +{ + struct line *p; + + p = (struct line *) xmalloc (sizeof (struct line)); + + p->next = NULL; + clear_line_control (p); + + return p; +} + +/* Record LINE_START, which is the address of the start of a line + of length LINE_LEN in the large buffer, in the lines buffer of B. */ + +static void +keep_new_line (struct buffer_record *b, char *line_start, int line_len) +{ + struct line *l; + + /* If there is no existing area to keep line info, get some. */ + if (b->line_start == NULL) + b->line_start = b->curr_line = new_line_control (); + + /* If existing area for lines is full, get more. */ + if (b->curr_line->used == CTRL_SIZE) + { + b->curr_line->next = new_line_control (); + b->curr_line = b->curr_line->next; + } + + l = b->curr_line; + + /* Record the start of the line, and update counters. */ + l->starts[l->insert_index].str = line_start; + l->starts[l->insert_index].len = line_len; + l->used++; + l->insert_index++; +} + +/* Scan the buffer in B for newline characters + and record the line start locations and lengths in B. + Return the number of lines found in this buffer. + + There may be an incomplete line at the end of the buffer; + a pointer is kept to this area, which will be used when + the next buffer is filled. */ + +static unsigned int +record_line_starts (struct buffer_record *b) +{ + char *line_start; /* Start of current line. */ + char *line_end; /* End of each line found. */ + unsigned int bytes_left; /* Length of incomplete last line. */ + unsigned int lines; /* Number of lines found. */ + unsigned int line_length; /* Length of each line found. */ + + if (b->bytes_used == 0) + return 0; + + lines = 0; + line_start = b->buffer; + bytes_left = b->bytes_used; + + for (;;) + { + line_end = memchr (line_start, '\n', bytes_left); + if (line_end == NULL) + break; + line_length = line_end - line_start + 1; + keep_new_line (b, line_start, line_length); + bytes_left -= line_length; + line_start = line_end + 1; + lines++; + } + + /* Check for an incomplete last line. */ + if (bytes_left) + { + if (have_read_eof) + { + keep_new_line (b, line_start, bytes_left); + lines++; + } + else + save_to_hold_area (line_start, bytes_left); + } + + b->num_lines = lines; + b->first_available = b->start_line = last_line_number + 1; + last_line_number += lines; + + return lines; +} + +/* Return a new buffer with room to store SIZE bytes, plus + an extra byte for safety. */ + +static struct buffer_record * +create_new_buffer (unsigned int size) +{ + struct buffer_record *new_buffer; + + new_buffer = (struct buffer_record *) + xmalloc (sizeof (struct buffer_record)); + + new_buffer->buffer = (char *) xmalloc (size + 1); + + new_buffer->bytes_alloc = size; + new_buffer->line_start = new_buffer->curr_line = NULL; + + return new_buffer; +} + +/* Return a new buffer of at least MINSIZE bytes. If a buffer of at + least that size is currently free, use it, otherwise create a new one. */ + +static struct buffer_record * +get_new_buffer (unsigned int min_size) +{ + struct buffer_record *p, *q; + struct buffer_record *new_buffer; /* Buffer to return. */ + unsigned int alloc_size; /* Actual size that will be requested. */ + + alloc_size = START_SIZE; + while (min_size > alloc_size) + alloc_size += INCR_SIZE; + + if (free_list == NULL) + new_buffer = create_new_buffer (alloc_size); + else + { + /* Use first-fit to find a buffer. */ + p = new_buffer = NULL; + q = free_list; + + do + { + if (q->bytes_alloc >= min_size) + { + if (p == NULL) + free_list = q->next; + else + p->next = q->next; + break; + } + p = q; + q = q->next; + } + while (q); + + new_buffer = (q ? q : create_new_buffer (alloc_size)); + + new_buffer->curr_line = new_buffer->line_start; + clear_all_line_control (new_buffer); + } + + new_buffer->num_lines = 0; + new_buffer->bytes_used = 0; + new_buffer->start_line = new_buffer->first_available = last_line_number + 1; + new_buffer->next = NULL; + + return new_buffer; +} + +/* Add buffer BUF to the list of free buffers. */ + +static void +free_buffer (struct buffer_record *buf) +{ + buf->next = free_list; + free_list = buf; +} + +/* Append buffer BUF to the linked list of buffers that contain + some data yet to be processed. */ + +static void +save_buffer (struct buffer_record *buf) +{ + struct buffer_record *p; + + buf->next = NULL; + buf->curr_line = buf->line_start; + + if (head == NULL) + head = buf; + else + { + for (p = head; p->next; p = p->next) + /* Do nothing. */ ; + p->next = buf; + } +} + +/* Fill a buffer of input. + + Set the initial size of the buffer to a default. + Fill the buffer (from the hold area and input stream) + and find the individual lines. + If no lines are found (the buffer is too small to hold the next line), + release the current buffer (whose contents would have been put in the + hold area) and repeat the process with another large buffer until at least + one entire line has been read. + + Return TRUE if a new buffer was obtained, otherwise false + (in which case end-of-file must have been encountered). */ + +static boolean +load_buffer (void) +{ + struct buffer_record *b; + unsigned int bytes_wanted = START_SIZE; /* Minimum buffer size. */ + unsigned int bytes_avail; /* Size of new buffer created. */ + unsigned int lines_found; /* Number of lines in this new buffer. */ + char *p; /* Place to load into buffer. */ + + if (have_read_eof) + return FALSE; + + /* We must make the buffer at least as large as the amount of data + in the partial line left over from the last call. */ + if (bytes_wanted < hold_count) + bytes_wanted = hold_count; + + do + { + b = get_new_buffer (bytes_wanted); + bytes_avail = b->bytes_alloc; /* Size of buffer returned. */ + p = b->buffer; + + /* First check the `holding' area for a partial line. */ + if (hold_count) + { + if (p != hold_area) + memcpy (p, hold_area, hold_count); + p += hold_count; + b->bytes_used += hold_count; + bytes_avail -= hold_count; + hold_count = 0; + } + + b->bytes_used += (unsigned int) read_input (p, bytes_avail); + + lines_found = record_line_starts (b); + bytes_wanted = b->bytes_alloc * 2; + if (!lines_found) + free_buffer (b); + } + while (!lines_found && !have_read_eof); + + if (lines_found) + save_buffer (b); + + return lines_found != 0; +} + +/* Return the line number of the first line that has not yet been retrieved. */ + +static unsigned int +get_first_line_in_buffer (void) +{ + if (head == NULL && !load_buffer ()) + error (EXIT_FAILURE, errno, _("input disappeared")); + + return head->first_available; +} + +/* Return a pointer to the logical first line in the buffer and make the + next line the logical first line. + Return NULL if there is no more input. */ + +static struct cstring * +remove_line (void) +{ + struct cstring *line; /* Return value. */ + struct line *l; /* For convenience. */ + + if (head == NULL && !load_buffer ()) + return NULL; + + if (current_line < head->first_available) + current_line = head->first_available; + + ++(head->first_available); + + l = head->curr_line; + + line = &l->starts[l->retrieve_index]; + + /* Advance index to next line. */ + if (++l->retrieve_index == l->used) + { + /* Go on to the next line record. */ + head->curr_line = l->next; + if (head->curr_line == NULL || head->curr_line->used == 0) + { + /* Go on to the next data block. */ + struct buffer_record *b = head; + head = head->next; + free_buffer (b); + } + } + + return line; +} + +/* Search the buffers for line LINENUM, reading more input if necessary. + Return a pointer to the line, or NULL if it is not found in the file. */ + +static struct cstring * +find_line (unsigned int linenum) +{ + struct buffer_record *b; + + if (head == NULL && !load_buffer ()) + return NULL; + + if (linenum < head->start_line) + return NULL; + + for (b = head;;) + { + if (linenum < b->start_line + b->num_lines) + { + /* The line is in this buffer. */ + struct line *l; + unsigned int offset; /* How far into the buffer the line is. */ + + l = b->line_start; + offset = linenum - b->start_line; + /* Find the control record. */ + while (offset >= CTRL_SIZE) + { + l = l->next; + offset -= CTRL_SIZE; + } + return &l->starts[offset]; + } + if (b->next == NULL && !load_buffer ()) + return NULL; + b = b->next; /* Try the next data block. */ + } +} + +/* Return TRUE if at least one more line is available for input. */ + +static boolean +no_more_lines (void) +{ + return (find_line (current_line + 1) == NULL) ? TRUE : FALSE; +} + +/* Set the name of the input file to NAME and open it. */ + +static void +set_input_file (const char *name) +{ + if (STREQ (name, "-")) + input_desc = 0; + else + { + input_desc = open (name, O_RDONLY); + if (input_desc < 0) + error (EXIT_FAILURE, errno, "%s", name); + } +} + +/* Write all lines from the beginning of the buffer up to, but + not including, line LAST_LINE, to the current output file. + If IGNORE is TRUE, do not output lines selected here. + ARGNUM is the index in ARGV of the current pattern. */ + +static void +write_to_file (unsigned int last_line, boolean ignore, int argnum) +{ + struct cstring *line; + unsigned int first_line; /* First available input line. */ + unsigned int lines; /* Number of lines to output. */ + unsigned int i; + + first_line = get_first_line_in_buffer (); + + if (first_line > last_line) + { + error (0, 0, _("%s: line number out of range"), global_argv[argnum]); + cleanup_fatal (); + } + + lines = last_line - first_line; + + for (i = 0; i < lines; i++) + { + line = remove_line (); + if (line == NULL) + { + error (0, 0, _("%s: line number out of range"), global_argv[argnum]); + cleanup_fatal (); + } + if (!ignore) + save_line_to_file (line); + } +} + +/* Output any lines left after all regexps have been processed. */ + +static void +dump_rest_of_file (void) +{ + struct cstring *line; + + while ((line = remove_line ()) != NULL) + save_line_to_file (line); +} + +/* Handle an attempt to read beyond EOF under the control of record P, + on iteration REPETITION if nonzero. */ + +static void +handle_line_error (const struct control *p, int repetition) +{ + char buf[INT_BUFSIZE_BOUND (uintmax_t)]; + + fprintf (stderr, _("%s: `%s': line number out of range"), + program_name, umaxtostr (p->lines_required, buf)); + if (repetition) + fprintf (stderr, _(" on repetition %d\n"), repetition); + else + fprintf (stderr, "\n"); + + cleanup_fatal (); +} + +/* Determine the line number that marks the end of this file, + then get those lines and save them to the output file. + P is the control record. + REPETITION is the repetition number. */ + +static void +process_line_count (const struct control *p, int repetition) +{ + unsigned int linenum; + uintmax_t last_line_to_save = p->lines_required * (repetition + 1); + struct cstring *line; + + create_output_file (); + + linenum = get_first_line_in_buffer (); + + while (linenum++ < last_line_to_save) + { + line = remove_line (); + if (line == NULL) + handle_line_error (p, repetition); + save_line_to_file (line); + } + + close_output_file (); + + /* Ensure that the line number specified is not 1 greater than + the number of lines in the file. */ + if (no_more_lines ()) + handle_line_error (p, repetition); +} + +static void +regexp_error (struct control *p, int repetition, boolean ignore) +{ + fprintf (stderr, _("%s: `%s': match not found"), + program_name, global_argv[p->argnum]); + + if (repetition) + fprintf (stderr, _(" on repetition %d\n"), repetition); + else + fprintf (stderr, "\n"); + + if (!ignore) + { + dump_rest_of_file (); + close_output_file (); + } + cleanup_fatal (); +} + +/* Read the input until a line matches the regexp in P, outputting + it unless P->IGNORE is TRUE. + REPETITION is this repeat-count; 0 means the first time. */ + +static void +process_regexp (struct control *p, int repetition) +{ + struct cstring *line; /* From input file. */ + unsigned int line_len; /* To make "$" in regexps work. */ + unsigned int break_line; /* First line number of next file. */ + boolean ignore = p->ignore; /* If TRUE, skip this section. */ + int ret; + + if (!ignore) + create_output_file (); + + /* If there is no offset for the regular expression, or + it is positive, then it is not necessary to buffer the lines. */ + + if (p->offset >= 0) + { + for (;;) + { + line = find_line (++current_line); + if (line == NULL) + { + if (p->repeat_forever) + { + if (!ignore) + { + dump_rest_of_file (); + close_output_file (); + } + exit (EXIT_SUCCESS); + } + else + regexp_error (p, repetition, ignore); + } + line_len = line->len; + if (line->str[line_len - 1] == '\n') + line_len--; + ret = re_search (&p->re_compiled, line->str, line_len, + 0, line_len, (struct re_registers *) 0); + if (ret == -2) + { + error (0, 0, _("error in regular expression search")); + cleanup_fatal (); + } + if (ret == -1) + { + line = remove_line (); + if (!ignore) + save_line_to_file (line); + } + else + break; + } + } + else + { + /* Buffer the lines. */ + for (;;) + { + line = find_line (++current_line); + if (line == NULL) + { + if (p->repeat_forever) + { + if (!ignore) + { + dump_rest_of_file (); + close_output_file (); + } + exit (EXIT_SUCCESS); + } + else + regexp_error (p, repetition, ignore); + } + line_len = line->len; + if (line->str[line_len - 1] == '\n') + line_len--; + ret = re_search (&p->re_compiled, line->str, line_len, + 0, line_len, (struct re_registers *) 0); + if (ret == -2) + { + error (0, 0, _("error in regular expression search")); + cleanup_fatal (); + } + if (ret >= 0) + break; + } + } + + /* Account for any offset from this regexp. */ + break_line = current_line + p->offset; + + write_to_file (break_line, ignore, p->argnum); + + if (!ignore) + close_output_file (); + + if (p->offset > 0) + current_line = break_line; +} + +/* Split the input file according to the control records we have built. */ + +static void +split_file (void) +{ + unsigned int i, j; + + for (i = 0; i < control_used; i++) + { + if (controls[i].regexpr) + { + for (j = 0; (controls[i].repeat_forever + || j <= controls[i].repeat); j++) + process_regexp (&controls[i], j); + } + else + { + for (j = 0; (controls[i].repeat_forever + || j <= controls[i].repeat); j++) + process_line_count (&controls[i], j); + } + } + + create_output_file (); + dump_rest_of_file (); + close_output_file (); +} + +/* Return the name of output file number NUM. */ + +static char * +make_filename (unsigned int num) +{ + strcpy (filename_space, prefix); + if (suffix) + sprintf (filename_space+strlen(prefix), suffix, num); + else + sprintf (filename_space+strlen(prefix), "%0*d", digits, num); + return filename_space; +} + +/* Create the next output file. */ + +static void +create_output_file (void) +{ + output_filename = make_filename (files_created); + output_stream = fopen (output_filename, "w"); + if (output_stream == NULL) + { + error (0, errno, "%s", output_filename); + cleanup_fatal (); + } + files_created++; + bytes_written = 0; +} + +/* Delete all the files we have created. */ + +static void +delete_all_files (void) +{ + unsigned int i; + char *name; + + for (i = 0; i < files_created; i++) + { + name = make_filename (i); + if (unlink (name)) + error (0, errno, "%s", name); + } +} + +/* Close the current output file and print the count + of characters in this file. */ + +static void +close_output_file (void) +{ + if (output_stream) + { + if (ferror (output_stream) || fclose (output_stream) == EOF) + { + error (0, errno, _("write error for `%s'"), output_filename); + output_stream = NULL; + cleanup_fatal (); + } + if (bytes_written == 0 && elide_empty_files) + { + if (unlink (output_filename)) + error (0, errno, "%s", output_filename); + files_created--; + } + else + { + /* FIXME: if we write to stdout here, we have to close stdout + and check for errors. */ + if (!suppress_count) + fprintf (stdout, "%d\n", bytes_written); + } + output_stream = NULL; + } +} + +/* Save line LINE to the output file and + increment the character count for the current file. */ + +static void +save_line_to_file (const struct cstring *line) +{ + fwrite (line->str, sizeof (char), line->len, output_stream); + bytes_written += line->len; +} + +/* Return a new, initialized control record. */ + +static struct control * +new_control_record (void) +{ + static unsigned control_allocated = 0; /* Total space allocated. */ + struct control *p; + + if (control_allocated == 0) + { + control_allocated = ALLOC_SIZE; + controls = (struct control *) + xmalloc (sizeof (struct control) * control_allocated); + } + else if (control_used == control_allocated) + { + control_allocated += ALLOC_SIZE; + controls = (struct control *) + xrealloc ((char *) controls, + sizeof (struct control) * control_allocated); + } + p = &controls[control_used++]; + p->regexpr = NULL; + p->repeat = 0; + p->repeat_forever = 0; + p->lines_required = 0; + p->offset = 0; + return p; +} + +/* Check if there is a numeric offset after a regular expression. + STR is the entire command line argument. + P is the control record for this regular expression. + NUM is the numeric part of STR. */ + +static void +check_for_offset (struct control *p, const char *str, const char *num) +{ + unsigned long val; + + if (*num != '-' && *num != '+') + error (EXIT_FAILURE, 0, _("%s: `+' or `-' expected after delimeter"), str); + + if (xstrtoul (num + 1, NULL, 10, &val, "") != LONGINT_OK + || val > UINT_MAX) + error (EXIT_FAILURE, 0, _("%s: integer expected after `%c'"), str, *num); + p->offset = (unsigned int) val; + + if (*num == '-') + p->offset = -p->offset; +} + +/* Given that the first character of command line arg STR is '{', + make sure that the rest of the string is a valid repeat count + and store its value in P. + ARGNUM is the ARGV index of STR. */ + +static void +parse_repeat_count (int argnum, struct control *p, char *str) +{ + uintmax_t val; + char *end; + + end = str + strlen (str) - 1; + if (*end != '}') + error (EXIT_FAILURE, 0, _("%s: `}' is required in repeat count"), str); + *end = '\0'; + + if (str+1 == end-1 && *(str+1) == '*') + p->repeat_forever = 1; + else + { + if (xstrtoumax (str + 1, NULL, 10, &val, "") != LONGINT_OK) + { + error (EXIT_FAILURE, 0, + _("%s}: integer required between `{' and `}'"), + global_argv[argnum]); + } + p->repeat = val; + } + + *end = '}'; +} + +/* Extract the regular expression from STR and check for a numeric offset. + STR should start with the regexp delimiter character. + Return a new control record for the regular expression. + ARGNUM is the ARGV index of STR. + Unless IGNORE is TRUE, mark these lines for output. */ + +static struct control * +extract_regexp (int argnum, boolean ignore, char *str) +{ + int len; /* Number of chars in this regexp. */ + char delim = *str; + char *closing_delim; + struct control *p; + const char *err; + + closing_delim = strrchr (str + 1, delim); + if (closing_delim == NULL) + error (EXIT_FAILURE, 0, + _("%s: closing delimeter `%c' missing"), str, delim); + + len = closing_delim - str - 1; + p = new_control_record (); + p->argnum = argnum; + p->ignore = ignore; + + p->regexpr = (char *) xmalloc ((unsigned) (len + 1)); + strncpy (p->regexpr, str + 1, len); + p->re_compiled.allocated = len * 2; + p->re_compiled.buffer = (unsigned char *) xmalloc (p->re_compiled.allocated); + p->re_compiled.fastmap = xmalloc (256); + p->re_compiled.translate = 0; + err = re_compile_pattern (p->regexpr, len, &p->re_compiled); + if (err) + { + error (0, 0, _("%s: invalid regular expression: %s"), str, err); + cleanup_fatal (); + } + + if (closing_delim[1]) + check_for_offset (p, str, closing_delim + 1); + + return p; +} + +/* Extract the break patterns from args START through ARGC - 1 of ARGV. + After each pattern, check if the next argument is a repeat count. */ + +static void +parse_patterns (int argc, int start, char **argv) +{ + int i; /* Index into ARGV. */ + struct control *p; /* New control record created. */ + uintmax_t val; + static uintmax_t last_val = 0; + + for (i = start; i < argc; i++) + { + if (*argv[i] == '/' || *argv[i] == '%') + { + p = extract_regexp (i, *argv[i] == '%', argv[i]); + } + else + { + p = new_control_record (); + p->argnum = i; + + if (xstrtoumax (argv[i], NULL, 10, &val, "") != LONGINT_OK) + error (EXIT_FAILURE, 0, _("%s: invalid pattern"), argv[i]); + if (val == 0) + error (EXIT_FAILURE, 0, + _("%s: line number must be greater than zero"), + argv[i]); + if (val < last_val) + { + char buf[INT_BUFSIZE_BOUND (uintmax_t)]; + error (EXIT_FAILURE, 0, + _("line number `%s' is smaller than preceding line number, %s"), + argv[i], umaxtostr (last_val, buf)); + } + + if (val == last_val) + error (0, 0, + _("warning: line number `%s' is the same as preceding line number"), + argv[i]); + + last_val = val; + + p->lines_required = val; + } + + if (i + 1 < argc && *argv[i + 1] == '{') + { + /* We have a repeat count. */ + i++; + parse_repeat_count (i, p, argv[i]); + } + } +} + +static unsigned +get_format_flags (char **format_ptr) +{ + unsigned count = 0; + + for (; **format_ptr; (*format_ptr)++) + { + switch (**format_ptr) + { + case '-': + break; + + case '+': + case ' ': + count++; + break; + + case '#': + count += 2; /* Allow for 0x prefix preceeding an `x' conversion. */ + break; + + default: + return count; + } + } + return count; +} + +static unsigned +get_format_width (char **format_ptr) +{ + unsigned count = 0; + char *start; + int ch_save; + + start = *format_ptr; + for (; ISDIGIT (**format_ptr); (*format_ptr)++) + continue; + + ch_save = **format_ptr; + **format_ptr = '\0'; + /* In the case where no minimum field width is explicitly specified, + allow for enough octal digits to represent the value of LONG_MAX. */ + count = ((*format_ptr == start) + ? bytes_to_octal_digits[sizeof (long)] + /* FIXME: don't use atoi, it may silently overflow. + Besides, we know the result is non-negative, so shouldn't + need that cast. */ + : (unsigned) atoi (start)); + **format_ptr = ch_save; + return count; +} + +static unsigned +get_format_prec (char **format_ptr) +{ + unsigned count = 0; + char *start; + int ch_save; + int is_negative; + + if (**format_ptr != '.') + return 0; + (*format_ptr)++; + + if (**format_ptr == '-' || **format_ptr == '+') + { + is_negative = (**format_ptr == '-'); + (*format_ptr)++; + } + else + { + is_negative = 0; + } + + start = *format_ptr; + for (; ISDIGIT (**format_ptr); (*format_ptr)++) + continue; + + /* ANSI 4.9.6.1 says that if the precision is negative, it's as good as + not there. */ + if (is_negative) + start = *format_ptr; + + ch_save = **format_ptr; + **format_ptr = '\0'; + count = (*format_ptr == start) ? 11 : atoi (start); + **format_ptr = ch_save; + + return count; +} + +static void +get_format_conv_type (char **format_ptr) +{ + int ch = *((*format_ptr)++); + + switch (ch) + { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + break; + + case 0: + error (EXIT_FAILURE, 0, _("missing conversion specifier in suffix")); + break; + + default: + if (ISPRINT (ch)) + error (EXIT_FAILURE, 0, + _("invalid conversion specifier in suffix: %c"), ch); + else + error (EXIT_FAILURE, 0, + _("invalid conversion specifier in suffix: \\%.3o"), ch); + } +} + +static unsigned +max_out (char *format) +{ + unsigned out_count = 0; + unsigned percents = 0; + + for (; *format; ) + { + int ch = *format++; + + if (ch != '%') + out_count++; + else + { + percents++; + out_count += get_format_flags (&format); + { + int width = get_format_width (&format); + int prec = get_format_prec (&format); + + out_count += MAX (width, prec); + } + get_format_conv_type (&format); + } + } + + if (percents == 0) + error (EXIT_FAILURE, 0, + _("missing %% conversion specification in suffix")); + else if (percents > 1) + error (EXIT_FAILURE, 0, + _("too many %% conversion specifications in suffix")); + + return out_count; +} + +int +main (int argc, char **argv) +{ + int optc; + unsigned long val; +#ifdef SA_NOCLDSTOP + struct sigaction oldact, newact; +#endif + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + global_argv = argv; + controls = NULL; + control_used = 0; + suppress_count = FALSE; + remove_files = TRUE; + prefix = DEFAULT_PREFIX; + + /* Change the way xmalloc and xrealloc fail. */ + xalloc_fail_func = cleanup; + +#ifdef SA_NOCLDSTOP + newact.sa_handler = interrupt_handler; + sigemptyset (&newact.sa_mask); + newact.sa_flags = 0; + + sigaction (SIGHUP, NULL, &oldact); + if (oldact.sa_handler != SIG_IGN) + sigaction (SIGHUP, &newact, NULL); + + sigaction (SIGINT, NULL, &oldact); + if (oldact.sa_handler != SIG_IGN) + sigaction (SIGINT, &newact, NULL); + + sigaction (SIGQUIT, NULL, &oldact); + if (oldact.sa_handler != SIG_IGN) + sigaction (SIGQUIT, &newact, NULL); + + sigaction (SIGTERM, NULL, &oldact); + if (oldact.sa_handler != SIG_IGN) + sigaction (SIGTERM, &newact, NULL); +#else + if (signal (SIGHUP, SIG_IGN) != SIG_IGN) + signal (SIGHUP, interrupt_handler); + if (signal (SIGINT, SIG_IGN) != SIG_IGN) + signal (SIGINT, interrupt_handler); + if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) + signal (SIGQUIT, interrupt_handler); + if (signal (SIGTERM, SIG_IGN) != SIG_IGN) + signal (SIGTERM, interrupt_handler); +#endif + + while ((optc = getopt_long (argc, argv, "f:b:kn:sqz", longopts, NULL)) != -1) + switch (optc) + { + case 0: + break; + + case 'f': + prefix = optarg; + break; + + case 'b': + suffix = optarg; + break; + + case 'k': + remove_files = FALSE; + break; + + case 'n': + if (xstrtoul (optarg, NULL, 10, &val, "") != LONGINT_OK + || val > INT_MAX) + error (EXIT_FAILURE, 0, _("%s: invalid number"), optarg); + digits = (int) val; + break; + + case 's': + case 'q': + suppress_count = TRUE; + break; + + case 'z': + elide_empty_files = TRUE; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + + if (argc - optind < 2) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + if (suffix) + filename_space = (char *) xmalloc (strlen (prefix) + max_out (suffix) + 2); + else + filename_space = (char *) xmalloc (strlen (prefix) + digits + 2); + + set_input_file (argv[optind++]); + + parse_patterns (argc, optind, argv); + + split_file (); + + if (close (input_desc) < 0) + { + error (0, errno, _("read error")); + cleanup_fatal (); + } + + exit (EXIT_SUCCESS); +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... FILE PATTERN...\n\ +"), + program_name); + fputs (_("\ +Output pieces of FILE separated by PATTERN(s) to files `xx01', `xx02', ...,\n\ +and output byte counts of each piece to standard output.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -b, --suffix-format=FORMAT use sprintf FORMAT instead of %d\n\ + -f, --prefix=PREFIX use PREFIX instead of `xx'\n\ + -k, --keep-files do not remove output files on errors\n\ +"), stdout); + fputs (_("\ + -n, --digits=DIGITS use specified number of digits instead of 2\n\ + -s, --quiet, --silent do not print counts of output file sizes\n\ + -z, --elide-empty-files remove empty output files\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +Read standard input if FILE is -. Each PATTERN may be:\n\ +"), stdout); + fputs (_("\ +\n\ + INTEGER copy up to but not including specified line number\n\ + /REGEXP/[OFFSET] copy up to but not including a matching line\n\ + %REGEXP%[OFFSET] skip to, but not including a matching line\n\ + {INTEGER} repeat the previous pattern specified number of times\n\ + {*} repeat the previous pattern as many times as possible\n\ +\n\ +A line OFFSET is a required `+' or `-' followed by a positive integer.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/cut.c b/src/apps/bin/coreutils-5.0/src/cut.c new file mode 100644 index 0000000000..9609173942 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/cut.c @@ -0,0 +1,752 @@ +/* cut - remove parts of lines of files + Copyright (C) 1984, 1997, 1998, 1999, 2000, 2001, 2002, 2003 by David M. Ihnat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David Ihnat. */ + +/* POSIX changes, bug fixes, long-named options, and cleanup + by David MacKenzie . + + Rewrite cut_fields and cut_bytes -- Jim Meyering. */ + +#include + +#include +#include +#include +#include +#include "system.h" +#include "getstr.h" +#include "closeout.h" +#include "error.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "cut" + +#define AUTHORS N_ ("David Ihnat, David MacKenzie, and Jim Meyering") + +#define FATAL_ERROR(Message) \ + do \ + { \ + error (0, 0, (Message)); \ + usage (2); \ + } \ + while (0) + +/* Append LOW, HIGH to the list RP of range pairs, allocating additional + space if necessary. Update local variable N_RP. When allocating, + update global variable N_RP_ALLOCATED. */ + +#define ADD_RANGE_PAIR(rp, low, high) \ + do \ + { \ + if (n_rp >= n_rp_allocated) \ + { \ + n_rp_allocated *= 2; \ + (rp) = (struct range_pair *) xrealloc ((char *) (rp), \ + n_rp_allocated * sizeof (*(rp))); \ + } \ + rp[n_rp].lo = (low); \ + rp[n_rp].hi = (high); \ + ++n_rp; \ + } \ + while (0) + +struct range_pair + { + unsigned int lo; + unsigned int hi; + }; + +/* This buffer is used to support the semantics of the -s option + (or lack of same) when the specified field list includes (does + not include) the first field. In both of those cases, the entire + first field must be read into this buffer to determine whether it + is followed by a delimiter or a newline before any of it may be + output. Otherwise, cut_fields can do the job without using this + buffer. */ +static char *field_1_buffer; + +/* The number of bytes allocated for FIELD_1_BUFFER. */ +static size_t field_1_bufsize; + +/* The largest field or byte index used as an endpoint of a closed + or degenerate range specification; this doesn't include the starting + index of right-open-ended ranges. For example, with either range spec + `2-5,9-', `2-3,5,9-' this variable would be set to 5. */ +static unsigned int max_range_endpoint; + +/* If nonzero, this is the index of the first field in a range that goes + to end of line. */ +static unsigned int eol_range_start; + +/* A nonzero, non-1 value with which to distinguish the index + corresponding to the lower bound of a range. */ +#define RANGE_START_SENTINEL 2 + +/* In byte mode, which bytes to output. + In field mode, which DELIM-separated fields to output. + Both bytes and fields are numbered starting with 1, + so the zeroth element of this array is unused. + A field or byte K has been selected if + (K <= MAX_RANGE_ENDPOINT and PRINTABLE_FIELD[K]) + || (EOL_RANGE_START > 0 && K >= EOL_RANGE_START). */ +static int *printable_field; + +enum operating_mode + { + undefined_mode, + + /* Output characters that are in the given bytes. */ + byte_mode, + + /* Output the given delimeter-separated fields. */ + field_mode + }; + +/* The name this program was run with. */ +char *program_name; + +static enum operating_mode operating_mode; + +/* If nonzero do not output lines containing no delimeter characters. + Otherwise, all such lines are printed. This option is valid only + with field mode. */ +static int suppress_non_delimited; + +/* The delimeter character for field mode. */ +static int delim; + +/* Nonzero if the --output-delimiter=STRING option was specified. */ +static int output_delimiter_specified; + +/* The length of output_delimiter_string. */ +static size_t output_delimiter_length; + +/* The output field separator string. Defaults to the 1-character + string consisting of the input delimiter. */ +static char *output_delimiter_string; + +/* Nonzero if we have ever read standard input. */ +static int have_read_stdin; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + OUTPUT_DELIMITER_OPTION = CHAR_MAX + 1 +}; + +static struct option const longopts[] = +{ + {"bytes", required_argument, 0, 'b'}, + {"characters", required_argument, 0, 'c'}, + {"fields", required_argument, 0, 'f'}, + {"delimiter", required_argument, 0, 'd'}, + {"only-delimited", no_argument, 0, 's'}, + {"output-delimiter", required_argument, 0, OUTPUT_DELIMITER_OPTION}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + fputs (_("\ +Print selected parts of lines from each FILE to standard output.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -b, --bytes=LIST output only these bytes\n\ + -c, --characters=LIST output only these characters\n\ + -d, --delimiter=DELIM use DELIM instead of TAB for field delimiter\n\ +"), stdout); + fputs (_("\ + -f, --fields=LIST output only these fields; also print any line\n\ + that contains no delimiter character, unless\n\ + the -s option is specified\n\ + -n (ignored)\n\ +"), stdout); + fputs (_("\ + -s, --only-delimited do not print lines not containing delimiters\n\ + --output-delimiter=STRING use STRING as the output delimiter\n\ + the default is to use the input delimiter\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +Use one, and only one of -b, -c or -f. Each LIST is made up of one\n\ +range, or many ranges separated by commas. Each range is one of:\n\ +\n\ + N N'th byte, character or field, counted from 1\n\ + N- from N'th byte, character or field, to end of line\n\ + N-M from N'th to M'th (included) byte, character or field\n\ + -M from first to M'th (included) byte, character or field\n\ +\n\ +With no FILE, or when FILE is -, read standard input.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Return nonzero if the K'th field or byte is printable. + When returning nonzero, if RANGE_START is non-NULL, + set *RANGE_START to nonzero if K is the beginning of a range, and + set *RANGE_START to zero if K is not the beginning of a range. */ + +static int +print_kth (unsigned int k, int *range_start) +{ + if (0 < eol_range_start && eol_range_start <= k) + { + if (range_start) + *range_start = (k == eol_range_start); + return 1; + } + + if (k <= max_range_endpoint && printable_field[k]) + { + if (range_start) + *range_start = (printable_field[k] == RANGE_START_SENTINEL); + return 1; + } + + return 0; +} + +/* Given the list of field or byte range specifications FIELDSTR, set + MAX_RANGE_ENDPOINT and allocate and initialize the PRINTABLE_FIELD + array. If there is a right-open-ended range, set EOL_RANGE_START + to its starting index. FIELDSTR should be composed of one or more + numbers or ranges of numbers, separated by blanks or commas. + Incomplete ranges may be given: `-m' means `1-m'; `n-' means `n' + through end of line. Return nonzero if FIELDSTR contains at least + one field specification, zero otherwise. */ + +/* FIXME-someday: What if the user wants to cut out the 1,000,000-th field + of some huge input file? This function shouldn't have to allocate a table + of a million ints just so we can test every field < 10^6 with an array + dereference. Instead, consider using a dynamic hash table. It would be + simpler and nearly as good a solution to use a 32K x 4-byte table with + one bit per field index instead of a whole `int' per index. */ + +static int +set_fields (const char *fieldstr) +{ + unsigned int initial = 1; /* Value of first number in a range. */ + unsigned int value = 0; /* If nonzero, a number being accumulated. */ + int dash_found = 0; /* Nonzero if a '-' is found in this field. */ + int field_found = 0; /* Non-zero if at least one field spec + has been processed. */ + + struct range_pair *rp; + unsigned int n_rp; + unsigned int n_rp_allocated; + unsigned int i; + + n_rp = 0; + n_rp_allocated = 16; + rp = (struct range_pair *) xmalloc (n_rp_allocated * sizeof (*rp)); + + /* Collect and store in RP the range end points. + It also sets EOL_RANGE_START if appropriate. */ + + for (;;) + { + if (*fieldstr == '-') + { + /* Starting a range. */ + if (dash_found) + FATAL_ERROR (_("invalid byte or field list")); + dash_found++; + fieldstr++; + + if (value) + { + initial = value; + value = 0; + } + else + initial = 1; + } + else if (*fieldstr == ',' || ISBLANK (*fieldstr) || *fieldstr == '\0') + { + /* Ending the string, or this field/byte sublist. */ + if (dash_found) + { + dash_found = 0; + + /* A range. Possibilites: -n, m-n, n-. + In any case, `initial' contains the start of the range. */ + if (value == 0) + { + /* `n-'. From `initial' to end of line. */ + eol_range_start = initial; + field_found = 1; + } + else + { + /* `m-n' or `-n' (1-n). */ + if (value < initial) + FATAL_ERROR (_("invalid byte or field list")); + + /* Is there already a range going to end of line? */ + if (eol_range_start != 0) + { + /* Yes. Is the new sequence already contained + in the old one? If so, no processing is + necessary. */ + if (initial < eol_range_start) + { + /* No, the new sequence starts before the + old. Does the old range going to end of line + extend into the new range? */ + if (eol_range_start <= value) + { + /* Yes. Simply move the end of line marker. */ + eol_range_start = initial; + } + else + { + /* No. A simple range, before and disjoint from + the range going to end of line. Fill it. */ + ADD_RANGE_PAIR (rp, initial, value); + } + + /* In any case, some fields were selected. */ + field_found = 1; + } + } + else + { + /* There is no range going to end of line. */ + ADD_RANGE_PAIR (rp, initial, value); + field_found = 1; + } + value = 0; + } + } + else if (value != 0) + { + /* A simple field number, not a range. */ + ADD_RANGE_PAIR (rp, value, value); + value = 0; + field_found = 1; + } + + if (*fieldstr == '\0') + { + break; + } + + fieldstr++; + } + else if (ISDIGIT (*fieldstr)) + { + /* FIXME: detect overflow? */ + value = 10 * value + *fieldstr - '0'; + fieldstr++; + } + else + FATAL_ERROR (_("invalid byte or field list")); + } + + max_range_endpoint = 0; + for (i = 0; i < n_rp; i++) + { + if (rp[i].hi > max_range_endpoint) + max_range_endpoint = rp[i].hi; + } + + /* Allocate an array large enough so that it may be indexed by + the field numbers corresponding to all finite ranges + (i.e. `2-6' or `-4', but not `5-') in FIELDSTR. */ + + printable_field = (int *) xmalloc ((max_range_endpoint + 1) * sizeof (int)); + memset (printable_field, 0, (max_range_endpoint + 1) * sizeof (int)); + + /* Set the array entries corresponding to integers in the ranges of RP. */ + for (i = 0; i < n_rp; i++) + { + unsigned int j = rp[i].lo; + + /* Mark the first position of field or range with a sentinel, + but not if it's already part of another range. */ + if (j <= rp[i].hi && ! printable_field[j]) + printable_field[j] = RANGE_START_SENTINEL; + for (++j; j <= rp[i].hi; j++) + { + printable_field[j] = 1; + } + } + + free (rp); + + return field_found; +} + +/* Read from stream STREAM, printing to standard output any selected bytes. */ + +static void +cut_bytes (FILE *stream) +{ + unsigned int byte_idx; /* Number of bytes in the line so far. */ + /* Whether to begin printing delimiters between ranges for the current line. + Set after we've begun printing data corresponding to the first range. */ + int print_delimiter; + + byte_idx = 0; + print_delimiter = 0; + while (1) + { + register int c; /* Each character from the file. */ + + c = getc (stream); + + if (c == '\n') + { + putchar ('\n'); + byte_idx = 0; + print_delimiter = 0; + } + else if (c == EOF) + { + if (byte_idx > 0) + putchar ('\n'); + break; + } + else + { + int range_start; + if (print_kth (++byte_idx, &range_start)) + { + if (range_start && print_delimiter && output_delimiter_specified) + { + fwrite (output_delimiter_string, sizeof (char), + output_delimiter_length, stdout); + } + print_delimiter = 1; + putchar (c); + } + } + } +} + +/* Read from stream STREAM, printing to standard output any selected fields. */ + +static void +cut_fields (FILE *stream) +{ + int c; + unsigned int field_idx; + int found_any_selected_field; + int buffer_first_field; + int empty_input; + + found_any_selected_field = 0; + field_idx = 1; + + c = getc (stream); + empty_input = (c == EOF); + if (c != EOF) + ungetc (c, stream); + + /* To support the semantics of the -s flag, we may have to buffer + all of the first field to determine whether it is `delimited.' + But that is unnecessary if all non-delimited lines must be printed + and the first field has been selected, or if non-delimited lines + must be suppressed and the first field has *not* been selected. + That is because a non-delimited line has exactly one field. */ + buffer_first_field = (suppress_non_delimited ^ !print_kth (1, NULL)); + + while (1) + { + if (field_idx == 1 && buffer_first_field) + { + int len; + size_t n_bytes; + + len = getstr (&field_1_buffer, &field_1_bufsize, stream, + delim, '\n', 0); + if (len < 0) + { + if (ferror (stream) || feof (stream)) + break; + xalloc_die (); + } + + n_bytes = len; + assert (n_bytes != 0); + + /* If the first field extends to the end of line (it is not + delimited) and we are printing all non-delimited lines, + print this one. */ + if ((unsigned char) field_1_buffer[n_bytes - 1] != delim) + { + if (suppress_non_delimited) + { + /* Empty. */ + } + else + { + fwrite (field_1_buffer, sizeof (char), n_bytes, stdout); + /* Make sure the output line is newline terminated. */ + if (field_1_buffer[n_bytes - 1] != '\n') + putchar ('\n'); + } + continue; + } + if (print_kth (1, NULL)) + { + /* Print the field, but not the trailing delimiter. */ + fwrite (field_1_buffer, sizeof (char), n_bytes - 1, stdout); + found_any_selected_field = 1; + } + ++field_idx; + } + + if (c != EOF) + { + if (print_kth (field_idx, NULL)) + { + if (found_any_selected_field) + { + fwrite (output_delimiter_string, sizeof (char), + output_delimiter_length, stdout); + } + found_any_selected_field = 1; + + while ((c = getc (stream)) != delim && c != '\n' && c != EOF) + { + putchar (c); + } + } + else + { + while ((c = getc (stream)) != delim && c != '\n' && c != EOF) + { + /* Empty. */ + } + } + } + + if (c == '\n') + { + c = getc (stream); + if (c != EOF) + { + ungetc (c, stream); + c = '\n'; + } + } + + if (c == delim) + ++field_idx; + else if (c == '\n' || c == EOF) + { + if (found_any_selected_field + || (!empty_input && !(suppress_non_delimited && field_idx == 1))) + putchar ('\n'); + if (c == EOF) + break; + field_idx = 1; + found_any_selected_field = 0; + } + } +} + +static void +cut_stream (FILE *stream) +{ + if (operating_mode == byte_mode) + cut_bytes (stream); + else + cut_fields (stream); +} + +/* Process file FILE to standard output. + Return 0 if successful, 1 if not. */ + +static int +cut_file (char *file) +{ + FILE *stream; + + if (STREQ (file, "-")) + { + have_read_stdin = 1; + stream = stdin; + } + else + { + stream = fopen (file, "r"); + if (stream == NULL) + { + error (0, errno, "%s", file); + return 1; + } + } + + cut_stream (stream); + + if (ferror (stream)) + { + error (0, errno, "%s", file); + return 1; + } + if (STREQ (file, "-")) + clearerr (stream); /* Also clear EOF. */ + else if (fclose (stream) == EOF) + { + error (0, errno, "%s", file); + return 1; + } + return 0; +} + +int +main (int argc, char **argv) +{ + int optc, exit_status = 0; + int delim_specified = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + operating_mode = undefined_mode; + + /* By default, all non-delimited lines are printed. */ + suppress_non_delimited = 0; + + delim = '\0'; + have_read_stdin = 0; + + while ((optc = getopt_long (argc, argv, "b:c:d:f:ns", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + + case 'b': + case 'c': + /* Build the byte list. */ + if (operating_mode != undefined_mode) + FATAL_ERROR (_("only one type of list may be specified")); + operating_mode = byte_mode; + if (set_fields (optarg) == 0) + FATAL_ERROR (_("missing list of positions")); + break; + + case 'f': + /* Build the field list. */ + if (operating_mode != undefined_mode) + FATAL_ERROR (_("only one type of list may be specified")); + operating_mode = field_mode; + if (set_fields (optarg) == 0) + FATAL_ERROR (_("missing list of fields")); + break; + + case 'd': + /* New delimiter. */ + /* Interpret -d '' to mean `use the NUL byte as the delimiter.' */ + if (optarg[0] != '\0' && optarg[1] != '\0') + FATAL_ERROR (_("the delimiter must be a single character")); + delim = (unsigned char) optarg[0]; + delim_specified = 1; + break; + + case OUTPUT_DELIMITER_OPTION: + output_delimiter_specified = 1; + /* Interpret --output-delimiter='' to mean + `use the NUL byte as the delimiter.' */ + output_delimiter_length = (optarg[0] == '\0' + ? 1 : strlen (optarg)); + output_delimiter_string = xstrdup (optarg); + break; + + case 'n': + break; + + case 's': + suppress_non_delimited = 1; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (2); + } + } + + if (operating_mode == undefined_mode) + FATAL_ERROR (_("you must specify a list of bytes, characters, or fields")); + + if (delim != '\0' && operating_mode != field_mode) + FATAL_ERROR (_("an input delimiter may be specified only\ + when operating on fields")); + + if (suppress_non_delimited && operating_mode != field_mode) + FATAL_ERROR (_("suppressing non-delimited lines makes sense\n\ +\tonly when operating on fields")); + + if (!delim_specified) + delim = '\t'; + + if (output_delimiter_string == NULL) + { + static char dummy[2]; + dummy[0] = delim; + dummy[1] = '\0'; + output_delimiter_string = dummy; + output_delimiter_length = 1; + } + + if (optind == argc) + exit_status |= cut_file ("-"); + else + for (; optind < argc; optind++) + exit_status |= cut_file (argv[optind]); + + if (have_read_stdin && fclose (stdin) == EOF) + { + error (0, errno, "-"); + exit_status = 1; + } + + exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/date.c b/src/apps/bin/coreutils-5.0/src/date.c new file mode 100644 index 0000000000..37295c70db --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/date.c @@ -0,0 +1,552 @@ +/* date - print or set the system date and time + Copyright (C) 1989-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + David MacKenzie */ + +#include +#include +#include +#include +#if HAVE_LANGINFO_CODESET +# include +#endif + +#include "system.h" +#include "argmatch.h" +#include "closeout.h" +#include "error.h" +#include "getdate.h" +#include "getline.h" +#include "posixtm.h" +#include "posixver.h" +#include "strftime.h" +#include "timespec.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "date" + +#define AUTHORS "David MacKenzie" + +int putenv (); + +static void show_date (const char *format, struct timespec when); + +enum Time_spec +{ + /* display only the date: 1999-03-25 */ + TIME_SPEC_DATE=1, + /* display date and hour: 1999-03-25T03-0500 */ + TIME_SPEC_HOURS, + /* display date, hours, and minutes: 1999-03-25T03:23-0500 */ + TIME_SPEC_MINUTES, + /* display date, hours, minutes, and seconds: 1999-03-25T03:23:14-0500 */ + TIME_SPEC_SECONDS +}; + +static char const *const time_spec_string[] = +{ + "date", "hours", "minutes", "seconds", 0 +}; + +static enum Time_spec const time_spec[] = +{ + TIME_SPEC_DATE, TIME_SPEC_HOURS, TIME_SPEC_MINUTES, TIME_SPEC_SECONDS +}; + +/* The name this program was run with, for error messages. */ +char *program_name; + +/* If nonzero, display an ISO 8601 format date/time string */ +static int iso_8601_format = 0; + +/* If non-zero, display time in RFC-(2)822 format for mail or news. */ +static int rfc_format = 0; + +#define COMMON_SHORT_OPTIONS "Rd:f:r:s:u" + +static struct option const long_options[] = +{ + {"date", required_argument, NULL, 'd'}, + {"file", required_argument, NULL, 'f'}, + {"iso-8601", optional_argument, NULL, 'I'}, + {"reference", required_argument, NULL, 'r'}, + {"rfc-822", no_argument, NULL, 'R'}, + {"set", required_argument, NULL, 's'}, + {"uct", no_argument, NULL, 'u'}, + {"utc", no_argument, NULL, 'u'}, + {"universal", no_argument, NULL, 'u'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +#if LOCALTIME_CACHE +# define TZSET tzset () +#else +# define TZSET /* empty */ +#endif + +#ifdef _DATE_FMT +# define DATE_FMT_LANGINFO() nl_langinfo (_DATE_FMT) +#else +# define DATE_FMT_LANGINFO() "" +#endif + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [+FORMAT]\n\ + or: %s [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]\n\ +"), + program_name, program_name); + fputs (_("\ +Display the current time in the given FORMAT, or set the system date.\n\ +\n\ + -d, --date=STRING display time described by STRING, not `now'\n\ + -f, --file=DATEFILE like --date once for each line of DATEFILE\n\ + -ITIMESPEC, --iso-8601[=TIMESPEC] output date/time in ISO 8601 format.\n\ + TIMESPEC=`date' for date only,\n\ + `hours', `minutes', or `seconds' for date and\n\ + time to the indicated precision.\n\ + --iso-8601 without TIMESPEC defaults to `date'.\n\ +"), stdout); + fputs (_("\ + -r, --reference=FILE display the last modification time of FILE\n\ + -R, --rfc-822 output RFC-822 compliant date string\n\ + -s, --set=STRING set time described by STRING\n\ + -u, --utc, --universal print or set Coordinated Universal Time\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +FORMAT controls the output. The only valid option for the second form\n\ +specifies Coordinated Universal Time. Interpreted sequences are:\n\ +\n\ + %% a literal %\n\ + %a locale's abbreviated weekday name (Sun..Sat)\n\ +"), stdout); + fputs (_("\ + %A locale's full weekday name, variable length (Sunday..Saturday)\n\ + %b locale's abbreviated month name (Jan..Dec)\n\ + %B locale's full month name, variable length (January..December)\n\ + %c locale's date and time (Sat Nov 04 12:02:33 EST 1989)\n\ +"), stdout); + fputs (_("\ + %C century (year divided by 100 and truncated to an integer) [00-99]\n\ + %d day of month (01..31)\n\ + %D date (mm/dd/yy)\n\ + %e day of month, blank padded ( 1..31)\n\ +"), stdout); + fputs (_("\ + %F same as %Y-%m-%d\n\ + %g the 2-digit year corresponding to the %V week number\n\ + %G the 4-digit year corresponding to the %V week number\n\ +"), stdout); + fputs (_("\ + %h same as %b\n\ + %H hour (00..23)\n\ + %I hour (01..12)\n\ + %j day of year (001..366)\n\ +"), stdout); + fputs (_("\ + %k hour ( 0..23)\n\ + %l hour ( 1..12)\n\ + %m month (01..12)\n\ + %M minute (00..59)\n\ +"), stdout); + fputs (_("\ + %n a newline\n\ + %N nanoseconds (000000000..999999999)\n\ + %p locale's upper case AM or PM indicator (blank in many locales)\n\ + %P locale's lower case am or pm indicator (blank in many locales)\n\ + %r time, 12-hour (hh:mm:ss [AP]M)\n\ + %R time, 24-hour (hh:mm)\n\ + %s seconds since `00:00:00 1970-01-01 UTC' (a GNU extension)\n\ +"), stdout); + fputs (_("\ + %S second (00..60); the 60 is necessary to accommodate a leap second\n\ + %t a horizontal tab\n\ + %T time, 24-hour (hh:mm:ss)\n\ + %u day of week (1..7); 1 represents Monday\n\ +"), stdout); + fputs (_("\ + %U week number of year with Sunday as first day of week (00..53)\n\ + %V week number of year with Monday as first day of week (01..53)\n\ + %w day of week (0..6); 0 represents Sunday\n\ + %W week number of year with Monday as first day of week (00..53)\n\ +"), stdout); + fputs (_("\ + %x locale's date representation (mm/dd/yy)\n\ + %X locale's time representation (%H:%M:%S)\n\ + %y last two digits of year (00..99)\n\ + %Y year (1970...)\n\ +"), stdout); + fputs (_("\ + %z RFC-822 style numeric timezone (-0500) (a nonstandard extension)\n\ + %Z time zone (e.g., EDT), or nothing if no time zone is determinable\n\ +\n\ +By default, date pads numeric fields with zeroes. GNU date recognizes\n\ +the following modifiers between `%' and a numeric directive.\n\ +\n\ + `-' (hyphen) do not pad the field\n\ + `_' (underscore) pad the field with spaces\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +/* Parse each line in INPUT_FILENAME as with --date and display each + resulting time and date. If the file cannot be opened, tell why + then exit. Issue a diagnostic for any lines that cannot be parsed. + If any line cannot be parsed, return nonzero; otherwise return zero. */ + +static int +batch_convert (const char *input_filename, const char *format) +{ + int status; + FILE *in_stream; + char *line; + int line_length; + size_t buflen; + struct timespec when; + + if (strcmp (input_filename, "-") == 0) + { + input_filename = _("standard input"); + in_stream = stdin; + } + else + { + in_stream = fopen (input_filename, "r"); + if (in_stream == NULL) + { + error (EXIT_FAILURE, errno, "`%s'", input_filename); + } + } + + line = NULL; + buflen = 0; + status = 0; + while (1) + { + line_length = getline (&line, &buflen, in_stream); + if (line_length < 0) + { + /* FIXME: detect/handle error here. */ + break; + } + + when.tv_sec = get_date (line, NULL); + when.tv_nsec = 0; /* FIXME: get_date should set this. */ + + if (when.tv_sec == -1) + { + if (line[line_length - 1] == '\n') + line[line_length - 1] = '\0'; + error (0, 0, _("invalid date `%s'"), line); + status = 1; + } + else + { + show_date (format, when); + } + } + + if (fclose (in_stream) == EOF) + error (2, errno, "`%s'", input_filename); + + if (line != NULL) + free (line); + + return status; +} + +int +main (int argc, char **argv) +{ + int optc; + const char *datestr = NULL; + const char *set_datestr = NULL; + struct timespec when; + int set_date = 0; + char *format; + char *batch_file = NULL; + char *reference = NULL; + struct stat refstats; + int n_args; + int status; + int option_specified_date; + char const *short_options = (posix2_version () < 200112 + ? COMMON_SHORT_OPTIONS "I::" + : COMMON_SHORT_OPTIONS "I:"); + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + close_stdout_set_status (2); + atexit (close_stdout); + + while ((optc = getopt_long (argc, argv, short_options, long_options, NULL)) + != -1) + switch (optc) + { + case 0: + break; + case 'd': + datestr = optarg; + break; + case 'f': + batch_file = optarg; + break; + case 'I': + iso_8601_format = (optarg + ? XARGMATCH ("--iso-8601", optarg, + time_spec_string, time_spec) + : TIME_SPEC_DATE); + break; + case 'r': + reference = optarg; + break; + case 'R': + rfc_format = 1; + break; + case 's': + set_datestr = optarg; + set_date = 1; + break; + case 'u': + /* POSIX says that `date -u' is equivalent to setting the TZ + environment variable, so this option should do nothing other + than setting TZ. */ + if (putenv ("TZ=UTC0") != 0) + xalloc_die (); + TZSET; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + + n_args = argc - optind; + + option_specified_date = ((datestr ? 1 : 0) + + (batch_file ? 1 : 0) + + (reference ? 1 : 0)); + + if (option_specified_date > 1) + { + error (0, 0, + _("the options to specify dates for printing are mutually exclusive")); + usage (EXIT_FAILURE); + } + + if (set_date && option_specified_date) + { + error (0, 0, + _("the options to print and set the time may not be used together")); + usage (EXIT_FAILURE); + } + + if (n_args > 1) + { + error (0, 0, _("too many non-option arguments: %s%s"), + argv[optind + 1], n_args == 2 ? "" : " ..."); + usage (EXIT_FAILURE); + } + + if ((set_date || option_specified_date) + && n_args == 1 && argv[optind][0] != '+') + { + error (0, 0, _("\ +the argument `%s' lacks a leading `+';\n\ +When using an option to specify date(s), any non-option\n\ +argument must be a format string beginning with `+'."), + argv[optind]); + usage (EXIT_FAILURE); + } + + /* Simply ignore --rfc-822 if specified when setting the date. */ + if (rfc_format && !set_date && n_args > 0) + { + error (0, 0, + _("a format string may not be specified when using\ + the --rfc-822 (-R) option")); + usage (EXIT_FAILURE); + } + + if (set_date) + datestr = set_datestr; + + if (batch_file != NULL) + { + status = batch_convert (batch_file, + (n_args == 1 ? argv[optind] + 1 : NULL)); + } + else + { + bool valid_date = true; + status = 0; + + if (!option_specified_date && !set_date) + { + if (n_args == 1 && argv[optind][0] != '+') + { + /* Prepare to set system clock to the specified date/time + given in the POSIX-format. */ + set_date = 1; + datestr = argv[optind]; + valid_date = posixtime (&when.tv_sec, + datestr, + (PDS_TRAILING_YEAR + | PDS_CENTURY | PDS_SECONDS)); + when.tv_nsec = 0; /* FIXME: posixtime should set this. */ + format = NULL; + } + else + { + /* Prepare to print the current date/time. */ + datestr = _("undefined"); + if (gettime (&when) != 0) + error (EXIT_FAILURE, errno, _("cannot get time of day")); + format = (n_args == 1 ? argv[optind] + 1 : NULL); + } + } + else + { + /* (option_specified_date || set_date) */ + if (reference != NULL) + { + if (stat (reference, &refstats)) + error (EXIT_FAILURE, errno, "%s", reference); + when.tv_sec = refstats.st_mtime; + when.tv_nsec = TIMESPEC_NS (refstats.st_mtim); + } + else + { + when.tv_sec = get_date (datestr, NULL); + when.tv_nsec = 0; /* FIXME: get_date should set this. */ + valid_date = (when.tv_sec != (time_t) -1); + } + + format = (n_args == 1 ? argv[optind] + 1 : NULL); + } + + if (! valid_date) + error (EXIT_FAILURE, 0, _("invalid date `%s'"), datestr); + + if (set_date) + { + /* Set the system clock to the specified date, then regardless of + the success of that operation, format and print that date. */ + if (settime (&when) != 0) + { + error (0, errno, _("cannot set date")); + status = 1; + } + } + + show_date (format, when); + } + + exit (status); +} + +/* Display the date and/or time in WHEN according to the format specified + in FORMAT, followed by a newline. If FORMAT is NULL, use the + standard output format (ctime style but with a timezone inserted). */ + +static void +show_date (const char *format, struct timespec when) +{ + struct tm *tm; + char *out = NULL; + size_t out_length = 0; + /* ISO 8601 formats. See below regarding %z */ + static char const * const iso_format_string[] = + { + "%Y-%m-%d", + "%Y-%m-%dT%H%z", + "%Y-%m-%dT%H:%M%z", + "%Y-%m-%dT%H:%M:%S%z" + }; + + tm = localtime (&when.tv_sec); + + if (format == NULL) + { + if (rfc_format) + format = "%a, %d %b %Y %H:%M:%S %z"; + else if (iso_8601_format) + format = iso_format_string[iso_8601_format - 1]; + else + { + char *date_fmt = DATE_FMT_LANGINFO (); + /* Do not wrap the following literal format string with _(...). + For example, suppose LC_ALL is unset, LC_TIME="POSIX", + and LANG="ko_KR". In that case, POSIX says that LC_TIME + determines the format and contents of date and time strings + written by date, which means "date" must generate output + using the POSIX locale; but adding _() would cause "date" + to use a Korean translation of the format. */ + format = *date_fmt ? date_fmt : "%a %b %e %H:%M:%S %Z %Y"; + } + } + else if (*format == '\0') + { + printf ("\n"); + return; + } + + while (1) + { + int done; + out_length += 200; + out = (char *) xrealloc (out, out_length); + + /* Mark the first byte of the buffer so we can detect the case + of nstrftime producing an empty string. Otherwise, this loop + would not terminate when date was invoked like this + `LANG=de date +%p' on a system with good language support. */ + out[0] = '\1'; + + if (rfc_format) + setlocale (LC_ALL, "C"); + + done = (nstrftime (out, out_length, format, tm, 0, when.tv_nsec) + || out[0] == '\0'); + + if (rfc_format) + setlocale (LC_ALL, ""); + + if (done) + break; + } + + printf ("%s\n", out); + free (out); +} diff --git a/src/apps/bin/coreutils-5.0/src/dcgen b/src/apps/bin/coreutils-5.0/src/dcgen new file mode 100755 index 0000000000..8f45b364b5 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/dcgen @@ -0,0 +1,70 @@ +#!/usr/bin/perl -w +# -*- perl -*- + +eval 'exec /p/bin/perl -S $0 ${1+"$@"}' + if 0; + +# dcgen -- generate C declarations of arrays of lines and line lengths +# Copyright (C) 1996, 1998 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# written by Jim Meyering + +# If you uncomment the following lines, you should also do +# s/chop/chomp and s/local/my/. +#require 5.002; +#use strict; + +# Convert an arbitrary file to dcl of two arrays. +# One of lines, the other of lengths. + +local $prefix = 'G_'; + +local @line; +while (<>) + { + chop; + push (@line, $_); + } + +local $n = @line; +print "#define ${prefix}N_LINES $n\n\n"; + +local $indent = ' '; +print "const size_t ${prefix}line_length[${prefix}N_LINES] =\n{\n$indent"; +local $ind = $indent; +local $i; +for ($i = 0; $i < @line; $i++) + { + local $comma = ($i < @line - 1 ? ',' : ''); + $ind = '' if $i == @line - 1; + local $sep = ($i && $i % 18 == 0 || $i == @line - 1 ? "\n$ind" : ' '); + print length ($line[$i]), $comma, $sep; + } +print "};\n\n"; + +print "const char *const ${prefix}line[${prefix}N_LINES] =\n{\n"; +while (1) + { + $_ = shift (@line); + local $comma = (@line ? ',' : ''); + print "$indent\"$_\"$comma\n"; + last if !@line; + } +print "};\n"; + +exit (0); diff --git a/src/apps/bin/coreutils-5.0/src/dd.c b/src/apps/bin/coreutils-5.0/src/dd.c new file mode 100644 index 0000000000..aba75fcdb7 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/dd.c @@ -0,0 +1,1233 @@ +/* dd -- convert a file while copying it. + Copyright (C) 85, 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Paul Rubin, David MacKenzie, and Stuart Kemp. */ + +#include +#include + +#define SWAB_ALIGN_OFFSET 2 + +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "full-write.h" +#include "getpagesize.h" +#include "inttostr.h" +#include "long-options.h" +#include "quote.h" +#include "safe-read.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "dd" + +#define AUTHORS N_ ("Paul Rubin, David MacKenzie, and Stuart Kemp") + +#ifndef SIGINFO +# define SIGINFO SIGUSR1 +#endif + +#ifndef S_TYPEISSHM +# define S_TYPEISSHM(Stat_ptr) 0 +#endif + +#define ROUND_UP_OFFSET(X, M) ((M) - 1 - (((X) + (M) - 1) % (M))) +#define PTR_ALIGN(Ptr, M) ((Ptr) \ + + ROUND_UP_OFFSET ((char *)(Ptr) - (char *)0, (M))) + +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define output_char(c) \ + do \ + { \ + obuf[oc++] = (c); \ + if (oc >= output_blocksize) \ + write_output (); \ + } \ + while (0) + +/* Default input and output blocksize. */ +#define DEFAULT_BLOCKSIZE 512 + +/* Conversions bit masks. */ +#define C_ASCII 01 +#define C_EBCDIC 02 +#define C_IBM 04 +#define C_BLOCK 010 +#define C_UNBLOCK 020 +#define C_LCASE 040 +#define C_UCASE 0100 +#define C_SWAB 0200 +#define C_NOERROR 0400 +#define C_NOTRUNC 01000 +#define C_SYNC 02000 +/* Use separate input and output buffers, and combine partial input blocks. */ +#define C_TWOBUFS 04000 + +/* The name this program was run with. */ +char *program_name; + +/* The name of the input file, or NULL for the standard input. */ +static char const *input_file = NULL; + +/* The name of the output file, or NULL for the standard output. */ +static char const *output_file = NULL; + +/* The number of bytes in which atomic reads are done. */ +static size_t input_blocksize = 0; + +/* The number of bytes in which atomic writes are done. */ +static size_t output_blocksize = 0; + +/* Conversion buffer size, in bytes. 0 prevents conversions. */ +static size_t conversion_blocksize = 0; + +/* Skip this many records of `input_blocksize' bytes before input. */ +static uintmax_t skip_records = 0; + +/* Skip this many records of `output_blocksize' bytes before output. */ +static uintmax_t seek_records = 0; + +/* Copy only this many records. The default is effectively infinity. */ +static uintmax_t max_records = (uintmax_t) -1; + +/* Bit vector of conversions to apply. */ +static int conversions_mask = 0; + +/* If nonzero, filter characters through the translation table. */ +static int translation_needed = 0; + +/* Number of partial blocks written. */ +static uintmax_t w_partial = 0; + +/* Number of full blocks written. */ +static uintmax_t w_full = 0; + +/* Number of partial blocks read. */ +static uintmax_t r_partial = 0; + +/* Number of full blocks read. */ +static uintmax_t r_full = 0; + +/* Records truncated by conv=block. */ +static uintmax_t r_truncate = 0; + +/* Output representation of newline and space characters. + They change if we're converting to EBCDIC. */ +static char newline_character = '\n'; +static char space_character = ' '; + +/* Output buffer. */ +static char *obuf; + +/* Current index into `obuf'. */ +static size_t oc = 0; + +/* Index into current line, for `conv=block' and `conv=unblock'. */ +static size_t col = 0; + +struct conversion +{ + char *convname; + int conversion; +}; + +static struct conversion conversions[] = +{ + {"ascii", C_ASCII | C_TWOBUFS}, /* EBCDIC to ASCII. */ + {"ebcdic", C_EBCDIC | C_TWOBUFS}, /* ASCII to EBCDIC. */ + {"ibm", C_IBM | C_TWOBUFS}, /* Slightly different ASCII to EBCDIC. */ + {"block", C_BLOCK | C_TWOBUFS}, /* Variable to fixed length records. */ + {"unblock", C_UNBLOCK | C_TWOBUFS}, /* Fixed to variable length records. */ + {"lcase", C_LCASE | C_TWOBUFS}, /* Translate upper to lower case. */ + {"ucase", C_UCASE | C_TWOBUFS}, /* Translate lower to upper case. */ + {"swab", C_SWAB | C_TWOBUFS}, /* Swap bytes of input. */ + {"noerror", C_NOERROR}, /* Ignore i/o errors. */ + {"notrunc", C_NOTRUNC}, /* Do not truncate output file. */ + {"sync", C_SYNC}, /* Pad input records to ibs with NULs. */ + {NULL, 0} +}; + +/* Translation table formed by applying successive transformations. */ +static unsigned char trans_table[256]; + +static char const ascii_to_ebcdic[] = +{ + '\000', '\001', '\002', '\003', '\067', '\055', '\056', '\057', + '\026', '\005', '\045', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\074', '\075', '\062', '\046', + '\030', '\031', '\077', '\047', '\034', '\035', '\036', '\037', + '\100', '\117', '\177', '\173', '\133', '\154', '\120', '\175', + '\115', '\135', '\134', '\116', '\153', '\140', '\113', '\141', + '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + '\370', '\371', '\172', '\136', '\114', '\176', '\156', '\157', + '\174', '\301', '\302', '\303', '\304', '\305', '\306', '\307', + '\310', '\311', '\321', '\322', '\323', '\324', '\325', '\326', + '\327', '\330', '\331', '\342', '\343', '\344', '\345', '\346', + '\347', '\350', '\351', '\112', '\340', '\132', '\137', '\155', + '\171', '\201', '\202', '\203', '\204', '\205', '\206', '\207', + '\210', '\211', '\221', '\222', '\223', '\224', '\225', '\226', + '\227', '\230', '\231', '\242', '\243', '\244', '\245', '\246', + '\247', '\250', '\251', '\300', '\152', '\320', '\241', '\007', + '\040', '\041', '\042', '\043', '\044', '\025', '\006', '\027', + '\050', '\051', '\052', '\053', '\054', '\011', '\012', '\033', + '\060', '\061', '\032', '\063', '\064', '\065', '\066', '\010', + '\070', '\071', '\072', '\073', '\004', '\024', '\076', '\341', + '\101', '\102', '\103', '\104', '\105', '\106', '\107', '\110', + '\111', '\121', '\122', '\123', '\124', '\125', '\126', '\127', + '\130', '\131', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\160', '\161', '\162', '\163', '\164', '\165', + '\166', '\167', '\170', '\200', '\212', '\213', '\214', '\215', + '\216', '\217', '\220', '\232', '\233', '\234', '\235', '\236', + '\237', '\240', '\252', '\253', '\254', '\255', '\256', '\257', + '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', + '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', + '\312', '\313', '\314', '\315', '\316', '\317', '\332', '\333', + '\334', '\335', '\336', '\337', '\352', '\353', '\354', '\355', + '\356', '\357', '\372', '\373', '\374', '\375', '\376', '\377' +}; + +static char const ascii_to_ibm[] = +{ + '\000', '\001', '\002', '\003', '\067', '\055', '\056', '\057', + '\026', '\005', '\045', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\074', '\075', '\062', '\046', + '\030', '\031', '\077', '\047', '\034', '\035', '\036', '\037', + '\100', '\132', '\177', '\173', '\133', '\154', '\120', '\175', + '\115', '\135', '\134', '\116', '\153', '\140', '\113', '\141', + '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + '\370', '\371', '\172', '\136', '\114', '\176', '\156', '\157', + '\174', '\301', '\302', '\303', '\304', '\305', '\306', '\307', + '\310', '\311', '\321', '\322', '\323', '\324', '\325', '\326', + '\327', '\330', '\331', '\342', '\343', '\344', '\345', '\346', + '\347', '\350', '\351', '\255', '\340', '\275', '\137', '\155', + '\171', '\201', '\202', '\203', '\204', '\205', '\206', '\207', + '\210', '\211', '\221', '\222', '\223', '\224', '\225', '\226', + '\227', '\230', '\231', '\242', '\243', '\244', '\245', '\246', + '\247', '\250', '\251', '\300', '\117', '\320', '\241', '\007', + '\040', '\041', '\042', '\043', '\044', '\025', '\006', '\027', + '\050', '\051', '\052', '\053', '\054', '\011', '\012', '\033', + '\060', '\061', '\032', '\063', '\064', '\065', '\066', '\010', + '\070', '\071', '\072', '\073', '\004', '\024', '\076', '\341', + '\101', '\102', '\103', '\104', '\105', '\106', '\107', '\110', + '\111', '\121', '\122', '\123', '\124', '\125', '\126', '\127', + '\130', '\131', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\160', '\161', '\162', '\163', '\164', '\165', + '\166', '\167', '\170', '\200', '\212', '\213', '\214', '\215', + '\216', '\217', '\220', '\232', '\233', '\234', '\235', '\236', + '\237', '\240', '\252', '\253', '\254', '\255', '\256', '\257', + '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', + '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', + '\312', '\313', '\314', '\315', '\316', '\317', '\332', '\333', + '\334', '\335', '\336', '\337', '\352', '\353', '\354', '\355', + '\356', '\357', '\372', '\373', '\374', '\375', '\376', '\377' +}; + +static char const ebcdic_to_ascii[] = +{ + '\000', '\001', '\002', '\003', '\234', '\011', '\206', '\177', + '\227', '\215', '\216', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\235', '\205', '\010', '\207', + '\030', '\031', '\222', '\217', '\034', '\035', '\036', '\037', + '\200', '\201', '\202', '\203', '\204', '\012', '\027', '\033', + '\210', '\211', '\212', '\213', '\214', '\005', '\006', '\007', + '\220', '\221', '\026', '\223', '\224', '\225', '\226', '\004', + '\230', '\231', '\232', '\233', '\024', '\025', '\236', '\032', + '\040', '\240', '\241', '\242', '\243', '\244', '\245', '\246', + '\247', '\250', '\133', '\056', '\074', '\050', '\053', '\041', + '\046', '\251', '\252', '\253', '\254', '\255', '\256', '\257', + '\260', '\261', '\135', '\044', '\052', '\051', '\073', '\136', + '\055', '\057', '\262', '\263', '\264', '\265', '\266', '\267', + '\270', '\271', '\174', '\054', '\045', '\137', '\076', '\077', + '\272', '\273', '\274', '\275', '\276', '\277', '\300', '\301', + '\302', '\140', '\072', '\043', '\100', '\047', '\075', '\042', + '\303', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\304', '\305', '\306', '\307', '\310', '\311', + '\312', '\152', '\153', '\154', '\155', '\156', '\157', '\160', + '\161', '\162', '\313', '\314', '\315', '\316', '\317', '\320', + '\321', '\176', '\163', '\164', '\165', '\166', '\167', '\170', + '\171', '\172', '\322', '\323', '\324', '\325', '\326', '\327', + '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', + '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + '\173', '\101', '\102', '\103', '\104', '\105', '\106', '\107', + '\110', '\111', '\350', '\351', '\352', '\353', '\354', '\355', + '\175', '\112', '\113', '\114', '\115', '\116', '\117', '\120', + '\121', '\122', '\356', '\357', '\360', '\361', '\362', '\363', + '\134', '\237', '\123', '\124', '\125', '\126', '\127', '\130', + '\131', '\132', '\364', '\365', '\366', '\367', '\370', '\371', + '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', + '\070', '\071', '\372', '\373', '\374', '\375', '\376', '\377' +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]...\n"), program_name); + fputs (_("\ +Copy a file, converting and formatting according to the options.\n\ +\n\ + bs=BYTES force ibs=BYTES and obs=BYTES\n\ + cbs=BYTES convert BYTES bytes at a time\n\ + conv=KEYWORDS convert the file as per the comma separated keyword list\n\ + count=BLOCKS copy only BLOCKS input blocks\n\ + ibs=BYTES read BYTES bytes at a time\n\ +"), stdout); + fputs (_("\ + if=FILE read from FILE instead of stdin\n\ + obs=BYTES write BYTES bytes at a time\n\ + of=FILE write to FILE instead of stdout\n\ + seek=BLOCKS skip BLOCKS obs-sized blocks at start of output\n\ + skip=BLOCKS skip BLOCKS ibs-sized blocks at start of input\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +BLOCKS and BYTES may be followed by the following multiplicative suffixes:\n\ +xM M, c 1, w 2, b 512, kB 1000, K 1024, MB 1,000,000, M 1,048,576,\n\ +GB 1,000,000,000, G 1,073,741,824, and so on for T, P, E, Z, Y.\n\ +Each KEYWORD may be:\n\ +\n\ +"), stdout); + fputs (_("\ + ascii from EBCDIC to ASCII\n\ + ebcdic from ASCII to EBCDIC\n\ + ibm from ASCII to alternated EBCDIC\n\ + block pad newline-terminated records with spaces to cbs-size\n\ + unblock replace trailing spaces in cbs-size records with newline\n\ + lcase change upper case to lower case\n\ +"), stdout); + fputs (_("\ + notrunc do not truncate the output file\n\ + ucase change lower case to upper case\n\ + swab swap every pair of input bytes\n\ + noerror continue after read errors\n\ + sync pad every input block with NULs to ibs-size; when used\n\ + with block or unblock, pad with spaces rather than NULs\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +static void +translate_charset (char const *new_trans) +{ + int i; + + for (i = 0; i < 256; i++) + trans_table[i] = new_trans[trans_table[i]]; + translation_needed = 1; +} + +/* Return the number of 1 bits in `i'. */ + +static int +bit_count (register int i) +{ + register int set_bits; + + for (set_bits = 0; i != 0; set_bits++) + i &= i - 1; + return set_bits; +} + +static void +print_stats (void) +{ + char buf[2][INT_BUFSIZE_BOUND (uintmax_t)]; + fprintf (stderr, _("%s+%s records in\n"), + umaxtostr (r_full, buf[0]), umaxtostr (r_partial, buf[1])); + fprintf (stderr, _("%s+%s records out\n"), + umaxtostr (w_full, buf[0]), umaxtostr (w_partial, buf[1])); + if (r_truncate > 0) + { + fprintf (stderr, "%s %s\n", + umaxtostr (r_truncate, buf[0]), + (r_truncate == 1 + ? _("truncated record") + : _("truncated records"))); + } +} + +static void +cleanup (void) +{ + print_stats (); + if (close (STDIN_FILENO) < 0) + error (EXIT_FAILURE, errno, + _("closing input file %s"), quote (input_file)); + if (close (STDOUT_FILENO) < 0) + error (EXIT_FAILURE, errno, + _("closing output file %s"), quote (output_file)); +} + +static inline void +quit (int code) +{ + cleanup (); + exit (code); +} + +static RETSIGTYPE +interrupt_handler (int sig) +{ +#ifdef SA_NOCLDSTOP + struct sigaction sigact; + + sigact.sa_handler = SIG_DFL; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (sig, &sigact, NULL); +#else + signal (sig, SIG_DFL); +#endif + cleanup (); + raise (sig); +} + +static RETSIGTYPE +siginfo_handler (int sig ATTRIBUTE_UNUSED) +{ + print_stats (); +} + +/* Encapsulate portability mess of establishing signal handlers. */ + +static void +install_handler (int sig_num, RETSIGTYPE (*sig_handler) (int sig)) +{ +#ifdef SA_NOCLDSTOP + struct sigaction sigact; + sigaction (sig_num, NULL, &sigact); + if (sigact.sa_handler != SIG_IGN) + { + sigact.sa_handler = sig_handler; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (sig_num, &sigact, NULL); + } +#else + if (signal (sig_num, SIG_IGN) != SIG_IGN) + signal (sig_num, sig_handler); +#endif +} + +/* Open a file to a particular file descriptor. This is like standard + `open', except it always returns DESIRED_FD if successful. */ +static int +open_fd (int desired_fd, char const *filename, int options, mode_t mode) +{ + int fd; + close (desired_fd); + fd = open (filename, options, mode); + if (fd < 0) + return -1; + + if (fd != desired_fd) + { + if (dup2 (fd, desired_fd) != desired_fd) + desired_fd = -1; + if (close (fd) != 0) + return -1; + } + + return desired_fd; +} + +/* Write, then empty, the output buffer `obuf'. */ + +static void +write_output (void) +{ + size_t nwritten = full_write (STDOUT_FILENO, obuf, output_blocksize); + if (nwritten != output_blocksize) + { + error (0, errno, _("writing to %s"), quote (output_file)); + if (nwritten != 0) + w_partial++; + quit (1); + } + else + w_full++; + oc = 0; +} + +/* Interpret one "conv=..." option. + As a by product, this function replaces each `,' in STR with a NUL byte. */ + +static void +parse_conversion (char *str) +{ + char *new; + int i; + + do + { + new = strchr (str, ','); + if (new != NULL) + *new++ = '\0'; + for (i = 0; conversions[i].convname != NULL; i++) + if (STREQ (conversions[i].convname, str)) + { + conversions_mask |= conversions[i].conversion; + break; + } + if (conversions[i].convname == NULL) + { + error (0, 0, _("invalid conversion: %s"), quote (str)); + usage (EXIT_FAILURE); + } + str = new; + } while (new != NULL); +} + +/* Return the value of STR, interpreted as a non-negative decimal integer, + optionally multiplied by various values. + Assign nonzero to *INVALID if STR does not represent a number in + this format. */ + +static uintmax_t +parse_integer (const char *str, int *invalid) +{ + uintmax_t n; + char *suffix; + enum strtol_error e = xstrtoumax (str, &suffix, 10, &n, "bcEGkKMPTwYZ0"); + + if (e == LONGINT_INVALID_SUFFIX_CHAR && *suffix == 'x') + { + uintmax_t multiplier = parse_integer (suffix + 1, invalid); + + if (multiplier != 0 && n * multiplier / multiplier != n) + { + *invalid = 1; + return 0; + } + + n *= multiplier; + } + else if (e != LONGINT_OK) + { + *invalid = 1; + return 0; + } + + return n; +} + +static void +scanargs (int argc, char **argv) +{ + int i; + + --argc; + ++argv; + + for (i = optind; i < argc; i++) + { + char *name, *val; + + name = argv[i]; + val = strchr (name, '='); + if (val == NULL) + { + error (0, 0, _("unrecognized option %s"), quote (name)); + usage (EXIT_FAILURE); + } + *val++ = '\0'; + + if (STREQ (name, "if")) + input_file = val; + else if (STREQ (name, "of")) + output_file = val; + else if (STREQ (name, "conv")) + parse_conversion (val); + else + { + int invalid = 0; + uintmax_t n = parse_integer (val, &invalid); + + if (STREQ (name, "ibs")) + { + /* Ensure that each blocksize is <= SSIZE_MAX. */ + invalid |= SSIZE_MAX < n; + input_blocksize = n; + invalid |= input_blocksize != n || input_blocksize == 0; + conversions_mask |= C_TWOBUFS; + } + else if (STREQ (name, "obs")) + { + /* Ensure that each blocksize is <= SSIZE_MAX. */ + invalid |= SSIZE_MAX < n; + output_blocksize = n; + invalid |= output_blocksize != n || output_blocksize == 0; + conversions_mask |= C_TWOBUFS; + } + else if (STREQ (name, "bs")) + { + /* Ensure that each blocksize is <= SSIZE_MAX. */ + invalid |= SSIZE_MAX < n; + output_blocksize = input_blocksize = n; + invalid |= output_blocksize != n || output_blocksize == 0; + } + else if (STREQ (name, "cbs")) + { + conversion_blocksize = n; + invalid |= (conversion_blocksize != n + || conversion_blocksize == 0); + } + else if (STREQ (name, "skip")) + skip_records = n; + else if (STREQ (name, "seek")) + seek_records = n; + else if (STREQ (name, "count")) + max_records = n; + else + { + error (0, 0, _("unrecognized option %s=%s"), + quote_n (0, name), quote_n (1, val)); + usage (EXIT_FAILURE); + } + + if (invalid) + error (EXIT_FAILURE, 0, _("invalid number %s"), quote (val)); + } + } + + /* If bs= was given, both `input_blocksize' and `output_blocksize' will + have been set to positive values. If either has not been set, + bs= was not given, so make sure two buffers are used. */ + if (input_blocksize == 0 || output_blocksize == 0) + conversions_mask |= C_TWOBUFS; + if (input_blocksize == 0) + input_blocksize = DEFAULT_BLOCKSIZE; + if (output_blocksize == 0) + output_blocksize = DEFAULT_BLOCKSIZE; + if (conversion_blocksize == 0) + conversions_mask &= ~(C_BLOCK | C_UNBLOCK); +} + +/* Fix up translation table. */ + +static void +apply_translations (void) +{ + int i; + +#define MX(a) (bit_count (conversions_mask & (a))) + if ((MX (C_ASCII | C_EBCDIC | C_IBM) > 1) + || (MX (C_BLOCK | C_UNBLOCK) > 1) + || (MX (C_LCASE | C_UCASE) > 1) + || (MX (C_UNBLOCK | C_SYNC) > 1)) + { + error (EXIT_FAILURE, 0, _("\ +only one conv in {ascii,ebcdic,ibm}, {lcase,ucase}, {block,unblock}, {unblock,sync}")); + } +#undef MX + + if (conversions_mask & C_ASCII) + translate_charset (ebcdic_to_ascii); + + if (conversions_mask & C_UCASE) + { + for (i = 0; i < 256; i++) + if (ISLOWER (trans_table[i])) + trans_table[i] = TOUPPER (trans_table[i]); + translation_needed = 1; + } + else if (conversions_mask & C_LCASE) + { + for (i = 0; i < 256; i++) + if (ISUPPER (trans_table[i])) + trans_table[i] = TOLOWER (trans_table[i]); + translation_needed = 1; + } + + if (conversions_mask & C_EBCDIC) + { + translate_charset (ascii_to_ebcdic); + newline_character = ascii_to_ebcdic['\n']; + space_character = ascii_to_ebcdic[' ']; + } + else if (conversions_mask & C_IBM) + { + translate_charset (ascii_to_ibm); + newline_character = ascii_to_ibm['\n']; + space_character = ascii_to_ibm[' ']; + } +} + +/* Apply the character-set translations specified by the user + to the NREAD bytes in BUF. */ + +static void +translate_buffer (char *buf, size_t nread) +{ + char *cp; + size_t i; + + for (i = nread, cp = buf; i; i--, cp++) + *cp = trans_table[(unsigned char) *cp]; +} + +/* If nonnzero, the last char from the previous call to `swab_buffer' + is saved in `saved_char'. */ +static int char_is_saved = 0; + +/* Odd char from previous call. */ +static char saved_char; + +/* Swap NREAD bytes in BUF, plus possibly an initial char from the + previous call. If NREAD is odd, save the last char for the + next call. Return the new start of the BUF buffer. */ + +static char * +swab_buffer (char *buf, size_t *nread) +{ + char *bufstart = buf; + register char *cp; + register int i; + + /* Is a char left from last time? */ + if (char_is_saved) + { + *--bufstart = saved_char; + (*nread)++; + char_is_saved = 0; + } + + if (*nread & 1) + { + /* An odd number of chars are in the buffer. */ + saved_char = bufstart[--*nread]; + char_is_saved = 1; + } + + /* Do the byte-swapping by moving every second character two + positions toward the end, working from the end of the buffer + toward the beginning. This way we only move half of the data. */ + + cp = bufstart + *nread; /* Start one char past the last. */ + for (i = *nread / 2; i; i--, cp -= 2) + *cp = *(cp - 2); + + return ++bufstart; +} + +/* This is a wrapper for lseek. It detects and warns about a kernel + bug that makes lseek a no-op for tape devices, even though the kernel + lseek return value suggests that the function succeeded. + + The parameters are the same as those of the lseek function, but + with the addition of FILENAME, the name of the file associated with + descriptor FDESC. The file name is used solely in the warning that's + printed when the bug is detected. Return the same value that lseek + would have returned, but when the lseek bug is detected, return -1 + to indicate that lseek failed. + + The offending behavior has been confirmed with an Exabyte SCSI tape + drive accessed via /dev/nst0 on both Linux-2.2.17 and Linux-2.4.16. */ + +#ifdef __linux__ + +# include + +# define MT_SAME_POSITION(P, Q) \ + ((P).mt_resid == (Q).mt_resid \ + && (P).mt_fileno == (Q).mt_fileno \ + && (P).mt_blkno == (Q).mt_blkno) + +static off_t +skip_via_lseek (char const *filename, int fdesc, off_t offset, int whence) +{ + struct mtget s1; + struct mtget s2; + off_t new_position; + int got_original_tape_position; + + got_original_tape_position = (ioctl (fdesc, MTIOCGET, &s1) == 0); + /* known bad device type */ + /* && s.mt_type == MT_ISSCSI2 */ + + new_position = lseek (fdesc, offset, whence); + if (0 <= new_position + && got_original_tape_position + && ioctl (fdesc, MTIOCGET, &s2) == 0 + && MT_SAME_POSITION (s1, s2)) + { + error (0, 0, _("warning: working around lseek kernel bug for file (%s)\n\ + of mt_type=0x%0lx -- see for the list of types"), + filename, s2.mt_type); + new_position = -1; + } + + return new_position; +} +#else +# define skip_via_lseek(Filename, Fd, Offset, Whence) lseek (Fd, Offset, Whence) +#endif + +/* Throw away RECORDS blocks of BLOCKSIZE bytes on file descriptor FDESC, + which is open with read permission for FILE. Store up to BLOCKSIZE + bytes of the data at a time in BUF, if necessary. RECORDS must be + nonzero. */ + +static void +skip (int fdesc, char const *file, uintmax_t records, size_t blocksize, + char *buf) +{ + off_t offset = records * blocksize; + + /* Try lseek and if an error indicates it was an inappropriate operation -- + or if the the file offset is not representable as an off_t -- + fall back on using read. */ + + if ((uintmax_t) offset / blocksize != records + || skip_via_lseek (file, fdesc, offset, SEEK_CUR) < 0) + { + while (records--) + { + size_t nread = safe_read (fdesc, buf, blocksize); + if (nread == SAFE_READ_ERROR) + { + error (0, errno, _("reading %s"), quote (file)); + quit (1); + } + /* POSIX doesn't say what to do when dd detects it has been + asked to skip past EOF, so I assume it's non-fatal. + FIXME: maybe give a warning. */ + if (nread == 0) + break; + } + } +} + +/* Copy NREAD bytes of BUF, with no conversions. */ + +static void +copy_simple (char const *buf, int nread) +{ + int nfree; /* Number of unused bytes in `obuf'. */ + const char *start = buf; /* First uncopied char in BUF. */ + + do + { + nfree = output_blocksize - oc; + if (nfree > nread) + nfree = nread; + + memcpy (obuf + oc, start, nfree); + + nread -= nfree; /* Update the number of bytes left to copy. */ + start += nfree; + oc += nfree; + if (oc >= output_blocksize) + write_output (); + } + while (nread > 0); +} + +/* Copy NREAD bytes of BUF, doing conv=block + (pad newline-terminated records to `conversion_blocksize', + replacing the newline with trailing spaces). */ + +static void +copy_with_block (char const *buf, size_t nread) +{ + size_t i; + + for (i = nread; i; i--, buf++) + { + if (*buf == newline_character) + { + if (col < conversion_blocksize) + { + size_t j; + for (j = col; j < conversion_blocksize; j++) + output_char (space_character); + } + col = 0; + } + else + { + if (col == conversion_blocksize) + r_truncate++; + else if (col < conversion_blocksize) + output_char (*buf); + col++; + } + } +} + +/* Copy NREAD bytes of BUF, doing conv=unblock + (replace trailing spaces in `conversion_blocksize'-sized records + with a newline). */ + +static void +copy_with_unblock (char const *buf, size_t nread) +{ + size_t i; + char c; + static int pending_spaces = 0; + + for (i = 0; i < nread; i++) + { + c = buf[i]; + + if (col++ >= conversion_blocksize) + { + col = pending_spaces = 0; /* Wipe out any pending spaces. */ + i--; /* Push the char back; get it later. */ + output_char (newline_character); + } + else if (c == space_character) + pending_spaces++; + else + { + /* `c' is the character after a run of spaces that were not + at the end of the conversion buffer. Output them. */ + while (pending_spaces) + { + output_char (space_character); + --pending_spaces; + } + output_char (c); + } + } +} + +/* The main loop. */ + +static int +dd_copy (void) +{ + char *ibuf, *bufstart; /* Input buffer. */ + char *real_buf; /* real buffer address before alignment */ + char *real_obuf; + size_t nread; /* Bytes read in the current block. */ + int exit_status = 0; + size_t page_size = getpagesize (); + size_t n_bytes_read; + + /* Leave at least one extra byte at the beginning and end of `ibuf' + for conv=swab, but keep the buffer address even. But some peculiar + device drivers work only with word-aligned buffers, so leave an + extra two bytes. */ + + /* Some devices require alignment on a sector or page boundary + (e.g. character disk devices). Align the input buffer to a + page boundary to cover all bases. Note that due to the swab + algorithm, we must have at least one byte in the page before + the input buffer; thus we allocate 2 pages of slop in the + real buffer. 8k above the blocksize shouldn't bother anyone. + + The page alignment is necessary on any linux system that supports + either the SGI raw I/O patch or Steven Tweedies raw I/O patch. + It is necessary when accessing raw (i.e. character special) disk + devices on Unixware or other SVR4-derived system. */ + + real_buf = xmalloc (input_blocksize + + 2 * SWAB_ALIGN_OFFSET + + 2 * page_size - 1); + ibuf = real_buf; + ibuf += SWAB_ALIGN_OFFSET; /* allow space for swab */ + + ibuf = PTR_ALIGN (ibuf, page_size); + + if (conversions_mask & C_TWOBUFS) + { + /* Page-align the output buffer, too. */ + real_obuf = xmalloc (output_blocksize + page_size - 1); + obuf = PTR_ALIGN (real_obuf, page_size); + } + else + { + real_obuf = NULL; + obuf = ibuf; + } + + if (skip_records != 0) + skip (STDIN_FILENO, input_file, skip_records, input_blocksize, ibuf); + + if (seek_records != 0) + { + /* FIXME: this loses for + % ./dd if=dd seek=1 |: + ./dd: standard output: Bad file descriptor + 0+0 records in + 0+0 records out + */ + + skip (STDOUT_FILENO, output_file, seek_records, output_blocksize, obuf); + } + + if (max_records == 0) + quit (exit_status); + + while (1) + { + if (r_partial + r_full >= max_records) + break; + + /* Zero the buffer before reading, so that if we get a read error, + whatever data we are able to read is followed by zeros. + This minimizes data loss. */ + if ((conversions_mask & C_SYNC) && (conversions_mask & C_NOERROR)) + memset (ibuf, + (conversions_mask & (C_BLOCK | C_UNBLOCK)) ? ' ' : '\0', + input_blocksize); + + nread = safe_read (STDIN_FILENO, ibuf, input_blocksize); + + if (nread == 0) + break; /* EOF. */ + + if (nread == SAFE_READ_ERROR) + { + error (0, errno, _("reading %s"), quote (input_file)); + if (conversions_mask & C_NOERROR) + { + print_stats (); + /* Seek past the bad block if possible. */ + lseek (STDIN_FILENO, (off_t) input_blocksize, SEEK_CUR); + if (conversions_mask & C_SYNC) + /* Replace the missing input with null bytes and + proceed normally. */ + nread = 0; + else + continue; + } + else + { + /* Write any partial block. */ + exit_status = 2; + break; + } + } + + n_bytes_read = nread; + + if (n_bytes_read < input_blocksize) + { + r_partial++; + if (conversions_mask & C_SYNC) + { + if (!(conversions_mask & C_NOERROR)) + /* If C_NOERROR, we zeroed the block before reading. */ + memset (ibuf + n_bytes_read, + (conversions_mask & (C_BLOCK | C_UNBLOCK)) ? ' ' : '\0', + input_blocksize - n_bytes_read); + n_bytes_read = input_blocksize; + } + } + else + r_full++; + + if (ibuf == obuf) /* If not C_TWOBUFS. */ + { + size_t nwritten = full_write (STDOUT_FILENO, obuf, n_bytes_read); + if (nwritten != n_bytes_read) + { + error (0, errno, _("writing %s"), quote (output_file)); + quit (1); + } + else if (n_bytes_read == input_blocksize) + w_full++; + else + w_partial++; + continue; + } + + /* Do any translations on the whole buffer at once. */ + + if (translation_needed) + translate_buffer (ibuf, n_bytes_read); + + if (conversions_mask & C_SWAB) + bufstart = swab_buffer (ibuf, &n_bytes_read); + else + bufstart = ibuf; + + if (conversions_mask & C_BLOCK) + copy_with_block (bufstart, n_bytes_read); + else if (conversions_mask & C_UNBLOCK) + copy_with_unblock (bufstart, n_bytes_read); + else + copy_simple (bufstart, n_bytes_read); + } + + /* If we have a char left as a result of conv=swab, output it. */ + if (char_is_saved) + { + if (conversions_mask & C_BLOCK) + copy_with_block (&saved_char, 1); + else if (conversions_mask & C_UNBLOCK) + copy_with_unblock (&saved_char, 1); + else + output_char (saved_char); + } + + if ((conversions_mask & C_BLOCK) && col > 0) + { + /* If the final input line didn't end with a '\n', pad + the output block to `conversion_blocksize' chars. */ + size_t i; + for (i = col; i < conversion_blocksize; i++) + output_char (space_character); + } + + if ((conversions_mask & C_UNBLOCK) && col == conversion_blocksize) + /* Add a final '\n' if there are exactly `conversion_blocksize' + characters in the final record. */ + output_char (newline_character); + + /* Write out the last block. */ + if (oc != 0) + { + size_t nwritten = full_write (STDOUT_FILENO, obuf, oc); + if (nwritten != 0) + w_partial++; + if (nwritten != oc) + { + error (0, errno, _("writing %s"), quote (output_file)); + quit (1); + } + } + + free (real_buf); + if (real_obuf) + free (real_obuf); + + return exit_status; +} + +/* This is gross, but necessary, because of the way close_stdout + works and because this program closes STDOUT_FILENO directly. */ +static void (*closeout_func) (void) = close_stdout; + +static void +close_stdout_wrapper (void) +{ + if (closeout_func) + (*closeout_func) (); +} + +int +main (int argc, char **argv) +{ + int i; + int exit_status; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + /* Arrange to close stdout if parse_long_options exits. */ + atexit (close_stdout_wrapper); + + parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION, + AUTHORS, usage); + + /* Don't close stdout on exit from here on. */ + closeout_func = NULL; + + /* Initialize translation table to identity translation. */ + for (i = 0; i < 256; i++) + trans_table[i] = i; + + /* Decode arguments. */ + scanargs (argc, argv); + + apply_translations (); + + if (input_file != NULL) + { + if (open_fd (STDIN_FILENO, input_file, O_RDONLY, 0) < 0) + error (EXIT_FAILURE, errno, _("opening %s"), quote (input_file)); + } + else + input_file = _("standard input"); + + if (output_file != NULL) + { + mode_t perms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + int opts + = (O_CREAT + | (seek_records || (conversions_mask & C_NOTRUNC) ? 0 : O_TRUNC)); + + /* Open the output file with *read* access only if we might + need to read to satisfy a `seek=' request. If we can't read + the file, go ahead with write-only access; it might work. */ + if ((! seek_records + || open_fd (STDOUT_FILENO, output_file, O_RDWR | opts, perms) < 0) + && open_fd (STDOUT_FILENO, output_file, O_WRONLY | opts, perms) < 0) + error (EXIT_FAILURE, errno, _("opening %s"), quote (output_file)); + +#if HAVE_FTRUNCATE + if (seek_records != 0 && !(conversions_mask & C_NOTRUNC)) + { + struct stat stdout_stat; + off_t o = seek_records * output_blocksize; + if ((uintmax_t) o / output_blocksize != seek_records) + error (EXIT_FAILURE, 0, _("file offset out of range")); + + if (fstat (STDOUT_FILENO, &stdout_stat) != 0) + error (EXIT_FAILURE, errno, _("cannot fstat %s"), + quote (output_file)); + + /* Complain only when ftruncate fails on a regular file, a + directory, or a shared memory object, as the 2000-08 + POSIX draft specifies ftruncate's behavior only for these + file types. For example, do not complain when Linux 2.4 + ftruncate fails on /dev/fd0. */ + if (ftruncate (STDOUT_FILENO, o) != 0 + && (S_ISREG (stdout_stat.st_mode) + || S_ISDIR (stdout_stat.st_mode) + || S_TYPEISSHM (&stdout_stat))) + { + char buf[INT_BUFSIZE_BOUND (off_t)]; + error (EXIT_FAILURE, errno, + _("advancing past %s bytes in output file %s"), + offtostr (o, buf), quote (output_file)); + } + } +#endif + } + else + { + output_file = _("standard output"); + } + + install_handler (SIGINT, interrupt_handler); + install_handler (SIGQUIT, interrupt_handler); + install_handler (SIGPIPE, interrupt_handler); + install_handler (SIGINFO, siginfo_handler); + + exit_status = dd_copy (); + + quit (exit_status); +} diff --git a/src/apps/bin/coreutils-5.0/src/df.c b/src/apps/bin/coreutils-5.0/src/df.c new file mode 100644 index 0000000000..fdeb14c8c9 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/df.c @@ -0,0 +1,933 @@ +/* df - summarize free disk space + Copyright (C) 91, 1995-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie . + --human-readable and --megabyte options added by lm@sgi.com. + --si and large file support added by eggert@twinsun.com. */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include +#include +#include +#include + +#include "system.h" +#include "canonicalize.h" +#include "dirname.h" +#include "error.h" +#include "fsusage.h" +#include "human.h" +#include "inttostr.h" +#include "mountlist.h" +#include "path-concat.h" +#include "quote.h" +#include "save-cwd.h" +#include "xgetcwd.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "df" + +#define AUTHORS \ + N_ ("Torbjorn Granlund, David MacKenzie, Larry McVoy, and Paul Eggert") + +/* Name this program was run with. */ +char *program_name; + +/* If nonzero, show inode information. */ +static int inode_format; + +/* If nonzero, show even filesystems with zero size or + uninteresting types. */ +static int show_all_fs; + +/* If nonzero, show only local filesystems. */ +static int show_local_fs; + +/* If nonzero, output data for each filesystem corresponding to a + command line argument -- even if it's a dummy (automounter) entry. */ +static int show_listed_fs; + +/* Human-readable options for output. */ +static int human_output_opts; + +/* The units to use when printing sizes. */ +static uintmax_t output_block_size; + +/* If nonzero, use the POSIX output format. */ +static int posix_format; + +/* If nonzero, invoke the `sync' system call before getting any usage data. + Using this option can make df very slow, especially with many or very + busy disks. Note that this may make a difference on some systems -- + SunOs4.1.3, for one. It is *not* necessary on Linux. */ +static int require_sync = 0; + +/* Nonzero if errors have occurred. */ +static int exit_status; + +/* A filesystem type to display. */ + +struct fs_type_list +{ + char *fs_name; + struct fs_type_list *fs_next; +}; + +/* Linked list of filesystem types to display. + If `fs_select_list' is NULL, list all types. + This table is generated dynamically from command-line options, + rather than hardcoding into the program what it thinks are the + valid filesystem types; let the user specify any filesystem type + they want to, and if there are any filesystems of that type, they + will be shown. + + Some filesystem types: + 4.2 4.3 ufs nfs swap ignore io vm efs dbg */ + +static struct fs_type_list *fs_select_list; + +/* Linked list of filesystem types to omit. + If the list is empty, don't exclude any types. */ + +static struct fs_type_list *fs_exclude_list; + +/* Linked list of mounted filesystems. */ +static struct mount_entry *mount_list; + +/* If nonzero, print filesystem type as well. */ +static int print_type; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + SYNC_OPTION = CHAR_MAX + 1, + NO_SYNC_OPTION +}; + +static struct option const long_options[] = +{ + {"all", no_argument, NULL, 'a'}, + {"block-size", required_argument, NULL, 'B'}, + {"inodes", no_argument, NULL, 'i'}, + {"human-readable", no_argument, NULL, 'h'}, + {"si", no_argument, NULL, 'H'}, + {"kilobytes", no_argument, NULL, 'k'}, /* long form is obsolescent */ + {"local", no_argument, NULL, 'l'}, + {"megabytes", no_argument, NULL, 'm'}, /* obsolescent */ + {"portability", no_argument, NULL, 'P'}, + {"print-type", no_argument, NULL, 'T'}, + {"sync", no_argument, NULL, SYNC_OPTION}, + {"no-sync", no_argument, NULL, NO_SYNC_OPTION}, + {"type", required_argument, NULL, 't'}, + {"exclude-type", required_argument, NULL, 'x'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +static void +print_header (void) +{ + char buf[MAX (LONGEST_HUMAN_READABLE + 1, INT_BUFSIZE_BOUND (uintmax_t))]; + + if (print_type) + fputs (_("Filesystem Type"), stdout); + else + fputs (_("Filesystem "), stdout); + + if (inode_format) + printf (_(" Inodes IUsed IFree IUse%%")); + else if (human_output_opts & human_autoscale) + { + if (human_output_opts & human_base_1024) + printf (_(" Size Used Avail Use%%")); + else + printf (_(" Size Used Avail Use%%")); + } + else if (posix_format) + printf (_(" %4s-blocks Used Available Capacity"), + umaxtostr (output_block_size, buf)); + else + { + int opts = (human_suppress_point_zero + | human_autoscale | human_SI + | (human_output_opts + & (human_group_digits | human_base_1024 | human_B))); + + /* Prefer the base that makes the human-readable value more exact, + if there is a difference. */ + + uintmax_t q1000 = output_block_size; + uintmax_t q1024 = output_block_size; + bool divisible_by_1000; + bool divisible_by_1024; + + do + { + divisible_by_1000 = q1000 % 1000 == 0; q1000 /= 1000; + divisible_by_1024 = q1024 % 1024 == 0; q1024 /= 1024; + } + while (divisible_by_1000 & divisible_by_1024); + + if (divisible_by_1000 < divisible_by_1024) + opts |= human_base_1024; + if (divisible_by_1024 < divisible_by_1000) + opts &= ~human_base_1024; + if (! (opts & human_base_1024)) + opts |= human_B; + + printf (_(" %4s-blocks Used Available Use%%"), + human_readable (output_block_size, buf, opts, 1, 1)); + } + + printf (_(" Mounted on\n")); +} + +/* If FSTYPE is a type of filesystem that should be listed, + return nonzero, else zero. */ + +static int +selected_fstype (const char *fstype) +{ + const struct fs_type_list *fsp; + + if (fs_select_list == NULL || fstype == NULL) + return 1; + for (fsp = fs_select_list; fsp; fsp = fsp->fs_next) + if (STREQ (fstype, fsp->fs_name)) + return 1; + return 0; +} + +/* If FSTYPE is a type of filesystem that should be omitted, + return nonzero, else zero. */ + +static int +excluded_fstype (const char *fstype) +{ + const struct fs_type_list *fsp; + + if (fs_exclude_list == NULL || fstype == NULL) + return 0; + for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next) + if (STREQ (fstype, fsp->fs_name)) + return 1; + return 0; +} + +/* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS), + except: + + - Return "-" if N is -1, + - If NEGATIVE is 1 then N represents a negative number, + expressed in two's complement. */ + +static char const * +df_readable (int negative, uintmax_t n, char *buf, + uintmax_t input_units, uintmax_t output_units) +{ + if (n == -1) + return "-"; + else + { + char *p = human_readable (negative ? -n : n, buf + negative, + human_output_opts, input_units, output_units); + if (negative) + *--p = '-'; + return p; + } +} + +/* Display a space listing for the disk device with absolute path DISK. + If MOUNT_POINT is non-NULL, it is the path of the root of the + filesystem on DISK. + If FSTYPE is non-NULL, it is the type of the filesystem on DISK. + If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may + not be able to produce statistics in this case. + ME_DUMMY and ME_REMOTE are the mount entry flags. */ + +static void +show_dev (const char *disk, const char *mount_point, const char *fstype, + int me_dummy, int me_remote) +{ + struct fs_usage fsu; + const char *stat_file; + char buf[3][LONGEST_HUMAN_READABLE + 2]; + int width; + int use_width; + uintmax_t input_units; + uintmax_t output_units; + uintmax_t total; + uintmax_t available; + int negate_available; + uintmax_t available_to_root; + uintmax_t used; + int negate_used; + double pct = -1; + + if (me_remote && show_local_fs) + return; + + if (me_dummy && show_all_fs == 0 && !show_listed_fs) + return; + + if (!selected_fstype (fstype) || excluded_fstype (fstype)) + return; + + /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this + program reports on the filesystem that the special file is on. + It would be better to report on the unmounted filesystem, + but statfs doesn't do that on most systems. */ + stat_file = mount_point ? mount_point : disk; + + if (get_fs_usage (stat_file, disk, &fsu)) + { + error (0, errno, "%s", quote (stat_file)); + exit_status = 1; + return; + } + + if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs) + return; + + if (! disk) + disk = "-"; /* unknown */ + if (! fstype) + fstype = "-"; /* unknown */ + + /* df.c reserved 5 positions for fstype, + but that does not suffice for type iso9660 */ + if (print_type) + { + int disk_name_len = (int) strlen (disk); + int fstype_len = (int) strlen (fstype); + if (disk_name_len + fstype_len + 2 < 20) + printf ("%s%*s ", disk, 18 - disk_name_len, fstype); + else if (!posix_format) + printf ("%s\n%18s ", disk, fstype); + else + printf ("%s %s", disk, fstype); + } + else + { + if ((int) strlen (disk) > 20 && !posix_format) + printf ("%s\n%20s", disk, ""); + else + printf ("%-20s", disk); + } + + if (inode_format) + { + width = 7; + use_width = 5; + input_units = output_units = 1; + total = fsu.fsu_files; + available = fsu.fsu_ffree; + negate_available = 0; + available_to_root = available; + } + else + { + width = (human_output_opts & human_autoscale + ? 5 + ! (human_output_opts & human_base_1024) + : 9); + use_width = ((posix_format + && ! (human_output_opts & human_autoscale)) + ? 8 : 4); + input_units = fsu.fsu_blocksize; + output_units = output_block_size; + total = fsu.fsu_blocks; + available = fsu.fsu_bavail; + negate_available = fsu.fsu_bavail_top_bit_set; + available_to_root = fsu.fsu_bfree; + } + + used = -1; + negate_used = 0; + if (total != -1 && available_to_root != -1) + { + used = total - available_to_root; + if (total < available_to_root) + { + negate_used = 1; + used = - used; + } + } + + printf (" %*s %*s %*s ", + width, df_readable (0, total, + buf[0], input_units, output_units), + width, df_readable (negate_used, used, + buf[1], input_units, output_units), + width, df_readable (negate_available, available, + buf[2], input_units, output_units)); + + if (used == -1 || available == -1) + ; + else if (!negate_used + && used <= TYPE_MAXIMUM (uintmax_t) / 100 + && used + available != 0 + && (used + available < used) == negate_available) + { + uintmax_t u100 = used * 100; + uintmax_t nonroot_total = used + available; + pct = u100 / nonroot_total + (u100 % nonroot_total != 0); + } + else + { + /* The calculation cannot be done easily with integer + arithmetic. Fall back on floating point. This can suffer + from minor rounding errors, but doing it exactly requires + multiple precision arithmetic, and it's not worth the + aggravation. */ + double u = negate_used ? - (double) - used : used; + double a = negate_available ? - (double) - available : available; + double nonroot_total = u + a; + if (nonroot_total) + { + double ipct; + pct = u * 100 / nonroot_total; + ipct = (long) pct; + + /* Like `pct = ceil (dpct);', but avoid ceil so that + the math library needn't be linked. */ + if (ipct - 1 < pct && pct <= ipct + 1) + pct = ipct + (ipct < pct); + } + } + + if (0 <= pct) + printf ("%*.0f%%", use_width - 1, pct); + else + printf ("%*s", use_width, "- "); + + if (mount_point) + { +#ifdef HIDE_AUTOMOUNT_PREFIX + /* Don't print the first directory name in MOUNT_POINT if it's an + artifact of an automounter. This is a bit too aggressive to be + the default. */ + if (strncmp ("/auto/", mount_point, 6) == 0) + mount_point += 5; + else if (strncmp ("/tmp_mnt/", mount_point, 9) == 0) + mount_point += 8; +#endif + printf (" %s", mount_point); + } + putchar ('\n'); +} + +/* Return the root mountpoint of the filesystem on which FILE exists, in + malloced storage. FILE_STAT should be the result of stating FILE. */ +static char * +find_mount_point (const char *file, const struct stat *file_stat) +{ + struct saved_cwd cwd; + struct stat last_stat; + char *mp = 0; /* The malloced mount point path. */ + + if (save_cwd (&cwd)) + return NULL; + + if (S_ISDIR (file_stat->st_mode)) + /* FILE is a directory, so just chdir there directly. */ + { + last_stat = *file_stat; + if (chdir (file) < 0) + return NULL; + } + else + /* FILE is some other kind of file, we need to use its directory. */ + { + char *dir = dir_name (file); + int rv = chdir (dir); + free (dir); + + if (rv < 0) + return NULL; + + if (stat (".", &last_stat) < 0) + goto done; + } + + /* Now walk up FILE's parents until we find another filesystem or /, + chdiring as we go. LAST_STAT holds stat information for the last place + we visited. */ + for (;;) + { + struct stat st; + if (stat ("..", &st) < 0) + goto done; + if (st.st_dev != last_stat.st_dev || st.st_ino == last_stat.st_ino) + /* cwd is the mount point. */ + break; + if (chdir ("..") < 0) + goto done; + last_stat = st; + } + + /* Finally reached a mount point, see what it's called. */ + mp = xgetcwd (); + +done: + /* Restore the original cwd. */ + { + int save_errno = errno; + if (restore_cwd (&cwd)) + error (EXIT_FAILURE, errno, + _("failed to return to initial working directory")); + free_cwd (&cwd); + errno = save_errno; + } + + return mp; +} + +/* If DISK corresponds to a mount point, show its usage + and return nonzero. Otherwise, return zero. + STATP must be the result of `stat (DISK, STATP)'. */ +static int +show_disk (const char *disk, const struct stat *statp) +{ + struct mount_entry *me; + + for (me = mount_list; me; me = me->me_next) + if (STREQ (disk, me->me_devname)) + { + show_dev (me->me_devname, me->me_mountdir, me->me_type, + me->me_dummy, me->me_remote); + return 1; + } + + return 0; +} + +/* Figure out which device file or directory POINT is mounted on + and show its disk usage. + STATP must be the result of `stat (POINT, STATP)'. */ +static void +show_point (const char *point, const struct stat *statp) +{ + struct stat disk_stats; + struct mount_entry *me; + struct mount_entry *matching_dummy = NULL; + + /* If POINT is an absolute path name, see if we can find the + mount point without performing any extra stat calls at all. */ + if (*point == '/') + { + for (me = mount_list; me; me = me->me_next) + { + if (STREQ (me->me_mountdir, point) && !STREQ (me->me_type, "lofs")) + { + /* Prefer non-dummy entries. */ + if (! me->me_dummy) + goto show_me; + matching_dummy = me; + } + } + + if (matching_dummy) + goto show_matching_dummy; + } + + /* Calculate the real absolute path for POINT, and use that to find + the mount point. This avoids statting unavailable mount points, + which can hang df. */ + { + char *resolved = canonicalize_file_name (point); + ssize_t resolved_len = resolved ? strlen (resolved) : -1; + struct mount_entry *best_match = NULL; + + if (1 <= resolved_len && resolved[0] == '/') + { + size_t best_match_len = 0; + + for (me = mount_list; me; me = me->me_next) + if (! me->me_dummy) + { + size_t len = strlen (me->me_mountdir); + if (best_match_len < len && len <= resolved_len + && (len == 1 /* root file system */ + || ((len == resolved_len || resolved[len] == '/') + && strncmp (me->me_mountdir, resolved, len) == 0))) + { + best_match = me; + best_match_len = len; + } + } + } + + if (resolved) + free (resolved); + + if (best_match && !STREQ (best_match->me_type, "lofs") + && stat (best_match->me_mountdir, &disk_stats) == 0 + && disk_stats.st_dev == statp->st_dev) + { + me = best_match; + goto show_me; + } + } + + for (me = mount_list; me; me = me->me_next) + { + if (me->me_dev == (dev_t) -1) + { + if (stat (me->me_mountdir, &disk_stats) == 0) + me->me_dev = disk_stats.st_dev; + else + { + error (0, errno, "%s", quote (me->me_mountdir)); + exit_status = 1; + /* So we won't try and fail repeatedly. */ + me->me_dev = (dev_t) -2; + } + } + + if (statp->st_dev == me->me_dev) + { + /* Skip bogus mtab entries. */ + if (stat (me->me_mountdir, &disk_stats) != 0 + || disk_stats.st_dev != me->me_dev) + { + me->me_dev = (dev_t) -2; + continue; + } + + /* Prefer non-dummy entries. */ + if (! me->me_dummy) + goto show_me; + matching_dummy = me; + } + } + + if (matching_dummy) + goto show_matching_dummy; + + /* We couldn't find the mount entry corresponding to POINT. Go ahead and + print as much info as we can; methods that require the device to be + present will fail at a later point. */ + { + /* Find the actual mount point. */ + char *mp = find_mount_point (point, statp); + if (mp) + { + show_dev (0, mp, 0, 0, 0); + free (mp); + } + else + error (0, errno, "%s", quote (point)); + } + + return; + + show_matching_dummy: + me = matching_dummy; + show_me: + show_dev (me->me_devname, me->me_mountdir, me->me_type, me->me_dummy, + me->me_remote); +} + +/* Determine what kind of node PATH is and show the disk usage + for it. STATP is the results of `stat' on PATH. */ + +static void +show_entry (const char *path, const struct stat *statp) +{ + if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode)) + && show_disk (path, statp)) + return; + + show_point (path, statp); +} + +/* Show all mounted filesystems, except perhaps those that are of + an unselected type or are empty. */ + +static void +show_all_entries (void) +{ + struct mount_entry *me; + + for (me = mount_list; me; me = me->me_next) + show_dev (me->me_devname, me->me_mountdir, me->me_type, + me->me_dummy, me->me_remote); +} + +/* Add FSTYPE to the list of filesystem types to display. */ + +static void +add_fs_type (const char *fstype) +{ + struct fs_type_list *fsp; + + fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list)); + fsp->fs_name = (char *) fstype; + fsp->fs_next = fs_select_list; + fs_select_list = fsp; +} + +/* Add FSTYPE to the list of filesystem types to be omitted. */ + +static void +add_excluded_fs_type (const char *fstype) +{ + struct fs_type_list *fsp; + + fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list)); + fsp->fs_name = (char *) fstype; + fsp->fs_next = fs_exclude_list; + fs_exclude_list = fsp; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); + fputs (_("\ +Show information about the filesystem on which each FILE resides,\n\ +or all filesystems by default.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -a, --all include filesystems having 0 blocks\n\ + -B, --block-size=SIZE use SIZE-byte blocks\n\ + -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\ + -H, --si likewise, but use powers of 1000 not 1024\n\ +"), stdout); + fputs (_("\ + -i, --inodes list inode information instead of block usage\n\ + -k like --block-size=1K\n\ + -l, --local limit listing to local filesystems\n\ + --no-sync do not invoke sync before getting usage info (default)\n\ +"), stdout); + fputs (_("\ + -P, --portability use the POSIX output format\n\ + --sync invoke sync before getting usage info\n\ + -t, --type=TYPE limit listing to filesystems of type TYPE\n\ + -T, --print-type print filesystem type\n\ + -x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\ + -v (ignored)\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\n\ +SIZE may be (or may be an integer optionally followed by) one of following:\n\ +kB 1000, K 1024, MB 1,000,000, M 1,048,576, and so on for G, T, P, E, Z, Y.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int c; + struct stat *stats IF_LINT (= 0); + int n_valid_args = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + fs_select_list = NULL; + fs_exclude_list = NULL; + inode_format = 0; + show_all_fs = 0; + show_listed_fs = 0; + + human_output_opts = human_options (getenv ("DF_BLOCK_SIZE"), false, + &output_block_size); + + print_type = 0; + posix_format = 0; + exit_status = 0; + + while ((c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options, NULL)) + != -1) + { + switch (c) + { + case 0: /* Long option. */ + break; + case 'a': + show_all_fs = 1; + break; + case 'B': + human_output_opts = human_options (optarg, true, &output_block_size); + break; + case 'i': + inode_format = 1; + break; + case 'h': + human_output_opts = human_autoscale | human_SI | human_base_1024; + output_block_size = 1; + break; + case 'H': + human_output_opts = human_autoscale | human_SI; + output_block_size = 1; + break; + case 'k': + human_output_opts = 0; + output_block_size = 1024; + break; + case 'l': + show_local_fs = 1; + break; + case 'm': /* obsolescent */ + human_output_opts = 0; + output_block_size = 1024 * 1024; + break; + case 'T': + print_type = 1; + break; + case 'P': + posix_format = 1; + break; + case SYNC_OPTION: + require_sync = 1; + break; + case NO_SYNC_OPTION: + require_sync = 0; + break; + + case 'F': + /* Accept -F as a synonym for -t for compatibility with Solaris. */ + case 't': + add_fs_type (optarg); + break; + + case 'v': /* For SysV compatibility. */ + /* ignore */ + break; + case 'x': + add_excluded_fs_type (optarg); + break; + + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + /* Fail if the same file system type was both selected and excluded. */ + { + int match = 0; + struct fs_type_list *fs_incl; + for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next) + { + struct fs_type_list *fs_excl; + for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next) + { + if (STREQ (fs_incl->fs_name, fs_excl->fs_name)) + { + error (0, 0, + _("file system type %s both selected and excluded"), + quote (fs_incl->fs_name)); + match = 1; + break; + } + } + } + if (match) + exit (EXIT_FAILURE); + } + + { + int i; + + /* stat all the given entries to make sure they get automounted, + if necessary, before reading the filesystem table. */ + stats = (struct stat *) + xmalloc ((argc - optind) * sizeof (struct stat)); + for (i = optind; i < argc; ++i) + { + if (stat (argv[i], &stats[i - optind])) + { + error (0, errno, "%s", quote (argv[i])); + exit_status = 1; + argv[i] = NULL; + } + else + { + ++n_valid_args; + } + } + } + + mount_list = + read_filesystem_list ((fs_select_list != NULL + || fs_exclude_list != NULL + || print_type + || show_local_fs)); + + if (mount_list == NULL) + { + /* Couldn't read the table of mounted filesystems. + Fail if df was invoked with no file name arguments; + Otherwise, merely give a warning and proceed. */ + const char *warning = (optind == argc ? "" : _("Warning: ")); + int status = (optind == argc ? 1 : 0); + error (status, errno, + _("%scannot read table of mounted filesystems"), warning); + } + + if (require_sync) + sync (); + + if (optind == argc) + { + print_header (); + show_all_entries (); + } + else + { + int i; + + /* Display explicitly requested empty filesystems. */ + show_listed_fs = 1; + + if (n_valid_args > 0) + print_header (); + + for (i = optind; i < argc; ++i) + if (argv[i]) + show_entry (argv[i], &stats[i - optind]); + } + + exit (exit_status); +} diff --git a/src/apps/bin/coreutils-5.0/src/dircolors.c b/src/apps/bin/coreutils-5.0/src/dircolors.c new file mode 100644 index 0000000000..73362e8645 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/dircolors.c @@ -0,0 +1,542 @@ +/* dircolors - output commands to set the LS_COLOR environment variable + Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002 H. Peter Anvin + Copyright (C) 1996-2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "system.h" +#include "dircolors.h" +#include "dirname.h" +#include "error.h" +#include "getline.h" +#include "obstack.h" +#include "quote.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "dircolors" + +#define AUTHORS "H. Peter Anvin" + +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free + +enum Shell_syntax +{ + SHELL_SYNTAX_BOURNE, + SHELL_SYNTAX_C, + SHELL_SYNTAX_UNKNOWN +}; + +#define APPEND_CHAR(C) obstack_1grow (&lsc_obstack, C) +#define APPEND_TWO_CHAR_STRING(S) \ + do \ + { \ + APPEND_CHAR (S[0]); \ + APPEND_CHAR (S[1]); \ + } \ + while (0) + +/* Accumulate in this obstack the value for the LS_COLORS environment + variable. */ +static struct obstack lsc_obstack; + +/* Nonzero if the input file was the standard input. */ +static int have_read_stdin; + +/* FIXME: associate with ls_codes? */ +static const char *const slack_codes[] = +{ + "NORMAL", "NORM", "FILE", "DIR", "LNK", "LINK", + "SYMLINK", "ORPHAN", "MISSING", "FIFO", "PIPE", "SOCK", "BLK", "BLOCK", + "CHR", "CHAR", "DOOR", "EXEC", "LEFT", "LEFTCODE", "RIGHT", "RIGHTCODE", + "END", "ENDCODE", NULL +}; + +static const char *const ls_codes[] = +{ + "no", "no", "fi", "di", "ln", "ln", "ln", "or", "mi", "pi", "pi", + "so", "bd", "bd", "cd", "cd", "do", "ex", "lc", "lc", "rc", "rc", "ec", "ec" +}; + +static struct option const long_options[] = + { + {"bourne-shell", no_argument, NULL, 'b'}, + {"sh", no_argument, NULL, 'b'}, + {"csh", no_argument, NULL, 'c'}, + {"c-shell", no_argument, NULL, 'c'}, + {"print-database", no_argument, NULL, 'p'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} + }; + +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [FILE]\n"), program_name); + fputs (_("\ +Output commands to set the LS_COLORS environment variable.\n\ +\n\ +Determine format of output:\n\ + -b, --sh, --bourne-shell output Bourne shell code to set LS_COLORS\n\ + -c, --csh, --c-shell output C shell code to set LS_COLORS\n\ + -p, --print-database output defaults\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +If FILE is specified, read it to determine which colors to use for which\n\ +file types and extensions. Otherwise, a precompiled database is used.\n\ +For details on the format of these files, run `dircolors --print-database'.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +static void * +xstrndup (const char *s, size_t n) +{ + char *new = strndup (s, n); + if (new == NULL) + xalloc_die (); + return new; +} + +/* If the SHELL environment variable is set to `csh' or `tcsh,' + assume C shell. Else Bourne shell. */ + +static enum Shell_syntax +guess_shell_syntax (void) +{ + char *shell; + + shell = getenv ("SHELL"); + if (shell == NULL || *shell == '\0') + return SHELL_SYNTAX_UNKNOWN; + + shell = base_name (shell); + + if (STREQ (shell, "csh") || STREQ (shell, "tcsh")) + return SHELL_SYNTAX_C; + + return SHELL_SYNTAX_BOURNE; +} + +static void +parse_line (unsigned char const *line, char **keyword, char **arg) +{ + unsigned char const *p; + unsigned char const *keyword_start; + unsigned char const *arg_start; + + *keyword = NULL; + *arg = NULL; + + for (p = line; ISSPACE (*p); ++p) + ; + + /* Ignore blank lines and shell-style comments. */ + if (*p == '\0' || *p == '#') + return; + + keyword_start = p; + + while (!ISSPACE (*p) && *p != '\0') + { + ++p; + } + + *keyword = xstrndup ((const char *) keyword_start, p - keyword_start); + if (*p == '\0') + return; + + do + { + ++p; + } + while (ISSPACE (*p)); + + if (*p == '\0' || *p == '#') + return; + + arg_start = p; + + while (*p != '\0' && *p != '#') + ++p; + + for (--p; ISSPACE (*p); --p) + { + /* empty */ + } + ++p; + + *arg = xstrndup ((const char *) arg_start, p - arg_start); +} + +/* FIXME: Write a string to standard out, while watching for "dangerous" + sequences like unescaped : and = characters. */ + +static void +append_quoted (const char *str) +{ + int need_backslash = 1; + + while (*str != '\0') + { + switch (*str) + { + case '\\': + case '^': + need_backslash = !need_backslash; + break; + + case ':': + case '=': + if (need_backslash) + APPEND_CHAR ('\\'); + /* Fall through */ + + default: + need_backslash = 1; + break; + } + + APPEND_CHAR (*str); + ++str; + } +} + +/* Read the file open on FP (with name FILENAME). First, look for a + `TERM name' directive where name matches the current terminal type. + Once found, translate and accumulate the associated directives onto + the global obstack LSC_OBSTACK. Give a diagnostic and return nonzero + upon failure (unrecognized keyword is the only way to fail here). + Return zero otherwise. */ + +static int +dc_parse_stream (FILE *fp, const char *filename) +{ + size_t line_number = 0; + char *line = NULL; + size_t line_chars_allocated = 0; + int state; + char *term; + int err = 0; + + /* State for the parser. */ + enum states { ST_TERMNO, ST_TERMYES, ST_TERMSURE, ST_GLOBAL }; + + state = ST_GLOBAL; + + /* Get terminal type */ + term = getenv ("TERM"); + if (term == NULL || *term == '\0') + term = "none"; + + while (1) + { + int line_length; + char *keywd, *arg; + int unrecognized; + + ++line_number; + + if (fp) + { + line_length = getline (&line, &line_chars_allocated, fp); + if (line_length <= 0) + { + if (line) + free (line); + break; + } + } + else + { + line = (char *) (G_line[line_number - 1]); + line_length = G_line_length[line_number - 1]; + if (line_number > G_N_LINES) + break; + } + + parse_line ((unsigned char *) line, &keywd, &arg); + + if (keywd == NULL) + continue; + + if (arg == NULL) + { + error (0, 0, _("%s:%lu: invalid line; missing second token"), + filename, (long unsigned) line_number); + err = 1; + free (keywd); + continue; + } + + unrecognized = 0; + if (strcasecmp (keywd, "TERM") == 0) + { + if (STREQ (arg, term)) + state = ST_TERMSURE; + else if (state != ST_TERMSURE) + state = ST_TERMNO; + } + else + { + if (state == ST_TERMSURE) + state = ST_TERMYES; /* Another TERM can cancel */ + + if (state != ST_TERMNO) + { + if (keywd[0] == '.') + { + APPEND_CHAR ('*'); + append_quoted (keywd); + APPEND_CHAR ('='); + append_quoted (arg); + APPEND_CHAR (':'); + } + else if (keywd[0] == '*') + { + append_quoted (keywd); + APPEND_CHAR ('='); + append_quoted (arg); + APPEND_CHAR (':'); + } + else if (strcasecmp (keywd, "OPTIONS") == 0 + || strcasecmp (keywd, "COLOR") == 0 + || strcasecmp (keywd, "EIGHTBIT") == 0) + { + /* Ignore. */ + } + else + { + int i; + + for (i = 0; slack_codes[i] != NULL; ++i) + if (strcasecmp (keywd, slack_codes[i]) == 0) + break; + + if (slack_codes[i] != NULL) + { + APPEND_TWO_CHAR_STRING (ls_codes[i]); + APPEND_CHAR ('='); + append_quoted (arg); + APPEND_CHAR (':'); + } + else + { + unrecognized = 1; + } + } + } + else + { + unrecognized = 1; + } + } + + if (unrecognized && (state == ST_TERMSURE || state == ST_TERMYES)) + { + error (0, 0, _("%s:%lu: unrecognized keyword %s"), + (filename ? quote (filename) : _("")), + (long unsigned) line_number, keywd); + err = 1; + } + + free (keywd); + if (arg) + free (arg); + } + + return err; +} + +static int +dc_parse_file (const char *filename) +{ + FILE *fp; + int err; + + if (STREQ (filename, "-")) + { + have_read_stdin = 1; + fp = stdin; + } + else + { + /* OPENOPTS is a macro. It varies with the system. + Some systems distinguish between internal and + external text representations. */ + + fp = fopen (filename, "r"); + if (fp == NULL) + { + error (0, errno, "%s", quote (filename)); + return 1; + } + } + + err = dc_parse_stream (fp, filename); + + if (fp != stdin && fclose (fp) == EOF) + { + error (0, errno, "%s", quote (filename)); + return 1; + } + + return err; +} + +int +main (int argc, char **argv) +{ + int err = 0; + int optc; + enum Shell_syntax syntax = SHELL_SYNTAX_UNKNOWN; + int print_database = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + while ((optc = getopt_long (argc, argv, "bcp", long_options, NULL)) != -1) + switch (optc) + { + case 'b': /* Bourne shell syntax. */ + syntax = SHELL_SYNTAX_BOURNE; + break; + + case 'c': /* C shell syntax. */ + syntax = SHELL_SYNTAX_C; + break; + + case 'p': + print_database = 1; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + + argc -= optind; + argv += optind; + + /* It doesn't make sense to use --print with either of + --bourne or --c-shell. */ + if (print_database && syntax != SHELL_SYNTAX_UNKNOWN) + { + error (0, 0, + _("the options to output dircolors' internal database and\n\ +to select a shell syntax are mutually exclusive")); + usage (EXIT_FAILURE); + } + + if (print_database && argc > 0) + { + error (0, 0, + _("no FILE arguments may be used with the option to output\n\ +dircolors' internal database")); + usage (EXIT_FAILURE); + } + + if (!print_database && argc > 1) + { + error (0, 0, _("too many arguments")); + usage (EXIT_FAILURE); + } + + if (print_database) + { + int i; + for (i = 0; i < G_N_LINES; i++) + { + fwrite (G_line[i], 1, G_line_length[i], stdout); + fputc ('\n', stdout); + } + } + else + { + /* If shell syntax was not explicitly specified, try to guess it. */ + if (syntax == SHELL_SYNTAX_UNKNOWN) + { + syntax = guess_shell_syntax (); + if (syntax == SHELL_SYNTAX_UNKNOWN) + { + error (EXIT_FAILURE, 0, + _("no SHELL environment variable, and no shell type option given")); + } + } + + obstack_init (&lsc_obstack); + if (argc == 0) + err = dc_parse_stream (NULL, NULL); + else + err = dc_parse_file (argv[0]); + + if (!err) + { + size_t len = obstack_object_size (&lsc_obstack); + char *s = obstack_finish (&lsc_obstack); + const char *prefix; + const char *suffix; + + if (syntax == SHELL_SYNTAX_BOURNE) + { + prefix = "LS_COLORS='"; + suffix = "';\nexport LS_COLORS\n"; + } + else + { + prefix = "setenv LS_COLORS '"; + suffix = "'\n"; + } + fputs (prefix, stdout); + fwrite (s, 1, len, stdout); + fputs (suffix, stdout); + } + } + + + if (have_read_stdin && fclose (stdin) == EOF) + error (EXIT_FAILURE, errno, _("standard input")); + + exit (err == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/dircolors.h b/src/apps/bin/coreutils-5.0/src/dircolors.h new file mode 100644 index 0000000000..d8445979e4 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/dircolors.h @@ -0,0 +1,121 @@ +#define G_N_LINES 106 + +const size_t G_line_length[G_N_LINES] = +{ + 65, 72, 0, 59, 61, 0, 77, 10, 12, 15, 12, 14, 14, 14, 14, 13, 13, 13, 13, + 13, 13, 11, 10, 16, 17, 9, 11, 13, 10, 10, 0, 73, 64, 18, 64, 19, 72, + 25, 72, 68, 22, 22, 71, 72, 17, 19, 17, 34, 39, 45, 0, 44, 10, 0, 70, + 75, 48, 0, 73, 40, 11, 11, 11, 11, 0, 48, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 0, 15, 10, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 11, 10, 10, 11, 10, 10, 9, 9, 10, 10, 0, 15, 10, 10, 10 +}; + +const char *const G_line[G_N_LINES] = +{ + "# Configuration file for dircolors, a utility to help you set the", + "# LS_COLORS environment variable used by GNU ls with the --color option.", + "", + "# The keywords COLOR, OPTIONS, and EIGHTBIT (honored by the", + "# slackware version of dircolors) are recognized but ignored.", + "", + "# Below, there should be one TERM entry for each termtype that is colorizable", + "TERM linux", + "TERM linux-c", + "TERM mach-color", + "TERM console", + "TERM con132x25", + "TERM con132x30", + "TERM con132x43", + "TERM con132x60", + "TERM con80x25", + "TERM con80x28", + "TERM con80x30", + "TERM con80x43", + "TERM con80x50", + "TERM con80x60", + "TERM dtterm", + "TERM xterm", + "TERM xterm-color", + "TERM xterm-debian", + "TERM rxvt", + "TERM screen", + "TERM screen-w", + "TERM vt100", + "TERM Eterm", + "", + "# Below are the color init strings for the basic file types. A color init", + "# string consists of one or more of the following numeric codes:", + "# Attribute codes:", + "# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed", + "# Text color codes:", + "# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white", + "# Background color codes:", + "# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white", + "NORMAL 00 # global default, although everything should be something.", + "FILE 00 # normal file", + "DIR 01;34 # directory", + "LINK 01;36 # symbolic link. (If you set this to 'target' instead of a", + " # numerical value, the color is as for the file pointed to.)", + "FIFO 40;33 # pipe", + "SOCK 01;35 # socket", + "DOOR 01;35 # door", + "BLK 40;33;01 # block device driver", + "CHR 40;33;01 # character device driver", + "ORPHAN 40;31;01 # symlink to nonexistent file", + "", + "# This is for files with execute permission:", + "EXEC 01;32", + "", + "# List any file extensions like '.gz' or '.tar' that you would like ls", + "# to colorize below. Put the extension, a space, and the color init string.", + "# (and any comments you want to add after a '#')", + "", + "# If you use DOS-style suffixes, you may want to uncomment the following:", + "#.cmd 01;32 # executables (bright green)", + "#.exe 01;32", + "#.com 01;32", + "#.btm 01;32", + "#.bat 01;32", + "", + ".tar 01;31 # archives or compressed (bright red)", + ".tgz 01;31", + ".arj 01;31", + ".taz 01;31", + ".lzh 01;31", + ".zip 01;31", + ".z 01;31", + ".Z 01;31", + ".gz 01;31", + ".bz2 01;31", + ".deb 01;31", + ".rpm 01;31", + ".jar 01;31", + "", + "# image formats", + ".jpg 01;35", + ".jpeg 01;35", + ".gif 01;35", + ".bmp 01;35", + ".pbm 01;35", + ".pgm 01;35", + ".ppm 01;35", + ".tga 01;35", + ".xbm 01;35", + ".xpm 01;35", + ".tif 01;35", + ".tiff 01;35", + ".png 01;35", + ".mpg 01;35", + ".mpeg 01;35", + ".avi 01;35", + ".fli 01;35", + ".gl 01;35", + ".dl 01;35", + ".xcf 01;35", + ".xwd 01;35", + "", + "# audio formats", + ".ogg 01;35", + ".mp3 01;35", + ".wav 01;35" +}; diff --git a/src/apps/bin/coreutils-5.0/src/dircolors.hin b/src/apps/bin/coreutils-5.0/src/dircolors.hin new file mode 100644 index 0000000000..5a2e4a845a --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/dircolors.hin @@ -0,0 +1,106 @@ +# Configuration file for dircolors, a utility to help you set the +# LS_COLORS environment variable used by GNU ls with the --color option. + +# The keywords COLOR, OPTIONS, and EIGHTBIT (honored by the +# slackware version of dircolors) are recognized but ignored. + +# Below, there should be one TERM entry for each termtype that is colorizable +TERM linux +TERM linux-c +TERM mach-color +TERM console +TERM con132x25 +TERM con132x30 +TERM con132x43 +TERM con132x60 +TERM con80x25 +TERM con80x28 +TERM con80x30 +TERM con80x43 +TERM con80x50 +TERM con80x60 +TERM dtterm +TERM xterm +TERM xterm-color +TERM xterm-debian +TERM rxvt +TERM screen +TERM screen-w +TERM vt100 +TERM Eterm + +# Below are the color init strings for the basic file types. A color init +# string consists of one or more of the following numeric codes: +# Attribute codes: +# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed +# Text color codes: +# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white +# Background color codes: +# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white +NORMAL 00 # global default, although everything should be something. +FILE 00 # normal file +DIR 01;34 # directory +LINK 01;36 # symbolic link. (If you set this to 'target' instead of a + # numerical value, the color is as for the file pointed to.) +FIFO 40;33 # pipe +SOCK 01;35 # socket +DOOR 01;35 # door +BLK 40;33;01 # block device driver +CHR 40;33;01 # character device driver +ORPHAN 40;31;01 # symlink to nonexistent file + +# This is for files with execute permission: +EXEC 01;32 + +# List any file extensions like '.gz' or '.tar' that you would like ls +# to colorize below. Put the extension, a space, and the color init string. +# (and any comments you want to add after a '#') + +# If you use DOS-style suffixes, you may want to uncomment the following: +#.cmd 01;32 # executables (bright green) +#.exe 01;32 +#.com 01;32 +#.btm 01;32 +#.bat 01;32 + +.tar 01;31 # archives or compressed (bright red) +.tgz 01;31 +.arj 01;31 +.taz 01;31 +.lzh 01;31 +.zip 01;31 +.z 01;31 +.Z 01;31 +.gz 01;31 +.bz2 01;31 +.deb 01;31 +.rpm 01;31 +.jar 01;31 + +# image formats +.jpg 01;35 +.jpeg 01;35 +.gif 01;35 +.bmp 01;35 +.pbm 01;35 +.pgm 01;35 +.ppm 01;35 +.tga 01;35 +.xbm 01;35 +.xpm 01;35 +.tif 01;35 +.tiff 01;35 +.png 01;35 +.mpg 01;35 +.mpeg 01;35 +.avi 01;35 +.fli 01;35 +.gl 01;35 +.dl 01;35 +.xcf 01;35 +.xwd 01;35 + +# audio formats +.ogg 01;35 +.mp3 01;35 +.wav 01;35 diff --git a/src/apps/bin/coreutils-5.0/src/dirname.c b/src/apps/bin/coreutils-5.0/src/dirname.c new file mode 100644 index 0000000000..e88e6a21c6 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/dirname.c @@ -0,0 +1,107 @@ +/* dirname -- strip filename suffix from pathname + Copyright (C) 1990-1997, 1999-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie and Jim Meyering. */ + +#include +#include +#include + +#include "system.h" +#include "long-options.h" +#include "error.h" +#include "dirname.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "dirname" + +#define AUTHORS N_ ("David MacKenzie and Jim Meyering") + +/* The name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s NAME\n\ + or: %s OPTION\n\ +"), + program_name, program_name); + fputs (_("\ +Print NAME with its trailing /component removed; if NAME contains no /'s,\n\ +output `.' (meaning the current directory).\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + static char const dot = '.'; + char const *result; + size_t len; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + /* The above handles --help and --version. + Since there is no other invocation of getopt, handle `--' here. */ + if (argc > 1 && STREQ (argv[1], "--")) + { + --argc; + ++argv; + } + + if (argc != 2) + { + error (0, 0, argc < 2 ? _("too few arguments") + : _("too many arguments")); + usage (EXIT_FAILURE); + } + + result = argv[1]; + len = dir_len (result); + + if (! len) + { + result = ˙ + len = 1; + } + + fwrite (result, 1, len, stdout); + putchar ('\n'); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/du.c b/src/apps/bin/coreutils-5.0/src/du.c new file mode 100644 index 0000000000..6445f8e8a3 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/du.c @@ -0,0 +1,735 @@ +/* du -- summarize disk usage + Copyright (C) 1988-1991, 1995-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Differences from the Unix du: + * Doesn't simply ignore the names of regular files given as arguments + when -a is given. + + By tege@sics.se, Torbjorn Granlund, + and djm@ai.mit.edu, David MacKenzie. + Variable blocks added by lm@sgi.com and eggert@twinsun.com. + Rewritten to use nftw by Jim Meyering. */ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "dirname.h" /* for strip_trailing_slashes */ +#include "error.h" +#include "exclude.h" +#include "ftw.h" +#include "hash.h" +#include "human.h" +#include "quote.h" +#include "quotearg.h" +#include "same.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "du" + +#define AUTHORS \ + N_ ("Torbjorn Granlund, David MacKenzie, Larry McVoy, Paul Eggert, and Jim Meyering") + +/* Initial size of the hash table. */ +#define INITIAL_TABLE_SIZE 103 + +/* The maximum number of simultaneously open file handles that + may be used by ftw. */ +#define MAX_N_DESCRIPTORS (3 * UTILS_OPEN_MAX / 4) + +/* Hash structure for inode and device numbers. The separate entry + structure makes it easier to rehash "in place". */ + +struct entry +{ + ino_t st_ino; + dev_t st_dev; +}; + +/* A set of dev/ino pairs. */ +static Hash_table *htab; + +/* Name under which this program was invoked. */ +char *program_name; + +/* If nonzero, display counts for all files, not just directories. */ +static int opt_all = 0; + +/* If nonzero, rather than using the disk usage of each file, + use the apparent size (a la stat.st_size). */ +static int apparent_size = 0; + +/* If nonzero, count each hard link of files with multiple links. */ +static int opt_count_all = 0; + +/* If nonzero, print a grand total at the end. */ +static int print_totals = 0; + +/* If nonzero, do not add sizes of subdirectories. */ +static int opt_separate_dirs = 0; + +/* If nonzero, dereference symlinks that are command line arguments. + Implementing this while still using nftw is a little tricky. + For each command line argument that is a symlink-to-directory, + call nftw with "command_line_arg/." and remember to omit the + added `/.' when printing. */ +static int opt_dereference_arguments = 0; + +/* Show the total for each directory (and file if --all) that is at + most MAX_DEPTH levels down from the root of the hierarchy. The root + is at level 0, so `du --max-depth=0' is equivalent to `du -s'. */ +static int max_depth = INT_MAX; + +/* Human-readable options for output. */ +static int human_output_opts; + +/* The units to use when printing sizes. */ +static uintmax_t output_block_size; + +/* File name patterns to exclude. */ +static struct exclude *exclude; + +/* Grand total size of all args, in bytes. */ +static uintmax_t tot_size = 0; + +/* In some cases, we have to append `/.' or just `.' to an argument + (to dereference a symlink). When we do that, we don't want to + expose this artifact when printing file/directory names, so these + variables keep track of the length of the original command line + argument and the length of the suffix we've added, respectively. + ARG_LENGTH == 0 indicates that we haven't added a suffix. + This information is used to omit any such added characters when + printing names. */ +size_t arg_length; +size_t suffix_length; + +/* Nonzero indicates that du should exit with EXIT_FAILURE upon completion. */ +int G_fail; + +#define IS_FTW_DIR_TYPE(Type) \ + ((Type) == FTW_D \ + || (Type) == FTW_DP \ + || (Type) == FTW_DNR) + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + APPARENT_SIZE_OPTION = CHAR_MAX + 1, + EXCLUDE_OPTION, + MAX_DEPTH_OPTION +}; + +static struct option const long_options[] = +{ + {"all", no_argument, NULL, 'a'}, + {"apparent-size", no_argument, NULL, APPARENT_SIZE_OPTION}, + {"block-size", required_argument, 0, 'B'}, + {"bytes", no_argument, NULL, 'b'}, + {"count-links", no_argument, NULL, 'l'}, + {"dereference", no_argument, NULL, 'L'}, + {"dereference-args", no_argument, NULL, 'D'}, + {"exclude", required_argument, 0, EXCLUDE_OPTION}, + {"exclude-from", required_argument, 0, 'X'}, + {"human-readable", no_argument, NULL, 'h'}, + {"si", no_argument, 0, 'H'}, + {"kilobytes", no_argument, NULL, 'k'}, /* long form is obsolescent */ + {"max-depth", required_argument, NULL, MAX_DEPTH_OPTION}, + {"megabytes", no_argument, NULL, 'm'}, /* obsolescent */ + {"one-file-system", no_argument, NULL, 'x'}, + {"separate-dirs", no_argument, NULL, 'S'}, + {"summarize", no_argument, NULL, 's'}, + {"total", no_argument, NULL, 'c'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); + fputs (_("\ +Summarize disk usage of each FILE, recursively for directories.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -a, --all write counts for all files, not just directories\n\ + --apparent-size print apparent sizes, rather than disk usage; although\n\ + the apparent size is usually smaller, it may be\n\ + larger due to holes in (`sparse') files, internal\n\ + fragmentation, indirect blocks, and the like\n\ + -B, --block-size=SIZE use SIZE-byte blocks\n\ + -b, --bytes equivalent to `--apparent-size --block-size=1'\n\ + -c, --total produce a grand total\n\ + -D, --dereference-args dereference FILEs that are symbolic links\n\ +"), stdout); + fputs (_("\ + -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\ + -H, --si likewise, but use powers of 1000 not 1024\n\ + -k like --block-size=1K\n\ + -l, --count-links count sizes many times if hard linked\n\ +"), stdout); + fputs (_("\ + -L, --dereference dereference all symbolic links\n\ + -S, --separate-dirs do not include size of subdirectories\n\ + -s, --summarize display only a total for each argument\n\ +"), stdout); + fputs (_("\ + -x, --one-file-system skip directories on different filesystems\n\ + -X FILE, --exclude-from=FILE Exclude files that match any pattern in FILE.\n\ + --exclude=PATTERN Exclude files that match PATTERN.\n\ + --max-depth=N print the total for a directory (or file, with --all)\n\ + only if it is N or fewer levels below the command\n\ + line argument; --max-depth=0 is the same as\n\ + --summarize\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\n\ +SIZE may be (or may be an integer optionally followed by) one of following:\n\ +kB 1000, K 1024, MB 1,000,000, M 1,048,576, and so on for G, T, P, E, Z, Y.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +static unsigned int +entry_hash (void const *x, unsigned int table_size) +{ + struct entry const *p = x; + + /* Ignoring the device number here should be fine. */ + /* The cast to uintmax_t prevents negative remainders + if st_ino is negative. */ + return (uintmax_t) p->st_ino % table_size; +} + +/* Compare two dev/ino pairs. Return true if they are the same. */ +static bool +entry_compare (void const *x, void const *y) +{ + struct entry const *a = x; + struct entry const *b = y; + return SAME_INODE (*a, *b) ? true : false; +} + +/* Try to insert the INO/DEV pair into the global table, HTAB. + If the pair is successfully inserted, return zero. + Upon failed memory allocation exit nonzero. + If the pair is already in the table, return nonzero. */ +static int +hash_ins (ino_t ino, dev_t dev) +{ + struct entry *ent; + struct entry *ent_from_table; + + ent = (struct entry *) xmalloc (sizeof *ent); + ent->st_ino = ino; + ent->st_dev = dev; + + ent_from_table = hash_insert (htab, ent); + if (ent_from_table == NULL) + { + /* Insertion failed due to lack of memory. */ + xalloc_die (); + } + + if (ent_from_table == ent) + { + /* Insertion succeeded. */ + return 0; + } + + /* That pair is already in the table, so ENT was not inserted. Free it. */ + free (ent); + + return 1; +} + +/* Initialize the hash table. */ +static void +hash_init (void) +{ + htab = hash_initialize (INITIAL_TABLE_SIZE, NULL, + entry_hash, entry_compare, free); + if (htab == NULL) + xalloc_die (); +} + +/* Print N_BYTES. Convert it to a readable value before printing. */ + +static void +print_only_size (uintmax_t n_bytes) +{ + char buf[LONGEST_HUMAN_READABLE + 1]; + fputs (human_readable (n_bytes, buf, human_output_opts, + 1, output_block_size), stdout); +} + +/* Print N_BYTES followed by STRING on a line. + Convert N_BYTES to a readable value before printing. */ + +static void +print_size (uintmax_t n_bytes, const char *string) +{ + print_only_size (n_bytes); + printf ("\t%s\n", string); + fflush (stdout); +} + +/* This function is called once for every file system object that nftw + encounters. nftw does a depth-first traversal. This function knows + that and accumulates per-directory totals based on changes in + the depth of the current entry. */ + +static int +process_file (const char *file, const struct stat *sb, int file_type, + struct FTW *info) +{ + uintmax_t size; + uintmax_t size_to_print; + static int first_call = 1; + static size_t prev_level; + static size_t n_alloc; + static uintmax_t *sum_ent; + static uintmax_t *sum_subdir; + int print = 1; + + /* Always define info->skip before returning. */ + info->skip = excluded_filename (exclude, file + info->base); + + switch (file_type) + { + case FTW_NS: + error (0, errno, _("cannot access %s"), quote (file)); + G_fail = 1; + return 0; + + case FTW_DCHP: + error (0, errno, _("cannot change to parent of directory %s"), + quote (file)); + G_fail = 1; + return 0; + + case FTW_DCH: + /* Don't return just yet, since although nftw couldn't chdir into the + directory, it was able to stat it, so we do have a size. */ + error (0, errno, _("cannot change to directory %s"), quote (file)); + G_fail = 1; + break; + + case FTW_DNR: + /* Don't return just yet, since although nftw couldn't read the + directory, it was able to stat it, so we do have a size. */ + error (0, errno, _("cannot read directory %s"), quote (file)); + G_fail = 1; + break; + + default: + break; + } + + /* If this is the first (pre-order) encounter with a directory, + return right away. */ + if (file_type == FTW_DPRE) + return 0; + + /* If the file is being excluded or if it has already been counted + via a hard link, then don't let it contribute to the sums. */ + if (info->skip + || (!opt_count_all + && 1 < sb->st_nlink + && hash_ins (sb->st_ino, sb->st_dev))) + { + /* Note that we must not simply return here. + We still have to update prev_level and maybe propagate + some sums up the hierarchy. */ + size = 0; + print = 0; + } + else + { + size = (apparent_size + ? sb->st_size + : ST_NBLOCKS (*sb) * ST_NBLOCKSIZE); + } + + if (first_call) + { + n_alloc = info->level + 10; + sum_ent = XCALLOC (uintmax_t, n_alloc); + sum_subdir = XCALLOC (uintmax_t, n_alloc); + } + else + { + /* FIXME: it's a shame that we need these `size_t' casts to avoid + warnings from gcc about `comparison between signed and unsigned'. + Probably unavoidable, assuming that the members of struct FTW + are of type `int' (historical), since I want variables like + n_alloc and prev_level to have types that make sense. */ + if (n_alloc <= (size_t) info->level) + { + n_alloc = info->level * 2; + sum_ent = XREALLOC (sum_ent, uintmax_t, n_alloc); + sum_subdir = XREALLOC (sum_subdir, uintmax_t, n_alloc); + } + } + + size_to_print = size; + + if (! first_call) + { + if ((size_t) info->level == prev_level) + { + /* This is usually the most common case. Do nothing. */ + } + else if ((size_t) info->level > prev_level) + { + /* Descending the hierarchy. + Clear the accumulators for *all* levels between prev_level + and the current one. The depth may change dramatically, + e.g., from 1 to 10. */ + int i; + for (i = prev_level + 1; i <= info->level; i++) + sum_ent[i] = sum_subdir[i] = 0; + } + else /* info->level < prev_level */ + { + /* Ascending the hierarchy. + nftw processes a directory only after all entries in that + directory have been processed. When the depth decreases, + propagate sums from the children (prev_level) to the parent. + Here, the current level is always one smaller than the + previous one. */ + assert ((size_t) info->level == prev_level - 1); + size_to_print += sum_ent[prev_level]; + if (!opt_separate_dirs) + size_to_print += sum_subdir[prev_level]; + sum_subdir[info->level] += (sum_ent[prev_level] + + sum_subdir[prev_level]); + } + } + + prev_level = info->level; + first_call = 0; + + /* Let the size of a directory entry contribute to the total for the + containing directory, unless --separate-dirs (-S) is specified. */ + if ( ! (opt_separate_dirs && IS_FTW_DIR_TYPE (file_type))) + sum_ent[info->level] += size; + + /* Even if this directory is unreadable or we can't chdir into it, + do let its size contribute to the total, ... */ + tot_size += size; + + /* ... but don't print out a total for it, since without the size(s) + of any potential entries, it could be very misleading. */ + if (file_type == FTW_DNR || file_type == FTW_DCH) + return 0; + + /* If we're not counting an entry, e.g., because it's a hard link + to a file we've already counted (and --count-links), then don't + print a line for it. */ + if (!print) + return 0; + + /* FIXME: This looks suspiciously like it could be simplified. */ + if ((IS_FTW_DIR_TYPE (file_type) && + (info->level <= max_depth || info->level == 0)) + || ((opt_all && info->level <= max_depth) || info->level == 0)) + { + print_only_size (size_to_print); + fputc ('\t', stdout); + if (arg_length) + { + /* Print the file name, but without the `.' or `/.' + directory suffix that we may have added in main. */ + /* Print everything before the part we appended. */ + fwrite (file, arg_length, 1, stdout); + /* Print everything after what we appended. */ + fputs (file + arg_length + suffix_length + + (file[arg_length + suffix_length] == '/'), stdout); + } + else + { + fputs (file, stdout); + } + fputc ('\n', stdout); + fflush (stdout); + } + + return 0; +} + +static int +is_symlink_to_dir (char const *file) +{ + char *f; + struct stat sb; + + ASSIGN_STRDUPA (f, file); + strip_trailing_slashes (f); + return (lstat (f, &sb) == 0 && S_ISLNK (sb.st_mode) + && stat (f, &sb) == 0 && S_ISDIR (sb.st_mode)); +} + +/* Recursively print the sizes of the directories (and, if selected, files) + named in FILES, the last entry of which is NULL. + FTW_FLAGS controls how nftw works. + Return nonzero upon error. */ + +static int +du_files (char **files, int ftw_flags) +{ + int fail = 0; + int i; + for (i = 0; files[i]; i++) + { + char *file = files[i]; + char *orig = file; + int err; + arg_length = 0; + + if (!print_totals) + hash_clear (htab); + + /* When dereferencing only command line arguments, we're using + nftw's FTW_PHYS flag, so a symlink-to-directory specified on + the command line wouldn't normally be dereferenced. To work + around that, we incur the overhead of appending `/.' (or `.') + now, and later removing it each time we output the name of + a derived file or directory name. */ + if (opt_dereference_arguments && is_symlink_to_dir (file)) + { + size_t len = strlen (file); + /* Append `/.', but if there's already a trailing slash, + append only the `.'. */ + char const *suffix = (file[len - 1] == '/' ? "." : "/."); + char *new_file; + suffix_length = strlen (suffix); + new_file = xmalloc (len + suffix_length + 1); + memcpy (mempcpy (new_file, file, len), suffix, suffix_length + 1); + arg_length = len; + file = new_file; + } + + err = nftw (file, process_file, MAX_N_DESCRIPTORS, ftw_flags); + if (err) + error (0, errno, "%s", quote (orig)); + fail |= err; + + if (arg_length) + free (file); + } + + if (print_totals) + print_size (tot_size, _("total")); + + return fail; +} + +int +main (int argc, char **argv) +{ + int c; + char *cwd_only[2]; + int max_depth_specified = 0; + char **files; + int fail; + + /* Bit flags that control how nftw works. */ + int ftw_flags = FTW_DEPTH | FTW_PHYS | FTW_CHDIR; + + /* If nonzero, display only a total for each argument. */ + int opt_summarize_only = 0; + + cwd_only[0] = "."; + cwd_only[1] = NULL; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + exclude = new_exclude (); + + human_output_opts = human_options (getenv ("DU_BLOCK_SIZE"), false, + &output_block_size); + + fail = 0; + while ((c = getopt_long (argc, argv, "abchHklmsxB:DLSX:", long_options, NULL)) + != -1) + { + long int tmp_long; + switch (c) + { + case 0: /* Long option. */ + break; + + case 'a': + opt_all = 1; + break; + + case APPARENT_SIZE_OPTION: + apparent_size = 1; + break; + + case 'b': + apparent_size = 1; + human_output_opts = 0; + output_block_size = 1; + break; + + case 'c': + print_totals = 1; + break; + + case 'h': + human_output_opts = human_autoscale | human_SI | human_base_1024; + output_block_size = 1; + break; + + case 'H': + human_output_opts = human_autoscale | human_SI; + output_block_size = 1; + break; + + case 'k': + human_output_opts = 0; + output_block_size = 1024; + break; + + case MAX_DEPTH_OPTION: /* --max-depth=N */ + if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) == LONGINT_OK + && 0 <= tmp_long && tmp_long <= INT_MAX) + { + max_depth_specified = 1; + max_depth = (int) tmp_long; + } + else + { + error (0, 0, _("invalid maximum depth %s"), + quote (optarg)); + fail = 1; + } + break; + + case 'm': /* obsolescent */ + human_output_opts = 0; + output_block_size = 1024 * 1024; + break; + + case 'l': + opt_count_all = 1; + break; + + case 's': + opt_summarize_only = 1; + break; + + case 'x': + ftw_flags |= FTW_MOUNT; + break; + + case 'B': + human_output_opts = human_options (optarg, true, &output_block_size); + break; + + case 'D': + opt_dereference_arguments = 1; + break; + + case 'L': + ftw_flags &= ~FTW_PHYS; + break; + + case 'S': + opt_separate_dirs = 1; + break; + + case 'X': + if (add_exclude_file (add_exclude, exclude, optarg, + EXCLUDE_WILDCARDS, '\n')) + { + error (0, errno, "%s", quotearg_colon (optarg)); + fail = 1; + } + break; + + case EXCLUDE_OPTION: + add_exclude (exclude, optarg, EXCLUDE_WILDCARDS); + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + fail = 1; + } + } + + if (fail) + usage (EXIT_FAILURE); + + if (opt_all && opt_summarize_only) + { + error (0, 0, _("cannot both summarize and show all entries")); + usage (EXIT_FAILURE); + } + + if (opt_summarize_only && max_depth_specified && max_depth == 0) + { + error (0, 0, + _("warning: summarizing is the same as using --max-depth=0")); + } + + if (opt_summarize_only && max_depth_specified && max_depth != 0) + { + error (0, 0, + _("warning: summarizing conflicts with --max-depth=%d"), + max_depth); + usage (EXIT_FAILURE); + } + + if (opt_summarize_only) + max_depth = 0; + + files = (optind == argc ? cwd_only : argv + optind); + + /* Initialize the hash structure for inode numbers. */ + hash_init (); + + exit (du_files (files, ftw_flags) || G_fail + ? EXIT_FAILURE : EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/echo.c b/src/apps/bin/coreutils-5.0/src/echo.c new file mode 100644 index 0000000000..3538ed5030 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/echo.c @@ -0,0 +1,248 @@ +/* echo.c, derived from code echo.c in Bash. + Copyright (C) 87,89, 1991-1997, 1999-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include "system.h" +#include "closeout.h" +#include "long-options.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "echo" + +#define AUTHORS "FIXME unknown" + +/* echo [-neE] [arg ...] +Output the ARGs. If -n is specified, the trailing newline is +suppressed. If the -e option is given, interpretation of the +following backslash-escaped characters is turned on: + \a alert (bell) + \b backspace + \c suppress trailing newline + \f form feed + \n new line + \r carriage return + \t horizontal tab + \v vertical tab + \\ backslash + \num the character whose ASCII code is NUM (octal). + +You can explicitly turn off the interpretation of the above characters +on System V systems with the -E option. +*/ + +/* If defined, interpret backslash escapes if -e is given. */ +#define V9_ECHO + +/* If defined, interpret backslash escapes unless -E is given. + V9_ECHO must also be defined. */ +/* #define V9_DEFAULT */ + +#if defined (V9_ECHO) +# if defined (V9_DEFAULT) +# define VALID_ECHO_OPTIONS "neE" +# else +# define VALID_ECHO_OPTIONS "ne" +# endif /* !V9_DEFAULT */ +#else /* !V9_ECHO */ +# define VALID_ECHO_OPTIONS "n" +#endif /* !V9_ECHO */ + +/* The name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [STRING]...\n"), program_name); + fputs (_("\ +Echo the STRING(s) to standard output.\n\ +\n\ + -n do not output the trailing newline\n\ + -e enable interpretation of the backslash-escaped characters\n\ + listed below\n\ + -E disable interpretation of those sequences in STRINGs\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +Without -E, the following sequences are recognized and interpolated:\n\ +\n\ + \\NNN the character whose ASCII code is NNN (octal)\n\ + \\\\ backslash\n\ + \\a alert (BEL)\n\ + \\b backspace\n\ +"), stdout); + fputs (_("\ + \\c suppress trailing newline\n\ + \\f form feed\n\ + \\n new line\n\ + \\r carriage return\n\ + \\t horizontal tab\n\ + \\v vertical tab\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +/* Print the words in LIST to standard output. If the first word is + `-n', then don't print a trailing newline. We also support the + echo syntax from Version 9 unix systems. */ + +int +main (int argc, char **argv) +{ + int display_return = 1, do_v9 = 0; + int allow_options = 1; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */ + if (getenv ("POSIXLY_CORRECT") == NULL) + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + else + allow_options = 0; + +/* System V machines already have a /bin/sh with a v9 behaviour. We + use the identical behaviour for these machines so that the + existing system shell scripts won't barf. */ +#if defined (V9_ECHO) && defined (V9_DEFAULT) + do_v9 = allow_options; +#endif + + --argc; + ++argv; + + while (argc > 0 && *argv[0] == '-') + { + register char *temp; + register int i; + + /* If it appears that we are handling options, then make sure that + all of the options specified are actually valid. Otherwise, the + string should just be echoed. */ + temp = argv[0] + 1; + + for (i = 0; temp[i]; i++) + { + if (strrchr (VALID_ECHO_OPTIONS, temp[i]) == 0) + goto just_echo; + } + + if (!*temp) + goto just_echo; + + /* All of the options in TEMP are valid options to ECHO. + Handle them. */ + while (*temp) + { + if (allow_options && *temp == 'n') + display_return = 0; +#if defined (V9_ECHO) + else if (allow_options && *temp == 'e') + do_v9 = 1; +# if defined (V9_DEFAULT) + else if (allow_options && *temp == 'E') + do_v9 = 0; +# endif /* V9_DEFAULT */ +#endif /* V9_ECHO */ + else + goto just_echo; + + temp++; + } + argc--; + argv++; + } + +just_echo: + + if (argc > 0) + { +#if defined (V9_ECHO) + if (do_v9) + { + while (argc > 0) + { + register char *s = argv[0]; + register int c; + + while ((c = *s++)) + { + if (c == '\\' && *s) + { + switch (c = *s++) + { + case 'a': c = '\007'; break; + case 'b': c = '\b'; break; + case 'c': display_return = 0; continue; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = (int) 0x0B; break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c -= '0'; + if (*s >= '0' && *s <= '7') + c = c * 8 + (*s++ - '0'); + if (*s >= '0' && *s <= '7') + c = c * 8 + (*s++ - '0'); + break; + case '\\': break; + default: putchar ('\\'); break; + } + } + putchar(c); + } + argc--; + argv++; + if (argc > 0) + putchar(' '); + } + } + else +#endif /* V9_ECHO */ + { + while (argc > 0) + { + fputs (argv[0], stdout); + argc--; + argv++; + if (argc > 0) + putchar (' '); + } + } + } + if (display_return) + putchar ('\n'); + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/env.c b/src/apps/bin/coreutils-5.0/src/env.c new file mode 100644 index 0000000000..596498aa62 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/env.c @@ -0,0 +1,207 @@ +/* env - run a program in a modified environment + Copyright (C) 1986, 1991-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Richard Mlynarik and David MacKenzie */ + +/* Options: + - + -i + --ignore-environment + Construct a new environment from scratch; normally the + environment is inherited from the parent process, except as + modified by other options. + + -u variable + --unset=variable + Unset variable VARIABLE (remove it from the environment). + If VARIABLE was not set, does nothing. + + variable=value (an arg containing a "=" character) + Set the environment variable VARIABLE to value VALUE. VALUE + may be of zero length ("variable="). Setting a variable to a + zero-length value is different from unsetting it. + + -- + Indicate that the following argument is the program + to invoke. This is necessary when the program's name + begins with "-" or contains a "=". + + The first remaining argument specifies a program to invoke; + it is searched for according to the specification of the PATH + environment variable. Any arguments following that are + passed as arguments to that program. + + If no command name is specified following the environment + specifications, the resulting environment is printed. + This is like specifying a command name of "printenv". + + Examples: + + If the environment passed to "env" is + { LOGNAME=rms EDITOR=emacs PATH=.:/gnubin:/hacks } + + env - foo + runs "foo" in a null environment. + + env foo + runs "foo" in the environment + { LOGNAME=rms EDITOR=emacs PATH=.:/gnubin:/hacks } + + env DISPLAY=gnu:0 nemacs + runs "nemacs" in the environment + { LOGNAME=rms EDITOR=emacs PATH=.:/gnubin:/hacks DISPLAY=gnu:0 } + + env - LOGNAME=foo /hacks/hack bar baz + runs the "hack" program on arguments "bar" and "baz" in an + environment in which the only variable is "LOGNAME". Note that + the "-" option clears out the PATH variable, so one should be + careful to specify in which directory to find the program to + call. + + env -u EDITOR LOGNAME=foo PATH=/energy -- e=mc2 bar baz + runs the program "/energy/e=mc2" with environment + { LOGNAME=foo PATH=/energy } +*/ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "env" + +#define AUTHORS N_ ("Richard Mlynarik and David MacKenzie") + +int putenv (); + +extern char **environ; + +/* The name by which this program was run. */ +char *program_name; + +static struct option const longopts[] = +{ + {"ignore-environment", no_argument, NULL, 'i'}, + {"unset", required_argument, NULL, 'u'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]\n"), + program_name); + fputs (_("\ +Set each NAME to VALUE in the environment and run COMMAND.\n\ +\n\ + -i, --ignore-environment start with an empty environment\n\ + -u, --unset=NAME remove variable from the environment\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +A mere - implies -i. If no COMMAND, print the resulting environment.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (register int argc, register char **argv, char **envp) +{ + char *dummy_environ[1]; + int optc; + int ignore_environment = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + while ((optc = getopt_long (argc, argv, "+iu:", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + case 'i': + ignore_environment = 1; + break; + case 'u': + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (2); + } + } + + if (optind != argc && !strcmp (argv[optind], "-")) + ignore_environment = 1; + + environ = dummy_environ; + environ[0] = NULL; + + if (!ignore_environment) + for (; *envp; envp++) + putenv (*envp); + + optind = 0; /* Force GNU getopt to re-initialize. */ + while ((optc = getopt_long (argc, argv, "+iu:", longopts, NULL)) != -1) + if (optc == 'u') + putenv (optarg); /* Requires GNU putenv. */ + + if (optind != argc && !strcmp (argv[optind], "-")) + ++optind; + + while (optind < argc && strchr (argv[optind], '=')) + putenv (argv[optind++]); + + /* If no program is specified, print the environment and exit. */ + if (optind == argc) + { + while (*environ) + puts (*environ++); + exit (EXIT_SUCCESS); + } + + execvp (argv[optind], &argv[optind]); + + { + int exit_status = (errno == ENOENT ? 127 : 126); + error (0, errno, "%s", argv[optind]); + exit (exit_status); + } +} diff --git a/src/apps/bin/coreutils-5.0/src/expand.c b/src/apps/bin/coreutils-5.0/src/expand.c new file mode 100644 index 0000000000..84d14d9246 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/expand.c @@ -0,0 +1,412 @@ +/* expand - convert tabs to spaces + Copyright (C) 89, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* By default, convert all tabs to spaces. + Preserves backspace characters in the output; they decrement the + column count for tab calculations. + The default action is equivalent to -8. + + Options: + --tabs=tab1[,tab2[,...]] + -t tab1[,tab2[,...]] + -tab1[,tab2[,...]] If only one tab stop is given, set the tabs tab1 + spaces apart instead of the default 8. Otherwise, + set the tabs at columns tab1, tab2, etc. (numbered from + 0); replace any tabs beyond the tabstops given with + single spaces. + --initial + -i Only convert initial tabs on each line to spaces. + + David MacKenzie */ + +#include + +#include +#include +#include +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "posixver.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "expand" + +#define AUTHORS "David MacKenzie" + +/* The number of bytes added at a time to the amount of memory + allocated for the output line. */ +#define OUTPUT_BLOCK 256 + +/* The number of bytes added at a time to the amount of memory + allocated for the list of tabstops. */ +#define TABLIST_BLOCK 256 + +/* The name this program was run with. */ +char *program_name; + +/* If nonzero, convert blanks even after nonblank characters have been + read on the line. */ +static int convert_entire_line; + +/* If nonzero, the size of all tab stops. If zero, use `tab_list' instead. */ +static int tab_size; + +/* Array of the explicit column numbers of the tab stops; + after `tab_list' is exhausted, each additional tab is replaced + by a space. The first column is column 0. */ +static int *tab_list; + +/* The index of the first invalid element of `tab_list', + where the next element can be added. */ +static int first_free_tab; + +/* Null-terminated array of input filenames. */ +static char **file_list; + +/* Default for `file_list' if no files are given on the command line. */ +static char *stdin_argv[] = +{ + "-", NULL +}; + +/* Nonzero if we have ever read standard input. */ +static int have_read_stdin; + +/* Status to return to the system. */ +static int exit_status; + +static struct option const longopts[] = +{ + {"tabs", required_argument, NULL, 't'}, + {"initial", no_argument, NULL, 'i'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + fputs (_("\ +Convert tabs in each FILE to spaces, writing to standard output.\n\ +With no FILE, or when FILE is -, read standard input.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -i, --initial do not convert TABs after non whitespace\n\ + -t, --tabs=NUMBER have tabs NUMBER characters apart, not 8\n\ +"), stdout); + fputs (_("\ + -t, --tabs=LIST use comma separated list of explicit tab positions\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Add tab stop TABVAL to the end of `tab_list', except + if TABVAL is -1, do nothing. */ + +static void +add_tabstop (int tabval) +{ + if (tabval == -1) + return; + if (first_free_tab % TABLIST_BLOCK == 0) + tab_list = (int *) xrealloc ((char *) tab_list, + (first_free_tab + + TABLIST_BLOCK * sizeof (tab_list[0]))); + tab_list[first_free_tab++] = tabval; +} + +/* Add the comma or blank separated list of tabstops STOPS + to the list of tabstops. */ + +static void +parse_tabstops (char *stops) +{ + int tabval = -1; + + for (; *stops; stops++) + { + if (*stops == ',' || ISBLANK (*stops)) + { + add_tabstop (tabval); + tabval = -1; + } + else if (ISDIGIT (*stops)) + { + if (tabval == -1) + tabval = 0; + tabval = tabval * 10 + *stops - '0'; + } + else + error (EXIT_FAILURE, 0, _("tab size contains an invalid character")); + } + + add_tabstop (tabval); +} + +/* Check that the list of tabstops TABS, with ENTRIES entries, + contains only nonzero, ascending values. */ + +static void +validate_tabstops (int *tabs, int entries) +{ + int prev_tab = 0; + int i; + + for (i = 0; i < entries; i++) + { + if (tabs[i] == 0) + error (EXIT_FAILURE, 0, _("tab size cannot be 0")); + if (tabs[i] <= prev_tab) + error (EXIT_FAILURE, 0, _("tab sizes must be ascending")); + prev_tab = tabs[i]; + } +} + +/* Close the old stream pointer FP if it is non-NULL, + and return a new one opened to read the next input file. + Open a filename of `-' as the standard input. + Return NULL if there are no more input files. */ + +static FILE * +next_file (FILE *fp) +{ + static char *prev_file; + char *file; + + if (fp) + { + if (ferror (fp)) + { + error (0, errno, "%s", prev_file); + exit_status = 1; + } + if (fp == stdin) + clearerr (fp); /* Also clear EOF. */ + else if (fclose (fp) == EOF) + { + error (0, errno, "%s", prev_file); + exit_status = 1; + } + } + + while ((file = *file_list++) != NULL) + { + if (file[0] == '-' && file[1] == '\0') + { + have_read_stdin = 1; + prev_file = file; + return stdin; + } + fp = fopen (file, "r"); + if (fp) + { + prev_file = file; + return fp; + } + error (0, errno, "%s", file); + exit_status = 1; + } + return NULL; +} + +/* Change tabs to spaces, writing to stdout. + Read each file in `file_list', in order. */ + +static void +expand (void) +{ + FILE *fp; /* Input stream. */ + int c; /* Each input character. */ + int tab_index = 0; /* Index in `tab_list' of next tabstop. */ + int column = 0; /* Column on screen of the next char. */ + int next_tab_column; /* Column the next tab stop is on. */ + int convert = 1; /* If nonzero, perform translations. */ + + fp = next_file ((FILE *) NULL); + if (fp == NULL) + return; + + /* Binary I/O will preserve the original EOL style (DOS/Unix) of files. */ + SET_BINARY2 (fileno (fp), STDOUT_FILENO); + + for (;;) + { + c = getc (fp); + if (c == EOF) + { + fp = next_file (fp); + if (fp == NULL) + break; /* No more files. */ + else + { + SET_BINARY2 (fileno (fp), STDOUT_FILENO); + continue; + } + } + + if (c == '\n') + { + putchar (c); + tab_index = 0; + column = 0; + convert = 1; + } + else if (c == '\t' && convert) + { + if (tab_size == 0) + { + /* Do not let tab_index == first_free_tab; + stop when it is 1 less. */ + while (tab_index < first_free_tab - 1 + && column >= tab_list[tab_index]) + tab_index++; + next_tab_column = tab_list[tab_index]; + if (tab_index < first_free_tab - 1) + tab_index++; + if (column >= next_tab_column) + next_tab_column = column + 1; /* Ran out of tab stops. */ + } + else + { + next_tab_column = column + tab_size - column % tab_size; + } + while (column < next_tab_column) + { + putchar (' '); + ++column; + } + } + else + { + if (convert) + { + if (c == '\b') + { + if (column > 0) + --column; + } + else + { + ++column; + if (convert_entire_line == 0) + convert = 0; + } + } + putchar (c); + } + } +} + +int +main (int argc, char **argv) +{ + int tabval = -1; /* Value of tabstop being read, or -1. */ + int c; /* Option character. */ + + bool obsolete_tablist = false; + + have_read_stdin = 0; + exit_status = 0; + convert_entire_line = 1; + tab_list = NULL; + first_free_tab = 0; + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + while ((c = getopt_long (argc, argv, "it:,0123456789", longopts, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + case '?': + usage (EXIT_FAILURE); + case 'i': + convert_entire_line = 0; + break; + case 't': + parse_tabstops (optarg); + break; + case ',': + add_tabstop (tabval); + tabval = -1; + obsolete_tablist = true; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + if (tabval == -1) + tabval = 0; + tabval = tabval * 10 + c - '0'; + obsolete_tablist = true; + break; + } + } + + if (obsolete_tablist && 200112 <= posix2_version ()) + { + error (0, 0, _("`-LIST' option is obsolete; use `-t LIST'")); + usage (EXIT_FAILURE); + } + + add_tabstop (tabval); + + validate_tabstops (tab_list, first_free_tab); + + if (first_free_tab == 0) + tab_size = 8; + else if (first_free_tab == 1) + tab_size = tab_list[0]; + else + tab_size = 0; + + if (optind == argc) + file_list = stdin_argv; + else + file_list = &argv[optind]; + + expand (); + + if (have_read_stdin && fclose (stdin) == EOF) + error (EXIT_FAILURE, errno, "-"); + + exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/expr.c b/src/apps/bin/coreutils-5.0/src/expr.c new file mode 100644 index 0000000000..3a8dbdc0a0 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/expr.c @@ -0,0 +1,753 @@ +/* expr -- evaluate expressions. + Copyright (C) 86, 1991-1997, 1999-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Author: Mike Parker. + + This program evaluates expressions. Each token (operator, operand, + parenthesis) of the expression must be a seperate argument. The + parser used is a reasonably general one, though any incarnation of + it is language-specific. It is especially nice for expressions. + + No parse tree is needed; a new node is evaluated immediately. + One function can handle multiple operators all of equal precedence, + provided they all associate ((x op x) op x). + + Define EVAL_TRACE to print an evaluation trace. */ + +#include +#include +#include +#include "system.h" + +#include +#include "long-options.h" +#include "error.h" +#include "closeout.h" +#include "inttostr.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "expr" + +#define AUTHORS "Mike Parker" + +#undef NEW +#define NEW(Type) XMALLOC (Type, 1) +#define OLD(x) free ((char *) x) + +/* The kinds of value we can have. */ +enum valtype +{ + integer, + string +}; +typedef enum valtype TYPE; + +/* A value is.... */ +struct valinfo +{ + TYPE type; /* Which kind. */ + union + { /* The value itself. */ + intmax_t i; + char *s; + } u; +}; +typedef struct valinfo VALUE; + +/* The arguments given to the program, minus the program name. */ +static char **args; + +/* The name this program was run with. */ +char *program_name; + +static VALUE *eval (void); +static int nomoreargs (void); +static int null (VALUE *v); +static void printv (VALUE *v); + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s EXPRESSION\n\ + or: %s OPTION\n\ +"), + program_name, program_name); + putchar ('\n'); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +Print the value of EXPRESSION to standard output. A blank line below\n\ +separates increasing precedence groups. EXPRESSION may be:\n\ +\n\ + ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\ +\n\ + ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\ +"), stdout); + fputs (_("\ +\n\ + ARG1 < ARG2 ARG1 is less than ARG2\n\ + ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\ + ARG1 = ARG2 ARG1 is equal to ARG2\n\ + ARG1 != ARG2 ARG1 is unequal to ARG2\n\ + ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\ + ARG1 > ARG2 ARG1 is greater than ARG2\n\ +"), stdout); + fputs (_("\ +\n\ + ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\ + ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\ +"), stdout); + fputs (_("\ +\n\ + ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\ + ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\ + ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\ +"), stdout); + fputs (_("\ +\n\ + STRING : REGEXP anchored pattern match of REGEXP in STRING\n\ +\n\ + match STRING REGEXP same as STRING : REGEXP\n\ + substr STRING POS LENGTH substring of STRING, POS counted from 1\n\ + index STRING CHARS index in STRING where any CHARS is found, or 0\n\ + length STRING length of STRING\n\ +"), stdout); + fputs (_("\ + + TOKEN interpret TOKEN as a string, even if it is a\n\ + keyword like `match' or an operator like `/'\n\ +\n\ + ( EXPRESSION ) value of EXPRESSION\n\ +"), stdout); + fputs (_("\ +\n\ +Beware that many operators need to be escaped or quoted for shells.\n\ +Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\ +Pattern matches return the string matched between \\( and \\) or null; if\n\ +\\( and \\) are not used, they return the number of characters matched or 0.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + VALUE *v; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + /* The above handles --help and --version. + Since there is no other invocation of getopt, handle `--' here. */ + if (argc > 1 && STREQ (argv[1], "--")) + { + --argc; + ++argv; + } + + if (argc == 1) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + args = argv + 1; + + v = eval (); + if (!nomoreargs ()) + error (2, 0, _("syntax error")); + printv (v); + + exit (null (v)); +} + +/* Return a VALUE for I. */ + +static VALUE * +int_value (intmax_t i) +{ + VALUE *v; + + v = NEW (VALUE); + v->type = integer; + v->u.i = i; + return v; +} + +/* Return a VALUE for S. */ + +static VALUE * +str_value (char *s) +{ + VALUE *v; + + v = NEW (VALUE); + v->type = string; + v->u.s = xstrdup (s); + return v; +} + +/* Free VALUE V, including structure components. */ + +static void +freev (VALUE *v) +{ + if (v->type == string) + free (v->u.s); + OLD (v); +} + +/* Print VALUE V. */ + +static void +printv (VALUE *v) +{ + char *p; + char buf[INT_STRLEN_BOUND (intmax_t) + 1]; + + switch (v->type) + { + case integer: + p = imaxtostr (v->u.i, buf); + break; + case string: + p = v->u.s; + break; + default: + abort (); + } + + puts (p); +} + +/* Return nonzero if V is a null-string or zero-number. */ + +static int +null (VALUE *v) +{ + switch (v->type) + { + case integer: + return v->u.i == 0; + case string: + return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0; + default: + abort (); + } +} + +/* Coerce V to a string value (can't fail). */ + +static void +tostring (VALUE *v) +{ + char buf[INT_STRLEN_BOUND (intmax_t) + 1]; + + switch (v->type) + { + case integer: + v->u.s = xstrdup (imaxtostr (v->u.i, buf)); + v->type = string; + break; + case string: + break; + default: + abort (); + } +} + +/* Coerce V to an integer value. Return 1 on success, 0 on failure. */ + +static int +toarith (VALUE *v) +{ + intmax_t i; + int neg; + char *cp; + + switch (v->type) + { + case integer: + return 1; + case string: + i = 0; + cp = v->u.s; + neg = (*cp == '-'); + if (neg) + cp++; + + do + { + if (ISDIGIT (*cp)) + i = i * 10 + *cp - '0'; + else + return 0; + } + while (*++cp); + + free (v->u.s); + v->u.i = i * (neg ? -1 : 1); + v->type = integer; + return 1; + default: + abort (); + } +} + +/* Return nonzero and advance if the next token matches STR exactly. + STR must not be NULL. */ + +static int +nextarg (char *str) +{ + if (*args == NULL) + return 0; + else + { + int r = strcoll (*args, str) == 0; + args += r; + return r; + } +} + +/* Return nonzero if there no more tokens. */ + +static int +nomoreargs (void) +{ + return *args == 0; +} + +#ifdef EVAL_TRACE +/* Print evaluation trace and args remaining. */ + +static void +trace (fxn) + char *fxn; +{ + char **a; + + printf ("%s:", fxn); + for (a = args; *a; a++) + printf (" %s", *a); + putchar ('\n'); +} +#endif + +/* Do the : operator. + SV is the VALUE for the lhs (the string), + PV is the VALUE for the rhs (the pattern). */ + +static VALUE * +docolon (VALUE *sv, VALUE *pv) +{ + VALUE *v; + const char *errmsg; + struct re_pattern_buffer re_buffer; + struct re_registers re_regs; + size_t len; + int matchlen; + + tostring (sv); + tostring (pv); + + if (pv->u.s[0] == '^') + { + error (0, 0, _("\ +warning: unportable BRE: `%s': using `^' as the first character\n\ +of the basic regular expression is not portable; it is being ignored"), + pv->u.s); + } + + len = strlen (pv->u.s); + memset (&re_buffer, 0, sizeof (re_buffer)); + memset (&re_regs, 0, sizeof (re_regs)); + re_buffer.allocated = 2 * len; + if (re_buffer.allocated < len) + xalloc_die (); + re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated); + re_buffer.translate = 0; + re_syntax_options = RE_SYNTAX_POSIX_BASIC; + errmsg = re_compile_pattern (pv->u.s, len, &re_buffer); + if (errmsg) + error (2, 0, "%s", errmsg); + + matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs); + if (0 <= matchlen) + { + /* Were \(...\) used? */ + if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */ + { + sv->u.s[re_regs.end[1]] = '\0'; + v = str_value (sv->u.s + re_regs.start[1]); + } + else + v = int_value (matchlen); + } + else + { + /* Match failed -- return the right kind of null. */ + if (re_buffer.re_nsub > 0) + v = str_value (""); + else + v = int_value (0); + } + free (re_buffer.buffer); + return v; +} + +/* Handle bare operands and ( expr ) syntax. */ + +static VALUE * +eval7 (void) +{ + VALUE *v; + +#ifdef EVAL_TRACE + trace ("eval7"); +#endif + if (nomoreargs ()) + error (2, 0, _("syntax error")); + + if (nextarg ("(")) + { + v = eval (); + if (!nextarg (")")) + error (2, 0, _("syntax error")); + return v; + } + + if (nextarg (")")) + error (2, 0, _("syntax error")); + + return str_value (*args++); +} + +/* Handle match, substr, index, and length keywords, and quoting "+". */ + +static VALUE * +eval6 (void) +{ + VALUE *l; + VALUE *r; + VALUE *v; + VALUE *i1; + VALUE *i2; + +#ifdef EVAL_TRACE + trace ("eval6"); +#endif + if (nextarg ("+")) + { + if (nomoreargs ()) + error (2, 0, _("syntax error")); + return str_value (*args++); + } + else if (nextarg ("length")) + { + r = eval6 (); + tostring (r); + v = int_value (strlen (r->u.s)); + freev (r); + return v; + } + else if (nextarg ("match")) + { + l = eval6 (); + r = eval6 (); + v = docolon (l, r); + freev (l); + freev (r); + return v; + } + else if (nextarg ("index")) + { + l = eval6 (); + r = eval6 (); + tostring (l); + tostring (r); + v = int_value (strcspn (l->u.s, r->u.s) + 1); + if (v->u.i == strlen (l->u.s) + 1) + v->u.i = 0; + freev (l); + freev (r); + return v; + } + else if (nextarg ("substr")) + { + l = eval6 (); + i1 = eval6 (); + i2 = eval6 (); + tostring (l); + if (!toarith (i1) || !toarith (i2) + || strlen (l->u.s) < i1->u.i + || i1->u.i <= 0 || i2->u.i <= 0) + v = str_value (""); + else + { + v = NEW (VALUE); + v->type = string; + v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1), + l->u.s + i1->u.i - 1, i2->u.i); + v->u.s[i2->u.i] = 0; + } + freev (l); + freev (i1); + freev (i2); + return v; + } + else + return eval7 (); +} + +/* Handle : operator (pattern matching). + Calls docolon to do the real work. */ + +static VALUE * +eval5 (void) +{ + VALUE *l; + VALUE *r; + VALUE *v; + +#ifdef EVAL_TRACE + trace ("eval5"); +#endif + l = eval6 (); + while (1) + { + if (nextarg (":")) + { + r = eval6 (); + v = docolon (l, r); + freev (l); + freev (r); + l = v; + } + else + return l; + } +} + +/* Handle *, /, % operators. */ + +static VALUE * +eval4 (void) +{ + VALUE *l; + VALUE *r; + enum { multiply, divide, mod } fxn; + intmax_t val; + +#ifdef EVAL_TRACE + trace ("eval4"); +#endif + l = eval5 (); + while (1) + { + if (nextarg ("*")) + fxn = multiply; + else if (nextarg ("/")) + fxn = divide; + else if (nextarg ("%")) + fxn = mod; + else + return l; + r = eval5 (); + if (!toarith (l) || !toarith (r)) + error (2, 0, _("non-numeric argument")); + if (fxn == multiply) + val = l->u.i * r->u.i; + else + { + if (r->u.i == 0) + error (2, 0, _("division by zero")); + val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i; + } + freev (l); + freev (r); + l = int_value (val); + } +} + +/* Handle +, - operators. */ + +static VALUE * +eval3 (void) +{ + VALUE *l; + VALUE *r; + enum { plus, minus } fxn; + intmax_t val; + +#ifdef EVAL_TRACE + trace ("eval3"); +#endif + l = eval4 (); + while (1) + { + if (nextarg ("+")) + fxn = plus; + else if (nextarg ("-")) + fxn = minus; + else + return l; + r = eval4 (); + if (!toarith (l) || !toarith (r)) + error (2, 0, _("non-numeric argument")); + val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i; + freev (l); + freev (r); + l = int_value (val); + } +} + +/* Handle comparisons. */ + +static VALUE * +eval2 (void) +{ + VALUE *l; + VALUE *r; + enum + { + less_than, less_equal, equal, not_equal, greater_equal, greater_than + } fxn; + int val; + intmax_t lval; + intmax_t rval; + +#ifdef EVAL_TRACE + trace ("eval2"); +#endif + l = eval3 (); + while (1) + { + if (nextarg ("<")) + fxn = less_than; + else if (nextarg ("<=")) + fxn = less_equal; + else if (nextarg ("=") || nextarg ("==")) + fxn = equal; + else if (nextarg ("!=")) + fxn = not_equal; + else if (nextarg (">=")) + fxn = greater_equal; + else if (nextarg (">")) + fxn = greater_than; + else + return l; + r = eval3 (); + tostring (l); + tostring (r); + lval = strcoll (l->u.s, r->u.s); + rval = 0; + if (toarith (l) && toarith (r)) + { + lval = l->u.i; + rval = r->u.i; + } + switch (fxn) + { + case less_than: val = (lval < rval); break; + case less_equal: val = (lval <= rval); break; + case equal: val = (lval == rval); break; + case not_equal: val = (lval != rval); break; + case greater_equal: val = (lval >= rval); break; + case greater_than: val = (lval > rval); break; + default: abort (); + } + freev (l); + freev (r); + l = int_value (val); + } +} + +/* Handle &. */ + +static VALUE * +eval1 (void) +{ + VALUE *l; + VALUE *r; + +#ifdef EVAL_TRACE + trace ("eval1"); +#endif + l = eval2 (); + while (1) + { + if (nextarg ("&")) + { + r = eval2 (); + if (null (l) || null (r)) + { + freev (l); + freev (r); + l = int_value (0); + } + else + freev (r); + } + else + return l; + } +} + +/* Handle |. */ + +static VALUE * +eval (void) +{ + VALUE *l; + VALUE *r; + +#ifdef EVAL_TRACE + trace ("eval"); +#endif + l = eval1 (); + while (1) + { + if (nextarg ("|")) + { + r = eval1 (); + if (null (l)) + { + freev (l); + l = r; + } + else + freev (r); + } + else + return l; + } +} diff --git a/src/apps/bin/coreutils-5.0/src/factor.c b/src/apps/bin/coreutils-5.0/src/factor.c new file mode 100644 index 0000000000..fc2a407a82 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/factor.c @@ -0,0 +1,223 @@ +/* factor -- print prime factors of n. + Copyright (C) 86, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Paul Rubin . + Adapted for GNU, fixed to factor UINT_MAX by Jim Meyering. */ + +#include +#include +#include + +#include +#define NDEBUG 1 + +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "inttostr.h" +#include "long-options.h" +#include "readtokens.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "factor" + +#define AUTHORS "Paul Rubin" + +/* Token delimiters when reading from a file. */ +#define DELIM "\n\t " + +/* FIXME: if this program is ever modified to factor integers larger + than 2^128, this constant (and the algorithm :-) will have to change. */ +#define MAX_N_FACTORS 128 + +/* The trial divisor increment wheel. Use it to skip over divisors that + are composites of 2, 3, 5, 7, or 11. The part from WHEEL_START up to + WHEEL_END is reused periodically, while the "lead in" is used to test + for those primes and to jump onto the wheel. For more information, see + http://www.utm.edu/research/primes/glossary/WheelFactorization.html */ + +#include "wheel-size.h" /* For the definition of WHEEL_SIZE. */ +static const unsigned int wheel_tab[] = + { +#include "wheel.h" + }; + +#define WHEEL_START (wheel_tab + WHEEL_SIZE) +#define WHEEL_END (wheel_tab + (sizeof wheel_tab / sizeof wheel_tab[0])) + +/* The name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [NUMBER]...\n\ + or: %s OPTION\n\ +"), + program_name, program_name); + fputs (_("\ +Print the prime factors of each NUMBER.\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ + Print the prime factors of all specified integer NUMBERs. If no arguments\n\ + are specified on the command line, they are read from standard input.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +/* FIXME: comment */ + +static int +factor (uintmax_t n0, int max_n_factors, uintmax_t *factors) +{ + register uintmax_t n = n0, d, q; + int n_factors = 0; + unsigned int const *w = wheel_tab; + + if (n < 1) + return n_factors; + + /* The exit condition in the following loop is correct because + any time it is tested one of these 3 conditions holds: + (1) d divides n + (2) n is prime + (3) n is composite but has no factors less than d. + If (1) or (2) obviously the right thing happens. + If (3), then since n is composite it is >= d^2. */ + + d = 2; + do + { + q = n / d; + while (n == q * d) + { + assert (n_factors < max_n_factors); + factors[n_factors++] = d; + n = q; + q = n / d; + } + d += *(w++); + if (w == WHEEL_END) + w = WHEEL_START; + } + while (d <= q); + + if (n != 1 || n0 == 1) + { + assert (n_factors < max_n_factors); + factors[n_factors++] = n; + } + + return n_factors; +} + +/* FIXME: comment */ + +static int +print_factors (const char *s) +{ + uintmax_t factors[MAX_N_FACTORS]; + uintmax_t n; + int n_factors; + int i; + char buf[INT_BUFSIZE_BOUND (uintmax_t)]; + + if (xstrtoumax (s, NULL, 10, &n, "") != LONGINT_OK) + { + error (0, 0, _("`%s' is not a valid positive integer"), s); + return 1; + } + n_factors = factor (n, MAX_N_FACTORS, factors); + printf ("%s:", umaxtostr (n, buf)); + for (i = 0; i < n_factors; i++) + printf (" %s", umaxtostr (factors[i], buf)); + putchar ('\n'); + return 0; +} + +static int +do_stdin (void) +{ + int fail = 0; + token_buffer tokenbuffer; + + init_tokenbuffer (&tokenbuffer); + + for (;;) + { + long int token_length; + + token_length = readtoken (stdin, DELIM, sizeof (DELIM) - 1, + &tokenbuffer); + if (token_length < 0) + break; + fail |= print_factors (tokenbuffer.buffer); + } + free (tokenbuffer.buffer); + + return fail; +} + +int +main (int argc, char **argv) +{ + int fail; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + /* The above handles --help and --version. + Since there is no other invocation of getopt, handle `--' here. */ + if (argc > 1 && STREQ (argv[1], "--")) + { + --argc; + ++argv; + } + + fail = 0; + if (argc == 1) + fail = do_stdin (); + else + { + int i; + for (i = 1; i < argc; i++) + fail |= print_factors (argv[i]); + } + if (fail) + usage (EXIT_FAILURE); + + exit (fail); +} diff --git a/src/apps/bin/coreutils-5.0/src/false.c b/src/apps/bin/coreutils-5.0/src/false.c new file mode 100644 index 0000000000..d5841ccd94 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/false.c @@ -0,0 +1,71 @@ +/* Exit with a status code indicating failure. + Copyright (C) 1999-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include "system.h" +#include "version-etc.h" +#include "closeout.h" + +#define PROGRAM_NAME "false" +#define AUTHORS "Jim Meyering" + +/* The name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + printf (_("\ +Usage: %s [ignored command line arguments]\n\ + or: %s OPTION\n\ +Exit with a status code indicating failure.\n\ +\n\ +These option names may not be abbreviated.\n\ +\n\ +"), + program_name, program_name); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + exit (status); +} + +int +main (int argc, char **argv) +{ + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + /* Recognize --help or --version only if it's the only command-line + argument and if POSIXLY_CORRECT is not set. */ + if (argc == 2 && getenv ("POSIXLY_CORRECT") == NULL) + { + if (STREQ (argv[1], "--help")) + usage (EXIT_FAILURE); + + if (STREQ (argv[1], "--version")) + version_etc (stdout, PROGRAM_NAME, GNU_PACKAGE, VERSION, AUTHORS); + } + + exit (EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/fmt.c b/src/apps/bin/coreutils-5.0/src/fmt.c new file mode 100644 index 0000000000..c6fe5ba40e --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/fmt.c @@ -0,0 +1,1003 @@ +/* GNU fmt -- simple text formatter. + Copyright (C) 1994-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Ross Paterson . */ + +#include +#include +#include +#include + +/* Redefine. Otherwise, systems (Unicos for one) with headers that define + it to be a type get syntax errors for the variable declaration below. */ +#define word unused_word_type + +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "fmt" + +#define AUTHORS "Ross Paterson" + +/* The following parameters represent the program's idea of what is + "best". Adjust to taste, subject to the caveats given. */ + +/* Default longest permitted line length (max_width). */ +#define WIDTH 75 + +/* Prefer lines to be LEEWAY % shorter than the maximum width, giving + room for optimization. */ +#define LEEWAY 7 + +/* The default secondary indent of tagged paragraph used for unindented + one-line paragraphs not preceded by any multi-line paragraphs. */ +#define DEF_INDENT 3 + +/* Costs and bonuses are expressed as the equivalent departure from the + optimal line length, multiplied by 10. e.g. assigning something a + cost of 50 means that it is as bad as a line 5 characters too short + or too long. The definition of SHORT_COST(n) should not be changed. + However, EQUIV(n) may need tuning. */ + +typedef long COST; + +#define MAXCOST TYPE_MAXIMUM (COST) + +#define SQR(n) ((n) * (n)) +#define EQUIV(n) SQR ((COST) (n)) + +/* Cost of a filled line n chars longer or shorter than best_width. */ +#define SHORT_COST(n) EQUIV ((n) * 10) + +/* Cost of the difference between adjacent filled lines. */ +#define RAGGED_COST(n) (SHORT_COST (n) / 2) + +/* Basic cost per line. */ +#define LINE_COST EQUIV (70) + +/* Cost of breaking a line after the first word of a sentence, where + the length of the word is N. */ +#define WIDOW_COST(n) (EQUIV (200) / ((n) + 2)) + +/* Cost of breaking a line before the last word of a sentence, where + the length of the word is N. */ +#define ORPHAN_COST(n) (EQUIV (150) / ((n) + 2)) + +/* Bonus for breaking a line at the end of a sentence. */ +#define SENTENCE_BONUS EQUIV (50) + +/* Cost of breaking a line after a period not marking end of a sentence. + With the definition of sentence we are using (borrowed from emacs, see + get_line()) such a break would then look like a sentence break. Hence + we assign a very high cost -- it should be avoided unless things are + really bad. */ +#define NOBREAK_COST EQUIV (600) + +/* Bonus for breaking a line before open parenthesis. */ +#define PAREN_BONUS EQUIV (40) + +/* Bonus for breaking a line after other punctuation. */ +#define PUNCT_BONUS EQUIV(40) + +/* Credit for breaking a long paragraph one line later. */ +#define LINE_CREDIT EQUIV(3) + +/* Size of paragraph buffer, in words and characters. Longer paragraphs + are handled neatly (cf. flush_paragraph()), so there's little to gain + by making these larger. */ +#define MAXWORDS 1000 +#define MAXCHARS 5000 + +/* Extra ctype(3)-style macros. */ + +#define isopen(c) (strchr ("([`'\"", c) != NULL) +#define isclose(c) (strchr (")]'\"", c) != NULL) +#define isperiod(c) (strchr (".?!", c) != NULL) + +/* Size of a tab stop, for expansion on input and re-introduction on + output. */ +#define TABWIDTH 8 + +/* Miscellaneous definitions. */ + +#undef TRUE +#define TRUE true +#undef FALSE +#define FALSE false + +/* Word descriptor structure. */ + +typedef struct Word WORD; + +struct Word + { + + /* Static attributes determined during input. */ + + const char *text; /* the text of the word */ + int length; /* length of this word */ + int space; /* the size of the following space */ + unsigned int paren:1; /* starts with open paren */ + unsigned int period:1; /* ends in [.?!])* */ + unsigned int punct:1; /* ends in punctuation */ + unsigned int final:1; /* end of sentence */ + + /* The remaining fields are computed during the optimization. */ + + int line_length; /* length of the best line starting here */ + COST best_cost; /* cost of best paragraph starting here */ + WORD *next_break; /* break which achieves best_cost */ + }; + +/* Forward declarations. */ + +static void set_prefix (char *p); +static void fmt (FILE *f); +static bool get_paragraph (FILE *f); +static int get_line (FILE *f, int c); +static int get_prefix (FILE *f); +static int get_space (FILE *f, int c); +static int copy_rest (FILE *f, int c); +static bool same_para (int c); +static void flush_paragraph (void); +static void fmt_paragraph (void); +static void check_punctuation (WORD *w); +static COST base_cost (WORD *this); +static COST line_cost (WORD *next, int len); +static void put_paragraph (WORD *finish); +static void put_line (WORD *w, int indent); +static void put_word (WORD *w); +static void put_space (int space); + +/* The name this program was run with. */ +const char *program_name; + +/* Option values. */ + +/* If TRUE, first 2 lines may have different indent (default FALSE). */ +static bool crown; + +/* If TRUE, first 2 lines _must_ have different indent (default FALSE). */ +static bool tagged; + +/* If TRUE, each line is a paragraph on its own (default FALSE). */ +static bool split; + +/* If TRUE, don't preserve inter-word spacing (default FALSE). */ +static bool uniform; + +/* Prefix minus leading and trailing spaces (default ""). */ +static const char *prefix; + +/* User-supplied maximum line width (default WIDTH). The only output + lines longer than this will each comprise a single word. */ +static int max_width; + +/* Values derived from the option values. */ + +/* The length of prefix minus leading space. */ +static int prefix_full_length; + +/* The length of the leading space trimmed from the prefix. */ +static int prefix_lead_space; + +/* The length of prefix minus leading and trailing space. */ +static int prefix_length; + +/* The preferred width of text lines, set to LEEWAY % less than max_width. */ +static int best_width; + +/* Dynamic variables. */ + +/* Start column of the character most recently read from the input file. */ +static int in_column; + +/* Start column of the next character to be written to stdout. */ +static int out_column; + +/* Space for the paragraph text -- longer paragraphs are handled neatly + (cf. flush_paragraph()). */ +static char parabuf[MAXCHARS]; + +/* A pointer into parabuf, indicating the first unused character position. */ +static char *wptr; + +/* The words of a paragraph -- longer paragraphs are handled neatly + (cf. flush_paragraph()). */ +static WORD word[MAXWORDS]; + +/* A pointer into the above word array, indicating the first position + after the last complete word. Sometimes it will point at an incomplete + word. */ +static WORD *word_limit; + +/* If TRUE, current input file contains tab characters, and so tabs can be + used for white space on output. */ +static bool tabs; + +/* Space before trimmed prefix on each line of the current paragraph. */ +static int prefix_indent; + +/* Indentation of the first line of the current paragraph. */ +static int first_indent; + +/* Indentation of other lines of the current paragraph */ +static int other_indent; + +/* To detect the end of a paragraph, we need to look ahead to the first + non-blank character after the prefix on the next line, or the first + character on the following line that failed to match the prefix. + We can reconstruct the lookahead from that character (next_char), its + position on the line (in_column) and the amount of space before the + prefix (next_prefix_indent). See get_paragraph() and copy_rest(). */ + +/* The last character read from the input file. */ +static int next_char; + +/* The space before the trimmed prefix (or part of it) on the next line + after the current paragraph. */ +static int next_prefix_indent; + +/* If nonzero, the length of the last line output in the current + paragraph, used to charge for raggedness at the split point for long + paragraphs chosen by fmt_paragraph(). */ +static int last_line_length; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [-DIGITS] [OPTION]... [FILE]...\n"), program_name); + fputs (_("\ +Reformat each paragraph in the FILE(s), writing to standard output.\n\ +If no FILE or if FILE is `-', read standard input.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -c, --crown-margin preserve indentation of first two lines\n\ + -p, --prefix=STRING combine only lines having STRING as prefix\n\ + -s, --split-only split long lines, but do not refill\n\ +"), + stdout); + fputs (_("\ + -t, --tagged-paragraph indentation of first line different from second\n\ + -u, --uniform-spacing one space between words, two after sentences\n\ + -w, --width=NUMBER maximum line width (default of 75 columns)\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +In -wNUMBER, the letter `w' may be omitted.\n"), + stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Decode options and launch execution. */ + +static const struct option long_options[] = +{ + {"crown-margin", no_argument, NULL, 'c'}, + {"prefix", required_argument, NULL, 'p'}, + {"split-only", no_argument, NULL, 's'}, + {"tagged-paragraph", no_argument, NULL, 't'}, + {"uniform-spacing", no_argument, NULL, 'u'}, + {"width", required_argument, NULL, 'w'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0}, +}; + +int +main (register int argc, register char **argv) +{ + int optchar; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + crown = tagged = split = uniform = FALSE; + max_width = WIDTH; + prefix = ""; + prefix_length = prefix_lead_space = prefix_full_length = 0; + + if (argc > 1 && argv[1][0] == '-' && ISDIGIT (argv[1][1])) + { + const char *s = argv[1] + 1; + max_width = 0; + /* Old option syntax; a dash followed by one or more digits. + Move past the number. */ + for (; ISDIGIT (*s); ++s) + { + int old_max = max_width; + max_width = max_width * 10 + *s - '0'; + if (INT_MAX / 10 < old_max || max_width < old_max) + error (EXIT_FAILURE, 0, _("invalid width option: `%s'"), argv[1]); + } + /* Make the options we just parsed invisible to getopt. */ + argv[1] = argv[0]; + argv++; + argc--; + } + + while ((optchar = getopt_long (argc, argv, "0123456789cstuw:p:", + long_options, NULL)) + != -1) + switch (optchar) + { + default: + usage (EXIT_FAILURE); + + case 0: + break; + + case 'c': + crown = TRUE; + break; + + case 's': + split = TRUE; + break; + + case 't': + tagged = TRUE; + break; + + case 'u': + uniform = TRUE; + break; + + case 'w': + { + long int tmp_long; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long <= 0 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, _("invalid width: `%s'"), + optarg); + max_width = (int) tmp_long; + } + break; + + case 'p': + set_prefix (optarg); + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + } + + best_width = max_width * (2 * (100 - LEEWAY) + 1) / 200; + + if (optind == argc) + fmt (stdin); + else + { + for (; optind < argc; optind++) + { + char *file = argv[optind]; + if (STREQ (file, "-")) + fmt (stdin); + else + { + FILE *in_stream; + in_stream = fopen (file, "r"); + if (in_stream != NULL) + { + fmt (in_stream); + if (fclose (in_stream) == EOF) + error (EXIT_FAILURE, errno, "%s", file); + } + else + error (0, errno, "%s", file); + } + } + } + + exit (EXIT_SUCCESS); +} + +/* Trim space from the front and back of the string P, yielding the prefix, + and record the lengths of the prefix and the space trimmed. */ + +static void +set_prefix (register char *p) +{ + register char *s; + + prefix_lead_space = 0; + while (*p == ' ') + { + prefix_lead_space++; + p++; + } + prefix = p; + prefix_full_length = strlen (p); + s = p + prefix_full_length; + while (s > p && s[-1] == ' ') + s--; + *s = '\0'; + prefix_length = s - p; +} + +/* read file F and send formatted output to stdout. */ + +static void +fmt (FILE *f) +{ + tabs = FALSE; + other_indent = 0; + next_char = get_prefix (f); + while (get_paragraph (f)) + { + fmt_paragraph (); + put_paragraph (word_limit); + } +} + +/* Set the global variable `other_indent' according to SAME_PARAGRAPH + and other global variables. */ + +static void +set_other_indent (bool same_paragraph) +{ + if (split) + other_indent = first_indent; + else if (crown) + { + other_indent = (same_paragraph ? in_column : first_indent); + } + else if (tagged) + { + if (same_paragraph && in_column != first_indent) + { + other_indent = in_column; + } + + /* Only one line: use the secondary indent from last time if it + splits, or 0 if there have been no multi-line paragraphs in the + input so far. But if these rules make the two indents the same, + pick a new secondary indent. */ + + else if (other_indent == first_indent) + other_indent = first_indent == 0 ? DEF_INDENT : 0; + } + else + { + other_indent = first_indent; + } +} + +/* Read a paragraph from input file F. A paragraph consists of a + maximal number of non-blank (excluding any prefix) lines subject to: + * In split mode, a paragraph is a single non-blank line. + * In crown mode, the second and subsequent lines must have the + same indentation, but possibly different from the indent of the + first line. + * Tagged mode is similar, but the first and second lines must have + different indentations. + * Otherwise, all lines of a paragraph must have the same indent. + If a prefix is in effect, it must be present at the same indent for + each line in the paragraph. + + Return FALSE if end-of-file was encountered before the start of a + paragraph, else TRUE. */ + +static bool +get_paragraph (FILE *f) +{ + register int c; + + last_line_length = 0; + c = next_char; + + /* Scan (and copy) blank lines, and lines not introduced by the prefix. */ + + while (c == '\n' || c == EOF + || next_prefix_indent < prefix_lead_space + || in_column < next_prefix_indent + prefix_full_length) + { + c = copy_rest (f, c); + if (c == EOF) + { + next_char = EOF; + return FALSE; + } + putchar ('\n'); + c = get_prefix (f); + } + + /* Got a suitable first line for a paragraph. */ + + prefix_indent = next_prefix_indent; + first_indent = in_column; + wptr = parabuf; + word_limit = word; + c = get_line (f, c); + set_other_indent (same_para (c)); + + /* Read rest of paragraph (unless split is specified). */ + + if (split) + { + /* empty */ + } + else if (crown) + { + if (same_para (c)) + { + do + { /* for each line till the end of the para */ + c = get_line (f, c); + } + while (same_para (c) && in_column == other_indent); + } + } + else if (tagged) + { + if (same_para (c) && in_column != first_indent) + { + do + { /* for each line till the end of the para */ + c = get_line (f, c); + } + while (same_para (c) && in_column == other_indent); + } + } + else + { + while (same_para (c) && in_column == other_indent) + c = get_line (f, c); + } + (word_limit - 1)->period = (word_limit - 1)->final = TRUE; + next_char = c; + return TRUE; +} + +/* Copy to the output a line that failed to match the prefix, or that + was blank after the prefix. In the former case, C is the character + that failed to match the prefix. In the latter, C is \n or EOF. + Return the character (\n or EOF) ending the line. */ + +static int +copy_rest (FILE *f, register int c) +{ + register const char *s; + + out_column = 0; + if (in_column > next_prefix_indent && c != '\n' && c != EOF) + { + put_space (next_prefix_indent); + for (s = prefix; out_column != in_column && *s; out_column++) + putchar (*(unsigned char *)s++); + put_space (in_column - out_column); + } + while (c != '\n' && c != EOF) + { + putchar (c); + c = getc (f); + } + return c; +} + +/* Return TRUE if a line whose first non-blank character after the + prefix (if any) is C could belong to the current paragraph, + otherwise FALSE. */ + +static bool +same_para (register int c) +{ + return (next_prefix_indent == prefix_indent + && in_column >= next_prefix_indent + prefix_full_length + && c != '\n' && c != EOF); +} + +/* Read a line from input file F, given first non-blank character C + after the prefix, and the following indent, and break it into words. + A word is a maximal non-empty string of non-white characters. A word + ending in [.?!]["')\]]* and followed by end-of-line or at least two + spaces ends a sentence, as in emacs. + + Return the first non-blank character of the next line. */ + +static int +get_line (FILE *f, register int c) +{ + int start; + register char *end_of_parabuf; + register WORD *end_of_word; + + end_of_parabuf = ¶buf[MAXCHARS]; + end_of_word = &word[MAXWORDS - 2]; + + do + { /* for each word in a line */ + + /* Scan word. */ + + word_limit->text = wptr; + do + { + if (wptr == end_of_parabuf) + { + set_other_indent (true); + flush_paragraph (); + } + *wptr++ = c; + c = getc (f); + } + while (c != EOF && !ISSPACE (c)); + in_column += word_limit->length = wptr - word_limit->text; + check_punctuation (word_limit); + + /* Scan inter-word space. */ + + start = in_column; + c = get_space (f, c); + word_limit->space = in_column - start; + word_limit->final = (c == EOF + || (word_limit->period + && (c == '\n' || word_limit->space > 1))); + if (c == '\n' || c == EOF || uniform) + word_limit->space = word_limit->final ? 2 : 1; + if (word_limit == end_of_word) + { + set_other_indent (true); + flush_paragraph (); + } + word_limit++; + if (c == EOF) + return EOF; + } + while (c != '\n'); + return get_prefix (f); +} + +/* Read a prefix from input file F. Return either first non-matching + character, or first non-blank character after the prefix. */ + +static int +get_prefix (FILE *f) +{ + register int c; + + in_column = 0; + c = get_space (f, getc (f)); + if (prefix_length == 0) + next_prefix_indent = prefix_lead_space < in_column ? + prefix_lead_space : in_column; + else + { + const char *p; + next_prefix_indent = in_column; + for (p = prefix; *p != '\0'; p++) + { + if (c != *(unsigned char *)p) + return c; + in_column++; + c = getc (f); + } + c = get_space (f, c); + } + return c; +} + +/* Read blank characters from input file F, starting with C, and keeping + in_column up-to-date. Return first non-blank character. */ + +static int +get_space (FILE *f, register int c) +{ + for (;;) + { + if (c == ' ') + in_column++; + else if (c == '\t') + { + tabs = TRUE; + in_column = (in_column / TABWIDTH + 1) * TABWIDTH; + } + else + return c; + c = getc (f); + } +} + +/* Set extra fields in word W describing any attached punctuation. */ + +static void +check_punctuation (register WORD *w) +{ + const unsigned char *start, *finish; + + start = (unsigned char *) w->text; + finish = start + (w->length - 1); + w->paren = isopen (*start); + w->punct = ISPUNCT (*finish); + while (isclose (*finish) && finish > start) + finish--; + w->period = isperiod (*finish); +} + +/* Flush part of the paragraph to make room. This function is called on + hitting the limit on the number of words or characters. */ + +static void +flush_paragraph (void) +{ + WORD *split_point; + register WORD *w; + int shift; + COST best_break; + + /* In the special case where it's all one word, just flush it. */ + + if (word_limit == word) + { + printf ("%*s", wptr - parabuf, parabuf); + wptr = parabuf; + return; + } + + /* Otherwise: + - format what you have so far as a paragraph, + - find a low-cost line break near the end, + - output to there, + - make that the start of the paragraph. */ + + fmt_paragraph (); + + /* Choose a good split point. */ + + split_point = word_limit; + best_break = MAXCOST; + for (w = word->next_break; w != word_limit; w = w->next_break) + { + if (w->best_cost - w->next_break->best_cost < best_break) + { + split_point = w; + best_break = w->best_cost - w->next_break->best_cost; + } + if (best_break <= MAXCOST - LINE_CREDIT) + best_break += LINE_CREDIT; + } + put_paragraph (split_point); + + /* Copy text of words down to start of parabuf -- we use memmove because + the source and target may overlap. */ + + memmove (parabuf, split_point->text, (size_t) (wptr - split_point->text)); + shift = split_point->text - parabuf; + wptr -= shift; + + /* Adjust text pointers. */ + + for (w = split_point; w <= word_limit; w++) + w->text -= shift; + + /* Copy words from split_point down to word -- we use memmove because + the source and target may overlap. */ + + memmove ((char *) word, (char *) split_point, + (word_limit - split_point + 1) * sizeof (WORD)); + word_limit -= split_point - word; +} + +/* Compute the optimal formatting for the whole paragraph by computing + and remembering the optimal formatting for each suffix from the empty + one to the whole paragraph. */ + +static void +fmt_paragraph (void) +{ + register WORD *start, *w; + register int len; + register COST wcost, best; + int saved_length; + + word_limit->best_cost = 0; + saved_length = word_limit->length; + word_limit->length = max_width; /* sentinel */ + + for (start = word_limit - 1; start >= word; start--) + { + best = MAXCOST; + len = start == word ? first_indent : other_indent; + + /* At least one word, however long, in the line. */ + + w = start; + len += w->length; + do + { + w++; + + /* Consider breaking before w. */ + + wcost = line_cost (w, len) + w->best_cost; + if (start == word && last_line_length > 0) + wcost += RAGGED_COST (len - last_line_length); + if (wcost < best) + { + best = wcost; + start->next_break = w; + start->line_length = len; + } + + /* This is a kludge to keep us from computing `len' as the + sum of the sentinel length and some non-zero number. + Since the sentinel w->length may be INT_MAX, adding + to that would give a negative result. */ + if (w == word_limit) + break; + + len += (w - 1)->space + w->length; /* w > start >= word */ + } + while (len < max_width); + start->best_cost = best + base_cost (start); + } + + word_limit->length = saved_length; +} + +/* Return the constant component of the cost of breaking before the + word THIS. */ + +static COST +base_cost (register WORD *this) +{ + register COST cost; + + cost = LINE_COST; + + if (this > word) + { + if ((this - 1)->period) + { + if ((this - 1)->final) + cost -= SENTENCE_BONUS; + else + cost += NOBREAK_COST; + } + else if ((this - 1)->punct) + cost -= PUNCT_BONUS; + else if (this > word + 1 && (this - 2)->final) + cost += WIDOW_COST ((this - 1)->length); + } + + if (this->paren) + cost -= PAREN_BONUS; + else if (this->final) + cost += ORPHAN_COST (this->length); + + return cost; +} + +/* Return the component of the cost of breaking before word NEXT that + depends on LEN, the length of the line beginning there. */ + +static COST +line_cost (register WORD *next, register int len) +{ + register int n; + register COST cost; + + if (next == word_limit) + return 0; + n = best_width - len; + cost = SHORT_COST (n); + if (next->next_break != word_limit) + { + n = len - next->line_length; + cost += RAGGED_COST (n); + } + return cost; +} + +/* Output to stdout a paragraph from word up to (but not including) + FINISH, which must be in the next_break chain from word. */ + +static void +put_paragraph (register WORD *finish) +{ + register WORD *w; + + put_line (word, first_indent); + for (w = word->next_break; w != finish; w = w->next_break) + put_line (w, other_indent); +} + +/* Output to stdout the line beginning with word W, beginning in column + INDENT, including the prefix (if any). */ + +static void +put_line (register WORD *w, int indent) +{ + register WORD *endline; + + out_column = 0; + put_space (prefix_indent); + fputs (prefix, stdout); + out_column += prefix_length; + put_space (indent - out_column); + + endline = w->next_break - 1; + for (; w != endline; w++) + { + put_word (w); + put_space (w->space); + } + put_word (w); + last_line_length = out_column; + putchar ('\n'); +} + +/* Output to stdout the word W. */ + +static void +put_word (register WORD *w) +{ + register const char *s; + register int n; + + s = w->text; + for (n = w->length; n != 0; n--) + putchar (*s++); + out_column += w->length; +} + +/* Output to stdout SPACE spaces, or equivalent tabs. */ + +static void +put_space (int space) +{ + register int space_target, tab_target; + + space_target = out_column + space; + if (tabs) + { + tab_target = space_target / TABWIDTH * TABWIDTH; + if (out_column + 1 < tab_target) + while (out_column < tab_target) + { + putchar ('\t'); + out_column = (out_column / TABWIDTH + 1) * TABWIDTH; + } + } + while (out_column < space_target) + { + putchar (' '); + out_column++; + } +} diff --git a/src/apps/bin/coreutils-5.0/src/fold.c b/src/apps/bin/coreutils-5.0/src/fold.c new file mode 100644 index 0000000000..cf88673694 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/fold.c @@ -0,0 +1,319 @@ +/* fold -- wrap each input line to fit in specified width. + Copyright (C) 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie, djm@gnu.ai.mit.edu. */ + +#include + +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "posixver.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "fold" + +#define AUTHORS "David MacKenzie" + +/* The name this program was run with. */ +char *program_name; + +/* If nonzero, try to break on whitespace. */ +static int break_spaces; + +/* If nonzero, count bytes, not column positions. */ +static int count_bytes; + +/* If nonzero, at least one of the files we read was standard input. */ +static int have_read_stdin; + +static struct option const longopts[] = +{ + {"bytes", no_argument, NULL, 'b'}, + {"spaces", no_argument, NULL, 's'}, + {"width", required_argument, NULL, 'w'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + fputs (_("\ +Wrap input lines in each FILE (standard input by default), writing to\n\ +standard output.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -b, --bytes count bytes rather than columns\n\ + -s, --spaces break at spaces\n\ + -w, --width=WIDTH use WIDTH columns instead of 80\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Assuming the current column is COLUMN, return the column that + printing C will move the cursor to. + The first column is 0. */ + +static int +adjust_column (int column, char c) +{ + if (!count_bytes) + { + if (c == '\b') + { + if (column > 0) + column--; + } + else if (c == '\r') + column = 0; + else if (c == '\t') + column = column + 8 - column % 8; + else /* if (isprint (c)) */ + column++; + } + else + column++; + return column; +} + +/* Fold file FILENAME, or standard input if FILENAME is "-", + to stdout, with maximum line length WIDTH. + Return 0 if successful, 1 if an error occurs. */ + +static int +fold_file (char *filename, int width) +{ + FILE *istream; + register int c; + int column = 0; /* Screen column where next char will go. */ + int offset_out = 0; /* Index in `line_out' for next char. */ + static char *line_out = NULL; + static int allocated_out = 0; + + if (STREQ (filename, "-")) + { + istream = stdin; + have_read_stdin = 1; + } + else + istream = fopen (filename, "r"); + + if (istream == NULL) + { + error (0, errno, "%s", filename); + return 1; + } + + while ((c = getc (istream)) != EOF) + { + if (offset_out + 1 >= allocated_out) + { + allocated_out += 1024; + line_out = xrealloc (line_out, allocated_out); + } + + if (c == '\n') + { + line_out[offset_out++] = c; + fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); + column = offset_out = 0; + continue; + } + + rescan: + column = adjust_column (column, c); + + if (column > width) + { + /* This character would make the line too long. + Print the line plus a newline, and make this character + start the next line. */ + if (break_spaces) + { + /* Look for the last blank. */ + int logical_end; + + for (logical_end = offset_out - 1; logical_end >= 0; + logical_end--) + if (ISBLANK (line_out[logical_end])) + break; + if (logical_end >= 0) + { + int i; + + /* Found a blank. Don't output the part after it. */ + logical_end++; + fwrite (line_out, sizeof (char), (size_t) logical_end, + stdout); + putchar ('\n'); + /* Move the remainder to the beginning of the next line. + The areas being copied here might overlap. */ + memmove (line_out, line_out + logical_end, + offset_out - logical_end); + offset_out -= logical_end; + for (column = i = 0; i < offset_out; i++) + column = adjust_column (column, line_out[i]); + goto rescan; + } + } + else + { + if (offset_out == 0) + { + line_out[offset_out++] = c; + continue; + } + } + line_out[offset_out++] = '\n'; + fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); + column = offset_out = 0; + goto rescan; + } + + line_out[offset_out++] = c; + } + + if (offset_out) + fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); + + if (ferror (istream)) + { + error (0, errno, "%s", filename); + if (!STREQ (filename, "-")) + fclose (istream); + return 1; + } + if (!STREQ (filename, "-") && fclose (istream) == EOF) + { + error (0, errno, "%s", filename); + return 1; + } + + return 0; +} + +int +main (int argc, char **argv) +{ + int width = 80; + int i; + int optc; + int errs = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + break_spaces = count_bytes = have_read_stdin = 0; + + /* Turn any numeric options into -w options. */ + for (i = 1; i < argc; i++) + { + char const *a = argv[i]; + if (a[0] == '-') + { + if (a[1] == '-' && ! a[2]) + break; + if (ISDIGIT (a[1])) + { + char *s = xmalloc (strlen (a) + 2); + s[0] = '-'; + s[1] = 'w'; + strcpy (s + 2, a + 1); + argv[i] = s; + if (200112 <= posix2_version ()) + { + error (0, 0, _("`%s' option is obsolete; use `%s'"), a, s); + usage (EXIT_FAILURE); + } + } + } + } + + while ((optc = getopt_long (argc, argv, "bsw:", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + + case 'b': /* Count bytes rather than columns. */ + count_bytes = 1; + break; + + case 's': /* Break at word boundaries. */ + break_spaces = 1; + break; + + case 'w': /* Line width. */ + { + long int tmp_long; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long <= 0 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, + _("invalid number of columns: `%s'"), optarg); + width = (int) tmp_long; + } + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (argc == optind) + errs |= fold_file ("-", width); + else + for (i = optind; i < argc; i++) + errs |= fold_file (argv[i], width); + + if (have_read_stdin && fclose (stdin) == EOF) + error (EXIT_FAILURE, errno, "-"); + + exit (errs == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/foo b/src/apps/bin/coreutils-5.0/src/foo new file mode 100644 index 0000000000..95ef1b8868 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/foo @@ -0,0 +1,18991 @@ +# 1 "ls.c" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 1 "../lib/config.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 43 "ls.c" 2 + +# 1 "../../../../../headers/posix/sys/types.h" 1 + + + + + + + +typedef unsigned long u_long; +typedef unsigned int u_int; +typedef unsigned short u_short; +typedef unsigned char u_char; + + + + + typedef unsigned long ulong; + typedef unsigned short ushort; + typedef unsigned int uint; + +typedef unsigned char unchar; + + +typedef long long blkcnt_t; +typedef int blksize_t; +typedef long long fsblkcnt_t; +typedef long long fsfilcnt_t; +typedef long long off_t; +typedef long long ino_t; +typedef int cnt_t; +typedef long dev_t; +typedef long pid_t; + +typedef unsigned int uid_t; +typedef unsigned int gid_t; +typedef unsigned int mode_t; +typedef unsigned int umode_t; +typedef int nlink_t; + +typedef int daddr_t; +typedef char * caddr_t; + + +# 1 "../../../../../headers/posix/null.h" 1 + + + + + + + + + + + + + + +# 43 "../../../../../headers/posix/sys/types.h" 2 + +# 1 "../../../../../headers/posix/size_t.h" 1 + + + + + + + + + + + + +typedef unsigned long size_t; +typedef signed long ssize_t; + + + + + + +# 44 "../../../../../headers/posix/sys/types.h" 2 + +# 1 "../../../../../headers/posix/time.h" 1 + + + + + + + +# 1 "../../../../../headers/posix/sys/types.h" 1 + + + +# 47 "../../../../../headers/posix/sys/types.h" + +# 8 "../../../../../headers/posix/time.h" 2 + + + +typedef long clock_t; +typedef long time_t; +typedef long suseconds_t; +typedef long useconds_t; + + + + + + + +struct timespec { + time_t tv_sec; + long tv_nsec; +}; + +struct itimerspec { + struct timespec it_interval; + struct timespec it_value; +}; + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + int tm_gmtoff; + char *tm_zone; +}; + + + +extern char *tzname[2]; +extern int daylight; +extern long timezone; + + + + + + +extern clock_t clock(void); +extern double difftime(time_t time1, time_t time2); +extern time_t rpl_mktime (struct tm *tm); +extern time_t time(time_t *timer); +extern char *asctime(const struct tm *tm); +extern char *asctime_r(const struct tm *timep, char *buffer); +extern char *ctime(const time_t *timer); +extern char *ctime_r(const time_t *timer, char *buffer); +extern struct tm *gmtime(const time_t *timer); +extern struct tm *gmtime_r(const time_t *timer, struct tm *tm); +extern struct tm *localtime(const time_t *timer); +extern struct tm *localtime_r(const time_t *timer, struct tm *tm); +extern size_t strftime(char *buffer, size_t maxSize, const char *format, + const struct tm *tm); + + +extern void tzset(void); +extern int stime(const time_t *t); + + + + + + +# 45 "../../../../../headers/posix/sys/types.h" 2 + + + +# 44 "ls.c" 2 + + + +# 1 "../../../../../headers/posix/termios.h" 1 + + + + + + + + +# 1 "../../../../../headers/posix/unistd.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern int access(const char *path, int accessMode); + +extern int chdir(const char *path); +extern int fchdir(int fd); +extern char * rpl_getcwd (char *buffer, size_t size); + +extern int pipe(int fildes[2]); +extern int dup(int fd); +extern int dup2(int fd1, int fd2); +extern int close(int fd); +extern int link(const char *name, const char *new_name); +extern int unlink(const char *name); +extern int rmdir(const char *path); + +extern ssize_t readlink(const char *path, char *buffer, size_t bufferSize); +extern int symlink(const char *from, const char *to); + +extern int ftruncate(int fd, off_t newSize); +extern int truncate(const char *path, off_t newSize); +extern int ioctl(int fd, unsigned long op, ...); + +extern ssize_t read(int fd, void *buffer, size_t count); +extern ssize_t read_pos(int fd, off_t pos, void *buffer, size_t count); +extern ssize_t pread(int fd, void *buffer, size_t count, off_t pos); +extern ssize_t write(int fd, const void *buffer, size_t count); +extern ssize_t write_pos(int fd, off_t pos, const void *buffer,size_t count); +extern ssize_t pwrite(int fd, const void *buffer, size_t count, off_t pos); +extern off_t lseek(int fd, off_t offset, int whence); + +extern int sync(void); +extern int fsync(int fd); + +extern int rpl_chown (const char *path, uid_t owner, gid_t group); +extern int fchown(int fd, uid_t owner, gid_t group); +extern int lchown(const char *path, uid_t owner, gid_t group); + +extern int mknod(const char *name, mode_t mode, dev_t dev); + + + + + +extern int mount(const char *filesystem, const char *where, const char *device, + ulong flags, void *parms, int len); +extern int unmount(const char *path); + +extern int getdtablesize(void); +extern long sysconf(int name); +extern long fpathconf(int fd, int name); +extern long pathconf(const char *path, int name); + + +extern pid_t fork(void); +extern int execve(const char *path, char * const argv[], char * const envp[]); +extern int execl(const char *path, const char *arg, ...); +extern int execv(const char *path, char *const *argv); +extern int execlp(const char *file, const char *arg, ...); +extern int execle(const char *path, const char *arg , ... ); +extern int exect(const char *path, char *const *argv); +extern int execvp(const char *file, char *const *argv); + +extern void _exit(int status); + +extern int system(const char *string); +extern pid_t tcgetpgrp(int fd); +extern int tcsetpgrp(int fd, pid_t pgrpid); +extern void *sbrk(long incr); + +extern uint alarm(unsigned int seconds); +extern uint ualarm(unsigned int microSeconds); +extern uint sleep(unsigned int seconds); +extern int usleep(unsigned int microSeconds); +extern clock_t clock(void); +extern int pause(void); + + +extern pid_t getpgrp(void); +extern pid_t getpid(void); +extern pid_t getppid(void); + +extern pid_t setsid(void); +extern int setpgid(pid_t pid, pid_t pgid); + + +extern gid_t getegid(void); +extern uid_t geteuid(void); +extern gid_t getgid(void); +extern int getgroups(int groupSize, gid_t groupList[]); +extern uid_t getuid(void); +extern char *cuserid(char *s); + +extern int setgid(gid_t gid); +extern int setuid(uid_t uid); + +extern char *getlogin(void); +extern int getlogin_r(char *name, size_t nameSize); + + +extern int sethostname(const char *hostName, size_t nameSize); +extern int gethostname(char *hostName, size_t nameSize); + + +extern int isatty(int fd); +extern char *ttyname(int fd); +extern int ttyname_r(int fd, char *buffer, size_t bufferSize); +extern char *ctermid(char *s); + + +extern char *crypt(const char *key, const char *salt); +extern int getopt(int argc, char *const *argv, const char *shortOpts); + + +extern char *optarg; +extern int optind, opterr, optopt; + + +extern char **environ; + + + + + + +# 9 "../../../../../headers/posix/termios.h" 2 + + + + + + + + + + + + + + + + + + + + + + + + +typedef unsigned long tcflag_t; +typedef unsigned char speed_t; +typedef unsigned char cc_t; + +struct termios { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + char c_line; + speed_t c_ixxxxx; + speed_t c_oxxxxx; + cc_t c_cc[11 ]; +}; + + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern speed_t cfgetispeed( const struct termios *); +extern speed_t cfgetospeed( const struct termios *); +extern int cfsetispeed( struct termios *, speed_t); +extern int cfsetospeed( struct termios *, speed_t); +extern int tcsetattr( int fd, int opt, const struct termios *tp); + + + + + + + + + +int tcsendbreak(int fd, int duration); +int tcdrain(int fd); +int tcflow(int fd, int action); + + + + + + + + + + +int tcflush(int fd, int queue_selector); + + + + + + + + +int tcsetpgrp(int fd, pid_t pgrpid); +pid_t tcgetpgrp(int fd); + + + + + + +# 47 "ls.c" 2 + + + + + + + + + + + + +# 1 "/boot/develop/headers/posix/stdio.h" 1 + + + +# 1 "/boot/develop/headers/posix/be_setup.h" 1 + + + + + + + + + + + +# 22 "/boot/develop/headers/posix/be_setup.h" + + + + + + + + +# 1 "../../../../../headers/os/BeBuild.h" 1 + + + + + + + + + + + + + + + + + + + + +# 30 "../../../../../headers/os/BeBuild.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 374 "../../../../../headers/os/BeBuild.h" + + +typedef struct GLUnurbs GLUnurbs; +typedef struct GLUquadric GLUquadric; +typedef struct GLUtesselator GLUtesselator; + +typedef struct GLUnurbs GLUnurbsObj; +typedef struct GLUquadric GLUquadricObj; +typedef struct GLUtesselator GLUtesselatorObj; +typedef struct GLUtesselator GLUtriangulatorObj; + + + + +# 30 "/boot/develop/headers/posix/be_setup.h" 2 + + + +# 4 "/boot/develop/headers/posix/stdio.h" 2 + + + + +# 1 "/boot/develop/headers/posix/va_list.h" 1 + + + + + +# 1 "../../../../../headers/posix/stdarg.h" 1 + + + + + + + + + + +# 1 "/boot/develop/headers/posix/stdarg.h" 1 + + + + +# 1 "/boot/develop/tools/gnupro/lib/gcc-lib/i586-beos/2.9-beos-991026/include/stdarg.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef char *__gnuc_va_list; + + + + + + + + + + + + + + + + + + + + + + + + +void va_end (__gnuc_va_list); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 208 "/boot/develop/tools/gnupro/lib/gcc-lib/i586-beos/2.9-beos-991026/include/stdarg.h" + + + + + + + + + + + + + + + +typedef __gnuc_va_list va_list; + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 5 "/boot/develop/headers/posix/stdarg.h" 2 + + +# 24 "/boot/develop/headers/posix/stdarg.h" + + +# 11 "../../../../../headers/posix/stdarg.h" 2 + + +# 6 "/boot/develop/headers/posix/va_list.h" 2 + + + + + + + + + +# 8 "/boot/develop/headers/posix/stdio.h" 2 + +# 1 "../../../../../headers/posix/wchar_t.h" 1 + + + + + + + + + +typedef unsigned short wchar_t; + + +typedef unsigned int wint_t; + +typedef struct { + int __count; + wint_t __value; +} int ; + + + +# 9 "/boot/develop/headers/posix/stdio.h" 2 + + +typedef long long fpos_t; + + +# 1 "/boot/develop/headers/posix/gnu_stdio.h" 1 + + + + + + + +# 1 "../../../../../headers/posix/stddef.h" 1 + + + + + + + + + +typedef long ptrdiff_t; + + + + + +# 8 "/boot/develop/headers/posix/gnu_stdio.h" 2 + + + +# 1 "/boot/develop/headers/posix/_G_config.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef int _G_int16_t __attribute__ ((__mode__ (__HI__))); +typedef int _G_int32_t __attribute__ ((__mode__ (__SI__))); +typedef unsigned int _G_uint16_t __attribute__ ((__mode__ (__HI__))); +typedef unsigned int _G_uint32_t __attribute__ ((__mode__ (__SI__))); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 11 "/boot/develop/headers/posix/gnu_stdio.h" 2 + + + + + + + + + + + + + + + + +# 1 "/boot/develop/headers/posix/libio.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 103 "/boot/develop/headers/posix/libio.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct _IO_jump_t; struct _IO_FILE; + + + + + + + + + +typedef void _IO_lock_t; + + + + + +struct _IO_marker { + struct _IO_marker *_next; + struct _IO_FILE *_sbuf; + + + + int _pos; +# 191 "/boot/develop/headers/posix/libio.h" + +}; + +struct _IO_FILE { + int _flags; + + + + + char* _IO_read_ptr; + char* _IO_read_end; + char* _IO_read_base; + char* _IO_write_base; + char* _IO_write_ptr; + char* _IO_write_end; + char* _IO_buf_base; + char* _IO_buf_end; + + char *_IO_save_base; + char *_IO_backup_base; + char *_IO_save_end; + + struct _IO_marker *_markers; + + struct _IO_FILE *_chain; + + int _fileno; + int _blksize; + off_t _old_offset; + + + + unsigned short _cur_column; + signed char _vtable_offset; + char _shortbuf[1]; + + + + _IO_lock_t *_lock; + + + + + + + + + off_t _offset; + char *_IO_save_ptr; + + char _unused2[16 * sizeof (int) - sizeof (char *)]; + +}; + + +typedef struct _IO_FILE _IO_FILE; + + +struct _IO_FILE_plus; +extern struct _IO_FILE_plus _IO_2_1_stdin_; +extern struct _IO_FILE_plus _IO_2_1_stdout_; +extern struct _IO_FILE_plus _IO_2_1_stderr_; + + + + + + + + + + + + +typedef struct +{ + ssize_t (*read) (struct _IO_FILE *, void *, ssize_t ) ; + ssize_t (*write) (struct _IO_FILE *, const void *, ssize_t ) ; + off_t (*seek) (struct _IO_FILE *, off_t , int) ; + int (*close) (struct _IO_FILE *) ; +} _IO_cookie_io_functions_t; + + +struct _IO_cookie_file +{ + struct _IO_FILE file; + const void *vtable; + void *cookie; + _IO_cookie_io_functions_t io_functions; +}; + + + + + + +extern int __underflow (_IO_FILE *) ; +extern int __uflow (_IO_FILE *) ; +extern int __overflow (_IO_FILE *, int) ; + + + + + + + + + + + + + + + + +extern int _IO_getc (_IO_FILE *__fp) ; +extern int _IO_putc (int __c, _IO_FILE *__fp) ; +extern int _IO_feof (_IO_FILE *__fp) ; +extern int _IO_ferror (_IO_FILE *__fp) ; + +extern int _IO_peekc_locked (_IO_FILE *__fp) ; + + + + + +extern void _IO_flockfile (_IO_FILE *) ; +extern void _IO_funlockfile (_IO_FILE *) ; +extern int _IO_ftrylockfile (_IO_FILE *) ; + + + + + + + + + + + + +extern int _IO_vfscanf (_IO_FILE *, const char *, __gnuc_va_list , int *) ; +extern int _IO_vfprintf (_IO_FILE *, const char *, __gnuc_va_list ) ; +extern ssize_t _IO_padn (_IO_FILE *, int, ssize_t ) ; +extern size_t _IO_sgetn (_IO_FILE *, void *, size_t ) ; + +extern off_t _IO_seekoff (_IO_FILE *, off_t , int, int) ; +extern off_t _IO_seekpos (_IO_FILE *, off_t , int) ; + +extern void _IO_free_backup_area (_IO_FILE *) ; + + + + + + +# 27 "/boot/develop/headers/posix/gnu_stdio.h" 2 + + +typedef struct _IO_FILE FILE; + + + + + + +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + +extern char *tmpnam_r(char *__s); +extern int fflush_unlocked(FILE *__stream); +extern int vfprintf(FILE *__s, const char * __format, va_list __arg); +extern int vprintf(const char *__format, va_list __arg); + +extern __inline int +vprintf (const char * __fmt, va_list __arg) +{ + return vfprintf (stdout, __fmt, __arg); +} + +extern int snprintf(char * __s, size_t __maxlen, const char * __format, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); +extern int vsnprintf(char * __s, size_t __maxlen, const char * __format, va_list __arg) + __attribute__ ((__format__ (__printf__, 3, 0))); + +extern char _single_threaded; +extern int getchar(void); +extern int getc(FILE *__stream); +extern int putchar(int __c); + + + +extern __inline int +getchar(void) { return (_single_threaded ? (( stdin )->_IO_read_ptr >= ( stdin )->_IO_read_end ? __uflow ( stdin ) : *(unsigned char *) ( stdin )->_IO_read_ptr++) : _IO_getc ( stdin )) ; } + +extern int getc_unlocked(FILE *__stream); +extern int getchar_unlocked(void); + +extern __inline int +getc_unlocked (FILE *__fp) { return (( __fp )->_IO_read_ptr >= ( __fp )->_IO_read_end ? __uflow ( __fp ) : *(unsigned char *) ( __fp )->_IO_read_ptr++) ; } + +extern __inline int +getchar_unlocked (void) { return (( stdin )->_IO_read_ptr >= ( stdin )->_IO_read_end ? __uflow ( stdin ) : *(unsigned char *) ( stdin )->_IO_read_ptr++) ; } + +extern int fputc(int __c, FILE *__stream); +extern int putc(int __c, FILE *__stream); + + + +extern __inline int +putchar(int __c) { return (_single_threaded ? ((( stdout )->_IO_write_ptr >= ( stdout )->_IO_write_end) ? __overflow ( stdout , (unsigned char) ( __c )) : (unsigned char) (*( stdout )->_IO_write_ptr++ = ( __c ))) : _IO_putc ( __c , stdout )) ; } + +extern int fputc_unlocked (int __c, FILE *__stream) ; +extern __inline int +fputc_unlocked (int __c, FILE *__stream) { return ((( __stream )->_IO_write_ptr >= ( __stream )->_IO_write_end) ? __overflow ( __stream , (unsigned char) ( __c )) : (unsigned char) (*( __stream )->_IO_write_ptr++ = ( __c ))) ; } + +extern int putc_unlocked (int __c, FILE *__stream); +extern int putchar_unlocked (int __c) ; + +extern __inline int +putc_unlocked (int __c, FILE *__stream) { return ((( __stream )->_IO_write_ptr >= ( __stream )->_IO_write_end) ? __overflow ( __stream , (unsigned char) ( __c )) : (unsigned char) (*( __stream )->_IO_write_ptr++ = ( __c ))) ; } + +extern __inline int +putchar_unlocked (int __c) { return ((( stdout )->_IO_write_ptr >= ( stdout )->_IO_write_end) ? __overflow ( stdout , (unsigned char) ( __c )) : (unsigned char) (*( stdout )->_IO_write_ptr++ = ( __c ))) ; } + +extern size_t fread_unlocked(void *__ptr, size_t __size, + size_t __n, FILE *__stream); +extern size_t fwrite_unlocked(__const void *__ptr, size_t __size, + size_t __n, FILE *__stream); + +extern int fsetpos (FILE *__stream, __const fpos_t *__pos); +extern void clearerr_unlocked (FILE *__stream); +extern int feof_unlocked (FILE *__stream) ; +extern int ferror_unlocked (FILE *__stream) ; + +extern __inline int +feof_unlocked (FILE *__stream) { return ((( __stream )->_flags & 0x10 ) != 0) ; } + +extern __inline int +ferror_unlocked (FILE *__stream) { return ((( __stream )->_flags & 0x20 ) != 0) ; } + +extern int fileno_unlocked(FILE *__stream); +extern void flockfile(FILE *__stream); +extern int ftrylockfile(FILE *__stream); +extern void funlockfile(FILE *__stream); + + + + + + +# 14 "/boot/develop/headers/posix/stdio.h" 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +FILE *popen(const char *cmd, const char *type); +int pclose(FILE *fp); + +int remove(const char *name); +int rename(const char *old_name, const char *new_name); + +char *tempnam(char *dir, char *pfx); +char *tmpnam(char *name); +FILE *tmpfile(void); + +FILE *fopen (const char *name, const char *mode); +FILE *freopen(const char *name, const char *mode, FILE *file); + +FILE *fdopen(int fd, const char *type); +int fileno(FILE *fd); + +int fclose(FILE *file); +int fflush(FILE *file); + +int printf(const char *format, ...); +int fprintf(FILE *file, const char *format, ...); +int sprintf(char *s, const char *format, ...); +int vfprintf(FILE *file, const char *format, va_list arg); +int vprintf(const char *format, va_list arg); + +int asprintf (char **string_ptr, const char *format, ...); + + +int scanf (const char *format, ...); +int fscanf (FILE *file, const char *format, ...); +int sscanf (const char *s, const char *format, ...); +int vsprintf(char *s, const char *format, va_list arg); + +int (getchar)(void); +int (getc)(FILE *file); + +int (putchar)(int c); +int (putc)(int c, FILE *file); + +char *gets(char *s); +char *fgets(char *s, int n, FILE *file); +int fgetc(FILE *file); + +int puts(const char *s); +int (fputc)(int c, FILE *file); +int fputs(const char *s, FILE *file); + +int (ungetc)(int c, FILE *file); + +size_t fread(void *ptr, size_t memb_size, size_t num_memb, FILE *file); +size_t fwrite(const void *ptr, size_t memb_size, size_t num_memb, FILE *file); + +int fgetpos(FILE *file, fpos_t *pos); +long ftell(FILE *file); +fpos_t _ftell(FILE *); + +int fsetpos(FILE *file, const fpos_t *pos); +int fseek(FILE *file, long offset, int mode); +int _fseek(FILE *, fpos_t, int); + +void setbuf (FILE *file, char *buff); +int setvbuf(FILE *file, char *buff, int mode, size_t size); +int setbuffer(FILE *stream, char *buf, size_t size); +int setlinebuf(FILE *stream); + +void rewind(FILE *file); +void clearerr(FILE *file); + +void perror(const char *s); + +int (feof)(FILE *file); +int (ferror)(FILE *file); + + + + +# 59 "ls.c" 2 + +# 1 "/boot/develop/headers/posix/assert.h" 1 + + + + + + + + + + + + + + + + + + +extern void __assert_fail(const char *__assertion, + const char *__file, + unsigned int __line, + const char *__function); + + +extern void __assert_perror_fail(int __errnum, + const char *__file, + unsigned int __line, + const char *__function); + + + + + + + + +# 47 "/boot/develop/headers/posix/assert.h" + + + + + +# 60 "ls.c" 2 + +# 1 "/boot/develop/headers/posix/setjmp.h" 1 + + + + + +# 20 "/boot/develop/headers/posix/setjmp.h" + + +# 1 "../../../../../headers/posix/signal.h" 1 + + + + + + + + + + +typedef int sig_atomic_t; +typedef long sigset_t; + +typedef void (*sig_func_t)(int); +typedef void (*__signal_func_ptr)(int); + + + + + + + + + + + + + + + + + +struct sigaction { + sig_func_t sa_handler; + sigset_t sa_mask; + int sa_flags; + void *sa_userdata; +}; + + + + + + + + + + + + + + + + + +typedef struct stack_t { + void *ss_sp; + size_t ss_size; + int ss_flags; +} stack_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern const char * const sys_siglist[(22 +1) ]; + + + + + + + +sig_func_t signal(int sig, sig_func_t signal_handler); +int raise(int sig); +int kill(pid_t pid, int sig); +int send_signal(pid_t tid, uint sig); + +int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); +int sigprocmask(int how, const sigset_t *set, sigset_t *oset); +int sigpending(sigset_t *set); +int sigsuspend(const sigset_t *mask); + +int sigemptyset(sigset_t *set); +int sigfillset(sigset_t *set); +static int sigaddset(sigset_t *set, int signo); +static int sigdelset(sigset_t *set, int signo); +static int sigismember(const sigset_t *set, int signo); + +const char *strsignal(int sig); + +const void set_signal_stack(void *ptr, size_t size); +int sigaltstack(const stack_t *ss, stack_t *oss); + +static inline int +sigismember(const sigset_t *set, int sig) +{ + sigset_t mask = (((sigset_t) 1) << (( sig ) - 1)) ; + return (*set & mask) ? 1 : 0 ; +} + +static inline int +sigaddset(sigset_t *set, int sig) +{ + sigset_t mask = (((sigset_t) 1) << (( sig ) - 1)) ; + return ((*set |= mask), 0) ; +} + +static inline int +sigdelset(sigset_t *set, int sig) +{ + sigset_t mask = (((sigset_t) 1) << (( sig ) - 1)) ; + return ((*set &= ~mask), 0) ; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef struct vregs vregs; + +# 265 "../../../../../headers/posix/signal.h" + + + + +typedef struct packed_fp_stack { + unsigned char st0[10]; + unsigned char st1[10]; + unsigned char st2[10]; + unsigned char st3[10]; + unsigned char st4[10]; + unsigned char st5[10]; + unsigned char st6[10]; + unsigned char st7[10]; +} packed_fp_stack; + +typedef struct packed_mmx_regs { + unsigned char mm0[10]; + unsigned char mm1[10]; + unsigned char mm2[10]; + unsigned char mm3[10]; + unsigned char mm4[10]; + unsigned char mm5[10]; + unsigned char mm6[10]; + unsigned char mm7[10]; +} packed_mmx_regs; + +typedef struct old_extended_regs { + unsigned short fp_control; + unsigned short _reserved1; + unsigned short fp_status; + unsigned short _reserved2; + unsigned short fp_tag; + unsigned short _reserved3; + unsigned long fp_eip; + unsigned short fp_cs; + unsigned short fp_opcode; + unsigned long fp_datap; + unsigned short fp_ds; + unsigned short _reserved4; + union { + packed_fp_stack fp; + packed_mmx_regs mmx; + } fp_mmx; +} old_extended_regs; + +typedef struct fp_stack { + unsigned char st0[10]; + unsigned char _reserved_42_47[6]; + unsigned char st1[10]; + unsigned char _reserved_58_63[6]; + unsigned char st2[10]; + unsigned char _reserved_74_79[6]; + unsigned char st3[10]; + unsigned char _reserved_90_95[6]; + unsigned char st4[10]; + unsigned char _reserved_106_111[6]; + unsigned char st5[10]; + unsigned char _reserved_122_127[6]; + unsigned char st6[10]; + unsigned char _reserved_138_143[6]; + unsigned char st7[10]; + unsigned char _reserved_154_159[6]; +} fp_stack; + +typedef struct mmx_regs { + unsigned char mm0[10]; + unsigned char _reserved_42_47[6]; + unsigned char mm1[10]; + unsigned char _reserved_58_63[6]; + unsigned char mm2[10]; + unsigned char _reserved_74_79[6]; + unsigned char mm3[10]; + unsigned char _reserved_90_95[6]; + unsigned char mm4[10]; + unsigned char _reserved_106_111[6]; + unsigned char mm5[10]; + unsigned char _reserved_122_127[6]; + unsigned char mm6[10]; + unsigned char _reserved_138_143[6]; + unsigned char mm7[10]; + unsigned char _reserved_154_159[6]; +} mmx_regs; + +typedef struct xmmx_regs { + unsigned char xmm0[16]; + unsigned char xmm1[16]; + unsigned char xmm2[16]; + unsigned char xmm3[16]; + unsigned char xmm4[16]; + unsigned char xmm5[16]; + unsigned char xmm6[16]; + unsigned char xmm7[16]; +} xmmx_regs; + +typedef struct new_extended_regs { + unsigned short fp_control; + unsigned short fp_status; + unsigned short fp_tag; + unsigned short fp_opcode; + unsigned long fp_eip; + unsigned short fp_cs; + unsigned short res_14_15; + unsigned long fp_datap; + unsigned short fp_ds; + unsigned short _reserved_22_23; + unsigned long mxcsr; + unsigned long _reserved_28_31; + union { + fp_stack fp; + mmx_regs mmx; + } fp_mmx; + xmmx_regs xmmx; + unsigned char _reserved_288_511[224]; +} new_extended_regs; + +typedef struct extended_regs { + union { + old_extended_regs old_format; + new_extended_regs new_format; + } state; + unsigned long format; +} extended_regs; + +struct vregs { + unsigned long eip; + unsigned long eflags; + unsigned long eax; + unsigned long ecx; + unsigned long edx; + unsigned long esp; + unsigned long ebp; + unsigned long _reserved_1; + extended_regs xregs; + unsigned long _reserved_2[3]; +}; + + + + + +# 22 "/boot/develop/headers/posix/setjmp.h" 2 + + +typedef int __jmp_buf[6]; +typedef struct __jmp_buf_tag + { + + + + __jmp_buf __jmpbuf; + int __mask_was_saved; + sigset_t __saved_mask; + } jmp_buf[1]; + + + +int __sigsetjmp(jmp_buf env, int savemask); + + + +typedef jmp_buf sigjmp_buf; + + + + + + + + +void longjmp(jmp_buf,int); + +void siglongjmp(sigjmp_buf jmp, int val); + + + + + +# 61 "ls.c" 2 + +# 1 "/boot/develop/headers/posix/grp.h" 1 + + + + + + +struct group { + char *gr_name; + char *gr_passwd; + int gr_gid; + char **gr_mem; +}; + + + + +extern struct group *getgrgid(gid_t gid); +extern struct group *getgrnam(const char *name); + +extern struct group *getgrent(void); +extern void setgrent(void); +extern void endgrent(void); + + + + +# 62 "ls.c" 2 + +# 1 "../../../../../headers/posix/pwd.h" 1 + + + + + + + + + + + + +struct passwd { + char *pw_name; + char *pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + char *pw_dir; + char *pw_shell; + char *pw_gecos; +}; + + +extern struct passwd *getpwent(void); +extern void setpwent(void); +extern void endpwent(void); + + +extern struct passwd *getpwnam(const char *name); +extern int getpwnam_r(const char *name, struct passwd *passwd, char *buffer, + size_t bufferSize, struct passwd **result); +extern struct passwd *getpwuid(uid_t uid); +extern int getpwuid_r(uid_t uid, struct passwd *passwd, char *buffer, + size_t bufferSize, struct passwd **result); + + + + + + +# 63 "ls.c" 2 + +# 1 "../lib/getopt.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 1 "../../../../../headers/posix/ctype.h" 1 + + + + + + + +int isalnum(int); +int isalpha(int); +int isascii(int); +int isblank(int); +int iscntrl(int); +int isdigit(int); +int isgraph(int); +int islower(int); +int isprint(int); +int ispunct(int); +int isspace(int); +int isupper(int); +int isxdigit(int); +int toascii(int); +int tolower(int); +int toupper(int); + + + + + + + + + +# 33 "../lib/getopt.h" 2 + + + + + + + + + + + + + +extern char *optarg; + + + + + + + + + + + + + +extern int optind; + + + + +extern int opterr; + + + +extern int optopt; + + + + + + + + + + + + + + + + + + + + + + + +struct option +{ + + const char *name; + + + + + + int has_arg; + int *flag; + int val; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern int getopt (); + + + +extern int getopt_long (int ___argc, char *const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); +extern int getopt_long_only (int ___argc, char *const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); + + +extern int _getopt_internal (int ___argc, char *const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only); + +# 171 "../lib/getopt.h" + + + + + + + + + + +# 64 "ls.c" 2 + + + + + +# 1 "../../../../../headers/posix/stdlib.h" 1 + + + + + + + +# 1 "../../../../../headers/posix/div_t.h" 1 + + + + + + +typedef struct { + int quot; + int rem; +} div_t; + +typedef struct { + long quot; + long rem; +} ldiv_t; + +typedef struct { + long long quot; + long long rem; +} lldiv_t; + + +# 8 "../../../../../headers/posix/stdlib.h" 2 + + + +# 1 "../../../../../headers/posix/limits.h" 1 + + + +# 1 "../../../../../headers/posix/float.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 4 "../../../../../headers/posix/limits.h" 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 11 "../../../../../headers/posix/stdlib.h" 2 + +# 1 "../../../../../headers/posix/alloca.h" 1 + + + + + + + + + + + + + + + + + +extern void * __alloca (size_t __size); +extern void * alloca (size_t __size); + + + + + + + + + +# 12 "../../../../../headers/posix/stdlib.h" 2 + + + + + + + + + + +struct random_data { + int *fptr; + int *rptr; + int *state; + int rand_type; + int rand_deg; + int rand_sep; + int *end_ptr; +}; + +struct drand48_data { + unsigned short int x[3]; + unsigned short int a[3]; + unsigned short int c; + unsigned short int old_x[3]; + int init; +}; + + + + + + + +extern void *calloc(size_t nmemb, size_t size); +extern void free(void *pointer); +extern void *malloc(size_t size); +extern void *realloc(void * ptr, size_t size); + + +extern void abort(void); +extern int atexit(void (*func)(void)); +extern int atfork(void (*func)(void)); +extern void exit(int); + + +extern char *realpath(const char *path, char *resolved); + +extern int daemon(int nochdir, int noclose); +extern int system(const char *command); + +extern char *mktemp(char *name); +extern int mkstemp(char *templat); + + +extern char **environ; +extern char *getenv(const char *name); +extern int rpl_putenv (const char *string); +extern int setenv(char const *name, char const *value, int rewrite); +extern int unsetenv(const char *name); + + +extern double atof(const char *string); +extern int atoi(const char *string); +extern long atol(const char *string); +extern long long int atoll(const char *string); +extern unsigned int atoui(const char *string); +extern unsigned long atoul(const char *string); + +extern double strtod(const char *string, char **end); +extern long strtol(const char *string, char **end, int base); +extern unsigned long strtoul(const char *string, char **end, int base); +extern long long strtoll(const char *string, char **end, int base); +extern unsigned long long strtoull(const char *string, char **end, int base); + + + + + +extern void srand(unsigned int seed); +extern int rand(void); +extern int random(void); +extern void srandom(unsigned int seed); +extern int rand_r(unsigned int *seed); +extern int random_r(struct random_data *data, int *result); +extern int srandom_r(unsigned int seed, struct random_data *data); +extern char *initstate(unsigned int seed, char *state, size_t size); +extern char *setstate(char *state); +extern int initstate_r(unsigned int seed, void *stateBuffer, + size_t stateLength, struct random_data *data); +extern int setstate_r(void *stateBuffer, struct random_data *data); + +extern double drand48(void); +extern double erand48(unsigned short int xsubi[3]); +extern long lrand48(void); +extern long nrand48(unsigned short int xsubi[3]); +extern long mrand48(void); +extern long jrand48(unsigned short int xsubi[3]); +extern void srand48(long int seed); +extern unsigned short *seed48(unsigned short int seed16v[3]); +extern void lcong48(unsigned short int param[7]); + +extern int drand48_r(struct drand48_data *data, double *result); +extern int erand48_r(unsigned short int xsubi[3], + struct drand48_data *data, double *result); +extern int lrand48_r(struct drand48_data *data, long int *result); +extern int nrand48_r(unsigned short int xsubi[3], + struct drand48_data *data, long int *result); +extern int mrand48_r(struct drand48_data *data, long int *result); +extern int jrand48_r(unsigned short int xsubi[3], + struct drand48_data *data, long int *result); +extern int srand48_r(long int seed, struct drand48_data *data); +extern int seed48_r(unsigned short int seed16v[3], + struct drand48_data *data); +extern int lcong48_r(unsigned short int param[7], + struct drand48_data *data); + + +typedef int (*_compare_function)(const void *, const void *); + +extern void *bsearch(const void *key, const void *base, size_t numElements, + size_t sizeOfElement, _compare_function); +extern int heapsort(void *base, size_t numElements, size_t sizeOfElement, _compare_function); +extern int mergesort(void *base, size_t numElements, size_t sizeOfElement, _compare_function); +extern void qsort(void *base, size_t numElements, size_t sizeOfElement, _compare_function); +extern int radixsort(u_char const **base, int numElements, u_char const *table, u_int endByte); +extern int sradixsort(u_char const **base, int numElements, u_char const *table, u_int endByte); + + +extern int abs(int number); +extern long labs(long number); +extern long long llabs(long long number); + +extern div_t div(int numerator, int denominator); +extern ldiv_t ldiv(long numerator, long denominator); +extern lldiv_t lldiv(long long numerator, long long denominator); + + +extern int mblen(const char *string, size_t maxSize); +extern int mbtowc(wchar_t *pwc, const char *string, size_t maxSize); +extern int wctomb(char *string, wchar_t wchar); +extern size_t mbstowcs(wchar_t *pwcs, const char *string, size_t maxSize); +extern size_t wcstombs(char *string, const wchar_t *pwcs, size_t maxSize); + + + + + + +# 69 "ls.c" 2 + + + + + +# 1 "../../../../../headers/posix/wchar.h" 1 + + + + + + + + + + + + + +int mbsinit(const int *); +size_t wcrtomb(char *, wchar_t, int *); + + +# 74 "ls.c" 2 + + + + + + + + + + + + + + + +int wcwidth (); + + + + + + + + + + +# 1 "system.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + +# 1 "../../../../../headers/posix/sys/stat.h" 1 + + + + + + + + + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + off_t st_size; + + + unsigned int st_type; + + size_t st_blksize; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; + time_t st_crtime; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern int chmod(const char *path, mode_t mode); +extern int fchmod(int fd, mode_t mode); +extern int stat(const char *path, struct stat *buf); +extern int fstat(int fd, struct stat *buf); +extern int lstat(const char *path, struct stat *st); +extern int rpl_mkdir (const char *path, mode_t mode); +extern int mkfifo(const char *path, mode_t mode); +extern mode_t umask(mode_t cmask); + + + + + + +# 26 "system.h" 2 + + + + + + + +# 1 "../../../../../headers/posix/sys/param.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + +# 33 "system.h" 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 1 "../lib/pathmax.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 61 "system.h" 2 + + + +# 1 "../../../../../headers/posix/sys/time.h" 1 + + + + + + + + + + +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; + +# 1 "../../../../../headers/posix/sys/select.h" 1 + + + + + + + +# 1 "../../../../../headers/posix/sys/time.h" 1 +# 52 "../../../../../headers/posix/sys/time.h" + +# 8 "../../../../../headers/posix/sys/select.h" 2 + + + + + + + + + + + + + + + + +typedef unsigned long fd_mask; + + + + + + + +typedef struct fd_set { + fd_mask bits[((( 1024 ) + (( (sizeof(fd_mask) * 8) ) - 1)) / ( (sizeof(fd_mask) * 8) )) ]; +} fd_set; + + + + + + + + + + + + + + + +extern int pselect(int numBits, struct fd_set *readBits, struct fd_set *writeBits, + struct fd_set *errorBits, const struct timespec *timeout, const sigset_t *sigMask); +extern int select(int numBits, struct fd_set *readBits, struct fd_set *writeBits, + struct fd_set *errorBits, struct timeval *timeout); + + + + + + +# 16 "../../../../../headers/posix/sys/time.h" 2 + + + + + + +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; + +struct itimerval { + struct timeval it_interval; + struct timeval it_value; +}; + + + + + + + + + + +extern int getitimer(int which, struct itimerval *value); +extern int setitimer(int which, const struct itimerval *value, struct itimerval *oldValue); +extern int gettimeofday(struct timeval *tv, struct timezone *tz); + +extern int utimes(const char *name, const struct timeval times[2]); + + + + + + + +# 64 "system.h" 2 + + + + + + + + + + + + + + + + +# 1 "/boot/develop/headers/posix/sys/sysmacros.h" 1 + + + + + + + + + + + + + + +# 80 "system.h" 2 + + + + + + + + + + + + + + + +# 1 "../../../../../headers/posix/utime.h" 1 + + + + + + + + + +struct utimbuf +{ + time_t actime; + time_t modtime; +}; + + +extern + + + +int utime(const char *path, const struct utimbuf *buffer); + + +# 95 "system.h" 2 + + + + + + + + + + + + + + + + + + + + +# 1 "../../../../../headers/posix/string.h" 1 + + + + + + + + + + + + + + +extern void *memchr(const void *source, int value, size_t length); +extern int memcmp(const void *buffer1, const void *buffer2, size_t length); +extern void *memcpy(void *dest, const void *source, size_t length); +extern void *memmove(void *dest, const void *source, size_t length); +extern void *memset(void *dest, int value, size_t length); + + +extern char *strcpy(char *dest, const char *source); +extern char *strncpy(char *dest, const char *source, size_t length); +extern char *strcat(char *dest, const char *source); +extern char *strncat(char *dest, const char *source, size_t length); + +extern size_t strlen(const char *string); +extern int strcmp(const char *string1, const char *string2); +extern int strncmp(const char *string1, const char *string2, size_t length); + +extern char *strchr(const char *string, int character); +extern char *strrchr(const char *string, int character); +extern char *strstr(const char *string, const char *searchString); + +extern char *strchrnul(const char *string, int character); + + +extern char *strpbrk(const char *string, const char *set); +extern char *strtok(char *string, const char *set); +extern char *strtok_r(char *string, const char *set, char **savePointer); +extern size_t strspn(const char *string, const char *set); +extern size_t strcspn(const char *string, const char *set); + +extern int strcoll(const char *string1, const char *string2); +extern size_t strxfrm(char *string1, const char *string2, size_t length); + +extern char *strerror(int errorCode); +extern int strerror_r(int errorCode, char *buffer, size_t bufferSize); + + + + + + + + + + +extern int strcasecmp(const char *string1, const char *string2); +extern int strncasecmp(const char *string1, const char *string2, size_t length); + + + +extern int strnicmp(const char *string1, const char *string2, size_t length); + +extern char *strcasestr(const char *string, const char *searchString); + +extern char *strdup(const char *string); +extern char *stpcpy(char *dest, const char *source); +extern const char *strtcopy(char *dest, const char *source); + +extern size_t strlcat(char *dest, const char *source, size_t length); +extern size_t strlcpy(char *dest, const char *source, size_t length); + +extern size_t strnlen(const char *string, size_t count); + + + + + + +extern const char *strsignal(int signal); + + + + + + +# 115 "system.h" 2 + + + + + +void *memrchr (const void *, int, size_t); + + +# 1 "../../../../../headers/posix/errno.h" 1 + + + + + + + + + + + + +# 1 "../../../../../headers/os/support/Errors.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +enum { + B_NO_MEMORY = (-2147483647L-1) , + B_IO_ERROR, + B_PERMISSION_DENIED, + B_BAD_INDEX, + B_BAD_TYPE, + B_BAD_VALUE, + B_MISMATCHED_VALUES, + B_NAME_NOT_FOUND, + B_NAME_IN_USE, + B_TIMED_OUT, + B_INTERRUPTED, + B_WOULD_BLOCK, + B_CANCELED, + B_NO_INIT, + B_BUSY, + B_NOT_ALLOWED, + B_BAD_DATA, + + B_ERROR = -1, + B_OK = 0, + B_NO_ERROR = 0 +}; + + + +enum { + B_BAD_SEM_ID = (-2147483647L-1) + 0x1000 , + B_NO_MORE_SEMS, + + B_BAD_THREAD_ID = (-2147483647L-1) + 0x1000 + 0x100, + B_NO_MORE_THREADS, + B_BAD_THREAD_STATE, + B_BAD_TEAM_ID, + B_NO_MORE_TEAMS, + + B_BAD_PORT_ID = (-2147483647L-1) + 0x1000 + 0x200, + B_NO_MORE_PORTS, + + B_BAD_IMAGE_ID = (-2147483647L-1) + 0x1000 + 0x300, + B_BAD_ADDRESS, + B_NOT_AN_EXECUTABLE, + B_MISSING_LIBRARY, + B_MISSING_SYMBOL, + + B_DEBUGGER_ALREADY_INSTALLED = (-2147483647L-1) + 0x1000 + 0x400 +}; + + + + +enum +{ + B_BAD_REPLY = (-2147483647L-1) + 0x2000 , + B_DUPLICATE_REPLY, + B_MESSAGE_TO_SELF, + B_BAD_HANDLER, + B_ALREADY_RUNNING, + B_LAUNCH_FAILED, + B_AMBIGUOUS_APP_LAUNCH, + B_UNKNOWN_MIME_TYPE, + B_BAD_SCRIPT_SYNTAX, + B_LAUNCH_FAILED_NO_RESOLVE_LINK, + B_LAUNCH_FAILED_EXECUTABLE, + B_LAUNCH_FAILED_APP_NOT_FOUND, + B_LAUNCH_FAILED_APP_IN_TRASH, + B_LAUNCH_FAILED_NO_PREFERRED_APP, + B_LAUNCH_FAILED_FILES_APP_NOT_FOUND, + B_BAD_MIME_SNIFFER_RULE, + B_NOT_A_MESSAGE +}; + + + + +enum { + B_FILE_ERROR = (-2147483647L-1) + 0x6000 , + B_FILE_NOT_FOUND, + B_FILE_EXISTS, + B_ENTRY_NOT_FOUND, + B_NAME_TOO_LONG, + B_NOT_A_DIRECTORY, + B_DIRECTORY_NOT_EMPTY, + B_DEVICE_FULL, + B_READ_ONLY_DEVICE, + B_IS_A_DIRECTORY, + B_NO_MORE_FDS, + B_CROSS_DEVICE_LINK, + B_LINK_LIMIT, + B_BUSTED_PIPE, + B_UNSUPPORTED, + B_PARTITION_TOO_SMALL +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +enum { + B_STREAM_NOT_FOUND = (-2147483647L-1) + 0x4000 , + B_SERVER_NOT_FOUND, + B_RESOURCE_NOT_FOUND, + B_RESOURCE_UNAVAILABLE, + B_BAD_SUBSCRIBER, + B_SUBSCRIBER_NOT_ENTERED, + B_BUFFER_NOT_AVAILABLE, + B_LAST_BUFFER_ERROR +}; + + + +enum +{ + B_MAIL_NO_DAEMON = (-2147483647L-1) + 0x8000 , + B_MAIL_UNKNOWN_USER, + B_MAIL_WRONG_PASSWORD, + B_MAIL_UNKNOWN_HOST, + B_MAIL_ACCESS_ERROR, + B_MAIL_UNKNOWN_FIELD, + B_MAIL_NO_RECIPIENT, + B_MAIL_INVALID_MAIL +}; + + + +enum +{ + B_NO_PRINT_SERVER = (-2147483647L-1) + 0x9000 +}; + + + +enum +{ + B_DEV_INVALID_IOCTL = (-2147483647L-1) + 0xa000 , + B_DEV_NO_MEMORY, + B_DEV_BAD_DRIVE_NUM, + B_DEV_NO_MEDIA, + B_DEV_UNREADABLE, + B_DEV_FORMAT_ERROR, + B_DEV_TIMEOUT, + B_DEV_RECALIBRATE_ERROR, + B_DEV_SEEK_ERROR, + B_DEV_ID_ERROR, + B_DEV_READ_ERROR, + B_DEV_WRITE_ERROR, + B_DEV_NOT_READY, + B_DEV_MEDIA_CHANGED, + B_DEV_MEDIA_CHANGE_REQUESTED, + B_DEV_RESOURCE_CONFLICT, + B_DEV_CONFIGURATION_ERROR, + B_DEV_DISABLED_BY_USER, + B_DEV_DOOR_OPEN +}; + + + + + +# 13 "../../../../../headers/posix/errno.h" 2 + + + + + +extern int *_errnop(void); + + + + + + + +# 123 "system.h" 2 + + + + + + + + + +typedef enum {false = 0, true = 1} bool; + + + + + + + + + + + + + + + + + + + + + + +# 1 "../../../../../headers/posix/fcntl.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + + + + + + + + + + + + + + +extern int creat(const char *path, mode_t mode); +extern int open(const char *pathname, int oflags, ...); + + + +extern int fcntl(int fd, int op, ...); + + + + + + +# 155 "system.h" 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 202 "system.h" + + + + + + + + + +# 1 "../../../../../headers/posix/dirent.h" 1 + + + + + + + + + +typedef struct dirent { + dev_t d_dev; + dev_t d_pdev; + ino_t d_ino; + ino_t d_pino; + unsigned short d_reclen; + char d_name[1]; +} dirent_t; + +typedef struct { + int fd; + struct dirent ent; +} DIR; + + + + + + + + + + + + + +DIR *opendir(const char *dirname); +struct dirent *readdir(DIR *dirp); +int closedir(DIR *dirp); +void rewinddir(DIR *dirp); + + + + + + + +# 211 "system.h" 2 + + +# 225 "system.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 288 "system.h" + + + + + + + + + + +# 1 "sys2.h" 1 + + + + + + + + + +# 23 "sys2.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 250 "sys2.h" + + + + + + + + + + +# 1 "../../../../../headers/posix/stdint.h" 1 + + + + + + +typedef signed char int8_t; + + +typedef unsigned char uint8_t; + + + +typedef signed short int16_t; + + +typedef unsigned short uint16_t; + + + +typedef signed long int32_t; + + +typedef unsigned long uint32_t; + + + +typedef signed long long int64_t; + + +typedef unsigned long long uint64_t; + + + +typedef signed long long intmax_t; + + +typedef unsigned long long uintmax_t; + + + + + +typedef int8_t int_least8_t; + + +typedef uint8_t uint_least8_t; + + + +typedef int16_t int_least16_t; + + +typedef uint16_t uint_least16_t; + + + +typedef int32_t int_least32_t; + + +typedef uint32_t uint_least32_t; + + + +typedef int64_t int_least64_t; + + +typedef uint64_t uint_least64_t; + + + + + + +typedef int32_t int_fast8_t; + + +typedef uint32_t uint_fast8_t; + + + +typedef int32_t int_fast16_t; + + +typedef uint32_t uint_fast16_t; + + + +typedef int32_t int_fast32_t; + + +typedef uint32_t uint_fast32_t; + + + +typedef int64_t int_fast64_t; + + +typedef uint64_t uint_fast64_t; + + + + +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +typedef uint64_t u_int64_t; + + +# 260 "sys2.h" 2 + + + + +# 1 "../../../../../headers/posix/inttypes.h" 1 + + + + + + + + + + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + + + + + + +extern intmax_t imaxabs(intmax_t num); +extern imaxdiv_t imaxdiv(intmax_t numer, intmax_t denom); + +extern intmax_t strtoimax(const char *, char **, int); +extern uintmax_t strtoumax(const char *, char **, int); + + + + + + + + +# 264 "sys2.h" 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 1 "../../../../../headers/posix/locale.h" 1 + + + + + + + + +struct lconv { + char *decimal_point; + char *thousands_sep; + char *grouping; + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; +}; + + + + + + + + + + + + + +extern struct lconv *localeconv(void); +extern char *setlocale(int category, const char *locale); + + + + + + +# 356 "sys2.h" 2 + + + + + +# 1 "../lib/gettext.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 361 "sys2.h" 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +char *strndup (); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 1 "../lib/xalloc.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern int xalloc_exit_failure; + + + +extern void (*xalloc_fail_func) (void) ; + + + + +extern char const xalloc_msg_memory_exhausted[]; + + + + + +extern void xalloc_die (void) __attribute__ ((__noreturn__)) ; + +void *xmalloc (size_t n) ; +void *xcalloc (size_t n, size_t s) ; +void *xrealloc (void *p, size_t n) ; +char *xstrdup (const char *str) ; + + + + + + + + + + + + + + + + + + + + + + + + + +# 444 "sys2.h" 2 + + + + + + + + +# 1 "../lib/unlocked-io.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 452 "sys2.h" 2 + + + + + + + + + + + + + + + + + + + + + + + +enum +{ + GETOPT_HELP_CHAR = ((-127-1) - 2), + GETOPT_VERSION_CHAR = ((-127-1) - 3) +}; + + + + + + + + + + + + + + + + +# 1 "../lib/closeout.h" 1 + + + + + + + + + + + +void close_stdout_set_status (int status) ; +void close_stdout_set_file_name (const char *file) ; +void close_stdout (void) ; +void close_stdout_status (int status) ; + + +# 496 "sys2.h" 2 + +# 1 "../lib/version-etc.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern char *version_etc_copyright; + +void +version_etc (FILE *stream, + const char *command_name, const char *package, + const char *version, const char *authors) ; + + +# 497 "sys2.h" 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 648 "sys2.h" + + + + + + + + + + + +# 298 "system.h" 2 + +# 100 "ls.c" 2 + +# 1 "../lib/fnmatch.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern int rpl_fnmatch (const char *__pattern, const char *__name, + int __flags) ; + + + + + + +# 101 "ls.c" 2 + + +# 1 "../lib/acl.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + +int file_has_acl (char const *, struct stat const *); +# 103 "ls.c" 2 + +# 1 "../lib/argmatch.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +int argmatch (char const *arg, char const *const *arglist, + char const *vallist, size_t valsize); + + + + + + + +typedef void (*argmatch_exit_fn) (void); +extern argmatch_exit_fn argmatch_die; + + + +void argmatch_invalid (char const *context, char const *value, int problem); + + + + + + + + + + +void argmatch_valid (char const *const *arglist, + char const *vallist, size_t valsize); + + + + + + + + + +int __xargmatch_internal (char const *context, + char const *arg, char const *const *arglist, + char const *vallist, size_t valsize, + argmatch_exit_fn exit_fn); + + + + + + + + + + + +char const *argmatch_to_argument (char const *value, + char const *const *arglist, + char const *vallist, size_t valsize); + + + + + + +# 104 "ls.c" 2 + +# 1 "../lib/dev-ino.h" 1 + + + +struct dev_ino +{ + ino_t st_ino; + dev_t st_dev; +}; + + +# 105 "ls.c" 2 + +# 1 "../lib/dirname.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +char *base_name (char const *path) ; +char *dir_name (char const *path) ; +size_t base_len (char const *path) ; +size_t dir_len (char const *path) ; + +int strip_trailing_slashes (char *path) ; + + +# 106 "ls.c" 2 + +# 1 "../lib/dirfd.h" 1 + +# 1 "../lib/config.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 2 "../lib/dirfd.h" 2 + + + + + + + +# 20 "../lib/dirfd.h" + + + + + + +int dirfd (DIR const *); + +# 107 "ls.c" 2 + +# 1 "../lib/error.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern void error (int status, int errnum, const char *format, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); + +extern void error_at_line (int status, int errnum, const char *fname, + unsigned int lineno, const char *format, ...) + __attribute__ ((__format__ (__printf__, 5, 6))); + + + + +extern void (*error_print_progname) (void); + + + + + + + + +extern unsigned int error_message_count; + + + +extern int error_one_per_line; + + + + + + +# 108 "ls.c" 2 + +# 1 "../lib/full-write.h" 1 + + + + + + + + + + + + + + + + + + + + + + + +extern size_t full_write (int fd, const void *buf, size_t count); +# 109 "ls.c" 2 + +# 1 "../lib/hard-locale.h" 1 + + + + +# 1 "../lib/config.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 5 "../lib/hard-locale.h" 2 + + + + + + + + + + + +int hard_locale (int) ; + + +# 110 "ls.c" 2 + +# 1 "../lib/hash.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef unsigned (*Hash_hasher) (const void *, unsigned) ; +typedef bool (*Hash_comparator) (const void *, const void *) ; +typedef void (*Hash_data_freer) (void *) ; +typedef bool (*Hash_processor) (void *, void *) ; + +struct hash_entry + { + void *data; + struct hash_entry *next; + }; + +struct hash_tuning + { + + + + float shrink_threshold; + float shrink_factor; + float growth_threshold; + float growth_factor; + bool is_n_buckets; + }; + +typedef struct hash_tuning Hash_tuning; + +struct hash_table; + +typedef struct hash_table Hash_table; + + +unsigned hash_get_n_buckets (const Hash_table *) ; +unsigned hash_get_n_buckets_used (const Hash_table *) ; +unsigned hash_get_n_entries (const Hash_table *) ; +unsigned hash_get_max_bucket_length (const Hash_table *) ; +bool hash_table_ok (const Hash_table *) ; +void hash_print_statistics (const Hash_table *, FILE *) ; +void *hash_lookup (const Hash_table *, const void *) ; + + +void *hash_get_first (const Hash_table *) ; +void *hash_get_next (const Hash_table *, const void *) ; +unsigned hash_get_entries (const Hash_table *, void **, unsigned) ; +unsigned hash_do_for_each (const Hash_table *, Hash_processor, void *) ; + + +unsigned hash_string (const char *, unsigned) ; +void hash_reset_tuning (Hash_tuning *) ; +Hash_table *hash_initialize (unsigned, const Hash_tuning *, + Hash_hasher, Hash_comparator, + Hash_data_freer) ; +void hash_clear (Hash_table *) ; +void hash_free (Hash_table *) ; + + +bool hash_rehash (Hash_table *, unsigned) ; +void *hash_insert (Hash_table *, const void *) ; +void *hash_delete (Hash_table *, const void *) ; + + +# 111 "ls.c" 2 + +# 1 "../lib/human.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +enum +{ + + + + + human_ceiling = 0, + + human_round_to_nearest = 1, + + human_floor = 2, + + + + + human_group_digits = 4, + + + human_suppress_point_zero = 8, + + + human_autoscale = 16, + + + human_base_1024 = 32, + + + human_SI = 64, + + + human_B = 128 +}; + +char *human_readable (uintmax_t, char *, int, uintmax_t, uintmax_t); + +int human_options (char const *, bool, uintmax_t *); + + +# 112 "ls.c" 2 + +# 1 "../lib/filemode.h" 1 + + + +# 1 "../lib/config.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 4 "../lib/filemode.h" 2 + + + + + + + + + + + + + +void mode_string (mode_t mode, char *str) ; + + +# 113 "ls.c" 2 + +# 1 "../lib/inttostr.h" 1 + + + + + + + + + + + + + + + + + + + + + +# 1 "../lib/config.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 22 "../lib/inttostr.h" 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +char *offtostr (off_t, char *) ; +char *imaxtostr (intmax_t, char *) ; +char *umaxtostr (uintmax_t, char *) ; +# 114 "ls.c" 2 + +# 1 "ls.h" 1 + + + + + + + + + +extern int ls_mode; +# 115 "ls.c" 2 + +# 1 "../lib/mbswidth.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern int gnu_mbswidth (const char *string, int flags); + + + +extern int mbsnwidth (const char *buf, size_t nbytes, int flags); +# 116 "ls.c" 2 + +# 1 "../lib/obstack.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct _obstack_chunk +{ + char *limit; + struct _obstack_chunk *prev; + char contents[4]; +}; + +struct obstack +{ + long chunk_size; + struct _obstack_chunk *chunk; + char *object_base; + char *next_free; + char *chunk_limit; + long int temp; + int alignment_mask; + + + + + struct _obstack_chunk *(*chunkfun) (void *, long); + void (*freefun) (void *, struct _obstack_chunk *); + void *extra_arg; + + + + + + unsigned use_extra_arg:1; + unsigned maybe_empty_object:1; + + + + unsigned alloc_failed:1; + + +}; + + + + +extern void _obstack_newchunk (struct obstack *, int); +extern void _obstack_free (struct obstack *, void *); +extern int _obstack_begin (struct obstack *, int, int, + void *(*) (long), void (*) (void *)); +extern int _obstack_begin_1 (struct obstack *, int, int, + void *(*) (void *, long), + void (*) (void *, void *), void *); +extern int _obstack_memory_used (struct obstack *); + + + + + + + + + + + + + +void obstack_init (struct obstack *obstack); + +void * obstack_alloc (struct obstack *obstack, int size); + +void * obstack_copy (struct obstack *obstack, const void *address, int size); +void * obstack_copy0 (struct obstack *obstack, const void *address, int size); + +void obstack_free (struct obstack *obstack, void *block); + +void obstack_blank (struct obstack *obstack, int size); + +void obstack_grow (struct obstack *obstack, const void *data, int size); +void obstack_grow0 (struct obstack *obstack, const void *data, int size); + +void obstack_1grow (struct obstack *obstack, int data_char); +void obstack_ptr_grow (struct obstack *obstack, const void *data); +void obstack_int_grow (struct obstack *obstack, int data); + +void * obstack_finish (struct obstack *obstack); + +int obstack_object_size (struct obstack *obstack); + +int obstack_room (struct obstack *obstack); +void obstack_make_room (struct obstack *obstack, int size); +void obstack_1grow_fast (struct obstack *obstack, int data_char); +void obstack_ptr_grow_fast (struct obstack *obstack, const void *data); +void obstack_int_grow_fast (struct obstack *obstack, int data); +void obstack_blank_fast (struct obstack *obstack, int size); + +void * obstack_base (struct obstack *obstack); +void * obstack_next_free (struct obstack *obstack); +int obstack_alignment_mask (struct obstack *obstack); +int obstack_chunk_size (struct obstack *obstack); +int obstack_memory_used (struct obstack *obstack); + + + + + + + + + + + +extern void (*obstack_alloc_failed_handler) (void); + + + + + +extern int obstack_exit_failure; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 352 "../lib/obstack.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 405 "../lib/obstack.h" + + +# 416 "../lib/obstack.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 495 "../lib/obstack.h" + + + + + + + + + +# 607 "../lib/obstack.h" + + + + + + + +# 117 "ls.c" 2 + +# 1 "../lib/path-concat.h" 1 + + + + + + + + + + + +char * +path_concat (const char *dir, const char *base, char **base_in_result) ; + + +# 118 "ls.c" 2 + +# 1 "../lib/quote.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + +char const *quote_n (int n, char const *name) ; +char const *quote (char const *name) ; +# 119 "ls.c" 2 + +# 1 "../lib/quotearg.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + +enum quoting_style + { + literal_quoting_style, + shell_quoting_style, + shell_always_quoting_style, + c_quoting_style, + escape_quoting_style, + locale_quoting_style, + clocale_quoting_style + }; + + + + + + + +extern char const *const quoting_style_args[]; +extern enum quoting_style const quoting_style_vals[]; + +struct quoting_options; + + + + + + + +struct quoting_options *clone_quoting_options (struct quoting_options *o); + + +enum quoting_style get_quoting_style (struct quoting_options *o); + + + +void set_quoting_style (struct quoting_options *o, enum quoting_style s); + + + + + + +int set_char_quoting (struct quoting_options *o, char c, int i); + + + + + + + + + +size_t quotearg_buffer (char *buffer, size_t buffersize, + char const *arg, size_t argsize, + struct quoting_options const *o); + + + + + + +char *quotearg_n (int n, char const *arg); + + +char *quotearg (char const *arg); + + + + +char *quotearg_n_style (int n, enum quoting_style s, char const *arg); + + + + +char *quotearg_n_style_mem (int n, enum quoting_style s, + char const *arg, size_t argsize); + + +char *quotearg_style (enum quoting_style s, char const *arg); + + +char *quotearg_char (char const *arg, char ch); + + +char *quotearg_colon (char const *arg); + + +# 120 "ls.c" 2 + +# 1 "../lib/same.h" 1 + + + + + + + + + + + + + + + + + + + + +int +same_name (const char *source, const char *dest); + + +# 121 "ls.c" 2 + +# 1 "../lib/strftime.h" 1 + + + + + + + + + + + + + + + + + + +size_t nstrftime (char *, size_t, char const *, struct tm const *, int, int); +# 122 "ls.c" 2 + +# 1 "../lib/strverscmp.h" 1 + + + + + + +# 1 "../lib/config.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 7 "../lib/strverscmp.h" 2 + + + + + + + + + + + +int strverscmp (const char*, const char*) ; + + +# 123 "ls.c" 2 + +# 1 "../lib/xstrtol.h" 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +enum strtol_error + { + LONGINT_OK, LONGINT_INVALID, LONGINT_INVALID_SUFFIX_CHAR, LONGINT_OVERFLOW + }; +typedef enum strtol_error strtol_error; + + + + + + +strtol_error xstrtol (const char *s, char **ptr, int base, long int *val, const char *valid_suffixes) ; +strtol_error xstrtoul (const char *s, char **ptr, int base, unsigned long int *val, const char *valid_suffixes) ; +strtol_error xstrtoimax (const char *s, char **ptr, int base, intmax_t *val, const char *valid_suffixes) ; +strtol_error xstrtoumax (const char *s, char **ptr, int base, uintmax_t *val, const char *valid_suffixes) ; + + +# 75 "../lib/xstrtol.h" + + + + + + + + +# 124 "ls.c" 2 + +# 1 "../lib/xreadlink.h" 1 + + + + + + + + +char *xreadlink (char const *) ; +# 125 "ls.c" 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +enum filetype + { + unknown , + fifo , + chardev , + directory , + blockdev , + normal , + symbolic_link , + sock , + arg_directory + + }; + +struct fileinfo + { + + char *name; + + struct stat stat; + + + char *linkname; + + + + mode_t linkmode; + + + + int linkok; + + enum filetype filetype; + + + + + + }; + + + + + + + + + + + + + +struct bin_str + { + int len; + const char *string; + }; + + + + + +char *getgroup (); +char *getuser (); + +static size_t quote_name (FILE *out, const char *name, + struct quoting_options const *options, + size_t *width); +static char *make_link_path (const char *path, const char *linkname); +static int decode_switches (int argc, char **argv); +static int file_interesting (const struct dirent *next); +static uintmax_t gobble_file (const char *name, enum filetype type, + int explicit_arg, const char *dirname); +static void print_color_indicator (const char *name, mode_t mode, int linkok); +static void put_indicator (const struct bin_str *ind); +static int put_indicator_direct (const struct bin_str *ind); +static int length_of_file_name_and_frills (const struct fileinfo *f); +static void add_ignore_pattern (const char *pattern); +static void attach (char *dest, const char *dirname, const char *name); +static void clear_files (void); +static void extract_dirs_from_files (const char *dirname, + int ignore_dot_and_dot_dot); +static void get_link_name (const char *filename, struct fileinfo *f); +static void indent (int from, int to); +static void init_column_info (void); +static void print_current_files (void); +static void print_dir (const char *name, const char *realname); +static void print_file_name_and_frills (const struct fileinfo *f); +static void print_horizontal (void); +static void print_long_format (const struct fileinfo *f); +static void print_many_per_line (void); +static void print_name_with_quoting (const char *p, mode_t mode, + int linkok, + struct obstack *stack); +static void prep_non_filename_text (void); +static void print_type_indicator (mode_t mode); +static void print_with_commas (void); +static void queue_directory (const char *name, const char *realname); +static void sort_files (void); +static void parse_ls_color (void); +void usage (int status); + + +char *program_name; + + + + + + + + + + + + +static Hash_table *active_dir_set; + + + + + + + + + + +static struct fileinfo *files; + + +static int nfiles; + + +static int files_index; + + + + + + +static int color_symlink_as_referent; + + + + + + + + + +struct pending + { + char *name; + + + + char *realname; + struct pending *next; + }; + +static struct pending *pending_dirs; + + + + +static time_t current_time = (( time_t ) ((! (( time_t ) 0 < ( time_t ) -1)) ? ~ ( time_t ) 0 << (sizeof ( time_t ) * (8) - 1) : ( time_t ) 0)) ; +static int current_time_ns = -1; + + + + +static int block_size_size; + + + + + + + + + + + + +enum format + { + long_format, + one_per_line, + many_per_line, + horizontal, + with_commas + }; + +static enum format format; + + + + +enum time_style + { + full_iso_time_style, + long_iso_time_style, + iso_time_style, + locale_time_style + }; + +static char const *const time_style_args[] = +{ + "full-iso", "long-iso", "iso", "locale", 0 +}; + +static enum time_style const time_style_types[] = +{ + full_iso_time_style, long_iso_time_style, iso_time_style, + locale_time_style, 0 +}; + + + +enum time_type + { + time_mtime, + time_ctime, + time_atime + }; + +static enum time_type time_type; + + + +enum sort_type + { + sort_none, + sort_name, + sort_extension, + sort_time, + sort_size, + sort_version + }; + +static enum sort_type sort_type; + + + + + + + +static int sort_reverse; + + + +static int print_owner = 1; + + + +static bool print_author; + + + +static int print_group = 1; + + + + +static int numeric_ids; + + + +static int print_block_size; + + +static int human_output_opts; + + +static uintmax_t output_block_size; + + +static uintmax_t file_output_block_size = 1; + + + + + + +static int dired; + + + + + + + +enum indicator_style + { + none, + classify, + file_type + }; + +static enum indicator_style indicator_style; + + +static char const *const indicator_style_args[] = +{ + "none", "classify", "file-type", 0 +}; + +static enum indicator_style const indicator_style_types[]= +{ + none, classify, file_type +}; + + + + + +static int print_with_color; + +enum color_type + { + color_never, + color_always, + color_if_tty + }; + +enum Dereference_symlink + { + DEREF_UNDEFINED = 1, + DEREF_NEVER, + DEREF_COMMAND_LINE_ARGUMENTS, + DEREF_COMMAND_LINE_SYMLINK_TO_DIR, + DEREF_ALWAYS + }; + +enum indicator_no + { + C_LEFT, C_RIGHT, C_END, C_NORM, C_FILE, C_DIR, C_LINK, C_FIFO, C_SOCK, + C_BLK, C_CHR, C_MISSING, C_ORPHAN, C_EXEC, C_DOOR + }; + +static const char *const indicator_name[]= + { + "lc", "rc", "ec", "no", "fi", "di", "ln", "pi", "so", + "bd", "cd", "mi", "or", "ex", "do", 0 + }; + +struct color_ext_type + { + struct bin_str ext; + struct bin_str seq; + struct color_ext_type *next; + }; + +static struct bin_str color_indicator[] = + { + { sizeof ( "\033[" ) - 1, "\033[" }, + { sizeof ( "m" ) - 1, "m" }, + { 0, 0 }, + { sizeof ( "0" ) - 1, "0" }, + { sizeof ( "0" ) - 1, "0" }, + { sizeof ( "01;34" ) - 1, "01;34" }, + { sizeof ( "01;36" ) - 1, "01;36" }, + { sizeof ( "33" ) - 1, "33" }, + { sizeof ( "01;35" ) - 1, "01;35" }, + { sizeof ( "01;33" ) - 1, "01;33" }, + { sizeof ( "01;33" ) - 1, "01;33" }, + { 0, 0 }, + { 0, 0 }, + { sizeof ( "01;32" ) - 1, "01;32" }, + { sizeof ( "01;35" ) - 1, "01;35" } + }; + + +static struct color_ext_type *color_ext_list = 0 ; + + +static char *color_buf; + + + + +static int check_symlink_color; + + + +static int print_inode; + + + + +static enum Dereference_symlink dereference; + + + + +static int recursive; + + + + +static int immediate_dirs; + + + +static int all_files; + + + + +static int really_all_files; + + + + + + +struct ignore_pattern + { + const char *pattern; + struct ignore_pattern *next; + }; + +static struct ignore_pattern *ignore_patterns; + + + + + + + + + + +static int qmark_funny_chars; + + + +static struct quoting_options *filename_quoting_options; +static struct quoting_options *dirname_quoting_options; + + + +static int tabsize; + + + + +static int dir_defaulted; + + + +static int print_dir_name; + + + + +static int line_length; + + + + +static int format_needs_stat; + + + + +static int format_needs_type; + + + + +static char const *long_time_format[2] = + { + + + + + + + + "%b %e %Y" , + + + + + + + + "%b %e %H:%M" + }; + + + +static int exit_status; + + + +enum +{ + AUTHOR_OPTION = (127) + 1, + BLOCK_SIZE_OPTION, + COLOR_OPTION, + DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION, + FORMAT_OPTION, + FULL_TIME_OPTION, + INDICATOR_STYLE_OPTION, + QUOTING_STYLE_OPTION, + SHOW_CONTROL_CHARS_OPTION, + SI_OPTION, + SORT_OPTION, + TIME_OPTION, + TIME_STYLE_OPTION +}; + +static struct option const long_options[] = +{ + {"all", 0 , 0, 'a'}, + {"escape", 0 , 0, 'b'}, + {"directory", 0 , 0, 'd'}, + {"dired", 0 , 0, 'D'}, + {"full-time", 0 , 0, FULL_TIME_OPTION}, + {"human-readable", 0 , 0, 'h'}, + {"inode", 0 , 0, 'i'}, + {"kilobytes", 0 , 0, 'k'}, + {"numeric-uid-gid", 0 , 0, 'n'}, + {"no-group", 0 , 0, 'G'}, + {"hide-control-chars", 0 , 0, 'q'}, + {"reverse", 0 , 0, 'r'}, + {"size", 0 , 0, 's'}, + {"width", 1 , 0, 'w'}, + {"almost-all", 0 , 0, 'A'}, + {"ignore-backups", 0 , 0, 'B'}, + {"classify", 0 , 0, 'F'}, + {"file-type", 0 , 0, 'p'}, + {"si", 0 , 0, SI_OPTION}, + {"dereference-command-line", 0 , 0, 'H'}, + {"dereference-command-line-symlink-to-dir", 0 , 0, + DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION}, + {"ignore", 1 , 0, 'I'}, + {"indicator-style", 1 , 0, INDICATOR_STYLE_OPTION}, + {"dereference", 0 , 0, 'L'}, + {"literal", 0 , 0, 'N'}, + {"quote-name", 0 , 0, 'Q'}, + {"quoting-style", 1 , 0, QUOTING_STYLE_OPTION}, + {"recursive", 0 , 0, 'R'}, + {"format", 1 , 0, FORMAT_OPTION}, + {"show-control-chars", 0 , 0, SHOW_CONTROL_CHARS_OPTION}, + {"sort", 1 , 0, SORT_OPTION}, + {"tabsize", 1 , 0, 'T'}, + {"time", 1 , 0, TIME_OPTION}, + {"time-style", 1 , 0, TIME_STYLE_OPTION}, + {"color", 2 , 0, COLOR_OPTION}, + {"block-size", 1 , 0, BLOCK_SIZE_OPTION}, + {"author", 0 , 0, AUTHOR_OPTION}, + {"help", 0 , 0, GETOPT_HELP_CHAR }, + {"version", 0 , 0, GETOPT_VERSION_CHAR }, + {0 , 0, 0 , 0} +}; + +static char const *const format_args[] = +{ + "verbose", "long", "commas", "horizontal", "across", + "vertical", "single-column", 0 +}; + +static enum format const format_types[] = +{ + long_format, long_format, with_commas, horizontal, horizontal, + many_per_line, one_per_line +}; + +static char const *const sort_args[] = +{ + "none", "time", "size", "extension", "version", 0 +}; + +static enum sort_type const sort_types[] = +{ + sort_none, sort_time, sort_size, sort_extension, sort_version +}; + +static char const *const time_args[] = +{ + "atime", "access", "use", "ctime", "status", 0 +}; + +static enum time_type const time_types[] = +{ + time_atime, time_atime, time_atime, time_ctime, time_ctime +}; + +static char const *const color_args[] = +{ + + "always", "yes", "force", + "never", "no", "none", + "auto", "tty", "if-tty", 0 +}; + +static enum color_type const color_types[] = +{ + color_always, color_always, color_always, + color_never, color_never, color_never, + color_if_tty, color_if_tty, color_if_tty +}; + + +struct column_info +{ + int valid_len; + int line_len; + int *col_arr; +}; + + +static struct column_info *column_info; + + +static int max_idx; + + + + + + + + + + + +static size_t dired_pos; + + + + + + + + + + + + + + + + + + + + +static struct obstack dired_obstack; + + + + + + +static struct obstack subdired_obstack; + + + + + + + + + + + + + +static struct obstack dev_ino_obstack; + + + +# 878 "ls.c" + + + +static struct dev_ino +dev_ino_pop (void) +{ + ((void) (( sizeof (struct dev_ino) <= __extension__ ({ struct obstack const *__o = ( &dev_ino_obstack ); (unsigned) (__o->next_free - __o->object_base); }) ) ? 0 : (__assert_fail ("sizeof (struct dev_ino) <= obstack_object_size (&dev_ino_obstack)", "ls.c", 884, __PRETTY_FUNCTION__), 0))) ; + __extension__ ({ struct obstack *__o = ( &dev_ino_obstack ); int __len = ( -(int) (sizeof (struct dev_ino)) ); if (__o->chunk_limit - __o->next_free < __len) _obstack_newchunk (__o, __len); __o->next_free += __len; (void) 0; }) ; + return *(struct dev_ino*) (( &dev_ino_obstack )->next_free) ; +} + + +# 899 "ls.c" + + + + + +static void +dired_dump_obstack (const char *prefix, struct obstack *os) +{ + int n_pos; + + n_pos = __extension__ ({ struct obstack const *__o = ( os ); (unsigned) (__o->next_free - __o->object_base); }) / sizeof (dired_pos); + if (n_pos > 0) + { + int i; + size_t *pos; + + pos = (size_t *) __extension__ ({ struct obstack *__o1 = ( os ); void *value; value = (void *) __o1->object_base; if (__o1->next_free == value) __o1->maybe_empty_object = 1; __o1->next_free = ((void *) (( ((( __o1->next_free ) - (char *) 0) +__o1->alignment_mask) & ~ (__o1->alignment_mask) ) + (char *) 0)) ; if (__o1->next_free - (char *)__o1->chunk > __o1->chunk_limit - (char *)__o1->chunk) __o1->next_free = __o1->chunk_limit; __o1->object_base = __o1->next_free; value; }) ; + fputs (prefix, stdout); + for (i = 0; i < n_pos; i++) + printf (" %lu", (unsigned long) pos[i]); + putchar_unlocked ( '\n' ) ; + } +} + +static unsigned int +dev_ino_hash (void const *x, unsigned int table_size) +{ + struct dev_ino const *p = x; + return (uintmax_t) p->st_ino % table_size; +} + +static bool +dev_ino_compare (void const *x, void const *y) +{ + struct dev_ino const *a = x; + struct dev_ino const *b = y; + return (( *a ).st_ino == ( *b ).st_ino && ( *a ).st_dev == ( *b ).st_dev) ? true : false; +} + +static void +dev_ino_free (void *x) +{ + free (x); +} + + + + + +static int +visit_dir (dev_t dev, ino_t ino) +{ + struct dev_ino *ent; + struct dev_ino *ent_from_table; + int found_match; + + ent = (( struct dev_ino *) xmalloc (sizeof ( struct dev_ino ) * ( 1 ))) ; + ent->st_ino = ino; + ent->st_dev = dev; + + + ent_from_table = hash_insert (active_dir_set, ent); + + if (ent_from_table == 0 ) + { + + xalloc_die (); + } + + found_match = (ent_from_table != ent); + + if (found_match) + { + + free (ent); + } + + return found_match; +} + +static void +free_pending_ent (struct pending *p) +{ + if (p->name) + free (p->name); + if (p->realname) + free (p->realname); + free (p); +} + +static void +restore_default_color (void) +{ + if (put_indicator_direct (&color_indicator[C_LEFT]) == 0) + put_indicator_direct (&color_indicator[C_RIGHT]); +} + + + +static void +sighandler (int sig) +{ + + + + + restore_default_color (); + + + + + if (sig == 13 ) + { + sig = 10 ; + } + else + { + + struct sigaction sigact; + + sigact.sa_handler = ((sig_func_t) 0) ; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (sig, &sigact, 0 ); + + + + } + + raise (sig); +} + +int +main (int argc, char **argv) +{ + register int i; + register struct pending *thispend; + unsigned int n_files; + + program_name = argv[0]; + setlocale (0 , ""); + ((const char *) ( "/share/locale" )) ; + ((const char *) ( "coreutils" )) ; + + atexit (close_stdout); + + + ((void) (( (sizeof color_indicator / sizeof *( color_indicator )) + 1 == (sizeof indicator_name / sizeof *( indicator_name )) ) ? 0 : (__assert_fail ("N_ENTRIES (color_indicator) + 1 == N_ENTRIES (indicator_name)", "ls.c", 1046, __PRETTY_FUNCTION__), 0))) ; + + exit_status = 0; + dir_defaulted = 1; + print_dir_name = 1; + pending_dirs = 0; + + i = decode_switches (argc, argv); + + if (print_with_color) + parse_ls_color (); + + + + if (print_with_color) + { + prep_non_filename_text (); + + if (color_indicator[C_ORPHAN].string != 0 + || (color_indicator[C_MISSING].string != 0 + && format == long_format)) + check_symlink_color = 1; + + { + unsigned j; + static int const sigs[] = { 1 , 2 , 7 , + 3 , 15 , 13 }; + unsigned nsigs = sizeof sigs / sizeof *sigs; + + struct sigaction oldact, newact; + sigset_t caught_signals; + + sigemptyset (&caught_signals); + for (j = 0; j < nsigs; j++) + sigaddset (&caught_signals, sigs[j]); + newact.sa_handler = sighandler; + newact.sa_mask = caught_signals; + newact.sa_flags = 0; + + + for (j = 0; j < nsigs; j++) + { + int sig = sigs[j]; + + sigaction (sig, 0 , &oldact); + if (oldact.sa_handler != ((sig_func_t) 1) ) + sigaction (sig, &newact, 0 ); + + + + + } + } + } + + if (dereference == DEREF_UNDEFINED) + dereference = ((immediate_dirs + || indicator_style == classify + || format == long_format) + ? DEREF_NEVER + : DEREF_COMMAND_LINE_SYMLINK_TO_DIR); + + + + if (recursive) + { + active_dir_set = hash_initialize (30 , 0 , + dev_ino_hash, + dev_ino_compare, + dev_ino_free); + if (active_dir_set == 0 ) + xalloc_die (); + + _obstack_begin (( &dev_ino_obstack ), 0, 0, (void *(*) (long)) malloc , (void (*) (void *)) free ) ; + } + + format_needs_stat = sort_type == sort_time || sort_type == sort_size + || format == long_format + || dereference == DEREF_ALWAYS + || print_block_size || print_inode; + format_needs_type = (format_needs_stat == 0 + && (recursive || print_with_color + || indicator_style != none)); + + if (dired) + { + _obstack_begin (( &dired_obstack ), 0, 0, (void *(*) (long)) malloc , (void (*) (void *)) free ) ; + _obstack_begin (( &subdired_obstack ), 0, 0, (void *(*) (long)) malloc , (void (*) (void *)) free ) ; + } + + nfiles = 100; + files = (( struct fileinfo *) xmalloc (sizeof ( struct fileinfo ) * ( nfiles ))) ; + files_index = 0; + + clear_files (); + + n_files = argc - i; + if (0 < n_files) + dir_defaulted = 0; + + for (; i < argc; i++) + { + gobble_file (argv[i], unknown, 1, ""); + } + + if (dir_defaulted) + { + if (immediate_dirs) + gobble_file (".", directory, 1, ""); + else + queue_directory (".", 0); + } + + if (files_index) + { + sort_files (); + if (!immediate_dirs) + extract_dirs_from_files ("", 0); + + } + + + + + + if (files_index) + { + print_current_files (); + if (pending_dirs) + do {putchar_unlocked ( ( '\n' ) ) ; ++dired_pos;} while (0) ; + } + else if (n_files <= 1 && pending_dirs && pending_dirs->next == 0) + print_dir_name = 0; + + while (pending_dirs) + { + thispend = pending_dirs; + pending_dirs = pending_dirs->next; + + if ((!!active_dir_set) ) + { + if (thispend->name == 0 ) + { + + + + + struct dev_ino di = dev_ino_pop (); + struct dev_ino *found = hash_delete (active_dir_set, &di); + + ((void) (( found ) ? 0 : (__assert_fail ("found", "ls.c", 1196, __PRETTY_FUNCTION__), 0))) ; + dev_ino_free (found); + free_pending_ent (thispend); + continue; + } + } + + print_dir (thispend->name, thispend->realname); + + free_pending_ent (thispend); + print_dir_name = 1; + } + + if (dired) + { + + dired_dump_obstack ("//DIRED//", &dired_obstack); + dired_dump_obstack ("//SUBDIRED//", &subdired_obstack); + printf ("//DIRED-OPTIONS// --quoting-style=%s\n", + quoting_style_args[get_quoting_style (filename_quoting_options)]); + } + + + if (print_with_color) + { + put_indicator (&color_indicator[C_LEFT]); + put_indicator (&color_indicator[C_RIGHT]); + } + + if ((!!active_dir_set) ) + { + ((void) (( hash_get_n_entries (active_dir_set) == 0 ) ? 0 : (__assert_fail ("hash_get_n_entries (active_dir_set) == 0", "ls.c", 1227, __PRETTY_FUNCTION__), 0))) ; + hash_free (active_dir_set); + } + + exit (exit_status); +} + + + + +static int +decode_switches (int argc, char **argv) +{ + int c; + char *time_style_option = 0; + + + int sort_type_specified = 0; + + qmark_funny_chars = 0; + + + + switch (ls_mode) + { + case 2 : + + format = many_per_line; + set_quoting_style (0 , escape_quoting_style); + break; + + case 3 : + + format = long_format; + set_quoting_style (0 , escape_quoting_style); + break; + + case 1 : + + if (isatty (1 )) + { + format = many_per_line; + + qmark_funny_chars = 1; + } + else + { + format = one_per_line; + qmark_funny_chars = 0; + } + break; + + default: + abort (); + } + + time_type = time_mtime; + sort_type = sort_name; + sort_reverse = 0; + numeric_ids = 0; + print_block_size = 0; + indicator_style = none; + print_inode = 0; + dereference = DEREF_UNDEFINED; + recursive = 0; + immediate_dirs = 0; + all_files = 0; + really_all_files = 0; + ignore_patterns = 0; + + + { + char const *q_style = getenv ("QUOTING_STYLE"); + if (q_style) + { + int i = argmatch ( q_style , quoting_style_args , (char const *) ( quoting_style_vals ), sizeof *( quoting_style_vals )) ; + if (0 <= i) + set_quoting_style (0 , quoting_style_vals[i]); + else + error (0, 0, + ((const char *) ( "ignoring invalid value of environment variable QUOTING_STYLE: %s" )) , + quotearg (q_style)); + } + } + + { + char const *ls_block_size = getenv ("LS_BLOCK_SIZE"); + human_output_opts = human_options (ls_block_size, false, + &output_block_size); + if (ls_block_size || getenv ("BLOCK_SIZE")) + file_output_block_size = output_block_size; + } + + line_length = 80; + { + char const *p = getenv ("COLUMNS"); + if (p && *p) + { + long int tmp_long; + if (xstrtol (p, 0 , 0, &tmp_long, 0 ) == LONGINT_OK + && 0 < tmp_long && tmp_long <= (2147483647L) ) + { + line_length = (int) tmp_long; + } + else + { + error (0, 0, + ((const char *) ( "ignoring invalid width in environment variable COLUMNS: %s" )) , + quotearg (p)); + } + } + } + + + { + struct winsize ws; + + if (ioctl (1 , ((0x8000) +12) , &ws) != -1 && ws.ws_col != 0) + line_length = ws.ws_col; + } + + + + + { + char const *p; + tabsize = 8; + if (!getenv ("POSIXLY_CORRECT") && (p = getenv ("TABSIZE"))) + { + long int tmp_long; + if (xstrtol (p, 0 , 0, &tmp_long, 0 ) == LONGINT_OK + && 0 <= tmp_long && tmp_long <= (2147483647L) ) + { + tabsize = (int) tmp_long; + } + else + { + error (0, 0, + ((const char *) ( "ignoring invalid tab size in environment variable TABSIZE: %s" )) , + quotearg (p)); + } + } + } + + while ((c = getopt_long (argc, argv, + "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1", + long_options, 0 )) != -1) + { + switch (c) + { + case 0: + break; + + case 'a': + all_files = 1; + really_all_files = 1; + break; + + case 'b': + set_quoting_style (0 , escape_quoting_style); + break; + + case 'c': + time_type = time_ctime; + break; + + case 'd': + immediate_dirs = 1; + break; + + case 'f': + + all_files = 1; + really_all_files = 1; + sort_type = sort_none; + sort_type_specified = 1; + + if (format == long_format) + format = (isatty (1 ) ? many_per_line : one_per_line); + print_block_size = 0; + print_with_color = 0; + break; + + case 'g': + format = long_format; + print_owner = 0; + break; + + case 'h': + human_output_opts = human_autoscale | human_SI | human_base_1024; + file_output_block_size = output_block_size = 1; + break; + + case 'i': + print_inode = 1; + break; + + case 'k': + human_output_opts = 0; + file_output_block_size = output_block_size = 1024; + break; + + case 'l': + format = long_format; + break; + + case 'm': + format = with_commas; + break; + + case 'n': + numeric_ids = 1; + format = long_format; + break; + + case 'o': + format = long_format; + print_group = 0; + break; + + case 'p': + indicator_style = file_type; + break; + + case 'q': + qmark_funny_chars = 1; + break; + + case 'r': + sort_reverse = 1; + break; + + case 's': + print_block_size = 1; + break; + + case 't': + sort_type = sort_time; + sort_type_specified = 1; + break; + + case 'u': + time_type = time_atime; + break; + + case 'v': + sort_type = sort_version; + sort_type_specified = 1; + break; + + case 'w': + { + long int tmp_long; + if (xstrtol (optarg, 0 , 0, &tmp_long, 0 ) != LONGINT_OK + || tmp_long <= 0 || tmp_long > (2147483647L) ) + error (1 , 0, ((const char *) ( "invalid line width: %s" )) , + quotearg (optarg)); + line_length = (int) tmp_long; + break; + } + + case 'x': + format = horizontal; + break; + + case 'A': + really_all_files = 0; + all_files = 1; + break; + + case 'B': + add_ignore_pattern ("*~"); + add_ignore_pattern (".*~"); + break; + + case 'C': + format = many_per_line; + break; + + case 'D': + dired = 1; + break; + + case 'F': + indicator_style = classify; + break; + + case 'G': + print_group = 0; + break; + + case 'H': + dereference = DEREF_COMMAND_LINE_ARGUMENTS; + break; + + case DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION: + dereference = DEREF_COMMAND_LINE_SYMLINK_TO_DIR; + break; + + case 'I': + add_ignore_pattern (optarg); + break; + + case 'L': + dereference = DEREF_ALWAYS; + break; + + case 'N': + set_quoting_style (0 , literal_quoting_style); + break; + + case 'Q': + set_quoting_style (0 , c_quoting_style); + break; + + case 'R': + recursive = 1; + break; + + case 'S': + sort_type = sort_size; + sort_type_specified = 1; + break; + + case 'T': + { + long int tmp_long; + if (xstrtol (optarg, 0 , 0, &tmp_long, 0 ) != LONGINT_OK + || tmp_long < 0 || tmp_long > (2147483647L) ) + error (1 , 0, ((const char *) ( "invalid tab size: %s" )) , + quotearg (optarg)); + tabsize = (int) tmp_long; + break; + } + + case 'U': + sort_type = sort_none; + sort_type_specified = 1; + break; + + case 'X': + sort_type = sort_extension; + sort_type_specified = 1; + break; + + case '1': + + if (format != long_format) + format = one_per_line; + break; + + case AUTHOR_OPTION: + print_author = true; + break; + + case SORT_OPTION: + sort_type = (( sort_types ) [__xargmatch_internal ( "--sort" , optarg , sort_args , (char const *) ( sort_types ), sizeof *( sort_types ), argmatch_die)]) ; + sort_type_specified = 1; + break; + + case TIME_OPTION: + time_type = (( time_types ) [__xargmatch_internal ( "--time" , optarg , time_args , (char const *) ( time_types ), sizeof *( time_types ), argmatch_die)]) ; + break; + + case FORMAT_OPTION: + format = (( format_types ) [__xargmatch_internal ( "--format" , optarg , format_args , (char const *) ( format_types ), sizeof *( format_types ), argmatch_die)]) ; + break; + + case FULL_TIME_OPTION: + format = long_format; + time_style_option = "full-iso"; + break; + + case COLOR_OPTION: + { + int i; + if (optarg) + i = (( color_types ) [__xargmatch_internal ( "--color" , optarg , color_args , (char const *) ( color_types ), sizeof *( color_types ), argmatch_die)]) ; + else + + + i = color_always; + + print_with_color = (i == color_always + || (i == color_if_tty + && isatty (1 ))); + + if (print_with_color) + { + + + + tabsize = 0; + } + break; + } + + case INDICATOR_STYLE_OPTION: + indicator_style = (( + indicator_style_types ) [__xargmatch_internal ( "--indicator-style" , optarg , + indicator_style_args , (char const *) ( indicator_style_types ), sizeof *( indicator_style_types ), argmatch_die)]) ; + break; + + case QUOTING_STYLE_OPTION: + set_quoting_style (0 , + (( + quoting_style_vals ) [__xargmatch_internal ( "--quoting-style" , optarg , + quoting_style_args , (char const *) ( quoting_style_vals ), sizeof *( quoting_style_vals ), argmatch_die)]) ); + break; + + case TIME_STYLE_OPTION: + time_style_option = optarg; + break; + + case SHOW_CONTROL_CHARS_OPTION: + qmark_funny_chars = 0; + break; + + case BLOCK_SIZE_OPTION: + human_output_opts = human_options (optarg, true, &output_block_size); + file_output_block_size = output_block_size; + break; + + case SI_OPTION: + human_output_opts = human_autoscale | human_SI; + file_output_block_size = output_block_size = 1; + break; + + case GETOPT_HELP_CHAR: usage (0 ); break; ; + + case GETOPT_VERSION_CHAR: version_etc (stdout, (ls_mode == 1 ? "ls" : (ls_mode == 2 ? "dir" : "vdir")) , "coreutils" , "5.0" , "Richard Stallman and David MacKenzie" ); exit (0 ); break; ; + + default: + usage (1 ); + } + } + + filename_quoting_options = clone_quoting_options (0 ); + if (get_quoting_style (filename_quoting_options) == escape_quoting_style) + set_char_quoting (filename_quoting_options, ' ', 1); + if (indicator_style != none) + { + char const *p; + for (p = "*=@|" + (int) indicator_style - 1; *p; p++) + set_char_quoting (filename_quoting_options, *p, 1); + } + + dirname_quoting_options = clone_quoting_options (0 ); + set_char_quoting (dirname_quoting_options, ':', 1); + + + + + if (dired && format != long_format) + dired = 0; + + + + + + + + + + if ((time_type == time_ctime || time_type == time_atime) + && !sort_type_specified && format != long_format) + { + sort_type = sort_time; + } + + if (format == long_format) + { + char *style = time_style_option; + static char const posix_prefix[] = "posix-"; + + if (! style) + if (! (style = getenv ("TIME_STYLE"))) + style = "posix-long-iso"; + + while (strncmp (style, posix_prefix, sizeof posix_prefix - 1) == 0) + { + if (! hard_locale (5 )) + return optind; + style += sizeof posix_prefix - 1; + } + + if (*style == '+') + { + char *p0 = style + 1; + char *p1 = strchr (p0, '\n'); + if (! p1) + p1 = p0; + else + { + if (strchr (p1 + 1, '\n')) + error (1 , 0, ((const char *) ( "invalid time style format %s" )) , + quote (p0)); + *p1++ = '\0'; + } + long_time_format[0] = p0; + long_time_format[1] = p1; + } + else + switch ((( + time_style_types ) [__xargmatch_internal ( "time style" , style , + time_style_args , (char const *) ( time_style_types ), sizeof *( time_style_types ), argmatch_die)]) ) + { + case full_iso_time_style: + long_time_format[0] = long_time_format[1] = + "%Y-%m-%d %H:%M:%S.%N %z"; + break; + + case long_iso_time_style: + long_time_format[0] = long_time_format[1] = "%Y-%m-%d %H:%M"; + break; + + case iso_time_style: + long_time_format[0] = "%Y-%m-%d "; + long_time_format[1] = "%m-%d %H:%M"; + break; + + case locale_time_style: + if (hard_locale (5 )) + { + unsigned int i; + for (i = 0; i < 2; i++) + long_time_format[i] = + ((const char *) ( long_time_format[i] )) ; + } + } + } + + return optind; +} + + + + + + + + + + + + + +static int +get_funky_string (char **dest, const char **src, int equals_end) +{ + int num; + int count; + enum { + ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR + } state; + const char *p; + char *q; + + p = *src; + q = *dest; + + count = 0; + num = 0; + + state = ST_GND; + while (state < ST_END) + { + switch (state) + { + case ST_GND: + switch (*p) + { + case ':': + case '\0': + state = ST_END; + break; + case '\\': + state = ST_BACKSLASH; + ++p; + break; + case '^': + state = ST_CARET; + ++p; + break; + case '=': + if (equals_end) + { + state = ST_END; + break; + } + + default: + *(q++) = *(p++); + ++count; + break; + } + break; + + case ST_BACKSLASH: + switch (*p) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + state = ST_OCTAL; + num = *p - '0'; + break; + case 'x': + case 'X': + state = ST_HEX; + num = 0; + break; + case 'a': + num = 7; + break; + case 'b': + num = '\b'; + break; + case 'e': + num = 27; + break; + case 'f': + num = '\f'; + break; + case 'n': + num = '\n'; + break; + case 'r': + num = '\r'; + break; + case 't': + num = '\t'; + break; + case 'v': + num = '\v'; + break; + case '?': + num = 127; + break; + case '_': + num = ' '; + break; + case '\0': + state = ST_ERROR; + break; + default: + num = *p; + break; + } + if (state == ST_BACKSLASH) + { + *(q++) = num; + ++count; + state = ST_GND; + } + ++p; + break; + + case ST_OCTAL: + if (*p < '0' || *p > '7') + { + *(q++) = num; + ++count; + state = ST_GND; + } + else + num = (num << 3) + (*(p++) - '0'); + break; + + case ST_HEX: + switch (*p) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + num = (num << 4) + (*(p++) - '0'); + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + num = (num << 4) + (*(p++) - 'a') + 10; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + num = (num << 4) + (*(p++) - 'A') + 10; + break; + default: + *(q++) = num; + ++count; + state = ST_GND; + break; + } + break; + + case ST_CARET: + state = ST_GND; + if (*p >= '@' && *p <= '~') + { + *(q++) = *(p++) & 037; + ++count; + } + else if (*p == '?') + { + *(q++) = 127; + ++count; + } + else + state = ST_ERROR; + break; + + default: + abort (); + } + } + + *dest = q; + *src = p; + + return state == ST_ERROR ? -1 : count; +} + +static void +parse_ls_color (void) +{ + const char *p; + char *buf; + int state; + int ind_no; + char label[3]; + struct color_ext_type *ext; + + if ((p = getenv ("LS_COLORS")) == 0 || *p == '\0') + return; + + ext = 0 ; + strcpy (label, "??"); + + + + + + buf = color_buf = xstrdup (p); + + state = 1; + while (state > 0) + { + switch (state) + { + case 1: + switch (*p) + { + case ':': + ++p; + break; + + case '*': + + + + + + ext = (( struct color_ext_type *) xmalloc (sizeof ( struct color_ext_type ) * ( 1 ))) ; + ext->next = color_ext_list; + color_ext_list = ext; + + ++p; + ext->ext.string = buf; + + state = (ext->ext.len = + get_funky_string (&buf, &p, 1)) < 0 ? -1 : 4; + break; + + case '\0': + state = 0; + break; + + default: + label[0] = *(p++); + state = 2; + break; + } + break; + + case 2: + if (*p) + { + label[1] = *(p++); + state = 3; + } + else + state = -1; + break; + + case 3: + state = -1; + if (*(p++) == '=') + { + for (ind_no = 0; indicator_name[ind_no] != 0 ; ++ind_no) + { + if ((strcmp (( label ), ( indicator_name[ind_no] )) == 0) ) + { + color_indicator[ind_no].string = buf; + state = ((color_indicator[ind_no].len = + get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1); + break; + } + } + if (state == -1) + error (0, 0, ((const char *) ( "unrecognized prefix: %s" )) , quotearg (label)); + } + break; + + case 4: + if (*(p++) == '=') + { + ext->seq.string = buf; + state = (ext->seq.len = + get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1; + } + else + state = -1; + break; + } + } + + if (state < 0) + { + struct color_ext_type *e; + struct color_ext_type *e2; + + error (0, 0, + ((const char *) ( "unparsable value for LS_COLORS environment variable" )) ); + free (color_buf); + for (e = color_ext_list; e != 0 ; ) + { + e2 = e; + e = e->next; + free (e2); + } + print_with_color = 0; + } + + if (color_indicator[C_LINK].len == 6 + && !strncmp (color_indicator[C_LINK].string, "target", 6)) + color_symlink_as_referent = 1; +} + + + + + + + + + + +static void +queue_directory (const char *name, const char *realname) +{ + struct pending *new; + + new = (( struct pending *) xmalloc (sizeof ( struct pending ) * ( 1 ))) ; + new->realname = realname ? xstrdup (realname) : 0 ; + new->name = name ? xstrdup (name) : 0 ; + new->next = pending_dirs; + pending_dirs = new; +} + + + + + +static void +print_dir (const char *name, const char *realname) +{ + register DIR *dirp; + register struct dirent *next; + register uintmax_t total_blocks = 0; + static int first = 1; + + (*(_errnop())) = 0; + dirp = opendir (name); + if (!dirp) + { + error (0, (*(_errnop())) , "%s", quotearg_colon (name)); + exit_status = 1; + return; + } + + if ((!!active_dir_set) ) + { + struct stat dir_stat; + int fd = dirfd (dirp); + + + if ((0 <= fd + ? fstat (fd, &dir_stat) + : stat (name, &dir_stat)) < 0) + { + error (0, (*(_errnop())) , ((const char *) ( "cannot determine device and inode of %s" )) , + quotearg_colon (name)); + exit_status = 1; + return; + } + + + + if (visit_dir (dir_stat.st_dev, dir_stat.st_ino)) + { + error (0, 0, ((const char *) ( "not listing already-listed directory: %s" )) , + quotearg_colon (name)); + return; + } + + do { struct dev_ino *di; __extension__ ({ struct obstack *__o = ( &dev_ino_obstack ); int __len = ( sizeof (struct dev_ino) ); if (__o->chunk_limit - __o->next_free < __len) _obstack_newchunk (__o, __len); __o->next_free += __len; (void) 0; }) ; di = -1 + (struct dev_ino *) (( &dev_ino_obstack )->next_free) ; di->st_dev = ( dir_stat.st_dev ); di->st_ino = ( dir_stat.st_ino ); } while (0) ; + } + + + + + clear_files (); + + while (1) + { + + + (*(_errnop())) = 0; + if ((next = readdir (dirp)) == 0 ) + { + if ((*(_errnop())) ) + { + + int e = (*(_errnop())) ; + closedir (dirp); + (*(_errnop())) = e; + + + dirp = 0 ; + } + break; + } + + if (file_interesting (next)) + { + enum filetype type = unknown; + +# 2201 "ls.c" + + total_blocks += gobble_file (next->d_name, type, 0, name); + } + } + + if (dirp == 0 || closedir ( dirp ) ) + { + error (0, (*(_errnop())) , ((const char *) ( "reading directory %s" )) , quotearg_colon (name)); + exit_status = 1; + + } + + + sort_files (); + + + + + if (recursive) + extract_dirs_from_files (name, 1); + + if (recursive || print_dir_name) + { + if (!first) + do {putchar_unlocked ( ( '\n' ) ) ; ++dired_pos;} while (0) ; + first = 0; + do { if (dired) do {fputs (( " " ), ( stdout )); dired_pos += sizeof(( " " )) - 1;} while (0) ; } while (0) ; + do { if (dired) __extension__ ({ struct obstack *__o = ( ( &subdired_obstack ) ); int __len = ( sizeof (dired_pos) ); if (__o->next_free + __len > __o->chunk_limit) _obstack_newchunk (__o, __len); memcpy (( __o->next_free ), ( ( &dired_pos ) ), ( __len )) ; __o->next_free += __len; (void) 0; }) ; } while (0) ; + dired_pos += quote_name (stdout, realname ? realname : name, + dirname_quoting_options, 0 ); + do { if (dired) __extension__ ({ struct obstack *__o = ( ( &subdired_obstack ) ); int __len = ( sizeof (dired_pos) ); if (__o->next_free + __len > __o->chunk_limit) _obstack_newchunk (__o, __len); memcpy (( __o->next_free ), ( ( &dired_pos ) ), ( __len )) ; __o->next_free += __len; (void) 0; }) ; } while (0) ; + do {fputs (( ":\n" ), ( stdout )); dired_pos += sizeof(( ":\n" )) - 1;} while (0) ; + } + + if (format == long_format || print_block_size) + { + const char *p; + char buf[((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) + 1]; + + do { if (dired) do {fputs (( " " ), ( stdout )); dired_pos += sizeof(( " " )) - 1;} while (0) ; } while (0) ; + p = ((const char *) ( "total" )) ; + do {fputs (( p ), ( stdout )); dired_pos += strlen (p) ;} while (0) ; + do {putchar_unlocked ( ( ' ' ) ) ; ++dired_pos;} while (0) ; + p = human_readable (total_blocks, buf, human_output_opts, + 512 , output_block_size); + do {fputs (( p ), ( stdout )); dired_pos += strlen (p) ;} while (0) ; + do {putchar_unlocked ( ( '\n' ) ) ; ++dired_pos;} while (0) ; + } + + if (files_index) + print_current_files (); +} + + + + +static void +add_ignore_pattern (const char *pattern) +{ + register struct ignore_pattern *ignore; + + ignore = (( struct ignore_pattern *) xmalloc (sizeof ( struct ignore_pattern ) * ( 1 ))) ; + ignore->pattern = pattern; + + ignore->next = ignore_patterns; + ignore_patterns = ignore; +} + + + +static int +file_interesting (const struct dirent *next) +{ + register struct ignore_pattern *ignore; + + for (ignore = ignore_patterns; ignore; ignore = ignore->next) + if (rpl_fnmatch (ignore->pattern, next->d_name, (1 << 2) ) == 0) + return 0; + + if (really_all_files + || next->d_name[0] != '.' + || (all_files + && next->d_name[1] != '\0' + && (next->d_name[1] != '.' || next->d_name[2] != '\0'))) + return 1; + + return 0; +} + + + + + +static void +clear_files (void) +{ + register int i; + + for (i = 0; i < files_index; i++) + { + free (files[i].name); + if (files[i].linkname) + free (files[i].linkname); + } + + files_index = 0; + block_size_size = 4; +} + + + + + +static uintmax_t +gobble_file (const char *name, enum filetype type, int explicit_arg, + const char *dirname) +{ + register uintmax_t blocks; + register char *path; + + if (files_index == nfiles) + { + nfiles *= 2; + files = (( struct fileinfo *) xrealloc ((void *) ( files ), sizeof ( struct fileinfo ) * ( nfiles ))) ; + } + + files[files_index].linkname = 0; + files[files_index].linkmode = 0; + files[files_index].linkok = 0; + + if (explicit_arg + || format_needs_stat + || (format_needs_type + && (type == unknown + + + + + || type == symbolic_link + + + + + || (type == normal && (indicator_style == classify + + + + + || print_with_color))))) + + { + + int err; + + if (name[0] == '/' || dirname[0] == 0) + path = (char *) name; + else + { + path = (char *) __builtin_alloca ( strlen (name) + strlen (dirname) + 2 ) ; + attach (path, dirname, name); + } + + switch (dereference) + { + case DEREF_ALWAYS: + err = stat (path, &files[files_index].stat); + break; + + case DEREF_COMMAND_LINE_ARGUMENTS: + case DEREF_COMMAND_LINE_SYMLINK_TO_DIR: + if (explicit_arg) + { + int need_lstat; + err = stat (path, &files[files_index].stat); + + if (dereference == DEREF_COMMAND_LINE_ARGUMENTS) + break; + + need_lstat = (err < 0 + ? (*(_errnop())) == B_ENTRY_NOT_FOUND + : ! ((( files[files_index].stat.st_mode ) & 00000170000 ) == 00000040000 ) ); + if (!need_lstat) + break; + + + + + + } + + default: + err = lstat (path, &files[files_index].stat); + break; + } + + if (err < 0) + { + error (0, (*(_errnop())) , "%s", quotearg_colon (path)); + exit_status = 1; + return 0; + } + +# 2411 "ls.c" + + + if (((( files[files_index].stat.st_mode ) & 00000170000 ) == 00000120000 ) + && (format == long_format || check_symlink_color)) + { + char *linkpath; + struct stat linkstats; + + get_link_name (path, &files[files_index]); + linkpath = make_link_path (path, files[files_index].linkname); + + + + if (linkpath + && (indicator_style != none || check_symlink_color) + && stat (linkpath, &linkstats) == 0) + { + files[files_index].linkok = 1; + + + + + if (!explicit_arg || format == long_format + || ! ((( linkstats.st_mode ) & 00000170000 ) == 00000040000 ) ) + { + + + files[files_index].linkmode = linkstats.st_mode; + files[files_index].linkok = 1; + } + } + if (linkpath) + free (linkpath); + } + + if (((( files[files_index].stat.st_mode ) & 00000170000 ) == 00000120000 ) ) + files[files_index].filetype = symbolic_link; + else if (((( files[files_index].stat.st_mode ) & 00000170000 ) == 00000040000 ) ) + { + if (explicit_arg && !immediate_dirs) + files[files_index].filetype = arg_directory; + else + files[files_index].filetype = directory; + } + else + files[files_index].filetype = normal; + + blocks = (( files[files_index].stat ).st_size / 512 + (( files[files_index].stat ).st_size % 512 != 0)) ; + { + char buf[((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) + 1]; + int len = strlen (human_readable (blocks, buf, human_output_opts, + 512 , output_block_size)); + if (block_size_size < len) + block_size_size = len < 7 ? len : 7; + } + } + else + { + files[files_index].filetype = type; + + + + blocks = 0; + } + + files[files_index].name = xstrdup (name); + files_index++; + + return blocks; +} + + + + + + +static void +get_link_name (const char *filename, struct fileinfo *f) +{ + f->linkname = xreadlink (filename); + if (f->linkname == 0 ) + { + error (0, (*(_errnop())) , ((const char *) ( "cannot read symbolic link %s" )) , + quotearg_colon (filename)); + exit_status = 1; + } +} + + + + + + +static char * +make_link_path (const char *path, const char *linkname) +{ + char *linkbuf; + size_t bufsiz; + + if (linkname == 0) + return 0; + + if (*linkname == '/') + return xstrdup (linkname); + + + + linkbuf = strrchr (path, '/'); + if (linkbuf == 0) + return xstrdup (linkname); + + bufsiz = linkbuf - path + 1; + linkbuf = xmalloc (bufsiz + strlen (linkname) + 1); + strncpy (linkbuf, path, bufsiz); + strcpy (linkbuf + bufsiz, linkname); + return linkbuf; +} + + + + + +static int +basename_is_dot_or_dotdot (const char *name) +{ + char const *base = base_name (name); + return ( base [0] == '.' && ( base [1] == '\0' || ( base [1] == '.' && base [2] == '\0'))) ; +} + + + + + + + + +static void +extract_dirs_from_files (const char *dirname, int ignore_dot_and_dot_dot) +{ + register int i, j; + + if (*dirname && (!!active_dir_set) ) + { + + + + queue_directory (0 , dirname); + } + + + + for (i = files_index - 1; i >= 0; i--) + if ((files[i].filetype == directory || files[i].filetype == arg_directory) + && (!ignore_dot_and_dot_dot + || !basename_is_dot_or_dotdot (files[i].name))) + { + if (files[i].name[0] == '/' || dirname[0] == 0) + { + queue_directory (files[i].name, files[i].linkname); + } + else + { + char *path = path_concat (dirname, files[i].name, 0 ); + queue_directory (path, files[i].linkname); + free (path); + } + if (files[i].filetype == arg_directory) + free (files[i].name); + } + + + + + for (i = 0, j = 0; i < files_index; i++) + if (files[i].filetype != arg_directory) + files[j++] = files[i]; + files_index = j; +} + + + + +static jmp_buf failed_strcoll; + +static int +xstrcoll (char const *a, char const *b) +{ + int diff; + (*(_errnop())) = 0; + diff = strcoll (a, b); + if ((*(_errnop())) ) + { + error (0, (*(_errnop())) , ((const char *) ( "cannot compare file names %s and %s" )) , + quote_n (0, a), quote_n (1, b)); + exit_status = 1; + longjmp (failed_strcoll, 1); + } + return diff; +} + + + +typedef void const *V; + +static inline int +cmp_ctime (struct fileinfo const *a, struct fileinfo const *b, + int (*cmp) (char const *, char const *)) +{ + int diff = (( b->stat ). st_ctime < ( a->stat ). st_ctime ? -1 : ( b->stat ). st_ctime > ( a->stat ). st_ctime ? 1 : 0 ) ; + return diff ? diff : cmp (a->name, b->name); +} +static int compare_ctime (V a, V b) { return cmp_ctime (a, b, xstrcoll); } +static int compstr_ctime (V a, V b) { return cmp_ctime (a, b, strcmp); } +static int rev_cmp_ctime (V a, V b) { return compare_ctime (b, a); } +static int rev_str_ctime (V a, V b) { return compstr_ctime (b, a); } + +static inline int +cmp_mtime (struct fileinfo const *a, struct fileinfo const *b, + int (*cmp) (char const *, char const *)) +{ + int diff = (( b->stat ). st_mtime < ( a->stat ). st_mtime ? -1 : ( b->stat ). st_mtime > ( a->stat ). st_mtime ? 1 : 0 ) ; + return diff ? diff : cmp (a->name, b->name); +} +static int compare_mtime (V a, V b) { return cmp_mtime (a, b, xstrcoll); } +static int compstr_mtime (V a, V b) { return cmp_mtime (a, b, strcmp); } +static int rev_cmp_mtime (V a, V b) { return compare_mtime (b, a); } +static int rev_str_mtime (V a, V b) { return compstr_mtime (b, a); } + +static inline int +cmp_atime (struct fileinfo const *a, struct fileinfo const *b, + int (*cmp) (char const *, char const *)) +{ + int diff = (( b->stat ). st_atime < ( a->stat ). st_atime ? -1 : ( b->stat ). st_atime > ( a->stat ). st_atime ? 1 : 0 ) ; + return diff ? diff : cmp (a->name, b->name); +} +static int compare_atime (V a, V b) { return cmp_atime (a, b, xstrcoll); } +static int compstr_atime (V a, V b) { return cmp_atime (a, b, strcmp); } +static int rev_cmp_atime (V a, V b) { return compare_atime (b, a); } +static int rev_str_atime (V a, V b) { return compstr_atime (b, a); } + +static inline int +cmp_size (struct fileinfo const *a, struct fileinfo const *b, + int (*cmp) (char const *, char const *)) +{ + int diff = (( b->stat.st_size ) < ( a->stat.st_size ) ? -1 : ( b->stat.st_size ) > ( a->stat.st_size )) ; + return diff ? diff : cmp (a->name, b->name); +} +static int compare_size (V a, V b) { return cmp_size (a, b, xstrcoll); } +static int compstr_size (V a, V b) { return cmp_size (a, b, strcmp); } +static int rev_cmp_size (V a, V b) { return compare_size (b, a); } +static int rev_str_size (V a, V b) { return compstr_size (b, a); } + +static inline int +cmp_version (struct fileinfo const *a, struct fileinfo const *b) +{ + return strverscmp (a->name, b->name); +} +static int compare_version (V a, V b) { return cmp_version (a, b); } +static int rev_cmp_version (V a, V b) { return compare_version (b, a); } + +static inline int +cmp_name (struct fileinfo const *a, struct fileinfo const *b, + int (*cmp) (char const *, char const *)) +{ + return cmp (a->name, b->name); +} +static int compare_name (V a, V b) { return cmp_name (a, b, xstrcoll); } +static int compstr_name (V a, V b) { return cmp_name (a, b, strcmp); } +static int rev_cmp_name (V a, V b) { return compare_name (b, a); } +static int rev_str_name (V a, V b) { return compstr_name (b, a); } + + + + +static inline int +cmp_extension (struct fileinfo const *a, struct fileinfo const *b, + int (*cmp) (char const *, char const *)) +{ + char const *base1 = strrchr (a->name, '.'); + char const *base2 = strrchr (b->name, '.'); + int diff = cmp (base1 ? base1 : "", base2 ? base2 : ""); + return diff ? diff : cmp (a->name, b->name); +} +static int compare_extension (V a, V b) { return cmp_extension (a, b, xstrcoll); } +static int compstr_extension (V a, V b) { return cmp_extension (a, b, strcmp); } +static int rev_cmp_extension (V a, V b) { return compare_extension (b, a); } +static int rev_str_extension (V a, V b) { return compstr_extension (b, a); } + + + +static void +sort_files (void) +{ + int (*func) (V, V); + + switch (sort_type) + { + case sort_none: + return; + case sort_time: + switch (time_type) + { + case time_ctime: + func = sort_reverse ? rev_cmp_ctime : compare_ctime; + break; + case time_mtime: + func = sort_reverse ? rev_cmp_mtime : compare_mtime; + break; + case time_atime: + func = sort_reverse ? rev_cmp_atime : compare_atime; + break; + default: + abort (); + } + break; + case sort_name: + func = sort_reverse ? rev_cmp_name : compare_name; + break; + case sort_extension: + func = sort_reverse ? rev_cmp_extension : compare_extension; + break; + case sort_size: + func = sort_reverse ? rev_cmp_size : compare_size; + break; + case sort_version: + func = sort_reverse ? rev_cmp_version : compare_version; + break; + default: + abort (); + } + + + + + + + if (__sigsetjmp (( failed_strcoll ), 0) ) + { + switch (sort_type) + { + case sort_time: + switch (time_type) + { + case time_ctime: + func = sort_reverse ? rev_str_ctime : compstr_ctime; + break; + case time_mtime: + func = sort_reverse ? rev_str_mtime : compstr_mtime; + break; + case time_atime: + func = sort_reverse ? rev_str_atime : compstr_atime; + break; + default: + abort (); + } + break; + case sort_name: + func = sort_reverse ? rev_str_name : compstr_name; + break; + case sort_extension: + func = sort_reverse ? rev_str_extension : compstr_extension; + break; + case sort_size: + func = sort_reverse ? rev_str_size : compstr_size; + break; + default: + abort (); + } + } + + qsort (files, files_index, sizeof (struct fileinfo), func); +} + + + +static void +print_current_files (void) +{ + register int i; + + switch (format) + { + case one_per_line: + for (i = 0; i < files_index; i++) + { + print_file_name_and_frills (files + i); + putchar_unlocked ( '\n' ) ; + } + break; + + case many_per_line: + init_column_info (); + print_many_per_line (); + break; + + case horizontal: + init_column_info (); + print_horizontal (); + break; + + case with_commas: + print_with_commas (); + break; + + case long_format: + for (i = 0; i < files_index; i++) + { + print_long_format (files + i); + do {putchar_unlocked ( ( '\n' ) ) ; ++dired_pos;} while (0) ; + } + break; + } +} + + + + +static int +long_time_expected_width (void) +{ + static int width = -1; + + if (width < 0) + { + time_t epoch = 0; + struct tm const *tm = localtime (&epoch); + char const *fmt = long_time_format[0]; + char initbuf[100]; + char *buf = initbuf; + size_t bufsize = sizeof initbuf; + size_t len; + + for (;;) + { + *buf = '\1'; + len = nstrftime (buf, bufsize, fmt, tm, 0, 0); + if (len || ! *buf) + break; + buf = __builtin_alloca ( bufsize *= 2 ) ; + } + + width = mbsnwidth (buf, len, 0); + if (width < 0) + width = 0; + } + + return width; +} + + + +static void +get_current_time (void) +{ +# 2875 "ls.c" + + + + + + + + + + { + struct timeval timeval; + if (gettimeofday (&timeval, 0 ) == 0) + { + current_time = timeval.tv_sec; + current_time_ns = timeval.tv_usec * 1000 + 999; + return; + } + } + + + current_time = time (0 ); + current_time_ns = 999999999; +} + + + + + +static size_t +format_user (char *buffer, uid_t u) +{ + char const *name = (numeric_ids ? 0 : getuser (u)); + if (name) + sprintf (buffer, "%-8s ", name); + else + sprintf (buffer, "%-8lu ", (unsigned long) u); + return strlen (buffer); +} + + + +static void +print_long_format (const struct fileinfo *f) +{ + char modebuf[12]; + char init_bigbuf + [((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) + 1 + + ((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) + 1 + + sizeof (modebuf) - 1 + 1 + + ((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) + 1 + + ((( (32) - 1 ) > ( ((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) )) ? ( (32) - 1 ) : ( ((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) )) + 1 + + ((( (32) - 1 ) > ( ((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) )) ? ( (32) - 1 ) : ( ((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) )) + 1 + + ((( (32) - 1 ) > ( ((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) )) ? ( (32) - 1 ) : ( ((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) )) + 1 + + ((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) + 1 + + ((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) + 1 + + 35 + 1 + ]; + char *buf = init_bigbuf; + size_t bufsize = sizeof (init_bigbuf); + size_t s; + char *p; + time_t when; + int when_ns ; + struct tm *when_local; + + + + + mode_string ((( f->stat ).st_mode) , modebuf); + + modebuf[10] = (0 ? '+' : ' '); + modebuf[11] = '\0'; + + switch (time_type) + { + case time_ctime: + when = f->stat.st_ctime; + when_ns = 0 ; + break; + case time_mtime: + when = f->stat.st_mtime; + when_ns = 0 ; + break; + case time_atime: + when = f->stat.st_atime; + when_ns = 0 ; + break; + } + + p = buf; + + if (print_inode) + { + char hbuf[((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) + 1]; + sprintf (p, "%*s ", 7 , umaxtostr (f->stat.st_ino, hbuf)); + p += strlen (p); + } + + if (print_block_size) + { + char hbuf[((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) + 1]; + sprintf (p, "%*s ", block_size_size, + human_readable ((( f->stat ).st_size / 512 + (( f->stat ).st_size % 512 != 0)) , hbuf, human_output_opts, + 512 , output_block_size)); + p += strlen (p); + } + + + + sprintf (p, "%s %3lu ", modebuf, (unsigned long) f->stat.st_nlink); + p += strlen (p); + + if (print_owner) + p += format_user (p, f->stat.st_uid); + + if (print_group) + { + char const *group_name = (numeric_ids ? 0 : getgroup (f->stat.st_gid)); + if (group_name) + sprintf (p, "%-8s ", group_name); + else + sprintf (p, "%-8lu ", (unsigned long) f->stat.st_gid); + p += strlen (p); + } + + if (print_author) + p += format_user (p, f->stat. st_uid ); + + if (((( f->stat.st_mode ) & 00000170000 ) == 00000020000 ) || ((( f->stat.st_mode ) & 00000170000 ) == 00000060000 ) ) + sprintf (p, "%3lu, %3lu ", + (unsigned long) (int)((unsigned)(( f->stat.st_rdev )>>8)&0x7F) , + (unsigned long) (int)(( f->stat.st_rdev )&0xFF) ); + else + { + char hbuf[((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) + 1]; + uintmax_t size = f->stat.st_size; + + + + + size += (f->stat.st_size < 0) * ((uintmax_t) (( off_t ) (~ ( off_t ) 0 - (( off_t ) ((! (( off_t ) 0 < ( off_t ) -1)) ? ~ ( off_t ) 0 << (sizeof ( off_t ) * (8) - 1) : ( off_t ) 0)) )) - (( off_t ) ((! (( off_t ) 0 < ( off_t ) -1)) ? ~ ( off_t ) 0 << (sizeof ( off_t ) * (8) - 1) : ( off_t ) 0)) + 1); + + sprintf (p, "%8s ", + human_readable (size, hbuf, human_output_opts, + 1, file_output_block_size)); + } + + p += strlen (p); + + if ((when_local = localtime (&when))) + { + time_t six_months_ago; + int recent; + char const *fmt; + + + + + if (current_time < when + || (current_time == when && current_time_ns < when_ns)) + { + + + + + get_current_time (); + } + + + + + + six_months_ago = current_time - 31556952 / 2; + recent = (six_months_ago <= when + && (when < current_time + || (when == current_time && when_ns <= current_time_ns))); + fmt = long_time_format[recent]; + + for (;;) + { + char *newbuf; + *p = '\1'; + s = nstrftime (p, buf + bufsize - p - 1, fmt, + when_local, 0, when_ns); + if (s || ! *p) + break; + newbuf = __builtin_alloca ( bufsize *= 2 ) ; + memcpy (newbuf, buf, p - buf); + p = newbuf + (p - buf); + buf = newbuf; + } + + p += s; + *p++ = ' '; + + + *p = '\0'; + } + else + { + + + char hbuf[(((sizeof ( intmax_t ) * (8) - 1) * 302 / 1000 + 2) + 1) ]; + sprintf (p, "%*s ", long_time_expected_width (), + ((! (( time_t ) 0 < ( time_t ) -1)) + ? imaxtostr (when, hbuf) + : umaxtostr (when, hbuf))); + p += strlen (p); + } + + do { if (dired) do {fputs (( " " ), ( stdout )); dired_pos += sizeof(( " " )) - 1;} while (0) ; } while (0) ; + do {fputs (( buf ), ( stdout )); dired_pos += p - buf ;} while (0) ; + print_name_with_quoting (f->name, ((color_symlink_as_referent && ( f )->linkok) ? ( f )->linkmode : ( f )->stat.st_mode) , f->linkok, + &dired_obstack); + + if (f->filetype == symbolic_link) + { + if (f->linkname) + { + do {fputs (( " -> " ), ( stdout )); dired_pos += sizeof(( " -> " )) - 1;} while (0) ; + print_name_with_quoting (f->linkname, f->linkmode, f->linkok - 1, + 0 ); + if (indicator_style != none) + print_type_indicator (f->linkmode); + } + } + else if (indicator_style != none) + print_type_indicator (f->stat.st_mode); +} + + + + + + + +static size_t +quote_name (FILE *out, const char *name, struct quoting_options const *options, + size_t *width) +{ + char smallbuf[8192 ]; + size_t len = quotearg_buffer (smallbuf, sizeof smallbuf, name, -1, options); + char *buf; + size_t displayed_width ; + + if (len < sizeof smallbuf) + buf = smallbuf; + else + { + buf = (char *) __builtin_alloca ( len + 1 ) ; + quotearg_buffer (buf, len + 1, name, -1, options); + } + + if (qmark_funny_chars) + { +# 3234 "ls.c" + + { + char *p = buf; + char const *plimit = buf + len; + + while (p < plimit) + { + if (! (1 && isprint ( (unsigned char) *p )) ) + *p = '?'; + p++; + } + displayed_width = len; + } + } + else if (width != 0 ) + { + + + + + + { + char const *p = buf; + char const *plimit = buf + len; + + displayed_width = 0; + while (p < plimit) + { + if ((1 && isprint ( (unsigned char) *p )) ) + displayed_width++; + p++; + } + } + } + + if (out != 0 ) + fwrite_unlocked ( buf , 1 , len , out ) ; + if (width != 0 ) + *width = displayed_width; + return len; +} + +static void +print_name_with_quoting (const char *p, mode_t mode, int linkok, + struct obstack *stack) +{ + if (print_with_color) + print_color_indicator (p, mode, linkok); + + if (stack) + do { if (dired) __extension__ ({ struct obstack *__o = ( ( stack ) ); int __len = ( sizeof (dired_pos) ); if (__o->next_free + __len > __o->chunk_limit) _obstack_newchunk (__o, __len); memcpy (( __o->next_free ), ( ( &dired_pos ) ), ( __len )) ; __o->next_free += __len; (void) 0; }) ; } while (0) ; + + dired_pos += quote_name (stdout, p, filename_quoting_options, 0 ); + + if (stack) + do { if (dired) __extension__ ({ struct obstack *__o = ( ( stack ) ); int __len = ( sizeof (dired_pos) ); if (__o->next_free + __len > __o->chunk_limit) _obstack_newchunk (__o, __len); memcpy (( __o->next_free ), ( ( &dired_pos ) ), ( __len )) ; __o->next_free += __len; (void) 0; }) ; } while (0) ; + + if (print_with_color) + prep_non_filename_text (); +} + +static void +prep_non_filename_text (void) +{ + if (color_indicator[C_END].string != 0 ) + put_indicator (&color_indicator[C_END]); + else + { + put_indicator (&color_indicator[C_LEFT]); + put_indicator (&color_indicator[C_NORM]); + put_indicator (&color_indicator[C_RIGHT]); + } +} + + + + + +static void +print_file_name_and_frills (const struct fileinfo *f) +{ + char buf[((( ((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) + 1 ) > ( (((sizeof ( uintmax_t ) * (8) - 1) * 302 / 1000 + 2) + 1) )) ? ( ((2 * sizeof (uintmax_t) * (8) * 302 / 1000 + 1) * ((1) + 1) - (1) + 3) + 1 ) : ( (((sizeof ( uintmax_t ) * (8) - 1) * 302 / 1000 + 2) + 1) )) ]; + + if (print_inode) + printf ("%*s ", 7 , umaxtostr (f->stat.st_ino, buf)); + + if (print_block_size) + printf ("%*s ", block_size_size, + human_readable ((( f->stat ).st_size / 512 + (( f->stat ).st_size % 512 != 0)) , buf, human_output_opts, + 512 , output_block_size)); + + print_name_with_quoting (f->name, ((color_symlink_as_referent && ( f )->linkok) ? ( f )->linkmode : ( f )->stat.st_mode) , f->linkok, 0 ); + + if (indicator_style != none) + print_type_indicator (f->stat.st_mode); +} + +static void +print_type_indicator (mode_t mode) +{ + int c; + + if (((( mode ) & 00000170000 ) == 00000100000 ) ) + { + if (indicator_style == classify && (mode & (00100 | 00010 | 00001 ) )) + c ='*'; + else + c = 0; + } + else + { + if (((( mode ) & 00000170000 ) == 00000040000 ) ) + c = '/'; + else if (((( mode ) & 00000170000 ) == 00000120000 ) ) + c = '@'; + else if (((( mode ) & 00000170000 ) == 00000010000 ) ) + c = '|'; + else if (0 ) + c = '='; + else if (0 ) + c = '>'; + else + c = 0; + } + + if (c) + do {putchar_unlocked ( ( c ) ) ; ++dired_pos;} while (0) ; +} + +static void +print_color_indicator (const char *name, mode_t mode, int linkok) +{ + int type = C_FILE; + struct color_ext_type *ext; + size_t len; + + + + if (linkok == -1 && color_indicator[C_MISSING].string != 0 ) + { + ext = 0 ; + type = C_MISSING; + } + else + { + if (((( mode ) & 00000170000 ) == 00000040000 ) ) + type = C_DIR; + else if (((( mode ) & 00000170000 ) == 00000120000 ) ) + type = ((!linkok && color_indicator[C_ORPHAN].string) + ? C_ORPHAN : C_LINK); + else if (((( mode ) & 00000170000 ) == 00000010000 ) ) + type = C_FIFO; + else if (0 ) + type = C_SOCK; + else if (((( mode ) & 00000170000 ) == 00000060000 ) ) + type = C_BLK; + else if (((( mode ) & 00000170000 ) == 00000020000 ) ) + type = C_CHR; + else if (0 ) + type = C_DOOR; + + if (type == C_FILE && (mode & (00100 | 00010 | 00001 ) ) != 0) + type = C_EXEC; + + + ext = 0 ; + if (type == C_FILE) + { + + + len = strlen (name); + name += len; + for (ext = color_ext_list; ext != 0 ; ext = ext->next) + { + if ((size_t) ext->ext.len <= len + && strncmp (name - ext->ext.len, ext->ext.string, + ext->ext.len) == 0) + break; + } + } + } + + put_indicator (&color_indicator[C_LEFT]); + put_indicator (ext ? &(ext->seq) : &color_indicator[type]); + put_indicator (&color_indicator[C_RIGHT]); +} + + +static void +put_indicator (const struct bin_str *ind) +{ + register int i; + register const char *p; + + p = ind->string; + + for (i = ind->len; i > 0; --i) + putchar_unlocked ( *(p++) ) ; +} + + + + +static int +put_indicator_direct (const struct bin_str *ind) +{ + size_t len; + if (ind->len <= 0) + return 0; + + len = ind->len; + return (full_write (1 , ind->string, len) != len); +} + +static int +length_of_file_name_and_frills (const struct fileinfo *f) +{ + register int len = 0; + size_t name_width; + + if (print_inode) + len += 7 + 1; + + if (print_block_size) + len += 1 + block_size_size; + + quote_name (0 , f->name, filename_quoting_options, &name_width); + len += name_width; + + if (indicator_style != none) + { + mode_t filetype = f->stat.st_mode; + + if (((( filetype ) & 00000170000 ) == 00000100000 ) ) + { + if (indicator_style == classify + && (f->stat.st_mode & (00100 | 00010 | 00001 ) )) + len += 1; + } + else if (((( filetype ) & 00000170000 ) == 00000040000 ) + || ((( filetype ) & 00000170000 ) == 00000120000 ) + || ((( filetype ) & 00000170000 ) == 00000010000 ) + || 0 + || 0 + ) + len += 1; + } + + return len; +} + +static void +print_many_per_line (void) +{ + struct column_info *line_fmt; + int filesno; + int row; + int max_name_length; + int name_length; + int pos; + int cols; + int rows; + int max_cols; + + + + + max_cols = max_idx > files_index ? files_index : max_idx; + + + for (filesno = 0; filesno < files_index; ++filesno) + { + int i; + + name_length = length_of_file_name_and_frills (files + filesno); + + for (i = 0; i < max_cols; ++i) + { + if (column_info[i].valid_len) + { + int idx = filesno / ((files_index + i) / (i + 1)); + int real_length = name_length + (idx == i ? 0 : 2); + + if (real_length > column_info[i].col_arr[idx]) + { + column_info[i].line_len += (real_length + - column_info[i].col_arr[idx]); + column_info[i].col_arr[idx] = real_length; + column_info[i].valid_len = column_info[i].line_len < line_length; + } + } + } + } + + + for (cols = max_cols; cols > 1; --cols) + { + if (column_info[cols - 1].valid_len) + break; + } + + line_fmt = &column_info[cols - 1]; + + + + rows = files_index / cols + (files_index % cols != 0); + + for (row = 0; row < rows; row++) + { + int col = 0; + filesno = row; + pos = 0; + + while (1) + { + print_file_name_and_frills (files + filesno); + name_length = length_of_file_name_and_frills (files + filesno); + max_name_length = line_fmt->col_arr[col++]; + + filesno += rows; + if (filesno >= files_index) + break; + + indent (pos + name_length, pos + max_name_length); + pos += max_name_length; + } + putchar_unlocked ( '\n' ) ; + } +} + +static void +print_horizontal (void) +{ + struct column_info *line_fmt; + int filesno; + int max_name_length; + int name_length; + int cols; + int pos; + int max_cols; + + + + + max_cols = max_idx > files_index ? files_index : max_idx; + + + max_name_length = 0; + for (filesno = 0; filesno < files_index; ++filesno) + { + int i; + + name_length = length_of_file_name_and_frills (files + filesno); + + for (i = 0; i < max_cols; ++i) + { + if (column_info[i].valid_len) + { + int idx = filesno % (i + 1); + int real_length = name_length + (idx == i ? 0 : 2); + + if (real_length > column_info[i].col_arr[idx]) + { + column_info[i].line_len += (real_length + - column_info[i].col_arr[idx]); + column_info[i].col_arr[idx] = real_length; + column_info[i].valid_len = column_info[i].line_len < line_length; + } + } + } + } + + + for (cols = max_cols; cols > 1; --cols) + { + if (column_info[cols - 1].valid_len) + break; + } + + line_fmt = &column_info[cols - 1]; + + pos = 0; + + + print_file_name_and_frills (files); + name_length = length_of_file_name_and_frills (files); + max_name_length = line_fmt->col_arr[0]; + + + for (filesno = 1; filesno < files_index; ++filesno) + { + int col = filesno % cols; + + if (col == 0) + { + putchar_unlocked ( '\n' ) ; + pos = 0; + } + else + { + indent (pos + name_length, pos + max_name_length); + pos += max_name_length; + } + + print_file_name_and_frills (files + filesno); + + name_length = length_of_file_name_and_frills (files + filesno); + max_name_length = line_fmt->col_arr[col]; + } + putchar_unlocked ( '\n' ) ; +} + +static void +print_with_commas (void) +{ + int filesno; + int pos, old_pos; + + pos = 0; + + for (filesno = 0; filesno < files_index; filesno++) + { + old_pos = pos; + + pos += length_of_file_name_and_frills (files + filesno); + if (filesno + 1 < files_index) + pos += 2; + + if (old_pos != 0 && pos >= line_length) + { + putchar_unlocked ( '\n' ) ; + pos -= old_pos; + } + + print_file_name_and_frills (files + filesno); + if (filesno + 1 < files_index) + { + putchar_unlocked ( ',' ) ; + putchar_unlocked ( ' ' ) ; + } + } + putchar_unlocked ( '\n' ) ; +} + + + + +static void +indent (int from, int to) +{ + while (from < to) + { + if (tabsize > 0 && to / tabsize > (from + 1) / tabsize) + { + putchar_unlocked ( '\t' ) ; + from += tabsize - from % tabsize; + } + else + { + putchar_unlocked ( ' ' ) ; + from++; + } + } +} + + + + + +static void +attach (char *dest, const char *dirname, const char *name) +{ + const char *dirnamep = dirname; + + + if (dirname[0] != '.' || dirname[1] != 0) + { + while (*dirnamep) + *dest++ = *dirnamep++; + + if (dirnamep > dirname && dirnamep[-1] != '/') + *dest++ = '/'; + } + while (*name) + *dest++ = *name++; + *dest = 0; +} + +static void +init_column_info (void) +{ + int i; + int allocate = 0; + + max_idx = line_length / 3 ; + if (max_idx == 0) + max_idx = 1; + + if (column_info == 0 ) + { + column_info = (( struct column_info *) xmalloc (sizeof ( struct column_info ) * ( max_idx ))) ; + allocate = 1; + } + + for (i = 0; i < max_idx; ++i) + { + int j; + + column_info[i].valid_len = 1; + column_info[i].line_len = (i + 1) * 3 ; + + if (allocate) + column_info[i].col_arr = (( int *) xmalloc (sizeof ( int ) * ( i + 1 ))) ; + + for (j = 0; j <= i; ++j) + column_info[i].col_arr[j] = 3 ; + } +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, ((const char *) ( "Try `%s --help' for more information.\n" )) , + program_name); + else + { + printf (((const char *) ( "Usage: %s [OPTION]... [FILE]...\n" )) , program_name); + fputs (((const char *) ( "List information about the FILEs (the current directory by default).\nSort entries alphabetically if none of -cftuSUX nor --sort.\n\n" )) , stdout); + + + + + fputs (((const char *) ( "Mandatory arguments to long options are mandatory for short options too.\n" )) , stdout); + + + fputs (((const char *) ( " -a, --all do not hide entries starting with .\n -A, --almost-all do not list implied . and ..\n --author print the author of each file\n -b, --escape print octal escapes for nongraphic characters\n" )) , stdout); + + + + + + fputs (((const char *) ( " --block-size=SIZE use SIZE-byte blocks\n -B, --ignore-backups do not list implied entries ending with ~\n -c with -lt: sort by, and show, ctime (time of last\n modification of file status information)\n with -l: show ctime and sort by name\n otherwise: sort by ctime\n" )) , stdout); + + + + + + + + fputs (((const char *) ( " -C list entries by columns\n --color[=WHEN] control whether color is used to distinguish file\n types. WHEN may be `never', `always', or `auto'\n -d, --directory list directory entries instead of contents,\n and do not dereference symbolic links\n -D, --dired generate output designed for Emacs' dired mode\n" )) , stdout); + + + + + + + + fputs (((const char *) ( " -f do not sort, enable -aU, disable -lst\n -F, --classify append indicator (one of */=@|) to entries\n --format=WORD across -x, commas -m, horizontal -x, long -l,\n single-column -1, verbose -l, vertical -C\n --full-time like -l --time-style=full-iso\n" )) , stdout); + + + + + + + fputs (((const char *) ( " -g like -l, but do not list owner\n -G, --no-group inhibit display of group information\n -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n --si likewise, but use powers of 1000 not 1024\n -H, --dereference-command-line\n follow symbolic links listed on the command line\n --dereference-command-line-symlink-to-dir\n follow each command line symbolic link\n that points to a directory\n" )) , stdout); +# 3810 "ls.c" + fputs (((const char *) ( " --indicator-style=WORD append indicator with style WORD to entry names:\n none (default), classify (-F), file-type (-p)\n -i, --inode print index number of each file\n -I, --ignore=PATTERN do not list implied entries matching shell PATTERN\n -k like --block-size=1K\n" )) , stdout); + + + + + + + fputs (((const char *) ( " -l use a long listing format\n -L, --dereference when showing file information for a symbolic\n link, show information for the file the link\n references rather than for the link itself\n -m fill width with a comma separated list of entries\n" )) , stdout); + + + + + + + fputs (((const char *) ( " -n, --numeric-uid-gid like -l, but list numeric UIDs and GIDs\n -N, --literal print raw entry names (don't treat e.g. control\n characters specially)\n -o like -l, but do not list group information\n -p, --file-type append indicator (one of /=@|) to entries\n" )) , stdout); + + + + + + + fputs (((const char *) ( " -q, --hide-control-chars print ? instead of non graphic characters\n --show-control-chars show non graphic characters as-is (default\n unless program is `ls' and output is a terminal)\n -Q, --quote-name enclose entry names in double quotes\n --quoting-style=WORD use quoting style WORD for entry names:\n literal, locale, shell, shell-always, c, escape\n" )) , stdout); + + + + + + + + fputs (((const char *) ( " -r, --reverse reverse order while sorting\n -R, --recursive list subdirectories recursively\n -s, --size print size of each file, in blocks\n" )) , stdout); + + + + + fputs (((const char *) ( " -S sort by file size\n --sort=WORD extension -X, none -U, size -S, time -t,\n version -v\n status -c, time -t, atime -u, access -u, use -u\n --time=WORD show time as WORD instead of modification time:\n atime, access, use, ctime or status; use\n specified time as sort key if --sort=time\n" )) , stdout); +# 3853 "ls.c" + fputs (((const char *) ( " --time-style=STYLE show times using style STYLE:\n full-iso, long-iso, iso, locale, +FORMAT\n FORMAT is interpreted like `date'; if FORMAT is\n FORMAT1FORMAT2, FORMAT1 applies to\n non-recent files and FORMAT2 to recent files;\n if STYLE is prefixed with `posix-', STYLE\n takes effect only outside the POSIX locale\n -t sort by modification time\n -T, --tabsize=COLS assume tab stops at each COLS instead of 8\n" )) , stdout); +# 3864 "ls.c" + fputs (((const char *) ( " -u with -lt: sort by, and show, access time\n with -l: show access time and sort by name\n otherwise: sort by access time\n -U do not sort; list entries in directory order\n -v sort by version\n" )) , stdout); + + + + + + + fputs (((const char *) ( " -w, --width=COLS assume screen width instead of current value\n -x list entries by lines instead of by columns\n -X sort alphabetically by entry extension\n -1 list one file per line\n" )) , stdout); + + + + + + fputs (((const char *) ( " --help display this help and exit\n" )) , stdout); + fputs (((const char *) ( " --version output version information and exit\n" )) , stdout); + fputs (((const char *) ( "\nSIZE may be (or may be an integer optionally followed by) one of following:\nkB 1000, K 1024, MB 1,000,000, M 1,048,576, and so on for G, T, P, E, Z, Y.\n" )) , stdout); + + + + fputs (((const char *) ( "\nBy default, color is not used to distinguish types of files. That is\nequivalent to using --color=none. Using the --color option without the\noptional WHEN argument is equivalent to using --color=always. With\n--color=auto, color codes are output only if standard output is connected\nto a terminal (tty).\n" )) , stdout); + + + + + + + + printf (((const char *) ( "\nReport bugs to <%s>.\n" )) , "bug-coreutils@gnu.org" ); + } + exit (status); +} diff --git a/src/apps/bin/coreutils-5.0/src/fs.h b/src/apps/bin/coreutils-5.0/src/fs.h new file mode 100644 index 0000000000..1c420aa9d5 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/fs.h @@ -0,0 +1,36 @@ +/* define the magic numbers as given by statfs(2) */ +/* please send additions to meskes@debian.org */ + +#if defined __linux__ +# define S_MAGIC_AFFS 0xADFF +# define S_MAGIC_EXT 0x137D +# define S_MAGIC_EXT2_OLD 0xEF51 +# define S_MAGIC_EXT2 0xEF53 +# define S_MAGIC_HPFS 0xF995E849 +# define S_MAGIC_ISOFS 0x9660 +# define S_MAGIC_ISOFS_WIN 0x4000 +# define S_MAGIC_ISOFS_R_WIN 0x4004 +# define S_MAGIC_MINIX 0x137F +# define S_MAGIC_MINIX_30 0x138F +# define S_MAGIC_MINIX_V2 0x2468 +# define S_MAGIC_MINIX_V2_30 0x2478 +# define S_MAGIC_MSDOS 0x4d44 +# define S_MAGIC_FAT 0x4006 +# define S_MAGIC_NCP 0x564c +# define S_MAGIC_NFS 0x6969 +# define S_MAGIC_PROC 0x9fa0 +# define S_MAGIC_SMB 0x517B +# define S_MAGIC_XENIX 0x012FF7B4 +# define S_MAGIC_SYSV4 0x012FF7B5 +# define S_MAGIC_SYSV2 0x012FF7B6 +# define S_MAGIC_COH 0x012FF7B7 +# define S_MAGIC_UFS 0x00011954 +# define S_MAGIC_XIAFS 0x012FD16D +# define S_MAGIC_NTFS 0x5346544e +# define S_MAGIC_TMPFS 0x1021994 +# define S_MAGIC_REISERFS 0x52654973 +# define S_MAGIC_CRAMFS 0x28cd3d45 +# define S_MAGIC_ROMFS 0x7275 +#elif defined __GNU__ +# include +#endif diff --git a/src/apps/bin/coreutils-5.0/src/groups.sh b/src/apps/bin/coreutils-5.0/src/groups.sh new file mode 100755 index 0000000000..d371c063e3 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/groups.sh @@ -0,0 +1,62 @@ +#!/bin/sh +# groups -- print the groups a user is in +# Copyright (C) 1991, 1997, 2000, 2002 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +# Written by David MacKenzie . + +# Make sure we get GNU id, if possible; also allow +# it to be somewhere else in PATH if not installed yet. +PATH=@bindir@:$PATH + +usage="Usage: $0 [OPTION]... [USERNAME]... + + --help display this help and exit + --version output version information and exit + +Same as id -Gn. If no USERNAME, use current process. + +Report bugs to <@PACKAGE_BUGREPORT@>." + +fail=0 +case $# in + 1 ) + case "z${1}" in + z--help ) + echo "$usage" || fail=1; exit $fail;; + z--version ) + echo "groups (@GNU_PACKAGE@) @VERSION@" || fail=1; exit $fail;; + * ) ;; + esac + ;; + * ) ;; +esac + +if [ $# -eq 0 ]; then + id -Gn + fail=$? +else + for name in "$@"; do + groups=`id -Gn -- $name` + status=$? + if test $status = 0; then + echo $name : $groups + else + fail=$status + fi + done +fi +exit $fail diff --git a/src/apps/bin/coreutils-5.0/src/head.c b/src/apps/bin/coreutils-5.0/src/head.c new file mode 100644 index 0000000000..0c972e2832 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/head.c @@ -0,0 +1,421 @@ +/* head -- output first part of file(s) + Copyright (C) 89, 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Options: (see usage) + Reads from standard input if no files are given or when a filename of + ``-'' is encountered. + By default, filename headers are printed only if more than one file + is given. + By default, prints the first 10 lines (head -n 10). + + David MacKenzie */ + +#include + +#include +#include +#include +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "posixver.h" +#include "xstrtol.h" +#include "safe-read.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "head" + +#define AUTHORS "David MacKenzie" + +/* Number of lines/chars/blocks to head. */ +#define DEFAULT_NUMBER 10 + +/* Size of atomic reads. */ +#define BUFSIZE (512 * 8) + +/* If nonzero, print filename headers. */ +static int print_headers; + +/* When to print the filename banners. */ +enum header_mode +{ + multiple_files, always, never +}; + +/* Options corresponding to header_mode values. */ +static char const header_mode_option[][4] = { "", " -v", " -q" }; + +/* The name this program was run with. */ +char *program_name; + +/* Have we ever read standard input? */ +static int have_read_stdin; + +static struct option const long_options[] = +{ + {"bytes", required_argument, NULL, 'c'}, + {"lines", required_argument, NULL, 'n'}, + {"quiet", no_argument, NULL, 'q'}, + {"silent", no_argument, NULL, 'q'}, + {"verbose", no_argument, NULL, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + fputs (_("\ +Print first 10 lines of each FILE to standard output.\n\ +With more than one FILE, precede each with a header giving the file name.\n\ +With no FILE, or when FILE is -, read standard input.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -c, --bytes=SIZE print first SIZE bytes\n\ + -n, --lines=NUMBER print first NUMBER lines instead of first 10\n\ +"), stdout); + fputs (_("\ + -q, --quiet, --silent never print headers giving file names\n\ + -v, --verbose always print headers giving file names\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +static void +write_header (const char *filename) +{ + static int first_file = 1; + + printf ("%s==> %s <==\n", (first_file ? "" : "\n"), filename); + first_file = 0; +} + +static int +head_bytes (const char *filename, int fd, uintmax_t bytes_to_write) +{ + char buffer[BUFSIZE]; + size_t bytes_to_read = BUFSIZE; + + /* Need BINARY I/O for the byte counts to be accurate. */ + SET_BINARY2 (fd, fileno (stdout)); + + while (bytes_to_write) + { + size_t bytes_read; + if (bytes_to_write < bytes_to_read) + bytes_to_read = bytes_to_write; + bytes_read = safe_read (fd, buffer, bytes_to_read); + if (bytes_read == SAFE_READ_ERROR) + { + error (0, errno, "%s", filename); + return 1; + } + if (bytes_read == 0) + break; + if (fwrite (buffer, 1, bytes_read, stdout) == 0) + error (EXIT_FAILURE, errno, _("write error")); + bytes_to_write -= bytes_read; + } + return 0; +} + +static int +head_lines (const char *filename, int fd, uintmax_t lines_to_write) +{ + char buffer[BUFSIZE]; + + /* Need BINARY I/O for the byte counts to be accurate. */ + SET_BINARY2 (fd, fileno (stdout)); + + while (lines_to_write) + { + size_t bytes_read = safe_read (fd, buffer, BUFSIZE); + size_t bytes_to_write = 0; + + if (bytes_read == SAFE_READ_ERROR) + { + error (0, errno, "%s", filename); + return 1; + } + if (bytes_read == 0) + break; + while (bytes_to_write < bytes_read) + if (buffer[bytes_to_write++] == '\n' && --lines_to_write == 0) + { + off_t n_bytes_past_EOL = bytes_read - bytes_to_write; + /* If we have read more data than that on the specified number + of lines, try to seek back to the position we would have + gotten to had we been reading one byte at a time. */ + if (lseek (fd, -n_bytes_past_EOL, SEEK_CUR) < 0) + { + int e = errno; + struct stat st; + if (fstat (fd, &st) != 0 || S_ISREG (st.st_mode)) + error (0, e, _("cannot reposition file pointer for %s"), + filename); + } + break; + } + if (fwrite (buffer, 1, bytes_to_write, stdout) == 0) + error (EXIT_FAILURE, errno, _("write error")); + } + return 0; +} + +static int +head (const char *filename, int fd, uintmax_t n_units, int count_lines) +{ + if (print_headers) + write_header (filename); + + if (count_lines) + return head_lines (filename, fd, n_units); + else + return head_bytes (filename, fd, n_units); +} + +static int +head_file (const char *filename, uintmax_t n_units, int count_lines) +{ + int fd; + + if (STREQ (filename, "-")) + { + have_read_stdin = 1; + return head (_("standard input"), STDIN_FILENO, n_units, count_lines); + } + else + { + fd = open (filename, O_RDONLY); + if (fd >= 0) + { + int errors; + + errors = head (filename, fd, n_units, count_lines); + if (close (fd) == 0) + return errors; + } + error (0, errno, "%s", filename); + return 1; + } +} + +/* Convert a string of decimal digits, N_STRING, with a single, optional suffix + character (b, k, or m) to an integral value. Upon successful conversion, + return that value. If it cannot be converted, give a diagnostic and exit. + COUNT_LINES indicates whether N_STRING is a number of bytes or a number + of lines. It is used solely to give a more specific diagnostic. */ + +static uintmax_t +string_to_integer (int count_lines, const char *n_string) +{ + strtol_error s_err; + uintmax_t n; + + s_err = xstrtoumax (n_string, NULL, 10, &n, "bkm"); + + if (s_err == LONGINT_OVERFLOW) + { + error (EXIT_FAILURE, 0, + _("%s: %s is so large that it is not representable"), n_string, + count_lines ? _("number of lines") : _("number of bytes")); + } + + if (s_err != LONGINT_OK) + { + error (EXIT_FAILURE, 0, "%s: %s", n_string, + (count_lines + ? _("invalid number of lines") + : _("invalid number of bytes"))); + } + + return n; +} + +int +main (int argc, char **argv) +{ + enum header_mode header_mode = multiple_files; + int exit_status = 0; + int c; + + /* Number of items to print. */ + uintmax_t n_units = DEFAULT_NUMBER; + + /* If nonzero, interpret the numeric argument as the number of lines. + Otherwise, interpret it as the number of bytes. */ + int count_lines = 1; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + have_read_stdin = 0; + + print_headers = 0; + + if (1 < argc && argv[1][0] == '-' && ISDIGIT (argv[1][1])) + { + char *a = argv[1]; + char *n_string = ++a; + char *end_n_string; + char multiplier_char = 0; + + /* Old option syntax; a dash, one or more digits, and one or + more option letters. Move past the number. */ + do ++a; + while (ISDIGIT (*a)); + + /* Pointer to the byte after the last digit. */ + end_n_string = a; + + /* Parse any appended option letters. */ + for (; *a; a++) + { + switch (*a) + { + case 'c': + count_lines = 0; + multiplier_char = 0; + break; + + case 'b': + case 'k': + case 'm': + count_lines = 0; + multiplier_char = *a; + break; + + case 'l': + count_lines = 1; + break; + + case 'q': + header_mode = never; + break; + + case 'v': + header_mode = always; + break; + + default: + error (0, 0, _("unrecognized option `-%c'"), *a); + usage (EXIT_FAILURE); + } + } + + if (200112 <= posix2_version ()) + { + error (0, 0, _("`-%s' option is obsolete; use `-%c %.*s%.*s%s'"), + n_string, count_lines ? 'n' : 'c', + (int) (end_n_string - n_string), n_string, + multiplier_char != 0, &multiplier_char, + header_mode_option[header_mode]); + usage (EXIT_FAILURE); + } + + /* Append the multiplier character (if any) onto the end of + the digit string. Then add NUL byte if necessary. */ + *end_n_string = multiplier_char; + if (multiplier_char) + *(++end_n_string) = 0; + + n_units = string_to_integer (count_lines, n_string); + + /* Make the options we just parsed invisible to getopt. */ + argv[1] = argv[0]; + argv++; + argc--; + + /* FIXME: allow POSIX options if there were obsolescent ones? */ + + } + + while ((c = getopt_long (argc, argv, "c:n:qv", long_options, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + case 'c': + count_lines = 0; + n_units = string_to_integer (count_lines, optarg); + break; + + case 'n': + count_lines = 1; + n_units = string_to_integer (count_lines, optarg); + break; + + case 'q': + header_mode = never; + break; + + case 'v': + header_mode = always; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (header_mode == always + || (header_mode == multiple_files && optind < argc - 1)) + print_headers = 1; + + if (optind == argc) + exit_status |= head_file ("-", n_units, count_lines); + + for (; optind < argc; ++optind) + exit_status |= head_file (argv[optind], n_units, count_lines); + + if (have_read_stdin && close (STDIN_FILENO) < 0) + error (EXIT_FAILURE, errno, "-"); + + exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/hostid.c b/src/apps/bin/coreutils-5.0/src/hostid.c new file mode 100644 index 0000000000..d27207baff --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/hostid.c @@ -0,0 +1,87 @@ +/* print the hexadecimal identifier for the current host + Copyright (C) 1997, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Jim Meyering. */ + +#include +#include +#include +#if HAVE_UNISTD_H +# include +#endif + +#include "system.h" +#include "closeout.h" +#include "long-options.h" +#include "error.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "hostid" + +#define AUTHORS "Jim Meyering" + +/* The name this program was run with, for error messages. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s\n\ + or: %s OPTION\n\ +Print the numeric identifier (in hexadecimal) for the current host.\n\ +\n\ +"), + program_name, program_name); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + long int id; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + if (argc > 1) + { + error (0, 0, _("too many arguments")); + usage (EXIT_FAILURE); + } + + id = gethostid (); + printf ("%lx\n", id); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/hostname.c b/src/apps/bin/coreutils-5.0/src/hostname.c new file mode 100644 index 0000000000..3f13b072e2 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/hostname.c @@ -0,0 +1,127 @@ +/* hostname - set or print the name of current host system + Copyright (C) 1994-1997, 1999-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Jim Meyering */ + +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "long-options.h" +#include "error.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "hostname" + +#define AUTHORS "Jim Meyering" + +#if !defined(HAVE_SETHOSTNAME) && defined(HAVE_SYSINFO) && \ + defined (HAVE_SYS_SYSTEMINFO_H) && defined(HAVE_LIMITS_H) +# include + +int +sethostname (name, namelen) + char *name; + int namelen; +{ + /* Using sysinfo() is the SVR4 mechanism to set a hostname. */ + int result; + + result = sysinfo (SI_SET_HOSTNAME, name, namelen); + + return (result == -1 ? result : 0); +} + +# define HAVE_SETHOSTNAME 1 /* Now we have it... */ +#endif + +char *xgethostname (); + +/* The name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [NAME]\n\ + or: %s OPTION\n\ +Print or set the hostname of the current system.\n\ +\n\ +"), + program_name, program_name); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + char *hostname; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + +#ifdef HAVE_SETHOSTNAME + if (argc == 2) + { + int err; + + /* Set hostname to argv[1]. */ + err = sethostname (argv[1], strlen (argv[1])); + if (err != 0) + error (EXIT_FAILURE, errno, _("cannot set hostname to `%s'"), argv[1]); + exit (EXIT_SUCCESS); + } +#else + if (argc == 2) + error (EXIT_FAILURE, 0, + _("cannot set hostname; this system lacks the functionality")); +#endif + + if (argc == 1) + { + hostname = xgethostname (); + if (hostname == NULL) + error (EXIT_FAILURE, errno, _("cannot determine hostname")); + printf ("%s\n", hostname); + } + else + { + error (2, 0, _("too many arguments")); + usage (EXIT_FAILURE); + } + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/id.c b/src/apps/bin/coreutils-5.0/src/id.c new file mode 100644 index 0000000000..bb5e0cafda --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/id.c @@ -0,0 +1,400 @@ +/* id -- print real and effective UIDs and GIDs + Copyright (C) 1989-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Arnold Robbins. + Major rewrite by David MacKenzie, djm@gnu.ai.mit.edu. */ + +#include +#include +#include +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "id" + +#define AUTHORS N_ ("Arnold Robbins and David MacKenzie") + +#ifndef _POSIX_VERSION +struct passwd *getpwuid (); +struct group *getgrgid (); +uid_t getuid (); +gid_t getgid (); +uid_t geteuid (); +gid_t getegid (); +#endif /* not _POSIX_VERSION */ + +int getugroups (); + +static void print_user (uid_t uid); +static void print_group (gid_t gid); +static void print_group_list (const char *username); +static void print_full_info (const char *username); + +/* The name this program was run with. */ +char *program_name; + +/* If nonzero, output user/group name instead of ID number. -n */ +static int use_name = 0; + +/* The real and effective IDs of the user to print. */ +static uid_t ruid, euid; +static gid_t rgid, egid; + +/* The number of errors encountered so far. */ +static int problems = 0; + +static struct option const longopts[] = +{ + {"group", no_argument, NULL, 'g'}, + {"groups", no_argument, NULL, 'G'}, + {"name", no_argument, NULL, 'n'}, + {"real", no_argument, NULL, 'r'}, + {"user", no_argument, NULL, 'u'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [USERNAME]\n"), program_name); + fputs (_("\ +Print information for USERNAME, or the current user.\n\ +\n\ + -a ignore, for compatibility with other versions\n\ + -g, --group print only the effective group ID\n\ + -G, --groups print all group IDs\n\ + -n, --name print a name instead of a number, for -ugG\n\ + -r, --real print the real ID instead of the effective ID, with -ugG\n\ + -u, --user print only the effective user ID\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +Without any OPTION, print some useful set of identified information.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int optc; + + /* If nonzero, output the list of all group IDs. -G */ + int just_group_list = 0; + /* If nonzero, output only the group ID(s). -g */ + int just_group = 0; + /* If nonzero, output real UID/GID instead of default effective UID/GID. -r */ + int use_real = 0; + /* If nonzero, output only the user ID(s). -u */ + int just_user = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + while ((optc = getopt_long (argc, argv, "agnruG", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + case 'a': + /* Ignore -a, for compatibility with SVR4. */ + break; + case 'g': + just_group = 1; + break; + case 'n': + use_name = 1; + break; + case 'r': + use_real = 1; + break; + case 'u': + just_user = 1; + break; + case 'G': + just_group_list = 1; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + } + + if (just_user + just_group + just_group_list > 1) + error (EXIT_FAILURE, 0, _("cannot print only user and only group")); + + if (just_user + just_group + just_group_list == 0 && (use_real || use_name)) + error (EXIT_FAILURE, 0, + _("cannot print only names or real IDs in default format")); + + if (argc - optind > 1) + usage (EXIT_FAILURE); + + if (argc - optind == 1) + { + struct passwd *pwd = getpwnam (argv[optind]); + if (pwd == NULL) + error (EXIT_FAILURE, 0, _("%s: No such user"), argv[optind]); + ruid = euid = pwd->pw_uid; + rgid = egid = pwd->pw_gid; + } + else + { + euid = geteuid (); + ruid = getuid (); + egid = getegid (); + rgid = getgid (); + } + + if (just_user) + print_user (use_real ? ruid : euid); + else if (just_group) + print_group (use_real ? rgid : egid); + else if (just_group_list) + print_group_list (argv[optind]); + else + print_full_info (argv[optind]); + putchar ('\n'); + + exit (problems != 0); +} + +/* Print the name or value of user ID UID. */ + +static void +print_user (uid_t uid) +{ + struct passwd *pwd = NULL; + + if (use_name) + { + pwd = getpwuid (uid); + if (pwd == NULL) + { + error (0, 0, _("cannot find name for user ID %u"), uid); + problems++; + } + } + + if (pwd == NULL) + printf ("%u", (unsigned) uid); + else + printf ("%s", pwd->pw_name); +} + +/* Print the name or value of group ID GID. */ + +static void +print_group (gid_t gid) +{ + struct group *grp = NULL; + + if (use_name) + { + grp = getgrgid (gid); + if (grp == NULL) + { + error (0, 0, _("cannot find name for group ID %u"), gid); + problems++; + } + } + + if (grp == NULL) + printf ("%u", (unsigned) gid); + else + printf ("%s", grp->gr_name); +} + +#if HAVE_GETGROUPS + +/* FIXME: document */ + +static int +xgetgroups (const char *username, gid_t gid, int *n_groups, + GETGROUPS_T **groups) +{ + int max_n_groups; + int ng; + GETGROUPS_T *g; + int fail = 0; + + if (username == 0) + max_n_groups = getgroups (0, NULL); + else + max_n_groups = getugroups (0, NULL, username, gid); + + /* Add 1 just in case max_n_groups is zero. */ + g = (GETGROUPS_T *) xmalloc (max_n_groups * sizeof (GETGROUPS_T) + 1); + if (username == 0) + ng = getgroups (max_n_groups, g); + else + ng = getugroups (max_n_groups, g, username, gid); + + if (ng < 0) + { + error (0, errno, _("cannot get supplemental group list")); + ++fail; + free (groups); + } + if (!fail) + { + *n_groups = ng; + *groups = g; + } + return fail; +} + +#endif /* HAVE_GETGROUPS */ + +/* Print all of the distinct groups the user is in. */ + +static void +print_group_list (const char *username) +{ + struct passwd *pwd; + + pwd = getpwuid (ruid); + if (pwd == NULL) + problems++; + + print_group (rgid); + if (egid != rgid) + { + putchar (' '); + print_group (egid); + } + +#if HAVE_GETGROUPS + { + int n_groups; + GETGROUPS_T *groups; + register int i; + + if (xgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1), + &n_groups, &groups)) + { + ++problems; + return; + } + + for (i = 0; i < n_groups; i++) + if (groups[i] != rgid && groups[i] != egid) + { + putchar (' '); + print_group (groups[i]); + } + free (groups); + } +#endif /* HAVE_GETGROUPS */ +} + +/* Print all of the info about the user's user and group IDs. */ + +static void +print_full_info (const char *username) +{ + struct passwd *pwd; + struct group *grp; + + printf ("uid=%u", (unsigned) ruid); + pwd = getpwuid (ruid); + if (pwd == NULL) + problems++; + else + printf ("(%s)", pwd->pw_name); + + printf (" gid=%u", (unsigned) rgid); + grp = getgrgid (rgid); + if (grp == NULL) + problems++; + else + printf ("(%s)", grp->gr_name); + + if (euid != ruid) + { + printf (" euid=%u", (unsigned) euid); + pwd = getpwuid (euid); + if (pwd == NULL) + problems++; + else + printf ("(%s)", pwd->pw_name); + } + + if (egid != rgid) + { + printf (" egid=%u", (unsigned) egid); + grp = getgrgid (egid); + if (grp == NULL) + problems++; + else + printf ("(%s)", grp->gr_name); + } + +#if HAVE_GETGROUPS + { + int n_groups; + GETGROUPS_T *groups; + register int i; + + if (xgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1), + &n_groups, &groups)) + { + ++problems; + return; + } + + if (n_groups > 0) + fputs (_(" groups="), stdout); + for (i = 0; i < n_groups; i++) + { + if (i > 0) + putchar (','); + printf ("%u", (unsigned) groups[i]); + grp = getgrgid (groups[i]); + if (grp == NULL) + problems++; + else + printf ("(%s)", grp->gr_name); + } + free (groups); + } +#endif /* HAVE_GETGROUPS */ +} diff --git a/src/apps/bin/coreutils-5.0/src/install.c b/src/apps/bin/coreutils-5.0/src/install.c new file mode 100644 index 0000000000..0204eadeb1 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/install.c @@ -0,0 +1,651 @@ +/* install - copy files and set attributes + Copyright (C) 89, 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include +#include +#include +#include +#include + +#include "system.h" +#include "backupfile.h" +#include "error.h" +#include "cp-hash.h" +#include "copy.h" +#include "dirname.h" +#include "makepath.h" +#include "modechange.h" +#include "path-concat.h" +#include "quote.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "install" + +#define AUTHORS "David MacKenzie" + +#if HAVE_SYS_WAIT_H +# include +#endif + +struct passwd *getpwnam (); +struct group *getgrnam (); + +#ifndef _POSIX_VERSION +uid_t getuid (); +gid_t getgid (); +#endif + +#if ! HAVE_ENDGRENT +# define endgrent() ((void) 0) +#endif + +#if ! HAVE_ENDPWENT +# define endpwent() ((void) 0) +#endif + +/* Initial number of entries in each hash table entry's table of inodes. */ +#define INITIAL_HASH_MODULE 100 + +/* Initial number of entries in the inode hash table. */ +#define INITIAL_ENTRY_TAB_SIZE 70 + +/* Number of bytes of a file to copy at a time. */ +#define READ_SIZE (32 * 1024) + +int isdir (); + +int stat (); + +static int change_timestamps (const char *from, const char *to); +static int change_attributes (const char *path); +static int copy_file (const char *from, const char *to, + const struct cp_options *x); +static int install_file_to_path (const char *from, const char *to, + const struct cp_options *x); +static int install_file_in_dir (const char *from, const char *to_dir, + const struct cp_options *x); +static int install_file_in_file (const char *from, const char *to, + const struct cp_options *x); +static void get_ids (void); +static void strip (const char *path); +void usage (int status); + +/* The name this program was run with, for error messages. */ +char *program_name; + +/* The user name that will own the files, or NULL to make the owner + the current user ID. */ +static char *owner_name; + +/* The user ID corresponding to `owner_name'. */ +static uid_t owner_id; + +/* The group name that will own the files, or NULL to make the group + the current group ID. */ +static char *group_name; + +/* The group ID corresponding to `group_name'. */ +static gid_t group_id; + +/* The permissions to which the files will be set. The umask has + no effect. */ +static mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + +/* If nonzero, strip executable files after copying them. */ +static int strip_files; + +/* If nonzero, install a directory instead of a regular file. */ +static int dir_arg; + +static struct option const long_options[] = +{ + {"backup", optional_argument, NULL, 'b'}, + {"directory", no_argument, NULL, 'd'}, + {"group", required_argument, NULL, 'g'}, + {"mode", required_argument, NULL, 'm'}, + {"owner", required_argument, NULL, 'o'}, + {"preserve-timestamps", no_argument, NULL, 'p'}, + {"strip", no_argument, NULL, 's'}, + {"suffix", required_argument, NULL, 'S'}, + {"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */ + {"verbose", no_argument, NULL, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +static void +cp_option_init (struct cp_options *x) +{ + x->copy_as_regular = 1; + x->dereference = DEREF_ALWAYS; + x->unlink_dest_before_opening = 1; + x->unlink_dest_after_failed_open = 0; + x->hard_link = 0; + x->interactive = I_UNSPECIFIED; + x->move_mode = 0; + x->myeuid = geteuid (); + x->one_file_system = 0; + x->preserve_ownership = 0; + x->preserve_links = 0; + x->preserve_mode = 0; + x->preserve_timestamps = 0; + x->require_preserve = 0; + x->recursive = 0; + x->sparse_mode = SPARSE_AUTO; + x->symbolic_link = 0; + x->backup_type = none; + + /* Create destination files initially writable so we can run strip on them. + Although GNU strip works fine on read-only files, some others + would fail. */ + x->set_mode = 1; + x->mode = S_IRUSR | S_IWUSR; + x->stdin_tty = 0; + + x->umask_kill = 0; + x->update = 0; + x->verbose = 0; + x->xstat = stat; + x->dest_info = NULL; + x->src_info = NULL; +} + +int +main (int argc, char **argv) +{ + int optc; + int errors = 0; + const char *specified_mode = NULL; + int make_backups = 0; + char *backup_suffix_string; + char *version_control_string = NULL; + int mkdir_and_install = 0; + struct cp_options x; + int n_files; + char **file; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + cp_option_init (&x); + + owner_name = NULL; + group_name = NULL; + strip_files = 0; + dir_arg = 0; + umask (0); + + /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + + while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pvV:S:", long_options, + NULL)) != -1) + { + switch (optc) + { + case 0: + break; + + case 'V': /* FIXME: this is deprecated. Remove it in 2001. */ + error (0, 0, + _("warning: --version-control (-V) is obsolete; support for\ + it\nwill be removed in some future release. Use --backup=%s instead." + ), optarg); + /* Fall through. */ + + case 'b': + make_backups = 1; + if (optarg) + version_control_string = optarg; + break; + case 'c': + break; + case 's': + strip_files = 1; + break; + case 'd': + dir_arg = 1; + break; + case 'D': + mkdir_and_install = 1; + break; + case 'v': + x.verbose = 1; + break; + case 'g': + group_name = optarg; + break; + case 'm': + specified_mode = optarg; + break; + case 'o': + owner_name = optarg; + break; + case 'p': + x.preserve_timestamps = 1; + break; + case 'S': + make_backups = 1; + backup_suffix_string = optarg; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + } + + /* Check for invalid combinations of arguments. */ + if (dir_arg && strip_files) + error (EXIT_FAILURE, 0, + _("the strip option may not be used when installing a directory")); + + if (backup_suffix_string) + simple_backup_suffix = xstrdup (backup_suffix_string); + + x.backup_type = (make_backups + ? xget_version (_("backup type"), + version_control_string) + : none); + + n_files = argc - optind; + file = argv + optind; + + if (n_files == 0 || (n_files == 1 && !dir_arg)) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + if (specified_mode) + { + struct mode_change *change = mode_compile (specified_mode, 0); + if (change == MODE_INVALID) + error (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode)); + else if (change == MODE_MEMORY_EXHAUSTED) + xalloc_die (); + mode = mode_adjust (0, change); + } + + get_ids (); + + if (dir_arg) + { + int i; + for (i = 0; i < n_files; i++) + { + errors |= + make_path (file[i], mode, mode, owner_id, group_id, 0, + (x.verbose ? _("creating directory %s") : NULL)); + } + } + else + { + /* FIXME: it's a little gross that this initialization is + required by copy.c::copy. */ + hash_init (); + + if (n_files == 2) + { + if (mkdir_and_install) + errors = install_file_to_path (file[0], file[1], &x); + else if (!isdir (file[1])) + errors = install_file_in_file (file[0], file[1], &x); + else + errors = install_file_in_dir (file[0], file[1], &x); + } + else + { + int i; + const char *dest = file[n_files - 1]; + if (!isdir (dest)) + { + error (0, 0, + _("installing multiple files, but last argument, %s \ +is not a directory"), + quote (dest)); + usage (EXIT_FAILURE); + } + + dest_info_init (&x); + for (i = 0; i < n_files - 1; i++) + { + errors |= install_file_in_dir (file[i], dest, &x); + } + } + } + + exit (errors); +} + +/* Copy file FROM onto file TO, creating any missing parent directories of TO. + Return 0 if successful, 1 if an error occurs */ + +static int +install_file_to_path (const char *from, const char *to, + const struct cp_options *x) +{ + char *dest_dir; + int fail = 0; + + dest_dir = dir_name (to); + + /* check to make sure this is a path (not install a b ) */ + if (!STREQ (dest_dir, ".") + && !isdir (dest_dir)) + { + /* Someone will probably ask for a new option or three to specify + owner, group, and permissions for parent directories. Remember + that this option is intended mainly to help installers when the + distribution doesn't provide proper install rules. */ +#define DIR_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) + fail = make_path (dest_dir, DIR_MODE, DIR_MODE, owner_id, group_id, 0, + (x->verbose ? _("creating directory %s") : NULL)); + } + + if (fail == 0) + fail = install_file_in_file (from, to, x); + + free (dest_dir); + + return fail; +} + +/* Copy file FROM onto file TO and give TO the appropriate + attributes. + Return 0 if successful, 1 if an error occurs. */ + +static int +install_file_in_file (const char *from, const char *to, + const struct cp_options *x) +{ + if (copy_file (from, to, x)) + return 1; + if (strip_files) + strip (to); + if (change_attributes (to)) + return 1; + if (x->preserve_timestamps) + return change_timestamps (from, to); + return 0; +} + +/* Copy file FROM into directory TO_DIR, keeping its same name, + and give the copy the appropriate attributes. + Return 0 if successful, 1 if not. */ + +static int +install_file_in_dir (const char *from, const char *to_dir, + const struct cp_options *x) +{ + const char *from_base; + char *to; + int ret; + + from_base = base_name (from); + to = path_concat (to_dir, from_base, NULL); + ret = install_file_in_file (from, to, x); + free (to); + return ret; +} + +/* Copy file FROM onto file TO, creating TO if necessary. + Return 0 if the copy is successful, 1 if not. */ + +static int +copy_file (const char *from, const char *to, const struct cp_options *x) +{ + int fail; + int nonexistent_dst = 0; + int copy_into_self; + + /* Allow installing from non-regular files like /dev/null. + Charles Karney reported that some Sun version of install allows that + and that sendmail's installation process relies on the behavior. */ + if (isdir (from)) + { + error (0, 0, _("%s is a directory"), quote (from)); + return 1; + } + + fail = copy (from, to, nonexistent_dst, x, ©_into_self, NULL); + + return fail; +} + +/* Set the attributes of file or directory PATH. + Return 0 if successful, 1 if not. */ + +static int +change_attributes (const char *path) +{ + int err = 0; + + /* chown must precede chmod because on some systems, + chown clears the set[ug]id bits for non-superusers, + resulting in incorrect permissions. + On System V, users can give away files with chown and then not + be able to chmod them. So don't give files away. + + We don't normally ignore errors from chown because the idea of + the install command is that the file is supposed to end up with + precisely the attributes that the user specified (or defaulted). + If the file doesn't end up with the group they asked for, they'll + want to know. But AFS returns EPERM when you try to change a + file's group; thus the kludge. */ + + if (chown (path, owner_id, group_id) +#ifdef AFS + && errno != EPERM +#endif + ) + { + error (0, errno, "cannot change ownership of %s", quote (path)); + err = 1; + } + + if (!err && chmod (path, mode)) + { + error (0, errno, "cannot change permissions of %s", quote (path)); + err = 1; + } + + return err; +} + +/* Set the timestamps of file TO to match those of file FROM. + Return 0 if successful, 1 if not. */ + +static int +change_timestamps (const char *from, const char *to) +{ + struct stat stb; + struct utimbuf utb; + + if (stat (from, &stb)) + { + error (0, errno, _("cannot obtain time stamps for %s"), quote (from)); + return 1; + } + + /* There's currently no interface to set file timestamps with + better than 1-second resolution, so discard any fractional + part of the source timestamp. */ + + utb.actime = stb.st_atime; + utb.modtime = stb.st_mtime; + if (utime (to, &utb)) + { + error (0, errno, _("cannot set time stamps for %s"), quote (to)); + return 1; + } + return 0; +} + +/* Strip the symbol table from the file PATH. + We could dig the magic number out of the file first to + determine whether to strip it, but the header files and + magic numbers vary so much from system to system that making + it portable would be very difficult. Not worth the effort. */ + +static void +strip (const char *path) +{ + int status; + pid_t pid = fork (); + + switch (pid) + { + case -1: + error (EXIT_FAILURE, errno, _("fork system call failed")); + break; + case 0: /* Child. */ + execlp ("strip", "strip", path, NULL); + error (EXIT_FAILURE, errno, _("cannot run strip")); + break; + default: /* Parent. */ + /* Parent process. */ + while (pid != wait (&status)) /* Wait for kid to finish. */ + /* Do nothing. */ ; + if (status) + error (EXIT_FAILURE, 0, _("strip failed")); + break; + } +} + +/* Initialize the user and group ownership of the files to install. */ + +static void +get_ids (void) +{ + struct passwd *pw; + struct group *gr; + + if (owner_name) + { + pw = getpwnam (owner_name); + if (pw == NULL) + { + unsigned long int tmp; + if (xstrtoul (owner_name, NULL, 0, &tmp, NULL) != LONGINT_OK + || UID_T_MAX < tmp) + error (EXIT_FAILURE, 0, _("invalid user %s"), quote (owner_name)); + owner_id = tmp; + } + else + owner_id = pw->pw_uid; + endpwent (); + } + else + owner_id = (uid_t) -1; + + if (group_name) + { + gr = getgrnam (group_name); + if (gr == NULL) + { + unsigned long int tmp; + if (xstrtoul (group_name, NULL, 0, &tmp, NULL) != LONGINT_OK + || GID_T_MAX < tmp) + error (EXIT_FAILURE, 0, _("invalid group %s"), quote (group_name)); + group_id = tmp; + } + else + group_id = gr->gr_gid; + endgrent (); + } + else + group_id = (gid_t) -1; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... SOURCE DEST (1st format)\n\ + or: %s [OPTION]... SOURCE... DIRECTORY (2nd format)\n\ + or: %s -d [OPTION]... DIRECTORY... (3rd format)\n\ +"), + program_name, program_name, program_name); + fputs (_("\ +In the first two formats, copy SOURCE to DEST or multiple SOURCE(s) to\n\ +the existing DIRECTORY, while setting permission modes and owner/group.\n\ +In the third format, create all components of the given DIRECTORY(ies).\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + --backup[=CONTROL] make a backup of each existing destination file\n\ + -b like --backup but does not accept an argument\n\ + -c (ignored)\n\ + -d, --directory treat all arguments as directory names; create all\n\ + components of the specified directories\n\ +"), stdout); + fputs (_("\ + -D create all leading components of DEST except the last,\n\ + then copy SOURCE to DEST; useful in the 1st format\n\ + -g, --group=GROUP set group ownership, instead of process' current group\n\ + -m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\ + -o, --owner=OWNER set ownership (super-user only)\n\ +"), stdout); + fputs (_("\ + -p, --preserve-timestamps apply access/modification times of SOURCE files\n\ + to corresponding destination files\n\ + -s, --strip strip symbol tables, only for 1st and 2nd formats\n\ + -S, --suffix=SUFFIX override the usual backup suffix\n\ + -v, --verbose print the name of each directory as it is created\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ +The version control method may be selected via the --backup option or through\n\ +the VERSION_CONTROL environment variable. Here are the values:\n\ +\n\ +"), stdout); + fputs (_("\ + none, off never make backups (even if --backup is given)\n\ + numbered, t make numbered backups\n\ + existing, nil numbered if numbered backups exist, simple otherwise\n\ + simple, never always make simple backups\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} diff --git a/src/apps/bin/coreutils-5.0/src/join.c b/src/apps/bin/coreutils-5.0/src/join.c new file mode 100644 index 0000000000..77a7de962e --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/join.c @@ -0,0 +1,877 @@ +/* join - join lines of two files on a common field + Copyright (C) 91, 1995-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Written by Mike Haertel, mike@gnu.ai.mit.edu. */ + +#include + +#include +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "hard-locale.h" +#include "linebuffer.h" +#include "memcasecmp.h" +#include "xmemcoll.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "join" + +#define AUTHORS "Mike Haertel" + +#define join system_join + +/* Undefine, to avoid warning about redefinition on some systems. */ +#undef min +#undef max +#define min(A, B) ((A) < (B) ? (A) : (B)) +#define max(A, B) ((A) > (B) ? (A) : (B)) + +/* An element of the list identifying which fields to print for each + output line. */ +struct outlist + { + /* File number: 0, 1, or 2. 0 means use the join field. + 1 means use the first file argument, 2 the second. */ + int file; + + /* Field index (zero-based), specified only when FILE is 1 or 2. */ + int field; + + struct outlist *next; + }; + +/* A field of a line. */ +struct field + { + const unsigned char *beg; /* First character in field. */ + size_t len; /* The length of the field. */ + }; + +/* A line read from an input file. */ +struct line + { + struct linebuffer buf; /* The line itself. */ + int nfields; /* Number of elements in `fields'. */ + int nfields_allocated; /* Number of elements in `fields'. */ + struct field *fields; + }; + +/* One or more consecutive lines read from a file that all have the + same join field value. */ +struct seq + { + int count; /* Elements used in `lines'. */ + int alloc; /* Elements allocated in `lines'. */ + struct line *lines; + }; + +/* The name this program was run with. */ +char *program_name; + +/* Nonzero if the LC_COLLATE locale is hard. */ +static int hard_LC_COLLATE; + +/* If nonzero, print unpairable lines in file 1 or 2. */ +static int print_unpairables_1, print_unpairables_2; + +/* If nonzero, print pairable lines. */ +static int print_pairables; + +/* Empty output field filler. */ +static char *empty_filler; + +/* Field to join on. */ +static int join_field_1, join_field_2; + +/* List of fields to print. */ +static struct outlist outlist_head; + +/* Last element in `outlist', where a new element can be added. */ +static struct outlist *outlist_end = &outlist_head; + +/* Tab character separating fields; if this is NUL fields are separated + by any nonempty string of white space, otherwise by exactly one + tab character. */ +static unsigned char tab; + +/* When using getopt_long_only, no long option can start with + a character that is a short option. */ +static struct option const longopts[] = +{ + {"ignore-case", no_argument, NULL, 'i'}, + {"j", required_argument, NULL, 'j'}, + {"j1", required_argument, NULL, '1'}, + {"j2", required_argument, NULL, '2'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +/* Used to print non-joining lines */ +static struct line uni_blank; + +/* If nonzero, ignore case when comparing join fields. */ +static int ignore_case; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... FILE1 FILE2\n\ +"), + program_name); + fputs (_("\ +For each pair of input lines with identical join fields, write a line to\n\ +standard output. The default join field is the first, delimited\n\ +by whitespace. When FILE1 or FILE2 (not both) is -, read standard input.\n\ +\n\ + -a FILENUM print unpairable lines coming from file FILENUM, where\n\ + FILENUM is 1 or 2, corresponding to FILE1 or FILE2\n\ + -e EMPTY replace missing input fields with EMPTY\n\ +"), stdout); + fputs (_("\ + -i, --ignore-case ignore differences in case when comparing fields\n\ + -j FIELD (obsolescent) equivalent to `-1 FIELD -2 FIELD'\n\ + -j1 FIELD (obsolescent) equivalent to `-1 FIELD'\n\ + -j2 FIELD (obsolescent) equivalent to `-2 FIELD'\n\ + -o FORMAT obey FORMAT while constructing output line\n\ + -t CHAR use CHAR as input and output field separator\n\ +"), stdout); + fputs (_("\ + -v FILENUM like -a FILENUM, but suppress joined output lines\n\ + -1 FIELD join on this FIELD of file 1\n\ + -2 FIELD join on this FIELD of file 2\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +Unless -t CHAR is given, leading blanks separate fields and are ignored,\n\ +else fields are separated by CHAR. Any FIELD is a field number counted\n\ +from 1. FORMAT is one or more comma or blank separated specifications,\n\ +each being `FILENUM.FIELD' or `0'. Default FORMAT outputs the join field,\n\ +the remaining fields from FILE1, the remaining fields from FILE2, all\n\ +separated by CHAR.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +static void +ADD_FIELD (struct line *line, const unsigned char *field, size_t len) +{ + if (line->nfields >= line->nfields_allocated) + { + line->nfields_allocated = (3 * line->nfields_allocated) / 2 + 1; + line->fields = (struct field *) xrealloc ((char *) line->fields, + (line->nfields_allocated + * sizeof (struct field))); + } + line->fields[line->nfields].beg = field; + line->fields[line->nfields].len = len; + ++(line->nfields); +} + +/* Fill in the `fields' structure in LINE. */ + +static void +xfields (struct line *line) +{ + int i; + unsigned char *ptr0 = (unsigned char *) line->buf.buffer; + unsigned char *ptr; + unsigned char *lim; + + ptr = ptr0; + lim = ptr0 + line->buf.length - 1; + + if (!tab) + { + /* Skip leading blanks before the first field. */ + while (ptr < lim && ISBLANK (*ptr)) + ++ptr; + } + + for (i = 0; ptr < lim; ++i) + { + if (tab) + { + unsigned char *beg; + + beg = ptr; + while (ptr < lim && *ptr != tab) + ++ptr; + ADD_FIELD (line, beg, ptr - beg); + if (ptr < lim) + ++ptr; + } + else + { + unsigned char *beg; + + beg = ptr; + while (ptr < lim && !ISBLANK (*ptr)) + ++ptr; + ADD_FIELD (line, beg, ptr - beg); + while (ptr < lim && ISBLANK (*ptr)) + ++ptr; + } + } + + if (ptr != ptr0 && ((!tab && ISBLANK (ptr[-1])) || ptr[-1] == tab)) + { + /* Add one more (empty) field because the last character of the + line was a delimiter. */ + ADD_FIELD (line, NULL, 0); + } +} + +/* Read a line from FP into LINE and split it into fields. + Return 0 if EOF, 1 otherwise. */ + +static int +get_line (FILE *fp, struct line *line) +{ + initbuffer (&line->buf); + + if (! readline (&line->buf, fp)) + { + free (line->buf.buffer); + line->buf.buffer = NULL; + return 0; + } + + line->nfields_allocated = 0; + line->nfields = 0; + line->fields = NULL; + xfields (line); + return 1; +} + +static void +freeline (struct line *line) +{ + free ((char *) line->fields); + free (line->buf.buffer); + line->buf.buffer = NULL; +} + +static void +initseq (struct seq *seq) +{ + seq->count = 0; + seq->alloc = 1; + seq->lines = (struct line *) xmalloc (seq->alloc * sizeof (struct line)); +} + +/* Read a line from FP and add it to SEQ. Return 0 if EOF, 1 otherwise. */ + +static int +getseq (FILE *fp, struct seq *seq) +{ + if (seq->count == seq->alloc) + { + seq->alloc *= 2; + seq->lines = (struct line *) + xrealloc ((char *) seq->lines, seq->alloc * sizeof (struct line)); + } + + if (get_line (fp, &seq->lines[seq->count])) + { + ++seq->count; + return 1; + } + return 0; +} + +static void +delseq (struct seq *seq) +{ + int i; + for (i = 0; i < seq->count; i++) + if (seq->lines[i].buf.buffer) + freeline (&seq->lines[i]); + free ((char *) seq->lines); +} + +/* Return <0 if the join field in LINE1 compares less than the one in LINE2; + >0 if it compares greater; 0 if it compares equal. + Report an error and exit if the comparison fails. */ + +static int +keycmp (struct line *line1, struct line *line2) +{ + /* Start of field to compare in each file. */ + const unsigned char *beg1, *beg2; + + size_t len1, len2; /* Length of fields to compare. */ + int diff; + + if (join_field_1 < line1->nfields) + { + beg1 = line1->fields[join_field_1].beg; + len1 = line1->fields[join_field_1].len; + } + else + { + beg1 = NULL; + len1 = 0; + } + + if (join_field_2 < line2->nfields) + { + beg2 = line2->fields[join_field_2].beg; + len2 = line2->fields[join_field_2].len; + } + else + { + beg2 = NULL; + len2 = 0; + } + + if (len1 == 0) + return len2 == 0 ? 0 : -1; + if (len2 == 0) + return 1; + + /* Use an if-statement here rather than a function variable to + avoid portability hassles of getting a non-conflicting declaration + of memcmp. */ + if (ignore_case) + { + /* FIXME: ignore_case does not work with NLS (in particular, + with multibyte chars). */ + diff = memcasecmp (beg1, beg2, min (len1, len2)); + } + else + { + if (HAVE_SETLOCALE && hard_LC_COLLATE) + return xmemcoll ((char *) beg1, len1, (char *) beg2, len2); + diff = memcmp (beg1, beg2, min (len1, len2)); + } + + if (diff) + return diff; + return len1 < len2 ? -1 : len1 != len2; +} + +/* Print field N of LINE if it exists and is nonempty, otherwise + `empty_filler' if it is nonempty. */ + +static void +prfield (int n, struct line *line) +{ + size_t len; + + if (n < line->nfields) + { + len = line->fields[n].len; + if (len) + fwrite (line->fields[n].beg, 1, len, stdout); + else if (empty_filler) + fputs (empty_filler, stdout); + } + else if (empty_filler) + fputs (empty_filler, stdout); +} + +/* Print the join of LINE1 and LINE2. */ + +static void +prjoin (struct line *line1, struct line *line2) +{ + const struct outlist *outlist; + + outlist = outlist_head.next; + if (outlist) + { + const struct outlist *o; + + o = outlist; + while (1) + { + int field; + struct line *line; + + if (o->file == 0) + { + if (line1 == &uni_blank) + { + line = line2; + field = join_field_2; + } + else + { + line = line1; + field = join_field_1; + } + } + else + { + line = (o->file == 1 ? line1 : line2); + assert (o->field >= 0); + field = o->field; + } + prfield (field, line); + o = o->next; + if (o == NULL) + break; + putchar (tab ? tab : ' '); + } + putchar ('\n'); + } + else + { + int i; + + if (line1 == &uni_blank) + { + struct line *t; + t = line1; + line1 = line2; + line2 = t; + } + prfield (join_field_1, line1); + for (i = 0; i < join_field_1 && i < line1->nfields; ++i) + { + putchar (tab ? tab : ' '); + prfield (i, line1); + } + for (i = join_field_1 + 1; i < line1->nfields; ++i) + { + putchar (tab ? tab : ' '); + prfield (i, line1); + } + + for (i = 0; i < join_field_2 && i < line2->nfields; ++i) + { + putchar (tab ? tab : ' '); + prfield (i, line2); + } + for (i = join_field_2 + 1; i < line2->nfields; ++i) + { + putchar (tab ? tab : ' '); + prfield (i, line2); + } + putchar ('\n'); + } +} + +/* Print the join of the files in FP1 and FP2. */ + +static void +join (FILE *fp1, FILE *fp2) +{ + struct seq seq1, seq2; + struct line line; + int diff, i, j, eof1, eof2; + + /* Read the first line of each file. */ + initseq (&seq1); + getseq (fp1, &seq1); + initseq (&seq2); + getseq (fp2, &seq2); + + while (seq1.count && seq2.count) + { + diff = keycmp (&seq1.lines[0], &seq2.lines[0]); + if (diff < 0) + { + if (print_unpairables_1) + prjoin (&seq1.lines[0], &uni_blank); + freeline (&seq1.lines[0]); + seq1.count = 0; + getseq (fp1, &seq1); + continue; + } + if (diff > 0) + { + if (print_unpairables_2) + prjoin (&uni_blank, &seq2.lines[0]); + freeline (&seq2.lines[0]); + seq2.count = 0; + getseq (fp2, &seq2); + continue; + } + + /* Keep reading lines from file1 as long as they continue to + match the current line from file2. */ + eof1 = 0; + do + if (!getseq (fp1, &seq1)) + { + eof1 = 1; + ++seq1.count; + break; + } + while (!keycmp (&seq1.lines[seq1.count - 1], &seq2.lines[0])); + + /* Keep reading lines from file2 as long as they continue to + match the current line from file1. */ + eof2 = 0; + do + if (!getseq (fp2, &seq2)) + { + eof2 = 1; + ++seq2.count; + break; + } + while (!keycmp (&seq1.lines[0], &seq2.lines[seq2.count - 1])); + + if (print_pairables) + { + for (i = 0; i < seq1.count - 1; ++i) + for (j = 0; j < seq2.count - 1; ++j) + prjoin (&seq1.lines[i], &seq2.lines[j]); + } + + for (i = 0; i < seq1.count - 1; ++i) + freeline (&seq1.lines[i]); + if (!eof1) + { + seq1.lines[0] = seq1.lines[seq1.count - 1]; + seq1.count = 1; + } + else + seq1.count = 0; + + for (i = 0; i < seq2.count - 1; ++i) + freeline (&seq2.lines[i]); + if (!eof2) + { + seq2.lines[0] = seq2.lines[seq2.count - 1]; + seq2.count = 1; + } + else + seq2.count = 0; + } + + if (print_unpairables_1 && seq1.count) + { + prjoin (&seq1.lines[0], &uni_blank); + freeline (&seq1.lines[0]); + while (get_line (fp1, &line)) + { + prjoin (&line, &uni_blank); + freeline (&line); + } + } + + if (print_unpairables_2 && seq2.count) + { + prjoin (&uni_blank, &seq2.lines[0]); + freeline (&seq2.lines[0]); + while (get_line (fp2, &line)) + { + prjoin (&uni_blank, &line); + freeline (&line); + } + } + + delseq (&seq1); + delseq (&seq2); +} + +/* Add a field spec for field FIELD of file FILE to `outlist'. */ + +static void +add_field (int file, int field) +{ + struct outlist *o; + + assert (file == 0 || file == 1 || file == 2); + assert (file == 0 ? field < 0 : field >= 0); + + o = (struct outlist *) xmalloc (sizeof (struct outlist)); + o->file = file; + o->field = field; + o->next = NULL; + + /* Add to the end of the list so the fields are in the right order. */ + outlist_end->next = o; + outlist_end = o; +} + +/* Convert a single field specifier string, S, to a *FILE_INDEX, *FIELD_INDEX + pair. In S, the field index string is 1-based; *FIELD_INDEX is zero-based. + If S is valid, return zero. Otherwise, give a diagnostic, don't update + *FILE_INDEX or *FIELD_INDEX, and return nonzero. */ + +static int +decode_field_spec (const char *s, int *file_index, int *field_index) +{ + int invalid = 1; + + /* The first character must be 0, 1, or 2. */ + switch (s[0]) + { + case '0': + if (s[1] == '\0') + { + *file_index = 0; + /* Give *field_index an invalid value. */ + *field_index = -1; + invalid = 0; + } + else + { + /* `0' must be all alone -- no `.FIELD'. */ + error (0, 0, _("invalid field specifier: `%s'"), s); + } + break; + + case '1': + case '2': + if (s[1] == '.' && s[2] != '\0') + { + strtol_error s_err; + long int tmp_long; + + s_err = xstrtol (s + 2, NULL, 10, &tmp_long, ""); + if (s_err != LONGINT_OK || tmp_long <= 0 || tmp_long > INT_MAX) + { + error (0, 0, _("invalid field number: `%s'"), s + 2); + } + else + { + *file_index = s[0] - '0'; + /* Convert to a zero-based index. */ + *field_index = (int) tmp_long - 1; + invalid = 0; + } + } + break; + + default: + error (0, 0, _("invalid file number in field spec: `%s'"), s); + break; + } + return invalid; +} + +/* Add the comma or blank separated field spec(s) in STR to `outlist'. + Return nonzero to indicate failure. */ + +static int +add_field_list (const char *c_str) +{ + char *p, *str; + + /* Make a writable copy of c_str. */ + str = (char *) alloca (strlen (c_str) + 1); + strcpy (str, c_str); + + p = str; + do + { + int invalid; + int file_index, field_index; + char *spec_item = p; + + p = strpbrk (p, ", \t"); + if (p) + *p++ = 0; + invalid = decode_field_spec (spec_item, &file_index, &field_index); + if (invalid) + return 1; + add_field (file_index, field_index); + uni_blank.nfields = max (uni_blank.nfields, field_index); + } + while (p); + return 0; +} + +/* Create a blank line with COUNT fields separated by tabs. */ + +static void +make_blank (struct line *blank, int count) +{ + int i; + unsigned char *buffer; + struct field *fields; + blank->nfields = count; + blank->buf.size = blank->buf.length = count + 1; + blank->buf.buffer = xmalloc (blank->buf.size); + buffer = (unsigned char *) blank->buf.buffer; + blank->fields = fields = + (struct field *) xmalloc (sizeof (struct field) * count); + for (i = 0; i < count; i++) + { + buffer[i] = '\t'; + fields[i].beg = &buffer[i]; + fields[i].len = 0; + } + buffer[i] = '\n'; +} + +int +main (int argc, char **argv) +{ + char *names[2]; + FILE *fp1, *fp2; + int optc, prev_optc = 0, nfiles; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + hard_LC_COLLATE = hard_locale (LC_COLLATE); + + atexit (close_stdout); + + /* Initialize this before parsing options. In parsing options, + it may be increased. */ + uni_blank.nfields = 1; + + nfiles = 0; + print_pairables = 1; + + while ((optc = getopt_long_only (argc, argv, "-a:e:i1:2:o:t:v:", longopts, + NULL)) != -1) + { + long int val; + + switch (optc) + { + case 0: + break; + + case 'v': + print_pairables = 0; + /* Fall through. */ + + case 'a': + if (xstrtol (optarg, NULL, 10, &val, "") != LONGINT_OK + || (val != 1 && val != 2)) + error (EXIT_FAILURE, 0, _("invalid field number: `%s'"), optarg); + if (val == 1) + print_unpairables_1 = 1; + else + print_unpairables_2 = 1; + break; + + case 'e': + empty_filler = optarg; + break; + + case 'i': + ignore_case = 1; + break; + + case '1': + if (xstrtol (optarg, NULL, 10, &val, "") != LONGINT_OK + || val <= 0 || val > INT_MAX) + { + error (EXIT_FAILURE, 0, + _("invalid field number for file 1: `%s'"), optarg); + } + join_field_1 = (int) val - 1; + break; + + case '2': + if (xstrtol (optarg, NULL, 10, &val, "") != LONGINT_OK + || val <= 0 || val > INT_MAX) + error (EXIT_FAILURE, 0, + _("invalid field number for file 2: `%s'"), optarg); + join_field_2 = (int) val - 1; + break; + + case 'j': + if (xstrtol (optarg, NULL, 10, &val, "") != LONGINT_OK + || val <= 0 || val > INT_MAX) + error (EXIT_FAILURE, 0, _("invalid field number: `%s'"), optarg); + join_field_1 = join_field_2 = (int) val - 1; + break; + + case 'o': + if (add_field_list (optarg)) + exit (EXIT_FAILURE); + break; + + case 't': + tab = *optarg; + break; + + case 1: /* Non-option argument. */ + if (prev_optc == 'o' && optind <= argc - 2) + { + if (add_field_list (optarg)) + exit (EXIT_FAILURE); + + /* Might be continuation of args to -o. */ + continue; /* Don't change `prev_optc'. */ + } + + if (nfiles > 1) + { + error (0, 0, _("too many non-option arguments")); + usage (EXIT_FAILURE); + } + names[nfiles++] = optarg; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + prev_optc = optc; + } + + /* Now that we've seen the options, we can construct the blank line + structure. */ + make_blank (&uni_blank, uni_blank.nfields); + + if (nfiles != 2) + { + error (0, 0, _("too few non-option arguments")); + usage (EXIT_FAILURE); + } + + fp1 = STREQ (names[0], "-") ? stdin : fopen (names[0], "r"); + if (!fp1) + error (EXIT_FAILURE, errno, "%s", names[0]); + fp2 = STREQ (names[1], "-") ? stdin : fopen (names[1], "r"); + if (!fp2) + error (EXIT_FAILURE, errno, "%s", names[1]); + if (fp1 == fp2) + error (EXIT_FAILURE, errno, _("both files cannot be standard input")); + join (fp1, fp2); + + if (fp1 != stdin && fclose (fp1) == EOF) + error (EXIT_FAILURE, errno, "%s", names[0]); + if (fp2 != stdin && fclose (fp2) == EOF) + error (EXIT_FAILURE, errno, "%s", names[1]); + if ((fp1 == stdin || fp2 == stdin) && fclose (stdin) == EOF) + error (EXIT_FAILURE, errno, "-"); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/kill.c b/src/apps/bin/coreutils-5.0/src/kill.c new file mode 100644 index 0000000000..6595647f94 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/kill.c @@ -0,0 +1,374 @@ +/* kill -- send a signal to a process + Copyright (C) 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Paul Eggert. */ + +#include +#include +#include +#include +#include + +#if HAVE_SYS_WAIT_H +# include +#endif +#ifndef WIFSIGNALED +# define WIFSIGNALED(s) (((s) & 0xFFFF) - 1 < (unsigned int) 0xFF) +#endif +#ifndef WTERMSIG +# define WTERMSIG(s) ((s) & 0x7F) +#endif + +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "sig2str.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "kill" + +#define AUTHORS "Paul Eggert" + +#if ! (HAVE_DECL_STRTOIMAX || defined strtoimax) +intmax_t strtoimax (); +#endif + +#if ! (HAVE_DECL_STRSIGNAL || defined strsignal) +# if ! (HAVE_DECL_SYS_SIGLIST || defined sys_siglist) +# if HAVE_DECL__SYS_SIGLIST || defined _sys_siglist +# define sys_siglist _sys_siglist +# endif +# endif +# if HAVE_DECL_SYS_SIGLIST || defined sys_siglist +# define strsignal(signum) (0 <= (signum) && (signum) <= SIGNUM_BOUND \ + ? sys_siglist[signum] \ + : 0) +# endif +# ifndef strsignal +# define strsignal(signum) 0 +# endif +#endif + +/* The name this program was run with, for error messages. */ +char *program_name; + +static char const short_options[] = + "0::1::2::3::4::5::6::7::8::9::" + "A::B::C::D::E::F::G::H::I::J::K::L::M::" + "N::O::P::Q::R::S::T::U::V::W::X::Y::Z::" + "ln:s:t"; + +static struct option const long_options[] = +{ + {"list", no_argument, NULL, 'l'}, + {"signal", required_argument, NULL, 's'}, + {"table", no_argument, NULL, 't'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [-s SIGNAL | -SIGNAL] PID...\n\ + or: %s -l [SIGNAL]...\n\ + or: %s -t [SIGNAL]...\n\ +"), + program_name, program_name, program_name); + fputs (_("\ +Send signals to processes, or list signals.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -s, --signal=SIGNAL, -SIGNAL\n\ + specify the name or number of the signal to be sent\n\ + -l, --list list signal names, or convert signal names to/from numbers\n\ + -t, --table print a table of signal information\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\n\ +SIGNAL may be a signal name like `HUP', or a signal number like `1',\n\ +or an exit status of a process terminated by a signal.\n\ +PID is an integer; if negative it identifies a process group.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +/* Convert OPERAND to a signal number with printable representation SIGNAME. + Return the signal number, or -1 if unsuccessful. */ + +static int +operand2sig (char const *operand, char *signame) +{ + int signum; + + if (ISDIGIT (*operand)) + { + char *endp; + long int l = (errno = 0, strtol (operand, &endp, 10)); + int i = l; + signum = (operand == endp || *endp || errno || i != l ? -1 + : WIFSIGNALED (i) ? WTERMSIG (i) + : i); + } + else + { + /* Convert signal to upper case in the C locale, not in the + current locale. Don't assume ASCII; it might be EBCDIC. */ + char *upcased = xstrdup (operand); + char *p; + for (p = upcased; *p; p++) + if (strchr ("abcdefghijklmnopqrstuvwxyz", *p)) + *p += 'A' - 'a'; + + /* Look for the signal name, possibly prefixed by "SIG", + and possibly lowercased. */ + if (! (str2sig (upcased, &signum) == 0 + || (upcased[0] == 'S' && upcased[1] == 'I' && upcased[2] == 'G' + && str2sig (upcased + 3, &signum) == 0))) + signum = -1; + + free (upcased); + } + + if (signum < 0 || sig2str (signum, signame) != 0) + { + error (0, 0, _("%s: invalid signal"), operand); + return -1; + } + + return signum; +} + +/* Print a row of `kill -t' output. NUM_WIDTH is the maximum signal + number width, and SIGNUM is the signal number to print. The + maximum name width is NAME_WIDTH, and SIGNAME is the name to print. */ + +static void +print_table_row (unsigned int num_width, int signum, + unsigned int name_width, char const *signame) +{ + char const *description = strsignal (signum); + printf ("%*d %-*s %s\n", num_width, signum, name_width, signame, + description ? description : "?"); +} + +/* Print a list of signal names. If TABLE, print a table. + Print the names specified by ARGV if nonzero; otherwise, + print all known names. Return a suitable exit status. */ + +static int +list_signals (bool table, char *const *argv) +{ + int signum; + int status = EXIT_SUCCESS; + char signame[SIG2STR_MAX]; + + if (table) + { + unsigned int name_width = 0; + + /* Compute the maximum width of a signal number. */ + unsigned int num_width = 1; + for (signum = 1; signum <= SIGNUM_BOUND / 10; signum *= 10) + num_width++; + + /* Compute the maximum width of a signal name. */ + for (signum = 1; signum <= SIGNUM_BOUND; signum++) + if (sig2str (signum, signame) == 0) + { + size_t len = strlen (signame); + if (name_width < len) + name_width = len; + } + + if (argv) + for (; *argv; argv++) + { + signum = operand2sig (*argv, signame); + if (signum < 0) + status = EXIT_FAILURE; + else + print_table_row (num_width, signum, name_width, signame); + } + else + for (signum = 1; signum <= SIGNUM_BOUND; signum++) + if (sig2str (signum, signame) == 0) + print_table_row (num_width, signum, name_width, signame); + } + else + { + if (argv) + for (; *argv; argv++) + { + signum = operand2sig (*argv, signame); + if (signum < 0) + status = EXIT_FAILURE; + else + { + if (ISDIGIT (**argv)) + puts (signame); + else + printf ("%d\n", signum); + } + } + else + for (signum = 1; signum <= SIGNUM_BOUND; signum++) + if (sig2str (signum, signame) == 0) + puts (signame); + } + + return status; +} + +/* Send signal SIGNUM to all the processes or process groups specified + by ARGV. Return a suitable exit status. */ + +static int +send_signals (int signum, char *const *argv) +{ + int status = EXIT_SUCCESS; + char const *arg = *argv; + + if (! arg) + { + error (0, 0, _("missing operand after `%s'"), argv[-1]); + usage (EXIT_FAILURE); + } + + do + { + char *endp; + intmax_t n = (errno = 0, strtoimax (arg, &endp, 10)); + pid_t pid = n; + + if (errno == ERANGE || pid != n || arg == endp || *endp) + { + error (0, 0, _("%s: invalid process id"), arg); + status = EXIT_FAILURE; + } + else if (kill (pid, signum) != 0) + { + error (0, errno, "%s", arg); + status = EXIT_FAILURE; + } + } + while ((arg = *++argv)); + + return status; +} + +int +main (int argc, char **argv) +{ + int optc; + bool list = false; + bool table = false; + int signum = -1; + char signame[SIG2STR_MAX]; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + while ((optc = getopt_long (argc, argv, short_options, long_options, NULL)) + != -1) + switch (optc) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (optind != 2) + { + /* This option is actually a process-id. */ + optind--; + goto no_more_options; + } + /* Fall through. */ + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + if (! optarg) + optarg = argv[optind - 1] + strlen (argv[optind - 1]); + if (optarg != argv[optind - 1] + 2) + { + error (0, 0, _("invalid option -- %c"), optc); + usage (EXIT_FAILURE); + } + optarg--; + /* Fall through. */ + case 'n': /* -n is not documented, but is for Bash compatibility. */ + case 's': + if (0 <= signum) + { + error (0, 0, _("%s: multiple signals specified"), optarg); + usage (EXIT_FAILURE); + } + signum = operand2sig (optarg, signame); + if (signum < 0) + usage (EXIT_FAILURE); + break; + + case 't': + table = true; + /* Fall through. */ + case 'l': + if (list) + { + error (0, 0, _("multiple -l or -t options specified")); + usage (EXIT_FAILURE); + } + list = true; + break; + + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + no_more_options:; + + if (signum < 0) + signum = SIGTERM; + else if (list) + { + error (0, 0, _("cannot combine signal with -l or -t")); + usage (EXIT_FAILURE); + } + + return (list + ? list_signals (table, optind == argc ? NULL : argv + optind) + : send_signals (signum, argv + optind)); +} diff --git a/src/apps/bin/coreutils-5.0/src/link.c b/src/apps/bin/coreutils-5.0/src/link.c new file mode 100644 index 0000000000..760ad945bb --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/link.c @@ -0,0 +1,102 @@ +/* link utility for GNU. + Copyright (C) 2001-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Michael Stone */ + +/* Implementation overview: + + Simply call the system 'link' function */ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "long-options.h" +#include "quote.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "link" + +#define AUTHORS "Michael Stone" + +/* Name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s FILE1 FILE2\n\ + or: %s OPTION\n"), program_name, program_name); + fputs (_("Call the link function to create a link named FILE2\ + to an existing FILE1.\n\n"), + stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + /* The above handles --help and --version. + Since there is no other invocation of getopt, handle `--' here. */ + if (1 < argc && STREQ (argv[1], "--")) + { + --argc; + ++argv; + } + + if (argc < 3) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + if (3 < argc) + { + error (0, 0, _("too many arguments")); + usage (EXIT_FAILURE); + } + + if (link (argv[1], argv[2]) != 0) + error (EXIT_FAILURE, errno, _("cannot create link %s to %s"), + quote_n (0, argv[2]), quote_n (1, argv[1])); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/ln.c b/src/apps/bin/coreutils-5.0/src/ln.c new file mode 100644 index 0000000000..0bbd2cb6e5 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/ln.c @@ -0,0 +1,575 @@ +/* `ln' program to create links between files. + Copyright (C) 86, 89, 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Mike Parker and David MacKenzie. */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include +#include +#include + +#include "system.h" +#include "same.h" +#include "backupfile.h" +#include "dirname.h" +#include "error.h" +#include "quote.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "ln" + +#define AUTHORS N_ ("Mike Parker and David MacKenzie") + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + TARGET_DIRECTORY_OPTION = CHAR_MAX + 1 +}; + +int link (); /* Some systems don't declare this anywhere. */ + +#ifdef S_ISLNK +int symlink (); +#endif + +/* In being careful not even to try to make hard links to directories, + we have to know whether link(2) follows symlinks. If it does, then + we have to *stat* the `source' to see if the resulting link would be + to a directory. Otherwise, we have to use *lstat* so that we allow + users to make hard links to symlinks-that-point-to-directories. */ + +#if LINK_FOLLOWS_SYMLINKS +# define STAT_LIKE_LINK(File, Stat_buf) \ + stat (File, Stat_buf) +#else +# define STAT_LIKE_LINK(File, Stat_buf) \ + lstat (File, Stat_buf) +#endif + +/* Construct a string NEW_DEST by concatenating DEST, a slash, and + basename(SOURCE) in alloca'd memory. Don't modify DEST or SOURCE. */ + +#define PATH_BASENAME_CONCAT(new_dest, dest, source) \ + do \ + { \ + const char *source_base; \ + char *tmp_source; \ + \ + tmp_source = (char *) alloca (strlen ((source)) + 1); \ + strcpy (tmp_source, (source)); \ + strip_trailing_slashes (tmp_source); \ + source_base = base_name (tmp_source); \ + \ + (new_dest) = (char *) alloca (strlen ((dest)) + 1 \ + + strlen (source_base) + 1); \ + stpcpy (stpcpy (stpcpy ((new_dest), (dest)), "/"), source_base);\ + } \ + while (0) + +int isdir (); +int yesno (); + +/* The name by which the program was run, for error messages. */ +char *program_name; + +/* FIXME: document */ +enum backup_type backup_type; + +/* A pointer to the function used to make links. This will point to either + `link' or `symlink'. */ +static int (*linkfunc) (); + +/* If nonzero, make symbolic links; otherwise, make hard links. */ +static int symbolic_link; + +/* If nonzero, ask the user before removing existing files. */ +static int interactive; + +/* If nonzero, remove existing files unconditionally. */ +static int remove_existing_files; + +/* If nonzero, list each file as it is moved. */ +static int verbose; + +/* If nonzero, allow the superuser to make hard links to directories. */ +static int hard_dir_link; + +/* If nonzero, and the specified destination is a symbolic link to a + directory, treat it just as if it were a directory. Otherwise, the + command `ln --force --no-dereference file symlink-to-dir' deletes + symlink-to-dir before creating the new link. */ +static int dereference_dest_dir_symlinks = 1; + +static struct option const long_options[] = +{ + {"backup", optional_argument, NULL, 'b'}, + {"directory", no_argument, NULL, 'F'}, + {"no-dereference", no_argument, NULL, 'n'}, + {"force", no_argument, NULL, 'f'}, + {"interactive", no_argument, NULL, 'i'}, + {"suffix", required_argument, NULL, 'S'}, + {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION}, + {"symbolic", no_argument, NULL, 's'}, + {"verbose", no_argument, NULL, 'v'}, + {"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */ + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +/* Make a link DEST to the (usually) existing file SOURCE. + Symbolic links to nonexistent files are allowed. + If DEST is a directory, put the link to SOURCE in that directory. + Return 1 if there is an error, otherwise 0. */ + +static int +do_link (const char *source, const char *dest) +{ + struct stat source_stats; + struct stat dest_stats; + char *dest_backup = NULL; + int lstat_status; + int backup_succeeded = 0; + + /* Use stat here instead of lstat. + On SVR4, link does not follow symlinks, so this check disallows + making hard links to symlinks that point to directories. Big deal. + On other systems, link follows symlinks, so this check is right. */ + if (!symbolic_link) + { + if (STAT_LIKE_LINK (source, &source_stats) != 0) + { + error (0, errno, _("accessing %s"), quote (source)); + return 1; + } + + if (S_ISLNK (source_stats.st_mode)) + { + error (0, 0, _("%s: warning: making a hard link to a symbolic link\ + is not portable"), + quote (source)); + } + + if (!hard_dir_link && S_ISDIR (source_stats.st_mode)) + { + error (0, 0, _("%s: hard link not allowed for directory"), + quote (source)); + return 1; + } + } + + lstat_status = lstat (dest, &dest_stats); + if (lstat_status != 0 && errno != ENOENT) + { + error (0, errno, _("accessing %s"), quote (dest)); + return 1; + } + + /* If the destination is a directory or (it is a symlink to a directory + and the user has not specified --no-dereference), then form the + actual destination name by appending base_name (source) to the + specified destination directory. */ + if ((lstat_status == 0 + && S_ISDIR (dest_stats.st_mode)) +#ifdef S_ISLNK + || (dereference_dest_dir_symlinks + && (lstat_status == 0 + && S_ISLNK (dest_stats.st_mode) + && isdir (dest))) +#endif + ) + { + /* Target is a directory; build the full filename. */ + char *new_dest; + PATH_BASENAME_CONCAT (new_dest, dest, source); + dest = new_dest; + + /* Get stats for new DEST. */ + lstat_status = lstat (dest, &dest_stats); + if (lstat_status != 0 && errno != ENOENT) + { + error (0, errno, _("accessing %s"), quote (dest)); + return 1; + } + } + + /* If --force (-f) has been specified without --backup, then before + making a link ln must remove the destination file if it exists. + (with --backup, it just renames any existing destination file) + But if the source and destination are the same, don't remove + anything and fail right here. */ + if (remove_existing_files + && lstat_status == 0 + /* Allow `ln -sf --backup k k' to succeed in creating the + self-referential symlink, but don't allow the hard-linking + equivalent: `ln -f k k' (with or without --backup) to get + beyond this point, because the error message you'd get is + misleading. */ + && (backup_type == none || !symbolic_link) + && (!symbolic_link || stat (source, &source_stats) == 0) + && source_stats.st_dev == dest_stats.st_dev + && source_stats.st_ino == dest_stats.st_ino + /* The following detects whether removing DEST will also remove + SOURCE. If the file has only one link then both are surely + the same link. Otherwise check whether they point to the same + name in the same directory. */ + && (source_stats.st_nlink == 1 || same_name (source, dest))) + { + error (0, 0, _("%s and %s are the same file"), + quote_n (0, source), quote_n (1, dest)); + return 1; + } + + if (lstat_status == 0 || lstat (dest, &dest_stats) == 0) + { + if (S_ISDIR (dest_stats.st_mode)) + { + error (0, 0, _("%s: cannot overwrite directory"), quote (dest)); + return 1; + } + if (interactive) + { + fprintf (stderr, _("%s: replace %s? "), program_name, quote (dest)); + if (!yesno ()) + return 0; + } + else if (!remove_existing_files && backup_type == none) + { + error (0, 0, _("%s: File exists"), quote (dest)); + return 1; + } + + if (backup_type != none) + { + char *tmp_backup = find_backup_file_name (dest, backup_type); + if (tmp_backup == NULL) + xalloc_die (); + dest_backup = (char *) alloca (strlen (tmp_backup) + 1); + strcpy (dest_backup, tmp_backup); + free (tmp_backup); + if (rename (dest, dest_backup)) + { + if (errno != ENOENT) + { + error (0, errno, _("cannot backup %s"), quote (dest)); + return 1; + } + else + dest_backup = NULL; + } + else + { + backup_succeeded = 1; + } + } + + /* Try to unlink DEST even if we may have renamed it. In some unusual + cases (when DEST and DEST_BACKUP are hard-links that refer to the + same file), rename succeeds and DEST remains. If we didn't remove + DEST in that case, the subsequent LINKFUNC call would fail. */ + if (unlink (dest) && errno != ENOENT) + { + error (0, errno, _("cannot remove %s"), quote (dest)); + return 1; + } + } + else if (errno != ENOENT) + { + error (0, errno, _("accessing %s"), quote (dest)); + return 1; + } + + if (verbose) + { + printf ((symbolic_link + ? _("create symbolic link %s to %s") + : _("create hard link %s to %s")), + quote_n (0, dest), quote_n (1, source)); + if (backup_succeeded) + printf (_(" (backup: %s)"), quote (dest_backup)); + putchar ('\n'); + } + + if ((*linkfunc) (source, dest) == 0) + { + return 0; + } + + error (0, errno, + (symbolic_link + ? _("creating symbolic link %s to %s") + : _("creating hard link %s to %s")), + quote_n (0, dest), quote_n (1, source)); + + if (dest_backup) + { + if (rename (dest_backup, dest)) + error (0, errno, _("cannot un-backup %s"), quote (dest)); + } + return 1; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... TARGET [LINK_NAME]\n\ + or: %s [OPTION]... TARGET... DIRECTORY\n\ + or: %s [OPTION]... --target-directory=DIRECTORY TARGET...\n\ +"), + program_name, program_name, program_name); + fputs (_("\ +Create a link to the specified TARGET with optional LINK_NAME.\n\ +If LINK_NAME is omitted, a link with the same basename as the TARGET is\n\ +created in the current directory. When using the second form with more\n\ +than one TARGET, the last argument must be a directory; create links\n\ +in DIRECTORY to each TARGET. Create hard links by default, symbolic\n\ +links with --symbolic. When creating hard links, each TARGET must exist.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + --backup[=CONTROL] make a backup of each existing destination file\n\ + -b like --backup but does not accept an argument\n\ + -d, -F, --directory hard link directories (super-user only)\n\ + -f, --force remove existing destination files\n\ +"), stdout); + fputs (_("\ + -n, --no-dereference treat destination that is a symlink to a\n\ + directory as if it were a normal file\n\ + -i, --interactive prompt whether to remove destinations\n\ + -s, --symbolic make symbolic links instead of hard links\n\ +"), stdout); + fputs (_("\ + -S, --suffix=SUFFIX override the usual backup suffix\n\ + --target-directory=DIRECTORY specify the DIRECTORY in which to create\n\ + the links\n\ + -v, --verbose print name of each file before linking\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ +The version control method may be selected via the --backup option or through\n\ +the VERSION_CONTROL environment variable. Here are the values:\n\ +\n\ +"), stdout); + fputs (_("\ + none, off never make backups (even if --backup is given)\n\ + numbered, t make numbered backups\n\ + existing, nil numbered if numbered backups exist, simple otherwise\n\ + simple, never always make simple backups\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int c; + int errors; + int make_backups = 0; + char *backup_suffix_string; + char *version_control_string = NULL; + char *target_directory = NULL; + int target_directory_specified; + unsigned int n_files; + char **file; + int dest_is_dir; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + + symbolic_link = remove_existing_files = interactive = verbose + = hard_dir_link = 0; + errors = 0; + + while ((c = getopt_long (argc, argv, "bdfinsvFS:V:", long_options, NULL)) + != -1) + { + switch (c) + { + case 0: /* Long-named option. */ + break; + + case 'V': /* FIXME: this is deprecated. Remove it in 2001. */ + error (0, 0, + _("warning: --version-control (-V) is obsolete; support for\ + it\nwill be removed in some future release. Use --backup=%s instead." + ), optarg); + /* Fall through. */ + + case 'b': + make_backups = 1; + if (optarg) + version_control_string = optarg; + break; + case 'd': + case 'F': + hard_dir_link = 1; + break; + case 'f': + remove_existing_files = 1; + interactive = 0; + break; + case 'i': + remove_existing_files = 0; + interactive = 1; + break; + case 'n': + dereference_dest_dir_symlinks = 0; + break; + case 's': +#ifdef S_ISLNK + symbolic_link = 1; +#else + error (EXIT_FAILURE, 0, + _("symbolic links are not supported on this system")); +#endif + break; + case TARGET_DIRECTORY_OPTION: + target_directory = optarg; + break; + case 'v': + verbose = 1; + break; + case 'S': + make_backups = 1; + backup_suffix_string = optarg; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + break; + } + } + + n_files = argc - optind; + file = argv + optind; + + if (n_files == 0) + { + error (0, 0, _("missing file argument")); + usage (EXIT_FAILURE); + } + + target_directory_specified = (target_directory != NULL); + if (!target_directory) + target_directory = file[n_files - 1]; + + /* If target directory is not specified, and there's only one + file argument, then pretend `.' was given as the second argument. */ + if (!target_directory_specified && n_files == 1) + { + static char *dummy[2]; + dummy[0] = file[0]; + dummy[1] = "."; + file = dummy; + n_files = 2; + dest_is_dir = 1; + } + else + { + dest_is_dir = isdir (target_directory); + } + + if (symbolic_link) + linkfunc = symlink; + else + linkfunc = link; + + if (target_directory_specified && !dest_is_dir) + { + error (0, 0, _("%s: specified target directory is not a directory"), + quote (target_directory)); + usage (EXIT_FAILURE); + } + + if (backup_suffix_string) + simple_backup_suffix = xstrdup (backup_suffix_string); + + backup_type = (make_backups + ? xget_version (_("backup type"), version_control_string) + : none); + + if (target_directory_specified || n_files > 2) + { + unsigned int i; + unsigned int last_file_idx = (target_directory_specified + ? n_files - 1 + : n_files - 2); + + if (!target_directory_specified && !dest_is_dir) + error (EXIT_FAILURE, 0, + _("when making multiple links, last argument must be a directory")); + for (i = 0; i <= last_file_idx; ++i) + errors += do_link (file[i], target_directory); + } + else + { + struct stat source_stats; + const char *source; + char *dest; + char *new_dest; + + source = file[0]; + dest = file[1]; + + /* When the destination is specified with a trailing slash and the + source exists but is not a directory, convert the user's command + `ln source dest/' to `ln source dest/basename(source)'. */ + + if (dest[strlen (dest) - 1] == '/' + && lstat (source, &source_stats) == 0 + && !S_ISDIR (source_stats.st_mode)) + { + PATH_BASENAME_CONCAT (new_dest, dest, source); + } + else + { + new_dest = dest; + } + + errors = do_link (source, new_dest); + } + + exit (errors != 0); +} diff --git a/src/apps/bin/coreutils-5.0/src/logname.c b/src/apps/bin/coreutils-5.0/src/logname.c new file mode 100644 index 0000000000..d86fab0e89 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/logname.c @@ -0,0 +1,101 @@ +/* logname -- print user's login name + Copyright (C) 1990-1997, 1999-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "long-options.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "logname" + +#define AUTHORS "FIXME: unknown" + +/* The name this program was run with. */ +char *program_name; + +static struct option const long_options[] = +{ + {0, 0, 0, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]\n"), program_name); + fputs (_("\ +Print the name of the current user.\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + register char *cp; + int c; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + default: + usage (EXIT_FAILURE); + } + } + + if (argc - optind != 0) + usage (EXIT_FAILURE); + + /* POSIX requires using getlogin (or equivalent code). */ + cp = getlogin (); + if (cp) + { + puts (cp); + exit (EXIT_SUCCESS); + } + /* POSIX prohibits using a fallback technique. */ + fprintf (stderr, _("%s: no login name\n"), argv[0]); + exit (EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/ls-dir.c b/src/apps/bin/coreutils-5.0/src/ls-dir.c new file mode 100644 index 0000000000..85fe242ebf --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/ls-dir.c @@ -0,0 +1,2 @@ +#include "ls.h" +int ls_mode = LS_MULTI_COL; diff --git a/src/apps/bin/coreutils-5.0/src/ls-ls.c b/src/apps/bin/coreutils-5.0/src/ls-ls.c new file mode 100644 index 0000000000..f33fbbc061 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/ls-ls.c @@ -0,0 +1,2 @@ +#include "ls.h" +int ls_mode = LS_LS; diff --git a/src/apps/bin/coreutils-5.0/src/ls-vdir.c b/src/apps/bin/coreutils-5.0/src/ls-vdir.c new file mode 100644 index 0000000000..36ebf913bc --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/ls-vdir.c @@ -0,0 +1,2 @@ +#include "ls.h" +int ls_mode = LS_LONG_FORMAT; diff --git a/src/apps/bin/coreutils-5.0/src/ls.c b/src/apps/bin/coreutils-5.0/src/ls.c new file mode 100644 index 0000000000..cbd43a0190 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/ls.c @@ -0,0 +1,3894 @@ +/* `dir', `vdir' and `ls' directory listing programs for GNU. + Copyright (C) 85, 88, 90, 91, 1995-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* If ls_mode is LS_MULTI_COL, + the multi-column format is the default regardless + of the type of output device. + This is for the `dir' program. + + If ls_mode is LS_LONG_FORMAT, + the long format is the default regardless of the + type of output device. + This is for the `vdir' program. + + If ls_mode is LS_LS, + the output format depends on whether the output + device is a terminal. + This is for the `ls' program. */ + +/* Written by Richard Stallman and David MacKenzie. */ + +/* Color support by Peter Anvin and Dennis + Flaherty based on original patches by + Greg Lee . */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include + +#if HAVE_TERMIOS_H +# include +#endif + +#ifdef GWINSZ_IN_SYS_IOCTL +# include +#endif + +#ifdef WINSIZE_IN_PTEM +# include +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +/* Get MB_CUR_MAX. */ +#if HAVE_STDLIB_H +# include +#endif + +/* Get mbstate_t, mbrtowc(), mbsinit(), wcwidth(). */ +#if HAVE_WCHAR_H +# include +#endif + +/* Get iswprint(). */ +#if HAVE_WCTYPE_H +# include +#endif +#if !defined iswprint && !HAVE_ISWPRINT +# define iswprint(wc) 1 +#endif + +#ifndef HAVE_DECL_WCWIDTH +"this configure-time declaration test was not run" +#endif +#if !HAVE_DECL_WCWIDTH +int wcwidth (); +#endif + +/* If wcwidth() doesn't exist, assume all printable characters have + width 1. */ +#ifndef wcwidth +# if !HAVE_WCWIDTH +# define wcwidth(wc) ((wc) == 0 ? 0 : iswprint (wc) ? 1 : -1) +# endif +#endif + +#include "system.h" +#include + +#include "acl.h" +#include "argmatch.h" +#include "dev-ino.h" +#include "dirname.h" +#include "dirfd.h" +#include "error.h" +#include "full-write.h" +#include "hard-locale.h" +#include "hash.h" +#include "human.h" +#include "filemode.h" +#include "inttostr.h" +#include "ls.h" +#include "mbswidth.h" +#include "obstack.h" +#include "path-concat.h" +#include "quote.h" +#include "quotearg.h" +#include "same.h" +#include "strftime.h" +#include "strverscmp.h" +#include "xstrtol.h" +#include "xreadlink.h" + +#define PROGRAM_NAME (ls_mode == LS_LS ? "ls" \ + : (ls_mode == LS_MULTI_COL \ + ? "dir" : "vdir")) + +#define AUTHORS N_ ("Richard Stallman and David MacKenzie") + +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free + +/* Return an int indicating the result of comparing two integers. + Subtracting doesn't always work, due to overflow. */ +#define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b)) + +/* The field width for inode numbers. On some hosts inode numbers are + 64 bits, so columns won't line up exactly when a huge inode number + is encountered, but in practice 7 digits is usually enough. */ +#ifndef INODE_DIGITS +# define INODE_DIGITS 7 +#endif + +/* Arrange to make lstat calls go through the wrapper function + on systems with an lstat function that does not dereference symlinks + that are specified with a trailing slash. */ +#if ! LSTAT_FOLLOWS_SLASHED_SYMLINK +int rpl_lstat (const char *, struct stat *); +# undef lstat +# define lstat(Name, Stat_buf) rpl_lstat(Name, Stat_buf) +#endif + +#if HAVE_STRUCT_DIRENT_D_TYPE && defined DTTOIF +# define DT_INIT(Val) = Val +#else +# define DT_INIT(Val) /* empty */ +#endif + +#ifdef ST_MTIM_NSEC +# define TIMESPEC_NS(timespec) ((timespec).ST_MTIM_NSEC) +#else +# define TIMESPEC_NS(timespec) 0 +#endif + +#if ! HAVE_STRUCT_STAT_ST_AUTHOR +# define st_author st_uid +#endif + +/* Cray/Unicos DMF: use the file's migrated, not real, status */ +#if HAVE_ST_DM_MODE +# define ST_DM_MODE(Stat_buf) ((Stat_buf).st_dm_mode) +#else +# define ST_DM_MODE(Stat_buf) ((Stat_buf).st_mode) +#endif + +#ifndef LOGIN_NAME_MAX +# if _POSIX_LOGIN_NAME_MAX +# define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX +# else +# define LOGIN_NAME_MAX 17 +# endif +#endif + +/* The maximum length of a string representation of a user or group ID, + not counting any terminating NUL byte. */ +#define ID_LENGTH_MAX \ + MAX (LOGIN_NAME_MAX - 1, LONGEST_HUMAN_READABLE) + +enum filetype + { + unknown DT_INIT (DT_UNKNOWN), + fifo DT_INIT (DT_FIFO), + chardev DT_INIT (DT_CHR), + directory DT_INIT (DT_DIR), + blockdev DT_INIT (DT_BLK), + normal DT_INIT (DT_REG), + symbolic_link DT_INIT (DT_LNK), + sock DT_INIT (DT_SOCK), + arg_directory DT_INIT (2 * (DT_UNKNOWN | DT_FIFO | DT_CHR | DT_DIR | DT_BLK + | DT_REG | DT_LNK | DT_SOCK)) + }; + +struct fileinfo + { + /* The file name. */ + char *name; + + struct stat stat; + + /* For symbolic link, name of the file linked to, otherwise zero. */ + char *linkname; + + /* For symbolic link and long listing, st_mode of file linked to, otherwise + zero. */ + mode_t linkmode; + + /* For symbolic link and color printing, 1 if linked-to file + exists, otherwise 0. */ + int linkok; + + enum filetype filetype; + +#if HAVE_ACL + /* For long listings, true if the file has an access control list. */ + bool have_acl; +#endif + }; + +#if HAVE_ACL +# define FILE_HAS_ACL(F) ((F)->have_acl) +#else +# define FILE_HAS_ACL(F) 0 +#endif + +#define LEN_STR_PAIR(s) sizeof (s) - 1, s + +/* Null is a valid character in a color indicator (think about Epson + printers, for example) so we have to use a length/buffer string + type. */ + +struct bin_str + { + int len; /* Number of bytes */ + const char *string; /* Pointer to the same */ + }; + +#ifndef STDC_HEADERS +time_t time (); +#endif + +char *getgroup (); +char *getuser (); + +static size_t quote_name (FILE *out, const char *name, + struct quoting_options const *options, + size_t *width); +static char *make_link_path (const char *path, const char *linkname); +static int decode_switches (int argc, char **argv); +static int file_interesting (const struct dirent *next); +static uintmax_t gobble_file (const char *name, enum filetype type, + int explicit_arg, const char *dirname); +static void print_color_indicator (const char *name, mode_t mode, int linkok); +static void put_indicator (const struct bin_str *ind); +static int put_indicator_direct (const struct bin_str *ind); +static int length_of_file_name_and_frills (const struct fileinfo *f); +static void add_ignore_pattern (const char *pattern); +static void attach (char *dest, const char *dirname, const char *name); +static void clear_files (void); +static void extract_dirs_from_files (const char *dirname, + int ignore_dot_and_dot_dot); +static void get_link_name (const char *filename, struct fileinfo *f); +static void indent (int from, int to); +static void init_column_info (void); +static void print_current_files (void); +static void print_dir (const char *name, const char *realname); +static void print_file_name_and_frills (const struct fileinfo *f); +static void print_horizontal (void); +static void print_long_format (const struct fileinfo *f); +static void print_many_per_line (void); +static void print_name_with_quoting (const char *p, mode_t mode, + int linkok, + struct obstack *stack); +static void prep_non_filename_text (void); +static void print_type_indicator (mode_t mode); +static void print_with_commas (void); +static void queue_directory (const char *name, const char *realname); +static void sort_files (void); +static void parse_ls_color (void); +void usage (int status); + +/* The name the program was run with, stripped of any leading path. */ +char *program_name; + +/* Initial size of hash table. + Most hierarchies are likely to be shallower than this. */ +#define INITIAL_TABLE_SIZE 30 + +/* The set of `active' directories, from the current command-line argument + to the level in the hierarchy at which files are being listed. + A directory is represented by its device and inode numbers (struct dev_ino). + A directory is added to this set when ls begins listing it or its + entries, and it is removed from the set just after ls has finished + processing it. This set is used solely to detect loops, e.g., with + mkdir loop; cd loop; ln -s ../loop sub; ls -RL */ +static Hash_table *active_dir_set; + +#define LOOP_DETECT (!!active_dir_set) + +/* The table of files in the current directory: + + `files' points to a vector of `struct fileinfo', one per file. + `nfiles' is the number of elements space has been allocated for. + `files_index' is the number actually in use. */ + +/* Address of block containing the files that are described. */ +static struct fileinfo *files; /* FIXME: rename this to e.g. cwd_file */ + +/* Length of block that `files' points to, measured in files. */ +static int nfiles; /* FIXME: rename this to e.g. cwd_n_alloc */ + +/* Index of first unused in `files'. */ +static int files_index; /* FIXME: rename this to e.g. cwd_n_used */ + +/* When nonzero, in a color listing, color each symlink name according to the + type of file it points to. Otherwise, color them according to the `ln' + directive in LS_COLORS. Dangling (orphan) symlinks are treated specially, + regardless. This is set when `ln=target' appears in LS_COLORS. */ + +static int color_symlink_as_referent; + +/* mode of appropriate file for colorization */ +#define FILE_OR_LINK_MODE(File) \ + ((color_symlink_as_referent && (File)->linkok) \ + ? (File)->linkmode : (File)->stat.st_mode) + + +/* Record of one pending directory waiting to be listed. */ + +struct pending + { + char *name; + /* If the directory is actually the file pointed to by a symbolic link we + were told to list, `realname' will contain the name of the symbolic + link, otherwise zero. */ + char *realname; + struct pending *next; + }; + +static struct pending *pending_dirs; + +/* Current time in seconds and nanoseconds since 1970, updated as + needed when deciding whether a file is recent. */ + +static time_t current_time = TYPE_MINIMUM (time_t); +static int current_time_ns = -1; + +/* The number of digits to use for block sizes. + 4, or more if needed for bigger numbers. */ + +static int block_size_size; + +/* Option flags */ + +/* long_format for lots of info, one per line. + one_per_line for just names, one per line. + many_per_line for just names, many per line, sorted vertically. + horizontal for just names, many per line, sorted horizontally. + with_commas for just names, many per line, separated by commas. + + -l (and other options that imply -l), -1, -C, -x and -m control + this parameter. */ + +enum format + { + long_format, /* -l and other options that imply -l */ + one_per_line, /* -1 */ + many_per_line, /* -C */ + horizontal, /* -x */ + with_commas /* -m */ + }; + +static enum format format; + +/* `full-iso' uses full ISO-style dates and times. `long-iso' uses longer + ISO-style time stamps, though shorter than `full-iso'. `iso' uses shorter + ISO-style time stamps. `locale' uses locale-dependent time stamps. */ +enum time_style + { + full_iso_time_style, /* --time-style=full-iso */ + long_iso_time_style, /* --time-style=long-iso */ + iso_time_style, /* --time-style=iso */ + locale_time_style /* --time-style=locale */ + }; + +static char const *const time_style_args[] = +{ + "full-iso", "long-iso", "iso", "locale", 0 +}; + +static enum time_style const time_style_types[] = +{ + full_iso_time_style, long_iso_time_style, iso_time_style, + locale_time_style, 0 +}; + +/* Type of time to print or sort by. Controlled by -c and -u. */ + +enum time_type + { + time_mtime, /* default */ + time_ctime, /* -c */ + time_atime /* -u */ + }; + +static enum time_type time_type; + +/* The file characteristic to sort by. Controlled by -t, -S, -U, -X, -v. */ + +enum sort_type + { + sort_none, /* -U */ + sort_name, /* default */ + sort_extension, /* -X */ + sort_time, /* -t */ + sort_size, /* -S */ + sort_version /* -v */ + }; + +static enum sort_type sort_type; + +/* Direction of sort. + 0 means highest first if numeric, + lowest first if alphabetic; + these are the defaults. + 1 means the opposite order in each case. -r */ + +static int sort_reverse; + +/* Nonzero means to display owner information. -g turns this off. */ + +static int print_owner = 1; + +/* Nonzero means to display author information. */ + +static bool print_author; + +/* Nonzero means to display group information. -G and -o turn this off. */ + +static int print_group = 1; + +/* Nonzero means print the user and group id's as numbers rather + than as names. -n */ + +static int numeric_ids; + +/* Nonzero means mention the size in blocks of each file. -s */ + +static int print_block_size; + +/* Human-readable options for output. */ +static int human_output_opts; + +/* The units to use when printing sizes other than file sizes. */ +static uintmax_t output_block_size; + +/* Likewise, but for file sizes. */ +static uintmax_t file_output_block_size = 1; + +/* Precede each line of long output (per file) with a string like `m,n:' + where M is the number of characters after the `:' and before the + filename and N is the length of the filename. Using this format, + Emacs' dired mode starts up twice as fast, and can handle all + strange characters in file names. */ +static int dired; + +/* `none' means don't mention the type of files. + `classify' means mention file types and mark executables. + `file_type' means mention only file types. + + Controlled by -F, -p, and --indicator-style. */ + +enum indicator_style + { + none, /* --indicator-style=none */ + classify, /* -F, --indicator-style=classify */ + file_type /* -p, --indicator-style=file-type */ + }; + +static enum indicator_style indicator_style; + +/* Names of indicator styles. */ +static char const *const indicator_style_args[] = +{ + "none", "classify", "file-type", 0 +}; + +static enum indicator_style const indicator_style_types[]= +{ + none, classify, file_type +}; + +/* Nonzero means use colors to mark types. Also define the different + colors as well as the stuff for the LS_COLORS environment variable. + The LS_COLORS variable is now in a termcap-like format. */ + +static int print_with_color; + +enum color_type + { + color_never, /* 0: default or --color=never */ + color_always, /* 1: --color=always */ + color_if_tty /* 2: --color=tty */ + }; + +enum Dereference_symlink + { + DEREF_UNDEFINED = 1, + DEREF_NEVER, + DEREF_COMMAND_LINE_ARGUMENTS, /* -H */ + DEREF_COMMAND_LINE_SYMLINK_TO_DIR, /* the default, in certain cases */ + DEREF_ALWAYS /* -L */ + }; + +enum indicator_no + { + C_LEFT, C_RIGHT, C_END, C_NORM, C_FILE, C_DIR, C_LINK, C_FIFO, C_SOCK, + C_BLK, C_CHR, C_MISSING, C_ORPHAN, C_EXEC, C_DOOR + }; + +static const char *const indicator_name[]= + { + "lc", "rc", "ec", "no", "fi", "di", "ln", "pi", "so", + "bd", "cd", "mi", "or", "ex", "do", NULL + }; + +struct color_ext_type + { + struct bin_str ext; /* The extension we're looking for */ + struct bin_str seq; /* The sequence to output when we do */ + struct color_ext_type *next; /* Next in list */ + }; + +static struct bin_str color_indicator[] = + { + { LEN_STR_PAIR ("\033[") }, /* lc: Left of color sequence */ + { LEN_STR_PAIR ("m") }, /* rc: Right of color sequence */ + { 0, NULL }, /* ec: End color (replaces lc+no+rc) */ + { LEN_STR_PAIR ("0") }, /* no: Normal */ + { LEN_STR_PAIR ("0") }, /* fi: File: default */ + { LEN_STR_PAIR ("01;34") }, /* di: Directory: bright blue */ + { LEN_STR_PAIR ("01;36") }, /* ln: Symlink: bright cyan */ + { LEN_STR_PAIR ("33") }, /* pi: Pipe: yellow/brown */ + { LEN_STR_PAIR ("01;35") }, /* so: Socket: bright magenta */ + { LEN_STR_PAIR ("01;33") }, /* bd: Block device: bright yellow */ + { LEN_STR_PAIR ("01;33") }, /* cd: Char device: bright yellow */ + { 0, NULL }, /* mi: Missing file: undefined */ + { 0, NULL }, /* or: Orphanned symlink: undefined */ + { LEN_STR_PAIR ("01;32") }, /* ex: Executable: bright green */ + { LEN_STR_PAIR ("01;35") } /* do: Door: bright magenta */ + }; + +/* FIXME: comment */ +static struct color_ext_type *color_ext_list = NULL; + +/* Buffer for color sequences */ +static char *color_buf; + +/* Nonzero means to check for orphaned symbolic link, for displaying + colors. */ + +static int check_symlink_color; + +/* Nonzero means mention the inode number of each file. -i */ + +static int print_inode; + +/* What to do with symbolic links. Affected by -d, -F, -H, -l (and + other options that imply -l), and -L. */ + +static enum Dereference_symlink dereference; + +/* Nonzero means when a directory is found, display info on its + contents. -R */ + +static int recursive; + +/* Nonzero means when an argument is a directory name, display info + on it itself. -d */ + +static int immediate_dirs; + +/* Nonzero means don't omit files whose names start with `.'. -A */ + +static int all_files; + +/* Nonzero means don't omit files `.' and `..' + This flag implies `all_files'. -a */ + +static int really_all_files; + +/* A linked list of shell-style globbing patterns. If a non-argument + file name matches any of these patterns, it is omitted. + Controlled by -I. Multiple -I options accumulate. + The -B option adds `*~' and `.*~' to this list. */ + +struct ignore_pattern + { + const char *pattern; + struct ignore_pattern *next; + }; + +static struct ignore_pattern *ignore_patterns; + +/* Nonzero means output nongraphic chars in file names as `?'. + (-q, --hide-control-chars) + qmark_funny_chars and the quoting style (-Q, --quoting-style=WORD) are + independent. The algorithm is: first, obey the quoting style to get a + string representing the file name; then, if qmark_funny_chars is set, + replace all nonprintable chars in that string with `?'. It's necessary + to replace nonprintable chars even in quoted strings, because we don't + want to mess up the terminal if control chars get sent to it, and some + quoting methods pass through control chars as-is. */ +static int qmark_funny_chars; + +/* Quoting options for file and dir name output. */ + +static struct quoting_options *filename_quoting_options; +static struct quoting_options *dirname_quoting_options; + +/* The number of chars per hardware tab stop. Setting this to zero + inhibits the use of TAB characters for separating columns. -T */ +static int tabsize; + +/* Nonzero means we are listing the working directory because no + non-option arguments were given. */ + +static int dir_defaulted; + +/* Nonzero means print each directory name before listing it. */ + +static int print_dir_name; + +/* The line length to use for breaking lines in many-per-line format. + Can be set with -w. */ + +static int line_length; + +/* If nonzero, the file listing format requires that stat be called on + each file. */ + +static int format_needs_stat; + +/* Similar to `format_needs_stat', but set if only the file type is + needed. */ + +static int format_needs_type; + +/* strftime formats for non-recent and recent files, respectively, in + -l output. */ + +static char const *long_time_format[2] = + { + /* strftime format for non-recent files (older than 6 months), in + -l output when --time-style=locale is specified. This should + contain the year, month and day (at least), in an order that is + understood by people in your locale's territory. + Please try to keep the number of used screen columns small, + because many people work in windows with only 80 columns. But + make this as wide as the other string below, for recent files. */ + N_("%b %e %Y"), + /* strftime format for recent files (younger than 6 months), in + -l output when --time-style=locale is specified. This should + contain the month, day and time (at least), in an order that is + understood by people in your locale's territory. + Please try to keep the number of used screen columns small, + because many people work in windows with only 80 columns. But + make this as wide as the other string above, for non-recent files. */ + N_("%b %e %H:%M") + }; + +/* The exit status to use if we don't get any fatal errors. */ + +static int exit_status; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + AUTHOR_OPTION = CHAR_MAX + 1, + BLOCK_SIZE_OPTION, + COLOR_OPTION, + DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION, + FORMAT_OPTION, + FULL_TIME_OPTION, + INDICATOR_STYLE_OPTION, + QUOTING_STYLE_OPTION, + SHOW_CONTROL_CHARS_OPTION, + SI_OPTION, + SORT_OPTION, + TIME_OPTION, + TIME_STYLE_OPTION +}; + +static struct option const long_options[] = +{ + {"all", no_argument, 0, 'a'}, + {"escape", no_argument, 0, 'b'}, + {"directory", no_argument, 0, 'd'}, + {"dired", no_argument, 0, 'D'}, + {"full-time", no_argument, 0, FULL_TIME_OPTION}, + {"human-readable", no_argument, 0, 'h'}, + {"inode", no_argument, 0, 'i'}, + {"kilobytes", no_argument, 0, 'k'}, /* long form is obsolescent */ + {"numeric-uid-gid", no_argument, 0, 'n'}, + {"no-group", no_argument, 0, 'G'}, + {"hide-control-chars", no_argument, 0, 'q'}, + {"reverse", no_argument, 0, 'r'}, + {"size", no_argument, 0, 's'}, + {"width", required_argument, 0, 'w'}, + {"almost-all", no_argument, 0, 'A'}, + {"ignore-backups", no_argument, 0, 'B'}, + {"classify", no_argument, 0, 'F'}, + {"file-type", no_argument, 0, 'p'}, + {"si", no_argument, 0, SI_OPTION}, + {"dereference-command-line", no_argument, 0, 'H'}, + {"dereference-command-line-symlink-to-dir", no_argument, 0, + DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION}, + {"ignore", required_argument, 0, 'I'}, + {"indicator-style", required_argument, 0, INDICATOR_STYLE_OPTION}, + {"dereference", no_argument, 0, 'L'}, + {"literal", no_argument, 0, 'N'}, + {"quote-name", no_argument, 0, 'Q'}, + {"quoting-style", required_argument, 0, QUOTING_STYLE_OPTION}, + {"recursive", no_argument, 0, 'R'}, + {"format", required_argument, 0, FORMAT_OPTION}, + {"show-control-chars", no_argument, 0, SHOW_CONTROL_CHARS_OPTION}, + {"sort", required_argument, 0, SORT_OPTION}, + {"tabsize", required_argument, 0, 'T'}, + {"time", required_argument, 0, TIME_OPTION}, + {"time-style", required_argument, 0, TIME_STYLE_OPTION}, + {"color", optional_argument, 0, COLOR_OPTION}, + {"block-size", required_argument, 0, BLOCK_SIZE_OPTION}, + {"author", no_argument, 0, AUTHOR_OPTION}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +static char const *const format_args[] = +{ + "verbose", "long", "commas", "horizontal", "across", + "vertical", "single-column", 0 +}; + +static enum format const format_types[] = +{ + long_format, long_format, with_commas, horizontal, horizontal, + many_per_line, one_per_line +}; + +static char const *const sort_args[] = +{ + "none", "time", "size", "extension", "version", 0 +}; + +static enum sort_type const sort_types[] = +{ + sort_none, sort_time, sort_size, sort_extension, sort_version +}; + +static char const *const time_args[] = +{ + "atime", "access", "use", "ctime", "status", 0 +}; + +static enum time_type const time_types[] = +{ + time_atime, time_atime, time_atime, time_ctime, time_ctime +}; + +static char const *const color_args[] = +{ + /* force and none are for compatibility with another color-ls version */ + "always", "yes", "force", + "never", "no", "none", + "auto", "tty", "if-tty", 0 +}; + +static enum color_type const color_types[] = +{ + color_always, color_always, color_always, + color_never, color_never, color_never, + color_if_tty, color_if_tty, color_if_tty +}; + +/* Information about filling a column. */ +struct column_info +{ + int valid_len; + int line_len; + int *col_arr; +}; + +/* Array with information about column filledness. */ +static struct column_info *column_info; + +/* Maximum number of columns ever possible for this display. */ +static int max_idx; + +/* The minimum width of a colum is 3: 1 character for the name and 2 + for the separating white space. */ +#define MIN_COLUMN_WIDTH 3 + + +/* This zero-based index is used solely with the --dired option. + When that option is in effect, this counter is incremented for each + character of output generated by this program so that the beginning + and ending indices (in that output) of every file name can be recorded + and later output themselves. */ +static size_t dired_pos; + +#define DIRED_PUTCHAR(c) do {putchar ((c)); ++dired_pos;} while (0) + +/* Write S to STREAM and increment DIRED_POS by S_LEN. */ +#define DIRED_FPUTS(s, stream, s_len) \ + do {fputs ((s), (stream)); dired_pos += s_len;} while (0) + +/* Like DIRED_FPUTS, but for use when S is a literal string. */ +#define DIRED_FPUTS_LITERAL(s, stream) \ + do {fputs ((s), (stream)); dired_pos += sizeof((s)) - 1;} while (0) + +#define DIRED_INDENT() \ + do \ + { \ + if (dired) \ + DIRED_FPUTS_LITERAL (" ", stdout); \ + } \ + while (0) + +/* With --dired, store pairs of beginning and ending indices of filenames. */ +static struct obstack dired_obstack; + +/* With --dired, store pairs of beginning and ending indices of any + directory names that appear as headers (just before `total' line) + for lists of directory entries. Such directory names are seen when + listing hierarchies using -R and when a directory is listed with at + least one other command line argument. */ +static struct obstack subdired_obstack; + +/* Save the current index on the specified obstack, OBS. */ +#define PUSH_CURRENT_DIRED_POS(obs) \ + do \ + { \ + if (dired) \ + obstack_grow ((obs), &dired_pos, sizeof (dired_pos)); \ + } \ + while (0) + +/* With -R, this stack is used to help detect directory cycles. + The device/inode pairs on this stack mirror the pairs in the + active_dir_set hash table. */ +static struct obstack dev_ino_obstack; + +/* Push a pair onto the device/inode stack. */ +#define DEV_INO_PUSH(Dev, Ino) \ + do \ + { \ + struct dev_ino *di; \ + obstack_blank (&dev_ino_obstack, sizeof (struct dev_ino)); \ + di = -1 + (struct dev_ino *) obstack_next_free (&dev_ino_obstack); \ + di->st_dev = (Dev); \ + di->st_ino = (Ino); \ + } \ + while (0) + +/* Pop a dev/ino struct off the global dev_ino_obstack + and return that struct. */ +static struct dev_ino +dev_ino_pop (void) +{ + assert (sizeof (struct dev_ino) <= obstack_object_size (&dev_ino_obstack)); + obstack_blank (&dev_ino_obstack, -(int) (sizeof (struct dev_ino))); + return *(struct dev_ino*) obstack_next_free (&dev_ino_obstack); +} + +#define ASSERT_MATCHING_DEV_INO(Name, Di) \ + do \ + { \ + struct stat sb; \ + assert (Name); \ + assert (0 <= stat (Name, &sb)); \ + assert (sb.st_dev == Di.st_dev); \ + assert (sb.st_ino == Di.st_ino); \ + } \ + while (0) + + +/* Write to standard output PREFIX, followed by the quoting style and + a space-separated list of the integers stored in OS all on one line. */ + +static void +dired_dump_obstack (const char *prefix, struct obstack *os) +{ + int n_pos; + + n_pos = obstack_object_size (os) / sizeof (dired_pos); + if (n_pos > 0) + { + int i; + size_t *pos; + + pos = (size_t *) obstack_finish (os); + fputs (prefix, stdout); + for (i = 0; i < n_pos; i++) + printf (" %lu", (unsigned long) pos[i]); + putchar ('\n'); + } +} + +static unsigned int +dev_ino_hash (void const *x, unsigned int table_size) +{ + struct dev_ino const *p = x; + return (uintmax_t) p->st_ino % table_size; +} + +static bool +dev_ino_compare (void const *x, void const *y) +{ + struct dev_ino const *a = x; + struct dev_ino const *b = y; + return SAME_INODE (*a, *b) ? true : false; +} + +static void +dev_ino_free (void *x) +{ + free (x); +} + +/* Add the device/inode pair (P->st_dev/P->st_ino) to the set of + active directories. Return nonzero if there is already a matching + entry in the table. Otherwise, return zero. */ + +static int +visit_dir (dev_t dev, ino_t ino) +{ + struct dev_ino *ent; + struct dev_ino *ent_from_table; + int found_match; + + ent = XMALLOC (struct dev_ino, 1); + ent->st_ino = ino; + ent->st_dev = dev; + + /* Attempt to insert this entry into the table. */ + ent_from_table = hash_insert (active_dir_set, ent); + + if (ent_from_table == NULL) + { + /* Insertion failed due to lack of memory. */ + xalloc_die (); + } + + found_match = (ent_from_table != ent); + + if (found_match) + { + /* ent was not inserted, so free it. */ + free (ent); + } + + return found_match; +} + +static void +free_pending_ent (struct pending *p) +{ + if (p->name) + free (p->name); + if (p->realname) + free (p->realname); + free (p); +} + +static void +restore_default_color (void) +{ + if (put_indicator_direct (&color_indicator[C_LEFT]) == 0) + put_indicator_direct (&color_indicator[C_RIGHT]); +} + +/* Upon interrupt, suspend, hangup, etc. ensure that the + terminal text color is restored to the default. */ +static void +sighandler (int sig) +{ +#ifndef SA_NOCLDSTOP + signal (sig, SIG_IGN); +#endif + + restore_default_color (); + + /* SIGTSTP is special, since the application can receive that signal more + than once. In this case, don't set the signal handler to the default. + Instead, just raise the uncatchable SIGSTOP. */ + if (sig == SIGTSTP) + { + sig = SIGSTOP; + } + else + { +#ifdef SA_NOCLDSTOP + struct sigaction sigact; + + sigact.sa_handler = SIG_DFL; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (sig, &sigact, NULL); +#else + signal (sig, SIG_DFL); +#endif + } + + raise (sig); +} + +int +main (int argc, char **argv) +{ + register int i; + register struct pending *thispend; + unsigned int n_files; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + +#define N_ENTRIES(Array) (sizeof Array / sizeof *(Array)) + assert (N_ENTRIES (color_indicator) + 1 == N_ENTRIES (indicator_name)); + + exit_status = 0; + dir_defaulted = 1; + print_dir_name = 1; + pending_dirs = 0; + + i = decode_switches (argc, argv); + + if (print_with_color) + parse_ls_color (); + + /* Test print_with_color again, because the call to parse_ls_color + may have just reset it -- e.g., if LS_COLORS is invalid. */ + if (print_with_color) + { + prep_non_filename_text (); + /* Avoid following symbolic links when possible. */ + if (color_indicator[C_ORPHAN].string != NULL + || (color_indicator[C_MISSING].string != NULL + && format == long_format)) + check_symlink_color = 1; + + { + unsigned j; + static int const sigs[] = { SIGHUP, SIGINT, SIGPIPE, + SIGQUIT, SIGTERM, SIGTSTP }; + unsigned nsigs = sizeof sigs / sizeof *sigs; +#ifdef SA_NOCLDSTOP + struct sigaction oldact, newact; + sigset_t caught_signals; + + sigemptyset (&caught_signals); + for (j = 0; j < nsigs; j++) + sigaddset (&caught_signals, sigs[j]); + newact.sa_handler = sighandler; + newact.sa_mask = caught_signals; + newact.sa_flags = 0; +#endif + + for (j = 0; j < nsigs; j++) + { + int sig = sigs[j]; +#ifdef SA_NOCLDSTOP + sigaction (sig, NULL, &oldact); + if (oldact.sa_handler != SIG_IGN) + sigaction (sig, &newact, NULL); +#else + if (signal (sig, SIG_IGN) != SIG_IGN) + signal (sig, sighandler); +#endif + } + } + } + + if (dereference == DEREF_UNDEFINED) + dereference = ((immediate_dirs + || indicator_style == classify + || format == long_format) + ? DEREF_NEVER + : DEREF_COMMAND_LINE_SYMLINK_TO_DIR); + + /* When using -R, initialize a data structure we'll use to + detect any directory cycles. */ + if (recursive) + { + active_dir_set = hash_initialize (INITIAL_TABLE_SIZE, NULL, + dev_ino_hash, + dev_ino_compare, + dev_ino_free); + if (active_dir_set == NULL) + xalloc_die (); + + obstack_init (&dev_ino_obstack); + } + + format_needs_stat = sort_type == sort_time || sort_type == sort_size + || format == long_format + || dereference == DEREF_ALWAYS + || print_block_size || print_inode; + format_needs_type = (format_needs_stat == 0 + && (recursive || print_with_color + || indicator_style != none)); + + if (dired) + { + obstack_init (&dired_obstack); + obstack_init (&subdired_obstack); + } + + nfiles = 100; + files = XMALLOC (struct fileinfo, nfiles); + files_index = 0; + + clear_files (); + + n_files = argc - i; + if (0 < n_files) + dir_defaulted = 0; + + for (; i < argc; i++) + { + gobble_file (argv[i], unknown, 1, ""); + } + + if (dir_defaulted) + { + if (immediate_dirs) + gobble_file (".", directory, 1, ""); + else + queue_directory (".", 0); + } + + if (files_index) + { + sort_files (); + if (!immediate_dirs) + extract_dirs_from_files ("", 0); + /* `files_index' might be zero now. */ + } + + /* In the following if/else blocks, it is sufficient to test `pending_dirs' + (and not pending_dirs->name) because there may be no markers in the queue + at this point. A marker may be enqueued when extract_dirs_from_files is + called with a non-empty string or via print_dir. */ + if (files_index) + { + print_current_files (); + if (pending_dirs) + DIRED_PUTCHAR ('\n'); + } + else if (n_files <= 1 && pending_dirs && pending_dirs->next == 0) + print_dir_name = 0; + + while (pending_dirs) + { + thispend = pending_dirs; + pending_dirs = pending_dirs->next; + + if (LOOP_DETECT) + { + if (thispend->name == NULL) + { + /* thispend->name == NULL means this is a marker entry + indicating we've finished processing the directory. + Use its dev/ino numbers to remove the corresponding + entry from the active_dir_set hash table. */ + struct dev_ino di = dev_ino_pop (); + struct dev_ino *found = hash_delete (active_dir_set, &di); + /* ASSERT_MATCHING_DEV_INO (thispend->realname, di); */ + assert (found); + dev_ino_free (found); + free_pending_ent (thispend); + continue; + } + } + + print_dir (thispend->name, thispend->realname); + + free_pending_ent (thispend); + print_dir_name = 1; + } + + if (dired) + { + /* No need to free these since we're about to exit. */ + dired_dump_obstack ("//DIRED//", &dired_obstack); + dired_dump_obstack ("//SUBDIRED//", &subdired_obstack); + printf ("//DIRED-OPTIONS// --quoting-style=%s\n", + quoting_style_args[get_quoting_style (filename_quoting_options)]); + } + + /* Restore default color before exiting */ + if (print_with_color) + { + put_indicator (&color_indicator[C_LEFT]); + put_indicator (&color_indicator[C_RIGHT]); + } + + if (LOOP_DETECT) + { + assert (hash_get_n_entries (active_dir_set) == 0); + hash_free (active_dir_set); + } + + exit (exit_status); +} + +/* Set all the option flags according to the switches specified. + Return the index of the first non-option argument. */ + +static int +decode_switches (int argc, char **argv) +{ + int c; + char *time_style_option = 0; + + /* Record whether there is an option specifying sort type. */ + int sort_type_specified = 0; + + qmark_funny_chars = 0; + + /* initialize all switches to default settings */ + + switch (ls_mode) + { + case LS_MULTI_COL: + /* This is for the `dir' program. */ + format = many_per_line; + set_quoting_style (NULL, escape_quoting_style); + break; + + case LS_LONG_FORMAT: + /* This is for the `vdir' program. */ + format = long_format; + set_quoting_style (NULL, escape_quoting_style); + break; + + case LS_LS: + /* This is for the `ls' program. */ + if (isatty (STDOUT_FILENO)) + { + format = many_per_line; + /* See description of qmark_funny_chars, above. */ + qmark_funny_chars = 1; + } + else + { + format = one_per_line; + qmark_funny_chars = 0; + } + break; + + default: + abort (); + } + + time_type = time_mtime; + sort_type = sort_name; + sort_reverse = 0; + numeric_ids = 0; + print_block_size = 0; + indicator_style = none; + print_inode = 0; + dereference = DEREF_UNDEFINED; + recursive = 0; + immediate_dirs = 0; + all_files = 0; + really_all_files = 0; + ignore_patterns = 0; + + /* FIXME: put this in a function. */ + { + char const *q_style = getenv ("QUOTING_STYLE"); + if (q_style) + { + int i = ARGMATCH (q_style, quoting_style_args, quoting_style_vals); + if (0 <= i) + set_quoting_style (NULL, quoting_style_vals[i]); + else + error (0, 0, + _("ignoring invalid value of environment variable QUOTING_STYLE: %s"), + quotearg (q_style)); + } + } + + { + char const *ls_block_size = getenv ("LS_BLOCK_SIZE"); + human_output_opts = human_options (ls_block_size, false, + &output_block_size); + if (ls_block_size || getenv ("BLOCK_SIZE")) + file_output_block_size = output_block_size; + } + + line_length = 80; + { + char const *p = getenv ("COLUMNS"); + if (p && *p) + { + long int tmp_long; + if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK + && 0 < tmp_long && tmp_long <= INT_MAX) + { + line_length = (int) tmp_long; + } + else + { + error (0, 0, + _("ignoring invalid width in environment variable COLUMNS: %s"), + quotearg (p)); + } + } + } + +#ifdef TIOCGWINSZ + { + struct winsize ws; + + if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0) + line_length = ws.ws_col; + } +#endif + + /* Using the TABSIZE environment variable is not POSIX-approved. + Ignore it when POSIXLY_CORRECT is set. */ + { + char const *p; + tabsize = 8; + if (!getenv ("POSIXLY_CORRECT") && (p = getenv ("TABSIZE"))) + { + long int tmp_long; + if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK + && 0 <= tmp_long && tmp_long <= INT_MAX) + { + tabsize = (int) tmp_long; + } + else + { + error (0, 0, + _("ignoring invalid tab size in environment variable TABSIZE: %s"), + quotearg (p)); + } + } + } + + while ((c = getopt_long (argc, argv, + "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1", + long_options, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + case 'a': + all_files = 1; + really_all_files = 1; + break; + + case 'b': + set_quoting_style (NULL, escape_quoting_style); + break; + + case 'c': + time_type = time_ctime; + break; + + case 'd': + immediate_dirs = 1; + break; + + case 'f': + /* Same as enabling -a -U and disabling -l -s. */ + all_files = 1; + really_all_files = 1; + sort_type = sort_none; + sort_type_specified = 1; + /* disable -l */ + if (format == long_format) + format = (isatty (STDOUT_FILENO) ? many_per_line : one_per_line); + print_block_size = 0; /* disable -s */ + print_with_color = 0; /* disable --color */ + break; + + case 'g': + format = long_format; + print_owner = 0; + break; + + case 'h': + human_output_opts = human_autoscale | human_SI | human_base_1024; + file_output_block_size = output_block_size = 1; + break; + + case 'i': + print_inode = 1; + break; + + case 'k': + human_output_opts = 0; + file_output_block_size = output_block_size = 1024; + break; + + case 'l': + format = long_format; + break; + + case 'm': + format = with_commas; + break; + + case 'n': + numeric_ids = 1; + format = long_format; + break; + + case 'o': /* Just like -l, but don't display group info. */ + format = long_format; + print_group = 0; + break; + + case 'p': + indicator_style = file_type; + break; + + case 'q': + qmark_funny_chars = 1; + break; + + case 'r': + sort_reverse = 1; + break; + + case 's': + print_block_size = 1; + break; + + case 't': + sort_type = sort_time; + sort_type_specified = 1; + break; + + case 'u': + time_type = time_atime; + break; + + case 'v': + sort_type = sort_version; + sort_type_specified = 1; + break; + + case 'w': + { + long int tmp_long; + if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK + || tmp_long <= 0 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, _("invalid line width: %s"), + quotearg (optarg)); + line_length = (int) tmp_long; + break; + } + + case 'x': + format = horizontal; + break; + + case 'A': + really_all_files = 0; + all_files = 1; + break; + + case 'B': + add_ignore_pattern ("*~"); + add_ignore_pattern (".*~"); + break; + + case 'C': + format = many_per_line; + break; + + case 'D': + dired = 1; + break; + + case 'F': + indicator_style = classify; + break; + + case 'G': /* inhibit display of group info */ + print_group = 0; + break; + + case 'H': + dereference = DEREF_COMMAND_LINE_ARGUMENTS; + break; + + case DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION: + dereference = DEREF_COMMAND_LINE_SYMLINK_TO_DIR; + break; + + case 'I': + add_ignore_pattern (optarg); + break; + + case 'L': + dereference = DEREF_ALWAYS; + break; + + case 'N': + set_quoting_style (NULL, literal_quoting_style); + break; + + case 'Q': + set_quoting_style (NULL, c_quoting_style); + break; + + case 'R': + recursive = 1; + break; + + case 'S': + sort_type = sort_size; + sort_type_specified = 1; + break; + + case 'T': + { + long int tmp_long; + if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK + || tmp_long < 0 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, _("invalid tab size: %s"), + quotearg (optarg)); + tabsize = (int) tmp_long; + break; + } + + case 'U': + sort_type = sort_none; + sort_type_specified = 1; + break; + + case 'X': + sort_type = sort_extension; + sort_type_specified = 1; + break; + + case '1': + /* -1 has no effect after -l. */ + if (format != long_format) + format = one_per_line; + break; + + case AUTHOR_OPTION: + print_author = true; + break; + + case SORT_OPTION: + sort_type = XARGMATCH ("--sort", optarg, sort_args, sort_types); + sort_type_specified = 1; + break; + + case TIME_OPTION: + time_type = XARGMATCH ("--time", optarg, time_args, time_types); + break; + + case FORMAT_OPTION: + format = XARGMATCH ("--format", optarg, format_args, format_types); + break; + + case FULL_TIME_OPTION: + format = long_format; + time_style_option = "full-iso"; + break; + + case COLOR_OPTION: + { + int i; + if (optarg) + i = XARGMATCH ("--color", optarg, color_args, color_types); + else + /* Using --color with no argument is equivalent to using + --color=always. */ + i = color_always; + + print_with_color = (i == color_always + || (i == color_if_tty + && isatty (STDOUT_FILENO))); + + if (print_with_color) + { + /* Don't use TAB characters in output. Some terminal + emulators can't handle the combination of tabs and + color codes on the same line. */ + tabsize = 0; + } + break; + } + + case INDICATOR_STYLE_OPTION: + indicator_style = XARGMATCH ("--indicator-style", optarg, + indicator_style_args, + indicator_style_types); + break; + + case QUOTING_STYLE_OPTION: + set_quoting_style (NULL, + XARGMATCH ("--quoting-style", optarg, + quoting_style_args, + quoting_style_vals)); + break; + + case TIME_STYLE_OPTION: + time_style_option = optarg; + break; + + case SHOW_CONTROL_CHARS_OPTION: + qmark_funny_chars = 0; + break; + + case BLOCK_SIZE_OPTION: + human_output_opts = human_options (optarg, true, &output_block_size); + file_output_block_size = output_block_size; + break; + + case SI_OPTION: + human_output_opts = human_autoscale | human_SI; + file_output_block_size = output_block_size = 1; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + filename_quoting_options = clone_quoting_options (NULL); + if (get_quoting_style (filename_quoting_options) == escape_quoting_style) + set_char_quoting (filename_quoting_options, ' ', 1); + if (indicator_style != none) + { + char const *p; + for (p = "*=@|" + (int) indicator_style - 1; *p; p++) + set_char_quoting (filename_quoting_options, *p, 1); + } + + dirname_quoting_options = clone_quoting_options (NULL); + set_char_quoting (dirname_quoting_options, ':', 1); + + /* --dired is meaningful only with --format=long (-l). + Otherwise, ignore it. FIXME: warn about this? + Alternatively, make --dired imply --format=long? */ + if (dired && format != long_format) + dired = 0; + + /* If -c or -u is specified and not -l (or any other option that implies -l), + and no sort-type was specified, then sort by the ctime (-c) or atime (-u). + The behavior of ls when using either -c or -u but with neither -l nor -t + appears to be unspecified by POSIX. So, with GNU ls, `-u' alone means + sort by atime (this is the one that's not specified by the POSIX spec), + -lu means show atime and sort by name, -lut means show atime and sort + by atime. */ + + if ((time_type == time_ctime || time_type == time_atime) + && !sort_type_specified && format != long_format) + { + sort_type = sort_time; + } + + if (format == long_format) + { + char *style = time_style_option; + static char const posix_prefix[] = "posix-"; + + if (! style) + if (! (style = getenv ("TIME_STYLE"))) + style = "posix-long-iso"; + + while (strncmp (style, posix_prefix, sizeof posix_prefix - 1) == 0) + { + if (! hard_locale (LC_TIME)) + return optind; + style += sizeof posix_prefix - 1; + } + + if (*style == '+') + { + char *p0 = style + 1; + char *p1 = strchr (p0, '\n'); + if (! p1) + p1 = p0; + else + { + if (strchr (p1 + 1, '\n')) + error (EXIT_FAILURE, 0, _("invalid time style format %s"), + quote (p0)); + *p1++ = '\0'; + } + long_time_format[0] = p0; + long_time_format[1] = p1; + } + else + switch (XARGMATCH ("time style", style, + time_style_args, + time_style_types)) + { + case full_iso_time_style: + long_time_format[0] = long_time_format[1] = + "%Y-%m-%d %H:%M:%S.%N %z"; + break; + + case long_iso_time_style: + long_time_format[0] = long_time_format[1] = "%Y-%m-%d %H:%M"; + break; + + case iso_time_style: + long_time_format[0] = "%Y-%m-%d "; + long_time_format[1] = "%m-%d %H:%M"; + break; + + case locale_time_style: + if (hard_locale (LC_TIME)) + { + unsigned int i; + for (i = 0; i < 2; i++) + long_time_format[i] = + dcgettext (NULL, long_time_format[i], LC_TIME); + } + } + } + + return optind; +} + +/* Parse a string as part of the LS_COLORS variable; this may involve + decoding all kinds of escape characters. If equals_end is set an + unescaped equal sign ends the string, otherwise only a : or \0 + does. Returns the number of characters output, or -1 on failure. + + The resulting string is *not* null-terminated, but may contain + embedded nulls. + + Note that both dest and src are char **; on return they point to + the first free byte after the array and the character that ended + the input string, respectively. */ + +static int +get_funky_string (char **dest, const char **src, int equals_end) +{ + int num; /* For numerical codes */ + int count; /* Something to count with */ + enum { + ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR + } state; + const char *p; + char *q; + + p = *src; /* We don't want to double-indirect */ + q = *dest; /* the whole darn time. */ + + count = 0; /* No characters counted in yet. */ + num = 0; + + state = ST_GND; /* Start in ground state. */ + while (state < ST_END) + { + switch (state) + { + case ST_GND: /* Ground state (no escapes) */ + switch (*p) + { + case ':': + case '\0': + state = ST_END; /* End of string */ + break; + case '\\': + state = ST_BACKSLASH; /* Backslash scape sequence */ + ++p; + break; + case '^': + state = ST_CARET; /* Caret escape */ + ++p; + break; + case '=': + if (equals_end) + { + state = ST_END; /* End */ + break; + } + /* else fall through */ + default: + *(q++) = *(p++); + ++count; + break; + } + break; + + case ST_BACKSLASH: /* Backslash escaped character */ + switch (*p) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + state = ST_OCTAL; /* Octal sequence */ + num = *p - '0'; + break; + case 'x': + case 'X': + state = ST_HEX; /* Hex sequence */ + num = 0; + break; + case 'a': /* Bell */ + num = 7; /* Not all C compilers know what \a means */ + break; + case 'b': /* Backspace */ + num = '\b'; + break; + case 'e': /* Escape */ + num = 27; + break; + case 'f': /* Form feed */ + num = '\f'; + break; + case 'n': /* Newline */ + num = '\n'; + break; + case 'r': /* Carriage return */ + num = '\r'; + break; + case 't': /* Tab */ + num = '\t'; + break; + case 'v': /* Vtab */ + num = '\v'; + break; + case '?': /* Delete */ + num = 127; + break; + case '_': /* Space */ + num = ' '; + break; + case '\0': /* End of string */ + state = ST_ERROR; /* Error! */ + break; + default: /* Escaped character like \ ^ : = */ + num = *p; + break; + } + if (state == ST_BACKSLASH) + { + *(q++) = num; + ++count; + state = ST_GND; + } + ++p; + break; + + case ST_OCTAL: /* Octal sequence */ + if (*p < '0' || *p > '7') + { + *(q++) = num; + ++count; + state = ST_GND; + } + else + num = (num << 3) + (*(p++) - '0'); + break; + + case ST_HEX: /* Hex sequence */ + switch (*p) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + num = (num << 4) + (*(p++) - '0'); + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + num = (num << 4) + (*(p++) - 'a') + 10; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + num = (num << 4) + (*(p++) - 'A') + 10; + break; + default: + *(q++) = num; + ++count; + state = ST_GND; + break; + } + break; + + case ST_CARET: /* Caret escape */ + state = ST_GND; /* Should be the next state... */ + if (*p >= '@' && *p <= '~') + { + *(q++) = *(p++) & 037; + ++count; + } + else if (*p == '?') + { + *(q++) = 127; + ++count; + } + else + state = ST_ERROR; + break; + + default: + abort (); + } + } + + *dest = q; + *src = p; + + return state == ST_ERROR ? -1 : count; +} + +static void +parse_ls_color (void) +{ + const char *p; /* Pointer to character being parsed */ + char *buf; /* color_buf buffer pointer */ + int state; /* State of parser */ + int ind_no; /* Indicator number */ + char label[3]; /* Indicator label */ + struct color_ext_type *ext; /* Extension we are working on */ + + if ((p = getenv ("LS_COLORS")) == NULL || *p == '\0') + return; + + ext = NULL; + strcpy (label, "??"); + + /* This is an overly conservative estimate, but any possible + LS_COLORS string will *not* generate a color_buf longer than + itself, so it is a safe way of allocating a buffer in + advance. */ + buf = color_buf = xstrdup (p); + + state = 1; + while (state > 0) + { + switch (state) + { + case 1: /* First label character */ + switch (*p) + { + case ':': + ++p; + break; + + case '*': + /* Allocate new extension block and add to head of + linked list (this way a later definition will + override an earlier one, which can be useful for + having terminal-specific defs override global). */ + + ext = XMALLOC (struct color_ext_type, 1); + ext->next = color_ext_list; + color_ext_list = ext; + + ++p; + ext->ext.string = buf; + + state = (ext->ext.len = + get_funky_string (&buf, &p, 1)) < 0 ? -1 : 4; + break; + + case '\0': + state = 0; /* Done! */ + break; + + default: /* Assume it is file type label */ + label[0] = *(p++); + state = 2; + break; + } + break; + + case 2: /* Second label character */ + if (*p) + { + label[1] = *(p++); + state = 3; + } + else + state = -1; /* Error */ + break; + + case 3: /* Equal sign after indicator label */ + state = -1; /* Assume failure... */ + if (*(p++) == '=')/* It *should* be... */ + { + for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no) + { + if (STREQ (label, indicator_name[ind_no])) + { + color_indicator[ind_no].string = buf; + state = ((color_indicator[ind_no].len = + get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1); + break; + } + } + if (state == -1) + error (0, 0, _("unrecognized prefix: %s"), quotearg (label)); + } + break; + + case 4: /* Equal sign after *.ext */ + if (*(p++) == '=') + { + ext->seq.string = buf; + state = (ext->seq.len = + get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1; + } + else + state = -1; + break; + } + } + + if (state < 0) + { + struct color_ext_type *e; + struct color_ext_type *e2; + + error (0, 0, + _("unparsable value for LS_COLORS environment variable")); + free (color_buf); + for (e = color_ext_list; e != NULL; /* empty */) + { + e2 = e; + e = e->next; + free (e2); + } + print_with_color = 0; + } + + if (color_indicator[C_LINK].len == 6 + && !strncmp (color_indicator[C_LINK].string, "target", 6)) + color_symlink_as_referent = 1; +} + +/* Request that the directory named NAME have its contents listed later. + If REALNAME is nonzero, it will be used instead of NAME when the + directory name is printed. This allows symbolic links to directories + to be treated as regular directories but still be listed under their + real names. NAME == NULL is used to insert a marker entry for the + directory named in REALNAME. + If F is non-NULL, we use its dev/ino information to save + a call to stat -- when doing a recursive (-R) traversal. */ + +static void +queue_directory (const char *name, const char *realname) +{ + struct pending *new; + + new = XMALLOC (struct pending, 1); + new->realname = realname ? xstrdup (realname) : NULL; + new->name = name ? xstrdup (name) : NULL; + new->next = pending_dirs; + pending_dirs = new; +} + +/* Read directory `name', and list the files in it. + If `realname' is nonzero, print its name instead of `name'; + this is used for symbolic links to directories. */ + +static void +print_dir (const char *name, const char *realname) +{ + register DIR *dirp; + register struct dirent *next; + register uintmax_t total_blocks = 0; + static int first = 1; + + errno = 0; + dirp = opendir (name); + if (!dirp) + { + error (0, errno, "%s", quotearg_colon (name)); + exit_status = 1; + return; + } + + if (LOOP_DETECT) + { + struct stat dir_stat; + int fd = dirfd (dirp); + + /* If dirfd failed, endure the overhead of using stat. */ + if ((0 <= fd + ? fstat (fd, &dir_stat) + : stat (name, &dir_stat)) < 0) + { + error (0, errno, _("cannot determine device and inode of %s"), + quotearg_colon (name)); + exit_status = 1; + return; + } + + /* If we've already visited this dev/inode pair, warn that + we've found a loop, and do not process this directory. */ + if (visit_dir (dir_stat.st_dev, dir_stat.st_ino)) + { + error (0, 0, _("not listing already-listed directory: %s"), + quotearg_colon (name)); + return; + } + + DEV_INO_PUSH (dir_stat.st_dev, dir_stat.st_ino); + } + + /* Read the directory entries, and insert the subfiles into the `files' + table. */ + + clear_files (); + + while (1) + { + /* Set errno to zero so we can distinguish between a readdir failure + and when readdir simply finds that there are no more entries. */ + errno = 0; + if ((next = readdir (dirp)) == NULL) + { + if (errno) + { + /* Save/restore errno across closedir call. */ + int e = errno; + closedir (dirp); + errno = e; + + /* Arrange to give a diagnostic after exiting this loop. */ + dirp = NULL; + } + break; + } + + if (file_interesting (next)) + { + enum filetype type = unknown; + +#if HAVE_STRUCT_DIRENT_D_TYPE + if (next->d_type == DT_BLK + || next->d_type == DT_CHR + || next->d_type == DT_DIR + || next->d_type == DT_FIFO + || next->d_type == DT_LNK + || next->d_type == DT_REG + || next->d_type == DT_SOCK) + type = next->d_type; +#endif + total_blocks += gobble_file (next->d_name, type, 0, name); + } + } + + if (dirp == NULL || CLOSEDIR (dirp)) + { + error (0, errno, _("reading directory %s"), quotearg_colon (name)); + exit_status = 1; + /* Don't return; print whatever we got. */ + } + + /* Sort the directory contents. */ + sort_files (); + + /* If any member files are subdirectories, perhaps they should have their + contents listed rather than being mentioned here as files. */ + + if (recursive) + extract_dirs_from_files (name, 1); + + if (recursive || print_dir_name) + { + if (!first) + DIRED_PUTCHAR ('\n'); + first = 0; + DIRED_INDENT (); + PUSH_CURRENT_DIRED_POS (&subdired_obstack); + dired_pos += quote_name (stdout, realname ? realname : name, + dirname_quoting_options, NULL); + PUSH_CURRENT_DIRED_POS (&subdired_obstack); + DIRED_FPUTS_LITERAL (":\n", stdout); + } + + if (format == long_format || print_block_size) + { + const char *p; + char buf[LONGEST_HUMAN_READABLE + 1]; + + DIRED_INDENT (); + p = _("total"); + DIRED_FPUTS (p, stdout, strlen (p)); + DIRED_PUTCHAR (' '); + p = human_readable (total_blocks, buf, human_output_opts, + ST_NBLOCKSIZE, output_block_size); + DIRED_FPUTS (p, stdout, strlen (p)); + DIRED_PUTCHAR ('\n'); + } + + if (files_index) + print_current_files (); +} + +/* Add `pattern' to the list of patterns for which files that match are + not listed. */ + +static void +add_ignore_pattern (const char *pattern) +{ + register struct ignore_pattern *ignore; + + ignore = XMALLOC (struct ignore_pattern, 1); + ignore->pattern = pattern; + /* Add it to the head of the linked list. */ + ignore->next = ignore_patterns; + ignore_patterns = ignore; +} + +/* Return nonzero if the file in `next' should be listed. */ + +static int +file_interesting (const struct dirent *next) +{ + register struct ignore_pattern *ignore; + + for (ignore = ignore_patterns; ignore; ignore = ignore->next) + if (fnmatch (ignore->pattern, next->d_name, FNM_PERIOD) == 0) + return 0; + + if (really_all_files + || next->d_name[0] != '.' + || (all_files + && next->d_name[1] != '\0' + && (next->d_name[1] != '.' || next->d_name[2] != '\0'))) + return 1; + + return 0; +} + +/* Enter and remove entries in the table `files'. */ + +/* Empty the table of files. */ + +static void +clear_files (void) +{ + register int i; + + for (i = 0; i < files_index; i++) + { + free (files[i].name); + if (files[i].linkname) + free (files[i].linkname); + } + + files_index = 0; + block_size_size = 4; +} + +/* Add a file to the current table of files. + Verify that the file exists, and print an error message if it does not. + Return the number of blocks that the file occupies. */ + +static uintmax_t +gobble_file (const char *name, enum filetype type, int explicit_arg, + const char *dirname) +{ + register uintmax_t blocks; + register char *path; + + if (files_index == nfiles) + { + nfiles *= 2; + files = XREALLOC (files, struct fileinfo, nfiles); + } + + files[files_index].linkname = 0; + files[files_index].linkmode = 0; + files[files_index].linkok = 0; + + if (explicit_arg + || format_needs_stat + || (format_needs_type + && (type == unknown + + /* FIXME: remove this disjunct. + I don't think we care about symlinks here, but for now + this won't make a big performance difference. */ + || type == symbolic_link + + /* --indicator-style=classify (aka -F) + requires that we stat each regular file + to see if it's executable. */ + || (type == normal && (indicator_style == classify + /* This is so that --color ends up + highlighting files with the executable + bit set even when options like -F are + not specified. */ + || print_with_color))))) + + { + /* `path' is the absolute pathname of this file. */ + int err; + + if (name[0] == '/' || dirname[0] == 0) + path = (char *) name; + else + { + path = (char *) alloca (strlen (name) + strlen (dirname) + 2); + attach (path, dirname, name); + } + + switch (dereference) + { + case DEREF_ALWAYS: + err = stat (path, &files[files_index].stat); + break; + + case DEREF_COMMAND_LINE_ARGUMENTS: + case DEREF_COMMAND_LINE_SYMLINK_TO_DIR: + if (explicit_arg) + { + int need_lstat; + err = stat (path, &files[files_index].stat); + + if (dereference == DEREF_COMMAND_LINE_ARGUMENTS) + break; + + need_lstat = (err < 0 + ? errno == ENOENT + : ! S_ISDIR (files[files_index].stat.st_mode)); + if (!need_lstat) + break; + + /* stat failed because of ENOENT, maybe indicating a dangling + symlink. Or stat succeeded, PATH does not refer to a + directory, and --dereference-command-line-symlink-to-dir is + in effect. Fall through so that we call lstat instead. */ + } + + default: /* DEREF_NEVER */ + err = lstat (path, &files[files_index].stat); + break; + } + + if (err < 0) + { + error (0, errno, "%s", quotearg_colon (path)); + exit_status = 1; + return 0; + } + +#if HAVE_ACL + if (format == long_format) + { + int n = file_has_acl (path, &files[files_index].stat); + files[files_index].have_acl = (0 < n); + if (n < 0) + error (0, errno, "%s", quotearg_colon (path)); + } +#endif + + if (S_ISLNK (files[files_index].stat.st_mode) + && (format == long_format || check_symlink_color)) + { + char *linkpath; + struct stat linkstats; + + get_link_name (path, &files[files_index]); + linkpath = make_link_path (path, files[files_index].linkname); + + /* Avoid following symbolic links when possible, ie, when + they won't be traced and when no indicator is needed. */ + if (linkpath + && (indicator_style != none || check_symlink_color) + && stat (linkpath, &linkstats) == 0) + { + files[files_index].linkok = 1; + + /* Symbolic links to directories that are mentioned on the + command line are automatically traced if not being + listed as files. */ + if (!explicit_arg || format == long_format + || !S_ISDIR (linkstats.st_mode)) + { + /* Get the linked-to file's mode for the filetype indicator + in long listings. */ + files[files_index].linkmode = linkstats.st_mode; + files[files_index].linkok = 1; + } + } + if (linkpath) + free (linkpath); + } + + if (S_ISLNK (files[files_index].stat.st_mode)) + files[files_index].filetype = symbolic_link; + else if (S_ISDIR (files[files_index].stat.st_mode)) + { + if (explicit_arg && !immediate_dirs) + files[files_index].filetype = arg_directory; + else + files[files_index].filetype = directory; + } + else + files[files_index].filetype = normal; + + blocks = ST_NBLOCKS (files[files_index].stat); + { + char buf[LONGEST_HUMAN_READABLE + 1]; + int len = strlen (human_readable (blocks, buf, human_output_opts, + ST_NBLOCKSIZE, output_block_size)); + if (block_size_size < len) + block_size_size = len < 7 ? len : 7; + } + } + else + { + files[files_index].filetype = type; +#if HAVE_STRUCT_DIRENT_D_TYPE + files[files_index].stat.st_mode = DTTOIF (type); +#endif + blocks = 0; + } + + files[files_index].name = xstrdup (name); + files_index++; + + return blocks; +} + +#ifdef S_ISLNK + +/* Put the name of the file that `filename' is a symbolic link to + into the `linkname' field of `f'. */ + +static void +get_link_name (const char *filename, struct fileinfo *f) +{ + f->linkname = xreadlink (filename); + if (f->linkname == NULL) + { + error (0, errno, _("cannot read symbolic link %s"), + quotearg_colon (filename)); + exit_status = 1; + } +} + +/* If `linkname' is a relative path and `path' contains one or more + leading directories, return `linkname' with those directories + prepended; otherwise, return a copy of `linkname'. + If `linkname' is zero, return zero. */ + +static char * +make_link_path (const char *path, const char *linkname) +{ + char *linkbuf; + size_t bufsiz; + + if (linkname == 0) + return 0; + + if (*linkname == '/') + return xstrdup (linkname); + + /* The link is to a relative path. Prepend any leading path + in `path' to the link name. */ + linkbuf = strrchr (path, '/'); + if (linkbuf == 0) + return xstrdup (linkname); + + bufsiz = linkbuf - path + 1; + linkbuf = xmalloc (bufsiz + strlen (linkname) + 1); + strncpy (linkbuf, path, bufsiz); + strcpy (linkbuf + bufsiz, linkname); + return linkbuf; +} +#endif + +/* Return nonzero if base_name (NAME) ends in `.' or `..' + This is so we don't try to recurse on `././././. ...' */ + +static int +basename_is_dot_or_dotdot (const char *name) +{ + char const *base = base_name (name); + return DOT_OR_DOTDOT (base); +} + +/* Remove any entries from `files' that are for directories, + and queue them to be listed as directories instead. + `dirname' is the prefix to prepend to each dirname + to make it correct relative to ls's working dir. + If IGNORE_DOT_AND_DOT_DOT is nonzero don't treat `.' and `..' as dirs. + This is desirable when processing directories recursively. */ + +static void +extract_dirs_from_files (const char *dirname, int ignore_dot_and_dot_dot) +{ + register int i, j; + + if (*dirname && LOOP_DETECT) + { + /* Insert a marker entry first. When we dequeue this marker entry, + we'll know that DIRNAME has been processed and may be removed + from the set of active directories. */ + queue_directory (NULL, dirname); + } + + /* Queue the directories last one first, because queueing reverses the + order. */ + for (i = files_index - 1; i >= 0; i--) + if ((files[i].filetype == directory || files[i].filetype == arg_directory) + && (!ignore_dot_and_dot_dot + || !basename_is_dot_or_dotdot (files[i].name))) + { + if (files[i].name[0] == '/' || dirname[0] == 0) + { + queue_directory (files[i].name, files[i].linkname); + } + else + { + char *path = path_concat (dirname, files[i].name, NULL); + queue_directory (path, files[i].linkname); + free (path); + } + if (files[i].filetype == arg_directory) + free (files[i].name); + } + + /* Now delete the directories from the table, compacting all the remaining + entries. */ + + for (i = 0, j = 0; i < files_index; i++) + if (files[i].filetype != arg_directory) + files[j++] = files[i]; + files_index = j; +} + +/* Use strcoll to compare strings in this locale. If an error occurs, + report an error and longjmp to failed_strcoll. */ + +static jmp_buf failed_strcoll; + +static int +xstrcoll (char const *a, char const *b) +{ + int diff; + errno = 0; + diff = strcoll (a, b); + if (errno) + { + error (0, errno, _("cannot compare file names %s and %s"), + quote_n (0, a), quote_n (1, b)); + exit_status = 1; + longjmp (failed_strcoll, 1); + } + return diff; +} + +/* Comparison routines for sorting the files. */ + +typedef void const *V; + +static inline int +cmp_ctime (struct fileinfo const *a, struct fileinfo const *b, + int (*cmp) (char const *, char const *)) +{ + int diff = CTIME_CMP (b->stat, a->stat); + return diff ? diff : cmp (a->name, b->name); +} +static int compare_ctime (V a, V b) { return cmp_ctime (a, b, xstrcoll); } +static int compstr_ctime (V a, V b) { return cmp_ctime (a, b, strcmp); } +static int rev_cmp_ctime (V a, V b) { return compare_ctime (b, a); } +static int rev_str_ctime (V a, V b) { return compstr_ctime (b, a); } + +static inline int +cmp_mtime (struct fileinfo const *a, struct fileinfo const *b, + int (*cmp) (char const *, char const *)) +{ + int diff = MTIME_CMP (b->stat, a->stat); + return diff ? diff : cmp (a->name, b->name); +} +static int compare_mtime (V a, V b) { return cmp_mtime (a, b, xstrcoll); } +static int compstr_mtime (V a, V b) { return cmp_mtime (a, b, strcmp); } +static int rev_cmp_mtime (V a, V b) { return compare_mtime (b, a); } +static int rev_str_mtime (V a, V b) { return compstr_mtime (b, a); } + +static inline int +cmp_atime (struct fileinfo const *a, struct fileinfo const *b, + int (*cmp) (char const *, char const *)) +{ + int diff = ATIME_CMP (b->stat, a->stat); + return diff ? diff : cmp (a->name, b->name); +} +static int compare_atime (V a, V b) { return cmp_atime (a, b, xstrcoll); } +static int compstr_atime (V a, V b) { return cmp_atime (a, b, strcmp); } +static int rev_cmp_atime (V a, V b) { return compare_atime (b, a); } +static int rev_str_atime (V a, V b) { return compstr_atime (b, a); } + +static inline int +cmp_size (struct fileinfo const *a, struct fileinfo const *b, + int (*cmp) (char const *, char const *)) +{ + int diff = longdiff (b->stat.st_size, a->stat.st_size); + return diff ? diff : cmp (a->name, b->name); +} +static int compare_size (V a, V b) { return cmp_size (a, b, xstrcoll); } +static int compstr_size (V a, V b) { return cmp_size (a, b, strcmp); } +static int rev_cmp_size (V a, V b) { return compare_size (b, a); } +static int rev_str_size (V a, V b) { return compstr_size (b, a); } + +static inline int +cmp_version (struct fileinfo const *a, struct fileinfo const *b) +{ + return strverscmp (a->name, b->name); +} +static int compare_version (V a, V b) { return cmp_version (a, b); } +static int rev_cmp_version (V a, V b) { return compare_version (b, a); } + +static inline int +cmp_name (struct fileinfo const *a, struct fileinfo const *b, + int (*cmp) (char const *, char const *)) +{ + return cmp (a->name, b->name); +} +static int compare_name (V a, V b) { return cmp_name (a, b, xstrcoll); } +static int compstr_name (V a, V b) { return cmp_name (a, b, strcmp); } +static int rev_cmp_name (V a, V b) { return compare_name (b, a); } +static int rev_str_name (V a, V b) { return compstr_name (b, a); } + +/* Compare file extensions. Files with no extension are `smallest'. + If extensions are the same, compare by filenames instead. */ + +static inline int +cmp_extension (struct fileinfo const *a, struct fileinfo const *b, + int (*cmp) (char const *, char const *)) +{ + char const *base1 = strrchr (a->name, '.'); + char const *base2 = strrchr (b->name, '.'); + int diff = cmp (base1 ? base1 : "", base2 ? base2 : ""); + return diff ? diff : cmp (a->name, b->name); +} +static int compare_extension (V a, V b) { return cmp_extension (a, b, xstrcoll); } +static int compstr_extension (V a, V b) { return cmp_extension (a, b, strcmp); } +static int rev_cmp_extension (V a, V b) { return compare_extension (b, a); } +static int rev_str_extension (V a, V b) { return compstr_extension (b, a); } + +/* Sort the files now in the table. */ + +static void +sort_files (void) +{ + int (*func) (V, V); + + switch (sort_type) + { + case sort_none: + return; + case sort_time: + switch (time_type) + { + case time_ctime: + func = sort_reverse ? rev_cmp_ctime : compare_ctime; + break; + case time_mtime: + func = sort_reverse ? rev_cmp_mtime : compare_mtime; + break; + case time_atime: + func = sort_reverse ? rev_cmp_atime : compare_atime; + break; + default: + abort (); + } + break; + case sort_name: + func = sort_reverse ? rev_cmp_name : compare_name; + break; + case sort_extension: + func = sort_reverse ? rev_cmp_extension : compare_extension; + break; + case sort_size: + func = sort_reverse ? rev_cmp_size : compare_size; + break; + case sort_version: + func = sort_reverse ? rev_cmp_version : compare_version; + break; + default: + abort (); + } + + /* Try strcoll. If it fails, fall back on strcmp. We can't safely + ignore strcoll failures, as a failing strcoll might be a + comparison function that is not a total order, and if we ignored + the failure this might cause qsort to dump core. */ + + if (setjmp (failed_strcoll)) + { + switch (sort_type) + { + case sort_time: + switch (time_type) + { + case time_ctime: + func = sort_reverse ? rev_str_ctime : compstr_ctime; + break; + case time_mtime: + func = sort_reverse ? rev_str_mtime : compstr_mtime; + break; + case time_atime: + func = sort_reverse ? rev_str_atime : compstr_atime; + break; + default: + abort (); + } + break; + case sort_name: + func = sort_reverse ? rev_str_name : compstr_name; + break; + case sort_extension: + func = sort_reverse ? rev_str_extension : compstr_extension; + break; + case sort_size: + func = sort_reverse ? rev_str_size : compstr_size; + break; + default: + abort (); + } + } + + qsort (files, files_index, sizeof (struct fileinfo), func); +} + +/* List all the files now in the table. */ + +static void +print_current_files (void) +{ + register int i; + + switch (format) + { + case one_per_line: + for (i = 0; i < files_index; i++) + { + print_file_name_and_frills (files + i); + putchar ('\n'); + } + break; + + case many_per_line: + init_column_info (); + print_many_per_line (); + break; + + case horizontal: + init_column_info (); + print_horizontal (); + break; + + case with_commas: + print_with_commas (); + break; + + case long_format: + for (i = 0; i < files_index; i++) + { + print_long_format (files + i); + DIRED_PUTCHAR ('\n'); + } + break; + } +} + +/* Return the expected number of columns in a long-format time stamp, + or zero if it cannot be calculated. */ + +static int +long_time_expected_width (void) +{ + static int width = -1; + + if (width < 0) + { + time_t epoch = 0; + struct tm const *tm = localtime (&epoch); + char const *fmt = long_time_format[0]; + char initbuf[100]; + char *buf = initbuf; + size_t bufsize = sizeof initbuf; + size_t len; + + for (;;) + { + *buf = '\1'; + len = nstrftime (buf, bufsize, fmt, tm, 0, 0); + if (len || ! *buf) + break; + buf = alloca (bufsize *= 2); + } + + width = mbsnwidth (buf, len, 0); + if (width < 0) + width = 0; + } + + return width; +} + +/* Get the current time. */ + +static void +get_current_time (void) +{ +#if HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME + { + struct timespec timespec; + if (clock_gettime (CLOCK_REALTIME, ×pec) == 0) + { + current_time = timespec.tv_sec; + current_time_ns = timespec.tv_nsec; + return; + } + } +#endif + + /* The clock does not have nanosecond resolution, so get the maximum + possible value for the current time that is consistent with the + reported clock. That way, files are not considered to be in the + future merely because their time stamps have higher resolution + than the clock resolution. */ + +#if HAVE_GETTIMEOFDAY + { + struct timeval timeval; + if (gettimeofday (&timeval, NULL) == 0) + { + current_time = timeval.tv_sec; + current_time_ns = timeval.tv_usec * 1000 + 999; + return; + } + } +#endif + + current_time = time (NULL); + current_time_ns = 999999999; +} + +/* Format into BUFFER the name or id of the user with id U. Return + the length of the formatted buffer, not counting the terminating + null. */ + +static size_t +format_user (char *buffer, uid_t u) +{ + char const *name = (numeric_ids ? NULL : getuser (u)); + if (name) + sprintf (buffer, "%-8s ", name); + else + sprintf (buffer, "%-8lu ", (unsigned long) u); + return strlen (buffer); +} + +/* Print information about F in long format. */ + +static void +print_long_format (const struct fileinfo *f) +{ + char modebuf[12]; + char init_bigbuf + [LONGEST_HUMAN_READABLE + 1 /* inode */ + + LONGEST_HUMAN_READABLE + 1 /* size in blocks */ + + sizeof (modebuf) - 1 + 1 /* mode string */ + + LONGEST_HUMAN_READABLE + 1 /* st_nlink */ + + ID_LENGTH_MAX + 1 /* owner name */ + + ID_LENGTH_MAX + 1 /* group name */ + + ID_LENGTH_MAX + 1 /* author name */ + + LONGEST_HUMAN_READABLE + 1 /* major device number */ + + LONGEST_HUMAN_READABLE + 1 /* minor device number */ + + 35 + 1 /* usual length of time/date -- may be longer; see below */ + ]; + char *buf = init_bigbuf; + size_t bufsize = sizeof (init_bigbuf); + size_t s; + char *p; + time_t when; + int when_ns IF_LINT (= 0); + struct tm *when_local; + + /* Compute mode string. On most systems, it's based on st_mode. + On systems with migration (via the stat.st_dm_mode field), use + the file's migrated status. */ + mode_string (ST_DM_MODE (f->stat), modebuf); + + modebuf[10] = (FILE_HAS_ACL (f) ? '+' : ' '); + modebuf[11] = '\0'; + + switch (time_type) + { + case time_ctime: + when = f->stat.st_ctime; + when_ns = TIMESPEC_NS (f->stat.st_ctim); + break; + case time_mtime: + when = f->stat.st_mtime; + when_ns = TIMESPEC_NS (f->stat.st_mtim); + break; + case time_atime: + when = f->stat.st_atime; + when_ns = TIMESPEC_NS (f->stat.st_atim); + break; + } + + p = buf; + + if (print_inode) + { + char hbuf[LONGEST_HUMAN_READABLE + 1]; + sprintf (p, "%*s ", INODE_DIGITS, umaxtostr (f->stat.st_ino, hbuf)); + p += strlen (p); + } + + if (print_block_size) + { + char hbuf[LONGEST_HUMAN_READABLE + 1]; + sprintf (p, "%*s ", block_size_size, + human_readable (ST_NBLOCKS (f->stat), hbuf, human_output_opts, + ST_NBLOCKSIZE, output_block_size)); + p += strlen (p); + } + + /* The last byte of the mode string is the POSIX + "optional alternate access method flag". */ + sprintf (p, "%s %3lu ", modebuf, (unsigned long) f->stat.st_nlink); + p += strlen (p); + + if (print_owner) + p += format_user (p, f->stat.st_uid); + + if (print_group) + { + char const *group_name = (numeric_ids ? NULL : getgroup (f->stat.st_gid)); + if (group_name) + sprintf (p, "%-8s ", group_name); + else + sprintf (p, "%-8lu ", (unsigned long) f->stat.st_gid); + p += strlen (p); + } + + if (print_author) + p += format_user (p, f->stat.st_author); + +/* if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)) + sprintf (p, "%3lu, %3lu ", + (unsigned long) major (f->stat.st_rdev), + (unsigned long) minor (f->stat.st_rdev)); + else*/ + { + char hbuf[LONGEST_HUMAN_READABLE + 1]; + uintmax_t size = f->stat.st_size; + + /* POSIX requires that the size be printed without a sign, even + when negative. Assume the typical case where negative sizes + are actually positive values that have wrapped around. */ + size += (f->stat.st_size < 0) * ((uintmax_t) OFF_T_MAX - OFF_T_MIN + 1); + + sprintf (p, "%8s ", + human_readable (size, hbuf, human_output_opts, + 1, file_output_block_size)); + } + + p += strlen (p); + + if ((when_local = localtime (&when))) + { + time_t six_months_ago; + int recent; + char const *fmt; + + /* If the file appears to be in the future, update the current + time, in case the file happens to have been modified since + the last time we checked the clock. */ + if (current_time < when + || (current_time == when && current_time_ns < when_ns)) + { + /* Note that get_current_time calls gettimeofday which, on some non- + compliant systems, clobbers the buffer used for localtime's result. + But it's ok here, because we use a gettimeofday wrapper that + saves and restores the buffer around the gettimeofday call. */ + get_current_time (); + } + + /* Consider a time to be recent if it is within the past six + months. A Gregorian year has 365.2425 * 24 * 60 * 60 == + 31556952 seconds on the average. Write this value as an + integer constant to avoid floating point hassles. */ + six_months_ago = current_time - 31556952 / 2; + recent = (six_months_ago <= when + && (when < current_time + || (when == current_time && when_ns <= current_time_ns))); + fmt = long_time_format[recent]; + + for (;;) + { + char *newbuf; + *p = '\1'; + s = nstrftime (p, buf + bufsize - p - 1, fmt, + when_local, 0, when_ns); + if (s || ! *p) + break; + newbuf = alloca (bufsize *= 2); + memcpy (newbuf, buf, p - buf); + p = newbuf + (p - buf); + buf = newbuf; + } + + p += s; + *p++ = ' '; + + /* NUL-terminate the string -- fputs (via DIRED_FPUTS) requires it. */ + *p = '\0'; + } + else + { + /* The time cannot be represented as a local time; + print it as a huge integer number of seconds. */ + char hbuf[INT_BUFSIZE_BOUND (intmax_t)]; + sprintf (p, "%*s ", long_time_expected_width (), + (TYPE_SIGNED (time_t) + ? imaxtostr (when, hbuf) + : umaxtostr (when, hbuf))); + p += strlen (p); + } + + DIRED_INDENT (); + DIRED_FPUTS (buf, stdout, p - buf); + print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok, + &dired_obstack); + + if (f->filetype == symbolic_link) + { + if (f->linkname) + { + DIRED_FPUTS_LITERAL (" -> ", stdout); + print_name_with_quoting (f->linkname, f->linkmode, f->linkok - 1, + NULL); + if (indicator_style != none) + print_type_indicator (f->linkmode); + } + } + else if (indicator_style != none) + print_type_indicator (f->stat.st_mode); +} + +/* Output to OUT a quoted representation of the file name NAME, + using OPTIONS to control quoting. Produce no output if OUT is NULL. + Store the number of screen columns occupied by NAME's quoted + representation into WIDTH, if non-NULL. Return the number of bytes + produced. */ + +static size_t +quote_name (FILE *out, const char *name, struct quoting_options const *options, + size_t *width) +{ + char smallbuf[BUFSIZ]; + size_t len = quotearg_buffer (smallbuf, sizeof smallbuf, name, -1, options); + char *buf; + size_t displayed_width IF_LINT (= 0); + + if (len < sizeof smallbuf) + buf = smallbuf; + else + { + buf = (char *) alloca (len + 1); + quotearg_buffer (buf, len + 1, name, -1, options); + } + + if (qmark_funny_chars) + { +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1) + { + char const *p = buf; + char const *plimit = buf + len; + char *q = buf; + displayed_width = 0; + + while (p < plimit) + switch (*p) + { + case ' ': case '!': case '"': case '#': case '%': + case '&': case '\'': case '(': case ')': case '*': + case '+': case ',': case '-': case '.': case '/': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case ':': case ';': case '<': case '=': case '>': + case '?': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + case '[': case '\\': case ']': case '^': case '_': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': case '{': case '|': case '}': case '~': + /* These characters are printable ASCII characters. */ + *q++ = *p++; + displayed_width += 1; + break; + default: + /* If we have a multibyte sequence, copy it until we + reach its end, replacing each non-printable multibyte + character with a single question mark. */ + { + mbstate_t mbstate; + memset (&mbstate, 0, sizeof mbstate); + do + { + wchar_t wc; + size_t bytes; + int w; + + bytes = mbrtowc (&wc, p, plimit - p, &mbstate); + + if (bytes == (size_t) -1) + { + /* An invalid multibyte sequence was + encountered. Skip one input byte, and + put a question mark. */ + p++; + *q++ = '?'; + displayed_width += 1; + break; + } + + if (bytes == (size_t) -2) + { + /* An incomplete multibyte character + at the end. Replace it entirely with + a question mark. */ + p = plimit; + *q++ = '?'; + displayed_width += 1; + break; + } + + if (bytes == 0) + /* A null wide character was encountered. */ + bytes = 1; + + w = wcwidth (wc); + if (w >= 0) + { + /* A printable multibyte character. + Keep it. */ + for (; bytes > 0; --bytes) + *q++ = *p++; + displayed_width += w; + } + else + { + /* An unprintable multibyte character. + Replace it entirely with a question + mark. */ + p += bytes; + *q++ = '?'; + displayed_width += 1; + } + } + while (! mbsinit (&mbstate)); + } + break; + } + + /* The buffer may have shrunk. */ + len = q - buf; + } + else +#endif + { + char *p = buf; + char const *plimit = buf + len; + + while (p < plimit) + { + if (! ISPRINT ((unsigned char) *p)) + *p = '?'; + p++; + } + displayed_width = len; + } + } + else if (width != NULL) + { +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1) + displayed_width = mbsnwidth (buf, len, 0); + else +#endif + { + char const *p = buf; + char const *plimit = buf + len; + + displayed_width = 0; + while (p < plimit) + { + if (ISPRINT ((unsigned char) *p)) + displayed_width++; + p++; + } + } + } + + if (out != NULL) + fwrite (buf, 1, len, out); + if (width != NULL) + *width = displayed_width; + return len; +} + +static void +print_name_with_quoting (const char *p, mode_t mode, int linkok, + struct obstack *stack) +{ + if (print_with_color) + print_color_indicator (p, mode, linkok); + + if (stack) + PUSH_CURRENT_DIRED_POS (stack); + + dired_pos += quote_name (stdout, p, filename_quoting_options, NULL); + + if (stack) + PUSH_CURRENT_DIRED_POS (stack); + + if (print_with_color) + prep_non_filename_text (); +} + +static void +prep_non_filename_text (void) +{ + if (color_indicator[C_END].string != NULL) + put_indicator (&color_indicator[C_END]); + else + { + put_indicator (&color_indicator[C_LEFT]); + put_indicator (&color_indicator[C_NORM]); + put_indicator (&color_indicator[C_RIGHT]); + } +} + +/* Print the file name of `f' with appropriate quoting. + Also print file size, inode number, and filetype indicator character, + as requested by switches. */ + +static void +print_file_name_and_frills (const struct fileinfo *f) +{ + char buf[MAX (LONGEST_HUMAN_READABLE + 1, INT_BUFSIZE_BOUND (uintmax_t))]; + + if (print_inode) + printf ("%*s ", INODE_DIGITS, umaxtostr (f->stat.st_ino, buf)); + + if (print_block_size) + printf ("%*s ", block_size_size, + human_readable (ST_NBLOCKS (f->stat), buf, human_output_opts, + ST_NBLOCKSIZE, output_block_size)); + + print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok, NULL); + + if (indicator_style != none) + print_type_indicator (f->stat.st_mode); +} + +static void +print_type_indicator (mode_t mode) +{ + int c; + + if (S_ISREG (mode)) + { + if (indicator_style == classify && (mode & S_IXUGO)) + c ='*'; + else + c = 0; + } + else + { + if (S_ISDIR (mode)) + c = '/'; + else if (S_ISLNK (mode)) + c = '@'; + else if (S_ISFIFO (mode)) + c = '|'; + else if (S_ISSOCK (mode)) + c = '='; + else if (S_ISDOOR (mode)) + c = '>'; + else + c = 0; + } + + if (c) + DIRED_PUTCHAR (c); +} + +static void +print_color_indicator (const char *name, mode_t mode, int linkok) +{ + int type = C_FILE; + struct color_ext_type *ext; /* Color extension */ + size_t len; /* Length of name */ + + /* Is this a nonexistent file? If so, linkok == -1. */ + + if (linkok == -1 && color_indicator[C_MISSING].string != NULL) + { + ext = NULL; + type = C_MISSING; + } + else + { + if (S_ISDIR (mode)) + type = C_DIR; + else if (S_ISLNK (mode)) + type = ((!linkok && color_indicator[C_ORPHAN].string) + ? C_ORPHAN : C_LINK); + else if (S_ISFIFO (mode)) + type = C_FIFO; + else if (S_ISSOCK (mode)) + type = C_SOCK; + else if (S_ISBLK (mode)) + type = C_BLK; + else if (S_ISCHR (mode)) + type = C_CHR; + else if (S_ISDOOR (mode)) + type = C_DOOR; + + if (type == C_FILE && (mode & S_IXUGO) != 0) + type = C_EXEC; + + /* Check the file's suffix only if still classified as C_FILE. */ + ext = NULL; + if (type == C_FILE) + { + /* Test if NAME has a recognized suffix. */ + + len = strlen (name); + name += len; /* Pointer to final \0. */ + for (ext = color_ext_list; ext != NULL; ext = ext->next) + { + if ((size_t) ext->ext.len <= len + && strncmp (name - ext->ext.len, ext->ext.string, + ext->ext.len) == 0) + break; + } + } + } + + put_indicator (&color_indicator[C_LEFT]); + put_indicator (ext ? &(ext->seq) : &color_indicator[type]); + put_indicator (&color_indicator[C_RIGHT]); +} + +/* Output a color indicator (which may contain nulls). */ +static void +put_indicator (const struct bin_str *ind) +{ + register int i; + register const char *p; + + p = ind->string; + + for (i = ind->len; i > 0; --i) + putchar (*(p++)); +} + +/* Output a color indicator, but don't use stdio, for use from signal handlers. + Return zero if the write is successful or if the string length is zero. + Return nonzero if the write fails. */ +static int +put_indicator_direct (const struct bin_str *ind) +{ + size_t len; + if (ind->len <= 0) + return 0; + + len = ind->len; + return (full_write (STDOUT_FILENO, ind->string, len) != len); +} + +static int +length_of_file_name_and_frills (const struct fileinfo *f) +{ + register int len = 0; + size_t name_width; + + if (print_inode) + len += INODE_DIGITS + 1; + + if (print_block_size) + len += 1 + block_size_size; + + quote_name (NULL, f->name, filename_quoting_options, &name_width); + len += name_width; + + if (indicator_style != none) + { + mode_t filetype = f->stat.st_mode; + + if (S_ISREG (filetype)) + { + if (indicator_style == classify + && (f->stat.st_mode & S_IXUGO)) + len += 1; + } + else if (S_ISDIR (filetype) + || S_ISLNK (filetype) + || S_ISFIFO (filetype) + || S_ISSOCK (filetype) + || S_ISDOOR (filetype) + ) + len += 1; + } + + return len; +} + +static void +print_many_per_line (void) +{ + struct column_info *line_fmt; + int filesno; /* Index into files. */ + int row; /* Current row. */ + int max_name_length; /* Length of longest file name + frills. */ + int name_length; /* Length of each file name + frills. */ + int pos; /* Current character column. */ + int cols; /* Number of files across. */ + int rows; /* Maximum number of files down. */ + int max_cols; + + /* Normally the maximum number of columns is determined by the + screen width. But if few files are available this might limit it + as well. */ + max_cols = max_idx > files_index ? files_index : max_idx; + + /* Compute the maximum number of possible columns. */ + for (filesno = 0; filesno < files_index; ++filesno) + { + int i; + + name_length = length_of_file_name_and_frills (files + filesno); + + for (i = 0; i < max_cols; ++i) + { + if (column_info[i].valid_len) + { + int idx = filesno / ((files_index + i) / (i + 1)); + int real_length = name_length + (idx == i ? 0 : 2); + + if (real_length > column_info[i].col_arr[idx]) + { + column_info[i].line_len += (real_length + - column_info[i].col_arr[idx]); + column_info[i].col_arr[idx] = real_length; + column_info[i].valid_len = column_info[i].line_len < line_length; + } + } + } + } + + /* Find maximum allowed columns. */ + for (cols = max_cols; cols > 1; --cols) + { + if (column_info[cols - 1].valid_len) + break; + } + + line_fmt = &column_info[cols - 1]; + + /* Calculate the number of rows that will be in each column except possibly + for a short column on the right. */ + rows = files_index / cols + (files_index % cols != 0); + + for (row = 0; row < rows; row++) + { + int col = 0; + filesno = row; + pos = 0; + /* Print the next row. */ + while (1) + { + print_file_name_and_frills (files + filesno); + name_length = length_of_file_name_and_frills (files + filesno); + max_name_length = line_fmt->col_arr[col++]; + + filesno += rows; + if (filesno >= files_index) + break; + + indent (pos + name_length, pos + max_name_length); + pos += max_name_length; + } + putchar ('\n'); + } +} + +static void +print_horizontal (void) +{ + struct column_info *line_fmt; + int filesno; + int max_name_length; + int name_length; + int cols; + int pos; + int max_cols; + + /* Normally the maximum number of columns is determined by the + screen width. But if few files are available this might limit it + as well. */ + max_cols = max_idx > files_index ? files_index : max_idx; + + /* Compute the maximum file name length. */ + max_name_length = 0; + for (filesno = 0; filesno < files_index; ++filesno) + { + int i; + + name_length = length_of_file_name_and_frills (files + filesno); + + for (i = 0; i < max_cols; ++i) + { + if (column_info[i].valid_len) + { + int idx = filesno % (i + 1); + int real_length = name_length + (idx == i ? 0 : 2); + + if (real_length > column_info[i].col_arr[idx]) + { + column_info[i].line_len += (real_length + - column_info[i].col_arr[idx]); + column_info[i].col_arr[idx] = real_length; + column_info[i].valid_len = column_info[i].line_len < line_length; + } + } + } + } + + /* Find maximum allowed columns. */ + for (cols = max_cols; cols > 1; --cols) + { + if (column_info[cols - 1].valid_len) + break; + } + + line_fmt = &column_info[cols - 1]; + + pos = 0; + + /* Print first entry. */ + print_file_name_and_frills (files); + name_length = length_of_file_name_and_frills (files); + max_name_length = line_fmt->col_arr[0]; + + /* Now the rest. */ + for (filesno = 1; filesno < files_index; ++filesno) + { + int col = filesno % cols; + + if (col == 0) + { + putchar ('\n'); + pos = 0; + } + else + { + indent (pos + name_length, pos + max_name_length); + pos += max_name_length; + } + + print_file_name_and_frills (files + filesno); + + name_length = length_of_file_name_and_frills (files + filesno); + max_name_length = line_fmt->col_arr[col]; + } + putchar ('\n'); +} + +static void +print_with_commas (void) +{ + int filesno; + int pos, old_pos; + + pos = 0; + + for (filesno = 0; filesno < files_index; filesno++) + { + old_pos = pos; + + pos += length_of_file_name_and_frills (files + filesno); + if (filesno + 1 < files_index) + pos += 2; /* For the comma and space */ + + if (old_pos != 0 && pos >= line_length) + { + putchar ('\n'); + pos -= old_pos; + } + + print_file_name_and_frills (files + filesno); + if (filesno + 1 < files_index) + { + putchar (','); + putchar (' '); + } + } + putchar ('\n'); +} + +/* Assuming cursor is at position FROM, indent up to position TO. + Use a TAB character instead of two or more spaces whenever possible. */ + +static void +indent (int from, int to) +{ + while (from < to) + { + if (tabsize > 0 && to / tabsize > (from + 1) / tabsize) + { + putchar ('\t'); + from += tabsize - from % tabsize; + } + else + { + putchar (' '); + from++; + } + } +} + +/* Put DIRNAME/NAME into DEST, handling `.' and `/' properly. */ +/* FIXME: maybe remove this function someday. See about using a + non-malloc'ing version of path_concat. */ + +static void +attach (char *dest, const char *dirname, const char *name) +{ + const char *dirnamep = dirname; + + /* Copy dirname if it is not ".". */ + if (dirname[0] != '.' || dirname[1] != 0) + { + while (*dirnamep) + *dest++ = *dirnamep++; + /* Add '/' if `dirname' doesn't already end with it. */ + if (dirnamep > dirname && dirnamep[-1] != '/') + *dest++ = '/'; + } + while (*name) + *dest++ = *name++; + *dest = 0; +} + +static void +init_column_info (void) +{ + int i; + int allocate = 0; + + max_idx = line_length / MIN_COLUMN_WIDTH; + if (max_idx == 0) + max_idx = 1; + + if (column_info == NULL) + { + column_info = XMALLOC (struct column_info, max_idx); + allocate = 1; + } + + for (i = 0; i < max_idx; ++i) + { + int j; + + column_info[i].valid_len = 1; + column_info[i].line_len = (i + 1) * MIN_COLUMN_WIDTH; + + if (allocate) + column_info[i].col_arr = XMALLOC (int, i + 1); + + for (j = 0; j <= i; ++j) + column_info[i].col_arr[j] = MIN_COLUMN_WIDTH; + } +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); + fputs (_("\ +List information about the FILEs (the current directory by default).\n\ +Sort entries alphabetically if none of -cftuSUX nor --sort.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -a, --all do not hide entries starting with .\n\ + -A, --almost-all do not list implied . and ..\n\ + --author print the author of each file\n\ + -b, --escape print octal escapes for nongraphic characters\n\ +"), stdout); + fputs (_("\ + --block-size=SIZE use SIZE-byte blocks\n\ + -B, --ignore-backups do not list implied entries ending with ~\n\ + -c with -lt: sort by, and show, ctime (time of last\n\ + modification of file status information)\n\ + with -l: show ctime and sort by name\n\ + otherwise: sort by ctime\n\ +"), stdout); + fputs (_("\ + -C list entries by columns\n\ + --color[=WHEN] control whether color is used to distinguish file\n\ + types. WHEN may be `never', `always', or `auto'\n\ + -d, --directory list directory entries instead of contents,\n\ + and do not dereference symbolic links\n\ + -D, --dired generate output designed for Emacs' dired mode\n\ +"), stdout); + fputs (_("\ + -f do not sort, enable -aU, disable -lst\n\ + -F, --classify append indicator (one of */=@|) to entries\n\ + --format=WORD across -x, commas -m, horizontal -x, long -l,\n\ + single-column -1, verbose -l, vertical -C\n\ + --full-time like -l --time-style=full-iso\n\ +"), stdout); + fputs (_("\ + -g like -l, but do not list owner\n\ + -G, --no-group inhibit display of group information\n\ + -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\ + --si likewise, but use powers of 1000 not 1024\n\ + -H, --dereference-command-line\n\ + follow symbolic links listed on the command line\n\ + --dereference-command-line-symlink-to-dir\n\ + follow each command line symbolic link\n\ + that points to a directory\n\ +"), stdout); + fputs (_("\ + --indicator-style=WORD append indicator with style WORD to entry names:\n\ + none (default), classify (-F), file-type (-p)\n\ + -i, --inode print index number of each file\n\ + -I, --ignore=PATTERN do not list implied entries matching shell PATTERN\n\ + -k like --block-size=1K\n\ +"), stdout); + fputs (_("\ + -l use a long listing format\n\ + -L, --dereference when showing file information for a symbolic\n\ + link, show information for the file the link\n\ + references rather than for the link itself\n\ + -m fill width with a comma separated list of entries\n\ +"), stdout); + fputs (_("\ + -n, --numeric-uid-gid like -l, but list numeric UIDs and GIDs\n\ + -N, --literal print raw entry names (don't treat e.g. control\n\ + characters specially)\n\ + -o like -l, but do not list group information\n\ + -p, --file-type append indicator (one of /=@|) to entries\n\ +"), stdout); + fputs (_("\ + -q, --hide-control-chars print ? instead of non graphic characters\n\ + --show-control-chars show non graphic characters as-is (default\n\ + unless program is `ls' and output is a terminal)\n\ + -Q, --quote-name enclose entry names in double quotes\n\ + --quoting-style=WORD use quoting style WORD for entry names:\n\ + literal, locale, shell, shell-always, c, escape\n\ +"), stdout); + fputs (_("\ + -r, --reverse reverse order while sorting\n\ + -R, --recursive list subdirectories recursively\n\ + -s, --size print size of each file, in blocks\n\ +"), stdout); + fputs (_("\ + -S sort by file size\n\ + --sort=WORD extension -X, none -U, size -S, time -t,\n\ + version -v\n\ + status -c, time -t, atime -u, access -u, use -u\n\ + --time=WORD show time as WORD instead of modification time:\n\ + atime, access, use, ctime or status; use\n\ + specified time as sort key if --sort=time\n\ +"), stdout); + fputs (_("\ + --time-style=STYLE show times using style STYLE:\n\ + full-iso, long-iso, iso, locale, +FORMAT\n\ + FORMAT is interpreted like `date'; if FORMAT is\n\ + FORMAT1FORMAT2, FORMAT1 applies to\n\ + non-recent files and FORMAT2 to recent files;\n\ + if STYLE is prefixed with `posix-', STYLE\n\ + takes effect only outside the POSIX locale\n\ + -t sort by modification time\n\ + -T, --tabsize=COLS assume tab stops at each COLS instead of 8\n\ +"), stdout); + fputs (_("\ + -u with -lt: sort by, and show, access time\n\ + with -l: show access time and sort by name\n\ + otherwise: sort by access time\n\ + -U do not sort; list entries in directory order\n\ + -v sort by version\n\ +"), stdout); + fputs (_("\ + -w, --width=COLS assume screen width instead of current value\n\ + -x list entries by lines instead of by columns\n\ + -X sort alphabetically by entry extension\n\ + -1 list one file per line\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\n\ +SIZE may be (or may be an integer optionally followed by) one of following:\n\ +kB 1000, K 1024, MB 1,000,000, M 1,048,576, and so on for G, T, P, E, Z, Y.\n\ +"), stdout); + fputs (_("\ +\n\ +By default, color is not used to distinguish types of files. That is\n\ +equivalent to using --color=none. Using the --color option without the\n\ +optional WHEN argument is equivalent to using --color=always. With\n\ +--color=auto, color codes are output only if standard output is connected\n\ +to a terminal (tty).\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} diff --git a/src/apps/bin/coreutils-5.0/src/ls.h b/src/apps/bin/coreutils-5.0/src/ls.h new file mode 100644 index 0000000000..028271f574 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/ls.h @@ -0,0 +1,10 @@ +/* This is for the `ls' program. */ +#define LS_LS 1 + +/* This is for the `dir' program. */ +#define LS_MULTI_COL 2 + +/* This is for the `vdir' program. */ +#define LS_LONG_FORMAT 3 + +extern int ls_mode; diff --git a/src/apps/bin/coreutils-5.0/src/md5.c b/src/apps/bin/coreutils-5.0/src/md5.c new file mode 100644 index 0000000000..929ab23482 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/md5.c @@ -0,0 +1,7 @@ +#include +#include +#include +#include "system.h" +#include "checksum.h" + +int algorithm = ALG_MD5; diff --git a/src/apps/bin/coreutils-5.0/src/md5sum.c b/src/apps/bin/coreutils-5.0/src/md5sum.c new file mode 100644 index 0000000000..270f0110eb --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/md5sum.c @@ -0,0 +1,684 @@ +/* Compute MD5 or SHA1 checksum of files or strings + Copyright (C) 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Ulrich Drepper . */ + +#include + +#include +#include +#include + +#include "system.h" + +#include "md5.h" +#include "sha.h" +#include "checksum.h" +#include "getline.h" +#include "closeout.h" +#include "error.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME (algorithm == ALG_MD5 ? "md5sum" : "shasum") + +#define AUTHORS N_ ("Ulrich Drepper and Scott Miller") + +/* Most systems do not distinguish between external and internal + text representations. */ +/* FIXME: This begs for an autoconf test. */ +#if O_BINARY +# define OPENOPTS(BINARY) ((BINARY) != 0 ? TEXT1TO1 : TEXTCNVT) +# define TEXT1TO1 "rb" +# define TEXTCNVT "r" +#else +# if defined VMS +# define OPENOPTS(BINARY) ((BINARY) != 0 ? TEXT1TO1 : TEXTCNVT) +# define TEXT1TO1 "rb", "ctx=stm" +# define TEXTCNVT "r", "ctx=stm" +# else +# if UNIX || __UNIX__ || unix || __unix__ || _POSIX_VERSION +# define OPENOPTS(BINARY) "r" +# else + /* The following line is intended to evoke an error. + Using #error is not portable enough. */ + "Cannot determine system type." +# endif +# endif +#endif + + +#define DIGEST_TYPE_STRING(Alg) ((Alg) == ALG_MD5 ? "MD5" : "SHA1") +#define DIGEST_STREAM(Alg) ((Alg) == ALG_MD5 ? md5_stream : sha_stream) + +#define DIGEST_BITS(Alg) ((Alg) == ALG_MD5 ? 128 : 160) +#define DIGEST_HEX_BYTES(Alg) (DIGEST_BITS (Alg) / 4) +#define DIGEST_BIN_BYTES(Alg) (DIGEST_BITS (Alg) / 8) + +#define MAX_DIGEST_BIN_BYTES MAX (DIGEST_BIN_BYTES (ALG_MD5), \ + DIGEST_BIN_BYTES (ALG_SHA1)) + +/* The minimum length of a valid digest line. This length does + not include any newline character at the end of a line. */ +#define MIN_DIGEST_LINE_LENGTH(Alg) \ + (DIGEST_HEX_BYTES (Alg) /* length of hexadecimal message digest */ \ + + 2 /* blank and binary indicator */ \ + + 1 /* minimum filename length */ ) + +/* Nonzero if any of the files read were the standard input. */ +static int have_read_stdin; + +/* The minimum length of a valid checksum line for the selected algorithm. */ +static size_t min_digest_line_length; + +/* Set to the length of a digest hex string for the selected algorithm. */ +static size_t digest_hex_bytes; + +/* With --check, don't generate any output. + The exit code indicates success or failure. */ +static int status_only = 0; + +/* With --check, print a message to standard error warning about each + improperly formatted checksum line. */ +static int warn = 0; + +/* Declared and set via one of the wrapper .c files. */ +/* int algorithm = ALG_UNSPECIFIED; */ + +/* The name this program was run with. */ +char *program_name; + +static const struct option long_options[] = +{ + { "binary", no_argument, 0, 'b' }, + { "check", no_argument, 0, 'c' }, + { "status", no_argument, 0, 2 }, + { "string", required_argument, 0, 1 }, + { "text", no_argument, 0, 't' }, + { "warn", no_argument, 0, 'w' }, + { GETOPT_HELP_OPTION_DECL }, + { GETOPT_VERSION_OPTION_DECL }, + { NULL, 0, NULL, 0 } +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION] [FILE]...\n\ + or: %s [OPTION] --check [FILE]\n\ +Print or check %s (%d-bit) checksums.\n\ +With no FILE, or when FILE is -, read standard input.\n\ +"), + program_name, program_name, + DIGEST_TYPE_STRING (algorithm), + DIGEST_BITS (algorithm)); + printf (_("\ +\n\ + -b, --binary read files in binary mode (default on DOS/Windows)\n\ + -c, --check check %s sums against given list\n\ + -t, --text read files in text mode (default)\n\ +\n\ +"), + DIGEST_TYPE_STRING (algorithm)); + fputs (_("\ +The following two options are useful only when verifying checksums:\n\ + --status don't output anything, status code shows success\n\ + -w, --warn warn about improperly formated checksum lines\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\ +\n\ +The sums are computed as described in %s. When checking, the input\n\ +should be a former output of this program. The default mode is to print\n\ +a line with checksum, a character indicating type (`*' for binary, ` ' for\n\ +text), and name for each FILE.\n"), + (algorithm == ALG_MD5 ? "RFC 1321" : "FIPS-180-1")); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Split the string S (of length S_LEN) into three parts: + a hexadecimal digest, binary flag, and the file name. + S is modified. */ + +static int +split_3 (char *s, size_t s_len, + unsigned char **hex_digest, int *binary, char **file_name) +{ + size_t i; + int escaped_filename = 0; + +#define ISWHITE(c) ((c) == ' ' || (c) == '\t') + + i = 0; + while (ISWHITE (s[i])) + ++i; + + /* Ignore this line if it is too short. + Each line must have at least `min_digest_line_length - 1' (or one more, if + the first is a backslash) more characters to contain correct message digest + information. */ + if (s_len - i < min_digest_line_length + (s[i] == '\\')) + return 1; + + if (s[i] == '\\') + { + ++i; + escaped_filename = 1; + } + *hex_digest = (unsigned char *) &s[i]; + + /* The first field has to be the n-character hexadecimal + representation of the message digest. If it is not followed + immediately by a white space it's an error. */ + i += digest_hex_bytes; + if (!ISWHITE (s[i])) + return 1; + + s[i++] = '\0'; + + if (s[i] != ' ' && s[i] != '*') + return 1; + *binary = (s[i++] == '*'); + + /* All characters between the type indicator and end of line are + significant -- that includes leading and trailing white space. */ + *file_name = &s[i]; + + if (escaped_filename) + { + /* Translate each `\n' string in the file name to a NEWLINE, + and each `\\' string to a backslash. */ + + char *dst = &s[i]; + + while (i < s_len) + { + switch (s[i]) + { + case '\\': + if (i == s_len - 1) + { + /* A valid line does not end with a backslash. */ + return 1; + } + ++i; + switch (s[i++]) + { + case 'n': + *dst++ = '\n'; + break; + case '\\': + *dst++ = '\\'; + break; + default: + /* Only `\' or `n' may follow a backslash. */ + return 1; + } + break; + + case '\0': + /* The file name may not contain a NUL. */ + return 1; + break; + + default: + *dst++ = s[i++]; + break; + } + } + *dst = '\0'; + } + return 0; +} + +static int +hex_digits (unsigned char const *s) +{ + while (*s) + { + if (!ISXDIGIT (*s)) + return 0; + ++s; + } + return 1; +} + +/* An interface to the function, DIGEST_STREAM, + (either md5_stream or sha_stream). + Operate on FILENAME (it may be "-") and put the result in *BIN_RESULT. + Return non-zero upon failure, zero to indicate success. */ + +static int +digest_file (const char *filename, int binary, unsigned char *bin_result, + int (*digest_stream)(FILE *, void *)) +{ + FILE *fp; + int err; + + if (STREQ (filename, "-")) + { + have_read_stdin = 1; + fp = stdin; +#if O_BINARY + /* If we need binary reads from a pipe or redirected stdin, we need + to switch it to BINARY mode here, since stdin is already open. */ + if (binary) + SET_BINARY (fileno (stdin)); +#endif + } + else + { + /* OPENOPTS is a macro. It varies with the system. + Some systems distinguish between internal and + external text representations. */ + + fp = fopen (filename, OPENOPTS (binary)); + if (fp == NULL) + { + error (0, errno, "%s", filename); + return 1; + } + } + + err = (*digest_stream) (fp, bin_result); + if (err) + { + error (0, errno, "%s", filename); + if (fp != stdin) + fclose (fp); + return 1; + } + + if (fp != stdin && fclose (fp) == EOF) + { + error (0, errno, "%s", filename); + return 1; + } + + return 0; +} + +static int +digest_check (const char *checkfile_name, int (*digest_stream)(FILE *, void *)) +{ + FILE *checkfile_stream; + int n_properly_formated_lines = 0; + int n_mismatched_checksums = 0; + int n_open_or_read_failures = 0; + unsigned char bin_buffer[MAX_DIGEST_BIN_BYTES]; + size_t line_number; + char *line; + size_t line_chars_allocated; + + if (STREQ (checkfile_name, "-")) + { + have_read_stdin = 1; + checkfile_name = _("standard input"); + checkfile_stream = stdin; + } + else + { + checkfile_stream = fopen (checkfile_name, "r"); + if (checkfile_stream == NULL) + { + error (0, errno, "%s", checkfile_name); + return 1; + } + } + + SET_MODE (fileno (checkfile_stream), O_TEXT); + line_number = 0; + line = NULL; + line_chars_allocated = 0; + do + { + char *filename; + int binary; + unsigned char *hex_digest; + int err; + int line_length; + + ++line_number; + + line_length = getline (&line, &line_chars_allocated, checkfile_stream); + if (line_length <= 0) + break; + + /* Ignore comment lines, which begin with a '#' character. */ + if (line[0] == '#') + continue; + + /* Remove any trailing newline. */ + if (line[line_length - 1] == '\n') + line[--line_length] = '\0'; + + err = split_3 (line, line_length, &hex_digest, &binary, &filename); + if (err || !hex_digits (hex_digest)) + { + if (warn) + { + error (0, 0, + _("%s: %lu: improperly formatted %s checksum line"), + checkfile_name, (unsigned long) line_number, + DIGEST_TYPE_STRING (algorithm)); + } + } + else + { + static const char bin2hex[] = { '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f' }; + int fail; + + ++n_properly_formated_lines; + + fail = digest_file (filename, binary, bin_buffer, digest_stream); + + if (fail) + { + ++n_open_or_read_failures; + if (!status_only) + { + printf (_("%s: FAILED open or read\n"), filename); + fflush (stdout); + } + } + else + { + size_t digest_bin_bytes = digest_hex_bytes / 2; + size_t cnt; + /* Compare generated binary number with text representation + in check file. Ignore case of hex digits. */ + for (cnt = 0; cnt < digest_bin_bytes; ++cnt) + { + if (TOLOWER (hex_digest[2 * cnt]) + != bin2hex[bin_buffer[cnt] >> 4] + || (TOLOWER (hex_digest[2 * cnt + 1]) + != (bin2hex[bin_buffer[cnt] & 0xf]))) + break; + } + if (cnt != digest_bin_bytes) + ++n_mismatched_checksums; + + if (!status_only) + { + printf ("%s: %s\n", filename, + (cnt != digest_bin_bytes ? _("FAILED") : _("OK"))); + fflush (stdout); + } + } + } + } + while (!feof (checkfile_stream) && !ferror (checkfile_stream)); + + if (line) + free (line); + + if (ferror (checkfile_stream)) + { + error (0, 0, _("%s: read error"), checkfile_name); + return 1; + } + + if (checkfile_stream != stdin && fclose (checkfile_stream) == EOF) + { + error (0, errno, "%s", checkfile_name); + return 1; + } + + if (n_properly_formated_lines == 0) + { + /* Warn if no tests are found. */ + error (0, 0, _("%s: no properly formatted %s checksum lines found"), + checkfile_name, DIGEST_TYPE_STRING (algorithm)); + } + else + { + if (!status_only) + { + int n_computed_checkums = (n_properly_formated_lines + - n_open_or_read_failures); + + if (n_open_or_read_failures > 0) + { + error (0, 0, + _("WARNING: %d of %d listed %s could not be read"), + n_open_or_read_failures, n_properly_formated_lines, + (n_properly_formated_lines == 1 + ? _("file") : _("files"))); + } + + if (n_mismatched_checksums > 0) + { + error (0, 0, + _("WARNING: %d of %d computed %s did NOT match"), + n_mismatched_checksums, n_computed_checkums, + (n_computed_checkums == 1 + ? _("checksum") : _("checksums"))); + } + } + } + + return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0 + && n_open_or_read_failures == 0) ? 0 : 1); +} + +int +main (int argc, char **argv) +{ + unsigned char bin_buffer[MAX_DIGEST_BIN_BYTES]; + int do_check = 0; + int opt; + char **string = NULL; + size_t n_strings = 0; + size_t err = 0; + int file_type_specified = 0; + +#if O_BINARY + /* Binary is default on MSDOS, so the actual file contents + are used in computation. */ + int binary = 1; +#else + /* Text is default of the Plumb/Lankester format. */ + int binary = 0; +#endif + + /* Setting values of global variables. */ + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + while ((opt = getopt_long (argc, argv, "bctw", long_options, NULL)) != -1) + switch (opt) + { + case 0: /* long option */ + break; + case 1: /* --string */ + { + if (string == NULL) + string = (char **) xmalloc ((argc - 1) * sizeof (char *)); + + if (optarg == NULL) + optarg = ""; + string[n_strings++] = optarg; + } + break; + case 'b': + file_type_specified = 1; + binary = 1; + break; + case 'c': + do_check = 1; + break; + case 2: + status_only = 1; + warn = 0; + break; + case 't': + file_type_specified = 1; + binary = 0; + break; + case 'w': + status_only = 0; + warn = 1; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + + min_digest_line_length = MIN_DIGEST_LINE_LENGTH (algorithm); + digest_hex_bytes = DIGEST_HEX_BYTES (algorithm); + + if (file_type_specified && do_check) + { + error (0, 0, _("the --binary and --text options are meaningless when \ +verifying checksums")); + usage (EXIT_FAILURE); + } + + if (n_strings > 0 && do_check) + { + error (0, 0, + _("the --string and --check options are mutually exclusive")); + usage (EXIT_FAILURE); + } + + if (status_only && !do_check) + { + error (0, 0, + _("the --status option is meaningful only when verifying checksums")); + usage (EXIT_FAILURE); + } + + if (warn && !do_check) + { + error (0, 0, + _("the --warn option is meaningful only when verifying checksums")); + usage (EXIT_FAILURE); + } + + if (n_strings > 0) + { + size_t i; + + if (optind < argc) + { + error (0, 0, _("no files may be specified when using --string")); + usage (EXIT_FAILURE); + } + for (i = 0; i < n_strings; ++i) + { + size_t cnt; + if (algorithm == ALG_MD5) + md5_buffer (string[i], strlen (string[i]), bin_buffer); + else + sha_buffer (string[i], strlen (string[i]), bin_buffer); + + for (cnt = 0; cnt < (digest_hex_bytes / 2); ++cnt) + printf ("%02x", bin_buffer[cnt]); + + printf (" \"%s\"\n", string[i]); + } + } + else if (do_check) + { + if (optind + 1 < argc) + { + error (0, 0, + _("only one argument may be specified when using --check")); + usage (EXIT_FAILURE); + } + + err = digest_check ((optind == argc) ? "-" : argv[optind], + DIGEST_STREAM (algorithm)); + } + else + { + if (optind == argc) + argv[argc++] = "-"; + + for (; optind < argc; ++optind) + { + int fail; + char *file = argv[optind]; + + fail = digest_file (file, binary, bin_buffer, + DIGEST_STREAM (algorithm)); + err |= fail; + if (!fail) + { + size_t i; + + /* Output a leading backslash if the file name contains + a newline or backslash. */ + if (strchr (file, '\n') || strchr (file, '\\')) + putchar ('\\'); + + for (i = 0; i < (digest_hex_bytes / 2); ++i) + printf ("%02x", bin_buffer[i]); + + putchar (' '); + if (binary) + putchar ('*'); + else + putchar (' '); + + /* Translate each NEWLINE byte to the string, "\\n", + and each backslash to "\\\\". */ + for (i = 0; i < strlen (file); ++i) + { + switch (file[i]) + { + case '\n': + fputs ("\\n", stdout); + break; + + case '\\': + fputs ("\\\\", stdout); + break; + + default: + putchar (file[i]); + break; + } + } + putchar ('\n'); + } + } + } + + if (have_read_stdin && fclose (stdin) == EOF) + error (EXIT_FAILURE, errno, _("standard input")); + + exit (err == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/mkdir.c b/src/apps/bin/coreutils-5.0/src/mkdir.c new file mode 100644 index 0000000000..382d8027b9 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/mkdir.c @@ -0,0 +1,200 @@ +/* mkdir -- make directories + Copyright (C) 90, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* David MacKenzie */ + +#include +#include +#include +#include + +#include "system.h" +#include "dirname.h" +#include "error.h" +#include "makepath.h" +#include "modechange.h" +#include "quote.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "mkdir" + +#define AUTHORS "David MacKenzie" + +/* The name this program was run with. */ +char *program_name; + +/* If nonzero, ensure that all parents of the specified directory exist. */ +static int create_parents; + +static struct option const longopts[] = +{ + {"mode", required_argument, NULL, 'm'}, + {"parents", no_argument, NULL, 'p'}, + {"verbose", no_argument, NULL, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION] DIRECTORY...\n"), program_name); + fputs (_("\ +Create the DIRECTORY(ies), if they do not already exist.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -m, --mode=MODE set permission mode (as in chmod), not rwxrwxrwx - umask\n\ + -p, --parents no error if existing, make parent directories as needed\n\ + -v, --verbose print a message for each created directory\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + mode_t newmode; + mode_t parent_mode; + const char *specified_mode = NULL; + const char *verbose_fmt_string = NULL; + int errors = 0; + int optc; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + create_parents = 0; + + while ((optc = getopt_long (argc, argv, "pm:v", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: /* Long option. */ + break; + case 'p': + create_parents = 1; + break; + case 'm': + specified_mode = optarg; + break; + case 'v': /* --verbose */ + verbose_fmt_string = _("created directory %s"); + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + } + + if (optind == argc) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + newmode = S_IRWXUGO; + { + mode_t umask_value = umask (0); + umask (umask_value); /* Restore the old value. */ + parent_mode = (newmode & (~ umask_value)) | S_IWUSR | S_IXUSR; + } + + if (specified_mode) + { + struct mode_change *change = mode_compile (specified_mode, 0); + newmode &= ~ umask (0); + if (change == MODE_INVALID) + error (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode)); + else if (change == MODE_MEMORY_EXHAUSTED) + xalloc_die (); + newmode = mode_adjust (newmode, change); + } + + for (; optind < argc; ++optind) + { + int fail = 0; + + if (create_parents) + { + char *dir = argv[optind]; + fail = make_path (dir, newmode, parent_mode, + -1, -1, 1, verbose_fmt_string); + } + else + { + const char *dir = argv[optind]; + int dir_created; + fail = make_dir (dir, dir, newmode, &dir_created); + if (fail) + { + /* make_dir already gave a diagnostic. */ + } + else if (!create_parents && !dir_created) + { + /* make_dir `succeeds' when DIR already exists. + In that case, mkdir must fail, unless --parents (-p) + was specified. */ + error (0, EEXIST, _("cannot create directory %s"), + quote (dir)); + fail = 1; + } + else if (verbose_fmt_string) + error (0, 0, verbose_fmt_string, quote (dir)); + + /* mkdir(2) is required to honor only the file permission bits. + In particular, it needn't do anything about `special' bits, + so if any were set in newmode, apply them with chmod. + This extra step is necessary in some cases when the containing + directory has a default ACL. */ + + /* Set the permissions only if this directory has just + been created. */ + + if (fail == 0 && specified_mode && dir_created) + { + fail = chmod (dir, newmode); + if (fail) + error (0, errno, _("cannot set permissions of directory %s"), + quote (dir)); + } + } + + if (fail) + errors = 1; + } + + exit (errors); +} diff --git a/src/apps/bin/coreutils-5.0/src/mkfifo.c b/src/apps/bin/coreutils-5.0/src/mkfifo.c new file mode 100644 index 0000000000..2fa279e8e7 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/mkfifo.c @@ -0,0 +1,152 @@ +/* mkfifo -- make fifo's (named pipes) + Copyright (C) 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* David MacKenzie */ + +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "modechange.h" +#include "quote.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "mkfifo" + +#define AUTHORS "David MacKenzie" + +/* The name this program was run with. */ +char *program_name; + +static struct option const longopts[] = +{ + {"mode", required_argument, NULL, 'm'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +#ifdef S_ISFIFO +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION] NAME...\n"), program_name); + fputs (_("\ +Create named pipes (FIFOs) with the given NAMEs.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -m, --mode=MODE set permission mode (as in chmod), not a=rw - umask\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} +#endif + +int +main (int argc, char **argv) +{ + mode_t newmode; + struct mode_change *change; + const char *specified_mode; + int errors = 0; + int optc; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + specified_mode = NULL; + +#ifndef S_ISFIFO + error (4, 0, _("fifo files not supported")); +#else + while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + case 'm': + specified_mode = optarg; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + } + + if (optind == argc) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (specified_mode) + { + newmode &= ~ umask (0); + change = mode_compile (specified_mode, 0); + if (change == MODE_INVALID) + error (EXIT_FAILURE, 0, _("invalid mode")); + else if (change == MODE_MEMORY_EXHAUSTED) + xalloc_die (); + newmode = mode_adjust (newmode, change); + } + + for (; optind < argc; ++optind) + { + int fail = mkfifo (argv[optind], newmode); + if (fail) + error (0, errno, _("cannot create fifo %s"), quote (argv[optind])); + + /* If the containing directory happens to have a default ACL, chmod + ensures the file mode permission bits are still set as desired. */ + + if (fail == 0 && specified_mode) + { + fail = chmod (argv[optind], newmode); + if (fail) + error (0, errno, _("cannot set permissions of fifo %s"), + quote (argv[optind])); + } + + if (fail) + errors = 1; + } + + exit (errors); +#endif +} diff --git a/src/apps/bin/coreutils-5.0/src/mknod.c b/src/apps/bin/coreutils-5.0/src/mknod.c new file mode 100644 index 0000000000..8156fae699 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/mknod.c @@ -0,0 +1,236 @@ +/* mknod -- make special files + Copyright (C) 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie */ + +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "modechange.h" +#include "quote.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "mknod" + +#define AUTHORS "David MacKenzie" + +/* The name this program was run with. */ +char *program_name; + +static struct option const longopts[] = +{ + {"mode", required_argument, NULL, 'm'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... NAME TYPE [MAJOR MINOR]\n"), + program_name); + fputs (_("\ +Create the special file NAME of the given TYPE.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -m, --mode=MODE set permission mode (as in chmod), not a=rw - umask\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they\n\ +must be omitted when TYPE is p. If MAJOR or MINOR begins with 0x or 0X,\n\ +it is interpreted as hexadecimal; otherwise, if it begins with 0, as octal;\n\ +otherwise, as decimal. TYPE may be:\n\ +"), stdout); + fputs (_("\ +\n\ + b create a block (buffered) special file\n\ + c, u create a character (unbuffered) special file\n\ + p create a FIFO\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + mode_t newmode; + struct mode_change *change; + const char *specified_mode; + int optc; + mode_t node_type; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + specified_mode = NULL; + + while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + case 'm': + specified_mode = optarg; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + } + + newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (specified_mode) + { + newmode &= ~ umask (0); + change = mode_compile (specified_mode, 0); + if (change == MODE_INVALID) + error (EXIT_FAILURE, 0, _("invalid mode")); + else if (change == MODE_MEMORY_EXHAUSTED) + xalloc_die (); + newmode = mode_adjust (newmode, change); + } + + if (argc - optind != 2 && argc - optind != 4) + { + const char *msg; + if (argc - optind < 2) + msg = _("too few arguments"); + else if (argc - optind > 4) + msg = _("too many arguments"); + else + msg = _("wrong number of arguments"); + error (0, 0, "%s", msg); + usage (EXIT_FAILURE); + } + + /* Only check the first character, to allow mnemonic usage like + `mknod /dev/rst0 character 18 0'. */ + + switch (argv[optind + 1][0]) + { + case 'b': /* `block' or `buffered' */ +#ifndef S_IFBLK + error (4, 0, _("block special files not supported")); +#else + node_type = S_IFBLK; +#endif + goto block_or_character; + + case 'c': /* `character' */ + case 'u': /* `unbuffered' */ +#ifndef S_IFCHR + error (4, 0, _("character special files not supported")); +#else + node_type = S_IFCHR; +#endif + goto block_or_character; + + block_or_character: + if (argc - optind != 4) + { + error (0, 0, _("\ +when creating special files, major and minor device\n\ +numbers must be specified")); + usage (EXIT_FAILURE); + } + + { + char const *s_major = argv[optind + 2]; + char const *s_minor = argv[optind + 3]; + uintmax_t i_major, i_minor; + dev_t device; + + if (xstrtoumax (s_major, NULL, 0, &i_major, NULL) != LONGINT_OK + || i_major != (major_t) i_major) + error (EXIT_FAILURE, 0, + _("invalid major device number %s"), quote (s_major)); + + if (xstrtoumax (s_minor, NULL, 0, &i_minor, NULL) != LONGINT_OK + || i_minor != (minor_t) i_minor) + error (EXIT_FAILURE, 0, + _("invalid minor device number %s"), quote (s_minor)); + + device = makedev (i_major, i_minor); +#ifdef NODEV + if (device == NODEV) + error (EXIT_FAILURE, 0, _("invalid device %s %s"), s_major, s_minor); +#endif + + if (mknod (argv[optind], newmode | node_type, device) != 0) + error (EXIT_FAILURE, errno, "%s", quote (argv[optind])); + } + break; + + case 'p': /* `pipe' */ +#ifndef S_ISFIFO + error (4, 0, _("fifo files not supported")); +#else + if (argc - optind != 2) + { + error (0, 0, _("\ +major and minor device numbers may not be specified for fifo files")); + usage (EXIT_FAILURE); + } + if (mkfifo (argv[optind], newmode)) + error (EXIT_FAILURE, errno, "%s", quote (argv[optind])); +#endif + break; + + default: + error (0, 0, "invalid device type %s", quote (argv[optind + 1])); + usage (EXIT_FAILURE); + } + + /* Perform an explicit chmod to ensure the file mode permission bits + are set as specified. This extra step is necessary in some cases + when the containing directory has a default ACL. */ + + if (specified_mode) + { + if (chmod (argv[optind], newmode)) + error (0, errno, _("cannot set permissions of %s"), + quote (argv[optind])); + } + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/mv.c b/src/apps/bin/coreutils-5.0/src/mv.c new file mode 100644 index 0000000000..8c6f3b5ee2 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/mv.c @@ -0,0 +1,505 @@ +/* mv -- move or rename files + Copyright (C) 86, 89, 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Mike Parker, David MacKenzie, and Jim Meyering */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include +#include +#include +#include + +#include "system.h" +#include "argmatch.h" +#include "backupfile.h" +#include "copy.h" +#include "cp-hash.h" +#include "dirname.h" +#include "error.h" +#include "path-concat.h" +#include "quote.h" +#include "remove.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "mv" + +#define AUTHORS N_ ("Mike Parker, David MacKenzie, and Jim Meyering") + +/* Initial number of entries in each hash table entry's table of inodes. */ +#define INITIAL_HASH_MODULE 100 + +/* Initial number of entries in the inode hash table. */ +#define INITIAL_ENTRY_TAB_SIZE 70 + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + TARGET_DIRECTORY_OPTION = CHAR_MAX + 1, + STRIP_TRAILING_SLASHES_OPTION, + REPLY_OPTION +}; + +int isdir (); +int lstat (); + +/* The name this program was run with. */ +char *program_name; + +/* Remove any trailing slashes from each SOURCE argument. */ +static int remove_trailing_slashes; + +/* Valid arguments to the `--reply' option. */ +static char const* const reply_args[] = +{ + "yes", "no", "query", 0 +}; + +/* The values that correspond to the above strings. */ +static int const reply_vals[] = +{ + I_ALWAYS_YES, I_ALWAYS_NO, I_ASK_USER +}; + +static struct option const long_options[] = +{ + {"backup", optional_argument, NULL, 'b'}, + {"force", no_argument, NULL, 'f'}, + {"interactive", no_argument, NULL, 'i'}, + {"reply", required_argument, NULL, REPLY_OPTION}, + {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION}, + {"suffix", required_argument, NULL, 'S'}, + {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION}, + {"update", no_argument, NULL, 'u'}, + {"verbose", no_argument, NULL, 'v'}, + {"version-control", required_argument, NULL, 'V'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +static void +rm_option_init (struct rm_options *x) +{ + x->unlink_dirs = 0; + + x->ignore_missing_files = 0; + + x->recursive = 1; + + /* Should we prompt for removal, too? No. Prompting for the `move' + part is enough. It implies removal. */ + x->interactive = 0; + x->stdin_tty = 0; + + x->verbose = 0; +} + +static void +cp_option_init (struct cp_options *x) +{ + x->copy_as_regular = 0; /* FIXME: maybe make this an option */ + x->dereference = DEREF_NEVER; + x->unlink_dest_before_opening = 0; + x->unlink_dest_after_failed_open = 0; + x->hard_link = 0; + x->interactive = I_UNSPECIFIED; + x->move_mode = 1; + x->myeuid = geteuid (); + x->one_file_system = 0; + x->preserve_ownership = 1; + x->preserve_links = 1; + x->preserve_mode = 1; + x->preserve_timestamps = 1; + x->require_preserve = 0; /* FIXME: maybe make this an option */ + x->recursive = 1; + x->sparse_mode = SPARSE_AUTO; /* FIXME: maybe make this an option */ + x->symbolic_link = 0; + x->set_mode = 0; + x->mode = 0; + x->stdin_tty = isatty (STDIN_FILENO); + + /* Find out the current file creation mask, to knock the right bits + when using chmod. The creation mask is set to be liberal, so + that created directories can be written, even if it would not + have been allowed with the mask this process was started with. */ + x->umask_kill = ~ umask (0); + + x->update = 0; + x->verbose = 0; + x->xstat = lstat; + x->dest_info = NULL; + x->src_info = NULL; +} + +/* If PATH is an existing directory, return nonzero, else 0. */ + +static int +is_real_dir (const char *path) +{ + struct stat stats; + + return lstat (path, &stats) == 0 && S_ISDIR (stats.st_mode); +} + +/* Move SOURCE onto DEST. Handles cross-filesystem moves. + If SOURCE is a directory, DEST must not exist. + Return 0 if successful, non-zero if an error occurred. */ + +static int +do_move (const char *source, const char *dest, const struct cp_options *x) +{ + static int first = 1; + int copy_into_self; + int rename_succeeded; + int fail; + + if (first) + { + first = 0; + + /* Allocate space for remembering copied and created files. */ + hash_init (); + } + + fail = copy (source, dest, 0, x, ©_into_self, &rename_succeeded); + + if (!fail) + { + char const *dir_to_remove; + if (copy_into_self) + { + /* In general, when copy returns with copy_into_self set, SOURCE is + the same as, or a parent of DEST. In this case we know it's a + parent. It doesn't make sense to move a directory into itself, and + besides in some situations doing so would give highly nonintuitive + results. Run this `mkdir b; touch a c; mv * b' in an empty + directory. Here's the result of running echo `find b -print`: + b b/a b/b b/b/a b/c. Notice that only file `a' was copied + into b/b. Handle this by giving a diagnostic, removing the + copied-into-self directory, DEST (`b/b' in the example), + and failing. */ + + dir_to_remove = NULL; + fail = 1; + } + else if (rename_succeeded) + { + /* No need to remove anything. SOURCE was successfully + renamed to DEST. Or the user declined to rename a file. */ + dir_to_remove = NULL; + } + else + { + /* This may mean SOURCE and DEST referred to different devices. + It may also conceivably mean that even though they referred + to the same device, rename wasn't implemented for that device. + + E.g., (from Joel N. Weber), + [...] there might someday be cases where you can't rename + but you can copy where the device name is the same, especially + on Hurd. Consider an ftpfs with a primitive ftp server that + supports uploading, downloading and deleting, but not renaming. + + Also, note that comparing device numbers is not a reliable + check for `can-rename'. Some systems can be set up so that + files from many different physical devices all have the same + st_dev field. This is a feature of some NFS mounting + configurations. + + We reach this point if SOURCE has been successfully copied + to DEST. Now we have to remove SOURCE. + + This function used to resort to copying only when rename + failed and set errno to EXDEV. */ + + dir_to_remove = source; + } + + if (dir_to_remove != NULL) + { + struct rm_options rm_options; + enum RM_status status; + + rm_option_init (&rm_options); + rm_options.verbose = x->verbose; + + status = rm (1, &dir_to_remove, &rm_options); + assert (VALID_STATUS (status)); + if (status == RM_ERROR) + fail = 1; + } + } + + return fail; +} + +/* Move file SOURCE onto DEST. Handles the case when DEST is a directory. + DEST_IS_DIR must be nonzero when DEST is a directory or a symlink to a + directory and zero otherwise. + Return 0 if successful, non-zero if an error occurred. */ + +static int +movefile (char *source, char *dest, int dest_is_dir, + const struct cp_options *x) +{ + int dest_had_trailing_slash = strip_trailing_slashes (dest); + int fail; + + /* This code was introduced to handle the ambiguity in the semantics + of mv that is induced by the varying semantics of the rename function. + Some systems (e.g., Linux) have a rename function that honors a + trailing slash, while others (like Solaris 5,6,7) have a rename + function that ignores a trailing slash. I believe the Linux + rename semantics are POSIX and susv2 compliant. */ + + if (remove_trailing_slashes) + strip_trailing_slashes (source); + + /* In addition to when DEST is a directory, if DEST has a trailing + slash and neither SOURCE nor DEST is a directory, presume the target + is DEST/`basename source`. This converts `mv x y/' to `mv x y/x'. + This change means that the command `mv any file/' will now fail + rather than performing the move. The case when SOURCE is a + directory and DEST is not is properly diagnosed by do_move. */ + + if (dest_is_dir || (dest_had_trailing_slash && !is_real_dir (source))) + { + /* DEST is a directory; build full target filename. */ + char const *src_basename = base_name (source); + char *new_dest = path_concat (dest, src_basename, NULL); + if (new_dest == NULL) + xalloc_die (); + strip_trailing_slashes (new_dest); + fail = do_move (source, new_dest, x); + free (new_dest); + } + else + { + fail = do_move (source, dest, x); + } + + return fail; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... SOURCE DEST\n\ + or: %s [OPTION]... SOURCE... DIRECTORY\n\ + or: %s [OPTION]... --target-directory=DIRECTORY SOURCE...\n\ +"), + program_name, program_name, program_name); + fputs (_("\ +Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + --backup[=CONTROL] make a backup of each existing destination file\n\ + -b like --backup but does not accept an argument\n\ + -f, --force do not prompt before overwriting\n\ + equivalent to --reply=yes\n\ + -i, --interactive prompt before overwrite\n\ + equivalent to --reply=query\n\ +"), stdout); + fputs (_("\ + --reply={yes,no,query} specify how to handle the prompt about an\n\ + existing destination file\n\ + --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\ + argument\n\ + -S, --suffix=SUFFIX override the usual backup suffix\n\ +"), stdout); + fputs (_("\ + --target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY\n\ + -u, --update move only when the SOURCE file is newer\n\ + than the destination file or when the\n\ + destination file is missing\n\ + -v, --verbose explain what is being done\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ +The version control method may be selected via the --backup option or through\n\ +the VERSION_CONTROL environment variable. Here are the values:\n\ +\n\ +"), stdout); + fputs (_("\ + none, off never make backups (even if --backup is given)\n\ + numbered, t make numbered backups\n\ + existing, nil numbered if numbered backups exist, simple otherwise\n\ + simple, never always make simple backups\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int c; + int errors; + int make_backups = 0; + int dest_is_dir; + char *backup_suffix_string; + char *version_control_string = NULL; + struct cp_options x; + char *target_directory = NULL; + int target_directory_specified; + unsigned int n_files; + char **file; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + cp_option_init (&x); + + /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + + errors = 0; + + while ((c = getopt_long (argc, argv, "bfiuvS:V:", long_options, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + case 'V': /* FIXME: this is deprecated. Remove it in 2001. */ + error (0, 0, + _("warning: --version-control (-V) is obsolete; support for\ + it\nwill be removed in some future release. Use --backup=%s instead." + ), optarg); + /* Fall through. */ + + case 'b': + make_backups = 1; + if (optarg) + version_control_string = optarg; + break; + case 'f': + x.interactive = I_ALWAYS_YES; + break; + case 'i': + x.interactive = I_ASK_USER; + break; + case REPLY_OPTION: + x.interactive = XARGMATCH ("--reply", optarg, + reply_args, reply_vals); + break; + case STRIP_TRAILING_SLASHES_OPTION: + remove_trailing_slashes = 1; + break; + case TARGET_DIRECTORY_OPTION: + target_directory = optarg; + break; + case 'u': + x.update = 1; + break; + case 'v': + x.verbose = 1; + break; + case 'S': + make_backups = 1; + backup_suffix_string = optarg; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + } + + n_files = argc - optind; + file = argv + optind; + + target_directory_specified = (target_directory != NULL); + if (target_directory == NULL && n_files != 0) + target_directory = file[n_files - 1]; + + dest_is_dir = (n_files > 0 && isdir (target_directory)); + + if (n_files == 0 || (n_files == 1 && !target_directory_specified)) + { + error (0, 0, _("missing file argument")); + usage (EXIT_FAILURE); + } + + if (target_directory_specified) + { + if (!dest_is_dir) + { + error (0, 0, _("specified target, %s is not a directory"), + quote (target_directory)); + usage (EXIT_FAILURE); + } + } + else if (n_files > 2 && !dest_is_dir) + { + error (0, 0, + _("when moving multiple files, last argument must be a directory")); + usage (EXIT_FAILURE); + } + + if (backup_suffix_string) + simple_backup_suffix = xstrdup (backup_suffix_string); + + x.backup_type = (make_backups + ? xget_version (_("backup type"), + version_control_string) + : none); + + /* Move each arg but the last into the target_directory. */ + { + unsigned int last_file_idx = (target_directory_specified + ? n_files - 1 + : n_files - 2); + unsigned int i; + + /* Initialize the hash table only if we'll need it. + The problem it is used to detect can arise only if there are + two or more files to move. */ + if (last_file_idx) + dest_info_init (&x); + + for (i = 0; i <= last_file_idx; ++i) + errors |= movefile (file[i], target_directory, dest_is_dir, &x); + } + + exit (errors); +} diff --git a/src/apps/bin/coreutils-5.0/src/nice.c b/src/apps/bin/coreutils-5.0/src/nice.c new file mode 100644 index 0000000000..f8b5b85f28 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/nice.c @@ -0,0 +1,201 @@ +/* nice -- run a program with modified scheduling priority + Copyright (C) 1990-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* David MacKenzie */ + +#include +#include + +#include + +#include +#include +#ifndef NICE_PRIORITY +# include +# include +#endif + +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "long-options.h" +#include "posixver.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "nice" + +#define AUTHORS "David MacKenzie" + +#ifdef NICE_PRIORITY +# define GET_PRIORITY() nice (0) +#else +# define GET_PRIORITY() getpriority (PRIO_PROCESS, 0) +#endif + +/* The name this program was run with. */ +char *program_name; + +static struct option const longopts[] = +{ + {"adjustment", required_argument, NULL, 'n'}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION] [COMMAND [ARG]...]\n"), program_name); + fputs (_("\ +Run COMMAND with an adjusted scheduling priority.\n\ +With no COMMAND, print the current scheduling priority. ADJUST is 10\n\ +by default. Range goes from -20 (highest priority) to 19 (lowest).\n\ +\n\ + -n, --adjustment=ADJUST increment priority by ADJUST first\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int current_priority; + long int adjustment = 0; + int minusflag = 0; + int adjustment_given = 0; + int i; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + for (i = 1; i < argc; /* empty */) + { + char *s = argv[i]; + + if (s[0] == '-' && s[1] == '-' && ISDIGIT (s[2]) + && posix2_version () < 200112) + { + if (xstrtol (&s[2], NULL, 10, &adjustment, "") != LONGINT_OK) + error (EXIT_FAILURE, 0, _("invalid option `%s'"), s); + + minusflag = 1; + adjustment_given = 1; + ++i; + } + else if (s[0] == '-' + && (ISDIGIT (s[1]) || (s[1] == '+' && ISDIGIT (s[2]))) + && posix2_version () < 200112) + { + if (s[1] == '+') + ++s; + if (xstrtol (&s[1], NULL, 10, &adjustment, "") != LONGINT_OK) + error (EXIT_FAILURE, 0, _("invalid option `%s'"), s); + + minusflag = 0; + adjustment_given = 1; + ++i; + } + else + { + int optc; + char **fake_argv = argv + i - 1; + + /* Initialize getopt_long's internal state. */ + optind = 0; + + if ((optc = getopt_long (argc - (i - 1), fake_argv, "+n:", + longopts, NULL)) != -1) + { + switch (optc) + { + case '?': + usage (EXIT_FAILURE); + + case 'n': + if (xstrtol (optarg, NULL, 10, &adjustment, "") + != LONGINT_OK) + error (EXIT_FAILURE, 0, _("invalid priority `%s'"), optarg); + + minusflag = 0; + adjustment_given = 1; + break; + } + } + + i += optind - 1; + + if (optc == EOF) + break; + } + } + + if (minusflag) + adjustment = -adjustment; + if (!adjustment_given) + adjustment = 10; + + if (i == argc) + { + if (adjustment_given) + { + error (0, 0, _("a command must be given with an adjustment")); + usage (EXIT_FAILURE); + } + /* No command given; print the priority. */ + errno = 0; + current_priority = GET_PRIORITY (); + if (current_priority == -1 && errno != 0) + error (EXIT_FAILURE, errno, _("cannot get priority")); + printf ("%d\n", current_priority); + exit (EXIT_SUCCESS); + } + +#ifndef NICE_PRIORITY + errno = 0; + current_priority = GET_PRIORITY (); + if (current_priority == -1 && errno != 0) + error (EXIT_FAILURE, errno, _("cannot get priority")); + if (setpriority (PRIO_PROCESS, 0, current_priority + adjustment)) +#else + if (nice (adjustment) == -1) +#endif + error (EXIT_FAILURE, errno, _("cannot set priority")); + + execvp (argv[i], &argv[i]); + + { + int exit_status = (errno == ENOENT ? 127 : 126); + error (0, errno, "%s", argv[i]); + exit (exit_status); + } +} diff --git a/src/apps/bin/coreutils-5.0/src/nl.c b/src/apps/bin/coreutils-5.0/src/nl.c new file mode 100644 index 0000000000..8e227607f1 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/nl.c @@ -0,0 +1,629 @@ +/* nl -- number lines of files + Copyright (C) 89, 92, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Scott Bartram (nancy!scott@uunet.uu.net) + Revised by David MacKenzie (djm@gnu.ai.mit.edu) */ + +#include + +#include +#include +#include + +#include "system.h" +#include "closeout.h" + +#include + +#include "error.h" +#include "linebuffer.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "nl" + +#define AUTHORS N_ ("Scott Bartram and David MacKenzie") + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif + +/* Line-number formats. */ +enum number_format +{ + FORMAT_RIGHT_NOLZ, /* Right justified, no leading zeroes. */ + FORMAT_RIGHT_LZ, /* Right justified, leading zeroes. */ + FORMAT_LEFT /* Left justified, no leading zeroes. */ +}; + +/* Default section delimiter characters. */ +#define DEFAULT_SECTION_DELIMITERS "\\:" + +/* Types of input lines: either one of the section delimiters, + or text to output. */ +enum section +{ + Header, Body, Footer, Text +}; + +/* The name this program was run with. */ +char *program_name; + +/* Format of body lines (-b). */ +static char *body_type = "t"; + +/* Format of header lines (-h). */ +static char *header_type = "n"; + +/* Format of footer lines (-f). */ +static char *footer_type = "n"; + +/* Format currently being used (body, header, or footer). */ +static char *current_type; + +/* Regex for body lines to number (-bp). */ +static struct re_pattern_buffer body_regex; + +/* Regex for header lines to number (-hp). */ +static struct re_pattern_buffer header_regex; + +/* Regex for footer lines to number (-fp). */ +static struct re_pattern_buffer footer_regex; + +/* Pointer to current regex, if any. */ +static struct re_pattern_buffer *current_regex = NULL; + +/* Separator string to print after line number (-s). */ +static char *separator_str = "\t"; + +/* Input section delimiter string (-d). */ +static char *section_del = DEFAULT_SECTION_DELIMITERS; + +/* Header delimiter string. */ +static char *header_del = NULL; + +/* Header section delimiter length. */ +static size_t header_del_len; + +/* Body delimiter string. */ +static char *body_del = NULL; + +/* Body section delimiter length. */ +static size_t body_del_len; + +/* Footer delimiter string. */ +static char *footer_del = NULL; + +/* Footer section delimiter length. */ +static size_t footer_del_len; + +/* Input buffer. */ +static struct linebuffer line_buf; + +/* printf format string for line number. */ +static char *print_fmt; + +/* printf format string for unnumbered lines. */ +static char *print_no_line_fmt = NULL; + +/* Starting line number on each page (-v). */ +static int starting_line_number = 1; + +/* Line number increment (-i). */ +static int page_incr = 1; + +/* If TRUE, reset line number at start of each page (-p). */ +static int reset_numbers = TRUE; + +/* Number of blank lines to consider to be one line for numbering (-l). */ +static int blank_join = 1; + +/* Width of line numbers (-w). */ +static int lineno_width = 6; + +/* Line number format (-n). */ +static enum number_format lineno_format = FORMAT_RIGHT_NOLZ; + +/* Current print line number. */ +static int line_no; + +/* Nonzero if we have ever read standard input. */ +static int have_read_stdin; + +static struct option const longopts[] = +{ + {"header-numbering", required_argument, NULL, 'h'}, + {"body-numbering", required_argument, NULL, 'b'}, + {"footer-numbering", required_argument, NULL, 'f'}, + {"starting-line-number", required_argument, NULL, 'v'}, + {"page-increment", required_argument, NULL, 'i'}, + {"no-renumber", no_argument, NULL, 'p'}, + {"join-blank-lines", required_argument, NULL, 'l'}, + {"number-separator", required_argument, NULL, 's'}, + {"number-width", required_argument, NULL, 'w'}, + {"number-format", required_argument, NULL, 'n'}, + {"section-delimiter", required_argument, NULL, 'd'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +/* Print a usage message and quit. */ + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + fputs (_("\ +Write each FILE to standard output, with line numbers added.\n\ +With no FILE, or when FILE is -, read standard input.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -b, --body-numbering=STYLE use STYLE for numbering body lines\n\ + -d, --section-delimiter=CC use CC for separating logical pages\n\ + -f, --footer-numbering=STYLE use STYLE for numbering footer lines\n\ +"), stdout); + fputs (_("\ + -h, --header-numbering=STYLE use STYLE for numbering header lines\n\ + -i, --page-increment=NUMBER line number increment at each line\n\ + -l, --join-blank-lines=NUMBER group of NUMBER empty lines counted as one\n\ + -n, --number-format=FORMAT insert line numbers according to FORMAT\n\ + -p, --no-renumber do not reset line numbers at logical pages\n\ + -s, --number-separator=STRING add STRING after (possible) line number\n\ +"), stdout); + fputs (_("\ + -v, --first-page=NUMBER first line number on each logical page\n\ + -w, --number-width=NUMBER use NUMBER columns for line numbers\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +By default, selects -v1 -i1 -l1 -sTAB -w6 -nrn -hn -bt -fn. CC are\n\ +two delimiter characters for separating logical pages, a missing\n\ +second character implies :. Type \\\\ for \\. STYLE is one of:\n\ +"), stdout); + fputs (_("\ +\n\ + a number all lines\n\ + t number only nonempty lines\n\ + n number no lines\n\ + pREGEXP number only lines that contain a match for REGEXP\n\ +\n\ +FORMAT is one of:\n\ +\n\ + ln left justified, no leading zeros\n\ + rn right justified, no leading zeros\n\ + rz right justified, leading zeros\n\ +\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Build the printf format string, based on `lineno_format'. */ + +static void +build_print_fmt (void) +{ + print_fmt = xmalloc ( 1 /* for `%' */ + + 1 /* for `-' or `0' */ + + INT_STRLEN_BOUND (lineno_width) + + 1 /* for `d' */ + + 1 /* for trailing NUL byte */ ); + switch (lineno_format) + { + case FORMAT_RIGHT_NOLZ: + sprintf (print_fmt, "%%%dd", lineno_width); + break; + case FORMAT_RIGHT_LZ: + sprintf (print_fmt, "%%0%dd", lineno_width); + break; + case FORMAT_LEFT: + sprintf (print_fmt, "%%-%dd", lineno_width); + break; + } +} + +/* Set the command line flag TYPEP and possibly the regex pointer REGEXP, + according to `optarg'. */ + +static int +build_type_arg (char **typep, struct re_pattern_buffer *regexp) +{ + const char *errmsg; + int rval = TRUE; + int optlen; + + switch (*optarg) + { + case 'a': + case 't': + case 'n': + *typep = optarg; + break; + case 'p': + *typep = optarg++; + optlen = strlen (optarg); + regexp->allocated = optlen * 2; + regexp->buffer = (unsigned char *) xmalloc (regexp->allocated); + regexp->translate = NULL; + regexp->fastmap = xmalloc (256); + regexp->fastmap_accurate = 0; + errmsg = re_compile_pattern (optarg, optlen, regexp); + if (errmsg) + error (EXIT_FAILURE, 0, "%s", errmsg); + break; + default: + rval = FALSE; + break; + } + return rval; +} + +/* Print the line number and separator; increment the line number. */ + +static void +print_lineno (void) +{ + printf (print_fmt, line_no); + fputs (separator_str, stdout); + line_no += page_incr; +} + +/* Switch to a header section. */ + +static void +proc_header (void) +{ + current_type = header_type; + current_regex = &header_regex; + if (reset_numbers) + line_no = starting_line_number; + putchar ('\n'); +} + +/* Switch to a body section. */ + +static void +proc_body (void) +{ + current_type = body_type; + current_regex = &body_regex; + putchar ('\n'); +} + +/* Switch to a footer section. */ + +static void +proc_footer (void) +{ + current_type = footer_type; + current_regex = &footer_regex; + putchar ('\n'); +} + +/* Process a regular text line in `line_buf'. */ + +static void +proc_text (void) +{ + static int blank_lines = 0; /* Consecutive blank lines so far. */ + + switch (*current_type) + { + case 'a': + if (blank_join > 1) + { + if (1 < line_buf.length || ++blank_lines == blank_join) + { + print_lineno (); + blank_lines = 0; + } + else + puts (print_no_line_fmt); + } + else + print_lineno (); + break; + case 't': + if (1 < line_buf.length) + print_lineno (); + else + puts (print_no_line_fmt); + break; + case 'n': + puts (print_no_line_fmt); + break; + case 'p': + if (re_search (current_regex, line_buf.buffer, line_buf.length - 1, + 0, line_buf.length - 1, (struct re_registers *) 0) < 0) + puts (print_no_line_fmt); + else + print_lineno (); + break; + } + fwrite (line_buf.buffer, sizeof (char), line_buf.length, stdout); +} + +/* Return the type of line in `line_buf'. */ + +static enum section +check_section (void) +{ + size_t len = line_buf.length - 1; + + if (len < 2 || memcmp (line_buf.buffer, section_del, 2)) + return Text; + if (len == header_del_len + && !memcmp (line_buf.buffer, header_del, header_del_len)) + return Header; + if (len == body_del_len + && !memcmp (line_buf.buffer, body_del, body_del_len)) + return Body; + if (len == footer_del_len + && !memcmp (line_buf.buffer, footer_del, footer_del_len)) + return Footer; + return Text; +} + +/* Read and process the file pointed to by FP. */ + +static void +process_file (FILE *fp) +{ + while (readline (&line_buf, fp)) + { + switch ((int) check_section ()) + { + case Header: + proc_header (); + break; + case Body: + proc_body (); + break; + case Footer: + proc_footer (); + break; + case Text: + proc_text (); + break; + } + } +} + +/* Process file FILE to standard output. + Return 0 if successful, 1 if not. */ + +static int +nl_file (const char *file) +{ + FILE *stream; + + if (STREQ (file, "-")) + { + have_read_stdin = 1; + stream = stdin; + } + else + { + stream = fopen (file, "r"); + if (stream == NULL) + { + error (0, errno, "%s", file); + return 1; + } + } + + process_file (stream); + + if (ferror (stream)) + { + error (0, errno, "%s", file); + return 1; + } + if (STREQ (file, "-")) + clearerr (stream); /* Also clear EOF. */ + else if (fclose (stream) == EOF) + { + error (0, errno, "%s", file); + return 1; + } + return 0; +} + +int +main (int argc, char **argv) +{ + int c, exit_status = 0; + size_t len; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + have_read_stdin = 0; + + while ((c = getopt_long (argc, argv, "h:b:f:v:i:pl:s:w:n:d:", longopts, + NULL)) != -1) + { + switch (c) + { + case 0: + break; + + case 'h': + if (build_type_arg (&header_type, &header_regex) != TRUE) + usage (2); + break; + case 'b': + if (build_type_arg (&body_type, &body_regex) != TRUE) + usage (2); + break; + case 'f': + if (build_type_arg (&footer_type, &footer_regex) != TRUE) + usage (2); + break; + case 'v': + { + long int tmp_long; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + /* Allow it to be negative. */ + || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, _("invalid starting line number: `%s'"), + optarg); + starting_line_number = (int) tmp_long; + } + break; + case 'i': + { + long int tmp_long; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long <= 0 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, _("invalid line number increment: `%s'"), + optarg); + page_incr = (int) tmp_long; + } + break; + case 'p': + reset_numbers = FALSE; + break; + case 'l': + { + long int tmp_long; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long <= 0 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, _("invalid number of blank lines: `%s'"), + optarg); + blank_join = (int) tmp_long; + } + break; + case 's': + separator_str = optarg; + break; + case 'w': + { + long int tmp_long; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long <= 0 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, + _("invalid line number field width: `%s'"), + optarg); + lineno_width = (int) tmp_long; + } + break; + case 'n': + switch (*optarg) + { + case 'l': + if (optarg[1] == 'n') + lineno_format = FORMAT_LEFT; + else + usage (2); + break; + case 'r': + switch (optarg[1]) + { + case 'n': + lineno_format = FORMAT_RIGHT_NOLZ; + break; + case 'z': + lineno_format = FORMAT_RIGHT_LZ; + break; + default: + usage (2); + break; + } + break; + default: + usage (2); + break; + } + break; + case 'd': + section_del = optarg; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (2); + break; + } + } + + /* Initialize the section delimiters. */ + len = strlen (section_del); + + header_del_len = len * 3; + header_del = xmalloc (header_del_len + 1); + strcat (strcat (strcpy (header_del, section_del), section_del), section_del); + + body_del_len = len * 2; + body_del = xmalloc (body_del_len + 1); + strcat (strcpy (body_del, section_del), section_del); + + footer_del_len = len; + footer_del = xmalloc (footer_del_len + 1); + strcpy (footer_del, section_del); + + /* Initialize the input buffer. */ + initbuffer (&line_buf); + + /* Initialize the printf format for unnumbered lines. */ + len = strlen (separator_str); + print_no_line_fmt = xmalloc (lineno_width + len + 1); + memset (print_no_line_fmt, ' ', lineno_width + len); + print_no_line_fmt[lineno_width + len] = '\0'; + + line_no = starting_line_number; + current_type = body_type; + current_regex = &body_regex; + build_print_fmt (); + + /* Main processing. */ + + if (optind == argc) + exit_status |= nl_file ("-"); + else + for (; optind < argc; optind++) + exit_status |= nl_file (argv[optind]); + + if (have_read_stdin && fclose (stdin) == EOF) + { + error (0, errno, "-"); + exit_status = 1; + } + + exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/nohup.sh b/src/apps/bin/coreutils-5.0/src/nohup.sh new file mode 100755 index 0000000000..de3af298f6 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/nohup.sh @@ -0,0 +1,79 @@ +#!/bin/sh +# nohup -- run a command immume to hangups, with output to a non-tty +# Copyright (C) 1991, 1997, 1999, 2000, 2002 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +# Written by David MacKenzie . + +usage="Usage: $0 COMMAND [ARG]... + or: $0 OPTION" + +usage_try=" +Try \`$0 --help' for more information." + +usage_help="Run COMMAND, ignoring hangup signals. + + --help display this help and exit + --version output version information and exit + +Report bugs to <@PACKAGE_BUGREPORT@>." + +if [ $# -eq 0 ]; then + echo >&2 "$usage" + echo >&2 "$usage_try" + exit 127 +fi + +fail=0 +case $# in + 1 ) + case "z${1}" in + z--help ) + echo "$usage" || fail=127; echo "$usage_help" || fail=127 + exit $fail;; + z--version ) + echo "nohup (@GNU_PACKAGE@) @VERSION@" || fail=127 + exit $fail;; + * ) ;; + esac + ;; + * ) ;; +esac + +trap "" 1 + +# Redirect stdout if the user didn't already do it. +if [ -t 1 ]; then + oldmask=`umask`; umask 077 + # If we cannot write to the current directory, use the home directory. + if exec >> nohup.out; then + echo "nohup: appending output to \`nohup.out'" >&2 + elif exec >> "$HOME/nohup.out"; then + echo "nohup: appending output to \`$HOME/nohup.out'" >&2 + else + echo "nohup: cannot append to either \`nohup.out' or \`$HOME/nohup.out'" \ + >&2 + exit 127 + fi + umask $oldmask +fi + +# Redirect stderr if the user didn't already do it. +if [ -t 2 ]; then + exec 2>&1 +fi + +exec "$@" diff --git a/src/apps/bin/coreutils-5.0/src/od.c b/src/apps/bin/coreutils-5.0/src/od.c new file mode 100644 index 0000000000..734ba876d4 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/od.c @@ -0,0 +1,2004 @@ +/* od -- dump files in octal and other formats + Copyright (C) 92, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Jim Meyering. */ + +#include + +#include +#include +#include +#include +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "posixver.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "od" + +#define AUTHORS "Jim Meyering" + +#if defined(__GNUC__) || defined(STDC_HEADERS) +# include +#endif + +#ifdef HAVE_LONG_DOUBLE +typedef long double LONG_DOUBLE; +#else +typedef double LONG_DOUBLE; +#endif + +/* The default number of input bytes per output line. */ +#define DEFAULT_BYTES_PER_BLOCK 16 + +/* The number of decimal digits of precision in a float. */ +#ifndef FLT_DIG +# define FLT_DIG 7 +#endif + +/* The number of decimal digits of precision in a double. */ +#ifndef DBL_DIG +# define DBL_DIG 15 +#endif + +/* The number of decimal digits of precision in a long double. */ +#ifndef LDBL_DIG +# define LDBL_DIG DBL_DIG +#endif + +#if HAVE_UNSIGNED_LONG_LONG +typedef unsigned long long ulonglong_t; +#else +/* This is just a place-holder to avoid a few `#if' directives. + In this case, the type isn't actually used. */ +typedef unsigned long int ulonglong_t; +#endif + +enum size_spec + { + NO_SIZE, + CHAR, + SHORT, + INT, + LONG, + LONG_LONG, + /* FIXME: add INTMAX support, too */ + FLOAT_SINGLE, + FLOAT_DOUBLE, + FLOAT_LONG_DOUBLE, + N_SIZE_SPECS + }; + +enum output_format + { + SIGNED_DECIMAL, + UNSIGNED_DECIMAL, + OCTAL, + HEXADECIMAL, + FLOATING_POINT, + NAMED_CHARACTER, + CHARACTER + }; + +/* Each output format specification (from `-t spec' or from + old-style options) is represented by one of these structures. */ +struct tspec + { + enum output_format fmt; + enum size_spec size; + void (*print_function) (size_t, const char *, const char *); + char *fmt_string; + int hexl_mode_trailer; + int field_width; + }; + +/* The name this program was run with. */ +char *program_name; + +/* Convert the number of 8-bit bytes of a binary representation to + the number of characters (digits + sign if the type is signed) + required to represent the same quantity in the specified base/type. + For example, a 32-bit (4-byte) quantity may require a field width + as wide as the following for these types: + 11 unsigned octal + 11 signed decimal + 10 unsigned decimal + 8 unsigned hexadecimal */ + +static const unsigned int bytes_to_oct_digits[] = +{0, 3, 6, 8, 11, 14, 16, 19, 22, 25, 27, 30, 32, 35, 38, 41, 43}; + +static const unsigned int bytes_to_signed_dec_digits[] = +{1, 4, 6, 8, 11, 13, 16, 18, 20, 23, 25, 28, 30, 33, 35, 37, 40}; + +static const unsigned int bytes_to_unsigned_dec_digits[] = +{0, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37, 39}; + +static const unsigned int bytes_to_hex_digits[] = +{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32}; + +/* Convert enum size_spec to the size of the named type. */ +static const int width_bytes[] = +{ + -1, + sizeof (char), + sizeof (short int), + sizeof (int), + sizeof (long int), + sizeof (ulonglong_t), + sizeof (float), + sizeof (double), + sizeof (LONG_DOUBLE) +}; + +/* Ensure that for each member of `enum size_spec' there is an + initializer in the width_bytes array. */ +struct dummy +{ + int assert_width_bytes_matches_size_spec_decl + [sizeof width_bytes / sizeof width_bytes[0] == N_SIZE_SPECS ? 1 : -1]; +}; + +/* Names for some non-printing characters. */ +static const char *const charname[33] = +{ + "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", + "bs", "ht", "nl", "vt", "ff", "cr", "so", "si", + "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", + "can", "em", "sub", "esc", "fs", "gs", "rs", "us", + "sp" +}; + +/* Address base (8, 10 or 16). */ +static int address_base; + +/* The number of octal digits required to represent the largest + address value. */ +#define MAX_ADDRESS_LENGTH \ + ((sizeof (uintmax_t) * CHAR_BIT + CHAR_BIT - 1) / 3) + +/* Width of a normal address. */ +static int address_pad_len; + +static size_t string_min; +static int flag_dump_strings; + +/* Non-zero if we should recognize the older non-option arguments + that specified at most one file and optional arguments specifying + offset and pseudo-start address. */ +static int traditional; + +/* Non-zero if an old-style `pseudo-address' was specified. */ +static int flag_pseudo_start; + +/* The difference between the old-style pseudo starting address and + the number of bytes to skip. */ +static uintmax_t pseudo_offset; + +/* Function that accepts an address and an optional following char, + and prints the address and char to stdout. */ +static void (*format_address) (uintmax_t, char); + +/* The number of input bytes to skip before formatting and writing. */ +static uintmax_t n_bytes_to_skip = 0; + +/* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all + input is formatted. */ +static int limit_bytes_to_format = 0; + +/* The maximum number of bytes that will be formatted. */ +static uintmax_t max_bytes_to_format; + +/* The offset of the first byte after the last byte to be formatted. */ +static uintmax_t end_offset; + +/* When nonzero and two or more consecutive blocks are equal, format + only the first block and output an asterisk alone on the following + line to indicate that identical blocks have been elided. */ +static int abbreviate_duplicate_blocks = 1; + +/* An array of specs describing how to format each input block. */ +static struct tspec *spec; + +/* The number of format specs. */ +static size_t n_specs; + +/* The allocated length of SPEC. */ +static size_t n_specs_allocated; + +/* The number of input bytes formatted per output line. It must be + a multiple of the least common multiple of the sizes associated with + the specified output types. It should be as large as possible, but + no larger than 16 -- unless specified with the -w option. */ +static size_t bytes_per_block; + +/* Human-readable representation of *file_list (for error messages). + It differs from *file_list only when *file_list is "-". */ +static char const *input_filename; + +/* A NULL-terminated list of the file-arguments from the command line. */ +static char const *const *file_list; + +/* Initializer for file_list if no file-arguments + were specified on the command line. */ +static char const *const default_file_list[] = {"-", NULL}; + +/* The input stream associated with the current file. */ +static FILE *in_stream; + +/* If nonzero, at least one of the files we read was standard input. */ +static int have_read_stdin; + +#define MAX_INTEGRAL_TYPE_SIZE sizeof (ulonglong_t) +static enum size_spec integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1]; + +#define MAX_FP_TYPE_SIZE sizeof(LONG_DOUBLE) +static enum size_spec fp_type_size[MAX_FP_TYPE_SIZE + 1]; + +#define COMMON_SHORT_OPTIONS "A:N:abcdfhij:lot:vx" + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + TRADITIONAL_OPTION = CHAR_MAX + 1 +}; + +static struct option const long_options[] = +{ + {"skip-bytes", required_argument, NULL, 'j'}, + {"address-radix", required_argument, NULL, 'A'}, + {"read-bytes", required_argument, NULL, 'N'}, + {"format", required_argument, NULL, 't'}, + {"output-duplicates", no_argument, NULL, 'v'}, + {"strings", optional_argument, NULL, 's'}, + {"traditional", no_argument, NULL, TRADITIONAL_OPTION}, + {"width", optional_argument, NULL, 'w'}, + + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ + or: %s --traditional [FILE] [[+]OFFSET [[+]LABEL]]\n\ +"), + program_name, program_name); + fputs (_("\n\ +Write an unambiguous representation, octal bytes by default,\n\ +of FILE to standard output. With more than one FILE argument,\n\ +concatenate them in the listed order to form the input.\n\ +With no FILE, or when FILE is -, read standard input.\n\ +\n\ +"), stdout); + fputs (_("\ +All arguments to long options are mandatory for short options.\n\ +"), stdout); + fputs (_("\ + -A, --address-radix=RADIX decide how file offsets are printed\n\ + -j, --skip-bytes=BYTES skip BYTES input bytes first\n\ +"), stdout); + fputs (_("\ + -N, --read-bytes=BYTES limit dump to BYTES input bytes\n\ + -s, --strings[=BYTES] output strings of at least BYTES graphic chars\n\ + -t, --format=TYPE select output format or formats\n\ + -v, --output-duplicates do not use * to mark line suppression\n\ + -w, --width[=BYTES] output BYTES bytes per output line\n\ + --traditional accept arguments in traditional form\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +Traditional format specifications may be intermixed; they accumulate:\n\ + -a same as -t a, select named characters\n\ + -b same as -t oC, select octal bytes\n\ + -c same as -t c, select ASCII characters or backslash escapes\n\ + -d same as -t u2, select unsigned decimal shorts\n\ +"), stdout); + fputs (_("\ + -f same as -t fF, select floats\n\ + -h same as -t x2, select hexadecimal shorts\n\ + -i same as -t d2, select decimal shorts\n\ + -l same as -t d4, select decimal longs\n\ + -o same as -t o2, select octal shorts\n\ + -x same as -t x2, select hexadecimal shorts\n\ +"), stdout); + fputs (_("\ +\n\ +For older syntax (second call format), OFFSET means -j OFFSET. LABEL\n\ +is the pseudo-address at first byte printed, incremented when dump is\n\ +progressing. For OFFSET and LABEL, a 0x or 0X prefix indicates\n\ +hexadecimal, suffixes may be . for octal and b for multiply by 512.\n\ +\n\ +TYPE is made up of one or more of these specifications:\n\ +\n\ + a named character\n\ + c ASCII character or backslash escape\n\ +"), stdout); + fputs (_("\ + d[SIZE] signed decimal, SIZE bytes per integer\n\ + f[SIZE] floating point, SIZE bytes per integer\n\ + o[SIZE] octal, SIZE bytes per integer\n\ + u[SIZE] unsigned decimal, SIZE bytes per integer\n\ + x[SIZE] hexadecimal, SIZE bytes per integer\n\ +"), stdout); + fputs (_("\ +\n\ +SIZE is a number. For TYPE in doux, SIZE may also be C for\n\ +sizeof(char), S for sizeof(short), I for sizeof(int) or L for\n\ +sizeof(long). If TYPE is f, SIZE may also be F for sizeof(float), D\n\ +for sizeof(double) or L for sizeof(long double).\n\ +"), stdout); + fputs (_("\ +\n\ +RADIX is d for decimal, o for octal, x for hexadecimal or n for none.\n\ +BYTES is hexadecimal with 0x or 0X prefix, it is multiplied by 512\n\ +with b suffix, by 1024 with k and by 1048576 with m. Adding a z suffix to\n\ +any type adds a display of printable characters to the end of each line\n\ +of output. \ +"), stdout); + fputs (_("\ +--string without a number implies 3. --width without a number\n\ +implies 32. By default, od uses -A o -t d2 -w 16.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Compute the greatest common denominator of U and V + using Euclid's algorithm. */ + +static unsigned int +gcd (unsigned int u, unsigned int v) +{ + unsigned int t; + while (v != 0) + { + t = u % v; + u = v; + v = t; + } + return u; +} + +/* Compute the least common multiple of U and V. */ + +static unsigned int +lcm (unsigned int u, unsigned int v) +{ + unsigned int t = gcd (u, v); + if (t == 0) + return 0; + return u * v / t; +} + +static void +print_s_char (size_t n_bytes, const char *block, const char *fmt_string) +{ + size_t i; + for (i = n_bytes; i > 0; i--) + { + int tmp = (unsigned) *(const unsigned char *) block; + if (tmp > SCHAR_MAX) + tmp -= SCHAR_MAX - SCHAR_MIN + 1; + assert (tmp <= SCHAR_MAX); + printf (fmt_string, tmp); + block += sizeof (unsigned char); + } +} + +static void +print_char (size_t n_bytes, const char *block, const char *fmt_string) +{ + size_t i; + for (i = n_bytes; i > 0; i--) + { + unsigned int tmp = *(const unsigned char *) block; + printf (fmt_string, tmp); + block += sizeof (unsigned char); + } +} + +static void +print_s_short (size_t n_bytes, const char *block, const char *fmt_string) +{ + size_t i; + for (i = n_bytes / sizeof (unsigned short); i > 0; i--) + { + int tmp = (unsigned) *(const unsigned short *) block; + if (tmp > SHRT_MAX) + tmp -= SHRT_MAX - SHRT_MIN + 1; + assert (tmp <= SHRT_MAX); + printf (fmt_string, tmp); + block += sizeof (unsigned short); + } +} + +static void +print_short (size_t n_bytes, const char *block, const char *fmt_string) +{ + size_t i; + for (i = n_bytes / sizeof (unsigned short); i > 0; i--) + { + unsigned int tmp = *(const unsigned short *) block; + printf (fmt_string, tmp); + block += sizeof (unsigned short); + } +} + +static void +print_int (size_t n_bytes, const char *block, const char *fmt_string) +{ + size_t i; + for (i = n_bytes / sizeof (unsigned int); i > 0; i--) + { + unsigned int tmp = *(const unsigned int *) block; + printf (fmt_string, tmp); + block += sizeof (unsigned int); + } +} + +static void +print_long (size_t n_bytes, const char *block, const char *fmt_string) +{ + size_t i; + for (i = n_bytes / sizeof (unsigned long); i > 0; i--) + { + unsigned long tmp = *(const unsigned long *) block; + printf (fmt_string, tmp); + block += sizeof (unsigned long); + } +} + +static void +print_long_long (size_t n_bytes, const char *block, const char *fmt_string) +{ + size_t i; + for (i = n_bytes / sizeof (ulonglong_t); i > 0; i--) + { + ulonglong_t tmp = *(const ulonglong_t *) block; + printf (fmt_string, tmp); + block += sizeof (ulonglong_t); + } +} + +static void +print_float (size_t n_bytes, const char *block, const char *fmt_string) +{ + size_t i; + for (i = n_bytes / sizeof (float); i > 0; i--) + { + float tmp = *(const float *) block; + printf (fmt_string, tmp); + block += sizeof (float); + } +} + +static void +print_double (size_t n_bytes, const char *block, const char *fmt_string) +{ + size_t i; + for (i = n_bytes / sizeof (double); i > 0; i--) + { + double tmp = *(const double *) block; + printf (fmt_string, tmp); + block += sizeof (double); + } +} + +#ifdef HAVE_LONG_DOUBLE +static void +print_long_double (size_t n_bytes, const char *block, const char *fmt_string) +{ + size_t i; + for (i = n_bytes / sizeof (LONG_DOUBLE); i > 0; i--) + { + LONG_DOUBLE tmp = *(const LONG_DOUBLE *) block; + printf (fmt_string, tmp); + block += sizeof (LONG_DOUBLE); + } +} + +#endif + +static void +dump_hexl_mode_trailer (size_t n_bytes, const char *block) +{ + size_t i; + fputs (" >", stdout); + for (i = n_bytes; i > 0; i--) + { + unsigned int c = *(const unsigned char *) block; + unsigned int c2 = (ISPRINT(c) ? c : '.'); + putchar (c2); + block += sizeof (unsigned char); + } + putchar ('<'); +} + +static void +print_named_ascii (size_t n_bytes, const char *block, + const char *unused_fmt_string ATTRIBUTE_UNUSED) +{ + size_t i; + for (i = n_bytes; i > 0; i--) + { + unsigned int c = *(const unsigned char *) block; + unsigned int masked_c = (0x7f & c); + const char *s; + char buf[5]; + + if (masked_c == 127) + s = "del"; + else if (masked_c <= 040) + s = charname[masked_c]; + else + { + sprintf (buf, " %c", masked_c); + s = buf; + } + + printf (" %3s", s); + block += sizeof (unsigned char); + } +} + +static void +print_ascii (size_t n_bytes, const char *block, + const char *unused_fmt_string ATTRIBUTE_UNUSED) +{ + size_t i; + for (i = n_bytes; i > 0; i--) + { + unsigned int c = *(const unsigned char *) block; + const char *s; + char buf[5]; + + switch (c) + { + case '\0': + s = " \\0"; + break; + + case '\007': + s = " \\a"; + break; + + case '\b': + s = " \\b"; + break; + + case '\f': + s = " \\f"; + break; + + case '\n': + s = " \\n"; + break; + + case '\r': + s = " \\r"; + break; + + case '\t': + s = " \\t"; + break; + + case '\v': + s = " \\v"; + break; + + default: + sprintf (buf, (ISPRINT (c) ? " %c" : "%03o"), c); + s = (const char *) buf; + } + + printf (" %3s", s); + block += sizeof (unsigned char); + } +} + +/* Convert a null-terminated (possibly zero-length) string S to an + unsigned long integer value. If S points to a non-digit set *P to S, + *VAL to 0, and return 0. Otherwise, accumulate the integer value of + the string of digits. If the string of digits represents a value + larger than ULONG_MAX, don't modify *VAL or *P and return nonzero. + Otherwise, advance *P to the first non-digit after S, set *VAL to + the result of the conversion and return zero. */ + +static int +simple_strtoul (const char *s, const char **p, long unsigned int *val) +{ + unsigned long int sum; + + sum = 0; + while (ISDIGIT (*s)) + { + unsigned int c = *s++ - '0'; + if (sum > (ULONG_MAX - c) / 10) + return 1; + sum = sum * 10 + c; + } + *p = s; + *val = sum; + return 0; +} + +/* If S points to a single valid modern od format string, put + a description of that format in *TSPEC, make *NEXT point at the + character following the just-decoded format (if *NEXT is non-NULL), + and return zero. If S is not valid, don't modify *NEXT or *TSPEC, + give a diagnostic, and return nonzero. For example, if S were + "d4afL" *NEXT would be set to "afL" and *TSPEC would be + { + fmt = SIGNED_DECIMAL; + size = INT or LONG; (whichever integral_type_size[4] resolves to) + print_function = print_int; (assuming size == INT) + fmt_string = "%011d%c"; + } + S_ORIG is solely for reporting errors. It should be the full format + string argument. + */ + +static int +decode_one_format (const char *s_orig, const char *s, const char **next, + struct tspec *tspec) +{ + enum size_spec size_spec; + unsigned long int size; + enum output_format fmt; + const char *pre_fmt_string; + char *fmt_string; + void (*print_function) (size_t, const char *, const char *); + const char *p; + unsigned int c; + unsigned int field_width = 0; + + assert (tspec != NULL); + + switch (*s) + { + case 'd': + case 'o': + case 'u': + case 'x': + c = *s; + ++s; + switch (*s) + { + case 'C': + ++s; + size = sizeof (char); + break; + + case 'S': + ++s; + size = sizeof (short); + break; + + case 'I': + ++s; + size = sizeof (int); + break; + + case 'L': + ++s; + size = sizeof (long int); + break; + + default: + if (simple_strtoul (s, &p, &size) != 0) + { + /* The integer at P in S would overflow an unsigned long. + A digit string that long is sufficiently odd looking + that the following diagnostic is sufficient. */ + error (0, 0, _("invalid type string `%s'"), s_orig); + return 1; + } + if (p == s) + size = sizeof (int); + else + { + if (MAX_INTEGRAL_TYPE_SIZE < size + || integral_type_size[size] == NO_SIZE) + { + error (0, 0, _("invalid type string `%s';\n\ +this system doesn't provide a %lu-byte integral type"), s_orig, size); + return 1; + } + s = p; + } + break; + } + +#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \ + ((Spec) == LONG_LONG ? (Max_format) \ + : ((Spec) == LONG ? (Long_format) \ + : (Min_format))) \ + +#define FMT_BYTES_ALLOCATED 9 + fmt_string = xmalloc (FMT_BYTES_ALLOCATED); + + size_spec = integral_type_size[size]; + + switch (c) + { + case 'd': + fmt = SIGNED_DECIMAL; + sprintf (fmt_string, " %%%u%s", + (field_width = bytes_to_signed_dec_digits[size]), + ISPEC_TO_FORMAT (size_spec, "d", "ld", PRIdMAX)); + break; + + case 'o': + fmt = OCTAL; + sprintf (fmt_string, " %%0%u%s", + (field_width = bytes_to_oct_digits[size]), + ISPEC_TO_FORMAT (size_spec, "o", "lo", PRIoMAX)); + break; + + case 'u': + fmt = UNSIGNED_DECIMAL; + sprintf (fmt_string, " %%%u%s", + (field_width = bytes_to_unsigned_dec_digits[size]), + ISPEC_TO_FORMAT (size_spec, "u", "lu", PRIuMAX)); + break; + + case 'x': + fmt = HEXADECIMAL; + sprintf (fmt_string, " %%0%u%s", + (field_width = bytes_to_hex_digits[size]), + ISPEC_TO_FORMAT (size_spec, "x", "lx", PRIxMAX)); + break; + + default: + abort (); + } + + assert (strlen (fmt_string) < FMT_BYTES_ALLOCATED); + + switch (size_spec) + { + case CHAR: + print_function = (fmt == SIGNED_DECIMAL + ? print_s_char + : print_char); + break; + + case SHORT: + print_function = (fmt == SIGNED_DECIMAL + ? print_s_short + : print_short); + break; + + case INT: + print_function = print_int; + break; + + case LONG: + print_function = print_long; + break; + + case LONG_LONG: + print_function = print_long_long; + break; + + default: + abort (); + } + break; + + case 'f': + fmt = FLOATING_POINT; + ++s; + switch (*s) + { + case 'F': + ++s; + size = sizeof (float); + break; + + case 'D': + ++s; + size = sizeof (double); + break; + + case 'L': + ++s; + size = sizeof (LONG_DOUBLE); + break; + + default: + if (simple_strtoul (s, &p, &size) != 0) + { + /* The integer at P in S would overflow an unsigned long. + A digit string that long is sufficiently odd looking + that the following diagnostic is sufficient. */ + error (0, 0, _("invalid type string `%s'"), s_orig); + return 1; + } + if (p == s) + size = sizeof (double); + else + { + if (size > MAX_FP_TYPE_SIZE + || fp_type_size[size] == NO_SIZE) + { + error (0, 0, _("invalid type string `%s';\n\ +this system doesn't provide a %lu-byte floating point type"), s_orig, size); + return 1; + } + s = p; + } + break; + } + size_spec = fp_type_size[size]; + + switch (size_spec) + { + case FLOAT_SINGLE: + print_function = print_float; + /* Don't use %#e; not all systems support it. */ + pre_fmt_string = " %%%d.%de"; + fmt_string = xmalloc (strlen (pre_fmt_string)); + sprintf (fmt_string, pre_fmt_string, + (field_width = FLT_DIG + 8), FLT_DIG); + break; + + case FLOAT_DOUBLE: + print_function = print_double; + pre_fmt_string = " %%%d.%de"; + fmt_string = xmalloc (strlen (pre_fmt_string)); + sprintf (fmt_string, pre_fmt_string, + (field_width = DBL_DIG + 8), DBL_DIG); + break; + +#ifdef HAVE_LONG_DOUBLE + case FLOAT_LONG_DOUBLE: + print_function = print_long_double; + pre_fmt_string = " %%%d.%dLe"; + fmt_string = xmalloc (strlen (pre_fmt_string)); + sprintf (fmt_string, pre_fmt_string, + (field_width = LDBL_DIG + 8), LDBL_DIG); + break; +#endif + + default: + abort (); + } + break; + + case 'a': + ++s; + fmt = NAMED_CHARACTER; + size_spec = CHAR; + fmt_string = NULL; + print_function = print_named_ascii; + field_width = 3; + break; + + case 'c': + ++s; + fmt = CHARACTER; + size_spec = CHAR; + fmt_string = NULL; + print_function = print_ascii; + field_width = 3; + break; + + default: + error (0, 0, _("invalid character `%c' in type string `%s'"), + *s, s_orig); + return 1; + } + + tspec->size = size_spec; + tspec->fmt = fmt; + tspec->print_function = print_function; + tspec->fmt_string = fmt_string; + + tspec->field_width = field_width; + tspec->hexl_mode_trailer = (*s == 'z'); + if (tspec->hexl_mode_trailer) + s++; + + if (next != NULL) + *next = s; + + return 0; +} + +/* Given a list of one or more input filenames FILE_LIST, set the global + file pointer IN_STREAM and the global string INPUT_FILENAME to the + first one that can be successfully opened. Modify FILE_LIST to + reference the next filename in the list. A file name of "-" is + interpreted as standard input. If any file open fails, give an error + message and return nonzero. */ + +static int +open_next_file (void) +{ + int err = 0; + + do + { + input_filename = *file_list; + if (input_filename == NULL) + return err; + ++file_list; + + if (STREQ (input_filename, "-")) + { + input_filename = _("standard input"); + in_stream = stdin; + have_read_stdin = 1; + } + else + { + in_stream = fopen (input_filename, "r"); + if (in_stream == NULL) + { + error (0, errno, "%s", input_filename); + err = 1; + } + } + } + while (in_stream == NULL); + + if (limit_bytes_to_format && !flag_dump_strings) + SETVBUF (in_stream, NULL, _IONBF, 0); + SET_BINARY (fileno (in_stream)); + + return err; +} + +/* Test whether there have been errors on in_stream, and close it if + it is not standard input. Return nonzero if there has been an error + on in_stream or stdout; return zero otherwise. This function will + report more than one error only if both a read and a write error + have occurred. */ + +static int +check_and_close (void) +{ + int err = 0; + + if (in_stream != NULL) + { + if (ferror (in_stream)) + { + error (0, errno, "%s", input_filename); + if (in_stream != stdin) + fclose (in_stream); + err = 1; + } + else if (in_stream != stdin && fclose (in_stream) == EOF) + { + error (0, errno, "%s", input_filename); + err = 1; + } + + in_stream = NULL; + } + + if (ferror (stdout)) + { + error (0, errno, _("standard output")); + err = 1; + } + + return err; +} + +/* Decode the modern od format string S. Append the decoded + representation to the global array SPEC, reallocating SPEC if + necessary. Return zero if S is valid, nonzero otherwise. */ + +static int +decode_format_string (const char *s) +{ + const char *s_orig = s; + assert (s != NULL); + + while (*s != '\0') + { + struct tspec tspec; + const char *next; + + if (decode_one_format (s_orig, s, &next, &tspec)) + return 1; + + assert (s != next); + s = next; + + if (n_specs >= n_specs_allocated) + { + n_specs_allocated = 1 + (3 * n_specs_allocated) / 2; + spec = (struct tspec *) xrealloc ((char *) spec, + (n_specs_allocated + * sizeof (struct tspec))); + } + + memcpy ((char *) &spec[n_specs], (char *) &tspec, + sizeof (struct tspec)); + ++n_specs; + } + + return 0; +} + +/* Given a list of one or more input filenames FILE_LIST, set the global + file pointer IN_STREAM to position N_SKIP in the concatenation of + those files. If any file operation fails or if there are fewer than + N_SKIP bytes in the combined input, give an error message and return + nonzero. When possible, use seek rather than read operations to + advance IN_STREAM. */ + +static int +skip (uintmax_t n_skip) +{ + int err = 0; + + if (n_skip == 0) + return 0; + + while (in_stream != NULL) /* EOF. */ + { + struct stat file_stats; + + /* First try seeking. For large offsets, this extra work is + worthwhile. If the offset is below some threshold it may be + more efficient to move the pointer by reading. There are two + issues when trying to seek: + - the file must be seekable. + - before seeking to the specified position, make sure + that the new position is in the current file. + Try to do that by getting file's size using fstat. + But that will work only for regular files. */ + + if (fstat (fileno (in_stream), &file_stats) == 0) + { + /* The st_size field is valid only for regular files + (and for symbolic links, which cannot occur here). + If the number of bytes left to skip is at least + as large as the size of the current file, we can + decrement n_skip and go on to the next file. */ + + if (S_ISREG (file_stats.st_mode) && 0 <= file_stats.st_size) + { + if ((uintmax_t) file_stats.st_size <= n_skip) + n_skip -= file_stats.st_size; + else + { + if (fseeko (in_stream, n_skip, SEEK_CUR) != 0) + { + error (0, errno, "%s", input_filename); + err = 1; + } + n_skip = 0; + } + } + + /* If it's not a regular file with nonnegative size, + position the file pointer by reading. */ + + else + { + char buf[BUFSIZ]; + size_t n_bytes_read, n_bytes_to_read = BUFSIZ; + + while (0 < n_skip) + { + if (n_skip < n_bytes_to_read) + n_bytes_to_read = n_skip; + n_bytes_read = fread (buf, 1, n_bytes_to_read, in_stream); + n_skip -= n_bytes_read; + if (n_bytes_read != n_bytes_to_read) + break; + } + } + + if (n_skip == 0) + break; + } + + else /* cannot fstat() file */ + { + error (0, errno, "%s", input_filename); + err = 1; + } + + err |= check_and_close (); + + err |= open_next_file (); + } + + if (n_skip != 0) + error (EXIT_FAILURE, 0, _("cannot skip past end of combined input")); + + return err; +} + +static void +format_address_none (uintmax_t address ATTRIBUTE_UNUSED, char c ATTRIBUTE_UNUSED) +{ +} + +static void +format_address_std (uintmax_t address, char c) +{ + char buf[MAX_ADDRESS_LENGTH + 2]; + char *p = buf + sizeof buf; + char const *pbound; + + *--p = '\0'; + *--p = c; + pbound = p - address_pad_len; + + /* Use a special case of the code for each base. This is measurably + faster than generic code. */ + switch (address_base) + { + case 8: + do + *--p = '0' + (address & 7); + while ((address >>= 3) != 0); + break; + + case 10: + do + *--p = '0' + (address % 10); + while ((address /= 10) != 0); + break; + + case 16: + do + *--p = "0123456789abcdef"[address & 15]; + while ((address >>= 4) != 0); + break; + } + + while (pbound < p) + *--p = '0'; + + fputs (p, stdout); +} + +static void +format_address_paren (uintmax_t address, char c) +{ + putchar ('('); + format_address_std (address, ')'); + putchar (c); +} + +static void +format_address_label (uintmax_t address, char c) +{ + format_address_std (address, ' '); + format_address_paren (address + pseudo_offset, c); +} + +/* Write N_BYTES bytes from CURR_BLOCK to standard output once for each + of the N_SPEC format specs. CURRENT_OFFSET is the byte address of + CURR_BLOCK in the concatenation of input files, and it is printed + (optionally) only before the output line associated with the first + format spec. When duplicate blocks are being abbreviated, the output + for a sequence of identical input blocks is the output for the first + block followed by an asterisk alone on a line. It is valid to compare + the blocks PREV_BLOCK and CURR_BLOCK only when N_BYTES == BYTES_PER_BLOCK. + That condition may be false only for the last input block -- and then + only when it has not been padded to length BYTES_PER_BLOCK. */ + +static void +write_block (uintmax_t current_offset, size_t n_bytes, + const char *prev_block, const char *curr_block) +{ + static int first = 1; + static int prev_pair_equal = 0; + +#define EQUAL_BLOCKS(b1, b2) (memcmp ((b1), (b2), bytes_per_block) == 0) + + if (abbreviate_duplicate_blocks + && !first && n_bytes == bytes_per_block + && EQUAL_BLOCKS (prev_block, curr_block)) + { + if (prev_pair_equal) + { + /* The two preceding blocks were equal, and the current + block is the same as the last one, so print nothing. */ + } + else + { + printf ("*\n"); + prev_pair_equal = 1; + } + } + else + { + size_t i; + + prev_pair_equal = 0; + for (i = 0; i < n_specs; i++) + { + if (i == 0) + format_address (current_offset, '\0'); + else + printf ("%*s", address_pad_len, ""); + (*spec[i].print_function) (n_bytes, curr_block, spec[i].fmt_string); + if (spec[i].hexl_mode_trailer) + { + /* space-pad out to full line width, then dump the trailer */ + int datum_width = width_bytes[spec[i].size]; + int blank_fields = (bytes_per_block - n_bytes) / datum_width; + int field_width = spec[i].field_width + 1; + printf ("%*s", blank_fields * field_width, ""); + dump_hexl_mode_trailer (n_bytes, curr_block); + } + putchar ('\n'); + } + } + first = 0; +} + +/* Read a single byte into *C from the concatenation of the input files + named in the global array FILE_LIST. On the first call to this + function, the global variable IN_STREAM is expected to be an open + stream associated with the input file INPUT_FILENAME. If IN_STREAM + is at end-of-file, close it and update the global variables IN_STREAM + and INPUT_FILENAME so they correspond to the next file in the list. + Then try to read a byte from the newly opened file. Repeat if + necessary until EOF is reached for the last file in FILE_LIST, then + set *C to EOF and return. Subsequent calls do likewise. The return + value is nonzero if any errors occured, zero otherwise. */ + +static int +read_char (int *c) +{ + int err = 0; + + *c = EOF; + + while (in_stream != NULL) /* EOF. */ + { + *c = fgetc (in_stream); + + if (*c != EOF) + break; + + err |= check_and_close (); + + err |= open_next_file (); + } + + return err; +} + +/* Read N bytes into BLOCK from the concatenation of the input files + named in the global array FILE_LIST. On the first call to this + function, the global variable IN_STREAM is expected to be an open + stream associated with the input file INPUT_FILENAME. If all N + bytes cannot be read from IN_STREAM, close IN_STREAM and update + the global variables IN_STREAM and INPUT_FILENAME. Then try to + read the remaining bytes from the newly opened file. Repeat if + necessary until EOF is reached for the last file in FILE_LIST. + On subsequent calls, don't modify BLOCK and return zero. Set + *N_BYTES_IN_BUFFER to the number of bytes read. If an error occurs, + it will be detected through ferror when the stream is about to be + closed. If there is an error, give a message but continue reading + as usual and return nonzero. Otherwise return zero. */ + +static int +read_block (size_t n, char *block, size_t *n_bytes_in_buffer) +{ + int err = 0; + + assert (0 < n && n <= bytes_per_block); + + *n_bytes_in_buffer = 0; + + if (n == 0) + return 0; + + while (in_stream != NULL) /* EOF. */ + { + size_t n_needed; + size_t n_read; + + n_needed = n - *n_bytes_in_buffer; + n_read = fread (block + *n_bytes_in_buffer, 1, n_needed, in_stream); + + *n_bytes_in_buffer += n_read; + + if (n_read == n_needed) + break; + + err |= check_and_close (); + + err |= open_next_file (); + } + + return err; +} + +/* Return the least common multiple of the sizes associated + with the format specs. */ + +static int +get_lcm (void) +{ + size_t i; + int l_c_m = 1; + + for (i = 0; i < n_specs; i++) + l_c_m = lcm (l_c_m, width_bytes[(int) spec[i].size]); + return l_c_m; +} + +/* If S is a valid traditional offset specification with an optional + leading '+' return nonzero and set *OFFSET to the offset it denotes. */ + +static int +parse_old_offset (const char *s, uintmax_t *offset) +{ + int radix; + enum strtol_error s_err; + + if (*s == '\0') + return 0; + + /* Skip over any leading '+'. */ + if (s[0] == '+') + ++s; + + /* Determine the radix we'll use to interpret S. If there is a `.', + it's decimal, otherwise, if the string begins with `0X'or `0x', + it's hexadecimal, else octal. */ + if (strchr (s, '.') != NULL) + radix = 10; + else + { + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + radix = 16; + else + radix = 8; + } + + s_err = xstrtoumax (s, NULL, radix, offset, "Bb"); + if (s_err != LONGINT_OK) + { + STRTOL_FAIL_WARN (s, _("old-style offset"), s_err); + return 0; + } + return 1; +} + +/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the + formatted block to standard output, and repeat until the specified + maximum number of bytes has been read or until all input has been + processed. If the last block read is smaller than BYTES_PER_BLOCK + and its size is not a multiple of the size associated with a format + spec, extend the input block with zero bytes until its length is a + multiple of all format spec sizes. Write the final block. Finally, + write on a line by itself the offset of the byte after the last byte + read. Accumulate return values from calls to read_block and + check_and_close, and if any was nonzero, return nonzero. + Otherwise, return zero. */ + +static int +dump (void) +{ + char *block[2]; + uintmax_t current_offset; + int idx; + int err; + size_t n_bytes_read; + + block[0] = (char *) alloca (bytes_per_block); + block[1] = (char *) alloca (bytes_per_block); + + current_offset = n_bytes_to_skip; + + idx = 0; + err = 0; + if (limit_bytes_to_format) + { + while (1) + { + size_t n_needed; + if (current_offset >= end_offset) + { + n_bytes_read = 0; + break; + } + n_needed = MIN (end_offset - current_offset, + (uintmax_t) bytes_per_block); + err |= read_block (n_needed, block[idx], &n_bytes_read); + if (n_bytes_read < bytes_per_block) + break; + assert (n_bytes_read == bytes_per_block); + write_block (current_offset, n_bytes_read, + block[!idx], block[idx]); + current_offset += n_bytes_read; + idx = !idx; + } + } + else + { + while (1) + { + err |= read_block (bytes_per_block, block[idx], &n_bytes_read); + if (n_bytes_read < bytes_per_block) + break; + assert (n_bytes_read == bytes_per_block); + write_block (current_offset, n_bytes_read, + block[!idx], block[idx]); + current_offset += n_bytes_read; + idx = !idx; + } + } + + if (n_bytes_read > 0) + { + int l_c_m; + size_t bytes_to_write; + + l_c_m = get_lcm (); + + /* Make bytes_to_write the smallest multiple of l_c_m that + is at least as large as n_bytes_read. */ + bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m); + + memset (block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read); + write_block (current_offset, bytes_to_write, + block[!idx], block[idx]); + current_offset += n_bytes_read; + } + + format_address (current_offset, '\n'); + + if (limit_bytes_to_format && current_offset >= end_offset) + err |= check_and_close (); + + return err; +} + +/* STRINGS mode. Find each "string constant" in the input. + A string constant is a run of at least `string_min' ASCII + graphic (or formatting) characters terminated by a null. + Based on a function written by Richard Stallman for a + traditional version of od. Return nonzero if an error + occurs. Otherwise, return zero. */ + +static int +dump_strings (void) +{ + size_t bufsize = MAX (100, string_min); + char *buf = xmalloc (bufsize); + uintmax_t address = n_bytes_to_skip; + int err; + + err = 0; + while (1) + { + size_t i; + int c; + + /* See if the next `string_min' chars are all printing chars. */ + tryline: + + if (limit_bytes_to_format + && (end_offset < string_min || end_offset - string_min <= address)) + break; + + for (i = 0; i < string_min; i++) + { + err |= read_char (&c); + address++; + if (c < 0) + { + free (buf); + return err; + } + if (!ISPRINT (c)) + /* Found a non-printing. Try again starting with next char. */ + goto tryline; + buf[i] = c; + } + + /* We found a run of `string_min' printable characters. + Now see if it is terminated with a null byte. */ + while (!limit_bytes_to_format || address < end_offset) + { + if (i == bufsize) + { + bufsize = 1 + 3 * bufsize / 2; + buf = xrealloc (buf, bufsize); + } + err |= read_char (&c); + address++; + if (c < 0) + { + free (buf); + return err; + } + if (c == '\0') + break; /* It is; print this string. */ + if (!ISPRINT (c)) + goto tryline; /* It isn't; give up on this string. */ + buf[i++] = c; /* String continues; store it all. */ + } + + /* If we get here, the string is all printable and null-terminated, + so print it. It is all in `buf' and `i' is its length. */ + buf[i] = 0; + format_address (address - i - 1, ' '); + + for (i = 0; (c = buf[i]); i++) + { + switch (c) + { + case '\007': + fputs ("\\a", stdout); + break; + + case '\b': + fputs ("\\b", stdout); + break; + + case '\f': + fputs ("\\f", stdout); + break; + + case '\n': + fputs ("\\n", stdout); + break; + + case '\r': + fputs ("\\r", stdout); + break; + + case '\t': + fputs ("\\t", stdout); + break; + + case '\v': + fputs ("\\v", stdout); + break; + + default: + putc (c, stdout); + } + } + putchar ('\n'); + } + + /* We reach this point only if we search through + (max_bytes_to_format - string_min) bytes before reaching EOF. */ + + free (buf); + + err |= check_and_close (); + return err; +} + +int +main (int argc, char **argv) +{ + int c; + int n_files; + size_t i; + int l_c_m; + size_t desired_width IF_LINT (= 0); + int width_specified = 0; + int n_failed_decodes = 0; + int err; + char const *short_options = (posix2_version () < 200112 + ? COMMON_SHORT_OPTIONS "s::w::" + : COMMON_SHORT_OPTIONS "s:w:"); + + /* The old-style `pseudo starting address' to be printed in parentheses + after any true address. */ + uintmax_t pseudo_start IF_LINT (= 0); + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + err = 0; + + for (i = 0; i <= MAX_INTEGRAL_TYPE_SIZE; i++) + integral_type_size[i] = NO_SIZE; + + integral_type_size[sizeof (char)] = CHAR; + integral_type_size[sizeof (short int)] = SHORT; + integral_type_size[sizeof (int)] = INT; + integral_type_size[sizeof (long int)] = LONG; +#if HAVE_UNSIGNED_LONG_LONG + /* If `long' and `long long' have the same size, it's fine + to overwrite the entry for `long' with this one. */ + integral_type_size[sizeof (ulonglong_t)] = LONG_LONG; +#endif + + for (i = 0; i <= MAX_FP_TYPE_SIZE; i++) + fp_type_size[i] = NO_SIZE; + + fp_type_size[sizeof (float)] = FLOAT_SINGLE; + /* The array entry for `double' is filled in after that for LONG_DOUBLE + so that if `long double' is the same type or if long double isn't + supported FLOAT_LONG_DOUBLE will never be used. */ + fp_type_size[sizeof (LONG_DOUBLE)] = FLOAT_LONG_DOUBLE; + fp_type_size[sizeof (double)] = FLOAT_DOUBLE; + + n_specs = 0; + n_specs_allocated = 5; + spec = (struct tspec *) xmalloc (n_specs_allocated * sizeof (struct tspec)); + + format_address = format_address_std; + address_base = 8; + address_pad_len = 7; + flag_dump_strings = 0; + + while ((c = getopt_long (argc, argv, short_options, long_options, NULL)) + != -1) + { + uintmax_t tmp; + enum strtol_error s_err; + + switch (c) + { + case 0: + break; + + case 'A': + switch (optarg[0]) + { + case 'd': + format_address = format_address_std; + address_base = 10; + address_pad_len = 7; + break; + case 'o': + format_address = format_address_std; + address_base = 8; + address_pad_len = 7; + break; + case 'x': + format_address = format_address_std; + address_base = 16; + address_pad_len = 6; + break; + case 'n': + format_address = format_address_none; + address_pad_len = 0; + break; + default: + error (EXIT_FAILURE, 0, + _("invalid output address radix `%c'; \ +it must be one character from [doxn]"), + optarg[0]); + break; + } + break; + + case 'j': + s_err = xstrtoumax (optarg, NULL, 0, &n_bytes_to_skip, "bkm"); + if (s_err != LONGINT_OK) + STRTOL_FATAL_ERROR (optarg, _("skip argument"), s_err); + break; + + case 'N': + limit_bytes_to_format = 1; + + s_err = xstrtoumax (optarg, NULL, 0, &max_bytes_to_format, "bkm"); + if (s_err != LONGINT_OK) + STRTOL_FATAL_ERROR (optarg, _("limit argument"), s_err); + break; + + case 's': + if (optarg == NULL) + string_min = 3; + else + { + s_err = xstrtoumax (optarg, NULL, 0, &tmp, "bkm"); + if (s_err != LONGINT_OK) + STRTOL_FATAL_ERROR (optarg, _("minimum string length"), s_err); + + /* The minimum string length may be no larger than SIZE_MAX, + since we may allocate a buffer of this size. */ + if (SIZE_MAX < tmp) + error (EXIT_FAILURE, 0, _("%s is too large"), optarg); + + string_min = tmp; + } + flag_dump_strings = 1; + break; + + case 't': + if (decode_format_string (optarg)) + ++n_failed_decodes; + break; + + case 'v': + abbreviate_duplicate_blocks = 0; + break; + + case TRADITIONAL_OPTION: + traditional = 1; + break; + + /* The next several cases map the traditional format + specification options to the corresponding modern format + specs. GNU od accepts any combination of old- and + new-style options. Format specification options accumulate. */ + +#define CASE_OLD_ARG(old_char,new_string) \ + case old_char: \ + { \ + if (decode_format_string (new_string)) \ + ++n_failed_decodes; \ + } \ + break + + CASE_OLD_ARG ('a', "a"); + CASE_OLD_ARG ('b', "oC"); + CASE_OLD_ARG ('c', "c"); + CASE_OLD_ARG ('d', "u2"); + CASE_OLD_ARG ('f', "fF"); + CASE_OLD_ARG ('h', "x2"); + CASE_OLD_ARG ('i', "d2"); + CASE_OLD_ARG ('l', "d4"); + CASE_OLD_ARG ('o', "o2"); + CASE_OLD_ARG ('x', "x2"); + + /* FIXME: POSIX 1003.1-2001 with XSI requires this: + + CASE_OLD_ARG ('s', "d2"); + + for the traditional syntax, but this conflicts with case + 's' above. */ + +#undef CASE_OLD_ARG + + case 'w': + width_specified = 1; + if (optarg == NULL) + { + desired_width = 32; + } + else + { + uintmax_t w_tmp; + s_err = xstrtoumax (optarg, NULL, 10, &w_tmp, ""); + if (s_err != LONGINT_OK) + STRTOL_FATAL_ERROR (optarg, _("width specification"), s_err); + if (SIZE_MAX < w_tmp) + error (EXIT_FAILURE, 0, _("%s is too large"), optarg); + desired_width = w_tmp; + } + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + break; + } + } + + if (n_failed_decodes > 0) + exit (EXIT_FAILURE); + + if (flag_dump_strings && n_specs > 0) + error (EXIT_FAILURE, 0, + _("no type may be specified when dumping strings")); + + n_files = argc - optind; + + /* If the --traditional option is used, there may be from + 0 to 3 remaining command line arguments; handle each case + separately. + od [file] [[+]offset[.][b] [[+]label[.][b]]] + The offset and pseudo_start have the same syntax. + + FIXME: POSIX 1003.1-2001 with XSI requires support for the + traditional syntax even if --traditional is not given. */ + + if (traditional) + { + uintmax_t offset; + + if (n_files == 1) + { + if (parse_old_offset (argv[optind], &offset)) + { + n_bytes_to_skip = offset; + --n_files; + ++argv; + } + } + else if (n_files == 2) + { + uintmax_t o1, o2; + if (parse_old_offset (argv[optind], &o1) + && parse_old_offset (argv[optind + 1], &o2)) + { + n_bytes_to_skip = o1; + flag_pseudo_start = 1; + pseudo_start = o2; + argv += 2; + n_files -= 2; + } + else if (parse_old_offset (argv[optind + 1], &o2)) + { + n_bytes_to_skip = o2; + --n_files; + argv[optind + 1] = argv[optind]; + ++argv; + } + else + { + error (0, 0, + _("invalid second operand in compatibility mode `%s'"), + argv[optind + 1]); + usage (EXIT_FAILURE); + } + } + else if (n_files == 3) + { + uintmax_t o1, o2; + if (parse_old_offset (argv[optind + 1], &o1) + && parse_old_offset (argv[optind + 2], &o2)) + { + n_bytes_to_skip = o1; + flag_pseudo_start = 1; + pseudo_start = o2; + argv[optind + 2] = argv[optind]; + argv += 2; + n_files -= 2; + } + else + { + error (0, 0, + _("in compatibility mode, the last two arguments must be offsets")); + usage (EXIT_FAILURE); + } + } + else if (n_files > 3) + { + error (0, 0, + _("compatibility mode supports at most three arguments")); + usage (EXIT_FAILURE); + } + + if (flag_pseudo_start) + { + if (format_address == format_address_none) + { + address_base = 8; + address_pad_len = 7; + format_address = format_address_paren; + } + else + format_address = format_address_label; + } + } + + if (limit_bytes_to_format) + { + end_offset = n_bytes_to_skip + max_bytes_to_format; + if (end_offset < n_bytes_to_skip) + error (EXIT_FAILURE, 0, "skip-bytes + read-bytes is too large"); + } + + if (n_specs == 0) + { + if (decode_one_format ("o2", "o2", NULL, &(spec[0]))) + { + /* This happens on Cray systems that don't have a 2-byte + integral type. */ + exit (EXIT_FAILURE); + } + + n_specs = 1; + } + + if (n_files > 0) + { + /* Set the global pointer FILE_LIST so that it + references the first file-argument on the command-line. */ + + file_list = (char const *const *) &argv[optind]; + } + else + { + /* No files were listed on the command line. + Set the global pointer FILE_LIST so that it + references the null-terminated list of one name: "-". */ + + file_list = default_file_list; + } + + /* open the first input file */ + err |= open_next_file (); + if (in_stream == NULL) + goto cleanup; + + /* skip over any unwanted header bytes */ + err |= skip (n_bytes_to_skip); + if (in_stream == NULL) + goto cleanup; + + pseudo_offset = (flag_pseudo_start ? pseudo_start - n_bytes_to_skip : 0); + + /* Compute output block length. */ + l_c_m = get_lcm (); + + if (width_specified) + { + if (desired_width != 0 && desired_width % l_c_m == 0) + bytes_per_block = desired_width; + else + { + error (0, 0, _("warning: invalid width %lu; using %d instead"), + (unsigned long) desired_width, l_c_m); + bytes_per_block = l_c_m; + } + } + else + { + if (l_c_m < DEFAULT_BYTES_PER_BLOCK) + bytes_per_block = l_c_m * (DEFAULT_BYTES_PER_BLOCK / l_c_m); + else + bytes_per_block = l_c_m; + } + +#ifdef DEBUG + for (i = 0; i < n_specs; i++) + { + printf (_("%d: fmt=\"%s\" width=%d\n"), + i, spec[i].fmt_string, width_bytes[spec[i].size]); + } +#endif + + err |= (flag_dump_strings ? dump_strings () : dump ()); + +cleanup:; + + if (have_read_stdin && fclose (stdin) == EOF) + error (EXIT_FAILURE, errno, _("standard input")); + + exit (err == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/paste.c b/src/apps/bin/coreutils-5.0/src/paste.c new file mode 100644 index 0000000000..d94e806521 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/paste.c @@ -0,0 +1,486 @@ +/* paste - merge lines of files + Copyright (C) 1984, 1997-2002 by David M. Ihnat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David Ihnat. */ + +/* The list of valid escape sequences has been expanded over the Unix + version, to include \b, \f, \r, and \v. + + POSIX changes, bug fixes, long-named options, and cleanup + by David MacKenzie . + + Options: + --serial + -s Paste one file at a time rather than + one line from each file. + --delimiters=delim-list + -d delim-list Consecutively use the characters in + DELIM-LIST instead of tab to separate + merged lines. When DELIM-LIST is exhausted, + start again at its beginning. + A FILE of `-' means standard input. + If no FILEs are given, standard input is used. */ + +#include + +#include +#include +#include +#include "system.h" +#include "closeout.h" +#include "error.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "paste" + +#define AUTHORS N_ ("David M. Ihnat and David MacKenzie") + +/* Indicates that no delimiter should be added in the current position. */ +#define EMPTY_DELIM '\0' + +static FILE dummy_closed; +/* Element marking a file that has reached EOF and been closed. */ +#define CLOSED (&dummy_closed) + +static FILE dummy_endlist; +/* Element marking end of list of open files. */ +#define ENDLIST (&dummy_endlist) + +/* Name this program was run with. */ +char *program_name; + +/* If nonzero, we have read standard input at some point. */ +static int have_read_stdin; + +/* If nonzero, merge subsequent lines of each file rather than + corresponding lines from each file in parallel. */ +static int serial_merge; + +/* The delimeters between lines of input files (used cyclically). */ +static char *delims; + +/* A pointer to the character after the end of `delims'. */ +static char *delim_end; + +static struct option const longopts[] = +{ + {"serial", no_argument, 0, 's'}, + {"delimiters", required_argument, 0, 'd'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0} +}; + +/* Replace backslash representations of special characters in + STRPTR with their actual values. + The set of possible backslash characters has been expanded beyond + that recognized by the Unix version. + + Return a pointer to the character after the new end of STRPTR. */ + +static char * +collapse_escapes (char *strptr) +{ + register char *strout; + + strout = strptr; /* Start at the same place, anyway. */ + + while (*strptr) + { + if (*strptr != '\\') /* Is it an escape character? */ + *strout++ = *strptr++; /* No, just transfer it. */ + else + { + switch (*++strptr) + { + case '0': + *strout++ = EMPTY_DELIM; + break; + + case 'b': + *strout++ = '\b'; + break; + + case 'f': + *strout++ = '\f'; + break; + + case 'n': + *strout++ = '\n'; + break; + + case 'r': + *strout++ = '\r'; + break; + + case 't': + *strout++ = '\t'; + break; + + case 'v': + *strout++ = '\v'; + break; + + default: + *strout++ = *strptr; + break; + } + strptr++; + } + } + return strout; +} + +/* Perform column paste on the NFILES files named in FNAMPTR. + Return 0 if no errors, 1 if one or more files could not be + opened or read. */ + +static int +paste_parallel (int nfiles, char **fnamptr) +{ + int errors = 0; /* 1 if open or read errors occur. */ + /* Number of files for which space is allocated in `delbuf' and `fileptr'. + Enlarged as necessary. */ + int file_list_size = 12; + int chr IF_LINT (= 0); /* Input character. */ + int line_length; /* Number of chars in line. */ + int somedone; /* 0 if all files empty for this line. */ + /* If all files are just ready to be closed, or will be on this + round, the string of delimiters must be preserved. + delbuf[0] through delbuf[file_list_size] + store the delimiters for closed files. */ + char *delbuf; + size_t delims_saved; /* Number of delims saved in `delbuf'. */ + register char *delimptr; /* Cycling pointer into `delims'. */ + FILE **fileptr; /* Streams open to the files to process. */ + int files_open; /* Number of files still open to process. */ + int i; /* Loop index. */ + int opened_stdin = 0; /* Nonzero if any fopen got fd 0. */ + + delbuf = (char *) xmalloc (file_list_size + 2); + fileptr = (FILE **) xmalloc ((file_list_size + 1) * sizeof (FILE *)); + + /* Attempt to open all files. This could be expanded to an infinite + number of files, but at the (considerable) expense of remembering + each file and its current offset, then opening/reading/closing. */ + + for (files_open = 0; files_open < nfiles; ++files_open) + { + if (files_open == file_list_size - 2) + { + file_list_size += 12; + delbuf = (char *) xrealloc (delbuf, file_list_size + 2); + fileptr = (FILE **) xrealloc ((char *) fileptr, (file_list_size + 1) + * sizeof (FILE *)); + } + if (STREQ (fnamptr[files_open], "-")) + { + have_read_stdin = 1; + fileptr[files_open] = stdin; + } + else + { + fileptr[files_open] = fopen (fnamptr[files_open], "r"); + if (fileptr[files_open] == NULL) + error (EXIT_FAILURE, errno, "%s", fnamptr[files_open]); + else if (fileno (fileptr[files_open]) == 0) + opened_stdin = 1; + } + } + + fileptr[files_open] = ENDLIST; + + if (opened_stdin && have_read_stdin) + error (EXIT_FAILURE, 0, _("standard input is closed")); + + /* Read a line from each file and output it to stdout separated by a + delimiter, until we go through the loop without successfully + reading from any of the files. */ + + while (files_open) + { + /* Set up for the next line. */ + somedone = 0; + delimptr = delims; + delims_saved = 0; + + for (i = 0; fileptr[i] != ENDLIST && files_open; i++) + { + line_length = 0; /* Clear so we can easily detect EOF. */ + if (fileptr[i] != CLOSED) + { + chr = getc (fileptr[i]); + if (chr != EOF && delims_saved) + { + fwrite (delbuf, sizeof (char), delims_saved, stdout); + delims_saved = 0; + } + + while (chr != EOF) + { + line_length++; + if (chr == '\n') + break; + putc (chr, stdout); + chr = getc (fileptr[i]); + } + } + + if (line_length == 0) + { + /* EOF, read error, or closed file. + If an EOF or error, close the file and mark it in the list. */ + if (fileptr[i] != CLOSED) + { + if (ferror (fileptr[i])) + { + error (0, errno, "%s", fnamptr[i]); + errors = 1; + } + if (fileptr[i] == stdin) + clearerr (fileptr[i]); /* Also clear EOF. */ + else if (fclose (fileptr[i]) == EOF) + { + error (0, errno, "%s", fnamptr[i]); + errors = 1; + } + + fileptr[i] = CLOSED; + files_open--; + } + + if (fileptr[i + 1] == ENDLIST) + { + /* End of this output line. + Is this the end of the whole thing? */ + if (somedone) + { + /* No. Some files were not closed for this line. */ + if (delims_saved) + { + fwrite (delbuf, sizeof (char), delims_saved, stdout); + delims_saved = 0; + } + putc ('\n', stdout); + } + continue; /* Next read of files, or exit. */ + } + else + { + /* Closed file; add delimiter to `delbuf'. */ + if (*delimptr != EMPTY_DELIM) + delbuf[delims_saved++] = *delimptr; + if (++delimptr == delim_end) + delimptr = delims; + } + } + else + { + /* Some data read. */ + somedone++; + + /* Except for last file, replace last newline with delim. */ + if (fileptr[i + 1] != ENDLIST) + { + if (chr != '\n') + putc (chr, stdout); + if (*delimptr != EMPTY_DELIM) + putc (*delimptr, stdout); + if (++delimptr == delim_end) + delimptr = delims; + } + else + putc (chr, stdout); + } + } + } + return errors; +} + +/* Perform serial paste on the NFILES files named in FNAMPTR. + Return 0 if no errors, 1 if one or more files could not be + opened or read. */ + +static int +paste_serial (int nfiles, char **fnamptr) +{ + int errors = 0; /* 1 if open or read errors occur. */ + register int charnew, charold; /* Current and previous char read. */ + register char *delimptr; /* Current delimiter char. */ + register FILE *fileptr; /* Open for reading current file. */ + + for (; nfiles; nfiles--, fnamptr++) + { + if (STREQ (*fnamptr, "-")) + { + have_read_stdin = 1; + fileptr = stdin; + } + else + { + fileptr = fopen (*fnamptr, "r"); + if (fileptr == NULL) + { + error (0, errno, "%s", *fnamptr); + errors = 1; + continue; + } + } + + delimptr = delims; /* Set up for delimiter string. */ + + charold = getc (fileptr); + if (charold != EOF) + { + /* `charold' is set up. Hit it! + Keep reading characters, stashing them in `charnew'; + output `charold', converting to the appropriate delimiter + character if needed. After the EOF, output `charold' + if it's a newline; otherwise, output it and then a newline. */ + + while ((charnew = getc (fileptr)) != EOF) + { + /* Process the old character. */ + if (charold == '\n') + { + if (*delimptr != EMPTY_DELIM) + putc (*delimptr, stdout); + + if (++delimptr == delim_end) + delimptr = delims; + } + else + putc (charold, stdout); + + charold = charnew; + } + + /* Hit EOF. Process that last character. */ + putc (charold, stdout); + } + + if (charold != '\n') + putc ('\n', stdout); + + if (ferror (fileptr)) + { + error (0, errno, "%s", *fnamptr); + errors = 1; + } + if (fileptr == stdin) + clearerr (fileptr); /* Also clear EOF. */ + else if (fclose (fileptr) == EOF) + { + error (0, errno, "%s", *fnamptr); + errors = 1; + } + } + return errors; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + fputs (_("\ +Write lines consisting of the sequentially corresponding lines from\n\ +each FILE, separated by TABs, to standard output.\n\ +With no FILE, or when FILE is -, read standard input.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -d, --delimiters=LIST reuse characters from LIST instead of TABs\n\ + -s, --serial paste one file at a time instead of in parallel\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + /* FIXME: add a couple of examples. */ + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +int +main (int argc, char **argv) +{ + int optc, exit_status; + char default_delims[2], zero_delims[3]; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + have_read_stdin = 0; + serial_merge = 0; + delims = default_delims; + strcpy (delims, "\t"); + strcpy (zero_delims, "\\0"); + + while ((optc = getopt_long (argc, argv, "d:s", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + + case 'd': + /* Delimiter character(s). */ + if (optarg[0] == '\0') + optarg = zero_delims; + delims = optarg; + break; + + case 's': + serial_merge++; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (optind == argc) + argv[argc++] = "-"; + + delim_end = collapse_escapes (delims); + + if (!serial_merge) + exit_status = paste_parallel (argc - optind, &argv[optind]); + else + exit_status = paste_serial (argc - optind, &argv[optind]); + if (have_read_stdin && fclose (stdin) == EOF) + error (EXIT_FAILURE, errno, "-"); + exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/pathchk.c b/src/apps/bin/coreutils-5.0/src/pathchk.c new file mode 100644 index 0000000000..d84b4b6208 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/pathchk.c @@ -0,0 +1,387 @@ +/* pathchk -- check whether pathnames are valid or portable + Copyright (C) 1991-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Usage: pathchk [-p] [--portability] path... + + For each PATH, print a message if any of these conditions are false: + * all existing leading directories in PATH have search (execute) permission + * strlen (PATH) <= PATH_MAX + * strlen (each_directory_in_PATH) <= NAME_MAX + + Exit status: + 0 All PATH names passed all of the tests. + 1 An error occurred. + + Options: + -p, --portability Instead of performing length checks on the + underlying filesystem, test the length of the + pathname and its components against the POSIX + minimum limits for portability, _POSIX_NAME_MAX + and _POSIX_PATH_MAX in 2.9.2. Also check that + the pathname contains no character not in the + portable filename character set. + + David MacKenzie + and Jim Meyering */ + +#include +#include +#include +#include + +#include +#ifndef errno +extern int errno; +#endif + +#include "system.h" +#include "error.h" +#include "long-options.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "pathchk" + +#define AUTHORS N_ ("David MacKenzie and Jim Meyering") + +#define NEED_PATHCONF_WRAPPER 0 +#if HAVE_PATHCONF +# ifndef PATH_MAX +# define PATH_MAX_FOR(p) pathconf_wrapper ((p), _PC_PATH_MAX) +# define NEED_PATHCONF_WRAPPER 1 +# endif /* not PATH_MAX */ +# ifndef NAME_MAX +# define NAME_MAX_FOR(p) pathconf_wrapper ((p), _PC_NAME_MAX); +# undef NEED_PATHCONF_WRAPPER +# define NEED_PATHCONF_WRAPPER 1 +# endif /* not NAME_MAX */ + +#else + +# include +# ifndef PATH_MAX +# ifdef MAXPATHLEN +# define PATH_MAX MAXPATHLEN +# else /* not MAXPATHLEN */ +# define PATH_MAX _POSIX_PATH_MAX +# endif /* not MAXPATHLEN */ +# endif /* not PATH_MAX */ + +# ifndef NAME_MAX +# ifdef MAXNAMLEN +# define NAME_MAX MAXNAMLEN +# else /* not MAXNAMLEN */ +# define NAME_MAX _POSIX_NAME_MAX +# endif /* not MAXNAMLEN */ +# endif /* not NAME_MAX */ + +#endif + +#ifndef _POSIX_PATH_MAX +# define _POSIX_PATH_MAX 255 +#endif +#ifndef _POSIX_NAME_MAX +# define _POSIX_NAME_MAX 14 +#endif + +#ifndef PATH_MAX_FOR +# define PATH_MAX_FOR(p) PATH_MAX +#endif +#ifndef NAME_MAX_FOR +# define NAME_MAX_FOR(p) NAME_MAX +#endif + +static int validate_path (char *path, int portability); + +/* The name this program was run with. */ +char *program_name; + +static struct option const longopts[] = +{ + {"portability", no_argument, NULL, 'p'}, + {NULL, 0, NULL, 0} +}; + +#if NEED_PATHCONF_WRAPPER +/* Distinguish between the cases when pathconf fails and when it reports there + is no limit (the latter is the case for PATH_MAX on the Hurd). When there + is no limit, return LONG_MAX. Otherwise, return pathconf's return value. */ + +static long int +pathconf_wrapper (const char *filename, int param) +{ + long int ret; + + errno = 0; + ret = pathconf (filename, param); + if (ret < 0 && errno == 0) + return LONG_MAX; + + return ret; +} +#endif + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... NAME...\n"), program_name); + fputs (_("\ +Diagnose unportable constructs in NAME.\n\ +\n\ + -p, --portability check for all POSIX systems, not only this one\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int exit_status = 0; + int check_portability = 0; + int optc; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + while ((optc = getopt_long (argc, argv, "p", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + + case 'p': + check_portability = 1; + break; + + default: + usage (EXIT_FAILURE); + } + } + + if (optind == argc) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + for (; optind < argc; ++optind) + exit_status |= validate_path (argv[optind], check_portability); + + exit (exit_status); +} + +/* Each element is nonzero if the corresponding ASCII character is + in the POSIX portable character set, and zero if it is not. + In addition, the entry for `/' is nonzero to simplify checking. */ +static char const portable_chars[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, /* 32-47 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-63 */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 80-95 */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-127 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* If PATH contains only portable characters, return 1, else 0. */ + +static int +portable_chars_only (const char *path) +{ + const char *p; + + for (p = path; *p; ++p) + if (portable_chars[(unsigned char) *p] == 0) + { + error (0, 0, _("path `%s' contains nonportable character `%c'"), + path, *p); + return 0; + } + return 1; +} + +/* Return 1 if PATH is a usable leading directory, 0 if not, + 2 if it doesn't exist. */ + +static int +dir_ok (const char *path) +{ + struct stat stats; + + if (stat (path, &stats)) + return 2; + + if (!S_ISDIR (stats.st_mode)) + { + error (0, 0, _("`%s' is not a directory"), path); + return 0; + } + + /* Use access to test for search permission because + testing permission bits of st_mode can lose with new + access control mechanisms. Of course, access loses if you're + running setuid. */ + if (access (path, X_OK) != 0) + { + if (errno == EACCES) + error (0, 0, _("directory `%s' is not searchable"), path); + else + error (0, errno, "%s", path); + return 0; + } + + return 1; +} + +/* Make sure that + strlen (PATH) <= PATH_MAX + && strlen (each-existing-directory-in-PATH) <= NAME_MAX + + If PORTABILITY is nonzero, compare against _POSIX_PATH_MAX and + _POSIX_NAME_MAX instead, and make sure that PATH contains no + characters not in the POSIX portable filename character set, which + consists of A-Z, a-z, 0-9, ., _, -. + + Make sure that all leading directories along PATH that exist have + `x' permission. + + Return 0 if all of these tests are successful, 1 if any fail. */ + +static int +validate_path (char *path, int portability) +{ + long int path_max; + int last_elem; /* Nonzero if checking last element of path. */ + int exists IF_LINT (= 0); /* 2 if the path element exists. */ + char *slash; + char *parent; /* Last existing leading directory so far. */ + + if (portability && !portable_chars_only (path)) + return 1; + + if (*path == '\0') + return 0; + + /* Figure out the parent of the first element in PATH. */ + parent = xstrdup (*path == '/' ? "/" : "."); + + slash = path; + last_elem = 0; + while (1) + { + long int name_max; + long int length; /* Length of partial path being checked. */ + char *start; /* Start of path element being checked. */ + + /* Find the end of this element of the path. + Then chop off the rest of the path after this element. */ + while (*slash == '/') + slash++; + start = slash; + slash = strchr (slash, '/'); + if (slash != NULL) + *slash = '\0'; + else + { + last_elem = 1; + slash = strchr (start, '\0'); + } + + if (!last_elem) + { + exists = dir_ok (path); + if (exists == 0) + { + free (parent); + return 1; + } + } + + length = slash - start; + /* Since we know that `parent' is a directory, it's ok to call + pathconf with it as the argument. (If `parent' isn't a directory + or doesn't exist, the behavior of pathconf is undefined.) + But if `parent' is a directory and is on a remote file system, + it's likely that pathconf can't give us a reasonable value + and will return -1. (NFS and tempfs are not POSIX . . .) + In that case, we have no choice but to assume the pessimal + POSIX minimums. */ + name_max = portability ? _POSIX_NAME_MAX : NAME_MAX_FOR (parent); + if (name_max < 0) + name_max = _POSIX_NAME_MAX; + if (length > name_max) + { + error (0, 0, _("name `%s' has length %ld; exceeds limit of %ld"), + start, length, name_max); + free (parent); + return 1; + } + + if (last_elem) + break; + + if (exists == 1) + { + free (parent); + parent = xstrdup (path); + } + + *slash++ = '/'; + } + + /* `parent' is now the last existing leading directory in the whole path, + so it's ok to call pathconf with it as the argument. */ + path_max = portability ? _POSIX_PATH_MAX : PATH_MAX_FOR (parent); + if (path_max < 0) + path_max = _POSIX_PATH_MAX; + free (parent); + if (strlen (path) > (size_t) path_max) + { + error (0, 0, _("path `%s' has length %d; exceeds limit of %ld"), + path, strlen (path), path_max); + return 1; + } + + return 0; +} diff --git a/src/apps/bin/coreutils-5.0/src/pinky.c b/src/apps/bin/coreutils-5.0/src/pinky.c new file mode 100644 index 0000000000..c2bbd6eaba --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/pinky.c @@ -0,0 +1,585 @@ +/* GNU's pinky. + Copyright (C) 1992-1997, 1999-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Created by hacking who.c by Kaveh Ghazi ghazi@caip.rutgers.edu */ + +#include +#include +#include +#include + +#include +#include "system.h" + +#include "error.h" +#include "readutmp.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "pinky" + +#define AUTHORS N_ ("Joseph Arceneaux, David MacKenzie, and Kaveh Ghazi") + +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 64 +#endif + +#ifndef S_IWGRP +# define S_IWGRP 020 +#endif + +int gethostname (); +char *ttyname (); + +/* The name this program was run with. */ +const char *program_name; + +/* If nonzero, display the hours:minutes since each user has touched + the keyboard, or blank if within the last minute, or days followed + by a 'd' if not within the last day. */ +static int include_idle = 1; + +/* If nonzero, display a line at the top describing each field. */ +static int include_heading = 1; + +/* if nonzero, display the user's full name from pw_gecos. */ +static int include_fullname = 1; + +/* if nonzero, display the user's ~/.project file when doing long format. */ +static int include_project = 1; + +/* if nonzero, display the user's ~/.plan file when doing long format. */ +static int include_plan = 1; + +/* if nonzero, display the user's home directory and shell + when doing long format. */ +static int include_home_and_shell = 1; + +/* if nonzero, use the "short" output format. */ +static int do_short_format = 1; + +/* if nonzero, display the ut_host field. */ +#ifdef HAVE_UT_HOST +static int include_where = 1; +#endif + +static struct option const longopts[] = +{ + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +/* Count and return the number of ampersands in STR. */ + +static int +count_ampersands (const char *str) +{ + int count = 0; + do + { + if (*str == '&') + count++; + } while (*str++); + return count; +} + +/* Create a string (via xmalloc) which contains a full name by substituting + for each ampersand in GECOS_NAME the USER_NAME string with its first + character capitalized. The caller must ensure that GECOS_NAME contains + no `,'s. The caller also is responsible for free'ing the return value of + this function. */ + +static char * +create_fullname (const char *gecos_name, const char *user_name) +{ + const int result_len = strlen (gecos_name) + + count_ampersands (gecos_name) * (strlen (user_name) - 1) + 1; + char *const result = xmalloc (result_len); + char *r = result; + + while (*gecos_name) + { + if (*gecos_name == '&') + { + const char *uname = user_name; + if (ISLOWER (*uname)) + *r++ = TOUPPER (*uname++); + while (*uname) + *r++ = *uname++; + } + else + { + *r++ = *gecos_name; + } + + gecos_name++; + } + *r = 0; + + return result; +} + +/* Return a string representing the time between WHEN and the time + that this function is first run. */ + +static const char * +idle_string (time_t when) +{ + static time_t now = 0; + static char idle_hhmm[10]; + time_t seconds_idle; + + if (now == 0) + time (&now); + + seconds_idle = now - when; + if (seconds_idle < 60) /* One minute. */ + return " "; + if (seconds_idle < (24 * 60 * 60)) /* One day. */ + { + sprintf (idle_hhmm, "%02d:%02d", + (int) (seconds_idle / (60 * 60)), + (int) ((seconds_idle % (60 * 60)) / 60)); + return (const char *) idle_hhmm; + } + sprintf (idle_hhmm, "%dd", (int) (seconds_idle / (24 * 60 * 60))); + return (const char *) idle_hhmm; +} + +/* Display a line of information about UTMP_ENT. */ + +static void +print_entry (const STRUCT_UTMP *utmp_ent) +{ + struct stat stats; + time_t last_change; + char mesg; + +#define DEV_DIR_WITH_TRAILING_SLASH "/dev/" +#define DEV_DIR_LEN (sizeof (DEV_DIR_WITH_TRAILING_SLASH) - 1) + + char line[sizeof (utmp_ent->ut_line) + DEV_DIR_LEN + 1]; + time_t tm; + + /* Copy ut_line into LINE, prepending `/dev/' if ut_line is not + already an absolute pathname. Some system may put the full, + absolute pathname in ut_line. */ + if (utmp_ent->ut_line[0] == '/') + { + strncpy (line, utmp_ent->ut_line, sizeof (utmp_ent->ut_line)); + line[sizeof (utmp_ent->ut_line)] = '\0'; + } + else + { + strcpy (line, DEV_DIR_WITH_TRAILING_SLASH); + strncpy (line + DEV_DIR_LEN, utmp_ent->ut_line, sizeof (utmp_ent->ut_line)); + line[DEV_DIR_LEN + sizeof (utmp_ent->ut_line)] = '\0'; + } + + if (stat (line, &stats) == 0) + { + mesg = (stats.st_mode & S_IWGRP) ? ' ' : '*'; + last_change = stats.st_atime; + } + else + { + mesg = '?'; + last_change = 0; + } + + printf ("%-8.*s", (int) sizeof (UT_USER (utmp_ent)), UT_USER (utmp_ent)); + + if (include_fullname) + { + struct passwd *pw; + char name[sizeof (UT_USER (utmp_ent)) + 1]; + + strncpy (name, UT_USER (utmp_ent), sizeof (UT_USER (utmp_ent))); + name[sizeof (UT_USER (utmp_ent))] = '\0'; + pw = getpwnam (name); + if (pw == NULL) + printf (" %19s", " ???"); + else + { + char *const comma = strchr (pw->pw_gecos, ','); + char *result; + + if (comma) + *comma = '\0'; + + result = create_fullname (pw->pw_gecos, pw->pw_name); + printf (" %-19.19s", result); + free (result); + } + } + + printf (" %c%-8.*s", + mesg, (int) sizeof (utmp_ent->ut_line), utmp_ent->ut_line); + + if (include_idle) + { + if (last_change) + printf (" %-6s", idle_string (last_change)); + else + printf (" %-6s", "???"); + } + + /* Don't take the address of UT_TIME_MEMBER directly. + Ulrich Drepper wrote: + ``... GNU libc (and perhaps other libcs as well) have extended + utmp file formats which do not use a simple time_t ut_time field. + In glibc, ut_time is a macro which selects for backward compatibility + the tv_sec member of a struct timeval value.'' */ + tm = UT_TIME_MEMBER (utmp_ent); + printf (" %-12.12s", ctime (&tm) + 4); + +#ifdef HAVE_UT_HOST + if (include_where && utmp_ent->ut_host[0]) + { + extern char *canon_host (); + char ut_host[sizeof (utmp_ent->ut_host) + 1]; + char *host = 0, *display = 0; + + /* Copy the host name into UT_HOST, and ensure it's nul terminated. */ + strncpy (ut_host, utmp_ent->ut_host, (int) sizeof (utmp_ent->ut_host)); + ut_host[sizeof (utmp_ent->ut_host)] = '\0'; + + /* Look for an X display. */ + display = strrchr (ut_host, ':'); + if (display) + *display++ = '\0'; + + if (*ut_host) + /* See if we can canonicalize it. */ + host = canon_host (ut_host); + if ( ! host) + host = ut_host; + + if (display) + printf (" %s:%s", host, display); + else + printf (" %s", host); + } +#endif + + putchar ('\n'); +} + +/* Display a verbose line of information about UTMP_ENT. */ + +static void +print_long_entry (const char name[]) +{ + struct passwd *pw; + + pw = getpwnam (name); + + printf (_("Login name: ")); + printf ("%-28s", name); + + printf (_("In real life: ")); + if (pw == NULL) + { + printf (" %s", _("???\n")); + return; + } + else + { + char *const comma = strchr (pw->pw_gecos, ','); + char *result; + + if (comma) + *comma = '\0'; + + result = create_fullname (pw->pw_gecos, pw->pw_name); + printf (" %s", result); + free (result); + } + + putchar ('\n'); + + if (include_home_and_shell) + { + printf (_("Directory: ")); + printf ("%-29s", pw->pw_dir); + printf (_("Shell: ")); + printf (" %s", pw->pw_shell); + putchar ('\n'); + } + + if (include_project) + { + FILE *stream; + char buf[1024]; + const char *const baseproject = "/.project"; + char *const project = + xmalloc (strlen (pw->pw_dir) + strlen (baseproject) + 1); + + strcpy (project, pw->pw_dir); + strcat (project, baseproject); + + stream = fopen (project, "r"); + if (stream) + { + size_t bytes; + + printf (_("Project: ")); + + while ((bytes = fread (buf, 1, sizeof (buf), stream)) > 0) + fwrite (buf, 1, bytes, stdout); + fclose (stream); + } + + free (project); + } + + if (include_plan) + { + FILE *stream; + char buf[1024]; + const char *const baseplan = "/.plan"; + char *const plan = + xmalloc (strlen (pw->pw_dir) + strlen (baseplan) + 1); + + strcpy (plan, pw->pw_dir); + strcat (plan, baseplan); + + stream = fopen (plan, "r"); + if (stream) + { + size_t bytes; + + printf (_("Plan:\n")); + + while ((bytes = fread (buf, 1, sizeof (buf), stream)) > 0) + fwrite (buf, 1, bytes, stdout); + fclose (stream); + } + + free (plan); + } + + putchar ('\n'); +} + +/* Print the username of each valid entry and the number of valid entries + in UTMP_BUF, which should have N elements. */ + +static void +print_heading (void) +{ + printf ("%-8s", _("Login")); + if (include_fullname) + printf (" %-19s", _("Name")); + printf (" %-9s", _(" TTY")); + if (include_idle) + printf (" %-6s", _("Idle")); + printf (" %-12s", _("When")); +#ifdef HAVE_UT_HOST + if (include_where) + printf (" %s", _("Where")); +#endif + putchar ('\n'); +} + +/* Display UTMP_BUF, which should have N entries. */ + +static void +scan_entries (int n, const STRUCT_UTMP *utmp_buf, + const int argc_names, char *const argv_names[]) +{ + if (include_heading) + print_heading (); + + while (n--) + { + if (UT_USER (utmp_buf)[0] +#ifdef USER_PROCESS + && utmp_buf->ut_type == USER_PROCESS +#endif + ) + { + if (argc_names) + { + int i; + + for (i = 0; i < argc_names; i++) + if (strncmp (UT_USER (utmp_buf), argv_names[i], + sizeof (UT_USER (utmp_buf))) == 0) + { + print_entry (utmp_buf); + break; + } + } + else + print_entry (utmp_buf); + } + utmp_buf++; + } +} + +/* Display a list of who is on the system, according to utmp file FILENAME. */ + +static void +short_pinky (const char *filename, + const int argc_names, char *const argv_names[]) +{ + int n_users; + STRUCT_UTMP *utmp_buf; + int fail = read_utmp (filename, &n_users, &utmp_buf); + + if (fail) + error (EXIT_FAILURE, errno, "%s", filename); + + scan_entries (n_users, utmp_buf, argc_names, argv_names); +} + +static void +long_pinky (const int argc_names, char *const argv_names[]) +{ + int i; + + for (i = 0; i < argc_names; i++) + print_long_entry (argv_names[i]); +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [USER]...\n"), program_name); + fputs (_("\ +\n\ + -l produce long format output for the specified USERs\n\ + -b omit the user's home directory and shell in long format\n\ + -h omit the user's project file in long format\n\ + -p omit the user's plan file in long format\n\ + -s do short format output, this is the default\n\ +"), stdout); + fputs (_("\ + -f omit the line of column headings in short format\n\ + -w omit the user's full name in short format\n\ + -i omit the user's full name and remote host in short format\n\ + -q omit the user's full name, remote host and idle time\n\ + in short format\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\ +\n\ +A lightweight `finger' program; print user information.\n\ +The utmp file will be %s.\n\ +"), UTMP_FILE); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int optc, longind; + int n_users; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + while ((optc = getopt_long (argc, argv, "sfwiqbhlp", longopts, &longind)) + != -1) + { + switch (optc) + { + case 0: + break; + + case 's': + do_short_format = 1; + break; + + case 'l': + do_short_format = 0; + break; + + case 'f': + include_heading = 0; + break; + + case 'w': + include_fullname = 0; + break; + + case 'i': + include_fullname = 0; +#ifdef HAVE_UT_HOST + include_where = 0; +#endif + break; + + case 'q': + include_fullname = 0; +#ifdef HAVE_UT_HOST + include_where = 0; +#endif + include_idle = 0; + break; + + case 'h': + include_project = 0; + break; + + case 'p': + include_plan = 0; + break; + + case 'b': + include_home_and_shell = 0; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + n_users = argc - optind; + + if (do_short_format == 0 && n_users == 0) + { + error (0, 0, _("no username specified; at least one must be\ + specified when using -l")); + usage (EXIT_FAILURE); + } + + if (do_short_format) + short_pinky (UTMP_FILE, n_users, argv + optind); + else + long_pinky (n_users, argv + optind); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/pr.c b/src/apps/bin/coreutils-5.0/src/pr.c new file mode 100644 index 0000000000..13d5d7eaeb --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/pr.c @@ -0,0 +1,2865 @@ +/* pr -- convert text files for printing. + Copyright (C) 88, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* By Pete TerMaat, with considerable refinement by Roland Huebner. */ + +/* Things to watch: Sys V screws up on ... + pr -n -3 -s: /usr/dict/words + pr -m -o10 -n /usr/dict/words{,,,} + pr -6 -a -n -o5 /usr/dict/words + + Ideas: + + Keep a things_to_do list of functions to call when we know we have + something to print. Cleaner than current series of checks. + + Improve the printing of control prefixes. + + Expand the filename in the centered header line to a full pathname. + + + Concept: + + If the input_tab_char differs from the default value TAB + (`-e[CHAR[...]]' is used), any input text tab is expanded to the + default width of 8 spaces (compare char_to_clump). - Same as SunOS + does. + + The treatment of the number_separator (compare add_line_number): + The default value TAB of the number_separator (`-n[SEP[...]]') doesn't + be thought to be an input character. An optional `-e'-input has no + effect. + - With single column output + only one POSIX requirement has to be met: + The default n-separator should be a TAB. The consequence is a + different width between the number and the text if the output position + of the separator changes, i.e. it depends upon the left margin used. + That's not nice but easy-to-use together with the defaults of other + utilities, e.g. sort or cut. - Same as SunOS does. + - With multicolumn output + two conflicting POSIX requirements exist: + First `default n-separator is TAB', second `output text columns shall + be of equal width'. Moreover POSIX specifies the number+separator a + part of the column, together with `-COLUMN' and `-a -COLUMN'. + (With -m output the number shall occupy each line only once. Exactly + the same situation as single column output exists.) + GNU pr gives priority to the 2nd requirement and observes POSIX + column definition. The n-separator TAB is expanded to the same number + of spaces in each column using the default value 8. Tabification is + only performed if it is compatible with the output position. + Consequence: The output text columns are of equal width. The layout + of a page does not change if the left margin varies. - Looks better + than the SunOS approach. + SunOS pr gives priority to the 1st requirement. n-separator TAB + width varies with each column. Only the width of text part of the + column is fixed. + Consequence: The output text columns don't have equal width. The + widths and the layout of the whole page varies with the left margin. + An overflow of the line length (without margin) over the input value + PAGE_WIDTH may occur. + + The interference of the POSIX-compliant small letter options -w and -s: + (`interference' means `setting a _separator_ with -s switches off the + column sturctur and the default - not generally - page_width, + acts on -w option') + options: text form / separator: equivalent new options: + -w l -s[x] + -------------------------------------------------------------------- + 1. -- -- columns / space -- + trunc. to page_width = 72 + 2. -- -s[:] full lines / TAB[:] -J --sep-string[=""|:] + no truncation + 3. -w l -- columns / space -W l + trunc. to page_width = l + 4. -w l -s[:] columns / no sep.[:] -W l --sep-string[=:] + trunc. to page_width = l + -------------------------------------------------------------------- + + + Options: + + Including version 1.22i: + Some SMALL LETTER options has been redefined with the object of a + better POSIX compliance. The output of some further cases has been + adapted to other UNIXes. A violation of downward compatibility has to + be accepted. + Some NEW CAPITAL LETTER options ( -J, -S, -W) has been introduced to + turn off unexpected interferences of small letter options (-s and -w + together with the three column options). + -N option and the second argument LAST_PAGE of +FIRST_PAGE offer more + flexibility; The detailed handling of form feeds set in the input + files requires -T option. + + Capital letter options dominate small letter ones. + + Some of the option-arguments cannot be specified as separate arguments + from the preceding option letter (already stated in POSIX specification). + + Form feeds in the input cause page breaks in the output. Multiple + form feeds produce empty pages. + + +FIRST_PAGE[:LAST_PAGE], --pages=FIRST_PAGE[:LAST_PAGE] + begin [stop] printing with page FIRST_[LAST_]PAGE + + -COLUMN, --columns=COLUMN + Produce output that is COLUMN columns wide and + print columns down, unless -a is used. Balance number of + lines in the columns on each page. + + -a, --across Print columns across rather than down, used + together with -COLUMN. The input + one + two + three + four + will be printed with `-a -3' as + one two three + four + + -b Balance columns on the last page. + -b is no longer an independent option. It's always used + together with -COLUMN (unless -a is used) to get a + consistent formulation with "FF set by hand" in input + files. Each formfeed found terminates the number of lines + to be read with the actual page. The situation for + printing columns down is equivalent to that on the last + page. So we need a balancing. + + Keeping -b as an underground option guarantees some + downward compatibility. Utilities using pr with -b + (a most frequently used form) still work as usual. + + -c, --show-control-chars + Print unprintable characters as control prefixes. + Control-g is printed as ^G (use hat notation) and + octal backslash notation. + + -d, --double-space Double space the output. + + -D FORMAT, --date-format=FORMAT Use FORMAT for the header date. + + -e[CHAR[WIDTH]], --expand-tabs[=CHAR[WIDTH]] + Expand tabs to spaces on input. Optional argument CHAR + is the input TAB character. (Default is TAB). Optional + argument WIDTH is the input TAB character's width. + (Default is 8.) + + -F, -f, --form-feed Use formfeeds instead of newlines to separate + pages. A three line HEADER is used, no TRAILER with -F, + without -F both HEADER and TRAILER are made of five lines. + + -h HEADER, --header=HEADER + Replace the filename in the header with the string HEADER. + A centered header is used. + + -i[CHAR[WIDTH]], --output-tabs[=CHAR[WIDTH]] + Replace spaces with tabs on output. Optional argument + CHAR is the output TAB character. (Default is TAB). + Optional argument WIDTH is the output TAB character's + width. (Default is 8) + + -J, --join-lines Merge lines of full length, turns off -W/-w + line truncation, no column alignment, --sep-string[=STRING] + sets separators, works with all column options + (-COLUMN | -a -COLUMN | -m). + -J has been introduced (together with -W and --sep-string) to + disentangle the old (POSIX compliant) options -w, -s + along with the 3 column options. + + -l PAGE_LENGTH, --length=PAGE_LENGTH + Set the page length to PAGE_LENGTH lines. Default is 66, + including 5 lines of HEADER and 5 lines of TRAILER + without -F, but only 3 lines of HEADER and no TRAILER + with -F (i.e the number of text lines defaults to 56 or + 63 respectively). + + -m, --merge Print files in parallel; pad_across_to align + columns; truncate lines and print separator strings; + Do it also with empty columns to get a continuous line + numbering and column marking by separators throughout + the whole merged file. + + Empty pages in some input files produce empty columns + [marked by separators] in the merged pages. Completely + empty merged pages show no column separators at all. + + The layout of a merged page is ruled by the largest form + feed distance of the single pages at that page. Shorter + columns will be filled up with empty lines. + + Together with -J option join lines of full length and + set separators when -S option is used. + + -n[SEP[DIGITS]], --number-lines[=SEP[DIGITS]] + Provide DIGITS digit line numbering (default for DIGITS + is 5). With multicolumn output the number occupies the + first DIGITS column positions of each text column or only + each line of -m output. + With single column output the number precedes each line + just as -m output. + Optional argument SEP is the character appended to the + line number to separate it from the text followed. + The default separator is a TAB. In a strict sense a TAB + is always printed with single column output only. The + TAB-width varies with the TAB-position, e.g. with the + left margin specified by -o option. + With multicolumn output priority is given to `equal width + of output columns' (a POSIX specification). The TAB-width + is fixed to the value of the 1st column and does not + change with different values of left margin. That means a + fixed number of spaces is always printed in the place of + a TAB. The tabification depends upon the output + position. + + Default counting of the line numbers starts with 1st + line of the input file (not the 1st line printed, + compare the --page option and -N option). + + -N NUMBER, --first-line-number=NUMBER + Start line counting with the number NUMBER at the 1st + line of first page printed (mostly not the 1st line of + the input file). + + -o MARGIN, --indent=MARGIN + Offset each line with a margin MARGIN spaces wide. + Total page width is the size of the margin plus the + PAGE_WIDTH set with -W/-w option. + + -r, --no-file-warnings + Omit warning when a file cannot be opened. + + -s[CHAR], --separator[=CHAR] + Separate columns by a single character CHAR, default for + CHAR is the TAB character without -w and 'no char' with -w. + Without `-s' default separator `space' is set. + -s[CHAR] turns off line truncation of all 3 column options + (-COLUMN|-a -COLUMN|-m) except -w is set. That is a POSIX + compliant formulation. The source code translates -s into + the new options -S and -J, also -W if required. + + -S STRING, --sep-string[=STRING] + Separate columns by any string STRING. The -S option + doesn't react upon the -W/-w option (unlike -s option + does). It defines a separator nothing else. + Without -S: Default separator TAB is used with -J and + `space' otherwise (same as -S" "). + With -S "": No separator is used. + Quotes should be used with blanks and some shell active + characters. + -S is problematic because in its obsolete form you + cannot use -S "STRING", but in its standard form you + must use -S "STRING" if STRING is empty. Use + --sep-string to avoid the ambiguity. + + -t, --omit-header Do not print headers or footers but retain form + feeds set in the input files. + + -T, --omit-pagination + Do not print headers or footers, eliminate any pagination + by form feeds set in the input files. + + -v, --show-nonprinting + Print unprintable characters as escape sequences. Use + octal backslash notation. Control-G becomes \007. + + -w PAGE_WIDTH, --width=PAGE_WIDTH + Set page width to PAGE_WIDTH characters for multiple + text-column output only (default for PAGE_WIDTH is 72). + -s[CHAR] turns off the default page width and any line + truncation. Lines of full length will be merged, + regardless of the column options set. A POSIX compliant + formulation. + + -W PAGE_WIDTH, --page-width=PAGE_WIDTH + Set the page width to PAGE_WIDTH characters. That's valid + with and without a column option. Text lines will be + truncated, unless -J is used. Together with one of the + column options (-COLUMN| -a -COLUMN| -m) column alignment + is always used. + Default is 72 characters. + Without -W PAGE_WIDTH + - but with one of the column options default truncation of + 72 characters is used (to keep downward compatibility + and to simplify most frequently met column tasks). + Column alignment and column separators are used. + - and without any of the column options NO line truncation + is used (to keep downward compatibility and to meet most + frequent tasks). That's equivalent to -W 72 -J . + + With/without -W PAGE_WIDTH the header line is always + truncated to avoid line overflow. + + (In pr versions newer than 1.14 -S option does no longer + affect -W option.) + +*/ + + +#include + +#include +#include +#include +#include +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "mbswidth.h" +#include "posixver.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "pr" + +#define AUTHORS N_ ("Pete TerMaat and Roland Huebner") + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif + +/* Used with start_position in the struct COLUMN described below. + If start_position == ANYWHERE, we aren't truncating columns and + can begin printing a column anywhere. Otherwise we must pad to + the horizontal position start_position. */ +#define ANYWHERE 0 + +/* Each column has one of these structures allocated for it. + If we're only dealing with one file, fp is the same for all + columns. + + The general strategy is to spend time setting up these column + structures (storing columns if necessary), after which printing + is a matter of flitting from column to column and calling + print_func. + + Parallel files, single files printing across in multiple + columns, and single files printing down in multiple columns all + fit the same printing loop. + + print_func Function used to print lines in this column. + If we're storing this column it will be + print_stored(), Otherwise it will be read_line(). + + char_func Function used to process characters in this column. + If we're storing this column it will be store_char(), + otherwise it will be print_char(). + + current_line Index of the current entry in line_vector, which + contains the index of the first character of the + current line in buff[]. + + lines_stored Number of lines in this column which are stored in + buff. + + lines_to_print If we're storing this column, lines_to_print is + the number of stored_lines which remain to be + printed. Otherwise it is the number of lines + we can print without exceeding lines_per_body. + + start_position The horizontal position we want to be in before we + print the first character in this column. + + numbered True means precede this column with a line number. */ + +struct COLUMN; +struct COLUMN + { + FILE *fp; /* Input stream for this column. */ + char const *name; /* File name. */ + enum + { + OPEN, + FF_FOUND, /* used with -b option, set with \f, changed + to ON_HOLD after print_header */ + ON_HOLD, /* Hit a form feed. */ + CLOSED + } + status; /* Status of the file pointer. */ + + /* Func to print lines in this col. */ + int (*print_func) (struct COLUMN *); + + /* Func to print/store chars in this col. */ + void (*char_func) (int); + + int current_line; /* Index of current place in line_vector. */ + int lines_stored; /* Number of lines stored in buff. */ + int lines_to_print; /* No. lines stored or space left on page. */ + int start_position; /* Horizontal position of first char. */ + int numbered; + int full_page_printed; /* True means printed without a FF found. */ + + /* p->full_page_printed controls a special case of "FF set by hand": + True means a full page has been printed without FF found. To avoid an + additional empty page we have to ignore a FF immediately following in + the next line. */ + }; + +typedef struct COLUMN COLUMN; + +#define NULLCOL (COLUMN *)0 + +static int char_to_clump (int c); +static int read_line (COLUMN *p); +static int print_page (void); +static int print_stored (COLUMN *p); +static int open_file (char *name, COLUMN *p); +static int skip_to_page (int page); +static void print_header (void); +static void pad_across_to (int position); +static void add_line_number (COLUMN *p); +static void getoptarg (char *arg, char switch_char, char *character, + int *number); +void usage (int status); +static void print_files (int number_of_files, char **av); +static void init_parameters (int number_of_files); +static void init_header (char *filename, int desc); +static int init_fps (int number_of_files, char **av); +static void init_funcs (void); +static void init_store_cols (void); +static void store_columns (void); +static void balance (int total_stored); +static void store_char (int c); +static void pad_down (int lines); +static void read_rest_of_line (COLUMN *p); +static void skip_read (COLUMN *p, int column_number); +static void print_char (int c); +static void cleanup (void); +static void first_last_page (char *pages); +static void print_sep_string (void); +static void separator_string (const char *optarg_S); + +/* The name under which this program was invoked. */ +char *program_name; + +/* All of the columns to print. */ +static COLUMN *column_vector; + +/* When printing a single file in multiple downward columns, + we store the leftmost columns contiguously in buff. + To print a line from buff, get the index of the first character + from line_vector[i], and print up to line_vector[i + 1]. */ +static char *buff; + +/* Index of the position in buff where the next character + will be stored. */ +static int buff_current; + +/* The number of characters in buff. + Used for allocation of buff and to detect overflow of buff. */ +static int buff_allocated; + +/* Array of indices into buff. + Each entry is an index of the first character of a line. + This is used when storing lines to facilitate shuffling when + we do column balancing on the last page. */ +static int *line_vector; + +/* Array of horizonal positions. + For each line in line_vector, end_vector[line] is the horizontal + position we are in after printing that line. We keep track of this + so that we know how much we need to pad to prepare for the next + column. */ +static int *end_vector; + +/* (-m) True means we're printing multiple files in parallel. */ +static int parallel_files = FALSE; + +/* (-m) True means a line starts with some empty columns (some files + already CLOSED or ON_HOLD) which we have to align. */ +static int align_empty_cols; + +/* (-m) True means we have not yet found any printable column in a line. + align_empty_cols = TRUE has to be maintained. */ +static int empty_line; + +/* (-m) False means printable column output precedes a form feed found. + Column alignment is done only once. No additional action with that form + feed. + True means we found only a form feed in a column. Maybe we have to do + some column alignment with that form feed. */ +static int FF_only; + +/* (-[0-9]+) True means we're given an option explicitly specifying + number of columns. Used to detect when this option is used with -m + and when translating old options to new/long options. */ +static int explicit_columns = FALSE; + +/* (-t|-T) False means we aren't printing headers and footers. */ +static int extremities = TRUE; + +/* (-t) True means we retain all FF set by hand in input files. + False is set with -T option. */ +static int keep_FF = FALSE; +static int print_a_FF = FALSE; + +/* True means we need to print a header as soon as we know we've got input + to print after it. */ +static int print_a_header; + +/* (-f) True means use formfeeds instead of newlines to separate pages. */ +static int use_form_feed = FALSE; + +/* True means we have read the standard input. */ +static int have_read_stdin = FALSE; + +/* True means the -a flag has been given. */ +static int print_across_flag = FALSE; + +/* True means we're printing one file in multiple (>1) downward columns. */ +static int storing_columns = TRUE; + +/* (-b) True means balance columns on the last page as Sys V does. */ +/* That's no longer an independent option. With storing_columns = TRUE + balance_columns = TRUE is used too (s. function init_parameters). + We get a consistent formulation with "FF set by hand" in input files. */ +static int balance_columns = FALSE; + +/* (-l) Number of lines on a page, including header and footer lines. */ +static int lines_per_page = 66; + +/* Number of lines in the header and footer can be reset to 0 using + the -t flag. */ +static int lines_per_header = 5; +static int lines_per_body; +static int lines_per_footer = 5; + +/* (-w|-W) Width in characters of the page. Does not include the width of + the margin. */ +static int chars_per_line = 72; + +/* (-w|W) True means we truncate lines longer than chars_per_column. */ +static int truncate_lines = FALSE; + +/* (-J) True means we join lines without any line truncation. -J + dominates -w option. */ +static int join_lines = FALSE; + +/* Number of characters in a column. Based on col_sep_length and + page width. */ +static int chars_per_column; + +/* (-e) True means convert tabs to spaces on input. */ +static int untabify_input = FALSE; + +/* (-e) The input tab character. */ +static char input_tab_char = '\t'; + +/* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ... + where the leftmost column is 1. */ +static int chars_per_input_tab = 8; + +/* (-i) True means convert spaces to tabs on output. */ +static int tabify_output = FALSE; + +/* (-i) The output tab character. */ +static char output_tab_char = '\t'; + +/* (-i) The width of the output tab. */ +static int chars_per_output_tab = 8; + +/* Keeps track of pending white space. When we hit a nonspace + character after some whitespace, we print whitespace, tabbing + if necessary to get to output_position + spaces_not_printed. */ +static int spaces_not_printed; + +/* (-o) Number of spaces in the left margin (tabs used when possible). */ +static int chars_per_margin = 0; + +/* Position where the next character will fall. + Leftmost position is 0 + chars_per_margin. + Rightmost position is chars_per_margin + chars_per_line - 1. + This is important for converting spaces to tabs on output. */ +static int output_position; + +/* Horizontal position relative to the current file. + (output_position depends on where we are on the page; + input_position depends on where we are in the file.) + Important for converting tabs to spaces on input. */ +static int input_position; + +/* Count number of failed opens so we can exit with nonzero + status if there were any. */ +static int failed_opens = 0; + +/* The number of spaces taken up if we print a tab character with width + c_ from position h_. */ +#define TAB_WIDTH(c_, h_) ((c_) - ((h_) % (c_))) + +/* The horizontal position we'll be at after printing a tab character + of width c_ from the position h_. */ +#define POS_AFTER_TAB(c_, h_) ((h_) + TAB_WIDTH (c_, h_)) + +/* (-NNN) Number of columns of text to print. */ +static int columns = 1; + +/* (+NNN:MMM) Page numbers on which to begin and stop printing. + first_page_number = 0 will be used to check input only. */ +static int first_page_number = 0; +static int last_page_number = 0; + +/* Number of files open (not closed, not on hold). */ +static int files_ready_to_read = 0; + +/* Current page number. Displayed in header. */ +static int page_number; + +/* Current line number. Displayed when -n flag is specified. + + When printing files in parallel (-m flag), line numbering is as follows: + 1 foo goo moo + 2 hoo too zoo + + When printing files across (-a flag), ... + 1 foo 2 moo 3 goo + 4 hoo 5 too 6 zoo + + Otherwise, line numbering is as follows: + 1 foo 3 goo 5 too + 2 moo 4 hoo 6 zoo */ +static int line_number; + +/* With line_number overflow, we use power_10 to cut off the higher-order + digits of the line_number */ +static int power_10; + +/* (-n) True means lines should be preceded by numbers. */ +static int numbered_lines = FALSE; + +/* (-n) Character which follows each line number. */ +static char number_separator = '\t'; + +/* (-n) line counting starts with 1st line of input file (not with 1st + line of 1st page printed). */ +static int line_count = 1; + +/* (-n) True means counting of skipped lines starts with 1st line of + input file. False means -N option is used in addition, counting of + skipped lines not required. */ +static int skip_count = TRUE; + +/* (-N) Counting starts with start_line_number = NUMBER at 1st line of + first page printed, usually not 1st page of input file. */ +static int start_line_num = 1; + +/* (-n) Width in characters of a line number. */ +static int chars_per_number = 5; + +/* Used when widening the first column to accommodate numbers -- only + needed when printing files in parallel. Includes width of both the + number and the number_separator. */ +static int number_width; + +/* Buffer sprintf uses to format a line number. */ +static char *number_buff; + +/* (-v) True means unprintable characters are printed as escape sequences. + control-g becomes \007. */ +static int use_esc_sequence = FALSE; + +/* (-c) True means unprintable characters are printed as control prefixes. + control-g becomes ^G. */ +static int use_cntrl_prefix = FALSE; + +/* (-d) True means output is double spaced. */ +static int double_space = FALSE; + +/* Number of files opened initially in init_files. Should be 1 + unless we're printing multiple files in parallel. */ +static int total_files = 0; + +/* (-r) True means don't complain if we can't open a file. */ +static int ignore_failed_opens = FALSE; + +/* (-S) True means we separate columns with a specified string. + -S option does not affect line truncation nor column alignment. */ +static int use_col_separator = FALSE; + +/* String used to separate columns if the -S option has been specified. + Default without -S but together with one of the column options + -a|COLUMN|-m is a `space' and with the -J option a `tab'. */ +static char *col_sep_string = ""; +static int col_sep_length = 0; +static char *column_separator = " "; +static char *line_separator = "\t"; + +/* Number of separator characters waiting to be printed as soon as we + know that we have any input remaining to be printed. */ +static int separators_not_printed; + +/* Position we need to pad to, as soon as we know that we have input + remaining to be printed. */ +static int padding_not_printed; + +/* True means we should pad the end of the page. Remains false until we + know we have a page to print. */ +static int pad_vertically; + +/* (-h) String of characters used in place of the filename in the header. */ +static char *custom_header; + +/* (-D) Date format for the header. */ +static char const *date_format; + +/* Date and file name for the header. */ +static char *date_text; +static char const *file_text; + +/* Output columns available, not counting the date and file name. */ +static int header_width_available; + +static int *clump_buff; + +/* True means we read the line no. lines_per_body in skip_read + called by skip_to_page. That variable controls the coincidence of a + "FF set by hand" and "full_page_printed", see above the definition of + structure COLUMN. */ +static int last_line = FALSE; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + COLUMNS_OPTION = CHAR_MAX + 1, + PAGES_OPTION +}; + +#define COMMON_SHORT_OPTIONS \ + "-0123456789D:FJN:TW:abcde::fh:i::l:mn::o:rs::tvw:" + +static struct option const long_options[] = +{ + {"pages", required_argument, NULL, PAGES_OPTION}, + {"columns", required_argument, NULL, COLUMNS_OPTION}, + {"across", no_argument, NULL, 'a'}, + {"show-control-chars", no_argument, NULL, 'c'}, + {"double-space", no_argument, NULL, 'd'}, + {"date-format", required_argument, NULL, 'D'}, + {"expand-tabs", optional_argument, NULL, 'e'}, + {"form-feed", no_argument, NULL, 'f'}, + {"header", required_argument, NULL, 'h'}, + {"output-tabs", optional_argument, NULL, 'i'}, + {"join-lines", no_argument, NULL, 'J'}, + {"length", required_argument, NULL, 'l'}, + {"merge", no_argument, NULL, 'm'}, + {"number-lines", optional_argument, NULL, 'n'}, + {"first-line-number", required_argument, NULL, 'N'}, + {"indent", required_argument, NULL, 'o'}, + {"no-file-warnings", no_argument, NULL, 'r'}, + {"separator", optional_argument, NULL, 's'}, + {"sep-string", optional_argument, NULL, 'S'}, + {"omit-header", no_argument, NULL, 't'}, + {"omit-pagination", no_argument, NULL, 'T'}, + {"show-nonprinting", no_argument, NULL, 'v'}, + {"width", required_argument, NULL, 'w'}, + {"page-width", required_argument, NULL, 'W'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0} +}; + +/* Return the number of columns that have either an open file or + stored lines. */ + +static int +cols_ready_to_print (void) +{ + COLUMN *q; + int i; + int n; + + n = 0; + for (q = column_vector, i = 0; i < columns; ++q, ++i) + if (q->status == OPEN || + q->status == FF_FOUND || /* With -b: To print a header only */ + (storing_columns && q->lines_stored > 0 && q->lines_to_print > 0)) + ++n; + return n; +} + +/* Estimate first_ / last_page_number + using option +FIRST_PAGE:LAST_PAGE */ + +static void +first_last_page (char *pages) +{ + char *str1; + + if (*pages == ':') + { + error (0, 0, _("`--pages' invalid range of page numbers: `%s'"), pages); + usage (2); + } + + str1 = strchr (pages, ':'); + if (str1 != NULL) + *str1 = '\0'; + + { + long int tmp_long; + if (xstrtol (pages, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long < 1 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, _("`--pages' invalid starting page number: `%s'"), + pages); + first_page_number = (int) tmp_long; + } + + if (str1 == NULL) + return; + + { + long int tmp_long; + if (xstrtol (str1 + 1, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long <= 0 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, _("`--pages' invalid ending page number: `%s'"), + str1 + 1); + last_page_number = (int) tmp_long; + } + + if (first_page_number > last_page_number) + error (EXIT_FAILURE, 0, + _("`--pages' starting page number is larger than ending page number")); +} + +/* Estimate length of col_sep_string with option -S. */ + +static void +separator_string (const char *optarg_S) +{ + col_sep_length = (int) strlen (optarg_S); + col_sep_string = (char *) xmalloc (col_sep_length + 1); + strcpy (col_sep_string, optarg_S); +} + +int +main (int argc, char **argv) +{ + int c; + int accum = 0; + int n_files; + int old_options = FALSE; + int old_w = FALSE; + int old_s = FALSE; + char **file_names; + char const *short_options = (posix2_version () < 200112 + ? COMMON_SHORT_OPTIONS "S::" + : COMMON_SHORT_OPTIONS "S:"); + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + n_files = 0; + file_names = (argc > 1 + ? (char **) xmalloc ((argc - 1) * sizeof (char *)) + : NULL); + + while ((c = getopt_long (argc, argv, short_options, long_options, NULL)) + != -1) + { + if (ISDIGIT (c)) + { + accum = accum * 10 + c - '0'; + columns = accum; + explicit_columns = TRUE; + continue; + } + + if (accum > 0) /* reset for subsequent params */ + accum = 0; + + switch (c) + { + case 0: /* getopt long option */ + break; + + case 1: /* Non-option argument. */ + if (*optarg == '+') + { + /* long option --page dominates old `+FIRST_PAGE ...' */ + if (first_page_number <= 0 && last_page_number <= 0) + first_last_page (optarg); + } + else + file_names[n_files++] = optarg; + break; + + case PAGES_OPTION: /* --pages=FIRST_PAGE[:LAST_PAGE] */ + { /* dominates old opt +... */ + if (optarg) + first_last_page (optarg); + else + error (EXIT_FAILURE, 0, + _("`--pages=FIRST_PAGE[:LAST_PAGE]' missing argument")); + break; + } + + case COLUMNS_OPTION: /* --columns=COLUMN */ + { + long int tmp_long; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long <= 0 || tmp_long > INT_MAX) + { + error (EXIT_FAILURE, 0, + _("`--columns=COLUMN' invalid number of columns: `%s'"), + optarg); + } + columns = (int) tmp_long; + break; + } + + case 'a': + print_across_flag = TRUE; + storing_columns = FALSE; + break; + case 'b': + balance_columns = TRUE; + break; + case 'c': + use_cntrl_prefix = TRUE; + break; + case 'd': + double_space = TRUE; + break; + case 'D': + date_format = optarg; + break; + case 'e': + if (optarg) + getoptarg (optarg, 'e', &input_tab_char, + &chars_per_input_tab); + /* Could check tab width > 0. */ + untabify_input = TRUE; + break; + case 'f': + case 'F': + use_form_feed = TRUE; + break; + case 'h': + custom_header = optarg; + break; + case 'i': + if (optarg) + getoptarg (optarg, 'i', &output_tab_char, + &chars_per_output_tab); + /* Could check tab width > 0. */ + tabify_output = TRUE; + break; + case 'J': + join_lines = TRUE; + break; + case 'l': + { + long int tmp_long; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long <= 0 || tmp_long > INT_MAX) + { + error (EXIT_FAILURE, 0, + _("`-l PAGE_LENGTH' invalid number of lines: `%s'"), + optarg); + } + lines_per_page = (int) tmp_long; + break; + } + case 'm': + parallel_files = TRUE; + storing_columns = FALSE; + break; + case 'n': + numbered_lines = TRUE; + if (optarg) + getoptarg (optarg, 'n', &number_separator, + &chars_per_number); + break; + case 'N': + skip_count = FALSE; + { + long int tmp_long; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long > INT_MAX) + { + error (EXIT_FAILURE, 0, + _("`-N NUMBER' invalid starting line number: `%s'"), + optarg); + } + start_line_num = (int) tmp_long; + break; + } + case 'o': + { + long int tmp_long; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long < 0 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, + _("`-o MARGIN' invalid line offset: `%s'"), optarg); + chars_per_margin = (int) tmp_long; + break; + } + case 'r': + ignore_failed_opens = TRUE; + break; + case 's': + old_options = TRUE; + old_s = TRUE; + if (!use_col_separator && optarg) + separator_string (optarg); + break; + case 'S': + old_s = FALSE; + /* Reset an additional input of -s, -S dominates -s */ + col_sep_string = ""; + col_sep_length = 0; + use_col_separator = TRUE; + if (optarg) + separator_string (optarg); + break; + case 't': + extremities = FALSE; + keep_FF = TRUE; + break; + case 'T': + extremities = FALSE; + keep_FF = FALSE; + break; + case 'v': + use_esc_sequence = TRUE; + break; + case 'w': + old_options = TRUE; + old_w = TRUE; + { + long int tmp_long; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long <= 0 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, + _("`-w PAGE_WIDTH' invalid number of characters: `%s'"), optarg); + if (!truncate_lines) chars_per_line = (int) tmp_long; + break; + } + case 'W': + old_w = FALSE; /* dominates -w */ + truncate_lines = TRUE; + { + long int tmp_long; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long <= 0 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, + _("`-W PAGE_WIDTH' invalid number of characters: `%s'"), optarg); + chars_per_line = (int) tmp_long; + break; + } + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (2); + break; + } + } + + if (! date_format) + date_format = (getenv ("POSIXLY_CORRECT") + ? dcgettext (NULL, "%b %e %H:%M %Y", LC_TIME) + : "%Y-%m-%d %H:%M"); + + /* Now we can set a reasonable initial value: */ + if (first_page_number == 0) + first_page_number = 1; + + if (parallel_files && explicit_columns) + error (EXIT_FAILURE, 0, + _("Cannot specify number of columns when printing in parallel.")); + + if (parallel_files && print_across_flag) + error (EXIT_FAILURE, 0, + _("Cannot specify both printing across and printing in parallel.")); + +/* Translate some old short options to new/long options. + To meet downward compatibility with other UNIX pr utilities + and some POSIX specifications. */ + + if (old_options) + { + if (old_w) + { + if (parallel_files || explicit_columns) + { + /* activate -W */ + truncate_lines = TRUE; + if (old_s) + /* adapt HP-UX and SunOS: -s = no separator; + activate -S */ + use_col_separator = TRUE; + } + else + /* old -w sets width with columns only + activate -J */ + join_lines = TRUE; + } + else if (!use_col_separator) + { + /* No -S option read */ + if (old_s && (parallel_files || explicit_columns)) + { + if (!truncate_lines) + { + /* old -s (without -w and -W) annuls column alignment, + uses fields, activate -J */ + join_lines = TRUE; + if (col_sep_length > 0) + /* activate -S */ + use_col_separator = TRUE; + } + else + /* with -W */ + /* adapt HP-UX and SunOS: -s = no separator; + activate -S */ + use_col_separator = TRUE; + } + } + } + + for (; optind < argc; optind++) + { + file_names[n_files++] = argv[optind]; + } + + if (n_files == 0) + { + /* No file arguments specified; read from standard input. */ + print_files (0, NULL); + } + else + { + if (parallel_files) + print_files (n_files, file_names); + else + { + int i; + for (i = 0; i < n_files; i++) + print_files (1, &file_names[i]); + } + } + + cleanup (); + + if (have_read_stdin && fclose (stdin) == EOF) + error (EXIT_FAILURE, errno, _("standard input")); + if (failed_opens > 0) + exit (EXIT_FAILURE); + exit (EXIT_SUCCESS); +} + +/* Parse options of the form -scNNN. + + Example: -nck, where 'n' is the option, c is the optional number + separator, and k is the optional width of the field used when printing + a number. */ + +static void +getoptarg (char *arg, char switch_char, char *character, int *number) +{ + if (!ISDIGIT (*arg)) + *character = *arg++; + if (*arg) + { + long int tmp_long; + if (xstrtol (arg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long <= 0 || tmp_long > INT_MAX) + { + error (0, 0, + _("`-%c' extra characters or invalid number in the argument: `%s'"), + switch_char, arg); + usage (2); + } + *number = (int) tmp_long; + } +} + +/* Set parameters related to formatting. */ + +static void +init_parameters (int number_of_files) +{ + int chars_used_by_number = 0; + + if (use_form_feed) + { + lines_per_header = 3; + lines_per_footer = 0; + } + + lines_per_body = lines_per_page - lines_per_header - lines_per_footer; + if (lines_per_body <= 0) + { + extremities = FALSE; + keep_FF = TRUE; + } + if (extremities == FALSE) + lines_per_body = lines_per_page; + + if (double_space) + lines_per_body = lines_per_body / 2; + + /* If input is stdin, cannot print parallel files. BSD dumps core + on this. */ + if (number_of_files == 0) + parallel_files = FALSE; + + if (parallel_files) + columns = number_of_files; + + /* One file, multi columns down: -b option is set to get a consistent + formulation with "FF set by hand" in input files. */ + if (storing_columns) + balance_columns = TRUE; + + /* Tabification is assumed for multiple columns. */ + if (columns > 1) + { + if (!use_col_separator) + { + /* Use default separator */ + if (join_lines) + col_sep_string = line_separator; + else + col_sep_string = column_separator; + + col_sep_length = 1; + use_col_separator = TRUE; + } + /* It's rather pointless to define a TAB separator with column + alignment */ + else if (!join_lines && *col_sep_string == '\t') + col_sep_string = column_separator; + + truncate_lines = TRUE; + untabify_input = TRUE; + tabify_output = TRUE; + } + else + storing_columns = FALSE; + + /* -J dominates -w in any case */ + if (join_lines) + truncate_lines = FALSE; + + if (numbered_lines) + { + int tmp_i; + int chars_per_default_tab = 8; + + line_count = start_line_num; + + /* To allow input tab-expansion (-e sensitive) use: + if (number_separator == input_tab_char) + number_width = chars_per_number + + TAB_WIDTH (chars_per_input_tab, chars_per_number); */ + + /* Estimate chars_per_text without any margin and keep it constant. */ + if (number_separator == '\t') + number_width = chars_per_number + + TAB_WIDTH (chars_per_default_tab, chars_per_number); + else + number_width = chars_per_number + 1; + + /* The number is part of the column width unless we are + printing files in parallel. */ + if (parallel_files) + chars_used_by_number = number_width; + + /* We use power_10 to cut off the higher-order digits of the + line_number in function add_line_number */ + tmp_i = chars_per_number; + for (power_10 = 1; tmp_i > 0; --tmp_i) + power_10 = 10 * power_10; + } + + chars_per_column = (chars_per_line - chars_used_by_number - + (columns - 1) * col_sep_length) / columns; + + if (chars_per_column < 1) + error (EXIT_FAILURE, 0, _("page width too narrow")); + + if (numbered_lines) + { + if (number_buff != NULL) + free (number_buff); + number_buff = (char *) xmalloc (2 * chars_per_number); + } + + /* Pick the maximum between the tab width and the width of an + escape sequence. + The width of an escape sequence (4) isn't the lower limit any longer. + We've to use 8 as the lower limit, if we use chars_per_default_tab = 8 + to expand a tab which is not an input_tab-char. */ + if (clump_buff != NULL) + free (clump_buff); + clump_buff = (int *) xmalloc ((chars_per_input_tab > 8 + ? chars_per_input_tab : 8) * sizeof (int)); +} + +/* Open the necessary files, + maintaining a COLUMN structure for each column. + + With multiple files, each column p has a different p->fp. + With single files, each column p has the same p->fp. + Return 1 if (number_of_files > 0) and no files can be opened, + 0 otherwise. + + With each column/file p, p->full_page_printed is initialized, + see also open_file. */ + +static int +init_fps (int number_of_files, char **av) +{ + int i, files_left; + COLUMN *p; + FILE *firstfp; + char const *firstname; + + total_files = 0; + + if (column_vector != NULLCOL) + free ((char *) column_vector); + column_vector = (COLUMN *) xmalloc (columns * sizeof (COLUMN)); + + if (parallel_files) + { + files_left = number_of_files; + for (p = column_vector; files_left--; ++p, ++av) + { + if (open_file (*av, p) == 0) + { + --p; + --columns; + } + } + if (columns == 0) + return 1; + init_header ("", -1); + } + else + { + p = column_vector; + if (number_of_files > 0) + { + if (open_file (*av, p) == 0) + return 1; + init_header (*av, fileno (p->fp)); + p->lines_stored = 0; + } + else + { + p->name = _("standard input"); + p->fp = stdin; + have_read_stdin = TRUE; + p->status = OPEN; + p->full_page_printed = FALSE; + ++total_files; + init_header ("", -1); + p->lines_stored = 0; + } + + firstname = p->name; + firstfp = p->fp; + for (i = columns - 1, ++p; i; --i, ++p) + { + p->name = firstname; + p->fp = firstfp; + p->status = OPEN; + p->full_page_printed = FALSE; + p->lines_stored = 0; + } + } + files_ready_to_read = total_files; + return 0; +} + +/* Determine print_func and char_func, the functions + used by each column for printing and/or storing. + + Determine the horizontal position desired when we begin + printing a column (p->start_position). */ + +static void +init_funcs (void) +{ + int i, h, h_next; + COLUMN *p; + + h = chars_per_margin; + + if (!truncate_lines) + h_next = ANYWHERE; + else + { + /* When numbering lines of parallel files, we enlarge the + first column to accomodate the number. Looks better than + the Sys V approach. */ + if (parallel_files && numbered_lines) + h_next = h + chars_per_column + number_width; + else + h_next = h + chars_per_column; + } + + /* Enlarge p->start_position of first column to use the same form of + padding_not_printed with all columns. */ + h = h + col_sep_length; + + /* This loop takes care of all but the rightmost column. */ + + for (p = column_vector, i = 1; i < columns; ++p, ++i) + { + if (storing_columns) /* One file, multi columns down. */ + { + p->char_func = store_char; + p->print_func = print_stored; + } + else + /* One file, multi columns across; or parallel files. */ + { + p->char_func = print_char; + p->print_func = read_line; + } + + /* Number only the first column when printing files in + parallel. */ + p->numbered = numbered_lines && (!parallel_files || i == 1); + p->start_position = h; + + /* If we don't truncate lines, all start_positions are + ANYWHERE, except the first column's start_position when + using a margin. */ + + if (!truncate_lines) + { + h = ANYWHERE; + h_next = ANYWHERE; + } + else + { + h = h_next + col_sep_length; + h_next = h + chars_per_column; + } + } + + /* The rightmost column. + + Doesn't need to be stored unless we intend to balance + columns on the last page. */ + if (storing_columns && balance_columns) + { + p->char_func = store_char; + p->print_func = print_stored; + } + else + { + p->char_func = print_char; + p->print_func = read_line; + } + + p->numbered = numbered_lines && (!parallel_files || i == 1); + p->start_position = h; +} + +/* Open a file. Return nonzero if successful, zero if failed. + + With each file p, p->full_page_printed is initialized, + see also init_fps. */ + +static int +open_file (char *name, COLUMN *p) +{ + if (STREQ (name, "-")) + { + p->name = _("standard input"); + p->fp = stdin; + have_read_stdin = 1; + } + else + { + p->name = name; + p->fp = fopen (name, "r"); + } + if (p->fp == NULL) + { + ++failed_opens; + if (!ignore_failed_opens) + error (0, errno, "%s", name); + return 0; + } + p->status = OPEN; + p->full_page_printed = FALSE; + ++total_files; + return 1; +} + +/* Close the file in P. + + If we aren't dealing with multiple files in parallel, we change + the status of all columns in the column list to reflect the close. */ + +static void +close_file (COLUMN *p) +{ + COLUMN *q; + int i; + + if (p->status == CLOSED) + return; + if (ferror (p->fp)) + error (EXIT_FAILURE, errno, "%s", p->name); + if (p->fp != stdin && fclose (p->fp) == EOF) + error (EXIT_FAILURE, errno, "%s", p->name); + + if (!parallel_files) + { + for (q = column_vector, i = columns; i; ++q, --i) + { + q->status = CLOSED; + if (q->lines_stored == 0) + { + q->lines_to_print = 0; + } + } + } + else + { + p->status = CLOSED; + p->lines_to_print = 0; + } + + --files_ready_to_read; +} + +/* Put a file on hold until we start a new page, + since we've hit a form feed. + + If we aren't dealing with parallel files, we must change the + status of all columns in the column list. */ + +static void +hold_file (COLUMN *p) +{ + COLUMN *q; + int i; + + if (!parallel_files) + for (q = column_vector, i = columns; i; ++q, --i) + { + if (storing_columns) + q->status = FF_FOUND; + else + q->status = ON_HOLD; + } + else + p->status = ON_HOLD; + + p->lines_to_print = 0; + --files_ready_to_read; +} + +/* Undo hold_file -- go through the column list and change any + ON_HOLD columns to OPEN. Used at the end of each page. */ + +static void +reset_status (void) +{ + int i = columns; + COLUMN *p; + + for (p = column_vector; i; --i, ++p) + if (p->status == ON_HOLD) + { + p->status = OPEN; + files_ready_to_read++; + } + + if (storing_columns) + { + if (column_vector->status == CLOSED) + /* We use the info to output an error message in skip_to_page. */ + files_ready_to_read = 0; + else + files_ready_to_read = 1; + } +} + +/* Print a single file, or multiple files in parallel. + + Set up the list of columns, opening the necessary files. + Allocate space for storing columns, if necessary. + Skip to first_page_number, if user has asked to skip leading pages. + Determine which functions are appropriate to store/print lines + in each column. + Print the file(s). */ + +static void +print_files (int number_of_files, char **av) +{ + init_parameters (number_of_files); + if (init_fps (number_of_files, av)) + return; + if (storing_columns) + init_store_cols (); + + if (first_page_number > 1) + { + if (!skip_to_page (first_page_number)) + return; + else + page_number = first_page_number; + } + else + page_number = 1; + + init_funcs (); + + line_number = line_count; + while (print_page ()) + ; +} + +/* Initialize header information. + If DESC is non-negative, it is a file descriptor open to + FILENAME for reading. */ + +static void +init_header (char *filename, int desc) +{ + char *buf; + char initbuf[MAX (256, INT_STRLEN_BOUND (long) + 1)]; + struct stat st; + struct tm *tm; + + /* If parallel files or standard input, use current date. */ + if (STREQ (filename, "-")) + desc = -1; + if (desc < 0 || fstat (desc, &st) != 0) + st.st_mtime = time (NULL); + + buf = initbuf; + tm = localtime (&st.st_mtime); + if (! tm) + sprintf (buf, "%ld", (long) st.st_mtime); + else + { + size_t bufsize = sizeof initbuf; + for (;;) + { + *buf = '\1'; + if (strftime (buf, bufsize, date_format, tm) || ! *buf) + break; + buf = alloca (bufsize *= 2); + } + } + + if (date_text) + free (date_text); + date_text = xstrdup (buf); + file_text = custom_header ? custom_header : desc < 0 ? "" : filename; + header_width_available = (chars_per_line + - mbswidth (date_text, 0) + - mbswidth (file_text, 0)); +} + +/* Set things up for printing a page + + Scan through the columns ... + Determine which are ready to print + (i.e., which have lines stored or open files) + Set p->lines_to_print appropriately + (to p->lines_stored if we're storing, or lines_per_body + if we're reading straight from the file) + Keep track of this total so we know when to stop printing */ + +static void +init_page (void) +{ + int j; + COLUMN *p; + + if (storing_columns) + { + store_columns (); + for (j = columns - 1, p = column_vector; j; --j, ++p) + { + p->lines_to_print = p->lines_stored; + } + + /* Last column. */ + if (balance_columns) + { + p->lines_to_print = p->lines_stored; + } + /* Since we're not balancing columns, we don't need to store + the rightmost column. Read it straight from the file. */ + else + { + if (p->status == OPEN) + { + p->lines_to_print = lines_per_body; + } + else + p->lines_to_print = 0; + } + } + else + for (j = columns, p = column_vector; j; --j, ++p) + if (p->status == OPEN) + { + p->lines_to_print = lines_per_body; + } + else + p->lines_to_print = 0; +} + +/* Align empty columns and print separators. + Empty columns will be formed by files with status ON_HOLD or CLOSED + when printing multiple files in parallel. */ + +static void +align_column (COLUMN *p) +{ + padding_not_printed = p->start_position; + if (padding_not_printed - col_sep_length > 0) + { + pad_across_to (padding_not_printed - col_sep_length); + padding_not_printed = ANYWHERE; + } + + if (use_col_separator) + print_sep_string (); + + if (p->numbered) + add_line_number (p); +} + +/* Print one page. + + As long as there are lines left on the page and columns ready to print, + Scan across the column list + if the column has stored lines or the file is open + pad to the appropriate spot + print the column + pad the remainder of the page with \n or \f as requested + reset the status of all files -- any files which where on hold because + of formfeeds are now put back into the lineup. */ + +static int +print_page (void) +{ + int j; + int lines_left_on_page; + COLUMN *p; + + /* Used as an accumulator (with | operator) of successive values of + pad_vertically. The trick is to set pad_vertically + to zero before each run through the inner loop, then after that + loop, it tells us whether a line was actually printed (whether a + newline needs to be output -- or two for double spacing). But those + values have to be accumulated (in pv) so we can invoke pad_down + properly after the outer loop completes. */ + int pv; + + init_page (); + + if (cols_ready_to_print () == 0) + return FALSE; + + if (extremities) + print_a_header = TRUE; + + /* Don't pad unless we know a page was printed. */ + pad_vertically = FALSE; + pv = FALSE; + + lines_left_on_page = lines_per_body; + if (double_space) + lines_left_on_page *= 2; + + while (lines_left_on_page > 0 && cols_ready_to_print () > 0) + { + output_position = 0; + spaces_not_printed = 0; + separators_not_printed = 0; + pad_vertically = FALSE; + align_empty_cols = FALSE; + empty_line = TRUE; + + for (j = 1, p = column_vector; j <= columns; ++j, ++p) + { + input_position = 0; + if (p->lines_to_print > 0 || p->status == FF_FOUND) + { + FF_only = FALSE; + padding_not_printed = p->start_position; + if (!(p->print_func) (p)) + read_rest_of_line (p); + pv |= pad_vertically; + + --p->lines_to_print; + if (p->lines_to_print <= 0) + { + if (cols_ready_to_print () <= 0) + break; + } + + /* File p changed its status to ON_HOLD or CLOSED */ + if (parallel_files && p->status != OPEN) + { + if (empty_line) + align_empty_cols = TRUE; + else if (p->status == CLOSED || + (p->status == ON_HOLD && FF_only)) + align_column (p); + } + } + else if (parallel_files) + { + /* File status ON_HOLD or CLOSED */ + if (empty_line) + align_empty_cols = TRUE; + else + align_column (p); + } + + /* We need it also with an empty column */ + if (use_col_separator) + ++separators_not_printed; + } + + if (pad_vertically) + { + putchar ('\n'); + --lines_left_on_page; + } + + if (cols_ready_to_print () <= 0 && !extremities) + break; + + if (double_space && pv) + { + putchar ('\n'); + --lines_left_on_page; + } + } + + if (lines_left_on_page == 0) + for (j = 1, p = column_vector; j <= columns; ++j, ++p) + if (p->status == OPEN) + p->full_page_printed = TRUE; + + pad_vertically = pv; + + if (pad_vertically && extremities) + pad_down (lines_left_on_page + lines_per_footer); + else if (keep_FF && print_a_FF) + { + putchar ('\f'); + print_a_FF = FALSE; + } + + if (last_page_number && page_number > last_page_number) + return FALSE; /* Stop printing with LAST_PAGE */ + + reset_status (); /* Change ON_HOLD to OPEN. */ + + return TRUE; /* More pages to go. */ +} + +/* Allocate space for storing columns. + + This is necessary when printing multiple columns from a single file. + Lines are stored consecutively in buff, separated by '\0'. + + The following doesn't apply any longer - any tuning possible? + (We can't use a fixed offset since with the '-s' flag lines aren't + truncated.) + + We maintain a list (line_vector) of pointers to the beginnings + of lines in buff. We allocate one more than the number of lines + because the last entry tells us the index of the last character, + which we need to know in order to print the last line in buff. */ + +static void +init_store_cols (void) +{ + int total_lines = lines_per_body * columns; + int chars_if_truncate = total_lines * (chars_per_column + 1); + + if (line_vector != NULL) + free ((int *) line_vector); + /* FIXME: here's where it was allocated. */ + line_vector = (int *) xmalloc ((total_lines + 1) * sizeof (int *)); + + if (end_vector != NULL) + free ((int *) end_vector); + end_vector = (int *) xmalloc (total_lines * sizeof (int *)); + + if (buff != NULL) + free (buff); + buff_allocated = (use_col_separator + ? 2 * chars_if_truncate + : chars_if_truncate); /* Tune this. */ + buff = (char *) xmalloc (buff_allocated); +} + +/* Store all but the rightmost column. + (Used when printing a single file in multiple downward columns) + + For each column + set p->current_line to be the index in line_vector of the + first line in the column + For each line in the column + store the line in buff + add to line_vector the index of the line's first char + buff_start is the index in buff of the first character in the + current line. */ + +static void +store_columns (void) +{ + int i, j; + int line = 0; + int buff_start; + int last_col; /* The rightmost column which will be saved in buff */ + COLUMN *p; + + buff_current = 0; + buff_start = 0; + + if (balance_columns) + last_col = columns; + else + last_col = columns - 1; + + for (i = 1, p = column_vector; i <= last_col; ++i, ++p) + p->lines_stored = 0; + + for (i = 1, p = column_vector; i <= last_col && files_ready_to_read; + ++i, ++p) + { + p->current_line = line; + for (j = lines_per_body; j && files_ready_to_read; --j) + + if (p->status == OPEN) /* Redundant. Clean up. */ + { + input_position = 0; + + if (!read_line (p)) + read_rest_of_line (p); + + if (p->status == OPEN + || buff_start != buff_current) + { + ++p->lines_stored; + line_vector[line] = buff_start; + end_vector[line++] = input_position; + buff_start = buff_current; + } + } + } + + /* Keep track of the location of the last char in buff. */ + line_vector[line] = buff_start; + + if (balance_columns) + balance (line); +} + +static void +balance (int total_stored) +{ + COLUMN *p; + int i, lines; + int first_line = 0; + + for (i = 1, p = column_vector; i <= columns; ++i, ++p) + { + lines = total_stored / columns; + if (i <= total_stored % columns) + ++lines; + + p->lines_stored = lines; + p->current_line = first_line; + + first_line += lines; + } +} + +/* Store a character in the buffer. */ + +static void +store_char (int c) +{ + if (buff_current >= buff_allocated) + { + /* May be too generous. */ + buff_allocated = 2 * buff_allocated; + buff = (char *) xrealloc (buff, buff_allocated * sizeof (char)); + } + buff[buff_current++] = (char) c; +} + +static void +add_line_number (COLUMN *p) +{ + int i; + char *s; + int left_cut; + + /* Cutting off the higher-order digits is more informative than + lower-order cut off*/ + if (line_number < power_10) + sprintf (number_buff, "%*d", chars_per_number, line_number); + else + { + left_cut = line_number % power_10; + sprintf (number_buff, "%0*d", chars_per_number, left_cut); + } + line_number++; + s = number_buff; + for (i = chars_per_number; i > 0; i--) + (p->char_func) ((int) *s++); + + if (columns > 1) + { + /* Tabification is assumed for multiple columns, also for n-separators, + but `default n-separator = TAB' hasn't been given priority over + equal column_width also specified by POSIX. */ + if (number_separator == '\t') + { + i = number_width - chars_per_number; + while (i-- > 0) + (p->char_func) ((int) ' '); + } + else + (p->char_func) ((int) number_separator); + } + else + /* To comply with POSIX, we avoid any expansion of default TAB + separator with a single column output. No column_width requirement + has to be considered. */ + { + (p->char_func) ((int) number_separator); + if (number_separator == '\t') + output_position = POS_AFTER_TAB (chars_per_output_tab, + output_position); + } + + if (truncate_lines && !parallel_files) + input_position += number_width; +} + +/* Print (or store) padding until the current horizontal position + is position. */ + +static void +pad_across_to (int position) +{ + register int h = output_position; + + if (tabify_output) + spaces_not_printed = position - output_position; + else + { + while (++h <= position) + putchar (' '); + output_position = position; + } +} + +/* Pad to the bottom of the page. + + If the user has requested a formfeed, use one. + Otherwise, use newlines. */ + +static void +pad_down (int lines) +{ + register int i; + + if (use_form_feed) + putchar ('\f'); + else + for (i = lines; i; --i) + putchar ('\n'); +} + +/* Read the rest of the line. + + Read from the current column's file until an end of line is + hit. Used when we've truncated a line and we no longer need + to print or store its characters. */ + +static void +read_rest_of_line (COLUMN *p) +{ + register int c; + FILE *f = p->fp; + + while ((c = getc (f)) != '\n') + { + if (c == '\f') + { + if ((c = getc (f)) != '\n') + ungetc (c, f); + if (keep_FF) + print_a_FF = TRUE; + hold_file (p); + break; + } + else if (c == EOF) + { + close_file (p); + break; + } + } +} + +/* Read a line with skip_to_page. + + Read from the current column's file until an end of line is + hit. Used when we read full lines to skip pages. + With skip_to_page we have to check for FF-coincidence which is done + in function read_line otherwise. + Count lines of skipped pages to find the line number of 1st page + printed relative to 1st line of input file (start_line_num). */ + +static void +skip_read (COLUMN *p, int column_number) +{ + register int c; + FILE *f = p->fp; + int i, single_ff = FALSE; + COLUMN *q; + + /* Read 1st character in a line or any character succeeding a FF */ + if ((c = getc (f)) == '\f' && p->full_page_printed) + /* A FF-coincidence with a previous full_page_printed. + To avoid an additional empty page, eliminate the FF */ + if ((c = getc (f)) == '\n') + c = getc (f); + + p->full_page_printed = FALSE; + + /* 1st character a FF means a single FF without any printable + characters. Don't count it as a line with -n option. */ + if (c == '\f') + single_ff = TRUE; + + /* Preparing for a FF-coincidence: Maybe we finish that page + without a FF found */ + if (last_line) + p->full_page_printed = TRUE; + + while (c != '\n') + { + if (c == '\f') + { + /* No FF-coincidence possible, + no catching up of a FF-coincidence with next page */ + if (last_line) + { + if (!parallel_files) + for (q = column_vector, i = columns; i; ++q, --i) + q->full_page_printed = FALSE; + else + p->full_page_printed = FALSE; + } + + if ((c = getc (f)) != '\n') + ungetc (c, f); + hold_file (p); + break; + } + else if (c == EOF) + { + close_file (p); + break; + } + c = getc (f); + } + + if (skip_count) + if ((!parallel_files || column_number == 1) && !single_ff) + ++line_count; +} + +/* If we're tabifying output, + + When print_char encounters white space it keeps track + of our desired horizontal position and delays printing + until this function is called. */ + +static void +print_white_space (void) +{ + register int h_new; + register int h_old = output_position; + register int goal = h_old + spaces_not_printed; + + while (goal - h_old > 1 + && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal) + { + putchar (output_tab_char); + h_old = h_new; + } + while (++h_old <= goal) + putchar (' '); + + output_position = goal; + spaces_not_printed = 0; +} + +/* Print column separators. + + We keep a count until we know that we'll be printing a line, + then print_sep_string() is called. */ + +static void +print_sep_string () +{ + char *s; + int l = col_sep_length; + + s = col_sep_string; + + if (separators_not_printed <= 0) + { + /* We'll be starting a line with chars_per_margin, anything else? */ + if (spaces_not_printed > 0) + print_white_space (); + } + else + { + for (; separators_not_printed > 0; --separators_not_printed) + { + while (l-- > 0) + { + /* 3 types of sep_strings: spaces only, spaces and chars, + chars only */ + if (*s == ' ') + { + /* We're tabifying output; consecutive spaces in + sep_string may have to be converted to tabs */ + s++; + ++spaces_not_printed; + } + else + { + if (spaces_not_printed > 0) + print_white_space (); + putchar (*s++); + ++output_position; + } + } + /* sep_string ends with some spaces */ + if (spaces_not_printed > 0) + print_white_space (); + } + } +} + +/* Print (or store, depending on p->char_func) a clump of N + characters. */ + +static void +print_clump (COLUMN *p, int n, int *clump) +{ + while (n--) + (p->char_func) (*clump++); +} + +/* Print a character. + + Update the following comment: process-char hasn't been used any + longer. + If we're tabifying, all tabs have been converted to spaces by + process_char(). Keep a count of consecutive spaces, and when + a nonspace is encountered, call print_white_space() to print the + required number of tabs and spaces. */ + +static void +print_char (int c) +{ + if (tabify_output) + { + if (c == ' ') + { + ++spaces_not_printed; + return; + } + else if (spaces_not_printed > 0) + print_white_space (); + + /* Nonprintables are assumed to have width 0, except '\b'. */ + if (!ISPRINT (c)) + { + if (c == '\b') + --output_position; + } + else + ++output_position; + } + putchar (c); +} + +/* Skip to page PAGE before printing. + PAGE may be larger than total number of pages. */ + +static int +skip_to_page (int page) +{ + int n, i, j; + COLUMN *p; + + for (n = 1; n < page; ++n) + { + for (i = 1; i < lines_per_body; ++i) + { + for (j = 1, p = column_vector; j <= columns; ++j, ++p) + if (p->status == OPEN) + skip_read (p, j); + } + last_line = TRUE; + for (j = 1, p = column_vector; j <= columns; ++j, ++p) + if (p->status == OPEN) + skip_read (p, j); + + if (storing_columns) /* change FF_FOUND to ON_HOLD */ + for (j = 1, p = column_vector; j <= columns; ++j, ++p) + if (p->status != CLOSED) + p->status = ON_HOLD; + + reset_status (); + last_line = FALSE; + + if (files_ready_to_read < 1) + { + /* It's very helpful, normally the total number of pages is + not known in advance. */ + error (0, 0, + _("starting page number larger than total number of pages: `%d'"), + n); + break; + } + } + return files_ready_to_read > 0; +} + +/* Print a header. + + Formfeeds are assumed to use up two lines at the beginning of + the page. */ + +static void +print_header (void) +{ + char page_text[256 + INT_STRLEN_BOUND (int)]; + int available_width; + int lhs_spaces; + int rhs_spaces; + + if (!use_form_feed) + printf ("\n\n"); + + output_position = 0; + pad_across_to (chars_per_margin); + print_white_space (); + + /* The translator must ensure that formatting the translation of + "Page %d" does not generate more than (sizeof page_text - 1) + bytes. */ + sprintf (page_text, _("Page %d"), page_number++); + available_width = header_width_available - mbswidth (page_text, 0); + available_width = MAX (0, available_width); + lhs_spaces = available_width >> 1; + rhs_spaces = available_width - lhs_spaces; + + printf ("%s%*s%s%*s%s\n\n\n", + date_text, lhs_spaces, " ", file_text, rhs_spaces, " ", page_text); + + print_a_header = FALSE; + output_position = 0; +} + +/* Print (or store, if p->char_func is store_char()) a line. + + Read a character to determine whether we have a line or not. + (We may hit EOF, \n, or \f) + + Once we know we have a line, + set pad_vertically = TRUE, meaning it's safe + to pad down at the end of the page, since we do have a page. + print a header if needed. + pad across to padding_not_printed if needed. + print any separators which need to be printed. + print a line number if it needs to be printed. + + Print the clump which corresponds to the first character. + + Enter a loop and keep printing until an end of line condition + exists, or until we exceed chars_per_column. + + Return FALSE if we exceed chars_per_column before reading + an end of line character, TRUE otherwise. */ + +static int +read_line (COLUMN *p) +{ + int c; + int chars IF_LINT (= 0); + int last_input_position; + int j, k; + COLUMN *q; + + /* read 1st character in each line or any character succeeding a FF: */ + c = getc (p->fp); + + last_input_position = input_position; + + if (c == '\f' && p->full_page_printed) + if ((c = getc (p->fp)) == '\n') + c = getc (p->fp); + p->full_page_printed = FALSE; + + switch (c) + { + case '\f': + if ((c = getc (p->fp)) != '\n') + ungetc (c, p->fp); + FF_only = TRUE; + if (print_a_header && !storing_columns) + { + pad_vertically = TRUE; + print_header (); + } + else if (keep_FF) + print_a_FF = TRUE; + hold_file (p); + return TRUE; + case EOF: + close_file (p); + return TRUE; + case '\n': + break; + default: + chars = char_to_clump (c); + } + + if (truncate_lines && input_position > chars_per_column) + { + input_position = last_input_position; + return FALSE; + } + + if (p->char_func != store_char) + { + pad_vertically = TRUE; + + if (print_a_header && !storing_columns) + print_header (); + + if (parallel_files && align_empty_cols) + { + /* We have to align empty columns at the beginning of a line. */ + k = separators_not_printed; + separators_not_printed = 0; + for (j = 1, q = column_vector; j <= k; ++j, ++q) + { + align_column (q); + separators_not_printed += 1; + } + padding_not_printed = p->start_position; + if (truncate_lines) + spaces_not_printed = chars_per_column; + else + spaces_not_printed = 0; + align_empty_cols = FALSE; + } + + if (padding_not_printed - col_sep_length > 0) + { + pad_across_to (padding_not_printed - col_sep_length); + padding_not_printed = ANYWHERE; + } + + if (use_col_separator) + print_sep_string (); + } + + if (p->numbered) + add_line_number (p); + + empty_line = FALSE; + if (c == '\n') + return TRUE; + + print_clump (p, chars, clump_buff); + + for (;;) + { + c = getc (p->fp); + + switch (c) + { + case '\n': + return TRUE; + case '\f': + if ((c = getc (p->fp)) != '\n') + ungetc (c, p->fp); + if (keep_FF) + print_a_FF = TRUE; + hold_file (p); + return TRUE; + case EOF: + close_file (p); + return TRUE; + } + + last_input_position = input_position; + chars = char_to_clump (c); + if (truncate_lines && input_position > chars_per_column) + { + input_position = last_input_position; + return FALSE; + } + + print_clump (p, chars, clump_buff); + } +} + +/* Print a line from buff. + + If this function has been called, we know we have "something to + print". But it remains to be seen whether we have a real text page + or an empty page (a single form feed) with/without a header only. + Therefore first we set pad_vertically to TRUE and print a header + if necessary. + If FF_FOUND and we are using -t|-T option we omit any newline by + setting pad_vertically to FALSE (see print_page). + Otherwise we pad across if necessary, print separators if necessary + and text of COLUMN *p. + + Return TRUE, meaning there is no need to call read_rest_of_line. */ + +static int +print_stored (COLUMN *p) +{ + COLUMN *q; + int i; + + int line = p->current_line++; + register char *first = &buff[line_vector[line]]; + /* FIXME + UMR: Uninitialized memory read: + * This is occurring while in: + print_stored [pr.c:2239] + * Reading 4 bytes from 0x5148c in the heap. + * Address 0x5148c is 4 bytes into a malloc'd block at 0x51488 of 676 bytes + * This block was allocated from: + malloc [rtlib.o] + xmalloc [xmalloc.c:94] + init_store_cols [pr.c:1648] + */ + register char *last = &buff[line_vector[line + 1]]; + + pad_vertically = TRUE; + + if (print_a_header) + print_header (); + + if (p->status == FF_FOUND) + { + for (i = 1, q = column_vector; i <= columns; ++i, ++q) + q->status = ON_HOLD; + if (column_vector->lines_to_print <= 0) + { + if (!extremities) + pad_vertically = FALSE; + return TRUE; /* print a header only */ + } + } + + if (padding_not_printed - col_sep_length > 0) + { + pad_across_to (padding_not_printed - col_sep_length); + padding_not_printed = ANYWHERE; + } + + if (use_col_separator) + print_sep_string (); + + while (first != last) + print_char (*first++); + + if (spaces_not_printed == 0) + { + output_position = p->start_position + end_vector[line]; + if (p->start_position - col_sep_length == chars_per_margin) + output_position -= col_sep_length; + } + + return TRUE; +} + +/* Convert a character to the proper format and return the number of + characters in the resulting clump. Increment input_position by + the width of the clump. + + Tabs are converted to clumps of spaces. + Nonprintable characters may be converted to clumps of escape + sequences or control prefixes. + + Note: the width of a clump is not necessarily equal to the number of + characters in clump_buff. (e.g, the width of '\b' is -1, while the + number of characters is 1.) */ + +static int +char_to_clump (int c) +{ + register int *s = clump_buff; + register int i; + char esc_buff[4]; + int width; + int chars; + int chars_per_c = 8; + + if (c == input_tab_char) + chars_per_c = chars_per_input_tab; + + if (c == input_tab_char || c == '\t') + { + width = TAB_WIDTH (chars_per_c, input_position); + + if (untabify_input) + { + for (i = width; i; --i) + *s++ = ' '; + chars = width; + } + else + { + *s = c; + chars = 1; + } + + } + else if (!ISPRINT (c)) + { + if (use_esc_sequence) + { + width = 4; + chars = 4; + *s++ = '\\'; + sprintf (esc_buff, "%03o", c); + for (i = 0; i <= 2; ++i) + *s++ = (int) esc_buff[i]; + } + else if (use_cntrl_prefix) + { + if (c < 0200) + { + width = 2; + chars = 2; + *s++ = '^'; + *s++ = c ^ 0100; + } + else + { + width = 4; + chars = 4; + *s++ = '\\'; + sprintf (esc_buff, "%03o", c); + for (i = 0; i <= 2; ++i) + *s++ = (int) esc_buff[i]; + } + } + else if (c == '\b') + { + width = -1; + chars = 1; + *s = c; + } + else + { + width = 0; + chars = 1; + *s = c; + } + } + else + { + width = 1; + chars = 1; + *s = c; + } + + input_position += width; + return chars; +} + +/* We've just printed some files and need to clean up things before + looking for more options and printing the next batch of files. + + Free everything we've xmalloc'ed, except `header'. */ + +static void +cleanup (void) +{ + if (number_buff) + free (number_buff); + if (clump_buff) + free (clump_buff); + if (column_vector) + free (column_vector); + if (line_vector) + free (line_vector); + if (end_vector) + free (end_vector); + if (buff) + free (buff); +} + +/* Complain, print a usage message, and die. */ + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + + fputs (_("\ +Paginate or columnate FILE(s) for printing.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + +FIRST_PAGE[:LAST_PAGE], --pages=FIRST_PAGE[:LAST_PAGE]\n\ + begin [stop] printing with page FIRST_[LAST_]PAGE\n\ + -COLUMN, --columns=COLUMN\n\ + output COLUMN columns and print columns down,\n\ + unless -a is used. Balance number of lines in the\n\ + columns on each page.\n\ +"), stdout); + fputs (_("\ + -a, --across print columns across rather than down, used together\n\ + with -COLUMN\n\ + -c, --show-control-chars\n\ + use hat notation (^G) and octal backslash notation\n\ + -d, --double-space\n\ + double space the output\n\ +"), stdout); + fputs (_("\ + -D, --date-format=FORMAT\n\ + use FORMAT for the header date\n\ + -e[CHAR[WIDTH]], --expand-tabs[=CHAR[WIDTH]]\n\ + expand input CHARs (TABs) to tab WIDTH (8)\n\ + -F, -f, --form-feed\n\ + use form feeds instead of newlines to separate pages\n\ + (by a 3-line page header with -F or a 5-line header\n\ + and trailer without -F)\n\ +"), stdout); + fputs (_("\ + -h HEADER, --header=HEADER\n\ + use a centered HEADER instead of filename in page header,\n\ + -h \"\" prints a blank line, don't use -h\"\"\n\ + -i[CHAR[WIDTH]], --output-tabs[=CHAR[WIDTH]]\n\ + replace spaces with CHARs (TABs) to tab WIDTH (8)\n\ + -J, --join-lines merge full lines, turns off -W line truncation, no column\n\ + alignment, --sep-string[=STRING] sets separators\n\ +"), stdout); + fputs (_("\ + -l PAGE_LENGTH, --length=PAGE_LENGTH\n\ + set the page length to PAGE_LENGTH (66) lines\n\ + (default number of lines of text 56, and with -F 63)\n\ + -m, --merge print all files in parallel, one in each column,\n\ + truncate lines, but join lines of full length with -J\n\ +"), stdout); + fputs (_("\ + -n[SEP[DIGITS]], --number-lines[=SEP[DIGITS]]\n\ + number lines, use DIGITS (5) digits, then SEP (TAB),\n\ + default counting starts with 1st line of input file\n\ + -N NUMBER, --first-line-number=NUMBER\n\ + start counting with NUMBER at 1st line of first\n\ + page printed (see +FIRST_PAGE)\n\ +"), stdout); + fputs (_("\ + -o MARGIN, --indent=MARGIN\n\ + offset each line with MARGIN (zero) spaces, do not\n\ + affect -w or -W, MARGIN will be added to PAGE_WIDTH\n\ + -r, --no-file-warnings\n\ + omit warning when a file cannot be opened\n\ +"), stdout); + fputs (_("\ + -s[CHAR],--separator[=CHAR]\n\ + separate columns by a single character, default for CHAR\n\ + is the character without -w and \'no char\' with -w\n\ + -s[CHAR] turns off line truncation of all 3 column\n\ + options (-COLUMN|-a -COLUMN|-m) except -w is set\n\ +"), stdout); + fputs (_("\ + -SSTRING, --sep-string[=STRING]\n\ +"), stdout); + fputs (_("\ + separate columns by STRING,\n\ + without -S: Default separator with -J and \n\ + otherwise (same as -S\" \"), no effect on column options\n\ + -t, --omit-header omit page headers and trailers\n\ +"), stdout); + fputs (_("\ + -T, --omit-pagination\n\ + omit page headers and trailers, eliminate any pagination\n\ + by form feeds set in input files\n\ + -v, --show-nonprinting\n\ + use octal backslash notation\n\ + -w PAGE_WIDTH, --width=PAGE_WIDTH\n\ + set page width to PAGE_WIDTH (72) characters for\n\ + multiple text-column output only, -s[char] turns off (72)\n\ +"), stdout); + fputs (_("\ + -W PAGE_WIDTH, --page-width=PAGE_WIDTH\n\ + set page width to PAGE_WIDTH (72) characters always,\n\ + truncate lines, except -J option is set, no interference\n\ + with -S or -s\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +-T implied by -l nn when nn <= 10 or <= 3 with -F. With no FILE, or when\n\ +FILE is -, read standard input.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/printenv.c b/src/apps/bin/coreutils-5.0/src/printenv.c new file mode 100644 index 0000000000..89472ff8dc --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/printenv.c @@ -0,0 +1,139 @@ +/* printenv -- print all or part of environment + Copyright (C) 1989-1997, 1999-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Usage: printenv [variable...] + + If no arguments are given, print the entire environment. + If one or more variable names are given, print the value of + each one that is set, and nothing for ones that are not set. + + Exit status: + 0 if all variables specified were found + 1 if not + + David MacKenzie and Richard Mlynarik */ + +#include +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "long-options.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "printenv" + +#define AUTHORS N_ ("David MacKenzie and Richard Mlynarik") + +/* The name this program was run with. */ +char *program_name; + +static struct option const long_options[] = +{ + {0, 0, 0, 0} +}; + +extern char **environ; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [VARIABLE]...\n\ + or: %s OPTION\n\ +If no environment VARIABLE specified, print them all.\n\ +\n\ +"), + program_name, program_name); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + char **env; + char *ep, *ap; + int i; + int matches = 0; + int c; + int exit_status; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + close_stdout_set_status (2); + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + default: + usage (EXIT_FAILURE); + } + } + + if (optind == argc) + { + for (env = environ; *env != NULL; ++env) + puts (*env); + exit_status = 0; + } + else + { + for (i = optind; i < argc; ++i) + { + for (env = environ; *env; ++env) + { + ep = *env; + ap = argv[i]; + while (*ep != '\0' && *ap != '\0' && *ep++ == *ap++) + { + if (*ep == '=' && *ap == '\0') + { + puts (ep + 1); + ++matches; + break; + } + } + } + } + exit_status = (matches != argc - optind); + } + + exit (exit_status); +} diff --git a/src/apps/bin/coreutils-5.0/src/printf.c b/src/apps/bin/coreutils-5.0/src/printf.c new file mode 100644 index 0000000000..22e1b97559 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/printf.c @@ -0,0 +1,598 @@ +/* printf - format and print data + Copyright (C) 1990-2003, Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Usage: printf format [argument...] + + A front end to the printf function that lets it be used from the shell. + + Backslash escapes: + + \" = double quote + \\ = backslash + \a = alert (bell) + \b = backspace + \c = produce no further output + \f = form feed + \n = new line + \r = carriage return + \t = horizontal tab + \v = vertical tab + \0ooo = octal number (ooo is 0 to 3 digits) + \xhh = hexadecimal number (hhh is 1 to 2 digits) + \uhhhh = 16-bit Unicode character (hhhh is 4 digits) + \Uhhhhhhhh = 32-bit Unicode character (hhhhhhhh is 8 digits) + + Additional directive: + + %b = print an argument string, interpreting backslash escapes + + The `format' argument is re-used as many times as necessary + to convert all of the given arguments. + + David MacKenzie */ + +#include +#include +#include +#include + +#include "system.h" +#include "long-options.h" +#include "error.h" +#include "closeout.h" +#include "unicodeio.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "printf" + +#define AUTHORS "David MacKenzie" + +#ifndef STDC_HEADERS +double strtod (); +long int strtol (); +unsigned long int strtoul (); +#endif + +#define isodigit(c) ((c) >= '0' && (c) <= '7') +#define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \ + (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0') +#define octtobin(c) ((c) - '0') + +/* A value for field_width or precision that indicates it was not specified. */ +#define UNSPECIFIED INT_MIN + +/* The value to return to the calling program. */ +static int exit_status; + +/* Non-zero if the POSIXLY_CORRECT environment variable is set. */ +static int posixly_correct; + +/* This message appears in N_() here rather than just in _() below because + the sole use would have been in a #define. */ +static char *const cfcc_msg = + N_("warning: %s: character(s) following character constant have been ignored"); + +/* The name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s FORMAT [ARGUMENT]...\n\ + or: %s OPTION\n\ +"), + program_name, program_name); + fputs (_("\ +Print ARGUMENT(s) according to FORMAT.\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +FORMAT controls the output as in C printf. Interpreted sequences are:\n\ +\n\ + \\\" double quote\n\ + \\0NNN character with octal value NNN (0 to 3 digits)\n\ + \\\\ backslash\n\ +"), stdout); + fputs (_("\ + \\a alert (BEL)\n\ + \\b backspace\n\ + \\c produce no further output\n\ + \\f form feed\n\ +"), stdout); + fputs (_("\ + \\n new line\n\ + \\r carriage return\n\ + \\t horizontal tab\n\ + \\v vertical tab\n\ +"), stdout); + fputs (_("\ + \\xNN byte with hexadecimal value NN (1 to 2 digits)\n\ +\n\ + \\uNNNN character with hexadecimal value NNNN (4 digits)\n\ + \\UNNNNNNNN character with hexadecimal value NNNNNNNN (8 digits)\n\ +"), stdout); + fputs (_("\ + %% a single %\n\ + %b ARGUMENT as a string with `\\' escapes interpreted\n\ +\n\ +and all C format specifications ending with one of diouxXfeEgGcs, with\n\ +ARGUMENTs converted to proper type first. Variable widths are handled.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +static void +verify (const char *s, const char *end) +{ + if (errno) + { + error (0, errno, "%s", s); + exit_status = 1; + } + else if (*end) + { + if (s == end) + error (0, 0, _("%s: expected a numeric value"), s); + else + error (0, 0, _("%s: value not completely converted"), s); + exit_status = 1; + } +} + +#define STRTOX(TYPE, FUNC_NAME, LIB_FUNC_EXPR) \ +static TYPE \ +FUNC_NAME (s) \ + const char *s; \ +{ \ + char *end; \ + TYPE val; \ + \ + if (*s == '\"' || *s == '\'') \ + { \ + val = *(unsigned char *) ++s; \ + /* If POSIXLY_CORRECT is not set, then give a warning that there \ + are characters following the character constant and that GNU \ + printf is ignoring those characters. If POSIXLY_CORRECT *is* \ + set, then don't give the warning. */ \ + if (*++s != 0 && !posixly_correct) \ + error (0, 0, _(cfcc_msg), s); \ + } \ + else \ + { \ + errno = 0; \ + val = LIB_FUNC_EXPR; \ + verify (s, end); \ + } \ + return val; \ +} \ + +STRTOX (unsigned long int, xstrtoul, (strtoul (s, &end, 0))) +STRTOX (long int, xstrtol, (strtol (s, &end, 0))) +STRTOX (double, xstrtod, (strtod (s, &end))) + +/* Output a single-character \ escape. */ + +static void +print_esc_char (int c) +{ + switch (c) + { + case 'a': /* Alert. */ + putchar (7); + break; + case 'b': /* Backspace. */ + putchar (8); + break; + case 'c': /* Cancel the rest of the output. */ + exit (EXIT_SUCCESS); + break; + case 'f': /* Form feed. */ + putchar (12); + break; + case 'n': /* New line. */ + putchar (10); + break; + case 'r': /* Carriage return. */ + putchar (13); + break; + case 't': /* Horizontal tab. */ + putchar (9); + break; + case 'v': /* Vertical tab. */ + putchar (11); + break; + default: + putchar (c); + break; + } +} + +/* Print a \ escape sequence starting at ESCSTART. + Return the number of characters in the escape sequence + besides the backslash. */ + +static int +print_esc (const char *escstart) +{ + register const char *p = escstart + 1; + int esc_value = 0; /* Value of \nnn escape. */ + int esc_length; /* Length of \nnn escape. */ + + if (!posixly_correct && *p == 'x') + { + /* A hexadecimal \xhh escape sequence must have 1 or 2 hex. digits. */ + for (esc_length = 0, ++p; + esc_length < 2 && ISXDIGIT (*p); + ++esc_length, ++p) + esc_value = esc_value * 16 + hextobin (*p); + if (esc_length == 0) + error (EXIT_FAILURE, 0, _("missing hexadecimal number in escape")); + putchar (esc_value); + } + else if (*p == '0') + { + /* An octal \0ooo escape sequence has 0 to 3 octal digits + after the leading \0. */ + for (esc_length = 0, ++p; + esc_length < 3 && isodigit (*p); + ++esc_length, ++p) + esc_value = esc_value * 8 + octtobin (*p); + putchar (esc_value); + } + else if (*p && strchr ("\"\\abcfnrtv", *p)) + print_esc_char (*p++); + else if (!posixly_correct && (*p == 'u' || *p == 'U')) + { + char esc_char = *p; + unsigned int uni_value; + + uni_value = 0; + for (esc_length = (esc_char == 'u' ? 4 : 8), ++p; + esc_length > 0; + --esc_length, ++p) + { + if (!ISXDIGIT (*p)) + error (EXIT_FAILURE, 0, _("missing hexadecimal number in escape")); + uni_value = uni_value * 16 + hextobin (*p); + } + + /* A universal character name shall not specify a character short + identifier in the range 00000000 through 00000020, 0000007F through + 0000009F, or 0000D800 through 0000DFFF inclusive. A universal + character name shall not designate a character in the required + character set. */ + if ((uni_value <= 0x9f + && uni_value != 0x24 && uni_value != 0x40 && uni_value != 0x60) + || (uni_value >= 0xd800 && uni_value <= 0xdfff)) + error (EXIT_FAILURE, 0, _("invalid universal character name \\%c%0*x"), + esc_char, (esc_char == 'u' ? 4 : 8), uni_value); + + print_unicode_char (stdout, uni_value, 0); + } + else + { + putchar ('\\'); + if (*p) + { + putchar (*p); + p++; + } + } + return p - escstart - 1; +} + +/* Print string STR, evaluating \ escapes. */ + +static void +print_esc_string (const char *str) +{ + for (; *str; str++) + if (*str == '\\') + str += print_esc (str); + else + putchar (*str); +} + +/* Output a % directive. START is the start of the directive, + LENGTH is its length, and ARGUMENT is its argument. + If FIELD_WIDTH or PRECISION is UNSPECIFIED, they are args for + '*' values in those fields. */ + +static void +print_direc (const char *start, size_t length, int field_width, + int precision, const char *argument) +{ + char *p; /* Null-terminated copy of % directive. */ + + p = xmalloc ((unsigned) (length + 1)); + strncpy (p, start, length); + p[length] = 0; + + switch (p[length - 1]) + { + case 'd': + case 'i': + if (field_width == UNSPECIFIED) + { + if (precision == UNSPECIFIED) + printf (p, xstrtol (argument)); + else + printf (p, precision, xstrtol (argument)); + } + else + { + if (precision == UNSPECIFIED) + printf (p, field_width, xstrtol (argument)); + else + printf (p, field_width, precision, xstrtol (argument)); + } + break; + + case 'o': + case 'u': + case 'x': + case 'X': + if (field_width == UNSPECIFIED) + { + if (precision == UNSPECIFIED) + printf (p, xstrtoul (argument)); + else + printf (p, precision, xstrtoul (argument)); + } + else + { + if (precision == UNSPECIFIED) + printf (p, field_width, xstrtoul (argument)); + else + printf (p, field_width, precision, xstrtoul (argument)); + } + break; + + case 'f': + case 'e': + case 'E': + case 'g': + case 'G': + if (field_width == UNSPECIFIED) + { + if (precision == UNSPECIFIED) + printf (p, xstrtod (argument)); + else + printf (p, precision, xstrtod (argument)); + } + else + { + if (precision == UNSPECIFIED) + printf (p, field_width, xstrtod (argument)); + else + printf (p, field_width, precision, xstrtod (argument)); + } + break; + + case 'c': + printf (p, *argument); + break; + + case 's': + if (field_width == UNSPECIFIED) + { + if (precision == UNSPECIFIED) + printf (p, argument); + else + printf (p, precision, argument); + } + else + { + if (precision == UNSPECIFIED) + printf (p, field_width, argument); + else + printf (p, field_width, precision, argument); + } + break; + } + + free (p); +} + +/* Print the text in FORMAT, using ARGV (with ARGC elements) for + arguments to any `%' directives. + Return the number of elements of ARGV used. */ + +static int +print_formatted (const char *format, int argc, char **argv) +{ + int save_argc = argc; /* Preserve original value. */ + const char *f; /* Pointer into `format'. */ + const char *direc_start; /* Start of % directive. */ + size_t direc_length; /* Length of % directive. */ + int field_width; /* Arg to first '*', or UNSPECIFIED if none. */ + int precision; /* Arg to second '*', or UNSPECIFIED if none. */ + + for (f = format; *f; ++f) + { + switch (*f) + { + case '%': + direc_start = f++; + direc_length = 1; + field_width = precision = UNSPECIFIED; + if (*f == '%') + { + putchar ('%'); + break; + } + if (*f == 'b') + { + if (argc > 0) + { + print_esc_string (*argv); + ++argv; + --argc; + } + break; + } + while (*f == ' ' || *f == '#' || *f == '+' || *f == '-') + { + ++f; + ++direc_length; + } + if (*f == '*') + { + ++f; + ++direc_length; + if (argc > 0) + { + field_width = xstrtoul (*argv); + if (field_width == UNSPECIFIED) + error (EXIT_FAILURE, 0, _("invalid field width: %s"), + *argv); + ++argv; + --argc; + } + else + field_width = 0; + } + else + while (ISDIGIT (*f)) + { + ++f; + ++direc_length; + } + if (*f == '.') + { + ++f; + ++direc_length; + if (*f == '*') + { + ++f; + ++direc_length; + if (argc > 0) + { + precision = xstrtoul (*argv); + if (precision == UNSPECIFIED) + error (EXIT_FAILURE, 0, _("invalid precision: %s"), + *argv); + ++argv; + --argc; + } + else + precision = 0; + } + else + while (ISDIGIT (*f)) + { + ++f; + ++direc_length; + } + } + if (*f == 'l' || *f == 'L' || *f == 'h') + { + ++f; + ++direc_length; + } + if (! (*f && strchr ("diouxXfeEgGcs", *f))) + error (EXIT_FAILURE, 0, _("%%%c: invalid directive"), *f); + ++direc_length; + if (argc > 0) + { + print_direc (direc_start, direc_length, field_width, + precision, *argv); + ++argv; + --argc; + } + else + print_direc (direc_start, direc_length, field_width, + precision, ""); + break; + + case '\\': + f += print_esc (f); + break; + + default: + putchar (*f); + } + } + + return save_argc - argc; +} + +int +main (int argc, char **argv) +{ + char *format; + int args_used; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + exit_status = 0; + + /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */ + posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL); + if (!posixly_correct) + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + /* The above handles --help and --version. + Since there is no other invocation of getopt, handle `--' here. */ + if (1 < argc && STREQ (argv[1], "--")) + { + --argc; + ++argv; + } + + if (argc == 1) + { + fprintf (stderr, _("Usage: %s format [argument...]\n"), program_name); + exit (EXIT_FAILURE); + } + + format = argv[1]; + argc -= 2; + argv += 2; + + do + { + args_used = print_formatted (format, argc, argv); + argc -= args_used; + argv += args_used; + } + while (args_used > 0 && argc > 0); + + if (argc > 0) + error (0, 0, + _("warning: ignoring excess arguments, starting with `%s'"), + argv[0]); + + exit (exit_status); +} diff --git a/src/apps/bin/coreutils-5.0/src/ptx.c b/src/apps/bin/coreutils-5.0/src/ptx.c new file mode 100644 index 0000000000..75c815bfcf --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/ptx.c @@ -0,0 +1,2212 @@ +/* Permuted index for GNU, with keywords in their context. + Copyright (C) 1990, 1991, 1993, 1998-2003 Free Software Foundation, Inc. + François Pinard , 1988. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + François Pinard */ + +#include + +#include +#include +#include +#include "system.h" +#include "closeout.h" +#include "argmatch.h" +#include "bumpalloc.h" +#include "diacrit.h" +#include "error.h" +#include "regex.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "ptx" + +#define AUTHORS "François Pinard" + +/* Number of possible characters in a byte. */ +#define CHAR_SET_SIZE 256 + +#define ISODIGIT(C) ((C) >= '0' && (C) <= '7') +#define HEXTOBIN(C) ((C) >= 'a' && (C) <= 'f' ? (C)-'a'+10 \ + : (C) >= 'A' && (C) <= 'F' ? (C)-'A'+10 : (C)-'0') +#define OCTTOBIN(C) ((C) - '0') + +/* Debugging the memory allocator. */ + +#if WITH_DMALLOC +# define MALLOC_FUNC_CHECK 1 +# include +#endif + +/* Global definitions. */ + +/* Reallocation step when swallowing non regular files. The value is not + the actual reallocation step, but its base two logarithm. */ +#define SWALLOW_REALLOC_LOG 12 + +/* Imported from "regex.c". */ +#define Sword 1 + +/* The name this program was run with. */ +char *program_name; + +/* Program options. */ + +enum Format +{ + UNKNOWN_FORMAT, /* output format still unknown */ + DUMB_FORMAT, /* output for a dumb terminal */ + ROFF_FORMAT, /* output for `troff' or `nroff' */ + TEX_FORMAT /* output for `TeX' or `LaTeX' */ +}; + +int gnu_extensions = 1; /* trigger all GNU extensions */ +int auto_reference = 0; /* references are `file_name:line_number:' */ +int input_reference = 0; /* references at beginning of input lines */ +int right_reference = 0; /* output references after right context */ +int line_width = 72; /* output line width in characters */ +int gap_size = 3; /* number of spaces between output fields */ +const char *truncation_string = "/"; + /* string used to mark line truncations */ +const char *macro_name = "xx"; /* macro name for roff or TeX output */ +enum Format output_format = UNKNOWN_FORMAT; + /* output format */ + +int ignore_case = 0; /* fold lower to upper case for sorting */ +const char *context_regex_string = NULL; + /* raw regex for end of context */ +const char *word_regex_string = NULL; + /* raw regex for a keyword */ +const char *break_file = NULL; /* name of the `Break characters' file */ +const char *only_file = NULL; /* name of the `Only words' file */ +const char *ignore_file = NULL; /* name of the `Ignore words' file */ + +/* A BLOCK delimit a region in memory of arbitrary size, like the copy of a + whole file. A WORD is something smaller, its length should fit in a + short integer. A WORD_TABLE may contain several WORDs. */ + +typedef struct + { + char *start; /* pointer to beginning of region */ + char *end; /* pointer to end + 1 of region */ + } +BLOCK; + +typedef struct + { + char *start; /* pointer to beginning of region */ + short size; /* length of the region */ + } +WORD; + +typedef struct + { + WORD *start; /* array of WORDs */ + size_t length; /* number of entries */ + } +WORD_TABLE; + +/* Pattern description tables. */ + +/* For each character, provide its folded equivalent. */ +unsigned char folded_chars[CHAR_SET_SIZE]; + +/* For each character, indicate if it is part of a word. */ +char syntax_table[CHAR_SET_SIZE]; +char *re_syntax_table = syntax_table; + +/* Compiled regex for end of context. */ +struct re_pattern_buffer *context_regex; + +/* End of context pattern register indices. */ +struct re_registers context_regs; + +/* Compiled regex for a keyword. */ +struct re_pattern_buffer *word_regex; + +/* Keyword pattern register indices. */ +struct re_registers word_regs; + +/* A word characters fastmap is used only when no word regexp has been + provided. A word is then made up of a sequence of one or more characters + allowed by the fastmap. Contains !0 if character allowed in word. Not + only this is faster in most cases, but it simplifies the implementation + of the Break files. */ +char word_fastmap[CHAR_SET_SIZE]; + +/* Maximum length of any word read. */ +int maximum_word_length; + +/* Maximum width of any reference used. */ +int reference_max_width; + +/* Ignore and Only word tables. */ + +WORD_TABLE ignore_table; /* table of words to ignore */ +WORD_TABLE only_table; /* table of words to select */ + +#define ALLOC_NEW_WORD(table) \ + BUMP_ALLOC ((table)->start, (table)->length, 8, WORD) + +/* Source text table, and scanning macros. */ + +int number_input_files; /* number of text input files */ +int total_line_count; /* total number of lines seen so far */ +const char **input_file_name; /* array of text input file names */ +int *file_line_count; /* array of `total_line_count' values at end */ + +BLOCK text_buffer; /* file to study */ +char *text_buffer_maxend; /* allocated end of text_buffer */ + +/* SKIP_NON_WHITE used only for getting or skipping the reference. */ + +#define SKIP_NON_WHITE(cursor, limit) \ + while (cursor < limit && !ISSPACE(*cursor)) \ + cursor++ + +#define SKIP_WHITE(cursor, limit) \ + while (cursor < limit && ISSPACE(*cursor)) \ + cursor++ + +#define SKIP_WHITE_BACKWARDS(cursor, start) \ + while (cursor > start && ISSPACE(cursor[-1])) \ + cursor-- + +#define SKIP_SOMETHING(cursor, limit) \ + if (word_regex_string) \ + { \ + int count; \ + count = re_match (word_regex, cursor, limit - cursor, 0, NULL); \ + cursor += count <= 0 ? 1 : count; \ + } \ + else if (word_fastmap[(unsigned char) *cursor]) \ + while (cursor < limit && word_fastmap[(unsigned char) *cursor]) \ + cursor++; \ + else \ + cursor++ + +/* Occurrences table. + + The `keyword' pointer provides the central word, which is surrounded + by a left context and a right context. The `keyword' and `length' + field allow full 8-bit characters keys, even including NULs. At other + places in this program, the name `keyafter' refers to the keyword + followed by its right context. + + The left context does not extend, towards the beginning of the file, + further than a distance given by the `left' value. This value is + relative to the keyword beginning, it is usually negative. This + insures that, except for white space, we will never have to backward + scan the source text, when it is time to generate the final output + lines. + + The right context, indirectly attainable through the keyword end, does + not extend, towards the end of the file, further than a distance given + by the `right' value. This value is relative to the keyword + beginning, it is usually positive. + + When automatic references are used, the `reference' value is the + overall line number in all input files read so far, in this case, it + is of type (int). When input references are used, the `reference' + value indicates the distance between the keyword beginning and the + start of the reference field, it is of type (DELTA) and usually + negative. */ + +typedef short DELTA; /* to hold displacement within one context */ + +typedef struct + { + WORD key; /* description of the keyword */ + DELTA left; /* distance to left context start */ + DELTA right; /* distance to right context end */ + int reference; /* reference descriptor */ + } +OCCURS; + +/* The various OCCURS tables are indexed by the language. But the time + being, there is no such multiple language support. */ + +OCCURS *occurs_table[1]; /* all words retained from the read text */ +size_t number_of_occurs[1]; /* number of used slots in occurs_table */ + +#define ALLOC_NEW_OCCURS(language) \ + BUMP_ALLOC (occurs_table[language], number_of_occurs[language], 9, OCCURS) + +/* Communication among output routines. */ + +/* Indicate if special output processing is requested for each character. */ +char edited_flag[CHAR_SET_SIZE]; + +int half_line_width; /* half of line width, reference excluded */ +int before_max_width; /* maximum width of before field */ +int keyafter_max_width; /* maximum width of keyword-and-after field */ +int truncation_string_length; /* length of string used to flag truncation */ + +/* When context is limited by lines, wraparound may happen on final output: + the `head' pointer gives access to some supplementary left context which + will be seen at the end of the output line, the `tail' pointer gives + access to some supplementary right context which will be seen at the + beginning of the output line. */ + +BLOCK tail; /* tail field */ +int tail_truncation; /* flag truncation after the tail field */ + +BLOCK before; /* before field */ +int before_truncation; /* flag truncation before the before field */ + +BLOCK keyafter; /* keyword-and-after field */ +int keyafter_truncation; /* flag truncation after the keyafter field */ + +BLOCK head; /* head field */ +int head_truncation; /* flag truncation before the head field */ + +BLOCK reference; /* reference field for input reference mode */ + +/* Miscellaneous routines. */ + +/*------------------------------------------------------. +| Duplicate string STRING, while evaluating \-escapes. | +`------------------------------------------------------*/ + +/* Loosely adapted from GNU sh-utils printf.c code. */ + +static char * +copy_unescaped_string (const char *string) +{ + char *result; /* allocated result */ + char *cursor; /* cursor in result */ + int value; /* value of \nnn escape */ + int length; /* length of \nnn escape */ + + result = xmalloc (strlen (string) + 1); + cursor = result; + + while (*string) + if (*string == '\\') + { + string++; + switch (*string) + { + case 'x': /* \xhhh escape, 3 chars maximum */ + value = 0; + for (length = 0, string++; + length < 3 && ISXDIGIT (*string); + length++, string++) + value = value * 16 + HEXTOBIN (*string); + if (length == 0) + { + *cursor++ = '\\'; + *cursor++ = 'x'; + } + else + *cursor++ = value; + break; + + case '0': /* \0ooo escape, 3 chars maximum */ + value = 0; + for (length = 0, string++; + length < 3 && ISODIGIT (*string); + length++, string++) + value = value * 8 + OCTTOBIN (*string); + *cursor++ = value; + break; + + case 'a': /* alert */ +#if __STDC__ + *cursor++ = '\a'; +#else + *cursor++ = 7; +#endif + string++; + break; + + case 'b': /* backspace */ + *cursor++ = '\b'; + string++; + break; + + case 'c': /* cancel the rest of the output */ + while (*string) + string++; + break; + + case 'f': /* form feed */ + *cursor++ = '\f'; + string++; + break; + + case 'n': /* new line */ + *cursor++ = '\n'; + string++; + break; + + case 'r': /* carriage return */ + *cursor++ = '\r'; + string++; + break; + + case 't': /* horizontal tab */ + *cursor++ = '\t'; + string++; + break; + + case 'v': /* vertical tab */ +#if __STDC__ + *cursor++ = '\v'; +#else + *cursor++ = 11; +#endif + string++; + break; + + default: + *cursor++ = '\\'; + *cursor++ = *string++; + break; + } + } + else + *cursor++ = *string++; + + *cursor = '\0'; + return result; +} + +/*-------------------------------------------------------------------. +| Compile the regex represented by STRING, diagnose and abort if any | +| error. Returns the compiled regex structure. | +`-------------------------------------------------------------------*/ + +static struct re_pattern_buffer * +alloc_and_compile_regex (const char *string) +{ + struct re_pattern_buffer *pattern; /* newly allocated structure */ + const char *message; /* error message returned by regex.c */ + + pattern = (struct re_pattern_buffer *) + xmalloc (sizeof (struct re_pattern_buffer)); + memset (pattern, 0, sizeof (struct re_pattern_buffer)); + + pattern->buffer = NULL; + pattern->allocated = 0; + pattern->translate = ignore_case ? (char *) folded_chars : NULL; + pattern->fastmap = (char *) xmalloc ((size_t) CHAR_SET_SIZE); + + message = re_compile_pattern (string, (int) strlen (string), pattern); + if (message) + error (EXIT_FAILURE, 0, _("%s (for regexp `%s')"), message, string); + + /* The fastmap should be compiled before `re_match'. The following + call is not mandatory, because `re_search' is always called sooner, + and it compiles the fastmap if this has not been done yet. */ + + re_compile_fastmap (pattern); + + /* Do not waste extra allocated space. */ + + if (pattern->allocated > pattern->used) + { + pattern->buffer + = (unsigned char *) xrealloc (pattern->buffer, (size_t) pattern->used); + pattern->allocated = pattern->used; + } + + return pattern; +} + +/*------------------------------------------------------------------------. +| This will initialize various tables for pattern match and compiles some | +| regexps. | +`------------------------------------------------------------------------*/ + +static void +initialize_regex (void) +{ + int character; /* character value */ + + /* Initialize the regex syntax table. */ + + for (character = 0; character < CHAR_SET_SIZE; character++) + syntax_table[character] = ISALPHA (character) ? Sword : 0; + + /* Initialize the case folding table. */ + + if (ignore_case) + for (character = 0; character < CHAR_SET_SIZE; character++) + folded_chars[character] = TOUPPER (character); + + /* Unless the user already provided a description of the end of line or + end of sentence sequence, select an end of line sequence to compile. + If the user provided an empty definition, thus disabling end of line + or sentence feature, make it NULL to speed up tests. If GNU + extensions are enabled, use end of sentence like in GNU emacs. If + disabled, use end of lines. */ + + if (context_regex_string) + { + if (!*context_regex_string) + context_regex_string = NULL; + } + else if (gnu_extensions && !input_reference) + context_regex_string = "[.?!][]\"')}]*\\($\\|\t\\| \\)[ \t\n]*"; + else + context_regex_string = "\n"; + + if (context_regex_string) + context_regex = alloc_and_compile_regex (context_regex_string); + + /* If the user has already provided a non-empty regexp to describe + words, compile it. Else, unless this has already been done through + a user provided Break character file, construct a fastmap of + characters that may appear in a word. If GNU extensions enabled, + include only letters of the underlying character set. If disabled, + include almost everything, even punctuations; stop only on white + space. */ + + if (word_regex_string && *word_regex_string) + word_regex = alloc_and_compile_regex (word_regex_string); + else if (!break_file) + { + if (gnu_extensions) + { + + /* Simulate \w+. */ + + for (character = 0; character < CHAR_SET_SIZE; character++) + word_fastmap[character] = ISALPHA (character) ? 1 : 0; + } + else + { + + /* Simulate [^ \t\n]+. */ + + memset (word_fastmap, 1, CHAR_SET_SIZE); + word_fastmap[' '] = 0; + word_fastmap['\t'] = 0; + word_fastmap['\n'] = 0; + } + } +} + +/*------------------------------------------------------------------------. +| This routine will attempt to swallow a whole file name FILE_NAME into a | +| contiguous region of memory and return a description of it into BLOCK. | +| Standard input is assumed whenever FILE_NAME is NULL, empty or "-". | +| | +| Previously, in some cases, white space compression was attempted while | +| inputting text. This was defeating some regexps like default end of | +| sentence, which checks for two consecutive spaces. If white space | +| compression is ever reinstated, it should be in output routines. | +`------------------------------------------------------------------------*/ + +static void +swallow_file_in_memory (const char *file_name, BLOCK *block) +{ + int file_handle; /* file descriptor number */ + struct stat stat_block; /* stat block for file */ + size_t allocated_length; /* allocated length of memory buffer */ + size_t used_length; /* used length in memory buffer */ + int read_length; /* number of character gotten on last read */ + + /* As special cases, a file name which is NULL or "-" indicates standard + input, which is already opened. In all other cases, open the file from + its name. */ + bool using_stdin = !file_name || !*file_name || strcmp (file_name, "-") == 0; + if (using_stdin) + file_handle = STDIN_FILENO; + else + if ((file_handle = open (file_name, O_RDONLY)) < 0) + error (EXIT_FAILURE, errno, "%s", file_name); + + /* If the file is a plain, regular file, allocate the memory buffer all at + once and swallow the file in one blow. In other cases, read the file + repeatedly in smaller chunks until we have it all, reallocating memory + once in a while, as we go. */ + + if (fstat (file_handle, &stat_block) < 0) + error (EXIT_FAILURE, errno, "%s", file_name); + + if (S_ISREG (stat_block.st_mode)) + { + size_t in_memory_size; + + block->start = (char *) xmalloc ((size_t) stat_block.st_size); + + if ((in_memory_size = read (file_handle, + block->start, (size_t) stat_block.st_size)) + != stat_block.st_size) + { +#if MSDOS + /* On MSDOS, in memory size may be smaller than the file + size, because of end of line conversions. But it can + never be smaller than half the file size, because the + minimum is when all lines are empty and terminated by + CR+LF. */ + if (in_memory_size != (size_t)-1 + && in_memory_size >= stat_block.st_size / 2) + block->start = (char *) xrealloc (block->start, in_memory_size); + else +#endif /* not MSDOS */ + + error (EXIT_FAILURE, errno, "%s", file_name); + } + block->end = block->start + in_memory_size; + } + else + { + block->start = (char *) xmalloc ((size_t) 1 << SWALLOW_REALLOC_LOG); + used_length = 0; + allocated_length = (1 << SWALLOW_REALLOC_LOG); + + while (read_length = read (file_handle, + block->start + used_length, + allocated_length - used_length), + read_length > 0) + { + used_length += read_length; + if (used_length == allocated_length) + { + allocated_length += (1 << SWALLOW_REALLOC_LOG); + block->start + = (char *) xrealloc (block->start, allocated_length); + } + } + + if (read_length < 0) + error (EXIT_FAILURE, errno, "%s", file_name); + + block->end = block->start + used_length; + } + + /* Close the file, but only if it was not the standard input. */ + + if (! using_stdin && close (file_handle) != 0) + error (EXIT_FAILURE, errno, "%s", file_name); +} + +/* Sort and search routines. */ + +/*--------------------------------------------------------------------------. +| Compare two words, FIRST and SECOND, and return 0 if they are identical. | +| Return less than 0 if the first word goes before the second; return | +| greater than 0 if the first word goes after the second. | +| | +| If a word is indeed a prefix of the other, the shorter should go first. | +`--------------------------------------------------------------------------*/ + +static int +compare_words (const void *void_first, const void *void_second) +{ +#define first ((const WORD *) void_first) +#define second ((const WORD *) void_second) + int length; /* minimum of two lengths */ + int counter; /* cursor in words */ + int value; /* value of comparison */ + + length = first->size < second->size ? first->size : second->size; + + if (ignore_case) + { + for (counter = 0; counter < length; counter++) + { + value = (folded_chars [(unsigned char) (first->start[counter])] + - folded_chars [(unsigned char) (second->start[counter])]); + if (value != 0) + return value; + } + } + else + { + for (counter = 0; counter < length; counter++) + { + value = ((unsigned char) first->start[counter] + - (unsigned char) second->start[counter]); + if (value != 0) + return value; + } + } + + return first->size - second->size; +#undef first +#undef second +} + +/*-----------------------------------------------------------------------. +| Decides which of two OCCURS, FIRST or SECOND, should lexicographically | +| go first. In case of a tie, preserve the original order through a | +| pointer comparison. | +`-----------------------------------------------------------------------*/ + +static int +compare_occurs (const void *void_first, const void *void_second) +{ +#define first ((const OCCURS *) void_first) +#define second ((const OCCURS *) void_second) + int value; + + value = compare_words (&first->key, &second->key); + return value == 0 ? first->key.start - second->key.start : value; +#undef first +#undef second +} + +/*------------------------------------------------------------. +| Return !0 if WORD appears in TABLE. Uses a binary search. | +`------------------------------------------------------------*/ + +static int +search_table (WORD *word, WORD_TABLE *table) +{ + int lowest; /* current lowest possible index */ + int highest; /* current highest possible index */ + int middle; /* current middle index */ + int value; /* value from last comparison */ + + lowest = 0; + highest = table->length - 1; + while (lowest <= highest) + { + middle = (lowest + highest) / 2; + value = compare_words (word, table->start + middle); + if (value < 0) + highest = middle - 1; + else if (value > 0) + lowest = middle + 1; + else + return 1; + } + return 0; +} + +/*---------------------------------------------------------------------. +| Sort the whole occurs table in memory. Presumably, `qsort' does not | +| take intermediate copies or table elements, so the sort will be | +| stabilized throughout the comparison routine. | +`---------------------------------------------------------------------*/ + +static void +sort_found_occurs (void) +{ + + /* Only one language for the time being. */ + + qsort (occurs_table[0], number_of_occurs[0], sizeof (OCCURS), + compare_occurs); +} + +/* Parameter files reading routines. */ + +/*----------------------------------------------------------------------. +| Read a file named FILE_NAME, containing a set of break characters. | +| Build a content to the array word_fastmap in which all characters are | +| allowed except those found in the file. Characters may be repeated. | +`----------------------------------------------------------------------*/ + +static void +digest_break_file (const char *file_name) +{ + BLOCK file_contents; /* to receive a copy of the file */ + char *cursor; /* cursor in file copy */ + + swallow_file_in_memory (file_name, &file_contents); + + /* Make the fastmap and record the file contents in it. */ + + memset (word_fastmap, 1, CHAR_SET_SIZE); + for (cursor = file_contents.start; cursor < file_contents.end; cursor++) + word_fastmap[(unsigned char) *cursor] = 0; + + if (!gnu_extensions) + { + + /* If GNU extensions are enabled, the only way to avoid newline as + a break character is to write all the break characters in the + file with no newline at all, not even at the end of the file. + If disabled, spaces, tabs and newlines are always considered as + break characters even if not included in the break file. */ + + word_fastmap[' '] = 0; + word_fastmap['\t'] = 0; + word_fastmap['\n'] = 0; + } + + /* Return the space of the file, which is no more required. */ + + free (file_contents.start); +} + +/*-----------------------------------------------------------------------. +| Read a file named FILE_NAME, containing one word per line, then | +| construct in TABLE a table of WORD descriptors for them. The routine | +| swallows the whole file in memory; this is at the expense of space | +| needed for newlines, which are useless; however, the reading is fast. | +`-----------------------------------------------------------------------*/ + +static void +digest_word_file (const char *file_name, WORD_TABLE *table) +{ + BLOCK file_contents; /* to receive a copy of the file */ + char *cursor; /* cursor in file copy */ + char *word_start; /* start of the current word */ + + swallow_file_in_memory (file_name, &file_contents); + + table->start = NULL; + table->length = 0; + + /* Read the whole file. */ + + cursor = file_contents.start; + while (cursor < file_contents.end) + { + + /* Read one line, and save the word in contains. */ + + word_start = cursor; + while (cursor < file_contents.end && *cursor != '\n') + cursor++; + + /* Record the word in table if it is not empty. */ + + if (cursor > word_start) + { + ALLOC_NEW_WORD (table); + table->start[table->length].start = word_start; + table->start[table->length].size = cursor - word_start; + table->length++; + } + + /* This test allows for an incomplete line at end of file. */ + + if (cursor < file_contents.end) + cursor++; + } + + /* Finally, sort all the words read. */ + + qsort (table->start, table->length, (size_t) sizeof (WORD), compare_words); +} + +/* Keyword recognition and selection. */ + +/*----------------------------------------------------------------------. +| For each keyword in the source text, constructs an OCCURS structure. | +`----------------------------------------------------------------------*/ + +static void +find_occurs_in_text (void) +{ + char *cursor; /* for scanning the source text */ + char *scan; /* for scanning the source text also */ + char *line_start; /* start of the current input line */ + char *line_scan; /* newlines scanned until this point */ + int reference_length; /* length of reference in input mode */ + WORD possible_key; /* possible key, to ease searches */ + OCCURS *occurs_cursor; /* current OCCURS under construction */ + + char *context_start; /* start of left context */ + char *context_end; /* end of right context */ + char *word_start; /* start of word */ + char *word_end; /* end of word */ + char *next_context_start; /* next start of left context */ + + /* reference_length is always used within `if (input_reference)'. + However, GNU C diagnoses that it may be used uninitialized. The + following assignment is merely to shut it up. */ + + reference_length = 0; + + /* Tracking where lines start is helpful for reference processing. In + auto reference mode, this allows counting lines. In input reference + mode, this permits finding the beginning of the references. + + The first line begins with the file, skip immediately this very first + reference in input reference mode, to help further rejection any word + found inside it. Also, unconditionally assigning these variable has + the happy effect of shutting up lint. */ + + line_start = text_buffer.start; + line_scan = line_start; + if (input_reference) + { + SKIP_NON_WHITE (line_scan, text_buffer.end); + reference_length = line_scan - line_start; + SKIP_WHITE (line_scan, text_buffer.end); + } + + /* Process the whole buffer, one line or one sentence at a time. */ + + for (cursor = text_buffer.start; + cursor < text_buffer.end; + cursor = next_context_start) + { + + /* `context_start' gets initialized before the processing of each + line, or once for the whole buffer if no end of line or sentence + sequence separator. */ + + context_start = cursor; + + /* If a end of line or end of sentence sequence is defined and + non-empty, `next_context_start' will be recomputed to be the end of + each line or sentence, before each one is processed. If no such + sequence, then `next_context_start' is set at the end of the whole + buffer, which is then considered to be a single line or sentence. + This test also accounts for the case of an incomplete line or + sentence at the end of the buffer. */ + + if (context_regex_string + && (re_search (context_regex, cursor, text_buffer.end - cursor, + 0, text_buffer.end - cursor, &context_regs) + >= 0)) + next_context_start = cursor + context_regs.end[0]; + + else + next_context_start = text_buffer.end; + + /* Include the separator into the right context, but not any suffix + white space in this separator; this insures it will be seen in + output and will not take more space than necessary. */ + + context_end = next_context_start; + SKIP_WHITE_BACKWARDS (context_end, context_start); + + /* Read and process a single input line or sentence, one word at a + time. */ + + while (1) + { + if (word_regex) + + /* If a word regexp has been compiled, use it to skip at the + beginning of the next word. If there is no such word, exit + the loop. */ + + { + if (re_search (word_regex, cursor, context_end - cursor, + 0, context_end - cursor, &word_regs) + < 0) + break; + word_start = cursor + word_regs.start[0]; + word_end = cursor + word_regs.end[0]; + } + else + + /* Avoid re_search and use the fastmap to skip to the + beginning of the next word. If there is no more word in + the buffer, exit the loop. */ + + { + scan = cursor; + while (scan < context_end + && !word_fastmap[(unsigned char) *scan]) + scan++; + + if (scan == context_end) + break; + + word_start = scan; + + while (scan < context_end + && word_fastmap[(unsigned char) *scan]) + scan++; + + word_end = scan; + } + + /* Skip right to the beginning of the found word. */ + + cursor = word_start; + + /* Skip any zero length word. Just advance a single position, + then go fetch the next word. */ + + if (word_end == word_start) + { + cursor++; + continue; + } + + /* This is a genuine, non empty word, so save it as a possible + key. Then skip over it. Also, maintain the maximum length of + all words read so far. It is mandatory to take the maximum + length of all words in the file, without considering if they + are actually kept or rejected, because backward jumps at output + generation time may fall in *any* word. */ + + possible_key.start = cursor; + possible_key.size = word_end - word_start; + cursor += possible_key.size; + + if (possible_key.size > maximum_word_length) + maximum_word_length = possible_key.size; + + /* In input reference mode, update `line_start' from its previous + value. Count the lines just in case auto reference mode is + also selected. If it happens that the word just matched is + indeed part of a reference; just ignore it. */ + + if (input_reference) + { + while (line_scan < possible_key.start) + if (*line_scan == '\n') + { + total_line_count++; + line_scan++; + line_start = line_scan; + SKIP_NON_WHITE (line_scan, text_buffer.end); + reference_length = line_scan - line_start; + } + else + line_scan++; + if (line_scan > possible_key.start) + continue; + } + + /* Ignore the word if an `Ignore words' table exists and if it is + part of it. Also ignore the word if an `Only words' table and + if it is *not* part of it. + + It is allowed that both tables be used at once, even if this + may look strange for now. Just ignore a word that would appear + in both. If regexps are eventually implemented for these + tables, the Ignore table could then reject words that would + have been previously accepted by the Only table. */ + + if (ignore_file && search_table (&possible_key, &ignore_table)) + continue; + if (only_file && !search_table (&possible_key, &only_table)) + continue; + + /* A non-empty word has been found. First of all, insure + proper allocation of the next OCCURS, and make a pointer to + where it will be constructed. */ + + ALLOC_NEW_OCCURS (0); + occurs_cursor = occurs_table[0] + number_of_occurs[0]; + + /* Define the refence field, if any. */ + + if (auto_reference) + { + + /* While auto referencing, update `line_start' from its + previous value, counting lines as we go. If input + referencing at the same time, `line_start' has been + advanced earlier, and the following loop is never really + executed. */ + + while (line_scan < possible_key.start) + if (*line_scan == '\n') + { + total_line_count++; + line_scan++; + line_start = line_scan; + SKIP_NON_WHITE (line_scan, text_buffer.end); + } + else + line_scan++; + + occurs_cursor->reference = total_line_count; + } + else if (input_reference) + { + + /* If only input referencing, `line_start' has been computed + earlier to detect the case the word matched would be part + of the reference. The reference position is simply the + value of `line_start'. */ + + occurs_cursor->reference + = (DELTA) (line_start - possible_key.start); + if (reference_length > reference_max_width) + reference_max_width = reference_length; + } + + /* Exclude the reference from the context in simple cases. */ + + if (input_reference && line_start == context_start) + { + SKIP_NON_WHITE (context_start, context_end); + SKIP_WHITE (context_start, context_end); + } + + /* Completes the OCCURS structure. */ + + occurs_cursor->key = possible_key; + occurs_cursor->left = context_start - possible_key.start; + occurs_cursor->right = context_end - possible_key.start; + + number_of_occurs[0]++; + } + } +} + +/* Formatting and actual output - service routines. */ + +/*-----------------------------------------. +| Prints some NUMBER of spaces on stdout. | +`-----------------------------------------*/ + +static void +print_spaces (int number) +{ + int counter; + + for (counter = number; counter > 0; counter--) + putchar (' '); +} + +/*-------------------------------------. +| Prints the field provided by FIELD. | +`-------------------------------------*/ + +static void +print_field (BLOCK field) +{ + char *cursor; /* Cursor in field to print */ + int character; /* Current character */ + int base; /* Base character, without diacritic */ + int diacritic; /* Diacritic code for the character */ + + /* Whitespace is not really compressed. Instead, each white space + character (tab, vt, ht etc.) is printed as one single space. */ + + for (cursor = field.start; cursor < field.end; cursor++) + { + character = (unsigned char) *cursor; + if (edited_flag[character]) + { + + /* First check if this is a diacriticized character. + + This works only for TeX. I do not know how diacriticized + letters work with `roff'. Please someone explain it to me! */ + + diacritic = todiac (character); + if (diacritic != 0 && output_format == TEX_FORMAT) + { + base = tobase (character); + switch (diacritic) + { + + case 1: /* Latin diphthongs */ + switch (base) + { + case 'o': + fputs ("\\oe{}", stdout); + break; + + case 'O': + fputs ("\\OE{}", stdout); + break; + + case 'a': + fputs ("\\ae{}", stdout); + break; + + case 'A': + fputs ("\\AE{}", stdout); + break; + + default: + putchar (' '); + } + break; + + case 2: /* Acute accent */ + printf ("\\'%s%c", (base == 'i' ? "\\" : ""), base); + break; + + case 3: /* Grave accent */ + printf ("\\`%s%c", (base == 'i' ? "\\" : ""), base); + break; + + case 4: /* Circumflex accent */ + printf ("\\^%s%c", (base == 'i' ? "\\" : ""), base); + break; + + case 5: /* Diaeresis */ + printf ("\\\"%s%c", (base == 'i' ? "\\" : ""), base); + break; + + case 6: /* Tilde accent */ + printf ("\\~%s%c", (base == 'i' ? "\\" : ""), base); + break; + + case 7: /* Cedilla */ + printf ("\\c{%c}", base); + break; + + case 8: /* Small circle beneath */ + switch (base) + { + case 'a': + fputs ("\\aa{}", stdout); + break; + + case 'A': + fputs ("\\AA{}", stdout); + break; + + default: + putchar (' '); + } + break; + + case 9: /* Strike through */ + switch (base) + { + case 'o': + fputs ("\\o{}", stdout); + break; + + case 'O': + fputs ("\\O{}", stdout); + break; + + default: + putchar (' '); + } + break; + } + } + else + + /* This is not a diacritic character, so handle cases which are + really specific to `roff' or TeX. All white space processing + is done as the default case of this switch. */ + + switch (character) + { + case '"': + /* In roff output format, double any quote. */ + putchar ('"'); + putchar ('"'); + break; + + case '$': + case '%': + case '&': + case '#': + case '_': + /* In TeX output format, precede these with a backslash. */ + putchar ('\\'); + putchar (character); + break; + + case '{': + case '}': + /* In TeX output format, precede these with a backslash and + force mathematical mode. */ + printf ("$\\%c$", character); + break; + + case '\\': + /* In TeX output mode, request production of a backslash. */ + fputs ("\\backslash{}", stdout); + break; + + default: + /* Any other flagged character produces a single space. */ + putchar (' '); + } + } + else + putchar (*cursor); + } +} + +/* Formatting and actual output - planning routines. */ + +/*--------------------------------------------------------------------. +| From information collected from command line options and input file | +| readings, compute and fix some output parameter values. | +`--------------------------------------------------------------------*/ + +static void +fix_output_parameters (void) +{ + int file_index; /* index in text input file arrays */ + int line_ordinal; /* line ordinal value for reference */ + char ordinal_string[12]; /* edited line ordinal for reference */ + int reference_width; /* width for the whole reference */ + int character; /* character ordinal */ + const char *cursor; /* cursor in some constant strings */ + + /* In auto reference mode, the maximum width of this field is + precomputed and subtracted from the overall line width. Add one for + the column which separate the file name from the line number. */ + + if (auto_reference) + { + reference_max_width = 0; + for (file_index = 0; file_index < number_input_files; file_index++) + { + line_ordinal = file_line_count[file_index] + 1; + if (file_index > 0) + line_ordinal -= file_line_count[file_index - 1]; + sprintf (ordinal_string, "%d", line_ordinal); + reference_width = strlen (ordinal_string); + if (input_file_name[file_index]) + reference_width += strlen (input_file_name[file_index]); + if (reference_width > reference_max_width) + reference_max_width = reference_width; + } + reference_max_width++; + reference.start = (char *) xmalloc ((size_t) reference_max_width + 1); + } + + /* If the reference appears to the left of the output line, reserve some + space for it right away, including one gap size. */ + + if ((auto_reference || input_reference) && !right_reference) + line_width -= reference_max_width + gap_size; + + /* The output lines, minimally, will contain from left to right a left + context, a gap, and a keyword followed by the right context with no + special intervening gap. Half of the line width is dedicated to the + left context and the gap, the other half is dedicated to the keyword + and the right context; these values are computed once and for all here. + There also are tail and head wrap around fields, used when the keyword + is near the beginning or the end of the line, or when some long word + cannot fit in, but leave place from wrapped around shorter words. The + maximum width of these fields are recomputed separately for each line, + on a case by case basis. It is worth noting that it cannot happen that + both the tail and head fields are used at once. */ + + half_line_width = line_width / 2; + before_max_width = half_line_width - gap_size; + keyafter_max_width = half_line_width; + + /* If truncation_string is the empty string, make it NULL to speed up + tests. In this case, truncation_string_length will never get used, so + there is no need to set it. */ + + if (truncation_string && *truncation_string) + truncation_string_length = strlen (truncation_string); + else + truncation_string = NULL; + + if (gnu_extensions) + { + + /* When flagging truncation at the left of the keyword, the + truncation mark goes at the beginning of the before field, + unless there is a head field, in which case the mark goes at the + left of the head field. When flagging truncation at the right + of the keyword, the mark goes at the end of the keyafter field, + unless there is a tail field, in which case the mark goes at the + end of the tail field. Only eight combination cases could arise + for truncation marks: + + . None. + . One beginning the before field. + . One beginning the head field. + . One ending the keyafter field. + . One ending the tail field. + . One beginning the before field, another ending the keyafter field. + . One ending the tail field, another beginning the before field. + . One ending the keyafter field, another beginning the head field. + + So, there is at most two truncation marks, which could appear both + on the left side of the center of the output line, both on the + right side, or one on either side. */ + + before_max_width -= 2 * truncation_string_length; + keyafter_max_width -= 2 * truncation_string_length; + } + else + { + + /* I never figured out exactly how UNIX' ptx plans the output width + of its various fields. If GNU extensions are disabled, do not + try computing the field widths correctly; instead, use the + following formula, which does not completely imitate UNIX' ptx, + but almost. */ + + keyafter_max_width -= 2 * truncation_string_length + 1; + } + + /* Compute which characters need special output processing. Initialize + by flagging any white space character. Some systems do not consider + form feed as a space character, but we do. */ + + for (character = 0; character < CHAR_SET_SIZE; character++) + edited_flag[character] = ISSPACE (character) != 0; + edited_flag['\f'] = 1; + + /* Complete the special character flagging according to selected output + format. */ + + switch (output_format) + { + case UNKNOWN_FORMAT: + /* Should never happen. */ + + case DUMB_FORMAT: + break; + + case ROFF_FORMAT: + + /* `Quote' characters should be doubled. */ + + edited_flag['"'] = 1; + break; + + case TEX_FORMAT: + + /* Various characters need special processing. */ + + for (cursor = "$%&#_{}\\"; *cursor; cursor++) + edited_flag[(unsigned char) *cursor] = 1; + + /* Any character with 8th bit set will print to a single space, unless + it is diacriticized. */ + + for (character = 0200; character < CHAR_SET_SIZE; character++) + edited_flag[character] = todiac (character) != 0; + break; + } +} + +/*------------------------------------------------------------------. +| Compute the position and length of all the output fields, given a | +| pointer to some OCCURS. | +`------------------------------------------------------------------*/ + +static void +define_all_fields (OCCURS *occurs) +{ + int tail_max_width; /* allowable width of tail field */ + int head_max_width; /* allowable width of head field */ + char *cursor; /* running cursor in source text */ + char *left_context_start; /* start of left context */ + char *right_context_end; /* end of right context */ + char *left_field_start; /* conservative start for `head'/`before' */ + int file_index; /* index in text input file arrays */ + const char *file_name; /* file name for reference */ + int line_ordinal; /* line ordinal for reference */ + + /* Define `keyafter', start of left context and end of right context. + `keyafter' starts at the saved position for keyword and extend to the + right from the end of the keyword, eating separators or full words, but + not beyond maximum allowed width for `keyafter' field or limit for the + right context. Suffix spaces will be removed afterwards. */ + + keyafter.start = occurs->key.start; + keyafter.end = keyafter.start + occurs->key.size; + left_context_start = keyafter.start + occurs->left; + right_context_end = keyafter.start + occurs->right; + + cursor = keyafter.end; + while (cursor < right_context_end + && cursor <= keyafter.start + keyafter_max_width) + { + keyafter.end = cursor; + SKIP_SOMETHING (cursor, right_context_end); + } + if (cursor <= keyafter.start + keyafter_max_width) + keyafter.end = cursor; + + keyafter_truncation = truncation_string && keyafter.end < right_context_end; + + SKIP_WHITE_BACKWARDS (keyafter.end, keyafter.start); + + /* When the left context is wide, it might take some time to catch up from + the left context boundary to the beginning of the `head' or `before' + fields. So, in this case, to speed the catchup, we jump back from the + keyword, using some secure distance, possibly falling in the middle of + a word. A secure backward jump would be at least half the maximum + width of a line, plus the size of the longest word met in the whole + input. We conclude this backward jump by a skip forward of at least + one word. In this manner, we should not inadvertently accept only part + of a word. From the reached point, when it will be time to fix the + beginning of `head' or `before' fields, we will skip forward words or + delimiters until we get sufficiently near. */ + + if (-occurs->left > half_line_width + maximum_word_length) + { + left_field_start + = keyafter.start - (half_line_width + maximum_word_length); + SKIP_SOMETHING (left_field_start, keyafter.start); + } + else + left_field_start = keyafter.start + occurs->left; + + /* `before' certainly ends at the keyword, but not including separating + spaces. It starts after than the saved value for the left context, by + advancing it until it falls inside the maximum allowed width for the + before field. There will be no prefix spaces either. `before' only + advances by skipping single separators or whole words. */ + + before.start = left_field_start; + before.end = keyafter.start; + SKIP_WHITE_BACKWARDS (before.end, before.start); + + while (before.start + before_max_width < before.end) + SKIP_SOMETHING (before.start, before.end); + + if (truncation_string) + { + cursor = before.start; + SKIP_WHITE_BACKWARDS (cursor, text_buffer.start); + before_truncation = cursor > left_context_start; + } + else + before_truncation = 0; + + SKIP_WHITE (before.start, text_buffer.end); + + /* The tail could not take more columns than what has been left in the + left context field, and a gap is mandatory. It starts after the + right context, and does not contain prefixed spaces. It ends at + the end of line, the end of buffer or when the tail field is full, + whichever comes first. It cannot contain only part of a word, and + has no suffixed spaces. */ + + tail_max_width + = before_max_width - (before.end - before.start) - gap_size; + + if (tail_max_width > 0) + { + tail.start = keyafter.end; + SKIP_WHITE (tail.start, text_buffer.end); + + tail.end = tail.start; + cursor = tail.end; + while (cursor < right_context_end + && cursor < tail.start + tail_max_width) + { + tail.end = cursor; + SKIP_SOMETHING (cursor, right_context_end); + } + + if (cursor < tail.start + tail_max_width) + tail.end = cursor; + + if (tail.end > tail.start) + { + keyafter_truncation = 0; + tail_truncation = truncation_string && tail.end < right_context_end; + } + else + tail_truncation = 0; + + SKIP_WHITE_BACKWARDS (tail.end, tail.start); + } + else + { + + /* No place left for a tail field. */ + + tail.start = NULL; + tail.end = NULL; + tail_truncation = 0; + } + + /* `head' could not take more columns than what has been left in the right + context field, and a gap is mandatory. It ends before the left + context, and does not contain suffixed spaces. Its pointer is advanced + until the head field has shrunk to its allowed width. It cannot + contain only part of a word, and has no suffixed spaces. */ + + head_max_width + = keyafter_max_width - (keyafter.end - keyafter.start) - gap_size; + + if (head_max_width > 0) + { + head.end = before.start; + SKIP_WHITE_BACKWARDS (head.end, text_buffer.start); + + head.start = left_field_start; + while (head.start + head_max_width < head.end) + SKIP_SOMETHING (head.start, head.end); + + if (head.end > head.start) + { + before_truncation = 0; + head_truncation = (truncation_string + && head.start > left_context_start); + } + else + head_truncation = 0; + + SKIP_WHITE (head.start, head.end); + } + else + { + + /* No place left for a head field. */ + + head.start = NULL; + head.end = NULL; + head_truncation = 0; + } + + if (auto_reference) + { + + /* Construct the reference text in preallocated space from the file + name and the line number. Find out in which file the reference + occurred. Standard input yields an empty file name. Insure line + numbers are one based, even if they are computed zero based. */ + + file_index = 0; + while (file_line_count[file_index] < occurs->reference) + file_index++; + + file_name = input_file_name[file_index]; + if (!file_name) + file_name = ""; + + line_ordinal = occurs->reference + 1; + if (file_index > 0) + line_ordinal -= file_line_count[file_index - 1]; + + sprintf (reference.start, "%s:%d", file_name, line_ordinal); + reference.end = reference.start + strlen (reference.start); + } + else if (input_reference) + { + + /* Reference starts at saved position for reference and extends right + until some white space is met. */ + + reference.start = keyafter.start + (DELTA) occurs->reference; + reference.end = reference.start; + SKIP_NON_WHITE (reference.end, right_context_end); + } +} + +/* Formatting and actual output - control routines. */ + +/*----------------------------------------------------------------------. +| Output the current output fields as one line for `troff' or `nroff'. | +`----------------------------------------------------------------------*/ + +static void +output_one_roff_line (void) +{ + /* Output the `tail' field. */ + + printf (".%s \"", macro_name); + print_field (tail); + if (tail_truncation) + fputs (truncation_string, stdout); + putchar ('"'); + + /* Output the `before' field. */ + + fputs (" \"", stdout); + if (before_truncation) + fputs (truncation_string, stdout); + print_field (before); + putchar ('"'); + + /* Output the `keyafter' field. */ + + fputs (" \"", stdout); + print_field (keyafter); + if (keyafter_truncation) + fputs (truncation_string, stdout); + putchar ('"'); + + /* Output the `head' field. */ + + fputs (" \"", stdout); + if (head_truncation) + fputs (truncation_string, stdout); + print_field (head); + putchar ('"'); + + /* Conditionally output the `reference' field. */ + + if (auto_reference || input_reference) + { + fputs (" \"", stdout); + print_field (reference); + putchar ('"'); + } + + putchar ('\n'); +} + +/*---------------------------------------------------------. +| Output the current output fields as one line for `TeX'. | +`---------------------------------------------------------*/ + +static void +output_one_tex_line (void) +{ + BLOCK key; /* key field, isolated */ + BLOCK after; /* after field, isolated */ + char *cursor; /* running cursor in source text */ + + printf ("\\%s ", macro_name); + putchar ('{'); + print_field (tail); + fputs ("}{", stdout); + print_field (before); + fputs ("}{", stdout); + key.start = keyafter.start; + after.end = keyafter.end; + cursor = keyafter.start; + SKIP_SOMETHING (cursor, keyafter.end); + key.end = cursor; + after.start = cursor; + print_field (key); + fputs ("}{", stdout); + print_field (after); + fputs ("}{", stdout); + print_field (head); + putchar ('}'); + if (auto_reference || input_reference) + { + putchar ('{'); + print_field (reference); + putchar ('}'); + } + putchar ('\n'); +} + +/*-------------------------------------------------------------------. +| Output the current output fields as one line for a dumb terminal. | +`-------------------------------------------------------------------*/ + +static void +output_one_dumb_line (void) +{ + if (!right_reference) + { + if (auto_reference) + { + + /* Output the `reference' field, in such a way that GNU emacs + next-error will handle it. The ending colon is taken from the + gap which follows. */ + + print_field (reference); + putchar (':'); + print_spaces (reference_max_width + + gap_size + - (reference.end - reference.start) + - 1); + } + else + { + + /* Output the `reference' field and its following gap. */ + + print_field (reference); + print_spaces (reference_max_width + + gap_size + - (reference.end - reference.start)); + } + } + + if (tail.start < tail.end) + { + /* Output the `tail' field. */ + + print_field (tail); + if (tail_truncation) + fputs (truncation_string, stdout); + + print_spaces (half_line_width - gap_size + - (before.end - before.start) + - (before_truncation ? truncation_string_length : 0) + - (tail.end - tail.start) + - (tail_truncation ? truncation_string_length : 0)); + } + else + print_spaces (half_line_width - gap_size + - (before.end - before.start) + - (before_truncation ? truncation_string_length : 0)); + + /* Output the `before' field. */ + + if (before_truncation) + fputs (truncation_string, stdout); + print_field (before); + + print_spaces (gap_size); + + /* Output the `keyafter' field. */ + + print_field (keyafter); + if (keyafter_truncation) + fputs (truncation_string, stdout); + + if (head.start < head.end) + { + /* Output the `head' field. */ + + print_spaces (half_line_width + - (keyafter.end - keyafter.start) + - (keyafter_truncation ? truncation_string_length : 0) + - (head.end - head.start) + - (head_truncation ? truncation_string_length : 0)); + if (head_truncation) + fputs (truncation_string, stdout); + print_field (head); + } + else + + if ((auto_reference || input_reference) && right_reference) + print_spaces (half_line_width + - (keyafter.end - keyafter.start) + - (keyafter_truncation ? truncation_string_length : 0)); + + if ((auto_reference || input_reference) && right_reference) + { + /* Output the `reference' field. */ + + print_spaces (gap_size); + print_field (reference); + } + + putchar ('\n'); +} + +/*------------------------------------------------------------------------. +| Scan the whole occurs table and, for each entry, output one line in the | +| appropriate format. | +`------------------------------------------------------------------------*/ + +static void +generate_all_output (void) +{ + size_t occurs_index; /* index of keyword entry being processed */ + OCCURS *occurs_cursor; /* current keyword entry being processed */ + + /* The following assignments are useful to provide default values in case + line contexts or references are not used, in which case these variables + would never be computed. */ + + tail.start = NULL; + tail.end = NULL; + tail_truncation = 0; + + head.start = NULL; + head.end = NULL; + head_truncation = 0; + + /* Loop over all keyword occurrences. */ + + occurs_cursor = occurs_table[0]; + + for (occurs_index = 0; occurs_index < number_of_occurs[0]; occurs_index++) + { + /* Compute the exact size of every field and whenever truncation flags + are present or not. */ + + define_all_fields (occurs_cursor); + + /* Produce one output line according to selected format. */ + + switch (output_format) + { + case UNKNOWN_FORMAT: + /* Should never happen. */ + + case DUMB_FORMAT: + output_one_dumb_line (); + break; + + case ROFF_FORMAT: + output_one_roff_line (); + break; + + case TEX_FORMAT: + output_one_tex_line (); + break; + } + + /* Advance the cursor into the occurs table. */ + + occurs_cursor++; + } +} + +/* Option decoding and main program. */ + +/*------------------------------------------------------. +| Print program identification and options, then exit. | +`------------------------------------------------------*/ + +void +usage (int status) +{ + if (status != EXIT_SUCCESS) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [INPUT]... (without -G)\n\ + or: %s -G [OPTION]... [INPUT [OUTPUT]]\n"), + program_name, program_name); + fputs (_("\ +Output a permuted index, including context, of the words in the input files.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -A, --auto-reference output automatically generated references\n\ + -C, --copyright display Copyright and copying conditions\n\ + -G, --traditional behave more like System V `ptx'\n\ + -F, --flag-truncation=STRING use STRING for flagging line truncations\n\ +"), stdout); + fputs (_("\ + -M, --macro-name=STRING macro name to use instead of `xx'\n\ + -O, --format=roff generate output as roff directives\n\ + -R, --right-side-refs put references at right, not counted in -w\n\ + -S, --sentence-regexp=REGEXP for end of lines or end of sentences\n\ + -T, --format=tex generate output as TeX directives\n\ +"), stdout); + fputs (_("\ + -W, --word-regexp=REGEXP use REGEXP to match each keyword\n\ + -b, --break-file=FILE word break characters in this FILE\n\ + -f, --ignore-case fold lower case to upper case for sorting\n\ + -g, --gap-size=NUMBER gap size in columns between output fields\n\ + -i, --ignore-file=FILE read ignore word list from FILE\n\ + -o, --only-file=FILE read only word list from this FILE\n\ +"), stdout); + fputs (_("\ + -r, --references first field of each line is a reference\n\ + -t, --typeset-mode - not implemented -\n\ + -w, --width=NUMBER output width in columns, reference excluded\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +With no FILE or if FILE is -, read Standard Input. `-F /' by default.\n\ +"), stdout); + } + exit (status); +} + +/*----------------------------------------------------------------------. +| Main program. Decode ARGC arguments passed through the ARGV array of | +| strings, then launch execution. | +`----------------------------------------------------------------------*/ + +/* Long options equivalences. */ +static const struct option long_options[] = +{ + {"auto-reference", no_argument, NULL, 'A'}, + {"break-file", required_argument, NULL, 'b'}, + {"copyright", no_argument, NULL, 'C'}, + {"flag-truncation", required_argument, NULL, 'F'}, + {"ignore-case", no_argument, NULL, 'f'}, + {"gap-size", required_argument, NULL, 'g'}, + {"ignore-file", required_argument, NULL, 'i'}, + {"macro-name", required_argument, NULL, 'M'}, + {"only-file", required_argument, NULL, 'o'}, + {"references", no_argument, NULL, 'r'}, + {"right-side-refs", no_argument, NULL, 'R'}, + {"format", required_argument, NULL, 10}, + {"sentence-regexp", required_argument, NULL, 'S'}, + {"traditional", no_argument, NULL, 'G'}, + {"typeset-mode", no_argument, NULL, 't'}, + {"width", required_argument, NULL, 'w'}, + {"word-regexp", required_argument, NULL, 'W'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0}, +}; + +static char const* const format_args[] = +{ + "roff", "tex", 0 +}; + +static enum Format const format_vals[] = +{ + ROFF_FORMAT, TEX_FORMAT +}; + +int +main (int argc, char **argv) +{ + int optchar; /* argument character */ + int file_index; /* index in text input file arrays */ + + /* Decode program options. */ + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + +#if HAVE_SETCHRCLASS + setchrclass (NULL); +#endif + + while (optchar = getopt_long (argc, argv, "ACF:GM:ORS:TW:b:i:fg:o:trw:", + long_options, NULL), + optchar != EOF) + { + switch (optchar) + { + default: + usage (EXIT_FAILURE); + + case 0: + break; + + case 'C': + fputs (_("\ +This program is free software; you can redistribute it and/or modify\n\ +it under the terms of the GNU General Public License as published by\n\ +the Free Software Foundation; either version 2, or (at your option)\n\ +any later version.\n\ +\n\ +"), stdout); + fputs (_("\ +This program is distributed in the hope that it will be useful,\n\ +but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ +GNU General Public License for more details.\n\ +\n\ +"), stdout); + fputs (_("\ +You should have received a copy of the GNU General Public License\n\ +along with this program; if not, write to the Free Software Foundation,\n\ +Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"), + stdout); + + exit (EXIT_SUCCESS); + + case 'G': + gnu_extensions = 0; + break; + + case 'b': + break_file = optarg; + break; + + case 'f': + ignore_case = 1; + break; + + case 'g': + gap_size = atoi (optarg); + break; + + case 'i': + ignore_file = optarg; + break; + + case 'o': + only_file = optarg; + break; + + case 'r': + input_reference = 1; + break; + + case 't': + /* Yet to understand... */ + break; + + case 'w': + line_width = atoi (optarg); + break; + + case 'A': + auto_reference = 1; + break; + + case 'F': + truncation_string = copy_unescaped_string (optarg); + break; + + case 'M': + macro_name = optarg; + break; + + case 'O': + output_format = ROFF_FORMAT; + break; + + case 'R': + right_reference = 1; + break; + + case 'S': + context_regex_string = copy_unescaped_string (optarg); + break; + + case 'T': + output_format = TEX_FORMAT; + break; + + case 'W': + word_regex_string = copy_unescaped_string (optarg); + break; + + case 10: + output_format = XARGMATCH ("--format", optarg, + format_args, format_vals); + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + } + } + + /* Change the default Ignore file if one is defined. */ + +#ifdef DEFAULT_IGNORE_FILE + if (!ignore_file) + ignore_file = DEFAULT_IGNORE_FILE; +#endif + + /* Process remaining arguments. If GNU extensions are enabled, process + all arguments as input parameters. If disabled, accept at most two + arguments, the second of which is an output parameter. */ + + if (optind == argc) + { + + /* No more argument simply means: read standard input. */ + + input_file_name = (const char **) xmalloc (sizeof (const char *)); + file_line_count = (int *) xmalloc (sizeof (int)); + number_input_files = 1; + input_file_name[0] = NULL; + } + else if (gnu_extensions) + { + number_input_files = argc - optind; + input_file_name + = (const char **) xmalloc (number_input_files * sizeof (const char *)); + file_line_count + = (int *) xmalloc (number_input_files * sizeof (int)); + + for (file_index = 0; file_index < number_input_files; file_index++) + { + input_file_name[file_index] = argv[optind]; + if (!*argv[optind] || strcmp (argv[optind], "-") == 0) + input_file_name[0] = NULL; + else + input_file_name[0] = argv[optind]; + optind++; + } + } + else + { + + /* There is one necessary input file. */ + + number_input_files = 1; + input_file_name = (const char **) xmalloc (sizeof (const char *)); + file_line_count = (int *) xmalloc (sizeof (int)); + if (!*argv[optind] || strcmp (argv[optind], "-") == 0) + input_file_name[0] = NULL; + else + input_file_name[0] = argv[optind]; + optind++; + + /* Redirect standard output, only if requested. */ + + if (optind < argc) + { + /* FIXME: don't fclose here? */ + fclose (stdout); + if (fopen (argv[optind], "w") == NULL) + error (EXIT_FAILURE, errno, "%s", argv[optind]); + optind++; + } + + /* Diagnose any other argument as an error. */ + + if (optind < argc) + usage (EXIT_FAILURE); + } + + /* If the output format has not been explicitly selected, choose dumb + terminal format if GNU extensions are enabled, else `roff' format. */ + + if (output_format == UNKNOWN_FORMAT) + output_format = gnu_extensions ? DUMB_FORMAT : ROFF_FORMAT; + + /* Initialize the main tables. */ + + initialize_regex (); + + /* Read `Break character' file, if any. */ + + if (break_file) + digest_break_file (break_file); + + /* Read `Ignore words' file and `Only words' files, if any. If any of + these files is empty, reset the name of the file to NULL, to avoid + unnecessary calls to search_table. */ + + if (ignore_file) + { + digest_word_file (ignore_file, &ignore_table); + if (ignore_table.length == 0) + ignore_file = NULL; + } + + if (only_file) + { + digest_word_file (only_file, &only_table); + if (only_table.length == 0) + only_file = NULL; + } + + /* Prepare to study all the input files. */ + + number_of_occurs[0] = 0; + total_line_count = 0; + maximum_word_length = 0; + reference_max_width = 0; + + for (file_index = 0; file_index < number_input_files; file_index++) + { + + /* Read the file in core, than study it. */ + + swallow_file_in_memory (input_file_name[file_index], &text_buffer); + find_occurs_in_text (); + + /* Maintain for each file how many lines has been read so far when its + end is reached. Incrementing the count first is a simple kludge to + handle a possible incomplete line at end of file. */ + + total_line_count++; + file_line_count[file_index] = total_line_count; + } + + /* Do the output process phase. */ + + sort_found_occurs (); + fix_output_parameters (); + generate_all_output (); + + /* All done. */ + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/pwd.c b/src/apps/bin/coreutils-5.0/src/pwd.c new file mode 100644 index 0000000000..9d5aa15f21 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/pwd.c @@ -0,0 +1,82 @@ +/* pwd - print current directory + Copyright (C) 1994-1997, 1999-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Jim Meyering */ + +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "long-options.h" +#include "error.h" +#include "xgetcwd.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "pwd" + +#define AUTHORS "Jim Meyering" + +/* The name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]\n"), program_name); + fputs (_("\ +Print the full filename of the current working directory.\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + char *wd; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + if (argc != 1) + error (0, 0, _("ignoring non-option arguments")); + + wd = xgetcwd (); + if (wd == NULL) + error (EXIT_FAILURE, errno, _("cannot get current directory")); + printf ("%s\n", wd); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/readlink.c b/src/apps/bin/coreutils-5.0/src/readlink.c new file mode 100644 index 0000000000..96e5a0aeae --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/readlink.c @@ -0,0 +1,157 @@ +/* readlink -- display value of a symbolic link. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Dmitry V. Levin */ + +#include +#include +#include +#include +#include +#include + +#include "system.h" +#include "canonicalize.h" +#include "error.h" +#include "xreadlink.h" +#include "long-options.h" +#include "quote.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "readlink" + +#define AUTHORS "Dmitry V. Levin" + +/* Name this program was run with. */ +char *program_name; + + /* If nonzero, canonicalize file name. */ +static int canonicalize; + /* If nonzero, do not output the trailing newline. */ +static int no_newline; + /* If nonzero, report error messages. */ +static int verbose; + +static struct option const longopts[] = +{ + {"canonicalize", no_argument, 0, 'f'}, + {"no-newline", no_argument, 0, 'n'}, + {"quiet", no_argument, 0, 'q'}, + {"silent", no_argument, 0, 's'}, + {"verbose", no_argument, 0, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != EXIT_SUCCESS) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... FILE\n"), program_name); + fputs (_("Display value of a symbolic link on standard output.\n\n"), + stdout); + fputs (_("\ + -f, --canonicalize canonicalize by following every symlink in every\n\ + component of the given path recursively\n\ + -n, --no-newline do not output the trailing newline\n\ + -q, --quiet,\n\ + -s, --silent suppress most error messages\n\ + -v, --verbose report error messages\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char *const argv[]) +{ + const char *fname; + char *value; + int optc; + + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + if (argc < 1) + error (EXIT_FAILURE, 0, _("too few arguments")); + + program_name = argv[0]; + + while ((optc = getopt_long (argc, argv, "fnqsv", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + case 'f': + canonicalize = 1; + break; + case 'n': + no_newline = 1; + break; + case 'q': + case 's': + verbose = 0; + break; + case 'v': + verbose = 1; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + } + + if (optind >= argc) + { + error (EXIT_SUCCESS, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + fname = argv[optind++]; + + if (optind < argc) + { + error (EXIT_SUCCESS, 0, _("too many arguments")); + usage (EXIT_FAILURE); + } + + value = (canonicalize ? canonicalize_file_name : xreadlink) (fname); + if (value) + { + printf ("%s%s", value, (no_newline ? "" : "\n")); + free (value); + return EXIT_SUCCESS; + } + + if (verbose) + error (EXIT_SUCCESS, errno, "%s", fname); + + return EXIT_FAILURE; +} diff --git a/src/apps/bin/coreutils-5.0/src/remove.c b/src/apps/bin/coreutils-5.0/src/remove.c new file mode 100644 index 0000000000..0e891d87ad --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/remove.c @@ -0,0 +1,1146 @@ +/* remove.c -- core functions for removing files and directories + Copyright (C) 88, 90, 91, 1994-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Extracted from rm.c and librarified, then rewritten by Jim Meyering. */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include +#include +#include +#include + +#include "save-cwd.h" +#include "system.h" +#include "cycle-check.h" +#include "dirname.h" +#include "error.h" +#include "euidaccess.h" +#include "file-type.h" +#include "hash.h" +#include "hash-pjw.h" +#include "obstack.h" +#include "quote.h" +#include "remove.h" + +/* Avoid shadowing warnings because these are functions declared + in dirname.h as well as locals used below. */ +#define dir_name rm_dir_name +#define dir_len rm_dir_len + +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free + +/* FIXME: if possible, use autoconf... */ +#ifdef __GLIBC__ +# define ROOT_CAN_UNLINK_DIRS 0 +#else +# define ROOT_CAN_UNLINK_DIRS 1 +#endif + +enum Ternary + { + T_UNKNOWN = 2, + T_NO, + T_YES + }; +typedef enum Ternary Ternary; + +/* The prompt function may be called twice a given directory. + The first time, we ask whether to descend into it, and the + second time, we ask whether to remove it. */ +enum Prompt_action + { + PA_DESCEND_INTO_DIR = 2, + PA_REMOVE_DIR + }; + +/* On systems with an lstat function that accepts the empty string, + arrange to make lstat calls go through the wrapper function. */ +#if HAVE_LSTAT_EMPTY_STRING_BUG +int rpl_lstat (const char *, struct stat *); +# define lstat(Name, Stat_buf) rpl_lstat(Name, Stat_buf) +#endif + +#ifdef D_INO_IN_DIRENT +# define D_INO(dp) ((dp)->d_ino) +# define ENABLE_CYCLE_CHECK +#else +/* Some systems don't have inodes, so fake them to avoid lots of ifdefs. */ +# define D_INO(dp) 1 +#endif + +/* Initial capacity of per-directory hash table of entries that have + been processed but not been deleted. */ +#define HT_UNREMOVABLE_INITIAL_CAPACITY 13 + +/* An entry in the active directory stack. + Each entry corresponds to an `active' directory. */ +struct AD_ent +{ + /* For a given active directory, this is the set of names of + entries in that directory that could/should not be removed. + For example, `.' and `..', as well as files/dirs for which + unlink/rmdir failed e.g., due to access restrictions. */ + Hash_table *unremovable; + + /* Record the status for a given active directory; we need to know + whether an entry was not removed, either because of an error or + because the user declined. */ + enum RM_status status; + + union + { + /* The directory's dev/ino. Used to ensure that `chdir some-subdir', then + `chdir ..' takes us back to the same directory from which we started). + (valid for all but the bottommost entry on the stack. */ + struct dev_ino a; + + /* Enough information to restore the initial working directory. + (valid only for the bottommost entry on the stack) */ + struct saved_cwd saved_cwd; + } u; +}; + +int yesno (); + +extern char *program_name; + +struct dirstack_state +{ + /* The name of the directory (starting with and relative to a command + line argument) being processed. When a subdirectory is entered, a new + component is appended (pushed). Remove (pop) the top component + upon chdir'ing out of a directory. This is used to form the full + name of the current directory or a file therein, when necessary. */ + struct obstack dir_stack; + + /* Stack of lengths of directory names (including trailing slash) + appended to dir_stack. We have to have a separate stack of lengths + (rather than just popping back to previous slash) because the first + element pushed onto the dir stack may contain slashes. */ + struct obstack len_stack; + + /* Stack of active directory entries. + The first `active' directory is the initial working directory. + Additional active dirs are pushed onto the stack as we `chdir' + into each directory to be processed. When finished with the + hierarchy under a directory, pop the active dir stack. */ + struct obstack Active_dir; + + /* Used to detect cycles. */ + struct cycle_check_state cycle_check_state; + + /* Target of a longjmp in case rm detects a directory cycle. */ + jmp_buf current_arg_jumpbuf; +}; +typedef struct dirstack_state Dirstack_state; + +Dirstack_state * +ds_init () +{ + Dirstack_state *ds = XMALLOC (struct dirstack_state, 1); + obstack_init (&ds->dir_stack); + obstack_init (&ds->len_stack); + obstack_init (&ds->Active_dir); + return ds; +} + +void +ds_free (Dirstack_state *ds) +{ + obstack_free (&ds->dir_stack, NULL); + obstack_free (&ds->len_stack, NULL); + obstack_free (&ds->Active_dir, NULL); +} + +static void +hash_freer (void *x) +{ + free (x); +} + +static bool +hash_compare_strings (void const *x, void const *y) +{ + return STREQ (x, y) ? true : false; +} + +static inline void +push_dir (Dirstack_state *ds, const char *dir_name) +{ + size_t len; + + len = strlen (dir_name); + + /* Append the string onto the stack. */ + obstack_grow (&ds->dir_stack, dir_name, len); + + /* Append a trailing slash. */ + obstack_1grow (&ds->dir_stack, '/'); + + /* Add one for the slash. */ + ++len; + + /* Push the length (including slash) onto its stack. */ + obstack_grow (&ds->len_stack, &len, sizeof (len)); +} + +/* Return the entry name of the directory on the top of the stack + in malloc'd storage. */ +static inline char * +top_dir (Dirstack_state const *ds) +{ + int n_lengths = obstack_object_size (&ds->len_stack) / sizeof (size_t); + size_t *length = (size_t *) obstack_base (&ds->len_stack); + size_t top_len = length[n_lengths - 1]; + char const *p = obstack_next_free (&ds->dir_stack) - top_len; + char *q = xmalloc (top_len); + memcpy (q, p, top_len - 1); + q[top_len - 1] = 0; + return q; +} + +static inline void +pop_dir (Dirstack_state *ds) +{ + int n_lengths = obstack_object_size (&ds->len_stack) / sizeof (size_t); + size_t *length = (size_t *) obstack_base (&ds->len_stack); + size_t top_len; + + assert (n_lengths > 0); + top_len = length[n_lengths - 1]; + assert (top_len >= 2); + + /* Pop off the specified length of pathname. */ + assert (obstack_object_size (&ds->dir_stack) >= top_len); + obstack_blank (&ds->dir_stack, -top_len); + + /* Pop the length stack, too. */ + assert (obstack_object_size (&ds->len_stack) >= sizeof (size_t)); + obstack_blank (&ds->len_stack, -(int) sizeof (size_t)); +} + +/* Copy the SRC_LEN bytes of data beginning at SRC into the DST_LEN-byte + buffer, DST, so that the last source byte is at the end of the destination + buffer. If SRC_LEN is longer than DST_LEN, then set *TRUNCATED to non-zero. + Set *RESULT to point to the beginning of (the portion of) the source data + in DST. Return the number of bytes remaining in the destination buffer. */ + +static size_t +right_justify (char *dst, size_t dst_len, const char *src, size_t src_len, + char **result, int *truncated) +{ + const char *sp; + char *dp; + + if (src_len <= dst_len) + { + sp = src; + dp = dst + (dst_len - src_len); + *truncated = 0; + } + else + { + sp = src + (src_len - dst_len); + dp = dst; + src_len = dst_len; + *truncated = 1; + } + + *result = memcpy (dp, sp, src_len); + return dst_len - src_len; +} + +/* Using the global directory name obstack, create the full path to FILENAME. + Return it in sometimes-realloc'd space that should not be freed by the + caller. Realloc as necessary. If realloc fails, use a static buffer + and put as long a suffix in that buffer as possible. */ + +#define full_filename(Filename) full_filename_ (ds, Filename) +static char * +full_filename_ (Dirstack_state const *ds, const char *filename) +{ + static char *buf = NULL; + static size_t n_allocated = 0; + + int dir_len = obstack_object_size (&ds->dir_stack); + char *dir_name = (char *) obstack_base (&ds->dir_stack); + size_t n_bytes_needed; + size_t filename_len; + + filename_len = strlen (filename); + n_bytes_needed = dir_len + filename_len + 1; + + if (n_allocated < n_bytes_needed) + { + /* This code requires that realloc accept NULL as the first arg. + This function must not use xrealloc. Otherwise, an out-of-memory + error involving a file name to be expanded here wouldn't ever + be issued. Use realloc and fall back on using a static buffer + if memory allocation fails. */ + buf = realloc (buf, n_bytes_needed); + n_allocated = n_bytes_needed; + + if (buf == NULL) + { +#define SBUF_SIZE 512 +#define ELLIPSES_PREFIX "[...]" + static char static_buf[SBUF_SIZE]; + int truncated; + size_t len; + char *p; + + len = right_justify (static_buf, SBUF_SIZE, filename, + filename_len + 1, &p, &truncated); + right_justify (static_buf, len, dir_name, dir_len, &p, &truncated); + if (truncated) + { + memcpy (static_buf, ELLIPSES_PREFIX, + sizeof (ELLIPSES_PREFIX) - 1); + } + return p; + } + } + + if (filename_len == 1 && *filename == '.' && dir_len) + { + /* FILENAME is just `.' and dir_len is nonzero. + Copy the directory part, omitting the trailing slash, + and append a trailing zero byte. */ + char *p = mempcpy (buf, dir_name, dir_len - 1); + *p = 0; + } + else + { + /* Copy the directory part, including trailing slash, and then + append the filename part, including a trailing zero byte. */ + memcpy (mempcpy (buf, dir_name, dir_len), filename, filename_len + 1); + assert (strlen (buf) + 1 == n_bytes_needed); + } + + return buf; +} + +static size_t +AD_stack_height (Dirstack_state const *ds) +{ + return obstack_object_size (&ds->Active_dir) / sizeof (struct AD_ent); +} + +static struct AD_ent * +AD_stack_top (Dirstack_state const *ds) +{ + return (struct AD_ent *) + ((char *) obstack_next_free (&ds->Active_dir) - sizeof (struct AD_ent)); +} + +static void +AD_stack_pop (Dirstack_state *ds) +{ + /* operate on Active_dir. pop and free top entry */ + struct AD_ent *top = AD_stack_top (ds); + if (top->unremovable) + hash_free (top->unremovable); + obstack_blank (&ds->Active_dir, -(int) sizeof (struct AD_ent)); + pop_dir (ds); +} + +/* chdir `up' one level. + Whenever using chdir '..', verify that the post-chdir + dev/ino numbers for `.' match the saved ones. + Return the name (in malloc'd storage) of the + directory (usually now empty) from which we're coming. */ +static char * +AD_pop_and_chdir (Dirstack_state *ds) +{ + /* Get the name of the current directory from the top of the stack. */ + char *dir = top_dir (ds); + enum RM_status old_status = AD_stack_top(ds)->status; + struct stat sb; + struct AD_ent *top; + + AD_stack_pop (ds); + + /* Propagate any failure to parent. */ + UPDATE_STATUS (AD_stack_top(ds)->status, old_status); + + assert (AD_stack_height (ds)); + + top = AD_stack_top (ds); + if (1 < AD_stack_height (ds)) + { + /* We can give a better diagnostic here, since the target is relative. */ + if (chdir ("..")) + { + error (EXIT_FAILURE, errno, + _("cannot chdir from %s to .."), + quote (full_filename ("."))); + } + } + else + { + if (restore_cwd (&top->u.saved_cwd)) + error (EXIT_FAILURE, errno, + _("failed to return to initial working directory")); + } + + if (lstat (".", &sb)) + error (EXIT_FAILURE, errno, + _("cannot lstat `.' in %s"), quote (full_filename ("."))); + + if (1 < AD_stack_height (ds)) + { + /* Ensure that post-chdir dev/ino match the stored ones. */ + if ( ! SAME_INODE (sb, top->u.a)) + error (EXIT_FAILURE, 0, + _("%s changed dev/ino"), quote (full_filename ("."))); + } + + return dir; +} + +/* Initialize *HT if it is NULL. + Insert FILENAME into HT. */ +static void +AD_mark_helper (Hash_table **ht, char const *filename) +{ + if (*ht == NULL) + *ht = hash_initialize (HT_UNREMOVABLE_INITIAL_CAPACITY, NULL, hash_pjw, + hash_compare_strings, hash_freer); + if (*ht == NULL) + xalloc_die (); + if (! hash_insert (*ht, filename)) + xalloc_die (); +} + +/* Mark FILENAME (in current directory) as unremovable. */ +static void +AD_mark_as_unremovable (Dirstack_state *ds, char const *filename) +{ + AD_mark_helper (&AD_stack_top(ds)->unremovable, xstrdup (filename)); +} + +/* Mark the current directory as unremovable. I.e., mark the entry + in the parent directory corresponding to `.'. + This happens e.g., when an opendir fails and the only name + the caller has conveniently at hand is `.'. */ +static void +AD_mark_current_as_unremovable (Dirstack_state *ds) +{ + struct AD_ent *top = AD_stack_top (ds); + const char *curr = top_dir (ds); + + assert (1 < AD_stack_height (ds)); + + --top; + AD_mark_helper (&top->unremovable, curr); +} + +/* Push the initial cwd info onto the stack. + This will always be the bottommost entry on the stack. */ +static void +AD_push_initial (Dirstack_state *ds, struct saved_cwd const *cwd) +{ + struct AD_ent *top; + + /* Extend the stack. */ + obstack_blank (&ds->Active_dir, sizeof (struct AD_ent)); + + /* Fill in the new values. */ + top = AD_stack_top (ds); + top->u.saved_cwd = *cwd; + top->unremovable = NULL; +} + +/* Push info about the current working directory (".") onto the + active directory stack. DIR is the ./-relative name through + which we've just `chdir'd to this directory. DIR_SB_FROM_PARENT + is the result of calling lstat on DIR from the parent of DIR. */ +static void +AD_push (Dirstack_state *ds, char const *dir, + struct stat const *dir_sb_from_parent) +{ + struct stat sb; + struct AD_ent *top; + + push_dir (ds, dir); + + if (lstat (".", &sb)) + error (EXIT_FAILURE, errno, + _("cannot lstat `.' in %s"), quote (full_filename ("."))); + + if ( ! SAME_INODE (sb, *dir_sb_from_parent)) + error (EXIT_FAILURE, errno, + _("%s changed dev/ino"), quote (full_filename ("."))); + + /* Extend the stack. */ + obstack_blank (&ds->Active_dir, sizeof (struct AD_ent)); + + /* Fill in the new values. */ + top = AD_stack_top (ds); + top->u.a.st_dev = sb.st_dev; + top->u.a.st_ino = sb.st_ino; + top->unremovable = NULL; +} + +static int +AD_is_removable (Dirstack_state const *ds, char const *file) +{ + struct AD_ent *top = AD_stack_top (ds); + return ! (top->unremovable && hash_lookup (top->unremovable, file)); +} + +static bool +is_empty_dir (char const *dir) +{ + DIR *dirp = opendir (dir); + if (dirp == NULL) + { + closedir (dirp); + return false; + } + + while (1) + { + struct dirent *dp; + const char *f; + + errno = 0; + dp = readdir (dirp); + if (dp == NULL) + { + int saved_errno = errno; + closedir (dirp); + return saved_errno == 0 ? true : false; + } + + f = dp->d_name; + if ( ! DOT_OR_DOTDOT (f)) + { + closedir (dirp); + return false; + } + } +} + +/* Prompt whether to remove FILENAME, if required via a combination of + the options specified by X and/or file attributes. If the file may + be removed, return RM_OK. If the user declines to remove the file, + return RM_USER_DECLINED. If not ignoring missing files and we + cannot lstat FILENAME, then return RM_ERROR. + + Depending on MODE, ask whether to `descend into' or to `remove' the + directory FILENAME. MODE is ignored when FILENAME is not a directory. + Set *IS_EMPTY to T_YES if FILENAME is an empty directory, and it is + appropriate to try to remove it with rmdir (e.g. recursive mode). + Don't even try to set *IS_EMPTY when MODE == PA_REMOVE_DIR. + Set *IS_DIR to T_YES or T_NO if we happen to determine whether + FILENAME is a directory. */ +static enum RM_status +prompt (Dirstack_state const *ds, char const *filename, + struct rm_options const *x, enum Prompt_action mode, + Ternary *is_dir, Ternary *is_empty) +{ + int write_protected = 0; + *is_empty = T_UNKNOWN; + *is_dir = T_UNKNOWN; + + if ((!x->ignore_missing_files && (x->interactive || x->stdin_tty) + && (write_protected = (euidaccess (filename, W_OK) && errno == EACCES))) + || x->interactive) + { + struct stat sbuf; + if (lstat (filename, &sbuf)) + { + /* lstat failed. This happens e.g., with `rm '''. */ + error (0, errno, _("cannot lstat %s"), + quote (full_filename (filename))); + return RM_ERROR; + } + + /* Using permissions doesn't make sense for symlinks. */ + if (S_ISLNK (sbuf.st_mode)) + { + if ( ! x->interactive) + return RM_OK; + write_protected = 0; + } + + /* Issue the prompt. */ + { + char const *quoted_name = quote (full_filename (filename)); + + *is_dir = (S_ISDIR (sbuf.st_mode) ? T_YES : T_NO); + + /* FIXME: use a variant of error (instead of fprintf) that doesn't + append a newline. Then we won't have to declare program_name in + this file. */ + if (S_ISDIR (sbuf.st_mode) + && x->recursive + && mode == PA_DESCEND_INTO_DIR + && ((*is_empty = (is_empty_dir (filename) ? T_YES : T_NO)) + == T_NO)) + fprintf (stderr, + (write_protected + ? _("%s: descend into write-protected directory %s? ") + : _("%s: descend into directory %s? ")), + program_name, quoted_name); + else + { + /* TRANSLATORS: You may find it more convenient to translate + the equivalent of _("%s: remove %s (write-protected) %s? "). + It should avoid grammatical problems with the output + of file_type. */ + fprintf (stderr, + (write_protected + ? _("%s: remove write-protected %s %s? ") + : _("%s: remove %s %s? ")), + program_name, file_type (&sbuf), quoted_name); + } + + if (!yesno ()) + return RM_USER_DECLINED; + } + } + return RM_OK; +} + +#if HAVE_STRUCT_DIRENT_D_TYPE +# define DT_IS_DIR(D) ((D)->d_type == DT_DIR) +#else +/* Use this only if the member exists -- i.e., don't return 0. */ +# define DT_IS_DIR(D) do_not_use_this_macro +#endif + +#define DO_UNLINK(Filename, X) \ + do \ + { \ + if (unlink (Filename) == 0) \ + { \ + if ((X)->verbose) \ + printf (_("removed %s\n"), quote (full_filename (Filename))); \ + return RM_OK; \ + } \ + \ + if (errno == ENOENT && (X)->ignore_missing_files) \ + return RM_OK; \ + } \ + while (0) + +#define DO_RMDIR(Filename, X) \ + do \ + { \ + if (rmdir (Filename) == 0) \ + { \ + if ((X)->verbose) \ + printf (_("removed directory: %s\n"), \ + quote (full_filename (Filename))); \ + return RM_OK; \ + } \ + \ + if (errno == ENOENT && (X)->ignore_missing_files) \ + return RM_OK; \ + \ + if (errno == ENOTEMPTY || errno == EEXIST) \ + return RM_NONEMPTY_DIR; \ + } \ + while (0) + +/* Remove the file or directory specified by FILENAME. + Return RM_OK if it is removed, and RM_ERROR or RM_USER_DECLINED if not. + But if FILENAME specifies a non-empty directory, return RM_NONEMPTY_DIR. */ + +static enum RM_status +remove_entry (Dirstack_state const *ds, char const *filename, + struct rm_options const *x, struct dirent const *dp) +{ + Ternary is_dir; + Ternary is_empty_directory; + enum RM_status s = prompt (ds, filename, x, PA_DESCEND_INTO_DIR, + &is_dir, &is_empty_directory); + + if (s != RM_OK) + return s; + + /* Why bother with the following #if/#else block? Because on systems with + an unlink function that *can* unlink directories, we must determine the + type of each entry before removing it. Otherwise, we'd risk unlinking an + entire directory tree simply by unlinking a single directory; then all + the storage associated with that hierarchy would not be freed until the + next reboot. Not nice. To avoid that, on such slightly losing systems, we + need to call lstat to determine the type of each entry, and that represents + extra overhead that -- it turns out -- we can avoid on GNU-libc-based + systems, since there, unlink will never remove a directory. */ + +#if ROOT_CAN_UNLINK_DIRS + + /* If we don't already know whether FILENAME is a directory, find out now. + Then, if it's a non-directory, we can use unlink on it. */ + if (is_dir == T_UNKNOWN) + { +# if HAVE_STRUCT_DIRENT_D_TYPE + if (dp && dp->d_type != DT_UNKNOWN) + is_dir = DT_IS_DIR (dp) ? T_YES : T_NO; + else +# endif + { + struct stat sbuf; + if (lstat (filename, &sbuf)) + { + if (errno == ENOENT && x->ignore_missing_files) + return RM_OK; + + error (0, errno, + _("cannot lstat %s"), quote (full_filename (filename))); + return RM_ERROR; + } + + is_dir = S_ISDIR (sbuf.st_mode) ? T_YES : T_NO; + } + } + + if (is_dir == T_NO) + { + /* At this point, barring race conditions, FILENAME is known + to be a non-directory, so it's ok to try to unlink it. */ + DO_UNLINK (filename, x); + + /* unlink failed with some other error code. report it. */ + error (0, errno, _("cannot remove %s"), + quote (full_filename (filename))); + return RM_ERROR; + } + + if (! x->recursive) + { + error (0, EISDIR, _("cannot remove directory %s"), + quote (full_filename (filename))); + return RM_ERROR; + } + + if (is_empty_directory == T_YES) + { + DO_RMDIR (filename, x); + /* Don't diagnose any failure here. + It'll be detected when the caller tries another way. */ + } + + +#else /* ! ROOT_CAN_UNLINK_DIRS */ + + if (is_dir == T_YES && ! x->recursive) + { + error (0, EISDIR, _("cannot remove directory %s"), + quote (full_filename (filename))); + return RM_ERROR; + } + + /* is_empty_directory is set iff it's ok to use rmdir. + Note that it's set only in interactive mode -- in which case it's + an optimization that arranges so that the user is asked just + once whether to remove the directory. */ + if (is_empty_directory == T_YES) + DO_RMDIR (filename, x); + + /* If we happen to know that FILENAME is a directory, return now + and let the caller remove it -- this saves the overhead of a failed + unlink call. If FILENAME is a command-line argument, then dp is NULL, + so we'll first try to unlink it. Using unlink here is ok, because it + cannot remove a directory. */ +#if HAVE_STRUCT_DIRENT_D_TYPE + if ((dp && DT_IS_DIR (dp)) || is_dir == T_YES) + return RM_NONEMPTY_DIR; +#endif + + DO_UNLINK (filename, x); + + /* Accept either EISDIR or EPERM as an indication that FILENAME may be + a directory. POSIX says that unlink must set errno to EPERM when it + fails to remove a directory, while Linux-2.4.18 sets it to EISDIR. */ + if ((errno != EISDIR && errno != EPERM) || ! x->recursive) + { + /* some other error code. Report it and fail. + Likewise, if we're trying to remove a directory without + the --recursive option. */ + error (0, errno, _("cannot remove %s"), + quote (full_filename (filename))); + return RM_ERROR; + } +#endif + + return RM_NONEMPTY_DIR; +} + +/* Remove entries in `.', the current working directory (cwd). + Upon finding a directory that is both non-empty and that can be chdir'd + into, return RM_OK and set *SUBDIR and fill in SUBDIR_SB, where + SUBDIR is the malloc'd name of the subdirectory if the chdir succeeded, + NULL otherwise (e.g., if opendir failed or if there was no subdirectory). + Likewise, SUBDIR_SB is the result of calling lstat on SUBDIR. + Return RM_OK if all entries are removed. Return RM_ERROR if any + entry cannot be removed. Otherwise, return RM_USER_DECLINED if + the user declines to remove at least one entry. Remove as much as + possible, continuing even if we fail to remove some entries. */ +static enum RM_status +remove_cwd_entries (Dirstack_state *ds, char **subdir, struct stat *subdir_sb, + struct rm_options const *x) +{ + DIR *dirp = opendir ("."); + struct AD_ent *top = AD_stack_top (ds); + enum RM_status status = top->status; + + assert (VALID_STATUS (status)); + *subdir = NULL; + + if (dirp == NULL) + { + if (errno != ENOENT || !x->ignore_missing_files) + { + error (0, errno, _("cannot open directory %s"), + quote (full_filename ("."))); + return RM_ERROR; + } + } + + while (1) + { + struct dirent *dp; + enum RM_status tmp_status; + const char *f; + + /* Set errno to zero so we can distinguish between a readdir failure + and when readdir simply finds that there are no more entries. */ + errno = 0; + if ((dp = readdir (dirp)) == NULL) + { + if (errno) + { + /* Save/restore errno across closedir call. */ + int e = errno; + closedir (dirp); + errno = e; + + /* Arrange to give a diagnostic after exiting this loop. */ + dirp = NULL; + } + break; + } + + f = dp->d_name; + if (DOT_OR_DOTDOT (f)) + continue; + + /* Skip files we've already tried/failed to remove. */ + if ( ! AD_is_removable (ds, f)) + continue; + + /* Pass dp->d_type info to remove_entry so the non-glibc + case can decide whether to use unlink or chdir. + Systems without the d_type member will have to endure + the performance hit of first calling lstat F. */ + tmp_status = remove_entry (ds, f, x, dp); + switch (tmp_status) + { + case RM_OK: + /* do nothing */ + break; + + case RM_ERROR: + case RM_USER_DECLINED: + AD_mark_as_unremovable (ds, f); + UPDATE_STATUS (status, tmp_status); + break; + + case RM_NONEMPTY_DIR: + { + /* Save a copy of errno, in case the preceding unlink (from + remove_entry's DO_UNLINK) of a non-directory failed due + to EPERM. */ + int saved_errno = errno; + + /* Record dev/ino of F so that we can compare + that with dev/ino of `.' after the chdir. + This dev/ino pair is also used in cycle detection. */ + if (lstat (f, subdir_sb)) + error (EXIT_FAILURE, errno, _("cannot lstat %s"), + quote (full_filename (f))); + + if (chdir (f)) + { + /* It is much more common that we reach this point for an + inaccessible directory. Hence the second diagnostic, below. + However it is also possible that F is a non-directory. + That can happen when we use the `! ROOT_CAN_UNLINK_DIRS' + block of code and when DO_UNLINK fails due to EPERM. + In that case, give a better diagnostic. */ + if (errno == ENOTDIR) + error (0, saved_errno, _("cannot remove %s"), + quote (full_filename (f))); + else + error (0, errno, _("cannot chdir from %s to %s"), + quote_n (0, full_filename (".")), quote_n (1, f)); + AD_mark_as_unremovable (ds, f); + status = RM_ERROR; + break; + } + if (cycle_check (&ds->cycle_check_state, subdir_sb)) + { + error (0, 0, _("\ +WARNING: Circular directory structure.\n\ +This almost certainly means that you have a corrupted file system.\n\ +NOTIFY YOUR SYSTEM MANAGER.\n\ +The following directory is part of the cycle:\n %s\n"), + quote (full_filename ("."))); + longjmp (ds->current_arg_jumpbuf, 1); + } + + *subdir = xstrdup (f); + break; + } + } + + /* Record status for this directory. */ + UPDATE_STATUS (top->status, status); + + if (*subdir) + break; + } + + if (dirp == NULL || CLOSEDIR (dirp) != 0) + { + /* Note that this diagnostic serves for both readdir + and closedir failures. */ + error (0, errno, _("reading directory %s"), quote (full_filename ("."))); + status = RM_ERROR; + } + + return status; +} + +/* Do this after each call to AD_push or AD_push_initial. + Because the status = RM_OK bit is too remove-specific to + go into the general-purpose AD_* package. */ +#define AD_INIT_OTHER_MEMBERS() \ + do \ + { \ + AD_stack_top(ds)->status = RM_OK; \ + } \ + while (0) + +/* Remove the hierarchy rooted at DIR. + Do that by changing into DIR, then removing its contents, then + returning to the original working directory and removing DIR itself. + Don't use recursion. Be careful when using chdir ".." that we + return to the same directory from which we came, if necessary. + Return 1 for success, 0 if some file cannot be removed or if + a chdir fails. + If the working directory cannot be restored, exit immediately. */ + +static enum RM_status +remove_dir (Dirstack_state *ds, char const *dir, struct saved_cwd **cwd_state, + struct rm_options const *x) +{ + enum RM_status status; + struct stat dir_sb; + + /* Save any errno (from caller's failed remove_entry call), in case DIR + is not a directory, so that we can give a reasonable diagnostic. */ + int saved_errno = errno; + + if (*cwd_state == NULL) + { + *cwd_state = XMALLOC (struct saved_cwd, 1); + if (save_cwd (*cwd_state)) + return RM_ERROR; + AD_push_initial (ds, *cwd_state); + AD_INIT_OTHER_MEMBERS (); + } + + /* There is a race condition in that an attacker could replace the nonempty + directory, DIR, with a symlink between the preceding call to rmdir + (in our caller) and the chdir below. However, the following lstat, + along with the `stat (".",...' and dev/ino comparison in AD_push + ensure that we detect it and fail. */ + + if (lstat (dir, &dir_sb)) + { + error (0, errno, + _("cannot lstat %s"), quote (full_filename (dir))); + return RM_ERROR; + } + + if (chdir (dir)) + { + if (! S_ISDIR (dir_sb.st_mode)) + { + /* This happens on Linux-2.4.18 when a non-privileged user tries + to delete a file that is owned by another user in a directory + like /tmp that has the S_ISVTX flag set. */ + assert (saved_errno == EPERM); + error (0, saved_errno, + _("cannot remove %s"), quote (full_filename (dir))); + } + else + { + error (0, errno, + _("cannot chdir from %s to %s"), + quote_n (0, full_filename (".")), quote_n (1, dir)); + } + return RM_ERROR; + } + + AD_push (ds, dir, &dir_sb); + AD_INIT_OTHER_MEMBERS (); + + status = RM_OK; + + while (1) + { + char *subdir = NULL; + struct stat subdir_sb; + enum RM_status tmp_status = remove_cwd_entries (ds, + &subdir, &subdir_sb, x); + if (tmp_status != RM_OK) + { + UPDATE_STATUS (status, tmp_status); + AD_mark_current_as_unremovable (ds); + } + if (subdir) + { + AD_push (ds, subdir, &subdir_sb); + AD_INIT_OTHER_MEMBERS (); + + free (subdir); + continue; + } + + /* Execution reaches this point when we've removed the last + removable entry from the current directory. */ + { + char *d = AD_pop_and_chdir (ds); + + /* Try to remove D only if remove_cwd_entries succeeded. */ + if (tmp_status == RM_OK) + { + /* This does a little more work than necessary when it actually + prompts the user. E.g., we already know that D is a directory + and that it's almost certainly empty, yet we lstat it. + But that's no big deal since we're interactive. */ + Ternary is_dir; + Ternary is_empty; + enum RM_status s = prompt (ds, d, x, PA_REMOVE_DIR, + &is_dir, &is_empty); + + if (s != RM_OK) + { + free (d); + return s; + } + + if (rmdir (d) == 0) + { + if (x->verbose) + printf (_("removed directory: %s\n"), + quote (full_filename (d))); + } + else + { + error (0, errno, _("cannot remove directory %s"), + quote (full_filename (d))); + AD_mark_as_unremovable (ds, d); + status = RM_ERROR; + UPDATE_STATUS (AD_stack_top(ds)->status, status); + } + } + + free (d); + + if (AD_stack_height (ds) == 1) + break; + } + } + + return status; +} + +/* Remove the file or directory specified by FILENAME. + Return RM_OK if it is removed, and RM_ERROR or RM_USER_DECLINED if not. + On input, the first time this function is called, CWD_STATE should be + the address of a NULL pointer. Do not modify it for any subsequent calls. + On output, it is either that same NULL pointer or the address of + a malloc'd `struct saved_cwd' that may be freed. */ + +static enum RM_status +rm_1 (Dirstack_state *ds, char const *filename, + struct rm_options const *x, struct saved_cwd **cwd_state) +{ + char *base = base_name (filename); + enum RM_status status; + + if (DOT_OR_DOTDOT (base)) + { + error (0, 0, _("cannot remove `.' or `..'")); + return RM_ERROR; + } + + status = remove_entry (ds, filename, x, NULL); + if (status != RM_NONEMPTY_DIR) + return status; + + return remove_dir (ds, filename, cwd_state, x); +} + +/* Remove all files and/or directories specified by N_FILES and FILE. + Apply the options in X. */ +enum RM_status +rm (size_t n_files, char const *const *file, struct rm_options const *x) +{ + struct saved_cwd *cwd_state = NULL; + Dirstack_state *ds; + + /* Put the following two variables in static storage, so they can't + be clobbered by the potential longjmp into this function. */ + static enum RM_status status = RM_OK; + static size_t i; + + ds = ds_init (); + + for (i = 0; i < n_files; i++) + { + enum RM_status s; + cycle_check_init (&ds->cycle_check_state); + /* In the event that rm_1->remove_dir->remove_cwd_entries detects + a directory cycle, arrange to fail, give up on this FILE, but + continue on with any other arguments. */ + if (setjmp (ds->current_arg_jumpbuf)) + s = RM_ERROR; + else + s = rm_1 (ds, file[i], x, &cwd_state); + assert (VALID_STATUS (s)); + UPDATE_STATUS (status, s); + } + + ds_free (ds); + + XFREE (cwd_state); + + return status; +} diff --git a/src/apps/bin/coreutils-5.0/src/remove.h b/src/apps/bin/coreutils-5.0/src/remove.h new file mode 100644 index 0000000000..beaac27fdb --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/remove.h @@ -0,0 +1,51 @@ +#ifndef REMOVE_H +# define REMOVE_H + +struct rm_options +{ + /* If nonzero, ignore nonexistent files. */ + int ignore_missing_files; + + /* If nonzero, query the user about whether to remove each file. */ + int interactive; + + /* If nonzero, recursively remove directories. */ + int recursive; + + /* If nonzero, stdin is a tty. */ + int stdin_tty; + + /* If nonzero, remove directories with unlink instead of rmdir, and don't + require a directory to be empty before trying to unlink it. + Only works for the super-user. */ + int unlink_dirs; + + /* If nonzero, display the name of each file removed. */ + int verbose; +}; + +enum RM_status +{ + /* These must be listed in order of increasing seriousness. */ + RM_OK = 2, + RM_USER_DECLINED, + RM_ERROR, + RM_NONEMPTY_DIR +}; + +# define VALID_STATUS(S) \ + ((S) == RM_OK || (S) == RM_USER_DECLINED || (S) == RM_ERROR) + +# define UPDATE_STATUS(S, New_value) \ + do \ + { \ + if ((New_value) == RM_ERROR \ + || ((New_value) == RM_USER_DECLINED && (S) == RM_OK)) \ + (S) = (New_value); \ + } \ + while (0) + +enum RM_status rm (size_t n_files, char const *const *file, + struct rm_options const *x); + +#endif diff --git a/src/apps/bin/coreutils-5.0/src/rm.c b/src/apps/bin/coreutils-5.0/src/rm.c new file mode 100644 index 0000000000..737bce167b --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/rm.c @@ -0,0 +1,215 @@ +/* `rm' file deletion utility for GNU. + Copyright (C) 88, 90, 91, 1994-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Paul Rubin, David MacKenzie, and Richard Stallman. + Reworked to use chdir and avoid recursion by Jim Meyering. */ + +/* Implementation overview: + + In the `usual' case, RM saves no state for directories it is processing. + When a removal fails (either due to an error or to an interactive `no' + reply), the failure is noted (see description of `ht' in remove.c's + remove_cwd_entries function) so that when/if the containing directory + is reopened, RM doesn't try to remove the entry again. + + RM may delete arbitrarily deep hierarchies -- even ones in which file + names (from root to leaf) are longer than the system-imposed maximum. + It does this by using chdir to change to each directory in turn before + removing the entries in that directory. + + RM detects directory cycles lazily. See lib/cycle-check.c. + + RM is careful to avoid forming full file names whenever possible. + A full file name is formed only when it is about to be used -- e.g. + in a diagnostic or in an interactive-mode prompt. + + RM minimizes the number of lstat system calls it makes. On systems + that have valid d_type data in directory entries, RM makes only one + lstat call per command line argument -- regardless of the depth of + the hierarchy. */ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "remove.h" +#include "save-cwd.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "rm" + +#define AUTHORS \ + N_ ("Paul Rubin, David MacKenzie, Richard Stallman, and Jim Meyering") + +/* Name this program was run with. */ +char *program_name; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1 +}; + +static struct option const long_opts[] = +{ + {"directory", no_argument, NULL, 'd'}, + {"force", no_argument, NULL, 'f'}, + {"interactive", no_argument, NULL, 'i'}, + + /* This is solely for testing. Do not document. */ + /* It is relatively difficult to ensure that there is a tty on stdin. + Since rm acts differently depending on that, without this option, + it'd be harder to test the parts of rm that depend on that setting. */ + {"presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION}, + + {"recursive", no_argument, NULL, 'r'}, + {"verbose", no_argument, NULL, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... FILE...\n"), program_name); + fputs (_("\ +Remove (unlink) the FILE(s).\n\ +\n\ + -d, --directory unlink FILE, even if it is a non-empty directory\n\ + (super-user only)\n\ + -f, --force ignore nonexistent files, never prompt\n\ + -i, --interactive prompt before any removal\n\ + -r, -R, --recursive remove the contents of directories recursively\n\ + -v, --verbose explain what is being done\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\ +\n\ +To remove a file whose name starts with a `-', for example `-foo',\n\ +use one of these commands:\n\ + %s -- -foo\n\ +\n\ + %s ./-foo\n\ +"), + program_name, program_name); + fputs (_("\ +\n\ +Note that if you use rm to remove a file, it is usually possible to recover\n\ +the contents of that file. If you want more assurance that the contents are\n\ +truly unrecoverable, consider using shred.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +static void +rm_option_init (struct rm_options *x) +{ + x->unlink_dirs = 0; + x->ignore_missing_files = 0; + x->interactive = 0; + x->recursive = 0; + x->stdin_tty = isatty (STDIN_FILENO); + x->verbose = 0; +} + +int +main (int argc, char **argv) +{ + struct rm_options x; + int fail = 0; + int c; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + rm_option_init (&x); + + while ((c = getopt_long (argc, argv, "dfirvR", long_opts, NULL)) != -1) + { + switch (c) + { + case 0: /* Long option. */ + break; + case 'd': + x.unlink_dirs = 1; + break; + case 'f': + x.interactive = 0; + x.ignore_missing_files = 1; + break; + case 'i': + x.interactive = 1; + x.ignore_missing_files = 0; + break; + case 'r': + case 'R': + x.recursive = 1; + break; + case PRESUME_INPUT_TTY_OPTION: + x.stdin_tty = 1; + break; + case 'v': + x.verbose = 1; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + } + + if (optind == argc) + { + if (x.ignore_missing_files) + exit (EXIT_SUCCESS); + else + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + } + + { + size_t n_files = argc - optind; + char const *const *file = (char const *const *) argv + optind; + + enum RM_status status = rm (n_files, file, &x); + assert (VALID_STATUS (status)); + if (status == RM_ERROR) + fail = 1; + } + + exit (fail); +} diff --git a/src/apps/bin/coreutils-5.0/src/rmdir.c b/src/apps/bin/coreutils-5.0/src/rmdir.c new file mode 100644 index 0000000000..8c4ec98f20 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/rmdir.c @@ -0,0 +1,237 @@ +/* rmdir -- remove directories + Copyright (C) 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Options: + -p, --parent Remove any parent dirs that are explicitly mentioned + in an argument, if they become empty after the + argument file is removed. + + David MacKenzie */ + +#include +#include +#include +#include + +#include "system.h" +#include "dirname.h" +#include "error.h" +#include "quote.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "rmdir" + +#define AUTHORS "David MacKenzie" + +#ifndef EEXIST +# define EEXIST 0 +#endif + +#ifndef ENOTEMPTY +# define ENOTEMPTY 0 +#endif + +/* The name this program was run with. */ +char *program_name; + +/* If nonzero, remove empty parent directories. */ +static int empty_paths; + +/* If nonzero, don't treat failure to remove a nonempty directory + as an error. */ +static int ignore_fail_on_non_empty; + +/* If nonzero, output a diagnostic for every directory processed. */ +static int verbose; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + IGNORE_FAIL_ON_NON_EMPTY_OPTION = CHAR_MAX + 1 +}; + +static struct option const longopts[] = +{ + /* Don't name this `--force' because it's not close enough in meaning + to e.g. rm's -f option. */ + {"ignore-fail-on-non-empty", no_argument, NULL, + IGNORE_FAIL_ON_NON_EMPTY_OPTION}, + + {"path", no_argument, NULL, 'p'}, + {"parents", no_argument, NULL, 'p'}, + {"verbose", no_argument, NULL, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +/* Return nonzero if ERROR_NUMBER is one of the values associated + with a failed rmdir due to non-empty target directory. */ + +static int +errno_rmdir_non_empty (int error_number) +{ + return (error_number == RMDIR_ERRNO_NOT_EMPTY); +} + +/* Remove any empty parent directories of PATH. + If PATH contains slash characters, at least one of them + (beginning with the rightmost) is replaced with a NUL byte. */ + +static int +remove_parents (char *path) +{ + char *slash; + int fail = 0; + + strip_trailing_slashes (path); + while (1) + { + slash = strrchr (path, '/'); + if (slash == NULL) + break; + /* Remove any characters after the slash, skipping any extra + slashes in a row. */ + while (slash > path && *slash == '/') + --slash; + slash[1] = 0; + + /* Give a diagnostic for each attempted removal if --verbose. */ + if (verbose) + error (0, 0, _("removing directory, %s"), path); + + fail = rmdir (path); + + if (fail) + { + /* Stop quietly if --ignore-fail-on-non-empty. */ + if (ignore_fail_on_non_empty + && errno_rmdir_non_empty (errno)) + { + fail = 0; + } + else + { + error (0, errno, "%s", quote (path)); + } + break; + } + } + return fail; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... DIRECTORY...\n"), program_name); + fputs (_("\ +Remove the DIRECTORY(ies), if they are empty.\n\ +\n\ + --ignore-fail-on-non-empty\n\ + ignore each failure that is solely because a directory\n\ + is non-empty\n\ +"), stdout); + fputs (_("\ + -p, --parents remove DIRECTORY, then try to remove each directory\n\ + component of that path name. E.g., `rmdir -p a/b/c' is\n\ + similar to `rmdir a/b/c a/b a'.\n\ + -v, --verbose output a diagnostic for every directory processed\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int errors = 0; + int optc; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + empty_paths = 0; + + while ((optc = getopt_long (argc, argv, "pv", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: /* Long option. */ + break; + case 'p': + empty_paths = 1; + break; + case IGNORE_FAIL_ON_NON_EMPTY_OPTION: + ignore_fail_on_non_empty = 1; + break; + case 'v': + verbose = 1; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + } + + if (optind == argc) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + for (; optind < argc; ++optind) + { + int fail; + char *dir = argv[optind]; + + /* Give a diagnostic for each attempted removal if --verbose. */ + if (verbose) + error (0, 0, _("removing directory, %s"), dir); + + fail = rmdir (dir); + + if (fail) + { + if (ignore_fail_on_non_empty + && errno_rmdir_non_empty (errno)) + continue; + + error (0, errno, "%s", quote (dir)); + errors = 1; + } + else if (empty_paths) + { + errors += remove_parents (dir); + } + } + + exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/seq.c b/src/apps/bin/coreutils-5.0/src/seq.c new file mode 100644 index 0000000000..601f5f13c8 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/seq.c @@ -0,0 +1,466 @@ +/* seq - print sequence of numbers to standard output. + Copyright (C) 1994-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Ulrich Drepper. */ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "xstrtol.h" +#include "xstrtod.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "seq" + +#define AUTHORS "Ulrich Drepper" + +/* If nonzero print all number with equal width. */ +static int equal_width; + +/* The name that this program was run with. */ +char *program_name; + +/* The string used to separate two numbers. */ +static char *separator; + +/* The string output after all numbers have been output. + Usually "\n" or "\0". */ +/* FIXME: make this an option. */ +static char *terminator = "\n"; + +/* The representation of the decimal point in the current locale. + Always "." if the localeconv function is not supported. */ +static char *decimal_point = "."; + +/* The starting number. */ +static double first; + +/* The increment. */ +static double step; + +/* The last number. */ +static double last; + +static struct option const long_options[] = +{ + { "equal-width", no_argument, NULL, 'w'}, + { "format", required_argument, NULL, 'f'}, + { "separator", required_argument, NULL, 's'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + { NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... LAST\n\ + or: %s [OPTION]... FIRST LAST\n\ + or: %s [OPTION]... FIRST INCREMENT LAST\n\ +"), program_name, program_name, program_name); + fputs (_("\ +Print numbers from FIRST to LAST, in steps of INCREMENT.\n\ +\n\ + -f, --format=FORMAT use printf style floating-point FORMAT (default: %g)\n\ + -s, --separator=STRING use STRING to separate numbers (default: \\n)\n\ + -w, --equal-width equalize width by padding with leading zeroes\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +If FIRST or INCREMENT is omitted, it defaults to 1.\n\ +FIRST, INCREMENT, and LAST are interpreted as floating point values.\n\ +INCREMENT should be positive if FIRST is smaller than LAST, and negative\n\ +otherwise. When given, the FORMAT argument must contain exactly one of\n\ +the printf-style, floating point output formats %e, %f, %g\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +/* Read a double value from the command line. + Return if the string is correct else signal error. */ + +static double +scan_double_arg (const char *arg) +{ + double ret_val; + + if (xstrtod (arg, NULL, &ret_val)) + { + error (0, 0, _("invalid floating point argument: %s"), arg); + usage (EXIT_FAILURE); + } + + return ret_val; +} + +/* Check whether the format string is valid for a single `double' + argument. Return 0 if not, 1 if correct. */ + +static int +valid_format (const char *fmt) +{ + while (*fmt != '\0') + { + if (*fmt == '%') + { + fmt++; + if (*fmt != '%') + break; + } + + fmt++; + } + if (*fmt == '\0') + return 0; + + fmt += strspn (fmt, "-+#0 '"); + if (ISDIGIT (*fmt) || *fmt == '.') + { + fmt += strspn (fmt, "0123456789"); + + if (*fmt == '.') + { + ++fmt; + fmt += strspn (fmt, "0123456789"); + } + } + + if (!(*fmt == 'e' || *fmt == 'f' || *fmt == 'g')) + return 0; + + fmt++; + while (*fmt != '\0') + { + if (*fmt == '%') + { + fmt++; + if (*fmt != '%') + return 0; + } + + fmt++; + } + + return 1; +} + +/* Actually print the sequence of numbers in the specified range, with the + given or default stepping and format. */ +static int +print_numbers (const char *fmt) +{ + if (first > last) + { + int i; + + if (step >= 0) + { + error (0, 0, + _("when the starting value is larger than the limit,\n\ +the increment must be negative")); + usage (EXIT_FAILURE); + } + + printf (fmt, first); + for (i = 1; /* empty */; i++) + { + double x = first + i * step; + + if (x < last) + break; + + fputs (separator, stdout); + printf (fmt, x); + } + } + else + { + int i; + + if (step <= 0) + { + error (0, 0, + _("when the starting value is smaller than the limit,\n\ +the increment must be positive")); + usage (EXIT_FAILURE); + } + + printf (fmt, first); + for (i = 1; /* empty */; i++) + { + double x = first + i * step; + + if (x > last) + break; + + fputs (separator, stdout); + printf (fmt, x); + } + } + fputs (terminator, stdout); + + return 0; +} + +#if HAVE_RINT && HAVE_MODF && HAVE_FLOOR + +/* Return a printf-style format string with which all selected numbers + will format to strings of the same width. */ + +static char * +get_width_format () +{ + static char buffer[256]; + int full_width; + int frac_width; + int width1, width2; + double max_val; + double min_val; + double temp; + + if (first > last) + { + min_val = first - step * floor ((first - last) / step); + max_val = first; + } + else + { + min_val = first; + max_val = first + step * floor ((last - first) / step); + } + + sprintf (buffer, "%g", rint (max_val)); + if (buffer[strspn (buffer, "0123456789")] != '\0') + return "%g"; + width1 = strlen (buffer); + + if (min_val < 0.0) + { + double int_min_val = rint (min_val); + sprintf (buffer, "%g", int_min_val); + if (buffer[strspn (buffer, "-0123456789")] != '\0') + return "%g"; + /* On some systems, `seq -w -.1 .1 .1' results in buffer being `-0'. + On others, it is just `0'. The former results in better output. */ + width2 = (int_min_val == 0 ? 2 : strlen (buffer)); + + width1 = width1 > width2 ? width1 : width2; + } + full_width = width1; + + sprintf (buffer, "%g", 1.0 + modf (fabs (min_val), &temp)); + width1 = strlen (buffer); + if (width1 == 1) + width1 = 0; + else + { + if (buffer[0] != '1' + /* FIXME: assumes that decimal_point is a single character + string. */ + || buffer[1] != decimal_point[0] + || buffer[2 + strspn (&buffer[2], "0123456789")] != '\0') + return "%g"; + width1 -= 2; + } + + sprintf (buffer, "%g", 1.0 + modf (fabs (step), &temp)); + width2 = strlen (buffer); + if (width2 == 1) + width2 = 0; + else + { + if (buffer[0] != '1' + /* FIXME: assumes that decimal_point is a single character + string. */ + || buffer[1] != decimal_point[0] + || buffer[2 + strspn (&buffer[2], "0123456789")] != '\0') + return "%g"; + width2 -= 2; + } + frac_width = width1 > width2 ? width1 : width2; + + if (frac_width) + sprintf (buffer, "%%0%d.%df", full_width + 1 + frac_width, frac_width); + else + sprintf (buffer, "%%0%dg", full_width); + + return buffer; +} + +#else /* one of the math functions rint, modf, floor is missing. */ + +static char * +get_width_format (void) +{ + /* We cannot compute the needed information to determine the correct + answer. So we simply return a value that works for all cases. */ + return "%g"; +} + +#endif + +int +main (int argc, char **argv) +{ + int errs; + int optc; + int step_is_set; + + /* The printf(3) format used for output. */ + char *format_str = NULL; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + equal_width = 0; + separator = "\n"; + first = 1.0; + step_is_set = 0; + + /* Figure out the locale's idea of a decimal point. */ +#if HAVE_LOCALECONV + { + struct lconv *locale; + + locale = localeconv (); + /* Paranoia. */ + if (locale && locale->decimal_point && locale->decimal_point[0] != '\0') + decimal_point = locale->decimal_point; + } +#endif + + /* We have to handle negative numbers in the command line but this + conflicts with the command line arguments. So explicitly check first + whether the next argument looks like a negative number. */ + while (optind < argc) + { + if (argv[optind][0] == '-' + && ((optc = argv[optind][1]) == decimal_point[0] + || ISDIGIT (optc))) + { + /* means negative number */ + break; + } + + optc = getopt_long (argc, argv, "+f:s:w", long_options, NULL); + if (optc == -1) + break; + + switch (optc) + { + case 0: + break; + + case 'f': + format_str = optarg; + break; + + case 's': + separator = optarg; + break; + + case 'w': + equal_width = 1; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (argc - optind < 1) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + if (3 < argc - optind) + { + error (0, 0, _("too many arguments")); + usage (EXIT_FAILURE); + } + + if (format_str && !valid_format (format_str)) + { + error (0, 0, _("invalid format string: `%s'"), format_str); + usage (EXIT_FAILURE); + } + + last = scan_double_arg (argv[optind++]); + + if (optind < argc) + { + first = last; + last = scan_double_arg (argv[optind++]); + + if (optind < argc) + { + step = last; + step_is_set = 1; + last = scan_double_arg (argv[optind++]); + + } + } + + if (format_str != NULL && equal_width) + { + error (0, 0, _("\ +format string may not be specified when printing equal width strings")); + usage (EXIT_FAILURE); + } + + if (!step_is_set) + { + step = first <= last ? 1.0 : -1.0; + } + + if (format_str == NULL) + { + if (equal_width) + format_str = get_width_format (); + else + format_str = "%g"; + } + + errs = print_numbers (format_str); + + exit (errs); +} diff --git a/src/apps/bin/coreutils-5.0/src/sha1sum.c b/src/apps/bin/coreutils-5.0/src/sha1sum.c new file mode 100644 index 0000000000..1d4fdd8001 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/sha1sum.c @@ -0,0 +1,7 @@ +#include +#include +#include +#include "system.h" +#include "checksum.h" + +int algorithm = ALG_SHA1; diff --git a/src/apps/bin/coreutils-5.0/src/shred.c b/src/apps/bin/coreutils-5.0/src/shred.c new file mode 100644 index 0000000000..305023b5a0 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/shred.c @@ -0,0 +1,1629 @@ +/* shred.c - overwrite files and devices to make it harder to recover data + + Copyright (C) 1999-2003 Free Software Foundation, Inc. + Copyright (C) 1997, 1998, 1999 Colin Plumb. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Written by Colin Plumb. */ + +/* TODO: + - use consistent non-capitalization in error messages + - add standard GNU copyleft comment + + - Add -r/-R/--recursive + - Add -i/--interactive + - Reserve -d + - Add -L + - Deal with the amazing variety of gettimeofday() implementation bugs. + (Some systems use a one-arg form; still others insist that the timezone + either be NULL or be non-NULL. Whee.) + - Add an unlink-all option to emulate rm. + */ + +/* + * Do a more secure overwrite of given files or devices, to make it harder + * for even very expensive hardware probing to recover the data. + * + * Although this process is also known as "wiping", I prefer the longer + * name both because I think it is more evocative of what is happening and + * because a longer name conveys a more appropriate sense of deliberateness. + * + * For the theory behind this, see "Secure Deletion of Data from Magnetic + * and Solid-State Memory", on line at + * http://www.cs.auckland.ac.nz/~pgut001/pubs/secure_del.html + * + * Just for the record, reversing one or two passes of disk overwrite + * is not terribly difficult with hardware help. Hook up a good-quality + * digitizing oscilloscope to the output of the head preamplifier and copy + * the high-res digitized data to a computer for some off-line analysis. + * Read the "current" data and average all the pulses together to get an + * "average" pulse on the disk. Subtract this average pulse from all of + * the actual pulses and you can clearly see the "echo" of the previous + * data on the disk. + * + * Real hard drives have to balance the cost of the media, the head, + * and the read circuitry. They use better-quality media than absolutely + * necessary to limit the cost of the read circuitry. By throwing that + * assumption out, and the assumption that you want the data processed + * as fast as the hard drive can spin, you can do better. + * + * If asked to wipe a file, this also unlinks it, renaming it to in a + * clever way to try to leave no trace of the original filename. + * + * The ISAAC code still bears some resemblance to the code written + * by Bob Jenkins, but he permits pretty unlimited use. + * + * This was inspired by a desire to improve on some code titled: + * Wipe V1.0-- Overwrite and delete files. S. 2/3/96 + * but I've rewritten everything here so completely that no trace of + * the original remains. + * + * Thanks to: + * Bob Jenkins, for his good RNG work and patience with the FSF copyright + * paperwork. + * Jim Meyering, for his work merging this into the GNU fileutils while + * still letting me feel a sense of ownership and pride. Getting me to + * tolerate the GNU brace style was quite a feat of diplomacy. + * Paul Eggert, for lots of useful discussion and code. I disagree with + * an awful lot of his suggestions, but they're disagreements worth having. + * + * Things to think about: + * - Security: Is there any risk to the race + * between overwriting and unlinking a file? Will it do anything + * drastically bad if told to attack a named pipe or socket? + */ + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "shred" + +#define AUTHORS "Colin Plumb" + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include "system.h" +#include "xstrtol.h" +#include "closeout.h" +#include "error.h" +#include "human.h" +#include "inttostr.h" +#include "quotearg.h" /* For quotearg_colon */ +#include "quote.h" /* For quotearg_colon */ + +#ifndef O_NOCTTY +# define O_NOCTTY 0 /* This is a very optional frill */ +#endif + +#define DEFAULT_PASSES 25 /* Default */ + +/* How many seconds to wait before checking whether to output another + verbose output line. */ +#define VERBOSE_UPDATE 5 + +struct Options +{ + int force; /* -f flag: chmod files if necessary */ + size_t n_iterations; /* -n flag: Number of iterations */ + off_t size; /* -s flag: size of file */ + int remove_file; /* -u flag: remove file after shredding */ + int verbose; /* -v flag: Print progress */ + int exact; /* -x flag: Do not round up file size */ + int zero_fill; /* -z flag: Add a final zero pass */ +}; + +static struct option const long_opts[] = +{ + {"exact", no_argument, NULL, 'x'}, + {"force", no_argument, NULL, 'f'}, + {"iterations", required_argument, NULL, 'n'}, + {"size", required_argument, NULL, 's'}, + {"remove", no_argument, NULL, 'u'}, + {"verbose", no_argument, NULL, 'v'}, + {"zero", no_argument, NULL, 'z'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +/* Global variable for error printing purposes */ +char const *program_name; /* Initialized before any possible use */ + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTIONS] FILE [...]\n"), program_name); + fputs (_("\ +Overwrite the specified FILE(s) repeatedly, in order to make it harder\n\ +for even very expensive hardware probing to recover the data.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + printf (_("\ + -f, --force change permissions to allow writing if necessary\n\ + -n, --iterations=N Overwrite N times instead of the default (%d)\n\ + -s, --size=N shred this many bytes (suffixes like K, M, G accepted)\n\ +"), DEFAULT_PASSES); + fputs (_("\ + -u, --remove truncate and remove file after overwriting\n\ + -v, --verbose show progress\n\ + -x, --exact do not round file sizes up to the next full block;\n\ + this is the default for non-regular files\n\ + -z, --zero add a final overwrite with zeros to hide shredding\n\ + - shred standard output\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +Delete FILE(s) if --remove (-u) is specified. The default is not to remove\n\ +the files because it is common to operate on device files like /dev/hda,\n\ +and those files usually should not be removed. When operating on regular\n\ +files, most people use the --remove option.\n\ +\n\ +"), stdout); + fputs (_("\ +CAUTION: Note that shred relies on a very important assumption:\n\ +that the filesystem overwrites data in place. This is the traditional\n\ +way to do things, but many modern filesystem designs do not satisfy this\n\ +assumption. The following are examples of filesystems on which shred is\n\ +not effective:\n\ +\n\ +"), stdout); + fputs (_("\ +* log-structured or journaled filesystems, such as those supplied with\n\ + AIX and Solaris (and JFS, ReiserFS, XFS, Ext3, etc.)\n\ +\n\ +* filesystems that write redundant data and carry on even if some writes\n\ + fail, such as RAID-based filesystems\n\ +\n\ +* filesystems that make snapshots, such as Network Appliance's NFS server\n\ +\n\ +"), stdout); + fputs (_("\ +* filesystems that cache in temporary locations, such as NFS\n\ + version 3 clients\n\ +\n\ +* compressed filesystems\n\ +\n\ +In addition, file system backups and remote mirrors may contain copies\n\ +of the file that cannot be removed, and that will allow a shredded file\n\ +to be recovered later.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +#if ! HAVE_FDATASYNC +# define fdatasync(fd) -1 +#endif + +/* + * -------------------------------------------------------------------- + * Bob Jenkins' cryptographic random number generator, ISAAC. + * Hacked by Colin Plumb. + * + * We need a source of random numbers for some of the overwrite data. + * Cryptographically secure is desirable, but it's not life-or-death + * so I can be a little bit experimental in the choice of RNGs here. + * + * This generator is based somewhat on RC4, but has analysis + * (http://ourworld.compuserve.com/homepages/bob_jenkins/randomnu.htm) + * pointing to it actually being better. I like it because it's nice + * and fast, and because the author did good work analyzing it. + * -------------------------------------------------------------------- + */ + +#if defined __STDC__ && __STDC__ +# define UINT_MAX_32_BITS 4294967295U +#else +# define UINT_MAX_32_BITS 0xFFFFFFFF +#endif + +#if ULONG_MAX == UINT_MAX_32_BITS +typedef unsigned long word32; +#else +# if UINT_MAX == UINT_MAX_32_BITS +typedef unsigned word32; +# else +# if USHRT_MAX == UINT_MAX_32_BITS +typedef unsigned short word32; +# else +# if UCHAR_MAX == UINT_MAX_32_BITS +typedef unsigned char word32; +# else + "No 32-bit type available!" +# endif +# endif +# endif +#endif + +/* Size of the state tables to use. (You may change ISAAC_LOG) */ +#define ISAAC_LOG 8 +#define ISAAC_WORDS (1 << ISAAC_LOG) +#define ISAAC_BYTES (ISAAC_WORDS * sizeof (word32)) + +/* RNG state variables */ +struct isaac_state + { + word32 mm[ISAAC_WORDS]; /* Main state array */ + word32 iv[8]; /* Seeding initial vector */ + word32 a, b, c; /* Extra index variables */ + }; + +/* This index operation is more efficient on many processors */ +#define ind(mm, x) \ + (* (word32 *) ((char *) (mm) + ((x) & (ISAAC_WORDS - 1) * sizeof (word32)))) + +/* + * The central step. This uses two temporaries, x and y. mm is the + * whole state array, while m is a pointer to the current word. off is + * the offset from m to the word ISAAC_WORDS/2 words away in the mm array, + * i.e. +/- ISAAC_WORDS/2. + */ +#define isaac_step(mix, a, b, mm, m, off, r) \ +( \ + a = ((a) ^ (mix)) + (m)[off], \ + x = *(m), \ + *(m) = y = ind (mm, x) + (a) + (b), \ + *(r) = b = ind (mm, (y) >> ISAAC_LOG) + x \ +) + +/* + * Refill the entire R array, and update S. + */ +static void +isaac_refill (struct isaac_state *s, word32 r[/* ISAAC_WORDS */]) +{ + register word32 a, b; /* Caches of a and b */ + register word32 x, y; /* Temps needed by isaac_step macro */ + register word32 *m = s->mm; /* Pointer into state array */ + + a = s->a; + b = s->b + (++s->c); + + do + { + isaac_step (a << 13, a, b, s->mm, m, ISAAC_WORDS / 2, r); + isaac_step (a >> 6, a, b, s->mm, m + 1, ISAAC_WORDS / 2, r + 1); + isaac_step (a << 2, a, b, s->mm, m + 2, ISAAC_WORDS / 2, r + 2); + isaac_step (a >> 16, a, b, s->mm, m + 3, ISAAC_WORDS / 2, r + 3); + r += 4; + } + while ((m += 4) < s->mm + ISAAC_WORDS / 2); + do + { + isaac_step (a << 13, a, b, s->mm, m, -ISAAC_WORDS / 2, r); + isaac_step (a >> 6, a, b, s->mm, m + 1, -ISAAC_WORDS / 2, r + 1); + isaac_step (a << 2, a, b, s->mm, m + 2, -ISAAC_WORDS / 2, r + 2); + isaac_step (a >> 16, a, b, s->mm, m + 3, -ISAAC_WORDS / 2, r + 3); + r += 4; + } + while ((m += 4) < s->mm + ISAAC_WORDS); + s->a = a; + s->b = b; +} + +/* + * The basic seed-scrambling step for initialization, based on Bob + * Jenkins' 256-bit hash. + */ +#define mix(a,b,c,d,e,f,g,h) \ + ( a ^= b << 11, d += a, \ + b += c, b ^= c >> 2, e += b, \ + c += d, c ^= d << 8, f += c, \ + d += e, d ^= e >> 16, g += d, \ + e += f, e ^= f << 10, h += e, \ + f += g, f ^= g >> 4, a += f, \ + g += h, g ^= h << 8, b += g, \ + h += a, h ^= a >> 9, c += h, \ + a += b ) + +/* The basic ISAAC initialization pass. */ +static void +isaac_mix (struct isaac_state *s, word32 const seed[/* ISAAC_WORDS */]) +{ + int i; + word32 a = s->iv[0]; + word32 b = s->iv[1]; + word32 c = s->iv[2]; + word32 d = s->iv[3]; + word32 e = s->iv[4]; + word32 f = s->iv[5]; + word32 g = s->iv[6]; + word32 h = s->iv[7]; + + for (i = 0; i < ISAAC_WORDS; i += 8) + { + a += seed[i]; + b += seed[i + 1]; + c += seed[i + 2]; + d += seed[i + 3]; + e += seed[i + 4]; + f += seed[i + 5]; + g += seed[i + 6]; + h += seed[i + 7]; + + mix (a, b, c, d, e, f, g, h); + + s->mm[i] = a; + s->mm[i + 1] = b; + s->mm[i + 2] = c; + s->mm[i + 3] = d; + s->mm[i + 4] = e; + s->mm[i + 5] = f; + s->mm[i + 6] = g; + s->mm[i + 7] = h; + } + + s->iv[0] = a; + s->iv[1] = b; + s->iv[2] = c; + s->iv[3] = d; + s->iv[4] = e; + s->iv[5] = f; + s->iv[6] = g; + s->iv[7] = h; +} + +#if 0 /* Provided for reference only; not used in this code */ +/* + * Initialize the ISAAC RNG with the given seed material. + * Its size MUST be a multiple of ISAAC_BYTES, and may be + * stored in the s->mm array. + * + * This is a generalization of the original ISAAC initialization code + * to support larger seed sizes. For seed sizes of 0 and ISAAC_BYTES, + * it is identical. + */ +static void +isaac_init (struct isaac_state *s, word32 const *seed, size_t seedsize) +{ + static word32 const iv[8] = + { + 0x1367df5a, 0x95d90059, 0xc3163e4b, 0x0f421ad8, + 0xd92a4a78, 0xa51a3c49, 0xc4efea1b, 0x30609119}; + int i; + +# if 0 + /* The initialization of iv is a precomputed form of: */ + for (i = 0; i < 7; i++) + iv[i] = 0x9e3779b9; /* the golden ratio */ + for (i = 0; i < 4; ++i) /* scramble it */ + mix (iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]); +# endif + s->a = s->b = s->c = 0; + + for (i = 0; i < 8; i++) + s->iv[i] = iv[i]; + + if (seedsize) + { + /* First pass (as in reference ISAAC code) */ + isaac_mix (s, seed); + /* Second and subsequent passes (extension to ISAAC) */ + while (seedsize -= ISAAC_BYTES) + { + seed += ISAAC_WORDS; + for (i = 0; i < ISAAC_WORDS; i++) + s->mm[i] += seed[i]; + isaac_mix (s, s->mm); + } + } + else + { + /* The no seed case (as in reference ISAAC code) */ + for (i = 0; i < ISAAC_WORDS; i++) + s->mm[i] = 0; + } + + /* Final pass */ + isaac_mix (s, s->mm); +} +#endif + +/* Start seeding an ISAAC structire */ +static void +isaac_seed_start (struct isaac_state *s) +{ + static word32 const iv[8] = + { + 0x1367df5a, 0x95d90059, 0xc3163e4b, 0x0f421ad8, + 0xd92a4a78, 0xa51a3c49, 0xc4efea1b, 0x30609119 + }; + int i; + +#if 0 + /* The initialization of iv is a precomputed form of: */ + for (i = 0; i < 7; i++) + iv[i] = 0x9e3779b9; /* the golden ratio */ + for (i = 0; i < 4; ++i) /* scramble it */ + mix (iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]); +#endif + for (i = 0; i < 8; i++) + s->iv[i] = iv[i]; + /* We could initialize s->mm to zero, but why bother? */ + + /* s->c gets used for a data pointer during the seeding phase */ + s->a = s->b = s->c = 0; +} + +/* Add a buffer of seed material */ +static void +isaac_seed_data (struct isaac_state *s, void const *buf, size_t size) +{ + unsigned char *p; + size_t avail; + size_t i; + + avail = sizeof s->mm - (size_t) s->c; /* s->c is used as a write pointer */ + + /* Do any full buffers that are necessary */ + while (size > avail) + { + p = (unsigned char *) s->mm + s->c; + for (i = 0; i < avail; i++) + p[i] ^= ((unsigned char const *) buf)[i]; + buf = (char const *) buf + avail; + size -= avail; + isaac_mix (s, s->mm); + s->c = 0; + avail = sizeof s->mm; + } + + /* And the final partial block */ + p = (unsigned char *) s->mm + s->c; + for (i = 0; i < size; i++) + p[i] ^= ((unsigned char const *) buf)[i]; + s->c = (word32) size; +} + + +/* End of seeding phase; get everything ready to produce output. */ +static void +isaac_seed_finish (struct isaac_state *s) +{ + isaac_mix (s, s->mm); + isaac_mix (s, s->mm); + /* Now reinitialize c to start things off right */ + s->c = 0; +} +#define ISAAC_SEED(s,x) isaac_seed_data (s, &(x), sizeof (x)) + + +#if __GNUC__ >= 2 && (__i386__ || __alpha__) +/* + * Many processors have very-high-resolution timer registers, + * The timer registers can be made inaccessible, so we have to deal with the + * possibility of SIGILL while we're working. + */ +static jmp_buf env; +static RETSIGTYPE +sigill_handler (int signum) +{ + (void) signum; + longjmp (env, 1); /* Trivial, just return an indication that it happened */ +} + +/* FIXME: find a better way. + This signal-handling code may well end up being ripped out eventually. + An example of how fragile it is, on an i586-sco-sysv5uw7.0.1 system, with + gcc-2.95.3pl1, the "rdtsc" instruction causes a segmentation violation. + So now, the code catches SIGSEGV. It'd probably be better to remove all + of that mess and find a better source of random data. Patches welcome. */ + +static void +isaac_seed_machdep (struct isaac_state *s) +{ + RETSIGTYPE (*old_handler[2]) (int); + + /* This is how one does try/except in C */ + old_handler[0] = signal (SIGILL, sigill_handler); + old_handler[1] = signal (SIGSEGV, sigill_handler); + if (setjmp (env)) /* ANSI: Must be entire controlling expression */ + { + signal (SIGILL, old_handler[0]); + signal (SIGSEGV, old_handler[1]); + } + else + { +# if __i386__ + word32 t[2]; + __asm__ __volatile__ ("rdtsc" : "=a" (t[0]), "=d" (t[1])); +# endif +# if __alpha__ + unsigned long t; + __asm__ __volatile__ ("rpcc %0" : "=r" (t)); +# endif +# if _ARCH_PPC + /* Code not used because this instruction is available only on first- + generation PPCs and evokes a SIGBUS on some Linux 2.4 kernels. */ + word32 t; + __asm__ __volatile__ ("mfspr %0,22" : "=r" (t)); +# endif +# if __mips + /* Code not used because this is not accessible from userland */ + word32 t; + __asm__ __volatile__ ("mfc0\t%0,$9" : "=r" (t)); +# endif +# if __sparc__ + /* This doesn't compile on all platforms yet. How to fix? */ + unsigned long t; + __asm__ __volatile__ ("rd %%tick, %0" : "=r" (t)); +# endif + signal (SIGILL, old_handler[0]); + signal (SIGSEGV, old_handler[1]); + isaac_seed_data (s, &t, sizeof t); + } +} + +#else /* !(__i386__ || __alpha__) */ + +/* Do-nothing stub */ +# define isaac_seed_machdep(s) (void) 0 + +#endif /* !(__i386__ || __alpha__) */ + + +/* + * Get seed material. 16 bytes (128 bits) is plenty, but if we have + * /dev/urandom, we get 32 bytes = 256 bits for complete overkill. + */ +static void +isaac_seed (struct isaac_state *s) +{ + isaac_seed_start (s); + + { pid_t t = getpid (); ISAAC_SEED (s, t); } + { pid_t t = getppid (); ISAAC_SEED (s, t); } + { uid_t t = getuid (); ISAAC_SEED (s, t); } + { gid_t t = getgid (); ISAAC_SEED (s, t); } + + { +#if HAVE_GETHRTIME + hrtime_t t = gethrtime (); + ISAAC_SEED (s, t); +#else +# if HAVE_CLOCK_GETTIME /* POSIX ns-resolution */ + struct timespec t; + clock_gettime (CLOCK_REALTIME, &t); +# else +# if HAVE_GETTIMEOFDAY + struct timeval t; + gettimeofday (&t, (struct timezone *) 0); +# else + time_t t; + t = time (NULL); +# endif +# endif +#endif + ISAAC_SEED (s, t); + } + + isaac_seed_machdep (s); + + { + char buf[32]; + int fd = open ("/dev/urandom", O_RDONLY | O_NOCTTY); + if (fd >= 0) + { + read (fd, buf, 32); + close (fd); + isaac_seed_data (s, buf, 32); + } + else + { + fd = open ("/dev/random", O_RDONLY | O_NONBLOCK | O_NOCTTY); + if (fd >= 0) + { + /* /dev/random is more precious, so use less */ + read (fd, buf, 16); + close (fd); + isaac_seed_data (s, buf, 16); + } + } + } + + isaac_seed_finish (s); +} + +/* Single-word RNG built on top of ISAAC */ +struct irand_state +{ + word32 r[ISAAC_WORDS]; + unsigned numleft; + struct isaac_state *s; +}; + +static void +irand_init (struct irand_state *r, struct isaac_state *s) +{ + r->numleft = 0; + r->s = s; +} + +/* + * We take from the end of the block deliberately, so if we need + * only a small number of values, we choose the final ones which are + * marginally better mixed than the initial ones. + */ +static word32 +irand32 (struct irand_state *r) +{ + if (!r->numleft) + { + isaac_refill (r->s, r->r); + r->numleft = ISAAC_WORDS; + } + return r->r[--r->numleft]; +} + +/* + * Return a uniformly distributed random number between 0 and n, + * inclusive. Thus, the result is modulo n+1. + * + * Theory of operation: as x steps through every possible 32-bit number, + * x % n takes each value at least 2^32 / n times (rounded down), but + * the values less than 2^32 % n are taken one additional time. Thus, + * x % n is not perfectly uniform. To fix this, the values of x less + * than 2^32 % n are disallowed, and if the RNG produces one, we ask + * for a new value. + */ +static word32 +irand_mod (struct irand_state *r, word32 n) +{ + word32 x; + word32 lim; + + if (!++n) + return irand32 (r); + + lim = -n % n; /* == (2**32-n) % n == 2**32 % n */ + do + { + x = irand32 (r); + } + while (x < lim); + return x % n; +} + +/* + * Fill a buffer with a fixed pattern. + * + * The buffer must be at least 3 bytes long, even if + * size is less. Larger sizes are filled exactly. + */ +static void +fillpattern (int type, unsigned char *r, size_t size) +{ + size_t i; + unsigned bits = type & 0xfff; + + bits |= bits << 12; + ((unsigned char *) r)[0] = (bits >> 4) & 255; + ((unsigned char *) r)[1] = (bits >> 8) & 255; + ((unsigned char *) r)[2] = bits & 255; + for (i = 3; i < size / 2; i *= 2) + memcpy ((char *) r + i, (char *) r, i); + if (i < size) + memcpy ((char *) r + i, (char *) r, size - i); + + /* Invert the first bit of every 512-byte sector. */ + if (type & 0x1000) + for (i = 0; i < size; i += 512) + r[i] ^= 0x80; +} + +/* + * Fill a buffer, R (of size SIZE_MAX), with random data. + * SIZE is rounded UP to a multiple of ISAAC_BYTES. + */ +static void +fillrand (struct isaac_state *s, word32 *r, size_t size_max, size_t size) +{ + size = (size + ISAAC_BYTES - 1) / ISAAC_BYTES; + assert (size <= size_max); + + while (size--) + { + isaac_refill (s, r); + r += ISAAC_WORDS; + } +} + +/* + * Generate a 6-character (+ nul) pass name string + * FIXME: allow translation of "random". + */ +#define PASS_NAME_SIZE 7 +static void +passname (unsigned char const *data, char name[PASS_NAME_SIZE]) +{ + if (data) + sprintf (name, "%02x%02x%02x", data[0], data[1], data[2]); + else + memcpy (name, "random", PASS_NAME_SIZE); +} + +/* + * Do pass number k of n, writing "size" bytes of the given pattern "type" + * to the file descriptor fd. Qname, k and n are passed in only for verbose + * progress message purposes. If n == 0, no progress messages are printed. + * + * If *sizep == -1, the size is unknown, and it will be filled in as soon + * as writing fails. + */ +static int +dopass (int fd, char const *qname, off_t *sizep, int type, + struct isaac_state *s, unsigned long k, unsigned long n) +{ + off_t size = *sizep; + off_t offset; /* Current file posiiton */ + time_t thresh IF_LINT (= 0); /* Time to maybe print next status update */ + time_t now = 0; /* Current time */ + size_t lim; /* Amount of data to try writing */ + size_t soff; /* Offset into buffer for next write */ + ssize_t ssize; /* Return value from write */ +#if ISAAC_WORDS > 1024 + word32 r[ISAAC_WORDS * 3]; /* Multiple of 4K and of pattern size */ +#else + word32 r[1024 * 3]; /* Multiple of 4K and of pattern size */ +#endif + char pass_string[PASS_NAME_SIZE]; /* Name of current pass */ + + /* Printable previous offset into the file */ + char previous_offset_buf[LONGEST_HUMAN_READABLE + 1]; + char const *previous_human_offset IF_LINT (= 0); + + if (lseek (fd, (off_t) 0, SEEK_SET) == -1) + { + error (0, errno, _("%s: cannot rewind"), qname); + return -1; + } + + /* Constant fill patterns need only be set up once. */ + if (type >= 0) + { + lim = sizeof r; + if ((off_t) lim > size && size != -1) + { + lim = (size_t) size; + } + fillpattern (type, (unsigned char *) r, lim); + passname ((unsigned char *) r, pass_string); + } + else + { + passname (0, pass_string); + } + + /* Set position if first status update */ + if (n) + { + error (0, 0, _("%s: pass %lu/%lu (%s)..."), qname, k, n, pass_string); + thresh = time (NULL) + VERBOSE_UPDATE; + previous_human_offset = ""; + } + + offset = 0; + for (;;) + { + /* How much to write this time? */ + lim = sizeof r; + if ((off_t) lim > size - offset && size != -1) + { + if (size < offset) + break; + lim = (size_t) (size - offset); + if (!lim) + break; + } + if (type < 0) + fillrand (s, r, sizeof r, lim); + /* Loop to retry partial writes. */ + for (soff = 0; soff < lim; soff += ssize) + { + ssize = write (fd, (char *) r + soff, lim - soff); + if (ssize <= 0) + { + if ((ssize == 0 || errno == ENOSPC) + && size == -1) + { + /* Ah, we have found the end of the file */ + *sizep = size = offset + soff; + break; + } + else + { + int errnum = errno; + char buf[INT_BUFSIZE_BOUND (uintmax_t)]; + error (0, errnum, _("%s: error writing at offset %s"), + qname, umaxtostr ((uintmax_t) offset + soff, buf)); + /* + * I sometimes use shred on bad media, before throwing it + * out. Thus, I don't want it to give up on bad blocks. + * This code assumes 512-byte blocks and tries to skip + * over them. It works because lim is always a multiple + * of 512, except at the end. + */ + if (errnum == EIO && soff % 512 == 0 && lim >= soff + 512 + && size != -1) + { + if (lseek (fd, (off_t) (offset + soff + 512), SEEK_SET) + != -1) + { + soff += 512; + continue; + } + error (0, errno, "%s: lseek", qname); + } + return -1; + } + } + } + + /* Okay, we have written "soff" bytes. */ + + if (offset + soff < offset) + { + error (0, 0, _("%s: file too large"), qname); + return -1; + } + + offset += soff; + + /* Time to print progress? */ + if (n + && ((offset == size && *previous_human_offset) + || thresh <= (now = time (NULL)))) + { + char offset_buf[LONGEST_HUMAN_READABLE + 1]; + char size_buf[LONGEST_HUMAN_READABLE + 1]; + int human_progress_opts = (human_autoscale | human_SI + | human_base_1024 | human_B); + char const *human_offset + = human_readable (offset, offset_buf, + human_floor | human_progress_opts, 1, 1); + + if (offset == size + || !STREQ (previous_human_offset, human_offset)) + { + if (size == -1) + error (0, 0, _("%s: pass %lu/%lu (%s)...%s"), + qname, k, n, pass_string, human_offset); + else + { + uintmax_t off = offset; + int percent = (size == 0 + ? 100 + : (off <= TYPE_MAXIMUM (uintmax_t) / 100 + ? off * 100 / size + : off / (size / 100))); + char const *human_size + = human_readable (size, size_buf, + human_ceiling | human_progress_opts, + 1, 1); + if (offset == size) + human_offset = human_size; + error (0, 0, _("%s: pass %lu/%lu (%s)...%s/%s %d%%"), + qname, k, n, pass_string, human_offset, human_size, + percent); + } + + strcpy (previous_offset_buf, human_offset); + previous_human_offset = previous_offset_buf; + thresh = now + VERBOSE_UPDATE; + + /* + * Force periodic syncs to keep displayed progress accurate + * FIXME: Should these be present even if -v is not enabled, + * to keep the buffer cache from filling with dirty pages? + * It's a common problem with programs that do lots of writes, + * like mkfs. + */ + if (fdatasync (fd) < 0 && fsync (fd) < 0) + { + error (0, errno, "%s: fsync", qname); + return -1; + } + } + } + } + + /* Force what we just wrote to hit the media. */ + if (fdatasync (fd) < 0 && fsync (fd) < 0) + { + error (0, errno, "%s: fsync", qname); + return -1; + } + return 0; +} + +/* + * The passes start and end with a random pass, and the passes in between + * are done in random order. The idea is to deprive someone trying to + * reverse the process of knowledge of the overwrite patterns, so they + * have the additional step of figuring out what was done to the disk + * before they can try to reverse or cancel it. + * + * First, all possible 1-bit patterns. There are two of them. + * Then, all possible 2-bit patterns. There are four, but the two + * which are also 1-bit patterns can be omitted. + * Then, all possible 3-bit patterns. Likewise, 8-2 = 6. + * Then, all possible 4-bit patterns. 16-4 = 12. + * + * The basic passes are: + * 1-bit: 0x000, 0xFFF + * 2-bit: 0x555, 0xAAA + * 3-bit: 0x249, 0x492, 0x924, 0x6DB, 0xB6D, 0xDB6 (+ 1-bit) + * 100100100100 110110110110 + * 9 2 4 D B 6 + * 4-bit: 0x111, 0x222, 0x333, 0x444, 0x666, 0x777, + * 0x888, 0x999, 0xBBB, 0xCCC, 0xDDD, 0xEEE (+ 1-bit, 2-bit) + * Adding three random passes at the beginning, middle and end + * produces the default 25-pass structure. + * + * The next extension would be to 5-bit and 6-bit patterns. + * There are 30 uncovered 5-bit patterns and 64-8-2 = 46 uncovered + * 6-bit patterns, so they would increase the time required + * significantly. 4-bit patterns are enough for most purposes. + * + * The main gotcha is that this would require a trickier encoding, + * since lcm(2,3,4) = 12 bits is easy to fit into an int, but + * lcm(2,3,4,5) = 60 bits is not. + * + * One extension that is included is to complement the first bit in each + * 512-byte block, to alter the phase of the encoded data in the more + * complex encodings. This doesn't apply to MFM, so the 1-bit patterns + * are considered part of the 3-bit ones and the 2-bit patterns are + * considered part of the 4-bit patterns. + * + * + * How does the generalization to variable numbers of passes work? + * + * Here's how... + * Have an ordered list of groups of passes. Each group is a set. + * Take as many groups as will fit, plus a random subset of the + * last partial group, and place them into the passes list. + * Then shuffle the passes list into random order and use that. + * + * One extra detail: if we can't include a large enough fraction of the + * last group to be interesting, then just substitute random passes. + * + * If you want more passes than the entire list of groups can + * provide, just start repeating from the beginning of the list. + */ +static int const + patterns[] = +{ + -2, /* 2 random passes */ + 2, 0x000, 0xFFF, /* 1-bit */ + 2, 0x555, 0xAAA, /* 2-bit */ + -1, /* 1 random pass */ + 6, 0x249, 0x492, 0x6DB, 0x924, 0xB6D, 0xDB6, /* 3-bit */ + 12, 0x111, 0x222, 0x333, 0x444, 0x666, 0x777, + 0x888, 0x999, 0xBBB, 0xCCC, 0xDDD, 0xEEE, /* 4-bit */ + -1, /* 1 random pass */ + /* The following patterns have the frst bit per block flipped */ + 8, 0x1000, 0x1249, 0x1492, 0x16DB, 0x1924, 0x1B6D, 0x1DB6, 0x1FFF, + 14, 0x1111, 0x1222, 0x1333, 0x1444, 0x1555, 0x1666, 0x1777, + 0x1888, 0x1999, 0x1AAA, 0x1BBB, 0x1CCC, 0x1DDD, 0x1EEE, + -1, /* 1 random pass */ + 0 /* End */ +}; + +/* + * Generate a random wiping pass pattern with num passes. + * This is a two-stage process. First, the passes to include + * are chosen, and then they are shuffled into the desired + * order. + */ +static void +genpattern (int *dest, size_t num, struct isaac_state *s) +{ + struct irand_state r; + size_t randpasses; + int const *p; + int *d; + size_t n; + size_t accum, top, swap; + int k; + + if (!num) + return; + + irand_init (&r, s); + + /* Stage 1: choose the passes to use */ + p = patterns; + randpasses = 0; + d = dest; /* Destination for generated pass list */ + n = num; /* Passes remaining to fill */ + + for (;;) + { + k = *p++; /* Block descriptor word */ + if (!k) + { /* Loop back to the beginning */ + p = patterns; + } + else if (k < 0) + { /* -k random passes */ + k = -k; + if ((size_t) k >= n) + { + randpasses += n; + n = 0; + break; + } + randpasses += k; + n -= k; + } + else if ((size_t) k <= n) + { /* Full block of patterns */ + memcpy (d, p, k * sizeof (int)); + p += k; + d += k; + n -= k; + } + else if (n < 2 || 3 * n < (size_t) k) + { /* Finish with random */ + randpasses += n; + break; + } + else + { /* Pad out with k of the n available */ + do + { + if (n == (size_t) k-- || irand_mod (&r, k) < n) + { + *d++ = *p; + n--; + } + p++; + } + while (n); + break; + } + } + top = num - randpasses; /* Top of initialized data */ + /* assert (d == dest+top); */ + + /* + * We now have fixed patterns in the dest buffer up to + * "top", and we need to scramble them, with "randpasses" + * random passes evenly spaced among them. + * + * We want one at the beginning, one at the end, and + * evenly spaced in between. To do this, we basically + * use Bresenham's line draw (a.k.a DDA) algorithm + * to draw a line with slope (randpasses-1)/(num-1). + * (We use a positive accumulator and count down to + * do this.) + * + * So for each desired output value, we do the following: + * - If it should be a random pass, copy the pass type + * to top++, out of the way of the other passes, and + * set the current pass to -1 (random). + * - If it should be a normal pattern pass, choose an + * entry at random between here and top-1 (inclusive) + * and swap the current entry with that one. + */ + randpasses--; /* To speed up later math */ + accum = randpasses; /* Bresenham DDA accumulator */ + for (n = 0; n < num; n++) + { + if (accum <= randpasses) + { + accum += num - 1; + dest[top++] = dest[n]; + dest[n] = -1; + } + else + { + swap = n + irand_mod (&r, top - n - 1); + k = dest[n]; + dest[n] = dest[swap]; + dest[swap] = k; + } + accum -= randpasses; + } + /* assert (top == num); */ + + memset (&r, 0, sizeof r); /* Wipe this on general principles */ +} + +/* + * The core routine to actually do the work. This overwrites the first + * size bytes of the given fd. Returns -1 on error, 0 on success. + */ +static int +do_wipefd (int fd, char const *qname, struct isaac_state *s, + struct Options const *flags) +{ + size_t i; + struct stat st; + off_t size; /* Size to write, size to read */ + unsigned long n; /* Number of passes for printing purposes */ + int *passarray; + + n = 0; /* dopass takes n -- 0 to mean "don't print progress" */ + if (flags->verbose) + n = flags->n_iterations + ((flags->zero_fill) != 0); + + if (fstat (fd, &st)) + { + error (0, errno, "%s: fstat", qname); + return -1; + } + + /* If we know that we can't possibly shred the file, give up now. + Otherwise, we may go into a infinite loop writing data before we + find that we can't rewind the device. */ + if ((S_ISCHR (st.st_mode) && isatty (fd)) + || S_ISFIFO (st.st_mode) + || S_ISSOCK (st.st_mode)) + { + error (0, 0, _("%s: invalid file type"), qname); + return -1; + } + + /* Allocate pass array */ + passarray = xmalloc (flags->n_iterations * sizeof (int)); + + size = flags->size; + if (size == -1) + { + /* Accept a length of zero only if it's a regular file. + For any other type of file, try to get the size another way. */ + if (S_ISREG (st.st_mode)) + { + size = st.st_size; + if (size < 0) + { + error (0, 0, _("%s: file has negative size"), qname); + return -1; + } + } + else + { + size = lseek (fd, (off_t) 0, SEEK_END); + if (size <= 0) + { + /* We are unable to determine the length, up front. + Let dopass do that as part of its first iteration. */ + size = -1; + } + } + + /* Allow `rounding up' only for regular files. */ + if (0 <= size && !(flags->exact) && S_ISREG (st.st_mode)) + { + size += ST_BLKSIZE (st) - 1 - (size - 1) % ST_BLKSIZE (st); + + /* If in rounding up, we've just overflowed, use the maximum. */ + if (size < 0) + size = TYPE_MAXIMUM (off_t); + } + } + + /* Schedule the passes in random order. */ + genpattern (passarray, flags->n_iterations, s); + + /* Do the work */ + for (i = 0; i < flags->n_iterations; i++) + { + if (dopass (fd, qname, &size, passarray[i], s, i + 1, n) < 0) + { + memset (passarray, 0, flags->n_iterations * sizeof (int)); + free (passarray); + return -1; + } + } + + memset (passarray, 0, flags->n_iterations * sizeof (int)); + free (passarray); + + if (flags->zero_fill) + if (dopass (fd, qname, &size, 0, s, flags->n_iterations + 1, n) < 0) + return -1; + + /* Okay, now deallocate the data. The effect of ftruncate on + non-regular files is unspecified, so don't worry about any + errors reported for them. */ + if (flags->remove_file && ftruncate (fd, (off_t) 0) != 0 + && S_ISREG (st.st_mode)) + { + error (0, errno, _("%s: error truncating"), qname); + return -1; + } + + return 0; +} + +/* A wrapper with a little more checking for fds on the command line */ +static int +wipefd (int fd, char const *qname, struct isaac_state *s, + struct Options const *flags) +{ + int fd_flags = fcntl (fd, F_GETFL); + + if (fd_flags < 0) + { + error (0, errno, "%s: fcntl", qname); + return -1; + } + if (fd_flags & O_APPEND) + { + error (0, 0, _("%s: cannot shred append-only file descriptor"), qname); + return -1; + } + return do_wipefd (fd, qname, s, flags); +} + +/* --- Name-wiping code --- */ + +/* Characters allowed in a file name - a safe universal set. */ +static char const nameset[] = +"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_+=%@#."; + +/* + * This increments the name, considering it as a big-endian base-N number + * with the digits taken from nameset. Characters not in the nameset + * are considered to come before nameset[0]. + * + * It's not obvious, but this will explode if name[0..len-1] contains + * any 0 bytes. + * + * This returns the carry (1 on overflow). + */ +static int +incname (char *name, unsigned len) +{ + char const *p; + + if (!len) + return 1; + + p = strchr (nameset, name[--len]); + /* If the character is not found, replace it with a 0 digit */ + if (!p) + { + name[len] = nameset[0]; + return 0; + } + /* If this character has a successor, use it */ + if (p[1]) + { + name[len] = p[1]; + return 0; + } + /* Otherwise, set this digit to 0 and increment the prefix */ + name[len] = nameset[0]; + return incname (name, len); +} + +/* + * Repeatedly rename a file with shorter and shorter names, + * to obliterate all traces of the file name on any system that + * adds a trailing delimiter to on-disk file names and reuses + * the same directory slot. Finally, unlink it. + * The passed-in filename is modified in place to the new filename. + * (Which is unlinked if this function succeeds, but is still present if + * it fails for some reason.) + * + * The main loop is written carefully to not get stuck if all possible + * names of a given length are occupied. It counts down the length from + * the original to 0. While the length is non-zero, it tries to find an + * unused file name of the given length. It continues until either the + * name is available and the rename succeeds, or it runs out of names + * to try (incname wraps and returns 1). Finally, it unlinks the file. + * + * The unlink is Unix-specific, as ANSI-standard remove has more + * portability problems with C libraries making it "safe". rename + * is ANSI-standard. + * + * To force the directory data out, we try to open the directory and + * invoke fdatasync on it. This is rather non-standard, so we don't + * insist that it works, just fall back to a global sync in that case. + * This is fairly significantly Unix-specific. Of course, on any + * filesystem with synchronous metadata updates, this is unnecessary. + */ +static int +wipename (char *oldname, char const *qoldname, struct Options const *flags) +{ + char *newname, *base; /* Base points to filename part of newname */ + unsigned len; + int first = 1; + int err; + int dir_fd; /* Try to open directory to sync *it* */ + + newname = xstrdup (oldname); + if (flags->verbose) + error (0, 0, _("%s: removing"), qoldname); + + /* Find the file name portion */ + base = strrchr (newname, '/'); + /* Temporary hackery to get a directory fd */ + if (base) + { + *base = '\0'; + dir_fd = open (newname, O_RDONLY | O_NOCTTY); + *base = '/'; + } + else + { + dir_fd = open (".", O_RDONLY | O_NOCTTY); + } + base = base ? base + 1 : newname; + len = strlen (base); + + while (len) + { + memset (base, nameset[0], len); + base[len] = 0; + do + { + struct stat st; + if (lstat (newname, &st) < 0) + { + if (rename (oldname, newname) == 0) + { + if (dir_fd < 0 + || (fdatasync (dir_fd) < 0 && fsync (dir_fd) < 0)) + sync (); /* Force directory out */ + if (flags->verbose) + { + /* + * People seem to understand this better than talking + * about renaming oldname. newname doesn't need + * quoting because we picked it. oldname needs to + * be quoted only the first time. + */ + char const *old = (first ? qoldname : oldname); + error (0, 0, _("%s: renamed to %s"), old, newname); + first = 0; + } + memcpy (oldname + (base - newname), base, len + 1); + break; + } + else + { + /* The rename failed: give up on this length. */ + break; + } + } + else + { + /* newname exists, so increment BASE so we use another */ + } + } + while (!incname (base, len)); + len--; + } + free (newname); + err = unlink (oldname); + if (dir_fd < 0 || (fdatasync (dir_fd) < 0 && fsync (dir_fd) < 0)) + sync (); + close (dir_fd); + if (!err && flags->verbose) + error (0, 0, _("%s: removed"), qoldname); + return err; +} + +/* + * Finally, the function that actually takes a filename and grinds + * it into hamburger. + * + * FIXME + * Detail to note: since we do not restore errno to EACCES after + * a failed chmod, we end up printing the error code from the chmod. + * This is actually the error that stopped us from proceeding, so + * it's arguably the right one, and in practice it'll be either EACCES + * again or EPERM, which both give similar error messages. + * Does anyone disagree? + */ +static int +wipefile (char *name, char const *qname, + struct isaac_state *s, struct Options const *flags) +{ + int err, fd; + + fd = open (name, O_WRONLY | O_NOCTTY); + if (fd < 0) + { + if (errno == EACCES && flags->force) + { + if (chmod (name, S_IWUSR) >= 0) /* 0200, user-write-only */ + fd = open (name, O_WRONLY | O_NOCTTY); + } + else if ((errno == ENOENT || errno == ENOTDIR) + && strncmp (name, "/dev/fd/", 8) == 0) + { + /* We accept /dev/fd/# even if the OS doesn't support it */ + int errnum = errno; + unsigned long num; + char *p; + errno = 0; + num = strtoul (name + 8, &p, 10); + /* If it's completely decimal with no leading zeros... */ + if (errno == 0 && !*p && num <= INT_MAX && + (('1' <= name[8] && name[8] <= '9') + || (name[8] == '0' && !name[9]))) + { + return wipefd ((int) num, qname, s, flags); + } + errno = errnum; + } + } + if (fd < 0) + { + error (0, errno, "%s", qname); + return -1; + } + + err = do_wipefd (fd, qname, s, flags); + if (close (fd) != 0) + { + error (0, 0, "%s: close", qname); + err = -1; + } + if (err == 0 && flags->remove_file) + { + err = wipename (name, qname, flags); + if (err < 0) + error (0, 0, _("%s: cannot remove"), qname); + } + return err; +} + +int +main (int argc, char **argv) +{ + struct isaac_state s; + int err = 0; + struct Options flags; + char **file; + int n_files; + int c; + int i; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + isaac_seed (&s); + + memset (&flags, 0, sizeof flags); + + flags.n_iterations = DEFAULT_PASSES; + flags.size = -1; + + while ((c = getopt_long (argc, argv, "fn:s:uvxz", long_opts, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + case 'f': + flags.force = 1; + break; + + case 'n': + { + uintmax_t tmp; + if (xstrtoumax (optarg, NULL, 10, &tmp, NULL) != LONGINT_OK + || (word32) tmp != tmp + || ((size_t) (tmp * sizeof (int)) / sizeof (int) != tmp)) + { + error (EXIT_FAILURE, 0, _("%s: invalid number of passes"), + quotearg_colon (optarg)); + } + flags.n_iterations = (size_t) tmp; + } + break; + + case 'u': + flags.remove_file = 1; + break; + + case 's': + { + uintmax_t tmp; + if (xstrtoumax (optarg, NULL, 0, &tmp, "cbBkKMGTPEZY0") + != LONGINT_OK) + { + error (EXIT_FAILURE, 0, _("%s: invalid file size"), + quotearg_colon (optarg)); + } + flags.size = tmp; + } + break; + + case 'v': + flags.verbose = 1; + break; + + case 'x': + flags.exact = 1; + break; + + case 'z': + flags.zero_fill = 1; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + file = argv + optind; + n_files = argc - optind; + + if (n_files == 0) + { + error (0, 0, _("missing file argument")); + usage (EXIT_FAILURE); + } + + for (i = 0; i < n_files; i++) + { + char *qname = xstrdup (quotearg_colon (file[i])); + if (STREQ (file[i], "-")) + { + if (wipefd (STDOUT_FILENO, qname, &s, &flags) < 0) + err = 1; + } + else + { + /* Plain filename - Note that this overwrites *argv! */ + if (wipefile (file[i], qname, &s, &flags) < 0) + err = 1; + } + free (qname); + } + + /* Just on general principles, wipe s. */ + memset (&s, 0, sizeof s); + + exit (err); +} +/* + * vim:sw=2:sts=2: + */ diff --git a/src/apps/bin/coreutils-5.0/src/sleep.c b/src/apps/bin/coreutils-5.0/src/sleep.c new file mode 100644 index 0000000000..f8a818692e --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/sleep.c @@ -0,0 +1,169 @@ +/* sleep - delay for a specified amount of time. + Copyright (C) 84, 1991-1997, 1999-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "long-options.h" +#include "xnanosleep.h" +#include "xstrtod.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "sleep" + +#define AUTHORS N_ ("Jim Meyering and Paul Eggert") + +/* The name by which this program was run. */ +char *program_name; + +static struct option const long_options[] = +{ + {0, 0, 0, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s NUMBER[SUFFIX]...\n\ + or: %s OPTION\n\ +Pause for NUMBER seconds. SUFFIX may be `s' for seconds (the default),\n\ +`m' for minutes, `h' for hours or `d' for days. Unlike most implementations\n\ +that require NUMBER be an integer, here NUMBER may be an arbitrary floating\n\ +point number.\n\ +\n\ +"), + program_name, program_name); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +/* Given a floating point value *X, and a suffix character, SUFFIX_CHAR, + scale *X by the multiplier implied by SUFFIX_CHAR. SUFFIX_CHAR may + be the NUL byte or `s' to denote seconds, `m' for minutes, `h' for + hours, or `d' for days. If SUFFIX_CHAR is invalid, don't modify *X + and return nonzero. Otherwise return zero. */ + +static int +apply_suffix (double *x, char suffix_char) +{ + unsigned int multiplier; + + switch (suffix_char) + { + case 0: + case 's': + multiplier = 1; + break; + case 'm': + multiplier = 60; + break; + case 'h': + multiplier = 60 * 60; + break; + case 'd': + multiplier = 60 * 60 * 24; + break; + default: + multiplier = 0; + } + + if (multiplier == 0) + return 1; + + *x *= multiplier; + + return 0; +} + +int +main (int argc, char **argv) +{ + int i; + double seconds = 0.0; + int c; + int fail = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + default: + usage (EXIT_FAILURE); + } + } + + if (argc == 1) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + for (i = optind; i < argc; i++) + { + double s; + const char *p; + if (xstrtod (argv[i], &p, &s) + /* Nonnegative interval. */ + || ! (0 <= s) + /* No extra chars after the number and an optional s,m,h,d char. */ + || (*p && *(p+1)) + /* Check any suffix char and update S based on the suffix. */ + || apply_suffix (&s, *p)) + { + error (0, 0, _("invalid time interval `%s'"), argv[i]); + fail = 1; + } + + seconds += s; + } + + if (fail) + usage (EXIT_FAILURE); + + if (xnanosleep (seconds)) + error (EXIT_FAILURE, errno, _("cannot read realtime clock")); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/sort.c b/src/apps/bin/coreutils-5.0/src/sort.c new file mode 100644 index 0000000000..8da19dfd36 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/sort.c @@ -0,0 +1,2496 @@ +/* sort - sort lines of text (with all kinds of options). + Copyright (C) 88, 1991-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Written December 1988 by Mike Haertel. + The author may be reached (Email) at the address mike@gnu.ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. + + Ørn E. Hansen added NLS support in 1997. */ + +#include + +#include +#include +#include +#include +#include +#include "system.h" +#include "long-options.h" +#include "error.h" +#include "hard-locale.h" +#include "inttostr.h" +#include "physmem.h" +#include "posixver.h" +#include "stdio-safer.h" +#include "xmemcoll.h" +#include "xstrtol.h" + +#if HAVE_SYS_RESOURCE_H +# include +#endif +# define getrlimit(Resource, Rlp) (-1) + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "sort" + +#define AUTHORS N_ ("Mike Haertel and Paul Eggert") + +#if HAVE_LANGINFO_CODESET +# include +#endif + +#ifndef SA_NOCLDSTOP +# define sigprocmask(How, Set, Oset) /* empty */ +# define sigset_t int +#endif + +#ifndef STDC_HEADERS +double strtod (); +#endif + +/* Undefine, to avoid warning about redefinition on some systems. */ +/* FIXME: Remove these: use MIN/MAX from sys2.h. */ +#undef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#undef max +#define max(a, b) ((a) > (b) ? (a) : (b)) + +#define UCHAR_LIM (UCHAR_MAX + 1) +#define UCHAR(c) ((unsigned char) (c)) + +#ifndef DEFAULT_TMPDIR +# define DEFAULT_TMPDIR "/tmp" +#endif + +/* Use this as exit status in case of error, not EXIT_FAILURE. This + is necessary because EXIT_FAILURE is usually 1 and POSIX requires + that sort exit with status 1 IFF invoked with -c and the input is + not properly sorted. Any other irregular exit must exit with a + status code greater than 1. */ +#define SORT_FAILURE 2 +#define SORT_OUT_OF_ORDER 1 + +#define C_DECIMAL_POINT '.' +#define NEGATION_SIGN '-' +#define NUMERIC_ZERO '0' + +#if HAVE_SETLOCALE + +static char decimal_point; +static int th_sep; /* if CHAR_MAX + 1, then there is no thousands separator */ + +/* Nonzero if the corresponding locales are hard. */ +static int hard_LC_COLLATE; +# if HAVE_NL_LANGINFO +static int hard_LC_TIME; +# endif + +# define IS_THOUSANDS_SEP(x) ((x) == th_sep) + +#else + +# define decimal_point C_DECIMAL_POINT +# define IS_THOUSANDS_SEP(x) 0 + +#endif + +#define NONZERO(x) (x != 0) + +/* The kind of blanks for '-b' to skip in various options. */ +enum blanktype { bl_start, bl_end, bl_both }; + +/* The character marking end of line. Default to \n. */ +static int eolchar = '\n'; + +/* Lines are held in core as counted strings. */ +struct line +{ + char *text; /* Text of the line. */ + size_t length; /* Length including final newline. */ + char *keybeg; /* Start of first key. */ + char *keylim; /* Limit of first key. */ +}; + +/* Input buffers. */ +struct buffer +{ + char *buf; /* Dynamically allocated buffer, + partitioned into 3 regions: + - input data; + - unused area; + - an array of lines, in reverse order. */ + size_t used; /* Number of bytes used for input data. */ + size_t nlines; /* Number of lines in the line array. */ + size_t alloc; /* Number of bytes allocated. */ + size_t left; /* Number of bytes left from previous reads. */ + size_t line_bytes; /* Number of bytes to reserve for each line. */ + int eof; /* An EOF has been read. */ +}; + +struct keyfield +{ + size_t sword; /* Zero-origin 'word' to start at. */ + size_t schar; /* Additional characters to skip. */ + int skipsblanks; /* Skip leading white space at start. */ + size_t eword; /* Zero-origin first word after field. */ + size_t echar; /* Additional characters in field. */ + int skipeblanks; /* Skip trailing white space at finish. */ + int *ignore; /* Boolean array of characters to ignore. */ + char *translate; /* Translation applied to characters. */ + int numeric; /* Flag for numeric comparison. Handle + strings of digits with optional decimal + point, but no exponential notation. */ + int general_numeric; /* Flag for general, numeric comparison. + Handle numbers in exponential notation. */ + int month; /* Flag for comparison by month name. */ + int reverse; /* Reverse the sense of comparison. */ + struct keyfield *next; /* Next keyfield to try. */ +}; + +struct month +{ + char *name; + int val; +}; + +/* The name this program was run with. */ +char *program_name; + +/* FIXME: None of these tables work with multibyte character sets. + Also, there are many other bugs when handling multibyte characters, + or even unibyte encodings where line boundaries are not in the + initial shift state. One way to fix this is to rewrite `sort' to + use wide characters internally, but doing this with good + performance is a bit tricky. */ + +/* Table of white space. */ +static int blanks[UCHAR_LIM]; + +/* Table of non-printing characters. */ +static int nonprinting[UCHAR_LIM]; + +/* Table of non-dictionary characters (not letters, digits, or blanks). */ +static int nondictionary[UCHAR_LIM]; + +/* Translation table folding lower case to upper. */ +static char fold_toupper[UCHAR_LIM]; + +#define MONTHS_PER_YEAR 12 + +/* Table mapping month names to integers. + Alphabetic order allows binary search. */ +static struct month monthtab[] = +{ + {"APR", 4}, + {"AUG", 8}, + {"DEC", 12}, + {"FEB", 2}, + {"JAN", 1}, + {"JUL", 7}, + {"JUN", 6}, + {"MAR", 3}, + {"MAY", 5}, + {"NOV", 11}, + {"OCT", 10}, + {"SEP", 9} +}; + +/* During the merge phase, the number of files to merge at once. */ +#define NMERGE 16 + +/* Minimum size for a merge or check buffer. */ +#define MIN_MERGE_BUFFER_SIZE (2 + sizeof (struct line)) + +/* Minimum sort size; the code might not work with smaller sizes. */ +#define MIN_SORT_SIZE (NMERGE * MIN_MERGE_BUFFER_SIZE) + +/* The number of bytes needed for a merge or check buffer, which can + function relatively efficiently even if it holds only one line. If + a longer line is seen, this value is increased. */ +static size_t merge_buffer_size = MAX (MIN_MERGE_BUFFER_SIZE, 256 * 1024); + +/* The approximate maximum number of bytes of main memory to use, as + specified by the user. Zero if the user has not specified a size. */ +static size_t sort_size; + +/* The guessed size for non-regular files. */ +#define INPUT_FILE_SIZE_GUESS (1024 * 1024) + +/* Array of directory names in which any temporary files are to be created. */ +static char const **temp_dirs; + +/* Number of temporary directory names used. */ +static size_t temp_dir_count; + +/* Number of allocated slots in temp_dirs. */ +static size_t temp_dir_alloc; + +/* Flag to reverse the order of all comparisons. */ +static int reverse; + +/* Flag for stable sort. This turns off the last ditch bytewise + comparison of lines, and instead leaves lines in the same order + they were read if all keys compare equal. */ +static int stable; + +/* Tab character separating fields. If NUL, then fields are separated + by the empty string between a non-whitespace character and a whitespace + character. */ +static char tab; + +/* Flag to remove consecutive duplicate lines from the output. + Only the last of a sequence of equal lines will be output. */ +static int unique; + +/* Nonzero if any of the input files are the standard input. */ +static int have_read_stdin; + +/* List of key field comparisons to be tried. */ +static struct keyfield *keylist; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + fputs (_("\ +Write sorted concatenation of all FILE(s) to standard output.\n\ +\n\ +Ordering options:\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -b, --ignore-leading-blanks ignore leading blanks\n\ + -d, --dictionary-order consider only blanks and alphanumeric characters\n\ + -f, --ignore-case fold lower case to upper case characters\n\ +"), stdout); + fputs (_("\ + -g, --general-numeric-sort compare according to general numerical value\n\ + -i, --ignore-nonprinting consider only printable characters\n\ + -M, --month-sort compare (unknown) < `JAN' < ... < `DEC'\n\ + -n, --numeric-sort compare according to string numerical value\n\ + -r, --reverse reverse the result of comparisons\n\ +\n\ +"), stdout); + fputs (_("\ +Other options:\n\ +\n\ + -c, --check check whether input is sorted; do not sort\n\ + -k, --key=POS1[,POS2] start a key at POS1, end it at POS 2 (origin 1)\n\ + -m, --merge merge already sorted files; do not sort\n\ + -o, --output=FILE write result to FILE instead of standard output\n\ + -s, --stable stabilize sort by disabling last-resort comparison\n\ + -S, --buffer-size=SIZE use SIZE for main memory buffer\n\ +"), stdout); + printf (_("\ + -t, --field-separator=SEP use SEP instead of non- to whitespace transition\n\ + -T, --temporary-directory=DIR use DIR for temporaries, not $TMPDIR or %s\n\ + multiple options specify multiple directories\n\ + -u, --unique with -c: check for strict ordering\n\ + otherwise: output only the first of an equal run\n\ +"), DEFAULT_TMPDIR); + fputs (_("\ + -z, --zero-terminated end lines with 0 byte, not newline\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +POS is F[.C][OPTS], where F is the field number and C the character position\n\ +in the field. OPTS is one or more single-letter ordering options, which\n\ +override global ordering options for that key. If no key is given, use the\n\ +entire line as the key.\n\ +\n\ +SIZE may be followed by the following multiplicative suffixes:\n\ +"), stdout); + fputs (_("\ +% 1% of memory, b 1, K 1024 (default), and so on for M, G, T, P, E, Z, Y.\n\ +\n\ +With no FILE, or when FILE is -, read standard input.\n\ +\n\ +*** WARNING ***\n\ +The locale specified by the environment affects sort order.\n\ +Set LC_ALL=C to get the traditional sort order that uses\n\ +native byte values.\n\ +"), stdout ); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + /* Don't use EXIT_FAILURE here in case it is defined to be 1. + POSIX requires that sort return 1 IFF invoked with -c and + the input is not properly sorted. */ + assert (status == 0 || status == SORT_FAILURE); + exit (status); +} + +#define COMMON_SHORT_OPTIONS "-bcdfgik:mMno:rsS:t:T:uz" + +static struct option const long_options[] = +{ + {"ignore-leading-blanks", no_argument, NULL, 'b'}, + {"check", no_argument, NULL, 'c'}, + {"dictionary-order", no_argument, NULL, 'd'}, + {"ignore-case", no_argument, NULL, 'f'}, + {"general-numeric-sort", no_argument, NULL, 'g'}, + {"ignore-nonprinting", no_argument, NULL, 'i'}, + {"key", required_argument, NULL, 'k'}, + {"merge", no_argument, NULL, 'm'}, + {"month-sort", no_argument, NULL, 'M'}, + {"numeric-sort", no_argument, NULL, 'n'}, + {"output", required_argument, NULL, 'o'}, + {"reverse", no_argument, NULL, 'r'}, + {"stable", no_argument, NULL, 's'}, + {"buffer-size", required_argument, NULL, 'S'}, + {"field-separator", required_argument, NULL, 't'}, + {"temporary-directory", required_argument, NULL, 'T'}, + {"unique", no_argument, NULL, 'u'}, + {"zero-terminated", no_argument, NULL, 'z'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0}, +}; + +/* The set of signals that are caught. */ +static sigset_t caught_signals; + +/* The list of temporary files. */ +struct tempnode +{ + struct tempnode *volatile next; + char name[1]; /* Actual size is 1 + file name length. */ +}; +static struct tempnode *volatile temphead; + +/* Clean up any remaining temporary files. */ + +static void +cleanup (void) +{ + struct tempnode *node; + + for (node = temphead; node; node = node->next) + unlink (node->name); +} + +/* Report MESSAGE for FILE, then clean up and exit. */ + +static void die (char const *, char const *) ATTRIBUTE_NORETURN; +static void +die (char const *message, char const *file) +{ + error (0, errno, "%s: %s", message, file); + exit (SORT_FAILURE); +} + +/* Create a new temporary file, returning its newly allocated name. + Store into *PFP a stream open for writing. */ + +static char * +create_temp_file (FILE **pfp) +{ + static char const slashbase[] = "/sortXXXXXX"; + static size_t temp_dir_index; + sigset_t oldset; + int fd; + int saved_errno; + char const *temp_dir = temp_dirs[temp_dir_index]; + size_t len = strlen (temp_dir); + struct tempnode *node = + (struct tempnode *) xmalloc (sizeof node->next + len + sizeof slashbase); + char *file = node->name; + + memcpy (file, temp_dir, len); + memcpy (file + len, slashbase, sizeof slashbase); + node->next = temphead; + if (++temp_dir_index == temp_dir_count) + temp_dir_index = 0; + + /* Create the temporary file in a critical section, to avoid races. */ + sigprocmask (SIG_BLOCK, &caught_signals, &oldset); + fd = mkstemp (file); + if (0 <= fd) + temphead = node; + saved_errno = errno; + sigprocmask (SIG_SETMASK, &oldset, NULL); + errno = saved_errno; + + if (fd < 0 || (*pfp = fdopen (fd, "w")) == NULL) + die (_("cannot create temporary file"), file); + + return file; +} + +static FILE * +xfopen (const char *file, const char *how) +{ + FILE *fp; + + if (STREQ (file, "-")) + { + if (*how == 'r') + { + have_read_stdin = 1; + fp = stdin; + } + else + fp = stdout; + } + else + { + if ((fp = fopen_safer (file, how)) == NULL) + die (_("open failed"), file); + } + + return fp; +} + +/* Close FP, whose name is FILE, and report any errors. */ + +static void +xfclose (FILE *fp, char const *file) +{ + if (fp == stdin) + { + /* Allow reading stdin from tty more than once. */ + if (feof (fp)) + clearerr (fp); + } + else + { + if (fclose (fp) != 0) + die (_("close failed"), file); + } +} + +static void +write_bytes (const char *buf, size_t n_bytes, FILE *fp, const char *output_file) +{ + if (fwrite (buf, 1, n_bytes, fp) != n_bytes) + die (_("write failed"), output_file); +} + +/* Append DIR to the array of temporary directory names. */ +static void +add_temp_dir (char const *dir) +{ + if (temp_dir_count == temp_dir_alloc) + { + temp_dir_alloc = temp_dir_alloc ? temp_dir_alloc * 2 : 16; + temp_dirs = xrealloc (temp_dirs, sizeof (temp_dirs) * temp_dir_alloc); + } + + temp_dirs[temp_dir_count++] = dir; +} + +/* Search through the list of temporary files for NAME; + remove it if it is found on the list. */ + +static void +zaptemp (const char *name) +{ + struct tempnode *volatile *pnode; + struct tempnode *node; + + for (pnode = &temphead; (node = *pnode); pnode = &node->next) + if (node->name == name) + { + unlink (name); + *pnode = node->next; + free ((char *) node); + break; + } +} + +#if HAVE_NL_LANGINFO + +static int +struct_month_cmp (const void *m1, const void *m2) +{ + return strcmp (((const struct month *) m1)->name, + ((const struct month *) m2)->name); +} + +#endif + +/* Initialize the character class tables. */ + +static void +inittables (void) +{ + int i; + + for (i = 0; i < UCHAR_LIM; ++i) + { + if (ISBLANK (i)) + blanks[i] = 1; + if (!ISPRINT (i)) + nonprinting[i] = 1; + if (!ISALNUM (i) && !ISBLANK (i)) + nondictionary[i] = 1; + if (ISLOWER (i)) + fold_toupper[i] = toupper (i); + else + fold_toupper[i] = i; + } + +#if HAVE_NL_LANGINFO + /* If we're not in the "C" locale, read different names for months. */ + if (hard_LC_TIME) + { + for (i = 0; i < MONTHS_PER_YEAR; i++) + { + char *s; + size_t s_len; + size_t j; + char *name; + + s = (char *) nl_langinfo (ABMON_1 + i); + s_len = strlen (s); + monthtab[i].name = name = (char *) xmalloc (s_len + 1); + monthtab[i].val = i + 1; + + for (j = 0; j < s_len; j++) + name[j] = fold_toupper[UCHAR (s[j])]; + name[j] = '\0'; + } + qsort ((void *) monthtab, MONTHS_PER_YEAR, + sizeof (struct month), struct_month_cmp); + } +#endif +} + +/* Specify the amount of main memory to use when sorting. */ +static void +specify_sort_size (char const *s) +{ + uintmax_t n; + char *suffix; + enum strtol_error e = xstrtoumax (s, &suffix, 10, &n, "EgGkKmMPtTYZ"); + + /* The default unit is KiB. */ + if (e == LONGINT_OK && ISDIGIT (suffix[-1])) + { + if (n <= UINTMAX_MAX / 1024) + n *= 1024; + else + e = LONGINT_OVERFLOW; + } + + /* A 'b' suffix means bytes; a '%' suffix means percent of memory. */ + if (e == LONGINT_INVALID_SUFFIX_CHAR && ISDIGIT (suffix[-1]) && ! suffix[1]) + switch (suffix[0]) + { + case 'b': + e = LONGINT_OK; + break; + + case '%': + { + double mem = physmem_total () * n / 100; + + /* Use "<", not "<=", to avoid problems with rounding. */ + if (mem < UINTMAX_MAX) + { + n = mem; + e = LONGINT_OK; + } + else + e = LONGINT_OVERFLOW; + } + break; + } + + if (e == LONGINT_OK) + { + sort_size = n; + if (sort_size == n) + { + sort_size = MAX (sort_size, MIN_SORT_SIZE); + return; + } + + e = LONGINT_OVERFLOW; + } + + STRTOL_FATAL_ERROR (s, _("sort size"), e); +} + +/* Return the default sort size. */ +static size_t +default_sort_size (void) +{ + /* Let MEM be available memory or 1/8 of total memory, whichever + is greater. */ + double avail = physmem_available (); + double total = physmem_total (); + double mem = MAX (avail, total / 8); + struct rlimit rlimit; + + /* Let SIZE be MEM, but no more than the maximum object size or + system resource limits. Avoid the MIN macro here, as it is not + quite right when only one argument is floating point. Don't + bother to check for values like RLIM_INFINITY since in practice + they are not much less than SIZE_MAX. */ + size_t size = SIZE_MAX; + if (mem < size) + size = mem; + if (getrlimit (RLIMIT_DATA, &rlimit) == 0 && rlimit.rlim_cur < size) + size = rlimit.rlim_cur; +#ifdef RLIMIT_AS + if (getrlimit (RLIMIT_AS, &rlimit) == 0 && rlimit.rlim_cur < size) + size = rlimit.rlim_cur; +#endif + + /* Leave a large safety margin for the above limits, as failure can + occur when they are exceeded. */ + size /= 2; + +#ifdef RLIMIT_RSS + /* Leave a 1/16 margin for RSS to leave room for code, stack, etc. + Exceeding RSS is not fatal, but can be quite slow. */ + if (getrlimit (RLIMIT_RSS, &rlimit) == 0 && rlimit.rlim_cur / 16 * 15 < size) + size = rlimit.rlim_cur / 16 * 15; +#endif + + /* Use no less than the minimum. */ + return MAX (size, MIN_SORT_SIZE); +} + +/* Return the sort buffer size to use with the input files identified + by FPS and FILES, which are alternate paths to the same files. + NFILES gives the number of input files; NFPS may be less. Assume + that each input line requires LINE_BYTES extra bytes' worth of line + information. Return at most SIZE_BOUND. */ + +static size_t +sort_buffer_size (FILE *const *fps, int nfps, + char *const *files, int nfiles, + size_t line_bytes, size_t size_bound) +{ + /* In the worst case, each input byte is a newline. */ + size_t worst_case_per_input_byte = line_bytes + 1; + + /* Keep enough room for one extra input line and an extra byte. + This extra room might be needed when preparing to read EOF. */ + size_t size = worst_case_per_input_byte + 1; + + int i; + + for (i = 0; i < nfiles; i++) + { + struct stat st; + off_t file_size; + size_t worst_case; + + if ((i < nfps ? fstat (fileno (fps[i]), &st) + : strcmp (files[i], "-") == 0 ? fstat (STDIN_FILENO, &st) + : stat (files[i], &st)) + != 0) + die (_("stat failed"), files[i]); + + file_size = S_ISREG (st.st_mode) ? st.st_size : INPUT_FILE_SIZE_GUESS; + + /* Add the amount of memory needed to represent the worst case + where the input consists entirely of newlines followed by a + single non-newline. Check for overflow. */ + worst_case = file_size * worst_case_per_input_byte + 1; + if (file_size != worst_case / worst_case_per_input_byte + || size_bound - size <= worst_case) + return size_bound; + size += worst_case; + } + + return size; +} + +/* Initialize BUF. Reserve LINE_BYTES bytes for each line; LINE_BYTES + must be at least sizeof (struct line). Allocate ALLOC bytes + initially. */ + +static void +initbuf (struct buffer *buf, size_t line_bytes, size_t alloc) +{ + /* Ensure that the line array is properly aligned. If the desired + size cannot be allocated, repeatedly halve it until allocation + succeeds. The smaller allocation may hurt overall performance, + but that's better than failing. */ + for (;;) + { + alloc += sizeof (struct line) - alloc % sizeof (struct line); + buf->buf = malloc (alloc); + if (buf->buf) + break; + alloc /= 2; + if (alloc <= line_bytes + 1) + xalloc_die (); + } + + buf->line_bytes = line_bytes; + buf->alloc = alloc; + buf->used = buf->left = buf->nlines = 0; + buf->eof = 0; +} + +/* Return one past the limit of the line array. */ + +static inline struct line * +buffer_linelim (struct buffer const *buf) +{ + return (struct line *) (buf->buf + buf->alloc); +} + +/* Return a pointer to the first character of the field specified + by KEY in LINE. */ + +static char * +begfield (const struct line *line, const struct keyfield *key) +{ + register char *ptr = line->text, *lim = ptr + line->length - 1; + register size_t sword = key->sword; + register size_t schar = key->schar; + register size_t remaining_bytes; + + if (tab) + while (ptr < lim && sword--) + { + while (ptr < lim && *ptr != tab) + ++ptr; + if (ptr < lim) + ++ptr; + } + else + while (ptr < lim && sword--) + { + while (ptr < lim && blanks[UCHAR (*ptr)]) + ++ptr; + while (ptr < lim && !blanks[UCHAR (*ptr)]) + ++ptr; + } + + if (key->skipsblanks) + while (ptr < lim && blanks[UCHAR (*ptr)]) + ++ptr; + + /* Advance PTR by SCHAR (if possible), but no further than LIM. */ + remaining_bytes = lim - ptr; + if (schar < remaining_bytes) + ptr += schar; + else + ptr = lim; + + return ptr; +} + +/* Return the limit of (a pointer to the first character after) the field + in LINE specified by KEY. */ + +static char * +limfield (const struct line *line, const struct keyfield *key) +{ + register char *ptr = line->text, *lim = ptr + line->length - 1; + register size_t eword = key->eword, echar = key->echar; + register size_t remaining_bytes; + + /* Note: from the POSIX spec: + The leading field separator itself is included in + a field when -t is not used. FIXME: move this comment up... */ + + /* Move PTR past EWORD fields or to one past the last byte on LINE, + whichever comes first. If there are more than EWORD fields, leave + PTR pointing at the beginning of the field having zero-based index, + EWORD. If a delimiter character was specified (via -t), then that + `beginning' is the first character following the delimiting TAB. + Otherwise, leave PTR pointing at the first `blank' character after + the preceding field. */ + if (tab) + while (ptr < lim && eword--) + { + while (ptr < lim && *ptr != tab) + ++ptr; + if (ptr < lim && (eword | echar)) + ++ptr; + } + else + while (ptr < lim && eword--) + { + while (ptr < lim && blanks[UCHAR (*ptr)]) + ++ptr; + while (ptr < lim && !blanks[UCHAR (*ptr)]) + ++ptr; + } + +#ifdef POSIX_UNSPECIFIED + /* The following block of code makes GNU sort incompatible with + standard Unix sort, so it's ifdef'd out for now. + The POSIX spec isn't clear on how to interpret this. + FIXME: request clarification. + + From: kwzh@gnu.ai.mit.edu (Karl Heuer) + Date: Thu, 30 May 96 12:20:41 -0400 + [Translated to POSIX 1003.1-2001 terminology by Paul Eggert.] + + [...]I believe I've found another bug in `sort'. + + $ cat /tmp/sort.in + a b c 2 d + pq rs 1 t + $ textutils-1.15/src/sort -k1.7,1.7 skipsblanks) + while (ptr < lim && blanks[UCHAR (*ptr)]) + ++ptr; + + /* Advance PTR by ECHAR (if possible), but no further than LIM. */ + remaining_bytes = lim - ptr; + if (echar < remaining_bytes) + ptr += echar; + else + ptr = lim; + + return ptr; +} + +/* FIXME */ + +static void +trim_trailing_blanks (const char *a_start, char **a_end) +{ + while (*a_end > a_start && blanks[UCHAR (*(*a_end - 1))]) + --(*a_end); +} + +/* Fill BUF reading from FP, moving buf->left bytes from the end + of buf->buf to the beginning first. If EOF is reached and the + file wasn't terminated by a newline, supply one. Set up BUF's line + table too. FILE is the name of the file corresponding to FP. + Return nonzero if some input was read. */ + +static int +fillbuf (struct buffer *buf, register FILE *fp, char const *file) +{ + struct keyfield const *key = keylist; + char eol = eolchar; + size_t line_bytes = buf->line_bytes; + size_t mergesize = merge_buffer_size - MIN_MERGE_BUFFER_SIZE; + + if (buf->eof) + return 0; + + if (buf->used != buf->left) + { + memmove (buf->buf, buf->buf + buf->used - buf->left, buf->left); + buf->used = buf->left; + buf->nlines = 0; + } + + for (;;) + { + char *ptr = buf->buf + buf->used; + struct line *linelim = buffer_linelim (buf); + struct line *line = linelim - buf->nlines; + size_t avail = (char *) linelim - buf->nlines * line_bytes - ptr; + char *line_start = buf->nlines ? line->text + line->length : buf->buf; + + while (line_bytes + 1 < avail) + { + /* Read as many bytes as possible, but do not read so many + bytes that there might not be enough room for the + corresponding line array. The worst case is when the + rest of the input file consists entirely of newlines, + except that the last byte is not a newline. */ + size_t readsize = (avail - 1) / (line_bytes + 1); + size_t bytes_read = fread (ptr, 1, readsize, fp); + char *ptrlim = ptr + bytes_read; + char *p; + avail -= bytes_read; + + if (bytes_read != readsize) + { + if (ferror (fp)) + die (_("read failed"), file); + if (feof (fp)) + { + buf->eof = 1; + if (buf->buf == ptrlim) + return 0; + if (ptrlim[-1] != eol) + *ptrlim++ = eol; + } + } + + /* Find and record each line in the just-read input. */ + while ((p = memchr (ptr, eol, ptrlim - ptr))) + { + ptr = p + 1; + line--; + line->text = line_start; + line->length = ptr - line_start; + mergesize = MAX (mergesize, line->length); + avail -= line_bytes; + + if (key) + { + /* Precompute the position of the first key for + efficiency. */ + line->keylim = (key->eword == (size_t) -1 + ? p + : limfield (line, key)); + + if (key->sword != (size_t) -1) + line->keybeg = begfield (line, key); + else + { + if (key->skipsblanks) + while (blanks[UCHAR (*line_start)]) + line_start++; + line->keybeg = line_start; + } + if (key->skipeblanks) + trim_trailing_blanks (line->keybeg, &line->keylim); + } + + line_start = ptr; + } + + ptr = ptrlim; + if (buf->eof) + break; + } + + buf->used = ptr - buf->buf; + buf->nlines = buffer_linelim (buf) - line; + if (buf->nlines != 0) + { + buf->left = ptr - line_start; + merge_buffer_size = mergesize + MIN_MERGE_BUFFER_SIZE; + return 1; + } + + /* The current input line is too long to fit in the buffer. + Double the buffer size and try again. */ + if (2 * buf->alloc < buf->alloc) + xalloc_die (); + buf->alloc *= 2; + buf->buf = xrealloc (buf->buf, buf->alloc); + } +} + +/* Compare strings A and B containing decimal fractions < 1. Each string + should begin with a decimal point followed immediately by the digits + of the fraction. Strings not of this form are considered to be zero. */ + +/* The goal here, is to take two numbers a and b... compare these + in parallel. Instead of converting each, and then comparing the + outcome. Most likely stopping the comparison before the conversion + is complete. The algorithm used, in the old sort: + + Algorithm: fraccompare + Action : compare two decimal fractions + accepts : char *a, char *b + returns : -1 if ab. + implement: + + if *a == decimal_point AND *b == decimal_point + find first character different in a and b. + if both are digits, return the difference *a - *b. + if *a is a digit + skip past zeros + if digit return 1, else 0 + if *b is a digit + skip past zeros + if digit return -1, else 0 + if *a is a decimal_point + skip past decimal_point and zeros + if digit return 1, else 0 + if *b is a decimal_point + skip past decimal_point and zeros + if digit return -1, else 0 + return 0 */ + +static int +fraccompare (register const char *a, register const char *b) +{ + if (*a == decimal_point && *b == decimal_point) + { + while (*++a == *++b) + if (! ISDIGIT (*a)) + return 0; + if (ISDIGIT (*a) && ISDIGIT (*b)) + return *a - *b; + if (ISDIGIT (*a)) + goto a_trailing_nonzero; + if (ISDIGIT (*b)) + goto b_trailing_nonzero; + return 0; + } + else if (*a++ == decimal_point) + { + a_trailing_nonzero: + while (*a == NUMERIC_ZERO) + a++; + return ISDIGIT (*a); + } + else if (*b++ == decimal_point) + { + b_trailing_nonzero: + while (*b == NUMERIC_ZERO) + b++; + return - ISDIGIT (*b); + } + return 0; +} + +/* Compare strings A and B as numbers without explicitly converting them to + machine numbers. Comparatively slow for short strings, but asymptotically + hideously fast. */ + +static int +numcompare (register const char *a, register const char *b) +{ + register int tmpa, tmpb, tmp; + register size_t loga, logb; + + tmpa = *a; + tmpb = *b; + + while (blanks[UCHAR (tmpa)]) + tmpa = *++a; + while (blanks[UCHAR (tmpb)]) + tmpb = *++b; + + if (tmpa == NEGATION_SIGN) + { + do + tmpa = *++a; + while (tmpa == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpa)); + if (tmpb != NEGATION_SIGN) + { + if (tmpa == decimal_point) + do + tmpa = *++a; + while (tmpa == NUMERIC_ZERO); + if (ISDIGIT (tmpa)) + return -1; + while (tmpb == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpb)) + tmpb = *++b; + if (tmpb == decimal_point) + do + tmpb = *++b; + while (tmpb == NUMERIC_ZERO); + if (ISDIGIT (tmpb)) + return -1; + return 0; + } + do + tmpb = *++b; + while (tmpb == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpb)); + + while (tmpa == tmpb && ISDIGIT (tmpa)) + { + do + tmpa = *++a; + while (IS_THOUSANDS_SEP (tmpa)); + do + tmpb = *++b; + while (IS_THOUSANDS_SEP (tmpb)); + } + + if ((tmpa == decimal_point && !ISDIGIT (tmpb)) + || (tmpb == decimal_point && !ISDIGIT (tmpa))) + return -fraccompare (a, b); + + tmp = tmpb - tmpa; + + for (loga = 0; ISDIGIT (tmpa); ++loga) + do + tmpa = *++a; + while (IS_THOUSANDS_SEP (tmpa)); + + for (logb = 0; ISDIGIT (tmpb); ++logb) + do + tmpb = *++b; + while (IS_THOUSANDS_SEP (tmpb)); + + if (loga != logb) + return loga < logb ? 1 : -1; + + if (!loga) + return 0; + + return tmp; + } + else if (tmpb == NEGATION_SIGN) + { + do + tmpb = *++b; + while (tmpb == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpb)); + if (tmpb == decimal_point) + do + tmpb = *++b; + while (tmpb == NUMERIC_ZERO); + if (ISDIGIT (tmpb)) + return 1; + while (tmpa == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpa)) + tmpa = *++a; + if (tmpa == decimal_point) + do + tmpa = *++a; + while (tmpa == NUMERIC_ZERO); + if (ISDIGIT (tmpa)) + return 1; + return 0; + } + else + { + while (tmpa == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpa)) + tmpa = *++a; + while (tmpb == NUMERIC_ZERO || IS_THOUSANDS_SEP (tmpb)) + tmpb = *++b; + + while (tmpa == tmpb && ISDIGIT (tmpa)) + { + do + tmpa = *++a; + while (IS_THOUSANDS_SEP (tmpa)); + do + tmpb = *++b; + while (IS_THOUSANDS_SEP (tmpb)); + } + + if ((tmpa == decimal_point && !ISDIGIT (tmpb)) + || (tmpb == decimal_point && !ISDIGIT (tmpa))) + return fraccompare (a, b); + + tmp = tmpa - tmpb; + + for (loga = 0; ISDIGIT (tmpa); ++loga) + do + tmpa = *++a; + while (IS_THOUSANDS_SEP (tmpa)); + + for (logb = 0; ISDIGIT (tmpb); ++logb) + do + tmpb = *++b; + while (IS_THOUSANDS_SEP (tmpb)); + + if (loga != logb) + return loga < logb ? -1 : 1; + + if (!loga) + return 0; + + return tmp; + } +} + +static int +general_numcompare (const char *sa, const char *sb) +{ + /* FIXME: add option to warn about failed conversions. */ + /* FIXME: maybe add option to try expensive FP conversion + only if A and B can't be compared more cheaply/accurately. */ + + char *ea; + char *eb; + double a = strtod (sa, &ea); + double b = strtod (sb, &eb); + + /* Put conversion errors at the start of the collating sequence. */ + if (sa == ea) + return sb == eb ? 0 : -1; + if (sb == eb) + return 1; + + /* Sort numbers in the usual way, where -0 == +0. Put NaNs after + conversion errors but before numbers; sort them by internal + bit-pattern, for lack of a more portable alternative. */ + return (a < b ? -1 + : a > b ? 1 + : a == b ? 0 + : b == b ? -1 + : a == a ? 1 + : memcmp ((char *) &a, (char *) &b, sizeof a)); +} + +/* Return an integer in 1..12 of the month name S with length LEN. + Return 0 if the name in S is not recognized. */ + +static int +getmonth (const char *s, size_t len) +{ + char *month; + register size_t i; + register int lo = 0, hi = MONTHS_PER_YEAR, result; + + while (len > 0 && blanks[UCHAR (*s)]) + { + ++s; + --len; + } + + if (len == 0) + return 0; + + month = (char *) alloca (len + 1); + for (i = 0; i < len; ++i) + month[i] = fold_toupper[UCHAR (s[i])]; + while (blanks[UCHAR (month[i - 1])]) + --i; + month[i] = '\0'; + + do + { + int ix = (lo + hi) / 2; + + if (strncmp (month, monthtab[ix].name, strlen (monthtab[ix].name)) < 0) + hi = ix; + else + lo = ix; + } + while (hi - lo > 1); + + result = (!strncmp (month, monthtab[lo].name, strlen (monthtab[lo].name)) + ? monthtab[lo].val : 0); + + return result; +} + +/* Compare two lines A and B trying every key in sequence until there + are no more keys or a difference is found. */ + +static int +keycompare (const struct line *a, const struct line *b) +{ + struct keyfield *key = keylist; + + /* For the first iteration only, the key positions have been + precomputed for us. */ + register char *texta = a->keybeg; + register char *textb = b->keybeg; + register char *lima = a->keylim; + register char *limb = b->keylim; + + int diff; + + for (;;) + { + register unsigned char *translate = (unsigned char *) key->translate; + register int *ignore = key->ignore; + + /* Find the lengths. */ + size_t lena = lima <= texta ? 0 : lima - texta; + size_t lenb = limb <= textb ? 0 : limb - textb; + + if (key->skipeblanks) + { + char *a_end = texta + lena; + char *b_end = textb + lenb; + trim_trailing_blanks (texta, &a_end); + trim_trailing_blanks (textb, &b_end); + lena = a_end - texta; + lenb = b_end - textb; + } + + /* Actually compare the fields. */ + if (key->numeric | key->general_numeric) + { + char savea = *lima, saveb = *limb; + + *lima = *limb = '\0'; + diff = ((key->numeric ? numcompare : general_numcompare) + (texta, textb)); + *lima = savea, *limb = saveb; + } + else if (key->month) + diff = getmonth (texta, lena) - getmonth (textb, lenb); + /* Sorting like this may become slow, so in a simple locale the user + can select a faster sort that is similar to ascii sort */ + else if (HAVE_SETLOCALE && hard_LC_COLLATE) + { + if (ignore || translate) + { + char *copy_a = (char *) alloca (lena + 1 + lenb + 1); + char *copy_b = copy_a + lena + 1; + size_t new_len_a, new_len_b, i; + + /* Ignore and/or translate chars before comparing. */ + for (new_len_a = new_len_b = i = 0; i < max (lena, lenb); i++) + { + if (i < lena) + { + copy_a[new_len_a] = (translate + ? translate[UCHAR (texta[i])] + : texta[i]); + if (!ignore || !ignore[UCHAR (texta[i])]) + ++new_len_a; + } + if (i < lenb) + { + copy_b[new_len_b] = (translate + ? translate[UCHAR (textb[i])] + : textb [i]); + if (!ignore || !ignore[UCHAR (textb[i])]) + ++new_len_b; + } + } + + diff = xmemcoll (copy_a, new_len_a, copy_b, new_len_b); + } + else if (lena == 0) + diff = - NONZERO (lenb); + else if (lenb == 0) + goto greater; + else + diff = xmemcoll (texta, lena, textb, lenb); + } + else if (ignore) + { +#define CMP_WITH_IGNORE(A, B) \ + do \ + { \ + for (;;) \ + { \ + while (texta < lima && ignore[UCHAR (*texta)]) \ + ++texta; \ + while (textb < limb && ignore[UCHAR (*textb)]) \ + ++textb; \ + if (! (texta < lima && textb < limb)) \ + break; \ + diff = UCHAR (A) - UCHAR (B); \ + if (diff) \ + goto not_equal; \ + ++texta; \ + ++textb; \ + } \ + \ + diff = (texta < lima) - (textb < limb); \ + } \ + while (0) + + if (translate) + CMP_WITH_IGNORE (translate[UCHAR (*texta)], + translate[UCHAR (*textb)]); + else + CMP_WITH_IGNORE (UCHAR (*texta), UCHAR (*textb)); + } + else if (lena == 0) + diff = - NONZERO (lenb); + else if (lenb == 0) + goto greater; + else + { + if (translate) + { + while (texta < lima && textb < limb) + { + diff = (UCHAR (translate[UCHAR (*texta++)]) + - UCHAR (translate[UCHAR (*textb++)])); + if (diff) + goto not_equal; + } + } + else + { + diff = memcmp (texta, textb, min (lena, lenb)); + if (diff) + goto not_equal; + } + diff = lena < lenb ? -1 : lena != lenb; + } + + if (diff) + goto not_equal; + + key = key->next; + if (! key) + break; + + /* Find the beginning and limit of the next field. */ + if (key->eword != (size_t) -1) + lima = limfield (a, key), limb = limfield (b, key); + else + lima = a->text + a->length - 1, limb = b->text + b->length - 1; + + if (key->sword != (size_t) -1) + texta = begfield (a, key), textb = begfield (b, key); + else + { + texta = a->text, textb = b->text; + if (key->skipsblanks) + { + while (texta < lima && blanks[UCHAR (*texta)]) + ++texta; + while (textb < limb && blanks[UCHAR (*textb)]) + ++textb; + } + } + } + + return 0; + + greater: + diff = 1; + not_equal: + return key->reverse ? -diff : diff; +} + +/* Compare two lines A and B, returning negative, zero, or positive + depending on whether A compares less than, equal to, or greater than B. */ + +static int +compare (register const struct line *a, register const struct line *b) +{ + int diff; + size_t alen, blen; + + /* First try to compare on the specified keys (if any). + The only two cases with no key at all are unadorned sort, + and unadorned sort -r. */ + if (keylist) + { + diff = keycompare (a, b); + alloca (0); + if (diff != 0 || unique || stable) + return diff; + } + + /* If the keys all compare equal (or no keys were specified) + fall through to the default comparison. */ + alen = a->length - 1, blen = b->length - 1; + + if (alen == 0) + diff = - NONZERO (blen); + else if (blen == 0) + diff = NONZERO (alen); + else if (HAVE_SETLOCALE && hard_LC_COLLATE) + diff = xmemcoll (a->text, alen, b->text, blen); + else if (! (diff = memcmp (a->text, b->text, min (alen, blen)))) + diff = alen < blen ? -1 : alen != blen; + + return reverse ? -diff : diff; +} + +/* Check that the lines read from the given FP come in order. Print a + diagnostic (FILE_NAME, line number, contents of line) to stderr and return + one if they are not in order. Otherwise, print no diagnostic + and return zero. */ + +static int +checkfp (FILE *fp, char *file_name) +{ + struct buffer buf; /* Input buffer. */ + struct line temp; /* Copy of previous line. */ + size_t alloc = 0; + uintmax_t line_number = 0; + struct keyfield *key = keylist; + int nonunique = 1 - unique; + int disordered = 0; + + initbuf (&buf, sizeof (struct line), + MAX (merge_buffer_size, sort_size)); + temp.text = NULL; + + while (fillbuf (&buf, fp, file_name)) + { + struct line const *line = buffer_linelim (&buf); + struct line const *linebase = line - buf.nlines; + + /* Make sure the line saved from the old buffer contents is + less than or equal to the first line of the new buffer. */ + if (alloc && nonunique <= compare (&temp, line - 1)) + { + found_disorder: + { + struct line const *disorder_line = line - 1; + uintmax_t disorder_line_number = + buffer_linelim (&buf) - disorder_line + line_number; + char hr_buf[INT_BUFSIZE_BOUND (uintmax_t)]; + fprintf (stderr, _("%s: %s:%s: disorder: "), + program_name, file_name, + umaxtostr (disorder_line_number, hr_buf)); + write_bytes (disorder_line->text, disorder_line->length, stderr, + _("standard error")); + disordered = 1; + break; + } + } + + /* Compare each line in the buffer with its successor. */ + while (linebase < --line) + if (nonunique <= compare (line, line - 1)) + goto found_disorder; + + line_number += buf.nlines; + + /* Save the last line of the buffer. */ + if (alloc < line->length) + { + do + { + alloc *= 2; + if (! alloc) + { + alloc = line->length; + break; + } + } + while (alloc < line->length); + + temp.text = xrealloc (temp.text, alloc); + } + memcpy (temp.text, line->text, line->length); + temp.length = line->length; + if (key) + { + temp.keybeg = temp.text + (line->keybeg - line->text); + temp.keylim = temp.text + (line->keylim - line->text); + } + } + + xfclose (fp, file_name); + free (buf.buf); + if (temp.text) + free (temp.text); + return disordered; +} + +/* Merge lines from FILES onto OFP. NFILES cannot be greater than + NMERGE. Close input and output files before returning. + OUTPUT_FILE gives the name of the output file; if OFP is NULL, the + output file has not been opened yet. */ + +static void +mergefps (char **files, register int nfiles, + FILE *ofp, const char *output_file) +{ + FILE *fps[NMERGE]; /* Input streams for each file. */ + struct buffer buffer[NMERGE]; /* Input buffers for each file. */ + struct line saved; /* Saved line storage for unique check. */ + struct line const *savedline = NULL; + /* &saved if there is a saved line. */ + size_t savealloc = 0; /* Size allocated for the saved line. */ + struct line const *cur[NMERGE]; /* Current line in each line table. */ + struct line const *base[NMERGE]; /* Base of each line table. */ + int ord[NMERGE]; /* Table representing a permutation of fps, + such that cur[ord[0]] is the smallest line + and will be next output. */ + register int i, j, t; + struct keyfield *key = keylist; + saved.text = NULL; + + /* Read initial lines from each input file. */ + for (i = 0; i < nfiles; ) + { + fps[i] = xfopen (files[i], "r"); + initbuf (&buffer[i], sizeof (struct line), + MAX (merge_buffer_size, sort_size / nfiles)); + if (fillbuf (&buffer[i], fps[i], files[i])) + { + struct line const *linelim = buffer_linelim (&buffer[i]); + cur[i] = linelim - 1; + base[i] = linelim - buffer[i].nlines; + i++; + } + else + { + /* fps[i] is empty; eliminate it from future consideration. */ + xfclose (fps[i], files[i]); + zaptemp (files[i]); + free (buffer[i].buf); + --nfiles; + for (j = i; j < nfiles; ++j) + files[j] = files[j + 1]; + } + } + + if (! ofp) + ofp = xfopen (output_file, "w"); + + /* Set up the ord table according to comparisons among input lines. + Since this only reorders two items if one is strictly greater than + the other, it is stable. */ + for (i = 0; i < nfiles; ++i) + ord[i] = i; + for (i = 1; i < nfiles; ++i) + if (0 < compare (cur[ord[i - 1]], cur[ord[i]])) + t = ord[i - 1], ord[i - 1] = ord[i], ord[i] = t, i = 0; + + /* Repeatedly output the smallest line until no input remains. */ + while (nfiles) + { + struct line const *smallest = cur[ord[0]]; + + /* If uniquified output is turned on, output only the first of + an identical series of lines. */ + if (unique) + { + if (savedline && compare (savedline, smallest)) + { + savedline = 0; + write_bytes (saved.text, saved.length, ofp, output_file); + } + if (!savedline) + { + savedline = &saved; + if (savealloc < smallest->length) + { + do + if (! savealloc) + { + savealloc = smallest->length; + break; + } + while ((savealloc *= 2) < smallest->length); + + saved.text = xrealloc (saved.text, savealloc); + } + saved.length = smallest->length; + memcpy (saved.text, smallest->text, saved.length); + if (key) + { + saved.keybeg = + saved.text + (smallest->keybeg - smallest->text); + saved.keylim = + saved.text + (smallest->keylim - smallest->text); + } + } + } + else + write_bytes (smallest->text, smallest->length, ofp, output_file); + + /* Check if we need to read more lines into core. */ + if (base[ord[0]] < smallest) + cur[ord[0]] = smallest - 1; + else + { + if (fillbuf (&buffer[ord[0]], fps[ord[0]], files[ord[0]])) + { + struct line const *linelim = buffer_linelim (&buffer[ord[0]]); + cur[ord[0]] = linelim - 1; + base[ord[0]] = linelim - buffer[ord[0]].nlines; + } + else + { + /* We reached EOF on fps[ord[0]]. */ + for (i = 1; i < nfiles; ++i) + if (ord[i] > ord[0]) + --ord[i]; + --nfiles; + xfclose (fps[ord[0]], files[ord[0]]); + zaptemp (files[ord[0]]); + free (buffer[ord[0]].buf); + for (i = ord[0]; i < nfiles; ++i) + { + fps[i] = fps[i + 1]; + files[i] = files[i + 1]; + buffer[i] = buffer[i + 1]; + cur[i] = cur[i + 1]; + base[i] = base[i + 1]; + } + for (i = 0; i < nfiles; ++i) + ord[i] = ord[i + 1]; + continue; + } + } + + /* The new line just read in may be larger than other lines + already in core; push it back in the queue until we encounter + a line larger than it. */ + for (i = 1; i < nfiles; ++i) + { + t = compare (cur[ord[0]], cur[ord[i]]); + if (!t) + t = ord[0] - ord[i]; + if (t < 0) + break; + } + t = ord[0]; + for (j = 1; j < i; ++j) + ord[j - 1] = ord[j]; + ord[i - 1] = t; + } + + if (unique && savedline) + { + write_bytes (saved.text, saved.length, ofp, output_file); + free (saved.text); + } + + xfclose (ofp, output_file); +} + +/* Sort the array LINES with NLINES members, using TEMP for temporary space. + The input and output arrays are in reverse order, and LINES and + TEMP point just past the end of their respective arrays. */ + +static void +sortlines (struct line *lines, size_t nlines, struct line *temp) +{ + register struct line *lo, *hi, *t; + register size_t nlo, nhi; + + if (nlines == 2) + { + if (0 < compare (&lines[-1], &lines[-2])) + { + struct line tmp = lines[-1]; + lines[-1] = lines[-2]; + lines[-2] = tmp; + } + return; + } + + nlo = nlines / 2; + lo = lines; + nhi = nlines - nlo; + hi = lines - nlo; + + if (nlo > 1) + sortlines (lo, nlo, temp); + + if (nhi > 1) + sortlines (hi, nhi, temp); + + t = temp; + + while (nlo && nhi) + if (compare (lo - 1, hi - 1) <= 0) + *--t = *--lo, --nlo; + else + *--t = *--hi, --nhi; + while (nlo--) + *--t = *--lo; + + for (lo = lines, nlo = nlines - nhi, t = temp; nlo; --nlo) + *--lo = *--t; +} + +/* Return the index of the first of NFILES FILES that is the same file + as OUTFILE. If none can be the same, return NFILES. Consider an + input pipe to be the same as OUTFILE, since the pipe might be the + output of a command like "cat OUTFILE". */ + +static int +first_same_file (char **files, int nfiles, char const *outfile) +{ + int i; + int got_outstat = 0; + struct stat instat, outstat; + + for (i = 0; i < nfiles; i++) + { + int standard_input = STREQ (files[i], "-"); + + if (STREQ (outfile, files[i]) && ! standard_input) + return i; + + if (! got_outstat) + { + got_outstat = 1; + if ((STREQ (outfile, "-") + ? fstat (STDOUT_FILENO, &outstat) + : stat (outfile, &outstat)) + != 0) + return nfiles; + } + + if (((standard_input + ? fstat (STDIN_FILENO, &instat) + : stat (files[i], &instat)) + == 0) + && (S_ISFIFO (instat.st_mode) || SAME_INODE (instat, outstat))) + return i; + } + + return nfiles; +} + +/* Check that each of the NFILES FILES is ordered. + Return a count of disordered files. */ + +static int +check (char **files, int nfiles) +{ + int i, disorders = 0; + FILE *fp; + + for (i = 0; i < nfiles; ++i) + { + fp = xfopen (files[i], "r"); + disorders += checkfp (fp, files[i]); + } + return disorders; +} + +/* Merge NFILES FILES onto OUTPUT_FILE. However, merge at most + MAX_MERGE input files directly onto OUTPUT_FILE. MAX_MERGE cannot + exceed NMERGE. */ + +static void +merge (char **files, int nfiles, int max_merge, char const *output_file) +{ + while (max_merge < nfiles) + { + FILE *tfp; + int i, t = 0; + char *temp; + for (i = 0; i < nfiles / NMERGE; ++i) + { + temp = create_temp_file (&tfp); + mergefps (&files[i * NMERGE], NMERGE, tfp, temp); + files[t++] = temp; + } + temp = create_temp_file (&tfp); + mergefps (&files[i * NMERGE], nfiles % NMERGE, tfp, temp); + files[t++] = temp; + nfiles = t; + if (nfiles == 1) + break; + } + + mergefps (files, nfiles, NULL, output_file); +} + +/* Sort NFILES FILES onto OUTPUT_FILE. */ + +static void +sort (char **files, int nfiles, char const *output_file) +{ + struct buffer buf; + int n_temp_files = 0; + int output_file_created = 0; + + static size_t size; + if (! size && ! (size = sort_size)) + size = default_sort_size (); + + buf.alloc = 0; + + while (nfiles) + { + char const *temp_output; + char const *file = *files; + FILE *fp = xfopen (file, "r"); + FILE *tfp; + + if (! buf.alloc) + initbuf (&buf, 2 * sizeof (struct line), + sort_buffer_size (&fp, 1, files, nfiles, + 2 * sizeof (struct line), size)); + buf.eof = 0; + files++; + nfiles--; + + while (fillbuf (&buf, fp, file)) + { + struct line *line; + struct line *linebase; + + if (buf.eof && nfiles + && (2 * sizeof (struct line) + 1 + < (buf.alloc - buf.used + - 2 * sizeof (struct line) * buf.nlines))) + { + /* End of file, but there is more input and buffer room. + Concatenate the next input file; this is faster in + the usual case. */ + buf.left = buf.used; + break; + } + + line = buffer_linelim (&buf); + linebase = line - buf.nlines; + sortlines (line, buf.nlines, linebase); + if (buf.eof && !nfiles && !n_temp_files && !buf.left) + { + xfclose (fp, file); + tfp = xfopen (output_file, "w"); + temp_output = output_file; + output_file_created = 1; + } + else + { + ++n_temp_files; + temp_output = create_temp_file (&tfp); + } + + do + { + line--; + write_bytes (line->text, line->length, tfp, temp_output); + if (unique) + while (linebase < line && compare (line, line - 1) == 0) + line--; + } + while (linebase < line); + + xfclose (tfp, temp_output); + + if (output_file_created) + goto finish; + } + xfclose (fp, file); + } + + finish: + free (buf.buf); + + if (! output_file_created) + { + int i = n_temp_files; + struct tempnode *node; + char **tempfiles = (char **) xmalloc (n_temp_files * sizeof (char *)); + for (node = temphead; i > 0; node = node->next) + tempfiles[--i] = node->name; + merge (tempfiles, n_temp_files, NMERGE, output_file); + free ((char *) tempfiles); + } +} + +/* Insert key KEY at the end of the key list. */ + +static void +insertkey (struct keyfield *key) +{ + struct keyfield **p; + + for (p = &keylist; *p; p = &(*p)->next) + continue; + *p = key; + key->next = NULL; +} + +/* Report a bad field specification SPEC, with extra info MSGID. */ + +static void badfieldspec (char const *, char const *) + ATTRIBUTE_NORETURN; +static void +badfieldspec (char const *spec, char const *msgid) +{ + error (SORT_FAILURE, 0, _("%s: invalid field specification `%s'"), + _(msgid), spec); + abort (); +} + +/* Parse the leading integer in STRING and store the resulting value + (which must fit into size_t) into *VAL. Return the address of the + suffix after the integer. If MSGID is NULL, return NULL after + failure; otherwise, report MSGID and exit on failure. */ + +static char const * +parse_field_count (char const *string, size_t *val, char const *msgid) +{ + char *suffix; + uintmax_t n; + + switch (xstrtoumax (string, &suffix, 10, &n, "")) + { + case LONGINT_OK: + case LONGINT_INVALID_SUFFIX_CHAR: + *val = n; + if (*val == n) + break; + /* Fall through. */ + case LONGINT_OVERFLOW: + if (msgid) + error (SORT_FAILURE, 0, _("%s: count `%.*s' too large"), + _(msgid), (int) (suffix - string), string); + return NULL; + + case LONGINT_INVALID: + if (msgid) + error (SORT_FAILURE, 0, _("%s: invalid count at start of `%s'"), + _(msgid), string); + return NULL; + } + + return suffix; +} + +/* Handle interrupts and hangups. */ + +static void +sighandler (int sig) +{ +#ifndef SA_NOCLDSTOP + signal (sig, SIG_IGN); +#endif + + cleanup (); + +#ifdef SA_NOCLDSTOP + { + struct sigaction sigact; + + sigact.sa_handler = SIG_DFL; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (sig, &sigact, NULL); + } +#else + signal (sig, SIG_DFL); +#endif + + raise (sig); +} + +/* Set the ordering options for KEY specified in S. + Return the address of the first character in S that + is not a valid ordering option. + BLANKTYPE is the kind of blanks that 'b' should skip. */ + +static char * +set_ordering (register const char *s, struct keyfield *key, + enum blanktype blanktype) +{ + while (*s) + { + switch (*s) + { + case 'b': + if (blanktype == bl_start || blanktype == bl_both) + key->skipsblanks = 1; + if (blanktype == bl_end || blanktype == bl_both) + key->skipeblanks = 1; + break; + case 'd': + key->ignore = nondictionary; + break; + case 'f': + key->translate = fold_toupper; + break; + case 'g': + key->general_numeric = 1; + break; + case 'i': + key->ignore = nonprinting; + break; + case 'M': + key->month = 1; + break; + case 'n': + key->numeric = 1; + break; + case 'r': + key->reverse = 1; + break; + default: + return (char *) s; + } + ++s; + } + return (char *) s; +} + +static struct keyfield * +new_key (void) +{ + struct keyfield *key = (struct keyfield *) xcalloc (1, sizeof *key); + key->eword = -1; + return key; +} + +int +main (int argc, char **argv) +{ + struct keyfield *key; + struct keyfield gkey; + char const *s; + int c = 0; + int checkonly = 0, mergeonly = 0, nfiles = 0; + int posix_pedantic = (getenv ("POSIXLY_CORRECT") != NULL); + bool obsolete_usage = (posix2_version () < 200112); + char const *short_options = (obsolete_usage + ? COMMON_SHORT_OPTIONS "y::" + : COMMON_SHORT_OPTIONS "y:"); + char *minus = "-", **files; + char const *outfile = minus; + static int const sigs[] = { SIGHUP, SIGINT, SIGPIPE, SIGTERM }; + unsigned nsigs = sizeof sigs / sizeof *sigs; +#ifdef SA_NOCLDSTOP + struct sigaction oldact, newact; +#endif + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (cleanup); + + hard_LC_COLLATE = hard_locale (LC_COLLATE); +#if HAVE_NL_LANGINFO + hard_LC_TIME = hard_locale (LC_TIME); +#endif + +#if HAVE_SETLOCALE + /* Let's get locale's representation of the decimal point */ + { + struct lconv *lconvp = localeconv (); + + /* If the locale doesn't define a decimal point, or if the decimal + point is multibyte, use the C decimal point. We don't support + multibyte decimal points yet. */ + decimal_point = *lconvp->decimal_point; + if (! decimal_point || lconvp->decimal_point[1]) + decimal_point = C_DECIMAL_POINT; + + /* We don't support multibyte thousands separators yet. */ + th_sep = *lconvp->thousands_sep; + if (! th_sep || lconvp->thousands_sep[1]) + th_sep = CHAR_MAX + 1; + } +#endif + + have_read_stdin = 0; + inittables (); + + /* Change the way library functions fail. */ + xalloc_exit_failure = SORT_FAILURE; + xmemcoll_exit_failure = SORT_FAILURE; + +#ifdef SA_NOCLDSTOP + { + unsigned i; + sigemptyset (&caught_signals); + for (i = 0; i < nsigs; i++) + sigaddset (&caught_signals, sigs[i]); + newact.sa_handler = sighandler; + newact.sa_mask = caught_signals; + newact.sa_flags = 0; + } +#endif + + { + unsigned i; + for (i = 0; i < nsigs; i++) + { + int sig = sigs[i]; +#ifdef SA_NOCLDSTOP + sigaction (sig, NULL, &oldact); + if (oldact.sa_handler != SIG_IGN) + sigaction (sig, &newact, NULL); +#else + if (signal (sig, SIG_IGN) != SIG_IGN) + signal (sig, sighandler); +#endif + } + } + + gkey.sword = gkey.eword = -1; + gkey.ignore = NULL; + gkey.translate = NULL; + gkey.numeric = gkey.general_numeric = gkey.month = gkey.reverse = 0; + gkey.skipsblanks = gkey.skipeblanks = 0; + + files = (char **) xmalloc (sizeof (char *) * argc); + + for (;;) + { + /* Parse an operand as a file after "--" was seen; or if + pedantic and a file was seen, unless the POSIX version + predates 1003.1-2001 and -c was not seen and the operand is + "-o FILE" or "-oFILE". */ + + if (c == -1 + || (posix_pedantic && nfiles != 0 + && ! (obsolete_usage + && ! checkonly + && optind != argc + && argv[optind][0] == '-' && argv[optind][1] == 'o' + && (argv[optind][2] || optind + 1 != argc))) + || ((c = getopt_long (argc, argv, short_options, + long_options, NULL)) + == -1)) + { + if (optind == argc) + break; + files[nfiles++] = argv[optind++]; + } + else switch (c) + { + case 1: + key = NULL; + if (obsolete_usage && optarg[0] == '+') + { + /* Treat +POS1 [-POS2] as a key if possible; but silently + treat an operand as a file if it is not a valid +POS1. */ + key = new_key (); + s = parse_field_count (optarg + 1, &key->sword, NULL); + if (s && *s == '.') + s = parse_field_count (s + 1, &key->schar, NULL); + if (! (key->sword | key->schar)) + key->sword = -1; + if (! s || *set_ordering (s, key, bl_start)) + { + free (key); + key = NULL; + } + else + { + if (optind != argc && argv[optind][0] == '-' + && ISDIGIT (argv[optind][1])) + { + char const *optarg1 = argv[optind++]; + s = parse_field_count (optarg1 + 1, &key->eword, + N_("invalid number after `-'")); + if (*s == '.') + s = parse_field_count (s + 1, &key->echar, + N_("invalid number after `.'")); + if (*set_ordering (s, key, bl_end)) + badfieldspec (optarg1, + N_("stray character in field spec")); + } + insertkey (key); + } + } + if (! key) + files[nfiles++] = optarg; + break; + + case 'b': + case 'd': + case 'f': + case 'g': + case 'i': + case 'M': + case 'n': + case 'r': + { + char str[2]; + str[0] = c; + str[1] = '\0'; + set_ordering (str, &gkey, bl_both); + } + break; + + case 'c': + checkonly = 1; + break; + + case 'k': + key = new_key (); + + /* Get POS1. */ + s = parse_field_count (optarg, &key->sword, + N_("invalid number at field start")); + if (! key->sword--) + { + /* Provoke with `sort -k0' */ + badfieldspec (optarg, N_("field number is zero")); + } + if (*s == '.') + { + s = parse_field_count (s + 1, &key->schar, + N_("invalid number after `.'")); + if (! key->schar--) + { + /* Provoke with `sort -k1.0' */ + badfieldspec (optarg, N_("character offset is zero")); + } + } + if (! (key->sword | key->schar)) + key->sword = -1; + s = set_ordering (s, key, bl_start); + if (*s != ',') + { + key->eword = -1; + key->echar = 0; + } + else + { + /* Get POS2. */ + s = parse_field_count (s + 1, &key->eword, + N_("invalid number after `,'")); + if (! key->eword--) + { + /* Provoke with `sort -k1,0' */ + badfieldspec (optarg, N_("field number is zero")); + } + if (*s == '.') + s = parse_field_count (s + 1, &key->echar, + N_("invalid number after `.'")); + else + { + /* `-k 2,3' is equivalent to `+1 -3'. */ + key->eword++; + } + s = set_ordering (s, key, bl_end); + } + if (*s) + badfieldspec (optarg, N_("stray character in field spec")); + insertkey (key); + break; + + case 'm': + mergeonly = 1; + break; + + case 'o': + outfile = optarg; + break; + + case 's': + stable = 1; + break; + + case 'S': + specify_sort_size (optarg); + break; + + case 't': + tab = optarg[0]; + if (tab && optarg[1]) + { + /* Provoke with `sort -txx'. Complain about + "multi-character tab" instead of "multibyte tab", so + that the diagnostic's wording does not need to be + changed once multibyte characters are supported. */ + error (SORT_FAILURE, 0, _("multi-character tab `%s'"), optarg); + } + break; + + case 'T': + add_temp_dir (optarg); + break; + + case 'u': + unique = 1; + break; + + case 'y': + /* Accept and ignore e.g. -y0 for compatibility with Solaris + 2.x through Solaris 7. -y is marked as obsolete starting + with Solaris 8. */ + break; + + case 'z': + eolchar = 0; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (SORT_FAILURE); + } + } + + /* Inheritance of global options to individual keys. */ + for (key = keylist; key; key = key->next) + if (!key->ignore && !key->translate && !key->skipsblanks && !key->reverse + && !key->skipeblanks && !key->month && !key->numeric + && !key->general_numeric) + { + key->ignore = gkey.ignore; + key->translate = gkey.translate; + key->skipsblanks = gkey.skipsblanks; + key->skipeblanks = gkey.skipeblanks; + key->month = gkey.month; + key->numeric = gkey.numeric; + key->general_numeric = gkey.general_numeric; + key->reverse = gkey.reverse; + } + + if (!keylist && (gkey.ignore || gkey.translate || gkey.skipsblanks + || gkey.skipeblanks || gkey.month || gkey.numeric + || gkey.general_numeric)) + insertkey (&gkey); + reverse = gkey.reverse; + + if (temp_dir_count == 0) + { + char const *tmp_dir = getenv ("TMPDIR"); + add_temp_dir (tmp_dir ? tmp_dir : DEFAULT_TMPDIR); + } + + if (nfiles == 0) + { + nfiles = 1; + files = − + } + + if (checkonly) + { + if (nfiles > 1) + error (SORT_FAILURE, 0, _("extra operand `%s' not allowed with -c"), + files[1]); + + /* POSIX requires that sort return 1 IFF invoked with -c and the + input is not properly sorted. */ + exit (check (files, nfiles) == 0 ? EXIT_SUCCESS : SORT_OUT_OF_ORDER); + } + + if (mergeonly) + { + int max_merge = first_same_file (files, MIN (nfiles, NMERGE), outfile); + merge (files, nfiles, max_merge, outfile); + } + else + sort (files, nfiles, outfile); + + if (have_read_stdin && fclose (stdin) == EOF) + die (_("close failed"), "-"); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/split.c b/src/apps/bin/coreutils-5.0/src/split.c new file mode 100644 index 0000000000..793f035a07 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/split.c @@ -0,0 +1,550 @@ +/* split.c -- split a file into pieces. + Copyright (C) 88, 91, 1995-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* By tege@sics.se, with rms. + + To do: + * Implement -t CHAR or -t REGEX to specify break characters other + than newline. */ + +#include + +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "dirname.h" +#include "error.h" +#include "full-read.h" +#include "full-write.h" +#include "posixver.h" +#include "safe-read.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "split" + +#define AUTHORS N_ ("Torbjorn Granlund and Richard M. Stallman") + +#define DEFAULT_SUFFIX_LENGTH 2 + +/* The name this program was run with. */ +char *program_name; + +/* Base name of output files. */ +static char const *outbase; + +/* Name of output files. */ +static char *outfile; + +/* Pointer to the end of the prefix in OUTFILE. + Suffixes are inserted here. */ +static char *outfile_mid; + +/* Length of OUTFILE's suffix. */ +static size_t suffix_length = DEFAULT_SUFFIX_LENGTH; + +/* Name of input file. May be "-". */ +static char *infile; + +/* Descriptor on which input file is open. */ +static int input_desc; + +/* Descriptor on which output file is open. */ +static int output_desc; + +/* If nonzero, print a diagnostic on standard error just before each + output file is opened. */ +static int verbose; + +static struct option const longopts[] = +{ + {"bytes", required_argument, NULL, 'b'}, + {"lines", required_argument, NULL, 'l'}, + {"line-bytes", required_argument, NULL, 'C'}, + {"suffix-length", required_argument, NULL, 'a'}, + {"verbose", no_argument, &verbose, 0}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION] [INPUT [PREFIX]]\n\ +"), + program_name); + fputs (_("\ +Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default\n\ +PREFIX is `x'. With no INPUT, or when INPUT is -, read standard input.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fprintf (stdout, _("\ + -a, --suffix-length=N use suffixes of length N (default %d)\n\ + -b, --bytes=SIZE put SIZE bytes per output file\n\ + -C, --line-bytes=SIZE put at most SIZE bytes of lines per output file\n\ + -l, --lines=NUMBER put NUMBER lines per output file\n\ +"), DEFAULT_SUFFIX_LENGTH); + fputs (_("\ + --verbose print a diagnostic to standard error just\n\ + before each output file is opened\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Compute the next sequential output file name and store it into the + string `outfile'. */ + +static void +next_file_name (void) +{ + if (! outfile) + { + /* Allocate and initialize the first file name. */ + + size_t outbase_length = strlen (outbase); + size_t outfile_length = outbase_length + suffix_length; + if (outfile_length + 1 < outbase_length) + xalloc_die (); + outfile = xmalloc (outfile_length + 1); + outfile_mid = outfile + outbase_length; + memcpy (outfile, outbase, outbase_length); + memset (outfile_mid, 'a', suffix_length); + outfile[outfile_length] = 0; + +#if ! _POSIX_NO_TRUNC && HAVE_PATHCONF && defined _PC_NAME_MAX + /* POSIX requires that if the output file name is too long for + its directory, `split' must fail without creating any files. + This must be checked for explicitly on operating systems that + silently truncate file names. */ + { + char *dir = dir_name (outfile); + long name_max = pathconf (dir, _PC_NAME_MAX); + if (0 <= name_max && name_max < base_len (base_name (outfile))) + error (EXIT_FAILURE, ENAMETOOLONG, "%s", outfile); + free (dir); + } +#endif + } + else + { + /* Increment the suffix in place, if possible. */ + + char *p; + for (p = outfile_mid + suffix_length; outfile_mid < p; *--p = 'a') + if (p[-1]++ != 'z') + return; + error (EXIT_FAILURE, 0, _("Output file suffixes exhausted")); + } +} + +/* Write BYTES bytes at BP to an output file. + If NEW_FILE_FLAG is nonzero, open the next output file. + Otherwise add to the same output file already in use. */ + +static void +cwrite (int new_file_flag, const char *bp, size_t bytes) +{ + if (new_file_flag) + { + if (output_desc >= 0 && close (output_desc) < 0) + error (EXIT_FAILURE, errno, "%s", outfile); + + next_file_name (); + if (verbose) + fprintf (stderr, _("creating file `%s'\n"), outfile); + output_desc = open (outfile, + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + if (output_desc < 0) + error (EXIT_FAILURE, errno, "%s", outfile); + } + if (full_write (output_desc, bp, bytes) != bytes) + error (EXIT_FAILURE, errno, "%s", outfile); +} + +/* Split into pieces of exactly NCHARS bytes. + Use buffer BUF, whose size is BUFSIZE. */ + +static void +bytes_split (size_t nchars, char *buf, size_t bufsize) +{ + size_t n_read; + int new_file_flag = 1; + size_t to_read; + size_t to_write = nchars; + char *bp_out; + + do + { + n_read = full_read (input_desc, buf, bufsize); + if (n_read == SAFE_READ_ERROR) + error (EXIT_FAILURE, errno, "%s", infile); + bp_out = buf; + to_read = n_read; + for (;;) + { + if (to_read < to_write) + { + if (to_read) /* do not write 0 bytes! */ + { + cwrite (new_file_flag, bp_out, to_read); + to_write -= to_read; + new_file_flag = 0; + } + break; + } + + cwrite (new_file_flag, bp_out, to_write); + bp_out += to_write; + to_read -= to_write; + new_file_flag = 1; + to_write = nchars; + } + } + while (n_read == bufsize); +} + +/* Split into pieces of exactly NLINES lines. + Use buffer BUF, whose size is BUFSIZE. */ + +static void +lines_split (size_t nlines, char *buf, size_t bufsize) +{ + size_t n_read; + char *bp, *bp_out, *eob; + int new_file_flag = 1; + size_t n = 0; + + do + { + n_read = full_read (input_desc, buf, bufsize); + if (n_read == SAFE_READ_ERROR) + error (EXIT_FAILURE, errno, "%s", infile); + bp = bp_out = buf; + eob = bp + n_read; + *eob = '\n'; + for (;;) + { + bp = memchr (bp, '\n', eob - bp + 1); + if (bp == eob) + { + if (eob != bp_out) /* do not write 0 bytes! */ + { + size_t len = eob - bp_out; + cwrite (new_file_flag, bp_out, len); + new_file_flag = 0; + } + break; + } + + ++bp; + if (++n >= nlines) + { + cwrite (new_file_flag, bp_out, bp - bp_out); + bp_out = bp; + new_file_flag = 1; + n = 0; + } + } + } + while (n_read == bufsize); +} + +/* Split into pieces that are as large as possible while still not more + than NCHARS bytes, and are split on line boundaries except + where lines longer than NCHARS bytes occur. */ + +static void +line_bytes_split (size_t nchars) +{ + size_t n_read; + char *bp; + int eof = 0; + size_t n_buffered = 0; + char *buf = (char *) xmalloc (nchars); + + do + { + /* Fill up the full buffer size from the input file. */ + + n_read = full_read (input_desc, buf + n_buffered, nchars - n_buffered); + if (n_read == SAFE_READ_ERROR) + error (EXIT_FAILURE, errno, "%s", infile); + + n_buffered += n_read; + if (n_buffered != nchars) + eof = 1; + + /* Find where to end this chunk. */ + bp = buf + n_buffered; + if (n_buffered == nchars) + { + while (bp > buf && bp[-1] != '\n') + bp--; + } + + /* If chunk has no newlines, use all the chunk. */ + if (bp == buf) + bp = buf + n_buffered; + + /* Output the chars as one output file. */ + cwrite (1, buf, bp - buf); + + /* Discard the chars we just output; move rest of chunk + down to be the start of the next chunk. Source and + destination probably overlap. */ + n_buffered -= bp - buf; + if (n_buffered > 0) + memmove (buf, bp, n_buffered); + } + while (!eof); + free (buf); +} + +#define FAIL_ONLY_ONE_WAY() \ + do \ + { \ + error (0, 0, _("cannot split in more than one way")); \ + usage (EXIT_FAILURE); \ + } \ + while (0) + +int +main (int argc, char **argv) +{ + struct stat stat_buf; + size_t num; /* numeric argument from command line */ + enum + { + type_undef, type_bytes, type_byteslines, type_lines, type_digits + } split_type = type_undef; + size_t in_blk_size; /* optimal block size of input file device */ + char *buf; /* file i/o buffer */ + size_t accum = 0; + int c; + int digits_optind = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + /* Parse command line options. */ + + infile = "-"; + outbase = "x"; + + while (1) + { + /* This is the argv-index of the option we will read next. */ + int this_optind = optind ? optind : 1; + long int tmp_long; + + c = getopt_long (argc, argv, "0123456789C:a:b:l:", longopts, NULL); + if (c == -1) + break; + + switch (c) + { + case 0: + break; + + case 'a': + { + unsigned long tmp; + if (xstrtoul (optarg, NULL, 10, &tmp, "") != LONGINT_OK + || SIZE_MAX < tmp) + { + error (0, 0, _("%s: invalid suffix length"), optarg); + usage (EXIT_FAILURE); + } + suffix_length = tmp; + } + break; + + case 'b': + if (split_type != type_undef) + FAIL_ONLY_ONE_WAY (); + split_type = type_bytes; + if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK + || tmp_long < 0 || tmp_long > INT_MAX) + { + error (0, 0, _("%s: invalid number of bytes"), optarg); + usage (EXIT_FAILURE); + } + accum = /* FIXME: */ (int) tmp_long; + break; + + case 'l': + if (split_type != type_undef) + FAIL_ONLY_ONE_WAY (); + split_type = type_lines; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long < 0 || tmp_long > INT_MAX) + { + error (0, 0, _("%s: invalid number of lines"), optarg); + usage (EXIT_FAILURE); + } + accum = /* FIXME */ (int) tmp_long; + break; + + case 'C': + if (split_type != type_undef) + FAIL_ONLY_ONE_WAY (); + split_type = type_byteslines; + if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK + || tmp_long < 0 || tmp_long > INT_MAX) + { + error (0, 0, _("%s: invalid number of bytes"), optarg); + usage (EXIT_FAILURE); + } + accum = /* FIXME */ (int) tmp_long; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (split_type != type_undef && split_type != type_digits) + FAIL_ONLY_ONE_WAY (); + if (digits_optind != 0 && digits_optind != this_optind) + accum = 0; /* More than one number given; ignore other. */ + digits_optind = this_optind; + split_type = type_digits; + accum = accum * 10 + c - '0'; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (digits_optind && 200112 <= posix2_version ()) + { + error (0, 0, _("`-%d' option is obsolete; use `-l %d'"), accum, accum); + usage (EXIT_FAILURE); + } + + /* Handle default case. */ + if (split_type == type_undef) + { + split_type = type_lines; + accum = 1000; + } + + if (accum < 1) + { + error (0, 0, _("invalid number")); + usage (EXIT_FAILURE); + } + num = accum; + + /* Get out the filename arguments. */ + + if (optind < argc) + infile = argv[optind++]; + + if (optind < argc) + outbase = argv[optind++]; + + if (optind < argc) + { + error (0, 0, _("too many arguments")); + usage (EXIT_FAILURE); + } + + /* Open the input file. */ + if (STREQ (infile, "-")) + input_desc = 0; + else + { + input_desc = open (infile, O_RDONLY); + if (input_desc < 0) + error (EXIT_FAILURE, errno, "%s", infile); + } + /* Binary I/O is safer when bytecounts are used. */ + SET_BINARY (input_desc); + + /* No output file is open now. */ + output_desc = -1; + + /* Get the optimal block size of input device and make a buffer. */ + + if (fstat (input_desc, &stat_buf) < 0) + error (EXIT_FAILURE, errno, "%s", infile); + in_blk_size = ST_BLKSIZE (stat_buf); + + buf = xmalloc (in_blk_size + 1); + + switch (split_type) + { + case type_digits: + case type_lines: + lines_split (num, buf, in_blk_size); + break; + + case type_bytes: + bytes_split (num, buf, in_blk_size); + break; + + case type_byteslines: + line_bytes_split (num); + break; + + default: + abort (); + } + + if (close (input_desc) < 0) + error (EXIT_FAILURE, errno, "%s", infile); + if (output_desc >= 0 && close (output_desc) < 0) + error (EXIT_FAILURE, errno, "%s", outfile); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/stat.c b/src/apps/bin/coreutils-5.0/src/stat.c new file mode 100644 index 0000000000..ec286abda1 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/stat.c @@ -0,0 +1,815 @@ +/* stat.c -- display file or filesystem status + Copyright (C) 2001, 2002, 2003 Free Software Foundation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Written by Michael Meskes. */ + +#include + +#include +#include +#include +#include +#include +#include +#if HAVE_SYS_STATVFS_H +# include +#endif +#if HAVE_SYS_VFS_H +# include +#endif + +/* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */ +#if !HAVE_SYS_STATVFS_H && !HAVE_SYS_VFS_H +# if HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H +# include +# include +# endif +#endif + +#include "system.h" + +#include "closeout.h" +#include "error.h" +#include "filemode.h" +#include "file-type.h" +#include "fs.h" +#include "getopt.h" +#include "quote.h" +#include "quotearg.h" +#include "strftime.h" +#include "xreadlink.h" + +#define NAMEMAX_FORMAT PRIuMAX + +#if HAVE_STRUCT_STATVFS_F_BASETYPE +# define STRUCT_STATVFS struct statvfs +# define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS +# if HAVE_STRUCT_STATVFS_F_NAMEMAX +# define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namemax)) +# endif +#else +# define STRUCT_STATVFS struct statfs +# define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS +# if HAVE_STRUCT_STATFS_F_NAMELEN +# define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namelen)) +# endif +#endif + +#ifndef SB_F_NAMEMAX +/* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */ +# define SB_F_NAMEMAX(S) "*" +# undef NAMEMAX_FORMAT +# define NAMEMAX_FORMAT "s" +#endif + +#if HAVE_STRUCT_STATVFS_F_BASETYPE +# define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype +#else +# if HAVE_STRUCT_STATFS_F_FSTYPENAME +# define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename +# endif +#endif + +#define PROGRAM_NAME "stat" + +#define AUTHORS "Michael Meskes" + +static struct option const long_options[] = { + {"link", no_argument, 0, 'l'}, /* deprecated. FIXME: remove in 2003 */ + {"dereference", no_argument, 0, 'L'}, + {"format", required_argument, 0, 'c'}, + {"filesystem", no_argument, 0, 'f'}, + {"terse", no_argument, 0, 't'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +/* Nonzero means we should exit with EXIT_FAILURE upon completion. */ +static int G_fail; + +char *program_name; + +/* Return the type of the specified file system. + Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris) + Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2) + Still others have neither and have to get by with f_type (Linux). */ +static char * +human_fstype (STRUCT_STATVFS const *statfsbuf) +{ +#ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME + /* Cast away the `const' attribute. */ + return (char *) statfsbuf->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME; +#else + char const *type; + switch (statfsbuf->f_type) + { +# if defined __linux__ + case S_MAGIC_AFFS: + type = "affs"; + break; + case S_MAGIC_EXT: + type = "ext"; + break; + case S_MAGIC_EXT2_OLD: + type = "ext2"; + break; + case S_MAGIC_EXT2: + type = "ext2/ext3"; + break; + case S_MAGIC_HPFS: + type = "hpfs"; + break; + case S_MAGIC_ISOFS: + type = "isofs"; + break; + case S_MAGIC_ISOFS_WIN: + type = "isofs"; + break; + case S_MAGIC_ISOFS_R_WIN: + type = "isofs"; + break; + case S_MAGIC_MINIX: + type = "minix"; + break; + case S_MAGIC_MINIX_30: + type = "minix (30 char.)"; + break; + case S_MAGIC_MINIX_V2: + type = "minix v2"; + break; + case S_MAGIC_MINIX_V2_30: + type = "minix v2 (30 char.)"; + break; + case S_MAGIC_MSDOS: + type = "msdos"; + break; + case S_MAGIC_FAT: + type = "fat"; + break; + case S_MAGIC_NCP: + type = "novell"; + break; + case S_MAGIC_NFS: + type = "nfs"; + break; + case S_MAGIC_PROC: + type = "proc"; + break; + case S_MAGIC_SMB: + type = "smb"; + break; + case S_MAGIC_XENIX: + type = "xenix"; + break; + case S_MAGIC_SYSV4: + type = "sysv4"; + break; + case S_MAGIC_SYSV2: + type = "sysv2"; + break; + case S_MAGIC_COH: + type = "coh"; + break; + case S_MAGIC_UFS: + type = "ufs"; + break; + case S_MAGIC_XIAFS: + type = "xia"; + break; + case S_MAGIC_NTFS: + type = "ntfs"; + break; + case S_MAGIC_TMPFS: + type = "tmpfs"; + break; + case S_MAGIC_REISERFS: + type = "reiserfs"; + break; + case S_MAGIC_CRAMFS: + type = "cramfs"; + break; + case S_MAGIC_ROMFS: + type = "romfs"; + break; +# elif __GNU__ + case FSTYPE_UFS: + type = "ufs"; + break; + case FSTYPE_NFS: + type = "nfs"; + break; + case FSTYPE_GFS: + type = "gfs"; + break; + case FSTYPE_LFS: + type = "lfs"; + break; + case FSTYPE_SYSV: + type = "sysv"; + break; + case FSTYPE_FTP: + type = "ftp"; + break; + case FSTYPE_TAR: + type = "tar"; + break; + case FSTYPE_AR: + type = "ar"; + break; + case FSTYPE_CPIO: + type = "cpio"; + break; + case FSTYPE_MSLOSS: + type = "msloss"; + break; + case FSTYPE_CPM: + type = "cpm"; + break; + case FSTYPE_HFS: + type = "hfs"; + break; + case FSTYPE_DTFS: + type = "dtfs"; + break; + case FSTYPE_GRFS: + type = "grfs"; + break; + case FSTYPE_TERM: + type = "term"; + break; + case FSTYPE_DEV: + type = "dev"; + break; + case FSTYPE_PROC: + type = "proc"; + break; + case FSTYPE_IFSOCK: + type = "ifsock"; + break; + case FSTYPE_AFS: + type = "afs"; + break; + case FSTYPE_DFS: + type = "dfs"; + break; + case FSTYPE_PROC9: + type = "proc9"; + break; + case FSTYPE_SOCKET: + type = "socket"; + break; + case FSTYPE_MISC: + type = "misc"; + break; + case FSTYPE_EXT2FS: + type = "ext2/ext3"; + break; + case FSTYPE_HTTP: + type = "http"; + break; + case FSTYPE_MEMFS: + type = "memfs"; + break; + case FSTYPE_ISO9660: + type = "iso9660"; + break; +# endif + default: + type = NULL; + break; + } + + if (type) + return (char *) type; + + { + static char buf[sizeof "UNKNOWN (0x%x)" - 2 + + 2 * sizeof (statfsbuf->f_type)]; + sprintf (buf, "UNKNOWN (0x%x)", statfsbuf->f_type); + return buf; + } +#endif +} + +static char * +human_access (struct stat const *statbuf) +{ + static char modebuf[11]; + mode_string (statbuf->st_mode, modebuf); + modebuf[10] = 0; + return modebuf; +} + +static char * +human_time (time_t const *t) +{ + static char str[80]; + struct tm *tm = localtime (t); + if (tm == NULL) + { + G_fail = 1; + return (char *) _("*** invalid date/time ***"); + } + nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", tm, 0, 0); + return str; +} + +/* print statfs info */ +static void +print_statfs (char *pformat, char m, char const *filename, + void const *data) +{ + STRUCT_STATVFS const *statfsbuf = data; + + switch (m) + { + case 'n': + strcat (pformat, "s"); + printf (pformat, filename); + break; + + case 'i': +#if HAVE_STRUCT_STATXFS_F_FSID___VAL + strcat (pformat, "x %-8x"); + printf (pformat, statfsbuf->f_fsid.__val[0], /* u_long */ + statfsbuf->f_fsid.__val[1]); +#else + strcat (pformat, "Lx"); + printf (pformat, statfsbuf->f_fsid); +#endif + break; + + case 'l': + strcat (pformat, NAMEMAX_FORMAT); + printf (pformat, SB_F_NAMEMAX (statfsbuf)); + break; + case 't': +#if HAVE_STRUCT_STATXFS_F_TYPE + strcat (pformat, "lx"); + printf (pformat, (long int) (statfsbuf->f_type)); /* no equiv. */ +#else + fputc ('*', stdout); +#endif + break; + case 'T': + strcat (pformat, "s"); + printf (pformat, human_fstype (statfsbuf)); + break; + case 'b': + strcat (pformat, PRIdMAX); + printf (pformat, (intmax_t) (statfsbuf->f_blocks)); + break; + case 'f': + strcat (pformat, PRIdMAX); + printf (pformat, (intmax_t) (statfsbuf->f_bfree)); + break; + case 'a': + strcat (pformat, PRIdMAX); + printf (pformat, (intmax_t) (statfsbuf->f_bavail)); + break; + case 's': + strcat (pformat, "ld"); + printf (pformat, (long int) (statfsbuf->f_bsize)); + break; + case 'c': + strcat (pformat, PRIdMAX); + printf (pformat, (intmax_t) (statfsbuf->f_files)); + break; + case 'd': + strcat (pformat, PRIdMAX); + printf (pformat, (intmax_t) (statfsbuf->f_ffree)); + break; + + default: + strcat (pformat, "c"); + printf (pformat, m); + break; + } +} + +/* print stat info */ +static void +print_stat (char *pformat, char m, char const *filename, void const *data) +{ + struct stat *statbuf = (struct stat *) data; + struct passwd *pw_ent; + struct group *gw_ent; + + switch (m) + { + case 'n': + strcat (pformat, "s"); + printf (pformat, filename); + break; + case 'N': + strcat (pformat, "s"); + if (S_ISLNK (statbuf->st_mode)) + { + char *linkname = xreadlink (filename); + if (linkname == NULL) + { + error (0, errno, _("cannot read symbolic link %s"), + quote (filename)); + return; + } + /*printf("\"%s\" -> \"%s\"", filename, linkname); */ + printf (pformat, quote (filename)); + printf (" -> "); + printf (pformat, quote (linkname)); + } + else + { + printf (pformat, quote (filename)); + } + break; + case 'd': + strcat (pformat, "d"); + printf (pformat, (int) statbuf->st_dev); + break; + case 'D': + strcat (pformat, "x"); + printf (pformat, (int) statbuf->st_dev); + break; + case 'i': + strcat (pformat, "d"); + printf (pformat, (int) statbuf->st_ino); + break; + case 'a': + strcat (pformat, "o"); + printf (pformat, statbuf->st_mode & 07777); + break; + case 'A': + strcat (pformat, "s"); + printf (pformat, human_access (statbuf)); + break; + case 'f': + strcat (pformat, "x"); + printf (pformat, statbuf->st_mode); + break; + case 'F': + strcat (pformat, "s"); + printf (pformat, file_type (statbuf)); + break; + case 'h': + strcat (pformat, "d"); + printf (pformat, (int) statbuf->st_nlink); + break; + case 'u': + strcat (pformat, "d"); + printf (pformat, statbuf->st_uid); + break; + case 'U': + strcat (pformat, "s"); + setpwent (); + pw_ent = getpwuid (statbuf->st_uid); + printf (pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN"); + break; + case 'g': + strcat (pformat, "d"); + printf (pformat, statbuf->st_gid); + break; + case 'G': + strcat (pformat, "s"); + setgrent (); + gw_ent = getgrgid (statbuf->st_gid); + printf (pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN"); + break; + case 't': + strcat (pformat, "x"); + printf (pformat, major (statbuf->st_rdev)); + break; + case 'T': + strcat (pformat, "x"); + printf (pformat, minor (statbuf->st_rdev)); + break; + case 's': + strcat (pformat, PRIuMAX); + printf (pformat, (uintmax_t) (statbuf->st_size)); + break; + case 'B': + strcat (pformat, "u"); + printf (pformat, (unsigned int) ST_NBLOCKSIZE); + break; + case 'b': + strcat (pformat, "u"); + printf (pformat, (unsigned int) ST_NBLOCKS (*statbuf)); + break; + case 'o': + strcat (pformat, "d"); + printf (pformat, (int) statbuf->st_blksize); + break; + case 'x': + strcat (pformat, "s"); + printf (pformat, human_time (&(statbuf->st_atime))); + break; + case 'X': + strcat (pformat, "d"); + printf (pformat, (int) statbuf->st_atime); + break; + case 'y': + strcat (pformat, "s"); + printf (pformat, human_time (&(statbuf->st_mtime))); + break; + case 'Y': + strcat (pformat, "d"); + printf (pformat, (int) statbuf->st_mtime); + break; + case 'z': + strcat (pformat, "s"); + printf (pformat, human_time (&(statbuf->st_ctime))); + break; + case 'Z': + strcat (pformat, "d"); + printf (pformat, (int) statbuf->st_ctime); + break; + default: + strcat (pformat, "c"); + printf (pformat, m); + break; + } +} + +static void +print_it (char const *masterformat, char const *filename, + void (*print_func) (char *, char, char const *, void const *), + void const *data) +{ + char *b; + + /* create a working copy of the format string */ + char *format = xstrdup (masterformat); + + char *dest = xmalloc (strlen (format) + 1); + + + b = format; + while (b) + { + char *p = strchr (b, '%'); + if (p != NULL) + { + size_t len; + *p++ = '\0'; + fputs (b, stdout); + + len = strspn (p, "#-+.I 0123456789"); + dest[0] = '%'; + memcpy (dest + 1, p, len); + dest[1 + len] = 0; + p += len; + + switch (*p) + { + case '\0': + case '%': + putchar ('%'); + break; + default: + print_func (dest, *p, filename, data); + break; + } + b = p + 1; + } + else + { + fputs (b, stdout); + b = NULL; + } + } + free (format); + free (dest); + fputc ('\n', stdout); +} + +/* stat the filesystem and print what we find */ +static void +do_statfs (char const *filename, int terse, char const *format) +{ + STRUCT_STATVFS statfsbuf; + int i = statfs (filename, &statfsbuf); + + if (i == -1) + { + error (0, errno, _("cannot read file system information for %s"), + quote (filename)); + return; + } + + if (format == NULL) + { + format = (terse + ? "%n %i %l %t %b %f %a %s %c %d" + : " File: \"%n\"\n" + " ID: %-8i Namelen: %-7l Type: %T\n" + "Blocks: Total: %-10b Free: %-10f Available: %-10a Size: %s\n" + "Inodes: Total: %-10c Free: %-10d"); + } + + print_it (format, filename, print_statfs, &statfsbuf); +} + +/* stat the file and print what we find */ +static void +do_stat (char const *filename, int follow_links, int terse, + char const *format) +{ + struct stat statbuf; + int i = ((follow_links == 1) + ? stat (filename, &statbuf) + : lstat (filename, &statbuf)); + + if (i == -1) + { + error (0, errno, _("cannot stat %s"), quote (filename)); + return; + } + + if (format == NULL) + { + if (terse != 0) + { + format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o"; + } + else + { + /* tmp hack to match orignal output until conditional implemented */ + i = statbuf.st_mode & S_IFMT; + if (i == S_IFCHR || i == S_IFBLK) + { + format = + " File: %N\n" + " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" + "Device: %Dh/%dd\tInode: %-10i Links: %-5h" + " Device type: %t,%T\n" + "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" + "Access: %x\n" "Modify: %y\n" "Change: %z\n"; + } + else + { + format = + " File: %N\n" + " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" + "Device: %Dh/%dd\tInode: %-10i Links: %-5h\n" + "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" + "Access: %x\n" "Modify: %y\n" "Change: %z\n"; + } + } + } + print_it (format, filename, print_stat, &statbuf); +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION] FILE...\n"), program_name); + fputs (_("\ +Display file or filesystem status.\n\ +\n\ + -f, --filesystem display filesystem status instead of file status\n\ + -c --format=FORMAT use the specified FORMAT instead of the default\n\ + -L, --dereference follow links\n\ + -t, --terse print the information in terse form\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + + fputs (_("\n\ +The valid format sequences for files (without --filesystem):\n\ +\n\ + %A Access rights in human readable form\n\ + %a Access rights in octal\n\ + %B The size in bytes of each block reported by `%b'\n\ + %b Number of blocks allocated (see %B)\n\ +"), stdout); + fputs (_("\ + %D Device number in hex\n\ + %d Device number in decimal\n\ + %F File type\n\ + %f Raw mode in hex\n\ + %G Group name of owner\n\ + %g Group ID of owner\n\ +"), stdout); + fputs (_("\ + %h Number of hard links\n\ + %i Inode number\n\ + %N Quoted File name with dereference if symbolic link\n\ + %n File name\n\ + %o IO block size\n\ + %s Total size, in bytes\n\ + %T Minor device type in hex\n\ + %t Major device type in hex\n\ +"), stdout); + fputs (_("\ + %U User name of owner\n\ + %u User ID of owner\n\ + %X Time of last access as seconds since Epoch\n\ + %x Time of last access\n\ + %Y Time of last modification as seconds since Epoch\n\ + %y Time of last modification\n\ + %Z Time of last change as seconds since Epoch\n\ + %z Time of last change\n\ +\n\ +"), stdout); + + fputs (_("\ +Valid format sequences for file systems:\n\ +\n\ + %a Free blocks available to non-superuser\n\ + %b Total data blocks in file system\n\ + %c Total file nodes in file system\n\ + %d Free file nodes in file system\n\ + %f Free blocks in file system\n\ +"), stdout); + fputs (_("\ + %i File System id in hex\n\ + %l Maximum length of filenames\n\ + %n File name\n\ + %s Optimal transfer block size\n\ + %T Type in human readable form\n\ + %t Type in hex\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char *argv[]) +{ + int c; + int i; + int follow_links = 0; + int fs = 0; + int terse = 0; + char *format = NULL; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + while ((c = getopt_long (argc, argv, "c:fLlt", long_options, NULL)) != -1) + { + switch (c) + { + case 'c': + format = optarg; + break; + case 'l': /* deprecated */ + case 'L': + follow_links = 1; + break; + case 'f': + fs = 1; + break; + case 't': + terse = 1; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (argc == optind) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + for (i = optind; i < argc; i++) + { + if (fs == 0) + do_stat (argv[i], follow_links, terse, format); + else + do_statfs (argv[i], terse, format); + } + + exit (G_fail ? EXIT_FAILURE : EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/stty.c b/src/apps/bin/coreutils-5.0/src/stty.c new file mode 100644 index 0000000000..3ec6d33273 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/stty.c @@ -0,0 +1,1948 @@ +/* stty -- change and print terminal line settings + Copyright (C) 1990-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Usage: stty [-ag] [--all] [--save] [-F device] [--file=device] [setting...] + + Options: + -a, --all Write all current settings to stdout in human-readable form. + -g, --save Write all current settings to stdout in stty-readable form. + -F, --file Open and use the specified device instead of stdin + + If no args are given, write to stdout the baud rate and settings that + have been changed from their defaults. Mode reading and changes + are done on the specified device, or stdin if none was specified. + + David MacKenzie */ + +#include + +#ifdef TERMIOS_NEEDS_XOPEN_SOURCE +# define _XOPEN_SOURCE +#endif + +#include +#include +#if HAVE_TERMIOS_H +# include +#endif +#ifdef GWINSZ_IN_SYS_IOCTL +# include +#endif +#ifdef WINSIZE_IN_PTEM +# include +# include +#endif +#ifdef GWINSZ_IN_SYS_PTY +# include +# include +# include +#endif +#include +#if PROTOTYPES +# include +# define VA_START(args, lastarg) va_start(args, lastarg) +#else +# include +# define VA_START(args, lastarg) va_start(args) +#endif + +#include "system.h" +#include "long-options.h" +#include "error.h" +#include "xstrtol.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "stty" + +#define AUTHORS "David MacKenzie" + +#ifndef _POSIX_VDISABLE +# define _POSIX_VDISABLE ((unsigned char) 0) +#endif + +#define Control(c) ((c) & 0x1f) +/* Canonical values for control characters. */ +#ifndef CINTR +# define CINTR Control ('c') +#endif +#ifndef CQUIT +# define CQUIT 28 +#endif +#ifndef CERASE +# define CERASE 127 +#endif +#ifndef CKILL +# define CKILL Control ('u') +#endif +#ifndef CEOF +# define CEOF Control ('d') +#endif +#ifndef CEOL +# define CEOL _POSIX_VDISABLE +#endif +#ifndef CSTART +# define CSTART Control ('q') +#endif +#ifndef CSTOP +# define CSTOP Control ('s') +#endif +#ifndef CSUSP +# define CSUSP Control ('z') +#endif +#if defined(VEOL2) && !defined(CEOL2) +# define CEOL2 _POSIX_VDISABLE +#endif +/* ISC renamed swtch to susp for termios, but we'll accept either name. */ +#if defined(VSUSP) && !defined(VSWTCH) +# define VSWTCH VSUSP +# define CSWTCH CSUSP +#endif +#if defined(VSWTCH) && !defined(CSWTCH) +# define CSWTCH _POSIX_VDISABLE +#endif + +/* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'. + So the default is to disable `swtch.' */ +#if defined (__sparc__) && defined (__svr4__) +# undef CSWTCH +# define CSWTCH _POSIX_VDISABLE +#endif + +#if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */ +# define VWERASE VWERSE +#endif +#if defined(VDSUSP) && !defined (CDSUSP) +# define CDSUSP Control ('y') +#endif +#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */ +# define VREPRINT VRPRNT +#endif +#if defined(VREPRINT) && !defined(CRPRNT) +# define CRPRNT Control ('r') +#endif +#if defined(CREPRINT) && !defined(CRPRNT) +# define CRPRNT Control ('r') +#endif +#if defined(VWERASE) && !defined(CWERASE) +# define CWERASE Control ('w') +#endif +#if defined(VLNEXT) && !defined(CLNEXT) +# define CLNEXT Control ('v') +#endif +#if defined(VDISCARD) && !defined(VFLUSHO) +# define VFLUSHO VDISCARD +#endif +#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */ +# define VFLUSHO VFLUSH +#endif +#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */ +# define ECHOCTL CTLECH +#endif +#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */ +# define ECHOCTL TCTLECH +#endif +#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */ +# define ECHOKE CRTKIL +#endif +#if defined(VFLUSHO) && !defined(CFLUSHO) +# define CFLUSHO Control ('o') +#endif +#if defined(VSTATUS) && !defined(CSTATUS) +# define CSTATUS Control ('t') +#endif + +/* Which speeds to set. */ +enum speed_setting + { + input_speed, output_speed, both_speeds + }; + +/* What to output and how. */ +enum output_type + { + changed, all, recoverable /* Default, -a, -g. */ + }; + +/* Which member(s) of `struct termios' a mode uses. */ +enum mode_type + { + control, input, output, local, combination + }; + +/* Flags for `struct mode_info'. */ +#define SANE_SET 1 /* Set in `sane' mode. */ +#define SANE_UNSET 2 /* Unset in `sane' mode. */ +#define REV 4 /* Can be turned off by prepending `-'. */ +#define OMIT 8 /* Don't display value. */ + +/* Each mode. */ +struct mode_info + { + const char *name; /* Name given on command line. */ + enum mode_type type; /* Which structure element to change. */ + char flags; /* Setting and display options. */ + unsigned long bits; /* Bits to set for this mode. */ + unsigned long mask; /* Other bits to turn off for this mode. */ + }; + +static struct mode_info mode_info[] = +{ + {"parenb", control, REV, PARENB, 0}, + {"parodd", control, REV, PARODD, 0}, + {"cs5", control, 0, CS5, CSIZE}, + {"cs6", control, 0, CS6, CSIZE}, + {"cs7", control, 0, CS7, CSIZE}, + {"cs8", control, 0, CS8, CSIZE}, + {"hupcl", control, REV, HUPCL, 0}, + {"hup", control, REV | OMIT, HUPCL, 0}, + {"cstopb", control, REV, CSTOPB, 0}, + {"cread", control, SANE_SET | REV, CREAD, 0}, + {"clocal", control, REV, CLOCAL, 0}, +#ifdef CRTSCTS + {"crtscts", control, REV, CRTSCTS, 0}, +#endif + + {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0}, + {"brkint", input, SANE_SET | REV, BRKINT, 0}, + {"ignpar", input, REV, IGNPAR, 0}, + {"parmrk", input, REV, PARMRK, 0}, + {"inpck", input, REV, INPCK, 0}, + {"istrip", input, REV, ISTRIP, 0}, + {"inlcr", input, SANE_UNSET | REV, INLCR, 0}, + {"igncr", input, SANE_UNSET | REV, IGNCR, 0}, + {"icrnl", input, SANE_SET | REV, ICRNL, 0}, + {"ixon", input, REV, IXON, 0}, + {"ixoff", input, SANE_UNSET | REV, IXOFF, 0}, + {"tandem", input, REV | OMIT, IXOFF, 0}, +#ifdef IUCLC + {"iuclc", input, SANE_UNSET | REV, IUCLC, 0}, +#endif +#ifdef IXANY + {"ixany", input, SANE_UNSET | REV, IXANY, 0}, +#endif +#ifdef IMAXBEL + {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0}, +#endif + + {"opost", output, SANE_SET | REV, OPOST, 0}, +#ifdef OLCUC + {"olcuc", output, SANE_UNSET | REV, OLCUC, 0}, +#endif +#ifdef OCRNL + {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0}, +#endif +#ifdef ONLCR + {"onlcr", output, SANE_SET | REV, ONLCR, 0}, +#endif +#ifdef ONOCR + {"onocr", output, SANE_UNSET | REV, ONOCR, 0}, +#endif +#ifdef ONLRET + {"onlret", output, SANE_UNSET | REV, ONLRET, 0}, +#endif +#ifdef OFILL + {"ofill", output, SANE_UNSET | REV, OFILL, 0}, +#endif +#ifdef OFDEL + {"ofdel", output, SANE_UNSET | REV, OFDEL, 0}, +#endif +#ifdef NLDLY + {"nl1", output, SANE_UNSET, NL1, NLDLY}, + {"nl0", output, SANE_SET, NL0, NLDLY}, +#endif +#ifdef CRDLY + {"cr3", output, SANE_UNSET, CR3, CRDLY}, + {"cr2", output, SANE_UNSET, CR2, CRDLY}, + {"cr1", output, SANE_UNSET, CR1, CRDLY}, + {"cr0", output, SANE_SET, CR0, CRDLY}, +#endif +#ifdef TABDLY + {"tab3", output, SANE_UNSET, TAB3, TABDLY}, + {"tab2", output, SANE_UNSET, TAB2, TABDLY}, + {"tab1", output, SANE_UNSET, TAB1, TABDLY}, + {"tab0", output, SANE_SET, TAB0, TABDLY}, +#else +# ifdef OXTABS + {"tab3", output, SANE_UNSET, OXTABS, 0}, +# endif +#endif +#ifdef BSDLY + {"bs1", output, SANE_UNSET, BS1, BSDLY}, + {"bs0", output, SANE_SET, BS0, BSDLY}, +#endif +#ifdef VTDLY + {"vt1", output, SANE_UNSET, VT1, VTDLY}, + {"vt0", output, SANE_SET, VT0, VTDLY}, +#endif +#ifdef FFDLY + {"ff1", output, SANE_UNSET, FF1, FFDLY}, + {"ff0", output, SANE_SET, FF0, FFDLY}, +#endif + + {"isig", local, SANE_SET | REV, ISIG, 0}, + {"icanon", local, SANE_SET | REV, ICANON, 0}, +#ifdef IEXTEN + {"iexten", local, SANE_SET | REV, IEXTEN, 0}, +#endif + {"echo", local, SANE_SET | REV, ECHO, 0}, + {"echoe", local, SANE_SET | REV, ECHOE, 0}, + {"crterase", local, REV | OMIT, ECHOE, 0}, + {"echok", local, SANE_SET | REV, ECHOK, 0}, + {"echonl", local, SANE_UNSET | REV, ECHONL, 0}, + {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0}, +#ifdef XCASE + {"xcase", local, SANE_UNSET | REV, XCASE, 0}, +#endif +#ifdef TOSTOP + {"tostop", local, SANE_UNSET | REV, TOSTOP, 0}, +#endif +#ifdef ECHOPRT + {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0}, + {"prterase", local, REV | OMIT, ECHOPRT, 0}, +#endif +#ifdef ECHOCTL + {"echoctl", local, SANE_SET | REV, ECHOCTL, 0}, + {"ctlecho", local, REV | OMIT, ECHOCTL, 0}, +#endif +#ifdef ECHOKE + {"echoke", local, SANE_SET | REV, ECHOKE, 0}, + {"crtkill", local, REV | OMIT, ECHOKE, 0}, +#endif + + {"evenp", combination, REV | OMIT, 0, 0}, + {"parity", combination, REV | OMIT, 0, 0}, + {"oddp", combination, REV | OMIT, 0, 0}, + {"nl", combination, REV | OMIT, 0, 0}, + {"ek", combination, OMIT, 0, 0}, + {"sane", combination, OMIT, 0, 0}, + {"cooked", combination, REV | OMIT, 0, 0}, + {"raw", combination, REV | OMIT, 0, 0}, + {"pass8", combination, REV | OMIT, 0, 0}, + {"litout", combination, REV | OMIT, 0, 0}, + {"cbreak", combination, REV | OMIT, 0, 0}, +#ifdef IXANY + {"decctlq", combination, REV | OMIT, 0, 0}, +#endif +#if defined (TABDLY) || defined (OXTABS) + {"tabs", combination, REV | OMIT, 0, 0}, +#endif +#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) + {"lcase", combination, REV | OMIT, 0, 0}, + {"LCASE", combination, REV | OMIT, 0, 0}, +#endif + {"crt", combination, OMIT, 0, 0}, + {"dec", combination, OMIT, 0, 0}, + + {NULL, control, 0, 0, 0} +}; + +/* Control character settings. */ +struct control_info + { + const char *name; /* Name given on command line. */ + unsigned char saneval; /* Value to set for `stty sane'. */ + int offset; /* Offset in c_cc. */ + }; + +/* Control characters. */ + +static struct control_info control_info[] = +{ + {"intr", CINTR, VINTR}, + {"quit", CQUIT, VQUIT}, + {"erase", CERASE, VERASE}, + {"kill", CKILL, VKILL}, + {"eof", CEOF, VEOF}, + {"eol", CEOL, VEOL}, +#ifdef VEOL2 + {"eol2", CEOL2, VEOL2}, +#endif +#ifdef VSWTCH + {"swtch", CSWTCH, VSWTCH}, +#endif + {"start", CSTART, VSTART}, + {"stop", CSTOP, VSTOP}, + {"susp", CSUSP, VSUSP}, +#ifdef VDSUSP + {"dsusp", CDSUSP, VDSUSP}, +#endif +#ifdef VREPRINT + {"rprnt", CRPRNT, VREPRINT}, +#else +# ifdef CREPRINT /* HPUX 10.20 needs this */ + {"rprnt", CRPRNT, CREPRINT}, +# endif +#endif +#ifdef VWERASE + {"werase", CWERASE, VWERASE}, +#endif +#ifdef VLNEXT + {"lnext", CLNEXT, VLNEXT}, +#endif +#ifdef VFLUSHO + {"flush", CFLUSHO, VFLUSHO}, +#endif +#ifdef VSTATUS + {"status", CSTATUS, VSTATUS}, +#endif + + /* These must be last because of the display routines. */ + {"min", 1, VMIN}, + {"time", 0, VTIME}, + {NULL, 0, 0} +}; + +static const char *visible (unsigned int ch); +static unsigned long baud_to_value (speed_t speed); +static int recover_mode (char *arg, struct termios *mode); +static int screen_columns (void); +static int set_mode (struct mode_info *info, int reversed, + struct termios *mode); +static long integer_arg (const char *s); +static speed_t string_to_baud (const char *arg); +static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode); +static void display_all (struct termios *mode, int fd, const char *device_name); +static void display_changed (struct termios *mode); +static void display_recoverable (struct termios *mode); +static void display_settings (enum output_type output_type, + struct termios *mode, int fd, + const char *device_name); +static void display_speed (struct termios *mode, int fancy); +static void display_window_size (int fancy, int fd, const char *device_name); +static void sane_mode (struct termios *mode); +static void set_control_char (struct control_info *info, + const char *arg, + struct termios *mode); +static void set_speed (enum speed_setting type, const char *arg, + struct termios *mode); +static void set_window_size (int rows, int cols, int fd, + const char *device_name); + +/* The width of the screen, for output wrapping. */ +static int max_col; + +/* Current position, to know when to wrap. */ +static int current_col; + +static struct option longopts[] = +{ + {"all", no_argument, NULL, 'a'}, + {"save", no_argument, NULL, 'g'}, + {"file", required_argument, NULL, 'F'}, + {NULL, 0, NULL, 0} +}; + +/* The name this program was run with. */ +char *program_name; + +/* Print format string MESSAGE and optional args. + Wrap to next line first if it won't fit. + Print a space first unless MESSAGE will start a new line. */ + +/* VARARGS */ +static void +#if PROTOTYPES +wrapf (const char *message,...) +#else + wrapf (message, va_alist) + const char *message; + va_dcl +#endif +{ + va_list args; + char buf[1024]; /* Plenty long for our needs. */ + int buflen; + + VA_START (args, message); + vsprintf (buf, message, args); + va_end (args); + buflen = strlen (buf); + if (0 < current_col + && max_col <= current_col + (0 < current_col) + buflen) + { + putchar ('\n'); + current_col = 0; + } + if (0 < current_col) + { + putchar (' '); + current_col++; + } + fputs (buf, stdout); + current_col += buflen; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [-F DEVICE] [--file=DEVICE] [SETTING]...\n\ + or: %s [-F DEVICE] [--file=DEVICE] [-a|--all]\n\ + or: %s [-F DEVICE] [--file=DEVICE] [-g|--save]\n\ +"), + program_name, program_name, program_name); + fputs (_("\ +Print or change terminal characteristics.\n\ +\n\ + -a, --all print all current settings in human-readable form\n\ + -g, --save print all current settings in a stty-readable form\n\ + -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +Optional - before SETTING indicates negation. An * marks non-POSIX\n\ +settings. The underlying system defines which settings are available.\n\ +"), stdout); + fputs (_("\ +\n\ +Special characters:\n\ + * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\ + eof CHAR CHAR will send an end of file (terminate the input)\n\ + eol CHAR CHAR will end the line\n\ +"), stdout); + fputs (_("\ + * eol2 CHAR alternate CHAR for ending the line\n\ + erase CHAR CHAR will erase the last character typed\n\ + intr CHAR CHAR will send an interrupt signal\n\ + kill CHAR CHAR will erase the current line\n\ +"), stdout); + fputs (_("\ + * lnext CHAR CHAR will enter the next character quoted\n\ + quit CHAR CHAR will send a quit signal\n\ + * rprnt CHAR CHAR will redraw the current line\n\ + start CHAR CHAR will restart the output after stopping it\n\ +"), stdout); + fputs (_("\ + stop CHAR CHAR will stop the output\n\ + susp CHAR CHAR will send a terminal stop signal\n\ + * swtch CHAR CHAR will switch to a different shell layer\n\ + * werase CHAR CHAR will erase the last word typed\n\ +"), stdout); + fputs (_("\ +\n\ +Special settings:\n\ + N set the input and output speeds to N bauds\n\ + * cols N tell the kernel that the terminal has N columns\n\ + * columns N same as cols N\n\ +"), stdout); + fputs (_("\ + ispeed N set the input speed to N\n\ + * line N use line discipline N\n\ + min N with -icanon, set N characters minimum for a completed read\n\ + ospeed N set the output speed to N\n\ +"), stdout); + fputs (_("\ + * rows N tell the kernel that the terminal has N rows\n\ + * size print the number of rows and columns according to the kernel\n\ + speed print the terminal speed\n\ + time N with -icanon, set read timeout of N tenths of a second\n\ +"), stdout); + fputs (_("\ +\n\ +Control settings:\n\ + [-]clocal disable modem control signals\n\ + [-]cread allow input to be received\n\ + * [-]crtscts enable RTS/CTS handshaking\n\ + csN set character size to N bits, N in [5..8]\n\ +"), stdout); + fputs (_("\ + [-]cstopb use two stop bits per character (one with `-')\n\ + [-]hup send a hangup signal when the last process closes the tty\n\ + [-]hupcl same as [-]hup\n\ + [-]parenb generate parity bit in output and expect parity bit in input\n\ + [-]parodd set odd parity (even with `-')\n\ +"), stdout); + fputs (_("\ +\n\ +Input settings:\n\ + [-]brkint breaks cause an interrupt signal\n\ + [-]icrnl translate carriage return to newline\n\ + [-]ignbrk ignore break characters\n\ + [-]igncr ignore carriage return\n\ +"), stdout); + fputs (_("\ + [-]ignpar ignore characters with parity errors\n\ + * [-]imaxbel beep and do not flush a full input buffer on a character\n\ + [-]inlcr translate newline to carriage return\n\ + [-]inpck enable input parity checking\n\ + [-]istrip clear high (8th) bit of input characters\n\ +"), stdout); + fputs (_("\ + * [-]iuclc translate uppercase characters to lowercase\n\ + * [-]ixany let any character restart output, not only start character\n\ + [-]ixoff enable sending of start/stop characters\n\ + [-]ixon enable XON/XOFF flow control\n\ + [-]parmrk mark parity errors (with a 255-0-character sequence)\n\ + [-]tandem same as [-]ixoff\n\ +"), stdout); + fputs (_("\ +\n\ +Output settings:\n\ + * bsN backspace delay style, N in [0..1]\n\ + * crN carriage return delay style, N in [0..3]\n\ + * ffN form feed delay style, N in [0..1]\n\ + * nlN newline delay style, N in [0..1]\n\ +"), stdout); + fputs (_("\ + * [-]ocrnl translate carriage return to newline\n\ + * [-]ofdel use delete characters for fill instead of null characters\n\ + * [-]ofill use fill (padding) characters instead of timing for delays\n\ + * [-]olcuc translate lowercase characters to uppercase\n\ + * [-]onlcr translate newline to carriage return-newline\n\ + * [-]onlret newline performs a carriage return\n\ +"), stdout); + fputs (_("\ + * [-]onocr do not print carriage returns in the first column\n\ + [-]opost postprocess output\n\ + * tabN horizontal tab delay style, N in [0..3]\n\ + * tabs same as tab0\n\ + * -tabs same as tab3\n\ + * vtN vertical tab delay style, N in [0..1]\n\ +"), stdout); + fputs (_("\ +\n\ +Local settings:\n\ + [-]crterase echo erase characters as backspace-space-backspace\n\ + * crtkill kill all line by obeying the echoprt and echoe settings\n\ + * -crtkill kill all line by obeying the echoctl and echok settings\n\ +"), stdout); + fputs (_("\ + * [-]ctlecho echo control characters in hat notation (`^c')\n\ + [-]echo echo input characters\n\ + * [-]echoctl same as [-]ctlecho\n\ + [-]echoe same as [-]crterase\n\ + [-]echok echo a newline after a kill character\n\ +"), stdout); + fputs (_("\ + * [-]echoke same as [-]crtkill\n\ + [-]echonl echo newline even if not echoing other characters\n\ + * [-]echoprt echo erased characters backward, between `\\' and '/'\n\ + [-]icanon enable erase, kill, werase, and rprnt special characters\n\ + [-]iexten enable non-POSIX special characters\n\ +"), stdout); + fputs (_("\ + [-]isig enable interrupt, quit, and suspend special characters\n\ + [-]noflsh disable flushing after interrupt and quit special characters\n\ + * [-]prterase same as [-]echoprt\n\ + * [-]tostop stop background jobs that try to write to the terminal\n\ + * [-]xcase with icanon, escape with `\\' for uppercase characters\n\ +"), stdout); + fputs (_("\ +\n\ +Combination settings:\n\ + * [-]LCASE same as [-]lcase\n\ + cbreak same as -icanon\n\ + -cbreak same as icanon\n\ +"), stdout); + fputs (_("\ + cooked same as brkint ignpar istrip icrnl ixon opost isig\n\ + icanon, eof and eol characters to their default values\n\ + -cooked same as raw\n\ + crt same as echoe echoctl echoke\n\ +"), stdout); + fputs (_("\ + dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\ + kill ^u\n\ + * [-]decctlq same as [-]ixany\n\ + ek erase and kill characters to their default values\n\ + evenp same as parenb -parodd cs7\n\ +"), stdout); + fputs (_("\ + -evenp same as -parenb cs8\n\ + * [-]lcase same as xcase iuclc olcuc\n\ + litout same as -parenb -istrip -opost cs8\n\ + -litout same as parenb istrip opost cs7\n\ + nl same as -icrnl -onlcr\n\ + -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\ +"), stdout); + fputs (_("\ + oddp same as parenb parodd cs7\n\ + -oddp same as -parenb cs8\n\ + [-]parity same as [-]evenp\n\ + pass8 same as -parenb -istrip cs8\n\ + -pass8 same as parenb istrip cs7\n\ +"), stdout); + fputs (_("\ + raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\ + -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\ + -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\ + -raw same as cooked\n\ +"), stdout); + fputs (_("\ + sane same as cread -ignbrk brkint -inlcr -igncr icrnl\n\ + -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\ + -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\ + isig icanon iexten echo echoe echok -echonl -noflsh\n\ + -xcase -tostop -echoprt echoctl echoke, all special\n\ + characters to their default values.\n\ +"), stdout); + fputs (_("\ +\n\ +Handle the tty line connected to standard input. Without arguments,\n\ +prints baud rate, line discipline, and deviations from stty sane. In\n\ +settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\ +127; special values ^- or undef used to disable special characters.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +/* Return 1 if the string contains only valid options. */ +static int +valid_options (char *opt, const char *valid_opts, + const char *valid_arg_opts) +{ + char ch; + + if (*opt++ != '-' || *opt == 0) + return 0; + + while ((ch = *opt)) + { + opt++; + if (strchr (valid_opts, ch)) + continue; + if (strchr (valid_arg_opts, ch)) + return 1; + return 0; + } + return 1; +} + +int +main (int argc, char **argv) +{ + struct termios mode; + enum output_type output_type; + int optc; + int require_set_attr; + int speed_was_set; + int verbose_output; + int recoverable_output; + int k; + int noargs = 1; + char *file_name = NULL; + int fd; + const char *device_name; + const char *posixly_correct = getenv ("POSIXLY_CORRECT"); + int invalid_long_option = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + output_type = changed; + verbose_output = 0; + recoverable_output = 0; + + /* Don't print error messages for unrecognized options. */ + opterr = 0; + + while ((optc = getopt_long (argc, argv, "agF:", longopts, NULL)) != -1) + { + int unrecognized_option = 0; + switch (optc) + { + case 'a': + verbose_output = 1; + output_type = all; + break; + + case 'g': + recoverable_output = 1; + output_type = recoverable; + break; + + case 'F': + if (file_name) + error (2, 0, _("only one device may be specified")); + file_name = optarg; + break; + + default: + unrecognized_option = 1; + break; + } + + if (unrecognized_option) + break; + } + + /* FIXME: what is this?!? */ + if (invalid_long_option) + usage (EXIT_FAILURE); + + /* Clear out the options that have been parsed. This is really + gross, but it's needed because stty SETTINGS look like options to + getopt(), so we need to work around things in a really horrible + way. If any new options are ever added to stty, the short option + MUST NOT be a letter which is the first letter of one of the + possible stty settings. If you change anything about how stty + parses options, be sure it still works with combinations of + short and long options, --, POSIXLY_CORRECT, etc. */ + for (k = 1; k < argc; k++) + { + size_t len; + char *eq; + + if (argv[k] == NULL) + continue; + + /* Handle --, and reset noargs if there are arguments following it. */ + if (STREQ (argv[k], "--")) + { + argv[k] = NULL; + if (k < argc - 1) + noargs = 0; + break; + } + + /* Handle "--file device" */ + len = strlen (argv[k]); + if (len >= 3 && strstr ("--file", argv[k])) + { + argv[k] = NULL; + argv[k + 1] = NULL; + continue; + } + + /* Handle "--all" and "--save". */ + if (len >= 3 + && (strstr ("--all", argv[k]) + || strstr ("--save", argv[k]))) + { + argv[k] = NULL; + continue; + } + + /* Handle "--file=device". */ + eq = strchr (argv[k], '='); + if (eq && eq - argv[k] >= 3) + { + *eq = '\0'; + if (strstr ("--file", argv[k])) + { + argv[k] = NULL; + continue; + } + /* Put the equals sign back for the error message. */ + *eq = '='; + } + + /* Handle "-a", "-ag", "-aF/dev/foo", "-aF /dev/foo", etc. */ + if (valid_options (argv[k], "ag", "F")) + { + /* FIXME: this loses when the device name ends in `F'. + e.g. `stty -F/dev/BARF nl' would clobber the `nl' argument. */ + if (argv[k][strlen (argv[k]) - 1] == 'F') + argv[k + 1] = NULL; + argv[k] = NULL; + } + /* Everything else must be a normal, non-option argument. */ + else + { + noargs = 0; + if (posixly_correct) + break; + } + } + + /* Specifying both -a and -g gets an error. */ + if (verbose_output && recoverable_output) + error (2, 0, + _("the options for verbose and stty-readable output styles are\n\ +mutually exclusive")); + + /* Specifying any other arguments with -a or -g gets an error. */ + if (!noargs && (verbose_output || recoverable_output)) + error (2, 0, _("when specifying an output style, modes may not be set")); + + /* FIXME: it'd be better not to open the file until we've verified + that all arguments are valid. Otherwise, we could end up doing + only some of the requested operations and then failing, probably + leaving things in an undesirable state. */ + + if (file_name) + { + int fdflags; + device_name = file_name; + fd = open (device_name, O_RDONLY | O_NONBLOCK); + if (fd < 0) + error (EXIT_FAILURE, errno, "%s", device_name); + if ((fdflags = fcntl (fd, F_GETFL)) == -1 + || fcntl (fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) + error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"), + device_name); + } + else + { + fd = 0; + device_name = _("standard input"); + } + + /* Initialize to all zeroes so there is no risk memcmp will report a + spurious difference in an uninitialized portion of the structure. */ + memset (&mode, 0, sizeof (mode)); + if (tcgetattr (fd, &mode)) + error (EXIT_FAILURE, errno, "%s", device_name); + + if (verbose_output || recoverable_output || noargs) + { + max_col = screen_columns (); + current_col = 0; + display_settings (output_type, &mode, fd, device_name); + exit (EXIT_SUCCESS); + } + + speed_was_set = 0; + require_set_attr = 0; + k = 1; + while (k < argc) + { + int match_found = 0; + int reversed = 0; + int i; + + if (argv[k] == 0) + { + k++; + continue; + } + + if (argv[k][0] == '-') + { + ++argv[k]; + reversed = 1; + } + for (i = 0; mode_info[i].name != NULL; ++i) + { + if (STREQ (argv[k], mode_info[i].name)) + { + match_found = set_mode (&mode_info[i], reversed, &mode); + require_set_attr = 1; + break; + } + } + if (match_found == 0 && reversed) + { + error (0, 0, _("invalid argument `%s'"), --argv[k]); + usage (EXIT_FAILURE); + } + if (match_found == 0) + { + for (i = 0; control_info[i].name != NULL; ++i) + { + if (STREQ (argv[k], control_info[i].name)) + { + if (k == argc - 1) + { + error (0, 0, _("missing argument to `%s'"), argv[k]); + usage (EXIT_FAILURE); + } + match_found = 1; + ++k; + set_control_char (&control_info[i], argv[k], &mode); + require_set_attr = 1; + break; + } + } + } + if (match_found == 0) + { + if (STREQ (argv[k], "ispeed")) + { + if (k == argc - 1) + { + error (0, 0, _("missing argument to `%s'"), argv[k]); + usage (EXIT_FAILURE); + } + ++k; + set_speed (input_speed, argv[k], &mode); + speed_was_set = 1; + require_set_attr = 1; + } + else if (STREQ (argv[k], "ospeed")) + { + if (k == argc - 1) + { + error (0, 0, _("missing argument to `%s'"), argv[k]); + usage (EXIT_FAILURE); + } + ++k; + set_speed (output_speed, argv[k], &mode); + speed_was_set = 1; + require_set_attr = 1; + } +#ifdef TIOCGWINSZ + else if (STREQ (argv[k], "rows")) + { + if (k == argc - 1) + { + error (0, 0, _("missing argument to `%s'"), argv[k]); + usage (EXIT_FAILURE); + } + ++k; + set_window_size ((int) integer_arg (argv[k]), -1, + fd, device_name); + } + else if (STREQ (argv[k], "cols") + || STREQ (argv[k], "columns")) + { + if (k == argc - 1) + { + error (0, 0, _("missing argument to `%s'"), argv[k]); + usage (EXIT_FAILURE); + } + ++k; + set_window_size (-1, (int) integer_arg (argv[k]), + fd, device_name); + } + else if (STREQ (argv[k], "size")) + { + max_col = screen_columns (); + current_col = 0; + display_window_size (0, fd, device_name); + } +#endif +#ifdef HAVE_C_LINE + else if (STREQ (argv[k], "line")) + { + if (k == argc - 1) + { + error (0, 0, _("missing argument to `%s'"), argv[k]); + usage (EXIT_FAILURE); + } + ++k; + mode.c_line = integer_arg (argv[k]); + require_set_attr = 1; + } +#endif + else if (STREQ (argv[k], "speed")) + { + max_col = screen_columns (); + display_speed (&mode, 0); + } + else if (string_to_baud (argv[k]) != (speed_t) -1) + { + set_speed (both_speeds, argv[k], &mode); + speed_was_set = 1; + require_set_attr = 1; + } + else + { + if (recover_mode (argv[k], &mode) == 0) + { + error (0, 0, _("invalid argument `%s'"), argv[k]); + usage (EXIT_FAILURE); + } + require_set_attr = 1; + } + } + k++; + } + + if (require_set_attr) + { + struct termios new_mode; + + if (tcsetattr (fd, TCSADRAIN, &mode)) + error (EXIT_FAILURE, errno, "%s", device_name); + + /* POSIX (according to Zlotnick's book) tcsetattr returns zero if + it performs *any* of the requested operations. This means it + can report `success' when it has actually failed to perform + some proper subset of the requested operations. To detect + this partial failure, get the current terminal attributes and + compare them to the requested ones. */ + + /* Initialize to all zeroes so there is no risk memcmp will report a + spurious difference in an uninitialized portion of the structure. */ + memset (&new_mode, 0, sizeof (new_mode)); + if (tcgetattr (fd, &new_mode)) + error (EXIT_FAILURE, errno, "%s", device_name); + + /* Normally, one shouldn't use memcmp to compare structures that + may have `holes' containing uninitialized data, but we have been + careful to initialize the storage of these two variables to all + zeroes. One might think it more efficient simply to compare the + modified fields, but that would require enumerating those fields -- + and not all systems have the same fields in this structure. */ + + if (memcmp (&mode, &new_mode, sizeof (mode)) != 0) + { +#ifdef CIBAUD + /* SunOS 4.1.3 (at least) has the problem that after this sequence, + tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2); + sometimes (m1 != m2). The only difference is in the four bits + of the c_cflag field corresponding to the baud rate. To save + Sun users a little confusion, don't report an error if this + happens. But suppress the error only if we haven't tried to + set the baud rate explicitly -- otherwise we'd never give an + error for a true failure to set the baud rate. */ + + new_mode.c_cflag &= (~CIBAUD); + if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0) +#endif + { + error (EXIT_FAILURE, 0, + _("%s: unable to perform all requested operations"), + device_name); +#ifdef TESTING + { + size_t i; + printf (_("new_mode: mode\n")); + for (i = 0; i < sizeof (new_mode); i++) + printf ("0x%02x: 0x%02x\n", + *(((unsigned char *) &new_mode) + i), + *(((unsigned char *) &mode) + i)); + } +#endif + } + } + } + + exit (EXIT_SUCCESS); +} + +/* Return 0 if not applied because not reversible; otherwise return 1. */ + +static int +set_mode (struct mode_info *info, int reversed, struct termios *mode) +{ + tcflag_t *bitsp; + + if (reversed && (info->flags & REV) == 0) + return 0; + + bitsp = mode_type_flag (info->type, mode); + + if (bitsp == NULL) + { + /* Combination mode. */ + if (STREQ (info->name, "evenp") || STREQ (info->name, "parity")) + { + if (reversed) + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + else + mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7; + } + else if (STREQ (info->name, "oddp")) + { + if (reversed) + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + else + mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB; + } + else if (STREQ (info->name, "nl")) + { + if (reversed) + { + mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR; + mode->c_oflag = (mode->c_oflag +#ifdef ONLCR + | ONLCR +#endif + ) +#ifdef OCRNL + & ~OCRNL +#endif +#ifdef ONLRET + & ~ONLRET +#endif + ; + } + else + { + mode->c_iflag = mode->c_iflag & ~ICRNL; +#ifdef ONLCR + mode->c_oflag = mode->c_oflag & ~ONLCR; +#endif + } + } + else if (STREQ (info->name, "ek")) + { + mode->c_cc[VERASE] = CERASE; + mode->c_cc[VKILL] = CKILL; + } + else if (STREQ (info->name, "sane")) + sane_mode (mode); + else if (STREQ (info->name, "cbreak")) + { + if (reversed) + mode->c_lflag |= ICANON; + else + mode->c_lflag &= ~ICANON; + } + else if (STREQ (info->name, "pass8")) + { + if (reversed) + { + mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB; + mode->c_iflag |= ISTRIP; + } + else + { + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + mode->c_iflag &= ~ISTRIP; + } + } + else if (STREQ (info->name, "litout")) + { + if (reversed) + { + mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB; + mode->c_iflag |= ISTRIP; + mode->c_oflag |= OPOST; + } + else + { + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + mode->c_iflag &= ~ISTRIP; + mode->c_oflag &= ~OPOST; + } + } + else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked")) + { + if ((info->name[0] == 'r' && reversed) + || (info->name[0] == 'c' && !reversed)) + { + /* Cooked mode. */ + mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON; + mode->c_oflag |= OPOST; + mode->c_lflag |= ISIG | ICANON; +#if VMIN == VEOF + mode->c_cc[VEOF] = CEOF; +#endif +#if VTIME == VEOL + mode->c_cc[VEOL] = CEOL; +#endif + } + else + { + /* Raw mode. */ + mode->c_iflag = 0; + mode->c_oflag &= ~OPOST; + mode->c_lflag &= ~(ISIG | ICANON +#ifdef XCASE + | XCASE +#endif + ); + mode->c_cc[VMIN] = 1; + mode->c_cc[VTIME] = 0; + } + } +#ifdef IXANY + else if (STREQ (info->name, "decctlq")) + { + if (reversed) + mode->c_iflag |= IXANY; + else + mode->c_iflag &= ~IXANY; + } +#endif +#ifdef TABDLY + else if (STREQ (info->name, "tabs")) + { + if (reversed) + mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3; + else + mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0; + } +#else +# ifdef OXTABS + else if (STREQ (info->name, "tabs")) + { + if (reversed) + mode->c_oflag = mode->c_oflag | OXTABS; + else + mode->c_oflag = mode->c_oflag & ~OXTABS; + } +# endif +#endif +#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) + else if (STREQ (info->name, "lcase") + || STREQ (info->name, "LCASE")) + { + if (reversed) + { + mode->c_lflag &= ~XCASE; + mode->c_iflag &= ~IUCLC; + mode->c_oflag &= ~OLCUC; + } + else + { + mode->c_lflag |= XCASE; + mode->c_iflag |= IUCLC; + mode->c_oflag |= OLCUC; + } + } +#endif + else if (STREQ (info->name, "crt")) + mode->c_lflag |= ECHOE +#ifdef ECHOCTL + | ECHOCTL +#endif +#ifdef ECHOKE + | ECHOKE +#endif + ; + else if (STREQ (info->name, "dec")) + { + mode->c_cc[VINTR] = 3; /* ^C */ + mode->c_cc[VERASE] = 127; /* DEL */ + mode->c_cc[VKILL] = 21; /* ^U */ + mode->c_lflag |= ECHOE +#ifdef ECHOCTL + | ECHOCTL +#endif +#ifdef ECHOKE + | ECHOKE +#endif + ; +#ifdef IXANY + mode->c_iflag &= ~IXANY; +#endif + } + } + else if (reversed) + *bitsp = *bitsp & ~info->mask & ~info->bits; + else + *bitsp = (*bitsp & ~info->mask) | info->bits; + + return 1; +} + +static void +set_control_char (struct control_info *info, const char *arg, + struct termios *mode) +{ + unsigned char value; + + if (STREQ (info->name, "min") || STREQ (info->name, "time")) + value = integer_arg (arg); + else if (arg[0] == '\0' || arg[1] == '\0') + value = arg[0]; + else if (STREQ (arg, "^-") || STREQ (arg, "undef")) + value = _POSIX_VDISABLE; + else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */ + { + if (arg[1] == '?') + value = 127; + else + value = arg[1] & ~0140; /* Non-letters get weird results. */ + } + else + value = integer_arg (arg); + mode->c_cc[info->offset] = value; +} + +static void +set_speed (enum speed_setting type, const char *arg, struct termios *mode) +{ + speed_t baud; + + baud = string_to_baud (arg); + if (type == input_speed || type == both_speeds) + cfsetispeed (mode, baud); + if (type == output_speed || type == both_speeds) + cfsetospeed (mode, baud); +} + +#ifdef TIOCGWINSZ + +static int +get_win_size (int fd, struct winsize *win) +{ + int err = ioctl (fd, TIOCGWINSZ, (char *) win); + return err; +} + +static void +set_window_size (int rows, int cols, int fd, const char *device_name) +{ + struct winsize win; + + if (get_win_size (fd, &win)) + { + if (errno != EINVAL) + error (EXIT_FAILURE, errno, "%s", device_name); + memset (&win, 0, sizeof (win)); + } + + if (rows >= 0) + win.ws_row = rows; + if (cols >= 0) + win.ws_col = cols; + +# ifdef TIOCSSIZE + /* Alexander Dupuy wrote: + The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel. + This comment from sys/ttold.h describes Sun's twisted logic - a better + test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0). + At any rate, the problem is gone in Solaris 2.x. + + Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ, + but they can be disambiguated by checking whether a "struct ttysize" + structure's "ts_lines" field is greater than 64K or not. If so, + it's almost certainly a "struct winsize" instead. + + At any rate, the bug manifests itself when ws_row == 0; the symptom is + that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) + + ws_ypixel. Since GNU stty sets rows and columns separately, this bug + caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while + "stty cols 0 rows 0" would do the right thing. On a little-endian + machine like the sun386i, the problem is the same, but for ws_col == 0. + + The workaround is to do the ioctl once with row and col = 1 to set the + pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */ + + if (win.ws_row == 0 || win.ws_col == 0) + { + struct ttysize ttysz; + + ttysz.ts_lines = win.ws_row; + ttysz.ts_cols = win.ws_col; + + win.ws_row = 1; + win.ws_col = 1; + + if (ioctl (fd, TIOCSWINSZ, (char *) &win)) + error (EXIT_FAILURE, errno, "%s", device_name); + + if (ioctl (fd, TIOCSSIZE, (char *) &ttysz)) + error (EXIT_FAILURE, errno, "%s", device_name); + return; + } +# endif + + if (ioctl (fd, TIOCSWINSZ, (char *) &win)) + error (EXIT_FAILURE, errno, "%s", device_name); +} + +static void +display_window_size (int fancy, int fd, const char *device_name) +{ + struct winsize win; + + if (get_win_size (fd, &win)) + { + if (errno != EINVAL) + error (EXIT_FAILURE, errno, "%s", device_name); + if (!fancy) + error (EXIT_FAILURE, 0, + _("%s: no size information for this device"), device_name); + } + else + { + wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n", + win.ws_row, win.ws_col); + if (!fancy) + current_col = 0; + } +} +#endif + +static int +screen_columns (void) +{ +#ifdef TIOCGWINSZ + struct winsize win; + + /* With Solaris 2.[123], this ioctl fails and errno is set to + EINVAL for telnet (but not rlogin) sessions. + On ISC 3.0, it fails for the console and the serial port + (but it works for ptys). + It can also fail on any system when stdout isn't a tty. + In case of any failure, just use the default. */ + if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col) + return win.ws_col; +#endif + { + /* Use $COLUMNS if it's in [1..INT_MAX-1]. */ + char *col_string = getenv ("COLUMNS"); + long n_columns; + if (!(col_string != NULL + && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK + && 0 < n_columns + && n_columns < INT_MAX)) + n_columns = 80; + return n_columns; + } +} + +static tcflag_t * +mode_type_flag (enum mode_type type, struct termios *mode) +{ + switch (type) + { + case control: + return &mode->c_cflag; + + case input: + return &mode->c_iflag; + + case output: + return &mode->c_oflag; + + case local: + return &mode->c_lflag; + + case combination: + return NULL; + + default: + abort (); + } +} + +static void +display_settings (enum output_type output_type, struct termios *mode, + int fd, const char *device_name) +{ + switch (output_type) + { + case changed: + display_changed (mode); + break; + + case all: + display_all (mode, fd, device_name); + break; + + case recoverable: + display_recoverable (mode); + break; + } +} + +static void +display_changed (struct termios *mode) +{ + int i; + int empty_line; + tcflag_t *bitsp; + unsigned long mask; + enum mode_type prev_type = control; + + display_speed (mode, 1); +#ifdef HAVE_C_LINE + wrapf ("line = %d;", mode->c_line); +#endif + putchar ('\n'); + current_col = 0; + + empty_line = 1; + for (i = 0; !STREQ (control_info[i].name, "min"); ++i) + { + if (mode->c_cc[control_info[i].offset] == control_info[i].saneval) + continue; + /* If swtch is the same as susp, don't print both. */ +#if VSWTCH == VSUSP + if (STREQ (control_info[i].name, "swtch")) + continue; +#endif + /* If eof uses the same slot as min, only print whichever applies. */ +#if VEOF == VMIN + if ((mode->c_lflag & ICANON) == 0 + && (STREQ (control_info[i].name, "eof") + || STREQ (control_info[i].name, "eol"))) + continue; +#endif + + empty_line = 0; + wrapf ("%s = %s;", control_info[i].name, + visible (mode->c_cc[control_info[i].offset])); + } + if ((mode->c_lflag & ICANON) == 0) + { + wrapf ("min = %d; time = %d;\n", (int) mode->c_cc[VMIN], + (int) mode->c_cc[VTIME]); + } + else if (empty_line == 0) + putchar ('\n'); + current_col = 0; + + empty_line = 1; + for (i = 0; mode_info[i].name != NULL; ++i) + { + if (mode_info[i].flags & OMIT) + continue; + if (mode_info[i].type != prev_type) + { + if (empty_line == 0) + { + putchar ('\n'); + current_col = 0; + empty_line = 1; + } + prev_type = mode_info[i].type; + } + + bitsp = mode_type_flag (mode_info[i].type, mode); + mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; + if ((*bitsp & mask) == mode_info[i].bits) + { + if (mode_info[i].flags & SANE_UNSET) + { + wrapf ("%s", mode_info[i].name); + empty_line = 0; + } + } + else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV)) + { + wrapf ("-%s", mode_info[i].name); + empty_line = 0; + } + } + if (empty_line == 0) + putchar ('\n'); + current_col = 0; +} + +static void +display_all (struct termios *mode, int fd, const char *device_name) +{ + int i; + tcflag_t *bitsp; + unsigned long mask; + enum mode_type prev_type = control; + + display_speed (mode, 1); +#ifdef TIOCGWINSZ + display_window_size (1, fd, device_name); +#endif +#ifdef HAVE_C_LINE + wrapf ("line = %d;", mode->c_line); +#endif + putchar ('\n'); + current_col = 0; + + for (i = 0; ! STREQ (control_info[i].name, "min"); ++i) + { + /* If swtch is the same as susp, don't print both. */ +#if VSWTCH == VSUSP + if (STREQ (control_info[i].name, "swtch")) + continue; +#endif + /* If eof uses the same slot as min, only print whichever applies. */ +#if VEOF == VMIN + if ((mode->c_lflag & ICANON) == 0 + && (STREQ (control_info[i].name, "eof") + || STREQ (control_info[i].name, "eol"))) + continue; +#endif + wrapf ("%s = %s;", control_info[i].name, + visible (mode->c_cc[control_info[i].offset])); + } +#if VEOF == VMIN + if ((mode->c_lflag & ICANON) == 0) +#endif + wrapf ("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]); + if (current_col != 0) + putchar ('\n'); + current_col = 0; + + for (i = 0; mode_info[i].name != NULL; ++i) + { + if (mode_info[i].flags & OMIT) + continue; + if (mode_info[i].type != prev_type) + { + putchar ('\n'); + current_col = 0; + prev_type = mode_info[i].type; + } + + bitsp = mode_type_flag (mode_info[i].type, mode); + mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; + if ((*bitsp & mask) == mode_info[i].bits) + wrapf ("%s", mode_info[i].name); + else if (mode_info[i].flags & REV) + wrapf ("-%s", mode_info[i].name); + } + putchar ('\n'); + current_col = 0; +} + +static void +display_speed (struct termios *mode, int fancy) +{ + if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode)) + wrapf (fancy ? "speed %lu baud;" : "%lu\n", + baud_to_value (cfgetospeed (mode))); + else + wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n", + baud_to_value (cfgetispeed (mode)), + baud_to_value (cfgetospeed (mode))); + if (!fancy) + current_col = 0; +} + +static void +display_recoverable (struct termios *mode) +{ + int i; + + printf ("%lx:%lx:%lx:%lx", + (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag, + (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag); + for (i = 0; i < NCCS; ++i) + printf (":%x", (unsigned int) mode->c_cc[i]); + putchar ('\n'); +} + +static int +recover_mode (char *arg, struct termios *mode) +{ + int i, n; + unsigned int chr; + unsigned long iflag, oflag, cflag, lflag; + + /* Scan into temporaries since it is too much trouble to figure out + the right format for `tcflag_t'. */ + if (sscanf (arg, "%lx:%lx:%lx:%lx%n", + &iflag, &oflag, &cflag, &lflag, &n) != 4) + return 0; + mode->c_iflag = iflag; + mode->c_oflag = oflag; + mode->c_cflag = cflag; + mode->c_lflag = lflag; + arg += n; + for (i = 0; i < NCCS; ++i) + { + if (sscanf (arg, ":%x%n", &chr, &n) != 1) + return 0; + mode->c_cc[i] = chr; + arg += n; + } + + /* Fail if there are too many fields. */ + if (*arg != '\0') + return 0; + + return 1; +} + +struct speed_map +{ + const char *string; /* ASCII representation. */ + speed_t speed; /* Internal form. */ + unsigned long value; /* Numeric value. */ +}; + +struct speed_map speeds[] = +{ + {"0", B0, 0}, + {"50", B50, 50}, + {"75", B75, 75}, + {"110", B110, 110}, + {"134", B134, 134}, + {"134.5", B134, 134}, + {"150", B150, 150}, + {"200", B200, 200}, + {"300", B300, 300}, + {"600", B600, 600}, + {"1200", B1200, 1200}, + {"1800", B1800, 1800}, + {"2400", B2400, 2400}, + {"4800", B4800, 4800}, + {"9600", B9600, 9600}, + {"19200", B19200, 19200}, + {"38400", B38400, 38400}, + {"exta", B19200, 19200}, + {"extb", B38400, 38400}, +#ifdef B57600 + {"57600", B57600, 57600}, +#endif +#ifdef B115200 + {"115200", B115200, 115200}, +#endif +#ifdef B230400 + {"230400", B230400, 230400}, +#endif +#ifdef B460800 + {"460800", B460800, 460800}, +#endif +#ifdef B500000 + {"500000", B500000, 500000}, +#endif +#ifdef B576000 + {"576000", B576000, 576000}, +#endif +#ifdef B921600 + {"921600", B921600, 921600}, +#endif +#ifdef B1000000 + {"1000000", B1000000, 1000000}, +#endif +#ifdef B1152000 + {"1152000", B1152000, 1152000}, +#endif +#ifdef B1500000 + {"1500000", B1500000, 1500000}, +#endif +#ifdef B2000000 + {"2000000", B2000000, 2000000}, +#endif +#ifdef B2500000 + {"2500000", B2500000, 2500000}, +#endif +#ifdef B3000000 + {"3000000", B3000000, 3000000}, +#endif +#ifdef B3500000 + {"3500000", B3500000, 3500000}, +#endif +#ifdef B4000000 + {"4000000", B4000000, 4000000}, +#endif + {NULL, 0, 0} +}; + +static speed_t +string_to_baud (const char *arg) +{ + int i; + + for (i = 0; speeds[i].string != NULL; ++i) + if (STREQ (arg, speeds[i].string)) + return speeds[i].speed; + return (speed_t) -1; +} + +static unsigned long +baud_to_value (speed_t speed) +{ + int i; + + for (i = 0; speeds[i].string != NULL; ++i) + if (speed == speeds[i].speed) + return speeds[i].value; + return 0; +} + +static void +sane_mode (struct termios *mode) +{ + int i; + tcflag_t *bitsp; + + for (i = 0; control_info[i].name; ++i) + { +#if VMIN == VEOF + if (STREQ (control_info[i].name, "min")) + break; +#endif + mode->c_cc[control_info[i].offset] = control_info[i].saneval; + } + + for (i = 0; mode_info[i].name != NULL; ++i) + { + if (mode_info[i].flags & SANE_SET) + { + bitsp = mode_type_flag (mode_info[i].type, mode); + *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits; + } + else if (mode_info[i].flags & SANE_UNSET) + { + bitsp = mode_type_flag (mode_info[i].type, mode); + *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits; + } + } +} + +/* Return a string that is the printable representation of character CH. */ +/* Adapted from `cat' by Torbjorn Granlund. */ + +static const char * +visible (unsigned int ch) +{ + static char buf[10]; + char *bpout = buf; + + if (ch == _POSIX_VDISABLE) + return ""; + + if (ch >= 32) + { + if (ch < 127) + *bpout++ = ch; + else if (ch == 127) + { + *bpout++ = '^'; + *bpout++ = '?'; + } + else + { + *bpout++ = 'M', + *bpout++ = '-'; + if (ch >= 128 + 32) + { + if (ch < 128 + 127) + *bpout++ = ch - 128; + else + { + *bpout++ = '^'; + *bpout++ = '?'; + } + } + else + { + *bpout++ = '^'; + *bpout++ = ch - 128 + 64; + } + } + } + else + { + *bpout++ = '^'; + *bpout++ = ch + 64; + } + *bpout = '\0'; + return (const char *) buf; +} + +/* Parse string S as an integer, using decimal radix by default, + but allowing octal and hex numbers as in C. */ +/* From `od' by Richard Stallman. */ + +static long +integer_arg (const char *s) +{ + long value; + if (xstrtol (s, NULL, 0, &value, "bB") != LONGINT_OK) + { + error (0, 0, _("invalid integer argument `%s'"), s); + usage (EXIT_FAILURE); + } + return value; +} diff --git a/src/apps/bin/coreutils-5.0/src/su.c b/src/apps/bin/coreutils-5.0/src/su.c new file mode 100644 index 0000000000..ae67bf9f38 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/su.c @@ -0,0 +1,583 @@ +/* su for GNU. Run a shell with substitute user and group IDs. + Copyright (C) 1992-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Run a shell with the real and effective UID and GID and groups + of USER, default `root'. + + The shell run is taken from USER's password entry, /bin/sh if + none is specified there. If the account has a password, su + prompts for a password unless run by a user with real UID 0. + + Does not change the current directory. + Sets `HOME' and `SHELL' from the password entry for USER, and if + USER is not root, sets `USER' and `LOGNAME' to USER. + The subshell is not a login shell. + + If one or more ARGs are given, they are passed as additional + arguments to the subshell. + + Does not handle /bin/sh or other shells specially + (setting argv[0] to "-su", passing -c only to certain shells, etc.). + I don't see the point in doing that, and it's ugly. + + This program intentionally does not support a "wheel group" that + restricts who can su to UID 0 accounts. RMS considers that to + be fascist. + + Options: + -, -l, --login Make the subshell a login shell. + Unset all environment variables except + TERM, HOME and SHELL (set as above), and USER + and LOGNAME (set unconditionally as above), and + set PATH to a default value. + Change to USER's home directory. + Prepend "-" to the shell's name. + -c, --commmand=COMMAND + Pass COMMAND to the subshell with a -c option + instead of starting an interactive shell. + -f, --fast Pass the -f option to the subshell. + -m, -p, --preserve-environment + Do not change HOME, USER, LOGNAME, SHELL. + Run $SHELL instead of USER's shell from /etc/passwd + unless not the superuser and USER's shell is + restricted. + Overridden by --login and --shell. + -s, --shell=shell Run SHELL instead of USER's shell from /etc/passwd + unless not the superuser and USER's shell is + restricted. + + Compile-time options: + -DSYSLOG_SUCCESS Log successful su's (by default, to root) with syslog. + -DSYSLOG_FAILURE Log failed su's (by default, to root) with syslog. + + -DSYSLOG_NON_ROOT Log all su's, not just those to root (UID 0). + Never logs attempted su's to nonexistent accounts. + + Written by David MacKenzie . */ + +#include +#include +#include +#include +#include +#include + +/* Hide any system prototype for getusershell. + This is necessary because some Cray systems have a conflicting + prototype (returning `int') in . */ +#define getusershell _getusershell_sys_proto_ + +#include "system.h" +#include "closeout.h" +#include "dirname.h" + +#undef getusershell + +#if HAVE_SYSLOG_H && HAVE_SYSLOG +# include +#else +# undef SYSLOG_SUCCESS +# undef SYSLOG_FAILURE +# undef SYSLOG_NON_ROOT +#endif + +#if HAVE_SYS_PARAM_H +# include +#endif + +#ifndef HAVE_ENDGRENT +# define endgrent() ((void) 0) +#endif + +#ifndef HAVE_ENDPWENT +# define endpwent() ((void) 0) +#endif + +#if HAVE_SHADOW_H +# include +#endif + +#include "error.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "su" + +#define AUTHORS "David MacKenzie" + +#if HAVE_PATHS_H +# include +#endif + +/* The default PATH for simulated logins to non-superuser accounts. */ +#ifdef _PATH_DEFPATH +# define DEFAULT_LOGIN_PATH _PATH_DEFPATH +#else +# define DEFAULT_LOGIN_PATH ":/usr/ucb:/bin:/usr/bin" +#endif + +/* The default PATH for simulated logins to superuser accounts. */ +#ifdef _PATH_DEFPATH_ROOT +# define DEFAULT_ROOT_LOGIN_PATH _PATH_DEFPATH_ROOT +#else +# define DEFAULT_ROOT_LOGIN_PATH "/usr/ucb:/bin:/usr/bin:/etc" +#endif + +/* The shell to run if none is given in the user's passwd entry. */ +#define DEFAULT_SHELL "/bin/sh" + +/* The user to become if none is specified. */ +#define DEFAULT_USER "root" + +char *crypt (); +char *getpass (); +char *getusershell (); +void endusershell (); +void setusershell (); + +extern char **environ; + +static void run_shell (const char *, const char *, char **) + ATTRIBUTE_NORETURN; + +/* The name this program was run with. */ +char *program_name; + +/* If nonzero, pass the `-f' option to the subshell. */ +static int fast_startup; + +/* If nonzero, simulate a login instead of just starting a shell. */ +static int simulate_login; + +/* If nonzero, change some environment vars to indicate the user su'd to. */ +static int change_environment; + +static struct option const longopts[] = +{ + {"command", required_argument, 0, 'c'}, + {"fast", no_argument, NULL, 'f'}, + {"login", no_argument, NULL, 'l'}, + {"preserve-environment", no_argument, &change_environment, 0}, + {"shell", required_argument, 0, 's'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0} +}; + +/* Add VAL to the environment, checking for out of memory errors. */ + +static void +xputenv (char *val) +{ + if (putenv (val)) + xalloc_die (); +} + +/* Return a newly-allocated string whose contents concatenate + those of S1, S2, S3. */ + +static char * +concat (const char *s1, const char *s2, const char *s3) +{ + int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); + char *result = (char *) xmalloc (len1 + len2 + len3 + 1); + + strcpy (result, s1); + strcpy (result + len1, s2); + strcpy (result + len1 + len2, s3); + result[len1 + len2 + len3] = 0; + + return result; +} + +/* Return the number of elements in ARR, a null-terminated array. */ + +static int +elements (char **arr) +{ + int n = 0; + + for (n = 0; *arr; ++arr) + ++n; + return n; +} + +#if defined (SYSLOG_SUCCESS) || defined (SYSLOG_FAILURE) +/* Log the fact that someone has run su to the user given by PW; + if SUCCESSFUL is nonzero, they gave the correct password, etc. */ + +static void +log_su (const struct passwd *pw, int successful) +{ + const char *new_user, *old_user, *tty; + +# ifndef SYSLOG_NON_ROOT + if (pw->pw_uid) + return; +# endif + new_user = pw->pw_name; + /* The utmp entry (via getlogin) is probably the best way to identify + the user, especially if someone su's from a su-shell. */ + old_user = getlogin (); + if (old_user == NULL) + { + /* getlogin can fail -- usually due to lack of utmp entry. + Resort to getpwuid. */ + struct passwd *pwd = getpwuid (getuid ()); + old_user = (pwd ? pwd->pw_name : ""); + } + tty = ttyname (2); + if (tty == NULL) + tty = "none"; + /* 4.2BSD openlog doesn't have the third parameter. */ + openlog (base_name (program_name), 0 +# ifdef LOG_AUTH + , LOG_AUTH +# endif + ); + syslog (LOG_NOTICE, +# ifdef SYSLOG_NON_ROOT + "%s(to %s) %s on %s", +# else + "%s%s on %s", +# endif + successful ? "" : "FAILED SU ", +# ifdef SYSLOG_NON_ROOT + new_user, +# endif + old_user, tty); + closelog (); +} +#endif + +/* Ask the user for a password. + Return 1 if the user gives the correct password for entry PW, + 0 if not. Return 1 without asking for a password if run by UID 0 + or if PW has an empty password. */ + +static int +correct_password (const struct passwd *pw) +{ + char *unencrypted, *encrypted, *correct; +#if HAVE_GETSPNAM && HAVE_STRUCT_SPWD_SP_PWDP + /* Shadow passwd stuff for SVR3 and maybe other systems. */ + struct spwd *sp = getspnam (pw->pw_name); + + endspent (); + if (sp) + correct = sp->sp_pwdp; + else +#endif + correct = pw->pw_passwd; + + if (getuid () == 0 || correct == 0 || correct[0] == '\0') + return 1; + + unencrypted = getpass (_("Password:")); + if (unencrypted == NULL) + { + error (0, 0, _("getpass: cannot open /dev/tty")); + return 0; + } + encrypted = crypt (unencrypted, correct); + memset (unencrypted, 0, strlen (unencrypted)); + return strcmp (encrypted, correct) == 0; +} + +/* Update `environ' for the new shell based on PW, with SHELL being + the value for the SHELL environment variable. */ + +static void +modify_environment (const struct passwd *pw, const char *shell) +{ + char *term; + + if (simulate_login) + { + /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH. + Unset all other environment variables. */ + term = getenv ("TERM"); + environ = (char **) xmalloc (2 * sizeof (char *)); + environ[0] = 0; + if (term) + xputenv (concat ("TERM", "=", term)); + xputenv (concat ("HOME", "=", pw->pw_dir)); + xputenv (concat ("SHELL", "=", shell)); + xputenv (concat ("USER", "=", pw->pw_name)); + xputenv (concat ("LOGNAME", "=", pw->pw_name)); + xputenv (concat ("PATH", "=", (pw->pw_uid + ? DEFAULT_LOGIN_PATH + : DEFAULT_ROOT_LOGIN_PATH))); + } + else + { + /* Set HOME, SHELL, and if not becoming a super-user, + USER and LOGNAME. */ + if (change_environment) + { + xputenv (concat ("HOME", "=", pw->pw_dir)); + xputenv (concat ("SHELL", "=", shell)); + if (pw->pw_uid) + { + xputenv (concat ("USER", "=", pw->pw_name)); + xputenv (concat ("LOGNAME", "=", pw->pw_name)); + } + } + } +} + +/* Become the user and group(s) specified by PW. */ + +static void +change_identity (const struct passwd *pw) +{ +#ifdef HAVE_INITGROUPS + errno = 0; + if (initgroups (pw->pw_name, pw->pw_gid) == -1) + error (EXIT_FAILURE, errno, _("cannot set groups")); + endgrent (); +#endif + if (setgid (pw->pw_gid)) + error (EXIT_FAILURE, errno, _("cannot set group id")); + if (setuid (pw->pw_uid)) + error (EXIT_FAILURE, errno, _("cannot set user id")); +} + +/* Run SHELL, or DEFAULT_SHELL if SHELL is empty. + If COMMAND is nonzero, pass it to the shell with the -c option. + If ADDITIONAL_ARGS is nonzero, pass it to the shell as more + arguments. */ + +static void +run_shell (const char *shell, const char *command, char **additional_args) +{ + const char **args; + int argno = 1; + + if (additional_args) + args = (const char **) xmalloc (sizeof (char *) + * (10 + elements (additional_args))); + else + args = (const char **) xmalloc (sizeof (char *) * 10); + if (simulate_login) + { + char *arg0; + char *shell_basename; + + shell_basename = base_name (shell); + arg0 = xmalloc (strlen (shell_basename) + 2); + arg0[0] = '-'; + strcpy (arg0 + 1, shell_basename); + args[0] = arg0; + } + else + args[0] = base_name (shell); + if (fast_startup) + args[argno++] = "-f"; + if (command) + { + args[argno++] = "-c"; + args[argno++] = command; + } + if (additional_args) + for (; *additional_args; ++additional_args) + args[argno++] = *additional_args; + args[argno] = NULL; + execv (shell, (char **) args); + + { + int exit_status = (errno == ENOENT ? 127 : 126); + error (0, errno, "%s", shell); + exit (exit_status); + } +} + +/* Return 1 if SHELL is a restricted shell (one not returned by + getusershell), else 0, meaning it is a standard shell. */ + +static int +restricted_shell (const char *shell) +{ + char *line; + + setusershell (); + while ((line = getusershell ()) != NULL) + { + if (*line != '#' && strcmp (line, shell) == 0) + { + endusershell (); + return 0; + } + } + endusershell (); + return 1; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [-] [USER [ARG]...]\n"), program_name); + fputs (_("\ +Change the effective user id and group id to that of USER.\n\ +\n\ + -, -l, --login make the shell a login shell\n\ + -c, --commmand=COMMAND pass a single COMMAND to the shell with -c\n\ + -f, --fast pass -f to the shell (for csh or tcsh)\n\ + -m, --preserve-environment do not reset environment variables\n\ + -p same as -m\n\ + -s, --shell=SHELL run SHELL if /etc/shells allows it\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +A mere - implies -l. If USER not given, assume root.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + close_stdout (); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int optc; + const char *new_user = DEFAULT_USER; + char *command = 0; + char **additional_args = 0; + char *shell = 0; + struct passwd *pw; + struct passwd pw_copy; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + fast_startup = 0; + simulate_login = 0; + change_environment = 1; + + while ((optc = getopt_long (argc, argv, "c:flmps:", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + + case 'c': + command = optarg; + break; + + case 'f': + fast_startup = 1; + break; + + case 'l': + simulate_login = 1; + break; + + case 'm': + case 'p': + change_environment = 0; + break; + + case 's': + shell = optarg; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (optind < argc && !strcmp (argv[optind], "-")) + { + simulate_login = 1; + ++optind; + } + if (optind < argc) + new_user = argv[optind++]; + if (optind < argc) + additional_args = argv + optind; + + pw = getpwnam (new_user); + if (pw == 0) + error (EXIT_FAILURE, 0, _("user %s does not exist"), new_user); + endpwent (); + + /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER + is a username that is retrieved via NIS (YP), but that doesn't have + a default shell listed. */ + if (pw->pw_shell == NULL || pw->pw_shell[0] == '\0') + pw->pw_shell = (char *) DEFAULT_SHELL; + + /* Make a copy of the password information and point pw at the local + copy instead. Otherwise, some systems (e.g. Linux) would clobber + the static data through the getlogin call from log_su. */ + pw_copy = *pw; + pw = &pw_copy; + pw->pw_name = xstrdup (pw->pw_name); + pw->pw_dir = xstrdup (pw->pw_dir); + pw->pw_shell = xstrdup (pw->pw_shell); + + if (!correct_password (pw)) + { +#ifdef SYSLOG_FAILURE + log_su (pw, 0); +#endif + error (EXIT_FAILURE, 0, _("incorrect password")); + } +#ifdef SYSLOG_SUCCESS + else + { + log_su (pw, 1); + } +#endif + + if (shell == 0 && change_environment == 0) + shell = getenv ("SHELL"); + if (shell != 0 && getuid () && restricted_shell (pw->pw_shell)) + { + /* The user being su'd to has a nonstandard shell, and so is + probably a uucp account or has restricted access. Don't + compromise the account by allowing access with a standard + shell. */ + error (0, 0, _("using restricted shell %s"), pw->pw_shell); + shell = 0; + } + if (shell == 0) + { + shell = xstrdup (pw->pw_shell); + } + modify_environment (pw, shell); + + change_identity (pw); + if (simulate_login && chdir (pw->pw_dir)) + error (0, errno, _("warning: cannot change directory to %s"), pw->pw_dir); + + run_shell (shell, command, additional_args); +} diff --git a/src/apps/bin/coreutils-5.0/src/sum.c b/src/apps/bin/coreutils-5.0/src/sum.c new file mode 100644 index 0000000000..f3fa819667 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/sum.c @@ -0,0 +1,273 @@ +/* sum -- checksum and count the blocks in a file + Copyright (C) 86, 89, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Like BSD sum or SysV sum -r, except like SysV sum if -s option is given. */ + +/* Written by Kayvan Aghaiepour and David MacKenzie. */ + +#include + +#include +#include +#include +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "human.h" +#include "safe-read.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "sum" + +#define AUTHORS N_ ("Kayvan Aghaiepour and David MacKenzie") + +/* The name this program was run with. */ +char *program_name; + +/* Nonzero if any of the files read were the standard input. */ +static int have_read_stdin; + +static struct option const longopts[] = +{ + {"sysv", no_argument, NULL, 's'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + fputs (_("\ +Print checksum and block counts for each FILE.\n\ +\n\ + -r defeat -s, use BSD sum algorithm, use 1K blocks\n\ + -s, --sysv use System V sum algorithm, use 512 bytes blocks\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +With no FILE, or when FILE is -, read standard input.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Calculate and print the rotated checksum and the size in 1K blocks + of file FILE, or of the standard input if FILE is "-". + If PRINT_NAME is >1, print FILE next to the checksum and size. + The checksum varies depending on sizeof(int). + Return 0 if successful, -1 if an error occurs. */ + +static int +bsd_sum_file (const char *file, int print_name) +{ + register FILE *fp; + register int checksum = 0; /* The checksum mod 2^16. */ + register uintmax_t total_bytes = 0; /* The number of bytes. */ + register int ch; /* Each character read. */ + char hbuf[LONGEST_HUMAN_READABLE + 1]; + + if (STREQ (file, "-")) + { + fp = stdin; + have_read_stdin = 1; + } + else + { + fp = fopen (file, "r"); + if (fp == NULL) + { + error (0, errno, "%s", file); + return -1; + } + } + /* Need binary I/O, or else byte counts and checksums are incorrect. */ + SET_BINARY (fileno(fp)); + + while ((ch = getc (fp)) != EOF) + { + total_bytes++; + checksum = (checksum >> 1) + ((checksum & 1) << 15); + checksum += ch; + checksum &= 0xffff; /* Keep it within bounds. */ + } + + if (ferror (fp)) + { + error (0, errno, "%s", file); + if (!STREQ (file, "-")) + fclose (fp); + return -1; + } + + if (!STREQ (file, "-") && fclose (fp) == EOF) + { + error (0, errno, "%s", file); + return -1; + } + + printf ("%05d %5s", checksum, + human_readable (total_bytes, hbuf, human_ceiling, 1, 1024)); + if (print_name > 1) + printf (" %s", file); + putchar ('\n'); + + return 0; +} + +/* Calculate and print the checksum and the size in 512-byte blocks + of file FILE, or of the standard input if FILE is "-". + If PRINT_NAME is >0, print FILE next to the checksum and size. + Return 0 if successful, -1 if an error occurs. */ + +static int +sysv_sum_file (const char *file, int print_name) +{ + int fd; + unsigned char buf[8192]; + uintmax_t total_bytes = 0; + char hbuf[LONGEST_HUMAN_READABLE + 1]; + int r; + int checksum; + + /* The sum of all the input bytes, modulo (UINT_MAX + 1). */ + unsigned int s = 0; + + if (STREQ (file, "-")) + { + fd = 0; + have_read_stdin = 1; + } + else + { + fd = open (file, O_RDONLY); + if (fd == -1) + { + error (0, errno, "%s", file); + return -1; + } + } + /* Need binary I/O, or else byte counts and checksums are incorrect. */ + SET_BINARY (fd); + + while (1) + { + size_t i; + size_t bytes_read = safe_read (fd, buf, sizeof buf); + + if (bytes_read == 0) + break; + + if (bytes_read == SAFE_READ_ERROR) + { + error (0, errno, "%s", file); + if (!STREQ (file, "-")) + close (fd); + return -1; + } + + for (i = 0; i < bytes_read; i++) + s += buf[i]; + total_bytes += bytes_read; + } + + if (!STREQ (file, "-") && close (fd) == -1) + { + error (0, errno, "%s", file); + return -1; + } + + r = (s & 0xffff) + ((s & 0xffffffff) >> 16); + checksum = (r & 0xffff) + (r >> 16); + + printf ("%d %s", checksum, + human_readable (total_bytes, hbuf, human_ceiling, 1, 512)); + if (print_name) + printf (" %s", file); + putchar ('\n'); + + return 0; +} + +int +main (int argc, char **argv) +{ + int errors = 0; + int optc; + int files_given; + int (*sum_func) (const char *, int) = bsd_sum_file; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + have_read_stdin = 0; + + while ((optc = getopt_long (argc, argv, "rs", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + + case 'r': /* For SysV compatibility. */ + sum_func = bsd_sum_file; + break; + + case 's': + sum_func = sysv_sum_file; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + files_given = argc - optind; + if (files_given == 0) + { + if ((*sum_func) ("-", files_given) < 0) + errors = 1; + } + else + for (; optind < argc; optind++) + if ((*sum_func) (argv[optind], files_given) < 0) + errors = 1; + + if (have_read_stdin && fclose (stdin) == EOF) + error (EXIT_FAILURE, errno, "-"); + exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/sync.c b/src/apps/bin/coreutils-5.0/src/sync.c new file mode 100644 index 0000000000..2b8c50ee8c --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/sync.c @@ -0,0 +1,74 @@ +/* sync - update the super block + Copyright (C) 1994-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Jim Meyering */ + +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "long-options.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "sync" + +#define AUTHORS "Jim Meyering" + +/* The name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]\n"), program_name); + fputs (_("\ +Force changed blocks to disk, update the super block.\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION, + AUTHORS, usage); + + if (argc != 1) + error (0, 0, _("ignoring all arguments")); + + sync (); + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/sys2.h b/src/apps/bin/coreutils-5.0/src/sys2.h new file mode 100644 index 0000000000..1030bc3cd6 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/sys2.h @@ -0,0 +1,658 @@ +/* WARNING -- this file is temporary. It is shared between the + sh-utils, fileutils, and textutils packages. Once I find a little + more time, I'll merge the remaining things in system.h and everything + in this file will go back there. */ + +#ifndef S_IFMT +# define S_IFMT 0170000 +#endif + +#if STAT_MACROS_BROKEN +# undef S_ISBLK +# undef S_ISCHR +# undef S_ISDIR +# undef S_ISDOOR +# undef S_ISFIFO +# undef S_ISLNK +# undef S_ISNAM +# undef S_ISMPB +# undef S_ISMPC +# undef S_ISNWK +# undef S_ISREG +# undef S_ISSOCK +#endif + + +#ifndef S_ISBLK +# ifdef S_IFBLK +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +# else +# define S_ISBLK(m) 0 +# endif +#endif + +#ifndef S_ISCHR +# ifdef S_IFCHR +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +# else +# define S_ISCHR(m) 0 +# endif +#endif + +#ifndef S_ISDIR +# ifdef S_IFDIR +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# else +# define S_ISDIR(m) 0 +# endif +#endif + +#ifndef S_ISDOOR /* Solaris 2.5 and up */ +# ifdef S_IFDOOR +# define S_ISDOOR(m) (((m) & S_IFMT) == S_IFDOOR) +# else +# define S_ISDOOR(m) 0 +# endif +#endif + +#ifndef S_ISFIFO +# ifdef S_IFIFO +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +# else +# define S_ISFIFO(m) 0 +# endif +#endif + +#ifndef S_ISLNK +# ifdef S_IFLNK +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +# else +# define S_ISLNK(m) 0 +# endif +#endif + +#ifndef S_ISMPB /* V7 */ +# ifdef S_IFMPB +# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) +# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) +# else +# define S_ISMPB(m) 0 +# define S_ISMPC(m) 0 +# endif +#endif + +#ifndef S_ISNAM /* Xenix */ +# ifdef S_IFNAM +# define S_ISNAM(m) (((m) & S_IFMT) == S_IFNAM) +# else +# define S_ISNAM(m) 0 +# endif +#endif + +#ifndef S_ISNWK /* HP/UX */ +# ifdef S_IFNWK +# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) +# else +# define S_ISNWK(m) 0 +# endif +#endif + +#ifndef S_ISREG +# ifdef S_IFREG +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +# else +# define S_ISREG(m) 0 +# endif +#endif + +#ifndef S_ISSOCK +# ifdef S_IFSOCK +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +# else +# define S_ISSOCK(m) 0 +# endif +#endif + + +#ifndef S_TYPEISSEM +# ifdef S_INSEM +# define S_TYPEISSEM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSEM) +# else +# define S_TYPEISSEM(p) 0 +# endif +#endif + +#ifndef S_TYPEISSHM +# ifdef S_INSHD +# define S_TYPEISSHM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSHD) +# else +# define S_TYPEISSHM(p) 0 +# endif +#endif + +#ifndef S_TYPEISMQ +# define S_TYPEISMQ(p) 0 +#endif + + +/* If any of the following are undefined, + define them to their de facto standard values. */ +#if !S_ISUID +# define S_ISUID 04000 +#endif +#if !S_ISGID +# define S_ISGID 02000 +#endif + +/* S_ISVTX is a common extension to POSIX. */ +#ifndef S_ISVTX +# define S_ISVTX 01000 +#endif + +#if !S_IRUSR && S_IREAD +# define S_IRUSR S_IREAD +#endif +#if !S_IRUSR +# define S_IRUSR 00400 +#endif +#if !S_IRGRP +# define S_IRGRP (S_IRUSR >> 3) +#endif +#if !S_IROTH +# define S_IROTH (S_IRUSR >> 6) +#endif + +#if !S_IWUSR && S_IWRITE +# define S_IWUSR S_IWRITE +#endif +#if !S_IWUSR +# define S_IWUSR 00200 +#endif +#if !S_IWGRP +# define S_IWGRP (S_IWUSR >> 3) +#endif +#if !S_IWOTH +# define S_IWOTH (S_IWUSR >> 6) +#endif + +#if !S_IXUSR && S_IEXEC +# define S_IXUSR S_IEXEC +#endif +#if !S_IXUSR +# define S_IXUSR 00100 +#endif +#if !S_IXGRP +# define S_IXGRP (S_IXUSR >> 3) +#endif +#if !S_IXOTH +# define S_IXOTH (S_IXUSR >> 6) +#endif + +#if !S_IRWXU +# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif +#if !S_IRWXG +# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +#endif +#if !S_IRWXO +# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#endif + +/* S_IXUGO is a common extension to POSIX. */ +#if !S_IXUGO +# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) +#endif + +#ifndef S_IRWXUGO +# define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO) +#endif + +/* All the mode bits that can be affected by chmod. */ +#define CHMOD_MODE_BITS \ + (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) + +#ifdef ST_MTIM_NSEC +# define ST_TIME_CMP_NS(a, b, ns) ((a).ns < (b).ns ? -1 : (a).ns > (b).ns) +#else +# define ST_TIME_CMP_NS(a, b, ns) 0 +#endif +#define ST_TIME_CMP(a, b, s, ns) \ + ((a).s < (b).s ? -1 : (a).s > (b).s ? 1 : ST_TIME_CMP_NS(a, b, ns)) +#define ATIME_CMP(a, b) ST_TIME_CMP (a, b, st_atime, st_atim.ST_MTIM_NSEC) +#define CTIME_CMP(a, b) ST_TIME_CMP (a, b, st_ctime, st_ctim.ST_MTIM_NSEC) +#define MTIME_CMP(a, b) ST_TIME_CMP (a, b, st_mtime, st_mtim.ST_MTIM_NSEC) + +#ifndef RETSIGTYPE +# define RETSIGTYPE void +#endif + +#if __GNUC__ +# ifndef alloca +# define alloca __builtin_alloca +# endif +#else +# if HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + # pragma alloca +# else +# ifdef _WIN32 +# include +# include +# else +# ifndef alloca +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +#ifdef __DJGPP__ + /* We need the declaration of setmode. */ +# include + /* We need the declaration of __djgpp_set_ctrl_c. */ +# include +#endif + +#if HAVE_STDINT_H +# include +#endif + +#if HAVE_INTTYPES_H +# include /* for the definition of UINTMAX_MAX */ +#endif + +#if !defined PRIdMAX || PRI_MACROS_BROKEN +# undef PRIdMAX +# define PRIdMAX (sizeof (uintmax_t) == sizeof (long) ? "ld" : "lld") +#endif +#if !defined PRIoMAX || PRI_MACROS_BROKEN +# undef PRIoMAX +# define PRIoMAX (sizeof (uintmax_t) == sizeof (long) ? "lo" : "llo") +#endif +#if !defined PRIuMAX || PRI_MACROS_BROKEN +# undef PRIuMAX +# define PRIuMAX (sizeof (uintmax_t) == sizeof (long) ? "lu" : "llu") +#endif +#if !defined PRIxMAX || PRI_MACROS_BROKEN +# undef PRIxMAX +# define PRIxMAX (sizeof (uintmax_t) == sizeof (long) ? "lx" : "llx") +#endif + +#include + +/* Jim Meyering writes: + + "... Some ctype macros are valid only for character codes that + isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when + using /bin/cc or gcc but without giving an ansi option). So, all + ctype uses should be through macros like ISPRINT... If + STDC_HEADERS is defined, then autoconf has verified that the ctype + macros don't need to be guarded with references to isascii. ... + Defining isascii to 1 should let any compiler worth its salt + eliminate the && through constant folding." + + Bruno Haible adds: + + "... Furthermore, isupper(c) etc. have an undefined result if c is + outside the range -1 <= c <= 255. One is tempted to write isupper(c) + with c being of type `char', but this is wrong if c is an 8-bit + character >= 128 which gets sign-extended to a negative value. + The macro ISUPPER protects against this as well." */ + +#if STDC_HEADERS || (!defined (isascii) && !HAVE_ISASCII) +# define IN_CTYPE_DOMAIN(c) 1 +#else +# define IN_CTYPE_DOMAIN(c) isascii(c) +#endif + +#ifdef isblank +# define ISBLANK(c) (IN_CTYPE_DOMAIN (c) && isblank (c)) +#else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#endif +#ifdef isgraph +# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isgraph (c)) +#else +# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isprint (c) && !isspace (c)) +#endif + +/* This is defined in on at least Solaris2.6 systems. */ +#undef ISPRINT + +#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c)) +#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c)) +#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) +#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl (c)) +#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c)) +#define ISPUNCT(c) (IN_CTYPE_DOMAIN (c) && ispunct (c)) +#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) +#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c)) +#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c)) +#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) + +#if STDC_HEADERS +# define TOLOWER(Ch) tolower (Ch) +# define TOUPPER(Ch) toupper (Ch) +#else +# define TOLOWER(Ch) (ISUPPER (Ch) ? tolower (Ch) : (Ch)) +# define TOUPPER(Ch) (ISLOWER (Ch) ? toupper (Ch) : (Ch)) +#endif + +/* ISDIGIT differs from ISDIGIT_LOCALE, as follows: + - Its arg may be any int or unsigned int; it need not be an unsigned char. + - It's guaranteed to evaluate its argument exactly once. + - It's typically faster. + POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to + ISDIGIT_LOCALE unless it's important to use the locale's definition + of `digit' even when the host does not conform to POSIX. */ +#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) + +/* Take care of NLS matters. */ + +#if HAVE_LOCALE_H +# include +#else +# define setlocale(Category, Locale) /* empty */ +#endif + +#include "gettext.h" + +#define _(msgid) gettext (msgid) +#define N_(msgid) msgid + +#ifndef HAVE_SETLOCALE +# define HAVE_SETLOCALE 0 +#endif + +#define STREQ(a, b) (strcmp ((a), (b)) == 0) + +#if !HAVE_DECL_FREE +void free (); +#endif + +#if !HAVE_DECL_MALLOC +char *malloc (); +#endif + +#if !HAVE_DECL_MEMCHR +char *memchr (); +#endif + +#if !HAVE_DECL_REALLOC +char *realloc (); +#endif + +#if !HAVE_DECL_STPCPY +# ifndef stpcpy +char *stpcpy (); +# endif +#endif + +#if !HAVE_DECL_STRNDUP +char *strndup (); +#endif + +#if !HAVE_DECL_STRSTR +char *strstr (); +#endif + +#if !HAVE_DECL_GETENV +char *getenv (); +#endif + +#if !HAVE_DECL_LSEEK +off_t lseek (); +#endif + +/* This is needed on some AIX systems. */ +#if !HAVE_DECL_STRTOUL +unsigned long strtoul (); +#endif + +/* This is needed on some AIX systems. */ +#if !HAVE_DECL_STRTOULL && HAVE_UNSIGNED_LONG_LONG +unsigned long long strtoull (); +#endif + +#if !HAVE_DECL_GETLOGIN +char *getlogin (); +#endif + +#if !HAVE_DECL_TTYNAME +char *ttyname (); +#endif + +#if !HAVE_DECL_GETEUID +uid_t geteuid (); +#endif + +#if !HAVE_DECL_GETPWUID +struct passwd *getpwuid (); +#endif + +#if !HAVE_DECL_GETGRGID +struct group *getgrgid (); +#endif + +#if !HAVE_DECL_GETUID +uid_t getuid (); +#endif + +#include "xalloc.h" + +#if ! defined HAVE_MEMPCPY && ! defined mempcpy +/* Be CAREFUL that there are no side effects in N. */ +# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N))) +#endif + +/* Include automatically-generated macros for unlocked I/O. */ +#include "unlocked-io.h" + +#define SAME_INODE(Stat_buf_1, Stat_buf_2) \ + ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \ + && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev) + +#define DOT_OR_DOTDOT(Basename) \ + (Basename[0] == '.' && (Basename[1] == '\0' \ + || (Basename[1] == '.' && Basename[2] == '\0'))) + +#if SETVBUF_REVERSED +# define SETVBUF(Stream, Buffer, Type, Size) \ + setvbuf (Stream, Type, Buffer, Size) +#else +# define SETVBUF(Stream, Buffer, Type, Size) \ + setvbuf (Stream, Buffer, Type, Size) +#endif + +/* Factor out some of the common --help and --version processing code. */ + +/* These enum values cannot possibly conflict with the option values + ordinarily used by commands, including CHAR_MAX + 1, etc. Avoid + CHAR_MIN - 1, as it may equal -1, the getopt end-of-options value. */ +enum +{ + GETOPT_HELP_CHAR = (CHAR_MIN - 2), + GETOPT_VERSION_CHAR = (CHAR_MIN - 3) +}; + +#define GETOPT_HELP_OPTION_DECL \ + "help", no_argument, 0, GETOPT_HELP_CHAR +#define GETOPT_VERSION_OPTION_DECL \ + "version", no_argument, 0, GETOPT_VERSION_CHAR + +#define case_GETOPT_HELP_CHAR \ + case GETOPT_HELP_CHAR: \ + usage (EXIT_SUCCESS); \ + break; + +#define HELP_OPTION_DESCRIPTION \ + _(" --help display this help and exit\n") +#define VERSION_OPTION_DESCRIPTION \ + _(" --version output version information and exit\n") + +#include "closeout.h" +#include "version-etc.h" + +#define case_GETOPT_VERSION_CHAR(Program_name, Authors) \ + case GETOPT_VERSION_CHAR: \ + version_etc (stdout, Program_name, PACKAGE, VERSION, Authors); \ + exit (EXIT_SUCCESS); \ + break; + +#ifndef MAX +# define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +# define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +/* The extra casts work around common compiler bugs. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. + It is necessary at least when t == time_t. */ +#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ + ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) +#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) + +/* Upper bound on the string length of an integer converted to string. + 302 / 1000 is ceil (log10 (2.0)). Subtract 1 for the sign bit; + add 1 for integer division truncation; add 1 more for a minus sign. */ +#define INT_STRLEN_BOUND(t) ((sizeof (t) * CHAR_BIT - 1) * 302 / 1000 + 2) + +#ifndef CHAR_MIN +# define CHAR_MIN TYPE_MINIMUM (char) +#endif + +#ifndef CHAR_MAX +# define CHAR_MAX TYPE_MAXIMUM (char) +#endif + +#ifndef SCHAR_MIN +# define SCHAR_MIN (-1 - SCHAR_MAX) +#endif + +#ifndef SCHAR_MAX +# define SCHAR_MAX (CHAR_MAX == UCHAR_MAX ? CHAR_MAX / 2 : CHAR_MAX) +#endif + +#ifndef UCHAR_MAX +# define UCHAR_MAX TYPE_MAXIMUM (unsigned char) +#endif + +#ifndef SHRT_MIN +# define SHRT_MIN TYPE_MINIMUM (short int) +#endif + +#ifndef SHRT_MAX +# define SHRT_MAX TYPE_MAXIMUM (short int) +#endif + +#ifndef INT_MAX +# define INT_MAX TYPE_MAXIMUM (int) +#endif + +#ifndef INT_MIN +# define INT_MIN TYPE_MINIMUM (int) +#endif + +#ifndef UINT_MAX +# define UINT_MAX TYPE_MAXIMUM (unsigned int) +#endif + +#ifndef LONG_MAX +# define LONG_MAX TYPE_MAXIMUM (long) +#endif + +#ifndef ULONG_MAX +# define ULONG_MAX TYPE_MAXIMUM (unsigned long) +#endif + +#ifndef SIZE_MAX +# define SIZE_MAX TYPE_MAXIMUM (size_t) +#endif + +#ifndef SSIZE_MAX +# define SSIZE_MAX TYPE_MAXIMUM (ssize_t) +#endif + +#ifndef UINTMAX_MAX +# define UINTMAX_MAX TYPE_MAXIMUM (uintmax_t) +#endif + +#ifndef OFF_T_MIN +# define OFF_T_MIN TYPE_MINIMUM (off_t) +#endif + +#ifndef OFF_T_MAX +# define OFF_T_MAX TYPE_MAXIMUM (off_t) +#endif + +#ifndef UID_T_MAX +# define UID_T_MAX TYPE_MAXIMUM (uid_t) +#endif + +#ifndef GID_T_MAX +# define GID_T_MAX TYPE_MAXIMUM (gid_t) +#endif + +#ifndef PID_T_MAX +# define PID_T_MAX TYPE_MAXIMUM (pid_t) +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +/* Use this to suppress gcc's `...may be used before initialized' warnings. */ +#ifdef lint +# define IF_LINT(Code) Code +#else +# define IF_LINT(Code) /* empty */ +#endif + +#ifndef __attribute__ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ +# define __attribute__(x) +# endif +#endif + +#ifndef ATTRIBUTE_NORETURN +# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) +#endif + +#ifndef ATTRIBUTE_UNUSED +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif + +#if defined strdupa +# define ASSIGN_STRDUPA(DEST, S) \ + do { DEST = strdupa(S); } while (0) +#else +# define ASSIGN_STRDUPA(DEST, S) \ + do \ + { \ + const char *s_ = (S); \ + size_t len_ = strlen (s_) + 1; \ + char *tmp_dest_ = (char *) alloca (len_); \ + DEST = memcpy (tmp_dest_, (s_), len_); \ + } \ + while (0) +#endif + +#ifndef EOVERFLOW +# define EOVERFLOW EINVAL +#endif + +#if ! HAVE_FSEEKO && ! defined fseeko +# define fseeko(s, o, w) ((o) == (long) (o) \ + ? fseek (s, o, w) \ + : (errno = EOVERFLOW, -1)) +#endif diff --git a/src/apps/bin/coreutils-5.0/src/system.h b/src/apps/bin/coreutils-5.0/src/system.h new file mode 100644 index 0000000000..637d30282e --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/system.h @@ -0,0 +1,298 @@ +/* system-dependent definitions for fileutils, textutils, and sh-utils packages. + Copyright (C) 1989, 1991-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Include sys/types.h before this file. */ + +#if 2 <= __GLIBC__ && 2 <= __GLIBC_MINOR__ +# if ! defined _SYS_TYPES_H +you must include before including this file +# endif +#endif + +#include + +#if !defined HAVE_MKFIFO +# define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0)) +#endif + +#if HAVE_SYS_PARAM_H +# include +#endif + +/* should be included before any preprocessor test + of _POSIX_VERSION. */ +#if HAVE_UNISTD_H +# include +#endif + +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif + +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +#endif + +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + + +#if HAVE_LIMITS_H +/* limits.h must come before pathmax.h because limits.h on some systems + undefs PATH_MAX, whereas pathmax.h sets PATH_MAX. */ +# include +#endif + +#include "pathmax.h" + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +/* Since major is a function on SVR4, we can't use `ifndef major'. */ +#if MAJOR_IN_MKDEV +# include +# define HAVE_MAJOR +#endif +#if MAJOR_IN_SYSMACROS +# include +# define HAVE_MAJOR +#endif +#ifdef major /* Might be defined in sys/types.h. */ +# define HAVE_MAJOR +#endif + +#ifndef HAVE_MAJOR +# define major(dev) (((dev) >> 8) & 0xff) +# define minor(dev) ((dev) & 0xff) +# define makedev(maj, min) (((maj) << 8) | (min)) +#endif +#undef HAVE_MAJOR + +#if HAVE_UTIME_H +# include +#endif + +/* Some systems (even some that do have ) don't declare this + structure anywhere. */ +#ifndef HAVE_STRUCT_UTIMBUF +struct utimbuf +{ + long actime; + long modtime; +}; +#endif + +/* Don't use bcopy! Use memmove if source and destination may overlap, + memcpy otherwise. */ + +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#else +# include +#endif +#if ! HAVE_DECL_MEMRCHR +void *memrchr (const void *, int, size_t); +#endif + +#include +#ifndef errno +extern int errno; +#endif + + +#if HAVE_STDBOOL_H +# include +#else +typedef enum {false = 0, true = 1} bool; +#endif + + +#if HAVE_STDLIB_H +# define getopt system_getopt +# include +# undef getopt +#endif + +/* The following test is to work around the gross typo in + systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE + is defined to 0, not 1. */ +#if !EXIT_FAILURE +# undef EXIT_FAILURE +# define EXIT_FAILURE 1 +#endif + +#ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +#endif + +#if HAVE_FCNTL_H +# include +#else +# include +#endif + +#if !defined SEEK_SET +# define SEEK_SET 0 +# define SEEK_CUR 1 +# define SEEK_END 2 +#endif +#ifndef F_OK +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 +#endif + +/* For systems that distinguish between text and binary I/O. + O_BINARY is usually declared in fcntl.h */ +#if !defined O_BINARY && defined _O_BINARY + /* For MSC-compatible compilers. */ +# define O_BINARY _O_BINARY +# define O_TEXT _O_TEXT +#endif + +#ifdef __BEOS__ + /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */ +# undef O_BINARY +# undef O_TEXT +#endif + +#if O_BINARY +# ifndef __DJGPP__ +# define setmode _setmode +# define fileno(_fp) _fileno (_fp) +# endif /* not DJGPP */ +# define SET_MODE(_f, _m) setmode (_f, _m) +# define SET_BINARY(_f) do {if (!isatty(_f)) setmode (_f, O_BINARY);} while (0) +# define SET_BINARY2(_f1, _f2) \ + do { \ + if (!isatty (_f1)) \ + { \ + setmode (_f1, O_BINARY); \ + if (!isatty (_f2)) \ + setmode (_f2, O_BINARY); \ + } \ + } while(0) +#else +# define SET_MODE(_f, _m) (void)0 +# define SET_BINARY(f) (void)0 +# define SET_BINARY2(f1,f2) (void)0 +# define O_BINARY 0 +# define O_TEXT 0 +#endif /* O_BINARY */ + +#if HAVE_DIRENT_H +# include +# define NLENGTH(direct) (strlen((direct)->d_name)) +#else /* not HAVE_DIRENT_H */ +# define dirent direct +# define NLENGTH(direct) ((direct)->d_namlen) +# if HAVE_SYS_NDIR_H +# include +# endif /* HAVE_SYS_NDIR_H */ +# if HAVE_SYS_DIR_H +# include +# endif /* HAVE_SYS_DIR_H */ +# if HAVE_NDIR_H +# include +# endif /* HAVE_NDIR_H */ +#endif /* HAVE_DIRENT_H */ + +#if CLOSEDIR_VOID +/* Fake a return value. */ +# define CLOSEDIR(d) (closedir (d), 0) +#else +# define CLOSEDIR(d) closedir (d) +#endif + +/* Get or fake the disk device blocksize. + Usually defined by sys/param.h (if at all). */ +#if !defined DEV_BSIZE && defined BSIZE +# define DEV_BSIZE BSIZE +#endif +#if !defined DEV_BSIZE && defined BBSIZE /* SGI */ +# define DEV_BSIZE BBSIZE +#endif +#ifndef DEV_BSIZE +# define DEV_BSIZE 4096 +#endif + +/* Extract or fake data from a `struct stat'. + ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes. + ST_NBLOCKS: Number of blocks in the file, including indirect blocks. + ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */ +#ifndef HAVE_STRUCT_STAT_ST_BLOCKS +# define ST_BLKSIZE(statbuf) DEV_BSIZE +# if defined _POSIX_SOURCE || !defined BSIZE /* fileblocks.c uses BSIZE. */ +# define ST_NBLOCKS(statbuf) \ + ((statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0)) +# else /* !_POSIX_SOURCE && BSIZE */ +# define ST_NBLOCKS(statbuf) \ + (S_ISREG ((statbuf).st_mode) \ + || S_ISDIR ((statbuf).st_mode) \ + ? st_blocks ((statbuf).st_size) : 0) +# endif /* !_POSIX_SOURCE && BSIZE */ +#else /* HAVE_STRUCT_STAT_ST_BLOCKS */ +/* Some systems, like Sequents, return st_blksize of 0 on pipes. + Also, when running `rsh hpux11-system cat any-file', cat would + determine that the output stream had an st_blksize of 2147421096. + So here we arbitrarily limit the `optimal' block size to 4MB. + If anyone knows of a system for which the legitimate value for + st_blksize can exceed 4MB, please report it as a bug in this code. */ +# define ST_BLKSIZE(statbuf) ((0 < (statbuf).st_blksize \ + && (statbuf).st_blksize <= (1 << 22)) /* 4MB */ \ + ? (statbuf).st_blksize : DEV_BSIZE) +# if defined hpux || defined __hpux__ || defined __hpux +/* HP-UX counts st_blocks in 1024-byte units. + This loses when mixing HP-UX and BSD filesystems with NFS. */ +# define ST_NBLOCKSIZE 1024 +# else /* !hpux */ +# if defined _AIX && defined _I386 +/* AIX PS/2 counts st_blocks in 4K units. */ +# define ST_NBLOCKSIZE (4 * 1024) +# else /* not AIX PS/2 */ +# if defined _CRAY +# define ST_NBLOCKS(statbuf) \ + (S_ISREG ((statbuf).st_mode) \ + || S_ISDIR ((statbuf).st_mode) \ + ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0) +# endif /* _CRAY */ +# endif /* not AIX PS/2 */ +# endif /* !hpux */ +#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */ + +#ifndef ST_NBLOCKS +# define ST_NBLOCKS(statbuf) ((statbuf).st_blocks) +#endif + +#ifndef ST_NBLOCKSIZE +# define ST_NBLOCKSIZE 512 +#endif + +#include "sys2.h" diff --git a/src/apps/bin/coreutils-5.0/src/tac-pipe.c b/src/apps/bin/coreutils-5.0/src/tac-pipe.c new file mode 100644 index 0000000000..e8e41aed75 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/tac-pipe.c @@ -0,0 +1,248 @@ +/* FIXME */ +#include + +/* FIXME: this is small for testing */ +#define BUFFER_SIZE (8) + +#define LEN(X, I) ((X)->p[(I)].one_past_end - (X)->p[(I)].start) +#define EMPTY(X) ((X)->n_bufs == 1 && LEN (X, 0) == 0) + +#define ONE_PAST_END(X, I) ((X)->p[(I)].one_past_end) + +struct Line_ptr +{ + size_t i; + char *ptr; +}; +typedef struct Line_ptr Line_ptr; + +struct B_pair +{ + char *start; + char *one_past_end; +}; + +struct Buf +{ + size_t n_bufs; + struct obstack obs; + struct B_pair *p; +}; +typedef struct Buf Buf; + +static int +buf_init_from_stdin (Buf *x, int eol_byte) +{ + int last_byte_is_eol_byte = 1; + int fail = 0; + +#define OBS (&(x->obs)) + obstack_init (OBS); + + while (1) + { + char *buf = (char *) malloc (BUFFER_SIZE); + int bytes_read; + + if (buf == NULL) + { + /* Fall back on the code that relies on a temporary file. + Write all buffers to that file and free them. */ + /* FIXME */ + fail = 1; + break; + } + bytes_read = full_read (STDIN_FILENO, buf, BUFFER_SIZE); + if (bytes_read < 0) + error (EXIT_FAILURE, errno, _("read error")); + + { + struct B_pair bp; + bp.start = buf; + bp.one_past_end = buf + bytes_read; + obstack_grow (OBS, &bp, sizeof (bp)); + } + + if (bytes_read > 0) + last_byte_is_eol_byte = (buf[bytes_read - 1] == eol_byte); + + if (bytes_read < BUFFER_SIZE) + break; + } + + if (!fail) + { + /* If the file was non-empty and lacked an EOL_BYTE at its end, + then add a buffer containing just that one byte. */ + if (!last_byte_is_eol_byte) + { + char *buf = malloc (1); + if (buf == NULL) + { + /* FIXME: just like above */ + fail = 1; + } + else + { + struct B_pair bp; + *buf = eol_byte; + bp.start = buf; + bp.one_past_end = buf + 1; + obstack_grow (OBS, &bp, sizeof (bp)); + } + } + } + + x->n_bufs = obstack_object_size (OBS) / sizeof (x->p[0]); + x->p = (struct B_pair *) obstack_finish (OBS); + + /* If there are two or more buffers and the last buffer is empty, + then free the last one and decrement the buffer count. */ + if (x->n_bufs >= 2 + && x->p[x->n_bufs - 1].start == x->p[x->n_bufs - 1].one_past_end) + free (x->p[--(x->n_bufs)].start); + + return fail; +} + +static void +buf_free (Buf *x) +{ + int i; + for (i = 0; i < x->n_bufs; i++) + free (x->p[i].start); + obstack_free (OBS, NULL); +} + +Line_ptr +line_ptr_decrement (const Buf *x, const Line_ptr *lp) +{ + Line_ptr lp_new; + + if (lp->ptr > x->p[lp->i].start) + { + lp_new.i = lp->i; + lp_new.ptr = lp->ptr - 1; + } + else + { + assert (lp->i > 0); + lp_new.i = lp->i - 1; + lp_new.ptr = ONE_PAST_END (x, lp->i - 1) - 1; + } + return lp_new; +} + +Line_ptr +line_ptr_increment (const Buf *x, const Line_ptr *lp) +{ + Line_ptr lp_new; + + assert (lp->ptr <= ONE_PAST_END (x, lp->i) - 1); + if (lp->ptr < ONE_PAST_END (x, lp->i) - 1) + { + lp_new.i = lp->i; + lp_new.ptr = lp->ptr + 1; + } + else + { + assert (lp->i < x->n_bufs - 1); + lp_new.i = lp->i + 1; + lp_new.ptr = x->p[lp->i + 1].start; + } + return lp_new; +} + +static int +find_bol (const Buf *x, + const Line_ptr *last_bol, Line_ptr *new_bol, char eol_byte) +{ + int i; + Line_ptr tmp; + char *last_bol_ptr; + + if (last_bol->ptr == x->p[0].start) + return 0; + + tmp = line_ptr_decrement (x, last_bol); + last_bol_ptr = tmp.ptr; + i = tmp.i; + while (1) + { + char *nl = memrchr (x->p[i].start, last_bol_ptr, eol_byte); + if (nl) + { + Line_ptr nl_pos; + nl_pos.i = i; + nl_pos.ptr = nl; + *new_bol = line_ptr_increment (x, &nl_pos); + return 1; + } + + if (i <= 0) + break; + + --i; + last_bol_ptr = ONE_PAST_END (x, i); + } + + /* If last_bol->ptr didn't point at the first byte of X, then reaching + this point means that we're about to return the line that is at the + beginning of X. */ + if (last_bol->ptr != x->p[0].start) + { + new_bol->i = 0; + new_bol->ptr = x->p[0].start; + return 1; + } + + return 0; +} + +static void +print_line (FILE *out_stream, const Buf *x, + const Line_ptr *bol, const Line_ptr *bol_next) +{ + int i; + for (i = bol->i; i <= bol_next->i; i++) + { + char *a = (i == bol->i ? bol->ptr : x->p[i].start); + char *b = (i == bol_next->i ? bol_next->ptr : ONE_PAST_END (x, i)); + fwrite (a, 1, b - a, out_stream); + } +} + +static int +tac_mem () +{ + Buf x; + Line_ptr bol; + char eol_byte = '\n'; + int fail; + + fail = buf_init_from_stdin (&x, eol_byte); + if (fail) + { + buf_free (&x); + return 1; + } + + /* Special case the empty file. */ + if (EMPTY (&x)) + return 0; + + /* Initially, point at one past the last byte of the file. */ + bol.i = x.n_bufs - 1; + bol.ptr = ONE_PAST_END (&x, bol.i); + + while (1) + { + Line_ptr new_bol; + int found = find_bol (&x, &bol, &new_bol, eol_byte); + if (!found) + break; + print_line (stdout, &x, &new_bol, &bol); + bol = new_bol; + } + return 0; +} diff --git a/src/apps/bin/coreutils-5.0/src/tac.c b/src/apps/bin/coreutils-5.0/src/tac.c new file mode 100644 index 0000000000..c7d9e258d3 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/tac.c @@ -0,0 +1,715 @@ +/* tac - concatenate and print files in reverse + Copyright (C) 1988-1991, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Jay Lepreau (lepreau@cs.utah.edu). + GNU enhancements by David MacKenzie (djm@gnu.ai.mit.edu). */ + +/* Copy each FILE, or the standard input if none are given or when a + FILE name of "-" is encountered, to the standard output with the + order of the records reversed. The records are separated by + instances of a string, or a newline if none is given. By default, the + separator string is attached to the end of the record that it + follows in the file. + + Options: + -b, --before The separator is attached to the beginning + of the record that it precedes in the file. + -r, --regex The separator is a regular expression. + -s, --separator=separator Use SEPARATOR as the record separator. + + To reverse a file byte by byte, use (in bash, ksh, or sh): +tac -r -s '.\| +' file */ + +#include + +#include +#include +#include +#include "system.h" +#include "closeout.h" + +#include + +#include "error.h" +#include "safe-read.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "tac" + +#define AUTHORS N_ ("Jay Lepreau and David MacKenzie") + +#if defined __MSDOS__ || defined _WIN32 +/* Define this to non-zero on systems for which the regular mechanism + (of unlinking an open file and expecting to be able to write, seek + back to the beginning, then reread it) doesn't work. E.g., on Windows + and DOS systems. */ +# define DONT_UNLINK_WHILE_OPEN 1 +#endif + + +#ifndef DEFAULT_TMPDIR +# define DEFAULT_TMPDIR "/tmp" +#endif + +/* The number of bytes per atomic read. */ +#define INITIAL_READSIZE 8192 + +/* The number of bytes per atomic write. */ +#define WRITESIZE 8192 + +/* The name this program was run with. */ +char *program_name; + +/* The string that separates the records of the file. */ +static char *separator; + +/* If nonzero, print `separator' along with the record preceding it + in the file; otherwise with the record following it. */ +static int separator_ends_record; + +/* 0 if `separator' is to be matched as a regular expression; + otherwise, the length of `separator', used as a sentinel to + stop the search. */ +static size_t sentinel_length; + +/* The length of a match with `separator'. If `sentinel_length' is 0, + `match_length' is computed every time a match succeeds; + otherwise, it is simply the length of `separator'. */ +static int match_length; + +/* The input buffer. */ +static char *G_buffer; + +/* The number of bytes to read at once into `buffer'. */ +static size_t read_size; + +/* The size of `buffer'. This is read_size * 2 + sentinel_length + 2. + The extra 2 bytes allow `past_end' to have a value beyond the + end of `G_buffer' and `match_start' to run off the front of `G_buffer'. */ +static unsigned G_buffer_size; + +/* The compiled regular expression representing `separator'. */ +static struct re_pattern_buffer compiled_separator; + +static struct option const longopts[] = +{ + {"before", no_argument, NULL, 'b'}, + {"regex", no_argument, NULL, 'r'}, + {"separator", required_argument, NULL, 's'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + fputs (_("\ +Write each FILE to standard output, last line first.\n\ +With no FILE, or when FILE is -, read standard input.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -b, --before attach the separator before instead of after\n\ + -r, --regex interpret the separator as a regular expression\n\ + -s, --separator=STRING use STRING as the separator instead of newline\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Print the characters from START to PAST_END - 1. + If START is NULL, just flush the buffer. */ + +static void +output (const char *start, const char *past_end) +{ + static char buffer[WRITESIZE]; + static size_t bytes_in_buffer = 0; + size_t bytes_to_add = past_end - start; + size_t bytes_available = WRITESIZE - bytes_in_buffer; + + if (start == 0) + { + fwrite (buffer, 1, bytes_in_buffer, stdout); + bytes_in_buffer = 0; + return; + } + + /* Write out as many full buffers as possible. */ + while (bytes_to_add >= bytes_available) + { + memcpy (buffer + bytes_in_buffer, start, bytes_available); + bytes_to_add -= bytes_available; + start += bytes_available; + fwrite (buffer, 1, WRITESIZE, stdout); + bytes_in_buffer = 0; + bytes_available = WRITESIZE; + } + + memcpy (buffer + bytes_in_buffer, start, bytes_to_add); + bytes_in_buffer += bytes_to_add; +} + +/* Print in reverse the file open on descriptor FD for reading FILE. + Return 0 if ok, 1 if an error occurs. */ + +static int +tac_seekable (int input_fd, const char *file) +{ + /* Pointer to the location in `G_buffer' where the search for + the next separator will begin. */ + char *match_start; + + /* Pointer to one past the rightmost character in `G_buffer' that + has not been printed yet. */ + char *past_end; + + /* Length of the record growing in `G_buffer'. */ + size_t saved_record_size; + + /* Offset in the file of the next read. */ + off_t file_pos; + + /* Nonzero if `output' has not been called yet for any file. + Only used when the separator is attached to the preceding record. */ + int first_time = 1; + char first_char = *separator; /* Speed optimization, non-regexp. */ + char *separator1 = separator + 1; /* Speed optimization, non-regexp. */ + int match_length1 = match_length - 1; /* Speed optimization, non-regexp. */ + struct re_registers regs; + + /* Find the size of the input file. */ + file_pos = lseek (input_fd, (off_t) 0, SEEK_END); + if (file_pos < 1) + return 0; /* It's an empty file. */ + + /* Arrange for the first read to lop off enough to leave the rest of the + file a multiple of `read_size'. Since `read_size' can change, this may + not always hold during the program run, but since it usually will, leave + it here for i/o efficiency (page/sector boundaries and all that). + Note: the efficiency gain has not been verified. */ + saved_record_size = file_pos % read_size; + if (saved_record_size == 0) + saved_record_size = read_size; + file_pos -= saved_record_size; + /* `file_pos' now points to the start of the last (probably partial) block + in the input file. */ + + if (lseek (input_fd, file_pos, SEEK_SET) < 0) + error (0, errno, "%s: seek failed", file); + + if (safe_read (input_fd, G_buffer, saved_record_size) != saved_record_size) + { + error (0, errno, "%s", file); + return 1; + } + + match_start = past_end = G_buffer + saved_record_size; + /* For non-regexp search, move past impossible positions for a match. */ + if (sentinel_length) + match_start -= match_length1; + + for (;;) + { + /* Search backward from `match_start' - 1 to `G_buffer' for a match + with `separator'; for speed, use strncmp if `separator' contains no + metacharacters. + If the match succeeds, set `match_start' to point to the start of + the match and `match_length' to the length of the match. + Otherwise, make `match_start' < `G_buffer'. */ + if (sentinel_length == 0) + { + int i = match_start - G_buffer; + int ret; + + ret = re_search (&compiled_separator, G_buffer, i, i - 1, -i, ®s); + if (ret == -1) + match_start = G_buffer - 1; + else if (ret == -2) + { + error (EXIT_FAILURE, 0, + _("error in regular expression search")); + } + else + { + match_start = G_buffer + regs.start[0]; + match_length = regs.end[0] - regs.start[0]; + } + } + else + { + /* `match_length' is constant for non-regexp boundaries. */ + while (*--match_start != first_char + || (match_length1 && strncmp (match_start + 1, separator1, + match_length1))) + /* Do nothing. */ ; + } + + /* Check whether we backed off the front of `G_buffer' without finding + a match for `separator'. */ + if (match_start < G_buffer) + { + if (file_pos == 0) + { + /* Hit the beginning of the file; print the remaining record. */ + output (G_buffer, past_end); + return 0; + } + + saved_record_size = past_end - G_buffer; + if (saved_record_size > read_size) + { + /* `G_buffer_size' is about twice `read_size', so since + we want to read in another `read_size' bytes before + the data already in `G_buffer', we need to increase + `G_buffer_size'. */ + char *newbuffer; + int offset = sentinel_length ? sentinel_length : 1; + + read_size *= 2; + G_buffer_size = read_size * 2 + sentinel_length + 2; + newbuffer = xrealloc (G_buffer - offset, G_buffer_size); + newbuffer += offset; + /* Adjust the pointers for the new buffer location. */ + match_start += newbuffer - G_buffer; + past_end += newbuffer - G_buffer; + G_buffer = newbuffer; + } + + /* Back up to the start of the next bufferfull of the file. */ + if (file_pos >= read_size) + file_pos -= read_size; + else + { + read_size = file_pos; + file_pos = 0; + } + lseek (input_fd, file_pos, SEEK_SET); + + /* Shift the pending record data right to make room for the new. + The source and destination regions probably overlap. */ + memmove (G_buffer + read_size, G_buffer, saved_record_size); + past_end = G_buffer + read_size + saved_record_size; + /* For non-regexp searches, avoid unneccessary scanning. */ + if (sentinel_length) + match_start = G_buffer + read_size; + else + match_start = past_end; + + if (safe_read (input_fd, G_buffer, read_size) != read_size) + { + error (0, errno, "%s", file); + return 1; + } + } + else + { + /* Found a match of `separator'. */ + if (separator_ends_record) + { + char *match_end = match_start + match_length; + + /* If this match of `separator' isn't at the end of the + file, print the record. */ + if (first_time == 0 || match_end != past_end) + output (match_end, past_end); + past_end = match_end; + first_time = 0; + } + else + { + output (match_start, past_end); + past_end = match_start; + } + + /* For non-regex matching, we can back up. */ + if (sentinel_length > 0) + match_start -= match_length - 1; + } + } +} + +/* Print FILE in reverse. + Return 0 if ok, 1 if an error occurs. */ + +static int +tac_file (const char *file) +{ + int errors; + FILE *in; + + in = fopen (file, "r"); + if (in == NULL) + { + error (0, errno, "%s", file); + return 1; + } + SET_BINARY (fileno (in)); + errors = tac_seekable (fileno (in), file); + if (ferror (in) || fclose (in) == EOF) + { + error (0, errno, "%s", file); + return 1; + } + return errors; +} + +#if DONT_UNLINK_WHILE_OPEN + +static const char *file_to_remove; +static FILE *fp_to_close; + +static void +unlink_tempfile (void) +{ + fclose (fp_to_close); + unlink (file_to_remove); +} + +static void +record_tempfile (const char *fn, FILE *fp) +{ + if (!file_to_remove) + { + file_to_remove = fn; + fp_to_close = fp; + atexit (unlink_tempfile); + } +} + +#endif + +/* Make a copy of the standard input in `FIXME'. */ + +static void +save_stdin (FILE **g_tmp, char **g_tempfile) +{ + static char *template = NULL; + static char *tempdir; + char *tempfile; + FILE *tmp; + int fd; + + if (template == NULL) + { + tempdir = getenv ("TMPDIR"); + if (tempdir == NULL) + tempdir = DEFAULT_TMPDIR; + template = xmalloc (strlen (tempdir) + 11); + } + sprintf (template, "%s/tacXXXXXX", tempdir); + tempfile = template; + fd = mkstemp (template); + if (fd == -1) + error (EXIT_FAILURE, errno, "%s", tempfile); + + tmp = fdopen (fd, "w+"); + if (tmp == NULL) + error (EXIT_FAILURE, errno, "%s", tempfile); + +#if DONT_UNLINK_WHILE_OPEN + record_tempfile (tempfile, tmp); +#else + unlink (tempfile); +#endif + + while (1) + { + size_t bytes_read = safe_read (STDIN_FILENO, G_buffer, read_size); + if (bytes_read == 0) + break; + if (bytes_read == SAFE_READ_ERROR) + error (EXIT_FAILURE, errno, _("stdin: read error")); + + if (fwrite (G_buffer, 1, bytes_read, tmp) != bytes_read) + break; + } + + if (ferror (tmp) || fflush (tmp) == EOF) + error (EXIT_FAILURE, errno, "%s", tempfile); + + SET_BINARY (fileno (tmp)); + *g_tmp = tmp; + *g_tempfile = tempfile; +} + +/* Print the standard input in reverse, saving it to temporary + file first if it is a pipe. + Return 0 if ok, 1 if an error occurs. */ + +static int +tac_stdin (void) +{ + int errors; + struct stat stats; + + /* No tempfile is needed for "tac < file". + Use fstat instead of checking for errno == ESPIPE because + lseek doesn't work on some special files but doesn't return an + error, either. */ + if (fstat (STDIN_FILENO, &stats)) + { + error (0, errno, _("standard input")); + return 1; + } + + if (S_ISREG (stats.st_mode)) + { + errors = tac_seekable (fileno (stdin), _("standard input")); + } + else + { + FILE *tmp_stream; + char *tmp_file; + save_stdin (&tmp_stream, &tmp_file); + errors = tac_seekable (fileno (tmp_stream), tmp_file); + } + + return errors; +} + +#if 0 +/* BUF_END points one byte past the end of the buffer to be searched. */ + +static void * +memrchr (const char *buf_start, const char *buf_end, int c) +{ + const char *p = buf_end; + while (buf_start <= --p) + { + if (*(const unsigned char *) p == c) + return (void *) p; + } + return NULL; +} + +/* FIXME: describe */ + +static int +tac_mem (const char *buf, size_t n_bytes, FILE *out) +{ + const char *nl; + const char *bol; + + if (n_bytes == 0) + return 0; + + nl = memrchr (buf, buf + n_bytes, '\n'); + bol = (nl == NULL ? buf : nl + 1); + + /* If the last line of the input file has no terminating newline, + treat it as a special case. */ + if (bol < buf + n_bytes) + { + /* Print out the line from bol to end of input. */ + fwrite (bol, 1, (buf + n_bytes) - bol, out); + + /* Add a newline here. Otherwise, the first and second lines + of output would appear to have been joined. */ + fputc ('\n', out); + } + + while ((nl = memrchr (buf, bol - 1, '\n')) != NULL) + { + /* Output the line (which includes a trailing newline) + from NL+1 to BOL-1. */ + fwrite (nl + 1, 1, bol - (nl + 1), out); + + bol = nl + 1; + } + + /* If there's anything left, output the last line: BUF .. BOL-1. + When the first byte of the input is a newline, there is nothing + left to do here. */ + if (buf < bol) + fwrite (buf, 1, bol - buf, out); + + /* FIXME: this is work in progress.... */ + return ferror (out); +} + +/* FIXME: describe */ + +static int +tac_stdin_to_mem (void) +{ + char *buf = NULL; + size_t bufsiz = 8 * BUFSIZ; + size_t delta = 8 * BUFSIZ; + size_t n_bytes = 0; + + while (1) + { + size_t bytes_read; + if (buf == NULL) + buf = (char *) malloc (bufsiz); + else + buf = (char *) realloc (buf, bufsiz); + + if (buf == NULL) + { + /* Free the buffer and fall back on the code that relies on a + temporary file. */ + free (buf); + /* FIXME */ + abort (); + } + bytes_read = safe_read (STDIN_FILENO, buf + n_bytes, bufsiz - n_bytes); + if (bytes_read == 0) + break; + if (bytes_read == SAFE_READ_ERROR) + error (EXIT_FAILURE, errno, _("stdin: read error")); + n_bytes += bytes_read; + + bufsiz += delta; + } + + tac_mem (buf, n_bytes, stdout); + + return 0; +} +#endif + +int +main (int argc, char **argv) +{ + const char *error_message; /* Return value from re_compile_pattern. */ + int optc, errors; + int have_read_stdin = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + errors = 0; + separator = "\n"; + sentinel_length = 1; + separator_ends_record = 1; + + while ((optc = getopt_long (argc, argv, "brs:", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + case 'b': + separator_ends_record = 0; + break; + case 'r': + sentinel_length = 0; + break; + case 's': + separator = optarg; + if (*separator == 0) + error (EXIT_FAILURE, 0, _("separator cannot be empty")); + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + } + } + + if (sentinel_length == 0) + { + compiled_separator.allocated = 100; + compiled_separator.buffer = (unsigned char *) + xmalloc (compiled_separator.allocated); + compiled_separator.fastmap = xmalloc (256); + compiled_separator.translate = 0; + error_message = re_compile_pattern (separator, strlen (separator), + &compiled_separator); + if (error_message) + error (EXIT_FAILURE, 0, "%s", error_message); + } + else + match_length = sentinel_length = strlen (separator); + + read_size = INITIAL_READSIZE; + /* A precaution that will probably never be needed. */ + while (sentinel_length * 2 >= read_size) + read_size *= 2; + G_buffer_size = read_size * 2 + sentinel_length + 2; + G_buffer = xmalloc (G_buffer_size); + if (sentinel_length) + { + strcpy (G_buffer, separator); + G_buffer += sentinel_length; + } + else + { + ++G_buffer; + } + + if (optind == argc) + { + have_read_stdin = 1; + /* We need binary I/O, since `tac' relies + on `lseek' and byte counts. */ + SET_BINARY2 (STDIN_FILENO, STDOUT_FILENO); + errors = tac_stdin (); + } + else + { + for (; optind < argc; ++optind) + { + if (STREQ (argv[optind], "-")) + { + have_read_stdin = 1; + SET_BINARY2 (STDIN_FILENO, STDOUT_FILENO); + errors |= tac_stdin (); + } + else + { + /* Binary output will leave the lines' ends (NL or + CR/LF) intact when the output is a disk file. + Writing a file with CR/LF pairs at end of lines in + text mode has no visible effect on console output, + since two CRs in a row are just like one CR. */ + SET_BINARY (STDOUT_FILENO); + errors |= tac_file (argv[optind]); + } + } + } + + /* Flush the output buffer. */ + output ((char *) NULL, (char *) NULL); + + if (have_read_stdin && close (STDIN_FILENO) < 0) + error (EXIT_FAILURE, errno, "-"); + exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/tail.c b/src/apps/bin/coreutils-5.0/src/tail.c new file mode 100644 index 0000000000..dad6da4848 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/tail.c @@ -0,0 +1,1668 @@ +/* tail -- output the last part of file(s) + Copyright (C) 1989, 90, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Can display any amount of data, unlike the Unix version, which uses + a fixed size buffer and therefore can only deliver a limited number + of lines. + + Original version by Paul Rubin . + Extensions by David MacKenzie . + tail -f for multiple files by Ian Lance Taylor . */ + +#include + +#include +#include +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "argmatch.h" +#include "error.h" +#include "inttostr.h" +#include "posixver.h" +#include "safe-read.h" +#include "xnanosleep.h" +#include "xstrtol.h" +#include "xstrtod.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "tail" + +#define AUTHORS \ + N_ ("Paul Rubin, David MacKenzie, Ian Lance Taylor, and Jim Meyering") + +#ifndef ENOSYS + /* Some systems don't have ENOSYS -- this should be a big enough + value that no valid errno value will match it. */ +# define ENOSYS 99999 +#endif + +/* Number of items to tail. */ +#define DEFAULT_N_LINES 10 + +/* Size of atomic reads. */ +#ifndef BUFSIZ +# define BUFSIZ (512 * 8) +#endif + +/* A special value for dump_remainder's N_BYTES parameter. */ +#define COPY_TO_EOF OFF_T_MAX + +/* FIXME: make Follow_name the default? */ +#define DEFAULT_FOLLOW_MODE Follow_descriptor + +enum Follow_mode +{ + /* Follow the name of each file: if the file is renamed, try to reopen + that name and track the end of the new file if/when it's recreated. + This is useful for tracking logs that are occasionally rotated. */ + Follow_name = 1, + + /* Follow each descriptor obtained upon opening a file. + That means we'll continue to follow the end of a file even after + it has been renamed or unlinked. */ + Follow_descriptor = 2 +}; + +/* The types of files for which tail works. */ +#define IS_TAILABLE_FILE_TYPE(Mode) \ + (S_ISREG (Mode) || S_ISFIFO (Mode) || S_ISCHR (Mode)) + +static char const *const follow_mode_string[] = +{ + "descriptor", "name", 0 +}; + +static enum Follow_mode const follow_mode_map[] = +{ + Follow_descriptor, Follow_name, +}; + +struct File_spec +{ + /* The actual file name, or "-" for stdin. */ + char *name; + + /* File descriptor on which the file is open; -1 if it's not open. */ + int fd; + + /* The size of the file the last time we checked. */ + off_t size; + + /* The device and inode of the file the last time we checked. */ + dev_t dev; + ino_t ino; + + /* The specified name initially referred to a directory or some other + type for which tail isn't meaningful. Unlike for a permission problem + (tailable, below) once this is set, the name is not checked ever again. */ + int ignore; + + /* See description of DEFAULT_MAX_N_... below. */ + unsigned int n_unchanged_stats; + + /* See description of DEFAULT_MAX_N_... below. */ + unsigned int n_consecutive_size_changes; + + /* A file is tailable if it exists, is readable, and is of type + IS_TAILABLE_FILE_TYPE. */ + int tailable; + + /* The value of errno seen last time we checked this file. */ + int errnum; + +}; + +/* Keep trying to open a file even if it is inaccessible when tail starts + or if it becomes inaccessible later -- useful only with -f. */ +static int reopen_inaccessible_files; + +/* If nonzero, interpret the numeric argument as the number of lines. + Otherwise, interpret it as the number of bytes. */ +static int count_lines; + +/* Whether we follow the name of each file or the file descriptor + that is initially associated with each name. */ +static enum Follow_mode follow_mode = Follow_descriptor; + +/* If nonzero, read from the ends of all specified files until killed. */ +static int forever; + +/* If nonzero, count from start of file instead of end. */ +static int from_start; + +/* If nonzero, print filename headers. */ +static int print_headers; + +/* When to print the filename banners. */ +enum header_mode +{ + multiple_files, always, never +}; + +/* When tailing a file by name, if there have been this many consecutive + iterations for which the size has remained the same, then open/fstat + the file to determine if that file name is still associated with the + same device/inode-number pair as before. This option is meaningful only + when following by name. --max-unchanged-stats=N */ +#define DEFAULT_MAX_N_UNCHANGED_STATS_BETWEEN_OPENS 5 +static unsigned long max_n_unchanged_stats_between_opens = + DEFAULT_MAX_N_UNCHANGED_STATS_BETWEEN_OPENS; + +/* This variable is used to ensure that a file that is unlinked or moved + aside, yet always growing will be recognized as having been renamed. + After detecting this many consecutive size changes for a file, open/fstat + the file to determine if that file name is still associated with the + same device/inode-number pair as before. This option is meaningful only + when following by name. --max-consecutive-size-changes=N */ +#define DEFAULT_MAX_N_CONSECUTIVE_SIZE_CHANGES 200 +static unsigned long max_n_consecutive_size_changes_between_opens = + DEFAULT_MAX_N_CONSECUTIVE_SIZE_CHANGES; + +/* The name this program was run with. */ +char *program_name; + +/* The process ID of the process (presumably on the current host) + that is writing to all followed files. */ +static pid_t pid; + +/* Nonzero if we have ever read standard input. */ +static int have_read_stdin; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + RETRY_OPTION = CHAR_MAX + 1, + MAX_UNCHANGED_STATS_OPTION, + + /* FIXME: remove this in 2001, unless someone can show a good + reason to keep it. */ + MAX_CONSECUTIVE_SIZE_CHANGES_OPTION, + + PID_OPTION, + LONG_FOLLOW_OPTION +}; + +static struct option const long_options[] = +{ + /* --allow-missing is deprecated; use --retry instead + FIXME: remove it some day */ + {"allow-missing", no_argument, NULL, RETRY_OPTION}, + {"bytes", required_argument, NULL, 'c'}, + {"follow", optional_argument, NULL, LONG_FOLLOW_OPTION}, + {"lines", required_argument, NULL, 'n'}, + {"max-unchanged-stats", required_argument, NULL, MAX_UNCHANGED_STATS_OPTION}, + {"max-consecutive-size-changes", required_argument, NULL, + MAX_CONSECUTIVE_SIZE_CHANGES_OPTION}, + {"pid", required_argument, NULL, PID_OPTION}, + {"quiet", no_argument, NULL, 'q'}, + {"retry", no_argument, NULL, RETRY_OPTION}, + {"silent", no_argument, NULL, 'q'}, + {"sleep-interval", required_argument, NULL, 's'}, + {"verbose", no_argument, NULL, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + printf (_("\ +Print the last %d lines of each FILE to standard output.\n\ +With more than one FILE, precede each with a header giving the file name.\n\ +With no FILE, or when FILE is -, read standard input.\n\ +\n\ +"), DEFAULT_N_LINES); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + --retry keep trying to open a file even if it is\n\ + inaccessible when tail starts or if it becomes\n\ + inaccessible later -- useful only with -f\n\ + -c, --bytes=N output the last N bytes\n\ +"), stdout); + fputs (_("\ + -f, --follow[={name|descriptor}]\n\ + output appended data as the file grows;\n\ + -f, --follow, and --follow=descriptor are\n\ + equivalent\n\ + -F same as --follow=name --retry\n\ +"), stdout); + printf (_("\ + -n, --lines=N output the last N lines, instead of the last %d\n\ + --max-unchanged-stats=N\n\ + with --follow=name, reopen a FILE which has not\n\ + changed size after N (default %d) iterations\n\ + to see if it has been unlinked or renamed\n\ + (this is the usual case of rotated log files)\n\ +"), + DEFAULT_N_LINES, + DEFAULT_MAX_N_UNCHANGED_STATS_BETWEEN_OPENS + ); + fputs (_("\ + --pid=PID with -f, terminate after process ID, PID dies\n\ + -q, --quiet, --silent never output headers giving file names\n\ + -s, --sleep-interval=S with -f, sleep for approximately S seconds\n\ + (default 1.0) between iterations.\n\ + -v, --verbose always output headers giving file names\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +If the first character of N (the number of bytes or lines) is a `+',\n\ +print beginning with the Nth item from the start of each file, otherwise,\n\ +print the last N items in the file. N may have a multiplier suffix:\n\ +b for 512, k for 1024, m for 1048576 (1 Meg).\n\ +\n\ +"), stdout); + fputs (_("\ +With --follow (-f), tail defaults to following the file descriptor, which\n\ +means that even if a tail'ed file is renamed, tail will continue to track\n\ +its end. \ +"), stdout); + fputs (_("\ +This default behavior is not desirable when you really want to\n\ +track the actual name of the file, not the file descriptor (e.g., log\n\ +rotation). Use --follow=name in that case. That causes tail to track the\n\ +named file by reopening it periodically to see if it has been removed and\n\ +recreated by some other program.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +static int +valid_file_spec (struct File_spec const *f) +{ + /* Exactly one of the following subexpressions must be true. */ + return ((f->fd == -1) ^ (f->errnum == 0)); +} + +static char * +pretty_name (struct File_spec const *f) +{ + return (STREQ (f->name, "-") ? "standard input" : f->name); +} + +static void +xwrite (int fd, char const *buffer, size_t n_bytes) +{ + assert (fd == STDOUT_FILENO); + if (n_bytes > 0 && fwrite (buffer, 1, n_bytes, stdout) == 0) + error (EXIT_FAILURE, errno, _("write error")); +} + +static void +close_fd (int fd, const char *filename) +{ + if (fd != -1 && fd != STDIN_FILENO && close (fd)) + { + error (0, errno, _("closing %s (fd=%d)"), filename, fd); + } +} + +static void +write_header (const char *pretty_filename) +{ + static int first_file = 1; + + printf ("%s==> %s <==\n", (first_file ? "" : "\n"), pretty_filename); + first_file = 0; +} + +/* Read and output N_BYTES of file PRETTY_FILENAME starting at the current + position in FD. If N_BYTES is COPY_TO_EOF, then copy until end of file. + Return the number of bytes read from the file. */ + +static long +dump_remainder (const char *pretty_filename, int fd, off_t n_bytes) +{ + char buffer[BUFSIZ]; + size_t bytes_read; + long n_written; + off_t n_remaining = n_bytes; + + n_written = 0; + while (1) + { + long n = MIN (n_remaining, (off_t) BUFSIZ); + bytes_read = safe_read (fd, buffer, n); + if (bytes_read == SAFE_READ_ERROR) + error (EXIT_FAILURE, errno, "%s", pretty_filename); + if (bytes_read == 0) + break; + xwrite (STDOUT_FILENO, buffer, bytes_read); + n_remaining -= bytes_read; + n_written += bytes_read; + } + + return n_written; +} + +/* Call lseek with the specified arguments, where file descriptor FD + corresponds to the file, FILENAME. + Give a diagnostic and exit nonzero if lseek fails. */ + +static void +xlseek (int fd, off_t offset, int whence, char const *filename) +{ + off_t new_offset = lseek (fd, offset, whence); + char buf[INT_BUFSIZE_BOUND (off_t)]; + char *s; + + if (0 <= new_offset) + return; + + s = offtostr (offset, buf); + switch (whence) + { + case SEEK_SET: + error (EXIT_FAILURE, errno, _("%s: cannot seek to offset %s"), + filename, s); + break; + case SEEK_CUR: + error (EXIT_FAILURE, errno, _("%s: cannot seek to relative offset %s"), + filename, s); + break; + case SEEK_END: + error (EXIT_FAILURE, errno, + _("%s: cannot seek to end-relative offset %s"), + filename, s); + break; + default: + abort (); + } +} + +/* Print the last N_LINES lines from the end of file FD. + Go backward through the file, reading `BUFSIZ' bytes at a time (except + probably the first), until we hit the start of the file or have + read NUMBER newlines. + START_POS is the starting position of the read pointer for the file + associated with FD (may be nonzero). + FILE_LENGTH is the length of the file (one more than the offset of the + last byte of the file). + Return 0 if successful, 1 if an error occurred. */ + +static int +file_lines (const char *pretty_filename, int fd, long int n_lines, + off_t start_pos, off_t file_length) +{ + char buffer[BUFSIZ]; + size_t bytes_read; + off_t pos = file_length; + + if (n_lines == 0) + return 0; + + /* Set `bytes_read' to the size of the last, probably partial, buffer; + 0 < `bytes_read' <= `BUFSIZ'. */ + bytes_read = (pos - start_pos) % BUFSIZ; + if (bytes_read == 0) + bytes_read = BUFSIZ; + /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all + reads will be on block boundaries, which might increase efficiency. */ + pos -= bytes_read; + xlseek (fd, pos, SEEK_SET, pretty_filename); + bytes_read = safe_read (fd, buffer, bytes_read); + if (bytes_read == SAFE_READ_ERROR) + { + error (0, errno, "%s", pretty_filename); + return 1; + } + + /* Count the incomplete line on files that don't end with a newline. */ + if (bytes_read && buffer[bytes_read - 1] != '\n') + --n_lines; + + do + { + /* Scan backward, counting the newlines in this bufferfull. */ + + size_t n = bytes_read; + while (n) + { + char const *nl; + nl = memrchr (buffer, '\n', n); + if (nl == NULL) + break; + n = nl - buffer; + if (n_lines-- == 0) + { + /* If this newline isn't the last character in the buffer, + output the part that is after it. */ + if (n != bytes_read - 1) + xwrite (STDOUT_FILENO, nl + 1, bytes_read - (n + 1)); + dump_remainder (pretty_filename, fd, + file_length - (pos + bytes_read)); + return 0; + } + } + + /* Not enough newlines in that bufferfull. */ + if (pos == start_pos) + { + /* Not enough lines in the file; print the entire file. */ + xlseek (fd, start_pos, SEEK_SET, pretty_filename); + dump_remainder (pretty_filename, fd, file_length); + return 0; + } + pos -= BUFSIZ; + xlseek (fd, pos, SEEK_SET, pretty_filename); + + bytes_read = safe_read (fd, buffer, BUFSIZ); + if (bytes_read == SAFE_READ_ERROR) + { + error (0, errno, "%s", pretty_filename); + return 1; + } + } + while (bytes_read > 0); + + return 0; +} + +/* Print the last N_LINES lines from the end of the standard input, + open for reading as pipe FD. + Buffer the text as a linked list of LBUFFERs, adding them as needed. + Return 0 if successful, 1 if an error occured. */ + +static int +pipe_lines (const char *pretty_filename, int fd, long int n_lines) +{ + struct linebuffer + { + int nbytes, nlines; + char buffer[BUFSIZ]; + struct linebuffer *next; + }; + typedef struct linebuffer LBUFFER; + LBUFFER *first, *last, *tmp; + int i; /* Index into buffers. */ + int total_lines = 0; /* Total number of newlines in all buffers. */ + int errors = 0; + int nbytes; /* Size of most recent read */ + + first = last = (LBUFFER *) xmalloc (sizeof (LBUFFER)); + first->nbytes = first->nlines = 0; + first->next = NULL; + tmp = (LBUFFER *) xmalloc (sizeof (LBUFFER)); + + /* Input is always read into a fresh buffer. */ + while ((nbytes = tmp->nbytes = safe_read (fd, tmp->buffer, BUFSIZ)) > 0) + { + tmp->nlines = 0; + tmp->next = NULL; + + /* Count the number of newlines just read. */ + for (i = 0; i < tmp->nbytes; i++) + if (tmp->buffer[i] == '\n') + ++tmp->nlines; + total_lines += tmp->nlines; + + /* If there is enough room in the last buffer read, just append the new + one to it. This is because when reading from a pipe, `nbytes' can + often be very small. */ + if (tmp->nbytes + last->nbytes < BUFSIZ) + { + memcpy (&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes); + last->nbytes += tmp->nbytes; + last->nlines += tmp->nlines; + } + else + { + /* If there's not enough room, link the new buffer onto the end of + the list, then either free up the oldest buffer for the next + read if that would leave enough lines, or else malloc a new one. + Some compaction mechanism is possible but probably not + worthwhile. */ + last = last->next = tmp; + if (total_lines - first->nlines > n_lines) + { + tmp = first; + total_lines -= first->nlines; + first = first->next; + } + else + tmp = (LBUFFER *) xmalloc (sizeof (LBUFFER)); + } + } + + free ((char *) tmp); + + if (nbytes < 0) + { + error (0, errno, "%s", pretty_filename); + errors = 1; + goto free_lbuffers; + } + + /* If the file is empty, then bail out. */ + if (last->nbytes == 0) + goto free_lbuffers; + + /* This prevents a core dump when the pipe contains no newlines. */ + if (n_lines == 0) + goto free_lbuffers; + + /* Count the incomplete line on files that don't end with a newline. */ + if (last->buffer[last->nbytes - 1] != '\n') + { + ++last->nlines; + ++total_lines; + } + + /* Run through the list, printing lines. First, skip over unneeded + buffers. */ + for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next) + total_lines -= tmp->nlines; + + /* Find the correct beginning, then print the rest of the file. */ + if (total_lines > n_lines) + { + const char *cp; + + /* Skip `total_lines' - `n_lines' newlines. We made sure that + `total_lines' - `n_lines' <= `tmp->nlines'. */ + cp = tmp->buffer; + for (i = total_lines - n_lines; i; --i) + while (*cp++ != '\n') + /* Do nothing. */ ; + i = cp - tmp->buffer; + } + else + i = 0; + xwrite (STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i); + + for (tmp = tmp->next; tmp; tmp = tmp->next) + xwrite (STDOUT_FILENO, tmp->buffer, tmp->nbytes); + +free_lbuffers: + while (first) + { + tmp = first->next; + free ((char *) first); + first = tmp; + } + return errors; +} + +/* Print the last N_BYTES characters from the end of pipe FD. + This is a stripped down version of pipe_lines. + Return 0 if successful, 1 if an error occurred. */ + +static int +pipe_bytes (const char *pretty_filename, int fd, off_t n_bytes) +{ + struct charbuffer + { + int nbytes; + char buffer[BUFSIZ]; + struct charbuffer *next; + }; + typedef struct charbuffer CBUFFER; + CBUFFER *first, *last, *tmp; + int i; /* Index into buffers. */ + int total_bytes = 0; /* Total characters in all buffers. */ + int errors = 0; + + first = last = (CBUFFER *) xmalloc (sizeof (CBUFFER)); + first->nbytes = 0; + first->next = NULL; + tmp = (CBUFFER *) xmalloc (sizeof (CBUFFER)); + + /* Input is always read into a fresh buffer. */ + while ((tmp->nbytes = safe_read (fd, tmp->buffer, BUFSIZ)) > 0) + { + tmp->next = NULL; + + total_bytes += tmp->nbytes; + /* If there is enough room in the last buffer read, just append the new + one to it. This is because when reading from a pipe, `nbytes' can + often be very small. */ + if (tmp->nbytes + last->nbytes < BUFSIZ) + { + memcpy (&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes); + last->nbytes += tmp->nbytes; + } + else + { + /* If there's not enough room, link the new buffer onto the end of + the list, then either free up the oldest buffer for the next + read if that would leave enough characters, or else malloc a new + one. Some compaction mechanism is possible but probably not + worthwhile. */ + last = last->next = tmp; + if (total_bytes - first->nbytes > n_bytes) + { + tmp = first; + total_bytes -= first->nbytes; + first = first->next; + } + else + { + tmp = (CBUFFER *) xmalloc (sizeof (CBUFFER)); + } + } + } + if (tmp->nbytes == -1) + { + error (0, errno, "%s", pretty_filename); + errors = 1; + free ((char *) tmp); + goto free_cbuffers; + } + + free ((char *) tmp); + + /* Run through the list, printing characters. First, skip over unneeded + buffers. */ + for (tmp = first; total_bytes - tmp->nbytes > n_bytes; tmp = tmp->next) + total_bytes -= tmp->nbytes; + + /* Find the correct beginning, then print the rest of the file. + We made sure that `total_bytes' - `n_bytes' <= `tmp->nbytes'. */ + if (total_bytes > n_bytes) + i = total_bytes - n_bytes; + else + i = 0; + xwrite (STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i); + + for (tmp = tmp->next; tmp; tmp = tmp->next) + xwrite (STDOUT_FILENO, tmp->buffer, tmp->nbytes); + +free_cbuffers: + while (first) + { + tmp = first->next; + free ((char *) first); + first = tmp; + } + return errors; +} + +/* Skip N_BYTES characters from the start of pipe FD, and print + any extra characters that were read beyond that. + Return 1 on error, 0 if ok, -1 if EOF. */ + +static int +start_bytes (const char *pretty_filename, int fd, off_t n_bytes) +{ + char buffer[BUFSIZ]; + size_t bytes_read = 0; + + while (0 < n_bytes) + { + bytes_read = safe_read (fd, buffer, BUFSIZ); + if (bytes_read == 0) + return -1; + if (bytes_read == SAFE_READ_ERROR) + { + error (0, errno, "%s", pretty_filename); + return 1; + } + n_bytes -= bytes_read; + } + + if (n_bytes < 0) + xwrite (STDOUT_FILENO, &buffer[bytes_read + n_bytes], -n_bytes); + + return 0; +} + +/* Skip N_LINES lines at the start of file or pipe FD, and print + any extra characters that were read beyond that. + Return 1 on error, 0 if ok, -1 if EOF. */ + +static int +start_lines (const char *pretty_filename, int fd, long int n_lines) +{ + char buffer[BUFSIZ]; + size_t bytes_read = 0; + size_t bytes_to_skip = 0; + + if (n_lines == 0) + return 0; + + while (n_lines) + { + bytes_to_skip = 0; + bytes_read = safe_read (fd, buffer, BUFSIZ); + if (bytes_read == 0) /* EOF */ + return -1; + if (bytes_read == SAFE_READ_ERROR) /* error */ + { + error (0, errno, "%s", pretty_filename); + return 1; + } + + while (bytes_to_skip < bytes_read) + if (buffer[bytes_to_skip++] == '\n' && --n_lines == 0) + break; + } + + if (bytes_to_skip < bytes_read) + { + xwrite (STDOUT_FILENO, &buffer[bytes_to_skip], + bytes_read - bytes_to_skip); + } + + return 0; +} + +/* FIXME: describe */ + +static void +recheck (struct File_spec *f) +{ + /* open/fstat the file and announce if dev/ino have changed */ + struct stat new_stats; + int fd; + int fail = 0; + int is_stdin = (STREQ (f->name, "-")); + int was_tailable = f->tailable; + int prev_errnum = f->errnum; + int new_file; + + assert (valid_file_spec (f)); + + fd = (is_stdin ? STDIN_FILENO : open (f->name, O_RDONLY)); + + /* If the open fails because the file doesn't exist, + then mark the file as not tailable. */ + f->tailable = !(reopen_inaccessible_files && fd == -1); + + if (fd == -1 || fstat (fd, &new_stats) < 0) + { + fail = 1; + f->errnum = errno; + if (!f->tailable) + { + if (was_tailable) + { + /* FIXME-maybe: detect the case in which the file first becomes + unreadable (perms), and later becomes readable again and can + be seen to be the same file (dev/ino). Otherwise, tail prints + the entire contents of the file when it becomes readable. */ + error (0, f->errnum, _("`%s' has become inaccessible"), + pretty_name (f)); + } + else + { + /* say nothing... it's still not tailable */ + } + } + else if (prev_errnum != errno) + { + error (0, errno, "%s", pretty_name (f)); + } + } + else if (!IS_TAILABLE_FILE_TYPE (new_stats.st_mode)) + { + fail = 1; + f->errnum = -1; + error (0, 0, _("`%s' has been replaced with an untailable file;\ + giving up on this name"), + pretty_name (f)); + f->ignore = 1; + } + else + { + f->errnum = 0; + } + + new_file = 0; + if (fail) + { + close_fd (fd, pretty_name (f)); + close_fd (f->fd, pretty_name (f)); + f->fd = -1; + } + else if (prev_errnum && prev_errnum != ENOENT) + { + new_file = 1; + assert (f->fd == -1); + error (0, 0, _("`%s' has become accessible"), pretty_name (f)); + } + else if (f->ino != new_stats.st_ino || f->dev != new_stats.st_dev) + { + new_file = 1; + if (f->fd == -1) + { + error (0, 0, + _("`%s' has appeared; following end of new file"), + pretty_name (f)); + } + else + { + /* Close the old one. */ + close_fd (f->fd, pretty_name (f)); + + /* File has been replaced (e.g., via log rotation) -- + tail the new one. */ + error (0, 0, + _("`%s' has been replaced; following end of new file"), + pretty_name (f)); + } + } + else + { + if (f->fd == -1) + { + /* This happens when one iteration finds the file missing, + then the preceding pair is reused as the + file is recreated. */ + new_file = 1; + } + else + { + close_fd (fd, pretty_name (f)); + } + } + + if (new_file) + { + /* Record new file info in f. */ + f->fd = fd; + f->size = 0; /* Start at the beginning of the file... */ + f->dev = new_stats.st_dev; + f->ino = new_stats.st_ino; + f->n_unchanged_stats = 0; + f->n_consecutive_size_changes = 0; + f->ignore = 0; + xlseek (f->fd, f->size, SEEK_SET, pretty_name (f)); + } +} + +/* FIXME: describe */ + +static unsigned int +n_live_files (const struct File_spec *f, int n_files) +{ + int i; + unsigned int n_live = 0; + + for (i = 0; i < n_files; i++) + { + if (f[i].fd >= 0) + ++n_live; + } + return n_live; +} + +/* Tail NFILES files forever, or until killed. + The pertinent information for each file is stored in an entry of F. + Loop over each of them, doing an fstat to see if they have changed size, + and an occasional open/fstat to see if any dev/ino pair has changed. + If none of them have changed size in one iteration, sleep for a + while and try again. Continue until the user interrupts us. */ + +static void +tail_forever (struct File_spec *f, int nfiles, double sleep_interval) +{ + int last; + int writer_is_dead = 0; + + last = nfiles - 1; + + while (1) + { + int i; + int any_changed; + + any_changed = 0; + for (i = 0; i < nfiles; i++) + { + struct stat stats; + + if (f[i].ignore) + continue; + + if (f[i].fd < 0) + { + recheck (&f[i]); + continue; + } + + if (fstat (f[i].fd, &stats) < 0) + { + f[i].fd = -1; + f[i].errnum = errno; + error (0, errno, "%s", pretty_name (&f[i])); + continue; + } + + if (stats.st_size == f[i].size) + { + f[i].n_consecutive_size_changes = 0; + if ((max_n_unchanged_stats_between_opens + <= f[i].n_unchanged_stats++) + && follow_mode == Follow_name) + { + recheck (&f[i]); + f[i].n_unchanged_stats = 0; + } + continue; + } + + /* Ensure that a file that's unlinked or moved aside, yet always + growing will be recognized as having been renamed. */ + if ((max_n_consecutive_size_changes_between_opens + <= f[i].n_consecutive_size_changes++) + && follow_mode == Follow_name) + { + f[i].n_consecutive_size_changes = 0; + recheck (&f[i]); + continue; + } + + /* This file has changed size. Print out what we can, and + then keep looping. */ + + any_changed = 1; + + /* reset counter */ + f[i].n_unchanged_stats = 0; + + if (stats.st_size < f[i].size) + { + error (0, 0, _("%s: file truncated"), pretty_name (&f[i])); + last = i; + xlseek (f[i].fd, (off_t) stats.st_size, SEEK_SET, + pretty_name (&f[i])); + f[i].size = stats.st_size; + continue; + } + + if (i != last) + { + if (print_headers) + write_header (pretty_name (&f[i])); + last = i; + } + f[i].size += dump_remainder (pretty_name (&f[i]), f[i].fd, + COPY_TO_EOF); + } + + if (n_live_files (f, nfiles) == 0 && ! reopen_inaccessible_files) + { + error (0, 0, _("no files remaining")); + break; + } + + /* If none of the files changed size, sleep. */ + if (!any_changed) + { + if (writer_is_dead) + break; + + if (xnanosleep (sleep_interval)) + error (EXIT_FAILURE, errno, _("cannot read realtime clock")); + + /* Once the writer is dead, read the files once more to + avoid a race condition. */ + writer_is_dead = (pid != 0 + && kill (pid, 0) != 0 + /* Handle the case in which you cannot send a + signal to the writer, so kill fails and sets + errno to EPERM. */ + && errno != EPERM); + } + } +} + +/* Output the last N_BYTES bytes of file FILENAME open for reading in FD. + Return 0 if successful, 1 if an error occurred. */ + +static int +tail_bytes (const char *pretty_filename, int fd, off_t n_bytes) +{ + struct stat stats; + + /* We need binary input, since `tail' relies on `lseek' and byte counts, + while binary output will preserve the style (Unix/DOS) of text file. */ + SET_BINARY2 (fd, STDOUT_FILENO); + + if (fstat (fd, &stats)) + { + error (0, errno, "%s", pretty_filename); + return 1; + } + + if (from_start) + { + if (S_ISREG (stats.st_mode)) + { + xlseek (fd, n_bytes, SEEK_CUR, pretty_filename); + } + else + { + int t; + if ((t = start_bytes (pretty_filename, fd, n_bytes)) < 0) + return 0; + if (t) + return 1; + } + dump_remainder (pretty_filename, fd, COPY_TO_EOF); + } + else + { + if (S_ISREG (stats.st_mode)) + { + off_t current_pos, end_pos; + off_t bytes_remaining; + + if ((current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1 + && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1) + { + off_t diff; + /* Be careful here. The current position may actually be + beyond the end of the file. */ + bytes_remaining = (diff = end_pos - current_pos) < 0 ? 0 : diff; + } + else + { + error (0, errno, "%s", pretty_filename); + return 1; + } + + if (bytes_remaining <= n_bytes) + { + /* From the current position to end of file, there are no + more bytes than have been requested. So reposition the + file pointer to the incoming current position and print + everything after that. */ + xlseek (fd, current_pos, SEEK_SET, pretty_filename); + } + else + { + /* There are more bytes remaining than were requested. + Back up. */ + xlseek (fd, -n_bytes, SEEK_END, pretty_filename); + } + dump_remainder (pretty_filename, fd, n_bytes); + } + else + return pipe_bytes (pretty_filename, fd, n_bytes); + } + return 0; +} + +/* Output the last N_LINES lines of file FILENAME open for reading in FD. + Return 0 if successful, 1 if an error occurred. */ + +static int +tail_lines (const char *pretty_filename, int fd, long int n_lines) +{ + struct stat stats; + + /* We need binary input, since `tail' relies on `lseek' and byte counts, + while binary output will preserve the style (Unix/DOS) of text file. */ + SET_BINARY2 (fd, STDOUT_FILENO); + + if (fstat (fd, &stats)) + { + error (0, errno, "%s", pretty_filename); + return 1; + } + + if (from_start) + { + int t; + if ((t = start_lines (pretty_filename, fd, n_lines)) < 0) + return 0; + if (t) + return 1; + dump_remainder (pretty_filename, fd, COPY_TO_EOF); + } + else + { + off_t length; + off_t start_pos; + + /* Use file_lines only if FD refers to a regular file for + which lseek (... SEEK_END) works. */ + if (S_ISREG (stats.st_mode) + && (start_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1 + && start_pos < (length = lseek (fd, (off_t) 0, SEEK_END))) + { + if (length != 0 && file_lines (pretty_filename, fd, n_lines, + start_pos, length)) + return 1; + } + else + return pipe_lines (pretty_filename, fd, n_lines); + } + return 0; +} + +/* Display the last N_UNITS units of file FILENAME, open for reading + in FD. + Return 0 if successful, 1 if an error occurred. */ + +static int +tail (const char *pretty_filename, int fd, off_t n_units) +{ + if (count_lines) + return tail_lines (pretty_filename, fd, (long) n_units); + else + return tail_bytes (pretty_filename, fd, n_units); +} + +/* Display the last N_UNITS units of the file described by F. + Return 0 if successful, 1 if an error occurred. */ + +static int +tail_file (struct File_spec *f, off_t n_units) +{ + int fd, errors; + + int is_stdin = (STREQ (f->name, "-")); + + if (is_stdin) + { + have_read_stdin = 1; + fd = STDIN_FILENO; + } + else + { + fd = open (f->name, O_RDONLY); + } + + f->tailable = !(reopen_inaccessible_files && fd == -1); + + if (fd == -1) + { + if (forever) + { + f->fd = -1; + f->errnum = errno; + f->ignore = 0; + f->ino = 0; + f->dev = 0; + } + error (0, errno, "%s", pretty_name (f)); + errors = 1; + } + else + { + if (print_headers) + write_header (pretty_name (f)); + errors = tail (pretty_name (f), fd, n_units); + if (forever) + { + struct stat stats; + + f->errnum = 0; + if (fstat (fd, &stats) < 0) + { + errors = 1; + f->errnum = errno; + error (0, errno, "%s", pretty_name (f)); + } + else if (!IS_TAILABLE_FILE_TYPE (stats.st_mode)) + { + error (0, 0, _("%s: cannot follow end of this type of file;\ + giving up on this name"), + pretty_name (f)); + errors = 1; + f->errnum = -1; + f->ignore = 1; + } + + if (errors) + { + close_fd (fd, pretty_name (f)); + f->fd = -1; + } + else + { + f->fd = fd; + f->size = stats.st_size; + f->dev = stats.st_dev; + f->ino = stats.st_ino; + f->n_unchanged_stats = 0; + f->n_consecutive_size_changes = 0; + f->ignore = 0; + } + } + else + { + if (!is_stdin && close (fd)) + { + error (0, errno, "%s", pretty_name (f)); + errors = 1; + } + } + } + + return errors; +} + +/* If the command line arguments are of the obsolescent form and the + option string is well-formed, set *FAIL to zero, set *N_UNITS, the + globals COUNT_LINES, FOREVER, and FROM_START, and return non-zero. + Otherwise, if the command line arguments appear to be of the + obsolescent form but the option string is malformed, set *FAIL to + non-zero, don't modify any other parameter or global variable, and + return non-zero. Otherwise, return zero and don't modify any parameter + or global variable. */ + +static int +parse_obsolescent_option (int argc, const char *const *argv, + off_t *n_units, int *fail) +{ + const char *p = argv[1]; + const char *n_string = NULL; + const char *n_string_end; + bool obsolete_usage; + + int t_from_start; + int t_count_lines; + int t_forever; + + /* With the obsolescent form, there is one option string and + (technically) at most one file argument. But we allow two or more + by default. */ + if (argc < 2) + return 0; + + obsolete_usage = (posix2_version () < 200112); + + /* If P starts with `+' and the POSIX version predates 1003.1-2001, + or if P starts with `-N' (where N is a digit), or `-l', then it + is obsolescent. Return zero otherwise. */ + if (! ((p[0] == '+' && obsolete_usage) + || (p[0] == '-' && (p[1] == 'l' || ISDIGIT (p[1]))))) + return 0; + + if (*p == '+') + t_from_start = 1; + else if (*p == '-') + t_from_start = 0; + else + return 0; + + ++p; + if (ISDIGIT (*p)) + { + n_string = p; + do + { + ++p; + } + while (ISDIGIT (*p)); + } + n_string_end = p; + + t_count_lines = 1; + if (*p == 'c' || *p == 'b') + { + t_count_lines = 0; + ++p; + } + else if (*p == 'l') + { + ++p; + } + + t_forever = 0; + if (*p == 'f') + { + t_forever = 1; + ++p; + } + + if (*p != '\0') + { + /* If (argv[1] begins with a `+' or if it begins with `-' followed + by a digit), but has an invalid suffix character, give a diagnostic + and indicate to caller that this *is* of the obsolescent form, + but that it's an invalid option. */ + if (t_from_start || n_string) + { + error (0, 0, + _("%c: invalid suffix character in obsolescent option" ), *p); + *fail = 1; + return 1; + } + + /* Otherwise, it might be a valid non-obsolescent option like -n. */ + return 0; + } + + *fail = 0; + if (n_string == NULL) + *n_units = DEFAULT_N_LINES; + else + { + strtol_error s_err; + uintmax_t tmp; + char *end; + + s_err = xstrtoumax (n_string, &end, 10, &tmp, + *n_string_end == 'b' ? "b" : NULL); + if (s_err == LONGINT_OK && tmp <= OFF_T_MAX) + *n_units = (off_t) tmp; + else + { + /* Extract a NUL-terminated string for the error message. */ + size_t len = n_string_end - n_string; + char *n_string_tmp = xmalloc (len + 1); + + strncpy (n_string_tmp, n_string, len); + n_string_tmp[len] = '\0'; + + error (0, 0, + _("%s: %s is so large that it is not representable"), + n_string_tmp, (t_count_lines + ? _("number of lines") + : _("number of bytes"))); + free (n_string_tmp); + *fail = 1; + } + } + + if (!*fail) + { + if (argc > 3) + { + /* When POSIXLY_CORRECT is set, enforce the `at most one + file argument' requirement. */ + if (getenv ("POSIXLY_CORRECT")) + { + error (0, 0, _("\ +too many arguments; When using tail's obsolescent option syntax (%s)\n\ +there may be no more than one file argument. Use the equivalent -n or -c\n\ +option instead."), argv[1]); + *fail = 1; + return 1; + } + +#if DISABLED /* FIXME: enable or remove this warning. */ + error (0, 0, _("\ +Warning: it is not portable to use two or more file arguments with\n\ +tail's obsolescent option syntax (%s). Use the equivalent -n or -c\n\ +option instead."), argv[1]); +#endif + } + + if (! obsolete_usage) + { + error (0, 0, _("`%s' option is obsolete; use `%s-%c %.*s'"), + argv[1], t_forever ? " -f" : "", t_count_lines ? 'n' : 'c', + (int) (n_string_end - n_string), n_string); + usage (EXIT_FAILURE); + } + + /* Set globals. */ + from_start = t_from_start; + count_lines = t_count_lines; + forever = t_forever; + } + + return 1; +} + +static void +parse_options (int argc, char **argv, + off_t *n_units, enum header_mode *header_mode, + double *sleep_interval) +{ + int c; + + count_lines = 1; + forever = from_start = print_headers = 0; + + while ((c = getopt_long (argc, argv, "c:n:fFqs:v", long_options, NULL)) + != -1) + { + switch (c) + { + case 0: + break; + + case 'F': + forever = 1; + follow_mode = Follow_name; + reopen_inaccessible_files = 1; + break; + + case 'c': + case 'n': + count_lines = (c == 'n'); + if (*optarg == '+') + from_start = 1; + else if (*optarg == '-') + ++optarg; + + { + strtol_error s_err; + uintmax_t n; + s_err = xstrtoumax (optarg, NULL, 10, &n, "bkm"); + if (s_err != LONGINT_OK) + { + error (EXIT_FAILURE, 0, "%s: %s", optarg, + (c == 'n' + ? _("invalid number of lines") + : _("invalid number of bytes"))); + } + + if (OFF_T_MAX < n) + error (EXIT_FAILURE, 0, + _("%s is larger than the maximum file size on this system"), + optarg); + *n_units = (off_t) n; + } + break; + + case 'f': + case LONG_FOLLOW_OPTION: + forever = 1; + if (optarg == NULL) + follow_mode = DEFAULT_FOLLOW_MODE; + else + follow_mode = XARGMATCH ("--follow", optarg, + follow_mode_string, follow_mode_map); + break; + + case RETRY_OPTION: + reopen_inaccessible_files = 1; + break; + + case MAX_UNCHANGED_STATS_OPTION: + /* --max-unchanged-stats=N */ + if (xstrtoul (optarg, NULL, 10, + &max_n_unchanged_stats_between_opens, "") != LONGINT_OK) + { + error (EXIT_FAILURE, 0, + _("%s: invalid maximum number of unchanged stats between opens"), + optarg); + } + break; + + case MAX_CONSECUTIVE_SIZE_CHANGES_OPTION: + /* --max-consecutive-size-changes=N */ + if (xstrtoul (optarg, NULL, 10, + &max_n_consecutive_size_changes_between_opens, "") + != LONGINT_OK) + { + error (EXIT_FAILURE, 0, + _("%s: invalid maximum number of consecutive size changes"), + optarg); + } + break; + + case PID_OPTION: + { + strtol_error s_err; + unsigned long int tmp_ulong; + s_err = xstrtoul (optarg, NULL, 10, &tmp_ulong, ""); + if (s_err != LONGINT_OK || tmp_ulong > PID_T_MAX) + { + error (EXIT_FAILURE, 0, _("%s: invalid PID"), optarg); + } + pid = tmp_ulong; + } + break; + + case 'q': + *header_mode = never; + break; + + case 's': + { + double s; + if (xstrtod (optarg, NULL, &s) || ! (0 <= s)) + error (EXIT_FAILURE, 0, + _("%s: invalid number of seconds"), optarg); + *sleep_interval = s; + } + break; + + case 'v': + *header_mode = always; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (reopen_inaccessible_files && follow_mode != Follow_name) + error (0, 0, _("warning: --retry is useful only when following by name")); + + if (pid && !forever) + error (0, 0, + _("warning: PID ignored; --pid=PID is useful only when following")); + else if (pid && kill (pid, 0) != 0 && errno == ENOSYS) + { + error (0, 0, _("warning: --pid=PID is not supported on this system")); + pid = 0; + } +} + +int +main (int argc, char **argv) +{ + enum header_mode header_mode = multiple_files; + int exit_status = 0; + /* If from_start, the number of items to skip before printing; otherwise, + the number of items at the end of the file to print. Although the type + is signed, the value is never negative. */ + off_t n_units = DEFAULT_N_LINES; + int n_files; + char **file; + struct File_spec *F; + int i; + + /* The number of seconds to sleep between iterations. + During one iteration, every file name or descriptor is checked to + see if it has changed. */ + double sleep_interval = 1.0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + have_read_stdin = 0; + + { + int fail; + + if (parse_obsolescent_option (argc, + (const char *const *) argv, + &n_units, &fail)) + { + if (fail) + exit (EXIT_FAILURE); + optind = 2; + } + else + { + parse_options (argc, argv, &n_units, &header_mode, &sleep_interval); + } + } + + /* To start printing with item N_UNITS from the start of the file, skip + N_UNITS - 1 items. `tail -n +0' is actually meaningless, but for Unix + compatibility it's treated the same as `tail -n +1'. */ + if (from_start) + { + if (n_units) + --n_units; + } + + n_files = argc - optind; + file = argv + optind; + + if (n_files == 0) + { + static char *dummy_stdin = "-"; + n_files = 1; + file = &dummy_stdin; + } + + F = (struct File_spec *) xmalloc (n_files * sizeof (F[0])); + for (i = 0; i < n_files; i++) + F[i].name = file[i]; + + if (header_mode == always + || (header_mode == multiple_files && n_files > 1)) + print_headers = 1; + + for (i = 0; i < n_files; i++) + exit_status |= tail_file (&F[i], n_units); + + if (forever) + { + /* This fflush appears to be required only on Solaris2.7. */ + if (fflush (stdout) < 0) + error (EXIT_FAILURE, errno, _("write error")); + + SETVBUF (stdout, NULL, _IONBF, 0); + tail_forever (F, n_files, sleep_interval); + } + + if (have_read_stdin && close (STDIN_FILENO) < 0) + error (EXIT_FAILURE, errno, "-"); + exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/tee.c b/src/apps/bin/coreutils-5.0/src/tee.c new file mode 100644 index 0000000000..5c11dccef6 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/tee.c @@ -0,0 +1,236 @@ +/* tee - read from standard input and write to standard output and files. + Copyright (C) 85,1990-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Mike Parker, Richard M. Stallman, and David MacKenzie */ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "error.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "tee" + +#define AUTHORS N_ ("Mike Parker, Richard M. Stallman, and David MacKenzie") + +static int tee (int nfiles, const char **files); + +/* If nonzero, append to output files rather than truncating them. */ +static int append; + +/* If nonzero, ignore interrupts. */ +static int ignore_interrupts; + +/* The name that this program was run with. */ +char *program_name; + +static struct option const long_options[] = +{ + {"append", no_argument, NULL, 'a'}, + {"ignore-interrupts", no_argument, NULL, 'i'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); + fputs (_("\ +Copy standard input to each FILE, and also to standard output.\n\ +\n\ + -a, --append append to the given FILEs, do not overwrite\n\ + -i, --ignore-interrupts ignore interrupt signals\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int errs; + int optc; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + append = 0; + ignore_interrupts = 0; + + while ((optc = getopt_long (argc, argv, "ai", long_options, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + + case 'a': + append = 1; + break; + + case 'i': + ignore_interrupts = 1; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (ignore_interrupts) + { +#ifdef _POSIX_SOURCE + struct sigaction sigact; + + sigact.sa_handler = SIG_IGN; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (SIGINT, &sigact, NULL); +#else /* !_POSIX_SOURCE */ + signal (SIGINT, SIG_IGN); +#endif /* _POSIX_SOURCE */ + } + + /* Don't let us be killed if one of the output files is a pipe that + doesn't consume all its input. */ +#ifdef _POSIX_SOURCE + { + struct sigaction sigact; + + sigact.sa_handler = SIG_IGN; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (SIGPIPE, &sigact, NULL); + } +#else + signal (SIGPIPE, SIG_IGN); +#endif + + /* Do *not* warn if tee is given no file arguments. + POSIX requires that it work when given no arguments. */ + + errs = tee (argc - optind, (const char **) &argv[optind]); + if (close (STDIN_FILENO) != 0) + error (EXIT_FAILURE, errno, _("standard input")); + + exit (errs); +} + +/* Copy the standard input into each of the NFILES files in FILES + and into the standard output. + Return 0 if successful, 1 if any errors occur. */ + +static int +tee (int nfiles, const char **files) +{ + FILE **descriptors; + char buffer[BUFSIZ]; + int bytes_read, i; + int ret = 0; + const char *mode_string = (append ? "a" : "w"); + + descriptors = (FILE **) xmalloc ((nfiles + 1) * sizeof (descriptors[0])); + + /* Move all the names `up' one in the argv array to make room for + the entry for standard output. This writes into argv[argc]. */ + for (i = nfiles; i >= 1; i--) + files[i] = files[i - 1]; + + SET_BINARY2 (0, 1); + + /* In the array of NFILES + 1 descriptors, make + the first one correspond to standard output. */ + descriptors[0] = stdout; + files[0] = _("standard output"); + SETVBUF (stdout, NULL, _IONBF, 0); + + for (i = 1; i <= nfiles; i++) + { + descriptors[i] = fopen (files[i], mode_string); + if (descriptors[i] == NULL) + { + error (0, errno, "%s", files[i]); + ret = 1; + } + else + { + SETVBUF (descriptors[i], NULL, _IONBF, 0); + SET_BINARY (fileno (descriptors[i])); + } + } + + while (1) + { + bytes_read = read (0, buffer, sizeof buffer); +#ifdef EINTR + if (bytes_read < 0 && errno == EINTR) + continue; +#endif + if (bytes_read <= 0) + break; + + /* Write to all NFILES + 1 descriptors. + Standard output is the first one. */ + for (i = 0; i <= nfiles; i++) + { + if (descriptors[i] != NULL) + fwrite (buffer, bytes_read, 1, descriptors[i]); + } + } + + if (bytes_read == -1) + { + error (0, errno, _("read error")); + ret = 1; + } + + /* Close the files, but not standard output. */ + for (i = 1; i <= nfiles; i++) + if (descriptors[i] != NULL + && (ferror (descriptors[i]) || fclose (descriptors[i]) == EOF)) + { + error (0, errno, "%s", files[i]); + ret = 1; + } + + free (descriptors); + + return ret; +} diff --git a/src/apps/bin/coreutils-5.0/src/test.c b/src/apps/bin/coreutils-5.0/src/test.c new file mode 100644 index 0000000000..3b01f13d43 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/test.c @@ -0,0 +1,1128 @@ +/* GNU test program (ksb and mjb) */ + +/* Modified to run with the GNU shell by bfox. */ + +/* Copyright (C) 1987-2003 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + Bash is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Define TEST_STANDALONE to get the /bin/test version. Otherwise, you get + the shell builtin version. */ +/* #define TEST_STANDALONE */ + +#include +#include +#include + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "test" + +#define TEST_STANDALONE 1 + +#if !defined (TEST_STANDALONE) +# include "shell.h" +# include "posixstat.h" +# include "filecntl.h" +#else /* TEST_STANDALONE */ +# include "system.h" +# include "error.h" +# include "euidaccess.h" +# if !defined (S_IXUGO) +# define S_IXUGO 0111 +# endif /* S_IXUGO */ +# if defined (_POSIX_VERSION) +# include +# else /* !_POSIX_VERSION */ +# include +# endif /* _POSIX_VERSION */ +# define whitespace(c) (((c) == ' ') || ((c) == '\t')) +# define digit(c) ((c) >= '0' && (c) <= '9') +# define digit_value(c) ((c) - '0') +char *program_name; +#endif /* TEST_STANDALONE */ + +#if !defined (_POSIX_VERSION) +# include +#endif /* !_POSIX_VERSION */ + +#include +#ifndef errno +extern int errno; +#endif + +#undef STREQ +#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp (a, b) == 0) + +#if !defined (member) +# define member(c, s) ((c) ? (strchr ((s), (c)) ? 1 : 0) : 0) +#endif /* !member */ + +extern gid_t getegid (); +extern uid_t geteuid (); + +#if !defined (R_OK) +# define R_OK 4 +# define W_OK 2 +# define X_OK 1 +# define F_OK 0 +#endif /* R_OK */ + +/* This name is used solely when printing --version information. */ +#define PROGRAM_NAME "test" + +/* The following few defines control the truth and false output of each stage. + TRUE and FALSE are what we use to compute the final output value. + SHELL_BOOLEAN is the form which returns truth or falseness in shell terms. + TRUTH_OR is how to do logical or with TRUE and FALSE. + TRUTH_AND is how to do logical and with TRUE and FALSE.. + Default is TRUE = 1, FALSE = 0, TRUTH_OR = a | b, TRUTH_AND = a & b, + SHELL_BOOLEAN = (!value). */ +#define TRUE 1 +#define FALSE 0 +#define SHELL_BOOLEAN(value) (!(value)) +#define TRUTH_OR(a, b) ((a) | (b)) +#define TRUTH_AND(a, b) ((a) & (b)) + +#if defined (TEST_STANDALONE) +# define test_exit(val) exit (val) +#else + static jmp_buf test_exit_buf; + static int test_error_return = 0; +# define test_exit(val) test_error_return = val, longjmp (test_exit_buf, 1) +#endif /* !TEST_STANDALONE */ + +static int pos; /* The offset of the current argument in ARGV. */ +static int argc; /* The number of arguments present in ARGV. */ +static char **argv; /* The argument list. */ + +static int unop (int op); +static int binop (char *s); +static int unary_operator (void); +static int binary_operator (void); +static int two_arguments (void); +static int three_arguments (void); +static int posixtest (void); + +static int expr (void); +static int term (void); +static int and (void); +static int or (void); + +static void test_syntax_error (char const *format, char const *arg) + ATTRIBUTE_NORETURN; +static void beyond (void) ATTRIBUTE_NORETURN; + +static void +test_syntax_error (char const *format, char const *arg) +{ + fprintf (stderr, "%s: ", argv[0]); + fprintf (stderr, format, arg); + fflush (stderr); + test_exit (SHELL_BOOLEAN (FALSE)); +} + +#if HAVE_SETREUID && HAVE_SETREGID +/* Do the same thing access(2) does, but use the effective uid and gid. */ + +static int +eaccess (char const *file, int mode) +{ + static int have_ids; + static uid_t uid, euid; + static gid_t gid, egid; + int result; + + if (have_ids == 0) + { + have_ids = 1; + uid = getuid (); + gid = getgid (); + euid = geteuid (); + egid = getegid (); + } + + /* Set the real user and group IDs to the effective ones. */ + if (uid != euid) + setreuid (euid, uid); + if (gid != egid) + setregid (egid, gid); + + result = access (file, mode); + + /* Restore them. */ + if (uid != euid) + setreuid (uid, euid); + if (gid != egid) + setregid (gid, egid); + + return result; +} +#else +# define eaccess(F, M) euidaccess (F, M) +#endif + +/* Increment our position in the argument list. Check that we're not + past the end of the argument list. This check is supressed if the + argument is FALSE. Made a macro for efficiency. */ +#define advance(f) \ + do \ + { \ + ++pos; \ + if ((f) && pos >= argc) \ + beyond (); \ + } \ + while (0) + +#if !defined (advance) +static int +advance (int f) +{ + ++pos; + + if (f && pos >= argc) + beyond (); +} +#endif /* advance */ + +#define unary_advance() \ + do \ + { \ + advance (1); \ + ++pos; \ + } \ + while (0) + +/* + * beyond - call when we're beyond the end of the argument list (an + * error condition) + */ +static void +beyond (void) +{ + test_syntax_error (_("argument expected\n"), NULL); +} + +/* Syntax error for when an integer argument was expected, but + something else was found. */ +static void +integer_expected_error (char const *pch) +{ + test_syntax_error (_("integer expression expected %s\n"), pch); +} + +/* Return nonzero if the characters pointed to by STRING constitute a + valid number. Stuff the converted number into RESULT if RESULT is + not null. */ +static int +isint (register char *string, intmax_t *result) +{ + int sign; + intmax_t value; + + sign = 1; + value = 0; + + if (result) + *result = 0; + + /* Skip leading whitespace characters. */ + while (whitespace (*string)) + string++; + + if (!*string) + return (0); + + /* We allow leading `-' or `+'. */ + if (*string == '-' || *string == '+') + { + if (!digit (string[1])) + return (0); + + if (*string == '-') + sign = -1; + + string++; + } + + while (digit (*string)) + { + if (result) + value = (value * 10) + digit_value (*string); + string++; + } + + /* Skip trailing whitespace, if any. */ + while (whitespace (*string)) + string++; + + /* Error if not at end of string. */ + if (*string) + return (0); + + if (result) + { + value *= sign; + *result = value; + } + + return (1); +} + +/* Find the modification time of FILE, and stuff it into *AGE. + Return 0 if successful, -1 if not. */ +static int +age_of (char *filename, time_t *age) +{ + struct stat finfo; + int r = stat (filename, &finfo); + if (r == 0) + *age = finfo.st_mtime; + return r; +} + +/* + * term - parse a term and return 1 or 0 depending on whether the term + * evaluates to true or false, respectively. + * + * term ::= + * '-'('h'|'d'|'f'|'r'|'s'|'w'|'c'|'b'|'p'|'u'|'g'|'k') filename + * '-'('L'|'x') filename + * '-t' [ int ] + * '-'('z'|'n') string + * string + * string ('!='|'=') string + * '-'(eq|ne|le|lt|ge|gt) + * file '-'(nt|ot|ef) file + * '(' ')' + * int ::= + * '-l' string + * positive and negative integers + */ +static int +term (void) +{ + int value; + + if (pos >= argc) + beyond (); + + /* Deal with leading "not"'s. */ + if ('!' == argv[pos][0] && '\000' == argv[pos][1]) + { + value = FALSE; + while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1]) + { + advance (1); + value ^= (TRUE); + } + + return (value ^ (term ())); + } + + /* A paren-bracketed argument. */ + if (argv[pos][0] == '(' && !argv[pos][1]) + { + advance (1); + value = expr (); + if (!argv[pos]) + test_syntax_error (_("')' expected\n"), NULL); + else + if (argv[pos][0] != ')' || argv[pos][1]) + test_syntax_error (_("')' expected, found %s\n"), argv[pos]); + advance (0); + return (TRUE == (value)); + } + + /* are there enough arguments left that this could be dyadic? */ + if (((pos + 3 <= argc) && binop (argv[pos + 1])) || + ((pos + 4 <= argc && STREQ (argv[pos], "-l") && binop (argv[pos + 2])))) + value = binary_operator (); + + /* Might be a switch type argument */ + else if ('-' == argv[pos][0] && argv[pos][1] && 0 == argv[pos][2]) + { + if (unop (argv[pos][1])) + value = unary_operator (); + else + test_syntax_error (_("%s: unary operator expected\n"), argv[pos]); + } + else + { + value = (argv[pos][0] != '\0'); + advance (0); + } + + return (value); +} + +static int +binary_operator (void) +{ + register int op; + struct stat stat_buf, stat_spare; + intmax_t l, r; + int value; + /* Are the left and right integer expressions of the form '-l string'? */ + int l_is_l, r_is_l; + + if (strcmp (argv[pos], "-l") == 0) + { + l_is_l = 1; + op = pos + 2; + + /* Make sure that OP is still a valid binary operator. */ + if ((op >= argc - 1) || (binop (argv[op]) == 0)) + test_syntax_error (_("%s: binary operator expected\n"), argv[op]); + + advance (0); + } + else + { + l_is_l = 0; + op = pos + 1; + } + + if ((op < argc - 2) && (strcmp (argv[op + 1], "-l") == 0)) + { + r_is_l = 1; + advance (0); + } + else + r_is_l = 0; + + if (argv[op][0] == '-') + { + /* check for eq, nt, and stuff */ + switch (argv[op][1]) + { + default: + break; + + case 'l': + if (argv[op][2] == 't' && !argv[op][3]) + { + /* lt */ + if (l_is_l) + l = strlen (argv[op - 1]); + else + { + if (!isint (argv[op - 1], &l)) + integer_expected_error (_("before -lt")); + } + + if (r_is_l) + r = strlen (argv[op + 2]); + else + { + if (!isint (argv[op + 1], &r)) + integer_expected_error (_("after -lt")); + } + pos += 3; + return (TRUE == (l < r)); + } + + if (argv[op][2] == 'e' && !argv[op][3]) + { + /* le */ + if (l_is_l) + l = strlen (argv[op - 1]); + else + { + if (!isint (argv[op - 1], &l)) + integer_expected_error (_("before -le")); + } + if (r_is_l) + r = strlen (argv[op + 2]); + else + { + if (!isint (argv[op + 1], &r)) + integer_expected_error (_("after -le")); + } + pos += 3; + return (TRUE == (l <= r)); + } + break; + + case 'g': + if (argv[op][2] == 't' && !argv[op][3]) + { + /* gt integer greater than */ + if (l_is_l) + l = strlen (argv[op - 1]); + else + { + if (!isint (argv[op - 1], &l)) + integer_expected_error (_("before -gt")); + } + if (r_is_l) + r = strlen (argv[op + 2]); + else + { + if (!isint (argv[op + 1], &r)) + integer_expected_error (_("after -gt")); + } + pos += 3; + return (TRUE == (l > r)); + } + + if (argv[op][2] == 'e' && !argv[op][3]) + { + /* ge - integer greater than or equal to */ + if (l_is_l) + l = strlen (argv[op - 1]); + else + { + if (!isint (argv[op - 1], &l)) + integer_expected_error (_("before -ge")); + } + if (r_is_l) + r = strlen (argv[op + 2]); + else + { + if (!isint (argv[op + 1], &r)) + integer_expected_error (_("after -ge")); + } + pos += 3; + return (TRUE == (l >= r)); + } + break; + + case 'n': + if (argv[op][2] == 't' && !argv[op][3]) + { + /* nt - newer than */ + time_t lt, rt; + int le, re; + pos += 3; + if (l_is_l || r_is_l) + test_syntax_error (_("-nt does not accept -l\n"), NULL); + le = age_of (argv[op - 1], <); + re = age_of (argv[op + 1], &rt); + return le > re || (le == 0 && lt > rt); + } + + if (argv[op][2] == 'e' && !argv[op][3]) + { + /* ne - integer not equal */ + if (l_is_l) + l = strlen (argv[op - 1]); + else + { + if (!isint (argv[op - 1], &l)) + integer_expected_error (_("before -ne")); + } + if (r_is_l) + r = strlen (argv[op + 2]); + else + { + if (!isint (argv[op + 1], &r)) + integer_expected_error (_("after -ne")); + } + pos += 3; + return (TRUE == (l != r)); + } + break; + + case 'e': + if (argv[op][2] == 'q' && !argv[op][3]) + { + /* eq - integer equal */ + if (l_is_l) + l = strlen (argv[op - 1]); + else + { + if (!isint (argv[op - 1], &l)) + integer_expected_error (_("before -eq")); + } + if (r_is_l) + r = strlen (argv[op + 2]); + else + { + if (!isint (argv[op + 1], &r)) + integer_expected_error (_("after -eq")); + } + pos += 3; + return (TRUE == (l == r)); + } + + if (argv[op][2] == 'f' && !argv[op][3]) + { + /* ef - hard link? */ + pos += 3; + if (l_is_l || r_is_l) + test_syntax_error (_("-ef does not accept -l\n"), NULL); + if (stat (argv[op - 1], &stat_buf) < 0) + return (FALSE); + if (stat (argv[op + 1], &stat_spare) < 0) + return (FALSE); + return (TRUE == + (stat_buf.st_dev == stat_spare.st_dev && + stat_buf.st_ino == stat_spare.st_ino)); + } + break; + + case 'o': + if ('t' == argv[op][2] && '\000' == argv[op][3]) + { + /* ot - older than */ + time_t lt, rt; + int le, re; + pos += 3; + if (l_is_l || r_is_l) + test_syntax_error (_("-ot does not accept -l\n"), NULL); + le = age_of (argv[op - 1], <); + re = age_of (argv[op + 1], &rt); + return le < re || (re == 0 && lt < rt); + } + break; + } + test_syntax_error (_("unknown binary operator"), argv[op]); + } + + if (argv[op][0] == '=' && !argv[op][1]) + { + value = (strcmp (argv[pos], argv[pos + 2]) == 0); + pos += 3; + return (TRUE == value); + } + + if (strcmp (argv[op], "!=") == 0) + { + value = (strcmp (argv[pos], argv[pos + 2]) != 0); + pos += 3; + return (TRUE == value); + } + + /* Not reached. */ + abort (); +} + +static int +unary_operator (void) +{ + int value; + struct stat stat_buf; + + switch (argv[pos][1]) + { + default: + return (FALSE); + + /* All of the following unary operators use unary_advance (), which + checks to make sure that there is an argument, and then advances + pos right past it. This means that pos - 1 is the location of the + argument. */ + + case 'a': /* file exists in the file system? */ + case 'e': + unary_advance (); + value = -1 != stat (argv[pos - 1], &stat_buf); + return (TRUE == value); + + case 'r': /* file is readable? */ + unary_advance (); + value = -1 != eaccess (argv[pos - 1], R_OK); + return (TRUE == value); + + case 'w': /* File is writable? */ + unary_advance (); + value = -1 != eaccess (argv[pos - 1], W_OK); + return (TRUE == value); + + case 'x': /* File is executable? */ + unary_advance (); + value = -1 != eaccess (argv[pos - 1], X_OK); + return (TRUE == value); + + case 'O': /* File is owned by you? */ + unary_advance (); + if (stat (argv[pos - 1], &stat_buf) < 0) + return (FALSE); + + return (TRUE == (geteuid () == stat_buf.st_uid)); + + case 'G': /* File is owned by your group? */ + unary_advance (); + if (stat (argv[pos - 1], &stat_buf) < 0) + return (FALSE); + + return (TRUE == (getegid () == stat_buf.st_gid)); + + case 'f': /* File is a file? */ + unary_advance (); + if (stat (argv[pos - 1], &stat_buf) < 0) + return (FALSE); + + /* Under POSIX, -f is true if the given file exists + and is a regular file. */ + return (TRUE == ((S_ISREG (stat_buf.st_mode)) || + (0 == (stat_buf.st_mode & S_IFMT)))); + + case 'd': /* File is a directory? */ + unary_advance (); + if (stat (argv[pos - 1], &stat_buf) < 0) + return (FALSE); + + return (TRUE == (S_ISDIR (stat_buf.st_mode))); + + case 's': /* File has something in it? */ + unary_advance (); + if (stat (argv[pos - 1], &stat_buf) < 0) + return (FALSE); + + return (TRUE == (stat_buf.st_size > (off_t) 0)); + + case 'S': /* File is a socket? */ +#if !defined (S_ISSOCK) + return (FALSE); +#else + unary_advance (); + + if (stat (argv[pos - 1], &stat_buf) < 0) + return (FALSE); + + return (TRUE == (S_ISSOCK (stat_buf.st_mode))); +#endif /* S_ISSOCK */ + + case 'c': /* File is character special? */ + unary_advance (); + if (stat (argv[pos - 1], &stat_buf) < 0) + return (FALSE); + + return (TRUE == (S_ISCHR (stat_buf.st_mode))); + + case 'b': /* File is block special? */ + unary_advance (); + if (stat (argv[pos - 1], &stat_buf) < 0) + return (FALSE); + + return (TRUE == (S_ISBLK (stat_buf.st_mode))); + + case 'p': /* File is a named pipe? */ + unary_advance (); +#ifndef S_ISFIFO + return (FALSE); +#else + if (stat (argv[pos - 1], &stat_buf) < 0) + return (FALSE); + return (TRUE == (S_ISFIFO (stat_buf.st_mode))); +#endif /* S_ISFIFO */ + + case 'L': /* Same as -h */ + /*FALLTHROUGH*/ + + case 'h': /* File is a symbolic link? */ + unary_advance (); +#ifndef S_ISLNK + return (FALSE); +#else + /* An empty filename is not a valid pathname. */ + if ((argv[pos - 1][0] == '\0') || + (lstat (argv[pos - 1], &stat_buf) < 0)) + return (FALSE); + + return (TRUE == (S_ISLNK (stat_buf.st_mode))); +#endif /* S_IFLNK */ + + case 'u': /* File is setuid? */ + unary_advance (); +#ifndef S_ISUID + return (FALSE); +#else + if (stat (argv[pos - 1], &stat_buf) < 0) + return (FALSE); + + return (TRUE == (0 != (stat_buf.st_mode & S_ISUID))); +#endif + + case 'g': /* File is setgid? */ + unary_advance (); +#ifndef S_ISGID + return (FALSE); +#else + if (stat (argv[pos - 1], &stat_buf) < 0) + return (FALSE); + + return (TRUE == (0 != (stat_buf.st_mode & S_ISGID))); +#endif + + case 'k': /* File has sticky bit set? */ + unary_advance (); + if (stat (argv[pos - 1], &stat_buf) < 0) + return (FALSE); +#ifndef S_ISVTX + /* This is not Posix, and is not defined on some Posix systems. */ + return (FALSE); +#else + return (TRUE == (0 != (stat_buf.st_mode & S_ISVTX))); +#endif + + case 't': /* File (fd) is a terminal? */ + { + intmax_t fd; + advance (0); + if (pos < argc) + { + if (!isint (argv[pos], &fd)) + integer_expected_error (_("after -t")); + advance (0); + } + else + { + fd = 1; + } + return (TRUE == (fd == (int) fd && isatty (fd))); + } + + case 'n': /* True if arg has some length. */ + unary_advance (); + return (TRUE == (argv[pos - 1][0] != 0)); + + case 'z': /* True if arg has no length. */ + unary_advance (); + return (TRUE == (argv[pos - 1][0] == '\0')); + } +} + +/* + * and: + * term + * term '-a' and + */ +static int +and (void) +{ + int value; + + value = term (); + while ((pos < argc) && strcmp (argv[pos], "-a") == 0) + { + advance (0); + value = TRUTH_AND (value, and ()); + } + return (TRUE == value); +} + +/* + * or: + * and + * and '-o' or + */ +static int +or (void) +{ + int value; + + value = and (); + + while ((pos < argc) && strcmp (argv[pos], "-o") == 0) + { + advance (0); + value = TRUTH_OR (value, or ()); + } + + return (TRUE == value); +} + +/* + * expr: + * or + */ +static int +expr (void) +{ + if (pos >= argc) + beyond (); + + return (FALSE ^ (or ())); /* Same with this. */ +} + +/* Return TRUE if S is one of the test command's binary operators. */ +static int +binop (char *s) +{ + return ((STREQ (s, "=")) || (STREQ (s, "!=")) || (STREQ (s, "-nt")) || + (STREQ (s, "-ot")) || (STREQ (s, "-ef")) || (STREQ (s, "-eq")) || + (STREQ (s, "-ne")) || (STREQ (s, "-lt")) || (STREQ (s, "-le")) || + (STREQ (s, "-gt")) || (STREQ (s, "-ge"))); +} + +/* Return nonzero if OP is one of the test command's unary operators. */ +static int +unop (int op) +{ + return (member (op, "abcdefgkLhprsStuwxOGnz")); +} + +static int +one_argument (const char *s) +{ + if (STREQ (s, "-t")) + return (TRUE == (isatty (1))); + + return strlen (s) != 0; +} + +static int +two_arguments (void) +{ + int value; + + if (STREQ (argv[pos], "!")) + value = ! one_argument (argv[pos+1]); + else if (argv[pos][0] == '-' + && argv[pos][1] != '\0' + && argv[pos][2] == '\0') + { + if (unop (argv[pos][1])) + value = unary_operator (); + else + test_syntax_error (_("%s: unary operator expected\n"), argv[pos]); + } + else + beyond (); + return (value); +} + +static int +three_arguments (void) +{ + int value; + + if (STREQ (argv[pos], "!")) + { + advance (1); + value = !two_arguments (); + } + else if (binop (argv[pos+1])) + { + value = binary_operator (); + pos = argc; + } + else if ((STREQ (argv[pos+1], "-a")) || (STREQ (argv[pos+1], "-o")) || + (argv[pos][0] == '(')) + value = expr (); + else + test_syntax_error (_("%s: binary operator expected\n"), argv[pos+1]); + return (value); +} + +/* This is an implementation of a Posix.2 proposal by David Korn. */ +static int +posixtest (void) +{ + int value; + + switch (argc - 1) /* one extra passed in */ + { + case 0: + value = FALSE; + pos = argc; + break; + + case 1: + value = one_argument (argv[1]); + pos = argc; + break; + + case 2: + value = two_arguments (); + pos = argc; + break; + + case 3: + value = three_arguments (); + break; + + case 4: + if (STREQ (argv[pos], "!")) + { + advance (1); + value = !three_arguments (); + break; + } + /* FALLTHROUGH */ + case 5: + default: + value = expr (); + } + + return (value); +} + +#if defined (TEST_STANDALONE) +# include "long-options.h" +# include "closeout.h" + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s EXPRESSION\n\ + or: [ EXPRESSION ]\n\ + or: %s OPTION\n\ +"), + program_name, program_name); + fputs (_("\ +Exit with the status determined by EXPRESSION.\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +EXPRESSION is true or false and sets exit status. It is one of:\n\ +"), stdout); + fputs (_("\ +\n\ + ( EXPRESSION ) EXPRESSION is true\n\ + ! EXPRESSION EXPRESSION is false\n\ + EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true\n\ + EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true\n\ +"), stdout); + fputs (_("\ +\n\ + [-n] STRING the length of STRING is nonzero\n\ + -z STRING the length of STRING is zero\n\ + STRING1 = STRING2 the strings are equal\n\ + STRING1 != STRING2 the strings are not equal\n\ +"), stdout); + fputs (_("\ +\n\ + INTEGER1 -eq INTEGER2 INTEGER1 is equal to INTEGER2\n\ + INTEGER1 -ge INTEGER2 INTEGER1 is greater than or equal to INTEGER2\n\ + INTEGER1 -gt INTEGER2 INTEGER1 is greater than INTEGER2\n\ + INTEGER1 -le INTEGER2 INTEGER1 is less than or equal to INTEGER2\n\ + INTEGER1 -lt INTEGER2 INTEGER1 is less than INTEGER2\n\ + INTEGER1 -ne INTEGER2 INTEGER1 is not equal to INTEGER2\n\ +"), stdout); + fputs (_("\ +\n\ + FILE1 -ef FILE2 FILE1 and FILE2 have the same device and inode numbers\n\ + FILE1 -nt FILE2 FILE1 is newer (modification date) than FILE2\n\ + FILE1 -ot FILE2 FILE1 is older than FILE2\n\ +"), stdout); + fputs (_("\ +\n\ + -b FILE FILE exists and is block special\n\ + -c FILE FILE exists and is character special\n\ + -d FILE FILE exists and is a directory\n\ + -e FILE FILE exists\n\ +"), stdout); + fputs (_("\ + -f FILE FILE exists and is a regular file\n\ + -g FILE FILE exists and is set-group-ID\n\ + -h FILE FILE exists and is a symbolic link (same as -L)\n\ + -G FILE FILE exists and is owned by the effective group ID\n\ + -k FILE FILE exists and has its sticky bit set\n\ +"), stdout); + fputs (_("\ + -L FILE FILE exists and is a symbolic link (same as -h)\n\ + -O FILE FILE exists and is owned by the effective user ID\n\ + -p FILE FILE exists and is a named pipe\n\ + -r FILE FILE exists and is readable\n\ + -s FILE FILE exists and has a size greater than zero\n\ +"), stdout); + fputs (_("\ + -S FILE FILE exists and is a socket\n\ + -t [FD] file descriptor FD (stdout by default) is opened on a terminal\n\ + -u FILE FILE exists and its set-user-ID bit is set\n\ + -w FILE FILE exists and is writable\n\ + -x FILE FILE exists and is executable\n\ +"), stdout); + fputs (_("\ +\n\ +Beware that parentheses need to be escaped (e.g., by backslashes) for shells.\n\ +INTEGER may also be -l STRING, which evaluates to the length of STRING.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} +#endif /* TEST_STANDALONE */ + +#if !defined (TEST_STANDALONE) +# define main test_command +#endif + +#define AUTHORS N_ ("FIXME: ksb and mjb") + +/* + * [: + * '[' expr ']' + * test: + * test expr + */ +int +main (int margc, char **margv) +{ + int value; + +#if !defined (TEST_STANDALONE) + int code; + + code = setjmp (test_exit_buf); + + if (code) + return (test_error_return); +#else /* TEST_STANDALONE */ + program_name = margv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); +#endif /* TEST_STANDALONE */ + + argv = margv; + + if (margv[0] && strcmp (margv[0], "[") == 0) + { + /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */ + if (getenv ("POSIXLY_CORRECT") == NULL) + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + --margc; + + if (margc < 2) + test_exit (SHELL_BOOLEAN (FALSE)); + + if (margv[margc] && strcmp (margv[margc], "]") != 0) + test_syntax_error (_("missing `]'\n"), NULL); + } + + argc = margc; + pos = 1; + + if (pos >= argc) + test_exit (SHELL_BOOLEAN (FALSE)); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + value = posixtest (); + + if (pos != argc) + test_syntax_error (_("too many arguments\n"), NULL); + + test_exit (SHELL_BOOLEAN (value)); +} diff --git a/src/apps/bin/coreutils-5.0/src/touch.c b/src/apps/bin/coreutils-5.0/src/touch.c new file mode 100644 index 0000000000..faec819116 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/touch.c @@ -0,0 +1,407 @@ +/* touch -- change modification and access times of files + Copyright (C) 87, 1989-1991, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Paul Rubin, Arnold Robbins, Jim Kingdon, David MacKenzie, + and Randy Smith. */ + +#include +#include +#include +#include + +#include "system.h" +#include "argmatch.h" +#include "error.h" +#include "getdate.h" +#include "posixtm.h" +#include "posixver.h" +#include "quote.h" +#include "safe-read.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "touch" + +#define AUTHORS \ +N_ ("Paul Rubin, Arnold Robbins, Jim Kingdon, David MacKenzie, and Randy Smith") + +#ifndef STDC_HEADERS +time_t time (); +#endif + +/* Bitmasks for `change_times'. */ +#define CH_ATIME 1 +#define CH_MTIME 2 + +#if !defined O_NDELAY +# define O_NDELAY 0 +#endif + +#if !defined O_NONBLOCK +# define O_NONBLOCK O_NDELAY +#endif + +#if !defined O_NOCTTY +# define O_NOCTTY 0 +#endif + +#if !defined EISDIR +# define EISDIR 0 +#endif + +/* The name by which this program was run. */ +char *program_name; + +/* Which timestamps to change. */ +static int change_times; + +/* (-c) If nonzero, don't create if not already there. */ +static int no_create; + +/* (-d) If nonzero, date supplied on command line in get_date formats. */ +static int flexible_date; + +/* (-r) If nonzero, use times from a reference file. */ +static int use_ref; + +/* (-t) If nonzero, date supplied on command line in POSIX format. */ +static int posix_date; + +/* If nonzero, the only thing we have to do is change both the + modification and access time to the current time, so we don't + have to own the file, just be able to read and write it. + On some systems, we can do this if we own the file, even though + we have neither read nor write access to it. */ +static int amtime_now; + +/* New time to use when setting time. */ +static time_t newtime; + +/* File to use for -r. */ +static char *ref_file; + +/* Info about the reference file. */ +static struct stat ref_stats; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + TIME_OPTION = CHAR_MAX + 1 +}; + +static struct option const longopts[] = +{ + {"time", required_argument, 0, TIME_OPTION}, + {"no-create", no_argument, 0, 'c'}, + {"date", required_argument, 0, 'd'}, + {"file", required_argument, 0, 'r'}, /* FIXME: phase out --file */ + {"reference", required_argument, 0, 'r'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0} +}; + +/* Valid arguments to the `--time' option. */ +static char const* const time_args[] = +{ + "atime", "access", "use", "mtime", "modify", 0 +}; + +/* The bits in `change_times' that those arguments set. */ +static int const time_masks[] = +{ + CH_ATIME, CH_ATIME, CH_ATIME, CH_MTIME, CH_MTIME +}; + +/* Update the time of file FILE according to the options given. + Return 0 if successful, 1 if an error occurs. */ + +static int +touch (const char *file) +{ + int status; + struct stat sbuf; + int fd = -1; + int open_errno = 0; + + if (! no_create) + { + /* Try to open FILE, creating it if necessary. */ + fd = open (file, O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + + /* Don't save a copy of errno if it's EISDIR, since that would lead + touch to give a bogus diagnostic for e.g., `touch /' (assuming + we don't own / or have write access to it). On Solaris 5.6, + and probably other systems, it is EINVAL. On SunOS4, it's EPERM. */ + if (fd == -1 && errno != EISDIR && errno != EINVAL && errno != EPERM) + open_errno = errno; + } + + if (! amtime_now) + { + /* We're setting only one of the time values. stat the target to get + the other one. If we have the file descriptor already, use fstat. + Otherwise, either we're in no-create mode (and hence didn't call open) + or FILE is inaccessible or a directory, so we have to use stat. */ + if (fd != -1 ? fstat (fd, &sbuf) : stat (file, &sbuf)) + { + if (open_errno) + error (0, open_errno, _("creating %s"), quote (file)); + else + { + if (no_create && errno == ENOENT) + return 0; + error (0, errno, _("failed to get attributes of %s"), + quote (file)); + } + close (fd); + return 1; + } + } + + if (fd != -1 && close (fd) < 0) + { + error (0, errno, _("creating %s"), quote (file)); + return 1; + } + + if (amtime_now) + { + /* Pass NULL to utime so it will not fail if we just have + write access to the file, but don't own it. */ + status = utime (file, NULL); + } + else + { + struct utimbuf utb; + + /* There's currently no interface to set file timestamps with + better than 1-second resolution, so discard any fractional + part of the source timestamp. */ + + if (use_ref) + { + utb.actime = ref_stats.st_atime; + utb.modtime = ref_stats.st_mtime; + } + else + utb.actime = utb.modtime = newtime; + + if (!(change_times & CH_ATIME)) + utb.actime = sbuf.st_atime; + + if (!(change_times & CH_MTIME)) + utb.modtime = sbuf.st_mtime; + + status = utime (file, &utb); + } + + if (status) + { + if (open_errno) + { + /* The wording of this diagnostic should cover at least two cases: + - the file does not exist, but the parent directory is unwritable + - the file exists, but it isn't writable + I think it's not worth trying to distinguish them. */ + error (0, open_errno, _("cannot touch %s"), quote (file)); + } + else + { + if (no_create && errno == ENOENT) + return 0; + error (0, errno, _("setting times of %s"), quote (file)); + } + return 1; + } + + return 0; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... FILE...\n"), program_name); + fputs (_("\ +Update the access and modification times of each FILE to the current time.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -a change only the access time\n\ + -c, --no-create do not create any files\n\ + -d, --date=STRING parse STRING and use it instead of current time\n\ + -f (ignored)\n\ + -m change only the modification time\n\ +"), stdout); + fputs (_("\ + -r, --reference=FILE use this file's times instead of current time\n\ + -t STAMP use [[CC]YY]MMDDhhmm[.ss] instead of current time\n\ + --time=WORD set time given by WORD: access atime use (same as -a)\n\ + modify mtime (same as -m)\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +Note that the -d and -t options accept different time-date formats.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int c; + int date_set = 0; + int err = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + change_times = no_create = use_ref = posix_date = flexible_date = 0; + + while ((c = getopt_long (argc, argv, "acd:fmr:t:", longopts, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + case 'a': + change_times |= CH_ATIME; + break; + + case 'c': + no_create++; + break; + + case 'd': + flexible_date++; + newtime = get_date (optarg, NULL); + if (newtime == (time_t) -1) + error (EXIT_FAILURE, 0, _("invalid date format %s"), quote (optarg)); + date_set++; + break; + + case 'f': + break; + + case 'm': + change_times |= CH_MTIME; + break; + + case 'r': + use_ref++; + ref_file = optarg; + break; + + case 't': + posix_date++; + if (! posixtime (&newtime, optarg, + PDS_LEADING_YEAR | PDS_CENTURY | PDS_SECONDS)) + error (EXIT_FAILURE, 0, _("invalid date format %s"), quote (optarg)); + date_set++; + break; + + case TIME_OPTION: /* --time */ + change_times |= XARGMATCH ("--time", optarg, + time_args, time_masks); + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (change_times == 0) + change_times = CH_ATIME | CH_MTIME; + + if ((use_ref && (posix_date || flexible_date)) + || (posix_date && flexible_date)) + { + error (0, 0, _("cannot specify times from more than one source")); + usage (EXIT_FAILURE); + } + + if (use_ref) + { + if (stat (ref_file, &ref_stats)) + error (EXIT_FAILURE, errno, + _("failed to get attributes of %s"), quote (ref_file)); + date_set++; + } + + /* The obsolete `MMDDhhmm[YY]' form is valid IFF there are + two or more non-option arguments. */ + if (!date_set && 2 <= argc - optind && !STREQ (argv[optind - 1], "--") + && posix2_version () < 200112) + { + if (posixtime (&newtime, argv[optind], PDS_TRAILING_YEAR)) + { + if (! getenv ("POSIXLY_CORRECT")) + { + struct tm const *tm = localtime (&newtime); + error (0, 0, + _("warning: `touch %s' is obsolete; use\ + `touch -t %04d%02d%02d%02d%02d.%02d'"), + argv[optind], + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + } + + optind++; + date_set++; + } + } + if (!date_set) + { + if ((change_times & (CH_ATIME | CH_MTIME)) == (CH_ATIME | CH_MTIME)) + amtime_now = 1; + else + time (&newtime); + } + + if (optind == argc) + { + error (0, 0, _("file arguments missing")); + usage (EXIT_FAILURE); + } + + for (; optind < argc; ++optind) + err += touch (argv[optind]); + + exit (err != 0); +} diff --git a/src/apps/bin/coreutils-5.0/src/tr.c b/src/apps/bin/coreutils-5.0/src/tr.c new file mode 100644 index 0000000000..ee21b2f883 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/tr.c @@ -0,0 +1,2030 @@ +/* tr -- a filter to translate characters + Copyright (C) 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Jim Meyering */ + +#include + +#include +#include +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "safe-read.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "tr" + +#define AUTHORS "Jim Meyering" + +#define N_CHARS (UCHAR_MAX + 1) + +/* A pointer to a filtering function. */ +typedef size_t (*Filter) (/* unsigned char *, size_t, Filter */); + +/* Convert from character C to its index in the collating + sequence array. Just cast to an unsigned int to avoid + problems with sign-extension. */ +#define ORD(c) (unsigned int)(c) + +/* The inverse of ORD. */ +#define CHR(i) (unsigned char)(i) + +/* The value for Spec_list->state that indicates to + get_next that it should initialize the tail pointer. + Its value should be as large as possible to avoid conflict + a valid value for the state field -- and that may be as + large as any valid repeat_count. */ +#define BEGIN_STATE (INT_MAX - 1) + +/* The value for Spec_list->state that indicates to + get_next that the element pointed to by Spec_list->tail is + being considered for the first time on this pass through the + list -- it indicates that get_next should make any necessary + initializations. */ +#define NEW_ELEMENT (BEGIN_STATE + 1) + +/* A value distinct from any character that may have been stored in a + buffer as the result of a block-read in the function squeeze_filter. */ +#define NOT_A_CHAR (unsigned int)(-1) + +/* The following (but not CC_NO_CLASS) are indices into the array of + valid character class strings. */ +enum Char_class + { + CC_ALNUM = 0, CC_ALPHA = 1, CC_BLANK = 2, CC_CNTRL = 3, + CC_DIGIT = 4, CC_GRAPH = 5, CC_LOWER = 6, CC_PRINT = 7, + CC_PUNCT = 8, CC_SPACE = 9, CC_UPPER = 10, CC_XDIGIT = 11, + CC_NO_CLASS = 9999 + }; + +/* Character class to which a character (returned by get_next) belonged; + but it is set only if the construct from which the character was obtained + was one of the character classes [:upper:] or [:lower:]. The value + is used only when translating and then, only to make sure that upper + and lower class constructs have the same relative positions in string1 + and string2. */ +enum Upper_Lower_class + { + UL_LOWER = 0, + UL_UPPER = 1, + UL_NONE = 2 + }; + +/* A shortcut to ensure that when constructing the translation array, + one of the values returned by paired calls to get_next (from s1 and s2) + is from [:upper:] and the other is from [:lower:], or neither is from + upper or lower. By default, GNU tr permits the identity mappings: from + [:upper:] to [:upper:] and [:lower:] to [:lower:]. But when + POSIXLY_CORRECT is set, those evoke diagnostics. This array is indexed + by values of type enum Upper_Lower_class. */ +static int const class_ok[3][3] = +{ + {1, 1, 0}, + {1, 1, 0}, + {0, 0, 1} +}; + +/* The type of a List_element. See build_spec_list for more details. */ +enum Range_element_type + { + RE_NO_TYPE = 0, + RE_NORMAL_CHAR, + RE_RANGE, + RE_CHAR_CLASS, + RE_EQUIV_CLASS, + RE_REPEATED_CHAR + }; + +/* One construct in one of tr's argument strings. + For example, consider the POSIX version of the classic tr command: + tr -cs 'a-zA-Z_' '[\n*]' + String1 has 3 constructs, two of which are ranges (a-z and A-Z), + and a single normal character, `_'. String2 has one construct. */ +struct List_element + { + enum Range_element_type type; + struct List_element *next; + union + { + int normal_char; + struct /* unnamed */ + { + unsigned int first_char; + unsigned int last_char; + } + range; + enum Char_class char_class; + int equiv_code; + struct /* unnamed */ + { + unsigned int the_repeated_char; + size_t repeat_count; + } + repeated_char; + } + u; + }; + +/* Each of tr's argument strings is parsed into a form that is easier + to work with: a linked list of constructs (struct List_element). + Each Spec_list structure also encapsulates various attributes of + the corresponding argument string. The attributes are used mainly + to verify that the strings are valid in the context of any options + specified (like -s, -d, or -c). The main exception is the member + `tail', which is first used to construct the list. After construction, + it is used by get_next to save its state when traversing the list. + The member `state' serves a similar function. */ +struct Spec_list + { + /* Points to the head of the list of range elements. + The first struct is a dummy; its members are never used. */ + struct List_element *head; + + /* When appending, points to the last element. When traversing via + get_next(), points to the element to process next. Setting + Spec_list.state to the value BEGIN_STATE before calling get_next + signals get_next to initialize tail to point to head->next. */ + struct List_element *tail; + + /* Used to save state between calls to get_next(). */ + unsigned int state; + + /* Length, in the sense that length ('a-z[:digit:]123abc') + is 42 ( = 26 + 10 + 6). */ + size_t length; + + /* The number of [c*] and [c*0] constructs that appear in this spec. */ + int n_indefinite_repeats; + + /* If n_indefinite_repeats is nonzero, this points to the List_element + corresponding to the last [c*] or [c*0] construct encountered in + this spec. Otherwise it is undefined. */ + struct List_element *indefinite_repeat_element; + + /* Non-zero if this spec contains at least one equivalence + class construct e.g. [=c=]. */ + int has_equiv_class; + + /* Non-zero if this spec contains at least one character class + construct. E.g. [:digit:]. */ + int has_char_class; + + /* Non-zero if this spec contains at least one of the character class + constructs (all but upper and lower) that aren't allowed in s2. */ + int has_restricted_char_class; + }; + +/* A representation for escaped string1 or string2. As a string is parsed, + any backslash-escaped characters (other than octal or \a, \b, \f, \n, + etc.) are marked as such in this structure by setting the corresponding + entry in the ESCAPED vector. */ +struct E_string +{ + unsigned char *s; + int *escaped; + size_t len; +}; + +/* Return nonzero if the Ith character of escaped string ES matches C + and is not escaped itself. */ +#define ES_MATCH(ES, I, C) ((ES)->s[(I)] == (C) && !(ES)->escaped[(I)]) + +/* The name by which this program was run. */ +char *program_name; + +/* When nonzero, each sequence in the input of a repeated character + (call it c) is replaced (in the output) by a single occurrence of c + for every c in the squeeze set. */ +static int squeeze_repeats = 0; + +/* When nonzero, removes characters in the delete set from input. */ +static int delete = 0; + +/* Use the complement of set1 in place of set1. */ +static int complement = 0; + +/* When nonzero, this flag causes GNU tr to provide strict + compliance with POSIX draft 1003.2.11.2. The POSIX spec + says that when -d is used without -s, string2 (if present) + must be ignored. Silently ignoring arguments is a bad idea. + The default GNU behavior is to give a usage message and exit. + Additionally, when this flag is nonzero, tr prints warnings + on stderr if it is being used in a manner that is not portable. + Applicable warnings are given by default, but are suppressed + if the environment variable `POSIXLY_CORRECT' is set, since + being POSIX conformant means we can't issue such messages. + Warnings on the following topics are suppressed when this + variable is nonzero: + 1. Ambiguous octal escapes. */ +static int posix_pedantic; + +/* When tr is performing translation and string1 is longer than string2, + POSIX says that the result is undefined. That gives the implementor + of a POSIX conforming version of tr two reasonable choices for the + semantics of this case. + + * The BSD tr pads string2 to the length of string1 by + repeating the last character in string2. + + * System V tr ignores characters in string1 that have no + corresponding character in string2. That is, string1 is effectively + truncated to the length of string2. + + When nonzero, this flag causes GNU tr to imitate the behavior + of System V tr when translating with string1 longer than string2. + The default is to emulate BSD tr. This flag is ignored in modes where + no translation is performed. Emulating the System V tr + in this exceptional case causes the relatively common BSD idiom: + + tr -cs A-Za-z0-9 '\012' + + to break (it would convert only zero bytes, rather than all + non-alphanumerics, to newlines). + + WARNING: This switch does not provide general BSD or System V + compatibility. For example, it doesn't disable the interpretation + of the POSIX constructs [:alpha:], [=c=], and [c*10], so if by + some unfortunate coincidence you use such constructs in scripts + expecting to use some other version of tr, the scripts will break. */ +static int truncate_set1 = 0; + +/* An alias for (!delete && non_option_args == 2). + It is set in main and used there and in validate(). */ +static int translating; + +#ifndef BUFSIZ +# define BUFSIZ 8192 +#endif + +#define IO_BUF_SIZE BUFSIZ +static unsigned char io_buf[IO_BUF_SIZE]; + +static char const *const char_class_name[] = +{ + "alnum", "alpha", "blank", "cntrl", "digit", "graph", + "lower", "print", "punct", "space", "upper", "xdigit" +}; +#define N_CHAR_CLASSES (sizeof(char_class_name) / sizeof(char_class_name[0])) + +typedef char SET_TYPE; + +/* Array of boolean values. A character `c' is a member of the + squeeze set if and only if in_squeeze_set[c] is true. The squeeze + set is defined by the last (possibly, the only) string argument + on the command line when the squeeze option is given. */ +static SET_TYPE in_squeeze_set[N_CHARS]; + +/* Array of boolean values. A character `c' is a member of the + delete set if and only if in_delete_set[c] is true. The delete + set is defined by the first (or only) string argument on the + command line when the delete option is given. */ +static SET_TYPE in_delete_set[N_CHARS]; + +/* Array of character values defining the translation (if any) that + tr is to perform. Translation is performed only when there are + two specification strings and the delete switch is not given. */ +static char xlate[N_CHARS]; + +static struct option const long_options[] = +{ + {"complement", no_argument, NULL, 'c'}, + {"delete", no_argument, NULL, 'd'}, + {"squeeze-repeats", no_argument, NULL, 's'}, + {"truncate-set1", no_argument, NULL, 't'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... SET1 [SET2]\n\ +"), + program_name); + fputs (_("\ +Translate, squeeze, and/or delete characters from standard input,\n\ +writing to standard output.\n\ +\n\ + -c, --complement first complement SET1\n\ + -d, --delete delete characters in SET1, do not translate\n\ + -s, --squeeze-repeats replace each input sequence of a repeated character\n\ + that is listed in SET1 with a single occurrence\n\ + of that character\n\ + -t, --truncate-set1 first truncate SET1 to length of SET2\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +SETs are specified as strings of characters. Most represent themselves.\n\ +Interpreted sequences are:\n\ +\n\ + \\NNN character with octal value NNN (1 to 3 octal digits)\n\ + \\\\ backslash\n\ + \\a audible BEL\n\ + \\b backspace\n\ + \\f form feed\n\ + \\n new line\n\ + \\r return\n\ + \\t horizontal tab\n\ +"), stdout); + fputs (_("\ + \\v vertical tab\n\ + CHAR1-CHAR2 all characters from CHAR1 to CHAR2 in ascending order\n\ + [CHAR*] in SET2, copies of CHAR until length of SET1\n\ + [CHAR*REPEAT] REPEAT copies of CHAR, REPEAT octal if starting with 0\n\ + [:alnum:] all letters and digits\n\ + [:alpha:] all letters\n\ + [:blank:] all horizontal whitespace\n\ + [:cntrl:] all control characters\n\ + [:digit:] all digits\n\ +"), stdout); + fputs (_("\ + [:graph:] all printable characters, not including space\n\ + [:lower:] all lower case letters\n\ + [:print:] all printable characters, including space\n\ + [:punct:] all punctuation characters\n\ + [:space:] all horizontal or vertical whitespace\n\ + [:upper:] all upper case letters\n\ + [:xdigit:] all hexadecimal digits\n\ + [=CHAR=] all characters which are equivalent to CHAR\n\ +"), stdout); + fputs (_("\ +\n\ +Translation occurs if -d is not given and both SET1 and SET2 appear.\n\ +-t may be used only when translating. SET2 is extended to length of\n\ +SET1 by repeating its last character as necessary. \ +"), stdout); + fputs (_("\ +Excess characters\n\ +of SET2 are ignored. Only [:lower:] and [:upper:] are guaranteed to\n\ +expand in ascending order; used in SET2 while translating, they may\n\ +only be used in pairs to specify case conversion. \ +"), stdout); + fputs (_("\ +-s uses SET1 if not\n\ +translating nor deleting; else squeezing uses SET2 and occurs after\n\ +translation or deletion.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Return nonzero if the character C is a member of the + equivalence class containing the character EQUIV_CLASS. */ + +static int +is_equiv_class_member (unsigned int equiv_class, unsigned int c) +{ + return (equiv_class == c); +} + +/* Return nonzero if the character C is a member of the + character class CHAR_CLASS. */ + +static int +is_char_class_member (enum Char_class char_class, unsigned int c) +{ + int result; + + switch (char_class) + { + case CC_ALNUM: + result = ISALNUM (c); + break; + case CC_ALPHA: + result = ISALPHA (c); + break; + case CC_BLANK: + result = ISBLANK (c); + break; + case CC_CNTRL: + result = ISCNTRL (c); + break; + case CC_DIGIT: + result = ISDIGIT_LOCALE (c); + break; + case CC_GRAPH: + result = ISGRAPH (c); + break; + case CC_LOWER: + result = ISLOWER (c); + break; + case CC_PRINT: + result = ISPRINT (c); + break; + case CC_PUNCT: + result = ISPUNCT (c); + break; + case CC_SPACE: + result = ISSPACE (c); + break; + case CC_UPPER: + result = ISUPPER (c); + break; + case CC_XDIGIT: + result = ISXDIGIT (c); + break; + default: + abort (); + break; + } + return result; +} + +static void +es_free (struct E_string *es) +{ + free (es->s); + free (es->escaped); +} + +/* Perform the first pass over each range-spec argument S, converting all + \c and \ddd escapes to their one-byte representations. The conversion + is done in-place, so S must point to writable storage. If an invalid + quote sequence is found print an error message and return nonzero. + Otherwise set *LEN to the length of the resulting string and return + zero. The resulting array of characters may contain zero-bytes; + however, on input, S is assumed to be null-terminated, and hence + cannot contain actual (non-escaped) zero bytes. */ + +static int +unquote (const unsigned char *s, struct E_string *es) +{ + size_t i, j; + size_t len; + + len = strlen ((char *) s); + + es->s = (unsigned char *) xmalloc (len); + es->escaped = (int *) xmalloc (len * sizeof (es->escaped[0])); + for (i = 0; i < len; i++) + es->escaped[i] = 0; + + j = 0; + for (i = 0; s[i]; i++) + { + switch (s[i]) + { + int c; + case '\\': + switch (s[i + 1]) + { + int oct_digit; + case '\\': + c = '\\'; + break; + case 'a': + c = '\007'; + break; + case 'b': + c = '\b'; + break; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'v': + c = '\v'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + c = s[i + 1] - '0'; + oct_digit = s[i + 2] - '0'; + if (0 <= oct_digit && oct_digit <= 7) + { + c = 8 * c + oct_digit; + ++i; + oct_digit = s[i + 2] - '0'; + if (0 <= oct_digit && oct_digit <= 7) + { + if (8 * c + oct_digit < N_CHARS) + { + c = 8 * c + oct_digit; + ++i; + } + else if (!posix_pedantic) + { + /* A 3-digit octal number larger than \377 won't + fit in 8 bits. So we stop when adding the + next digit would put us over the limit and + give a warning about the ambiguity. POSIX + isn't clear on this, but one person has said + that in his interpretation, POSIX says tr + can't even give a warning. */ + error (0, 0, _("warning: the ambiguous octal escape \ +\\%c%c%c is being\n\tinterpreted as the 2-byte sequence \\0%c%c, `%c'"), + s[i], s[i + 1], s[i + 2], + s[i], s[i + 1], s[i + 2]); + } + } + } + break; + case '\0': + error (0, 0, _("invalid backslash escape at end of string")); + return 1; + + default: + if (posix_pedantic) + { + error (0, 0, _("invalid backslash escape `\\%c'"), s[i + 1]); + return 1; + } + else + { + c = s[i + 1]; + es->escaped[j] = 1; + } + } + ++i; + es->s[j++] = c; + break; + default: + es->s[j++] = s[i]; + break; + } + } + es->len = j; + return 0; +} + +/* If CLASS_STR is a valid character class string, return its index + in the global char_class_name array. Otherwise, return CC_NO_CLASS. */ + +static enum Char_class +look_up_char_class (const unsigned char *class_str, size_t len) +{ + unsigned int i; + + for (i = 0; i < N_CHAR_CLASSES; i++) + if (strncmp ((const char *) class_str, char_class_name[i], len) == 0 + && strlen (char_class_name[i]) == len) + return (enum Char_class) i; + return CC_NO_CLASS; +} + +/* Return a newly allocated string with a printable version of C. + This function is used solely for formatting error messages. */ + +static char * +make_printable_char (unsigned int c) +{ + char *buf = xmalloc (5); + + assert (c < N_CHARS); + if (ISPRINT (c)) + { + buf[0] = c; + buf[1] = '\0'; + } + else + { + sprintf (buf, "\\%03o", c); + } + return buf; +} + +/* Return a newly allocated copy of S which is suitable for printing. + LEN is the number of characters in S. Most non-printing + (isprint) characters are represented by a backslash followed by + 3 octal digits. However, the characters represented by \c escapes + where c is one of [abfnrtv] are represented by their 2-character \c + sequences. This function is used solely for printing error messages. */ + +static char * +make_printable_str (const unsigned char *s, size_t len) +{ + /* Worst case is that every character expands to a backslash + followed by a 3-character octal escape sequence. */ + char *printable_buf = xmalloc (4 * len + 1); + char *p = printable_buf; + size_t i; + + for (i = 0; i < len; i++) + { + char buf[5]; + char *tmp = NULL; + + switch (s[i]) + { + case '\\': + tmp = "\\"; + break; + case '\007': + tmp = "\\a"; + break; + case '\b': + tmp = "\\b"; + break; + case '\f': + tmp = "\\f"; + break; + case '\n': + tmp = "\\n"; + break; + case '\r': + tmp = "\\r"; + break; + case '\t': + tmp = "\\t"; + break; + case '\v': + tmp = "\\v"; + break; + default: + if (ISPRINT (s[i])) + { + buf[0] = s[i]; + buf[1] = '\0'; + } + else + sprintf (buf, "\\%03o", s[i]); + tmp = buf; + break; + } + p = stpcpy (p, tmp); + } + return printable_buf; +} + +/* Append a newly allocated structure representing a + character C to the specification list LIST. */ + +static void +append_normal_char (struct Spec_list *list, unsigned int c) +{ + struct List_element *new; + + new = (struct List_element *) xmalloc (sizeof (struct List_element)); + new->next = NULL; + new->type = RE_NORMAL_CHAR; + new->u.normal_char = c; + assert (list->tail); + list->tail->next = new; + list->tail = new; +} + +/* Append a newly allocated structure representing the range + of characters from FIRST to LAST to the specification list LIST. + Return nonzero if LAST precedes FIRST in the collating sequence, + zero otherwise. This means that '[c-c]' is acceptable. */ + +static int +append_range (struct Spec_list *list, unsigned int first, unsigned int last) +{ + struct List_element *new; + + if (ORD (first) > ORD (last)) + { + char *tmp1 = make_printable_char (first); + char *tmp2 = make_printable_char (last); + + error (0, 0, + _("range-endpoints of `%s-%s' are in reverse collating sequence order"), + tmp1, tmp2); + free (tmp1); + free (tmp2); + return 1; + } + new = (struct List_element *) xmalloc (sizeof (struct List_element)); + new->next = NULL; + new->type = RE_RANGE; + new->u.range.first_char = first; + new->u.range.last_char = last; + assert (list->tail); + list->tail->next = new; + list->tail = new; + return 0; +} + +/* If CHAR_CLASS_STR is a valid character class string, append a + newly allocated structure representing that character class to the end + of the specification list LIST and return 0. If CHAR_CLASS_STR is not + a valid string return nonzero. */ + +static int +append_char_class (struct Spec_list *list, + const unsigned char *char_class_str, size_t len) +{ + enum Char_class char_class; + struct List_element *new; + + char_class = look_up_char_class (char_class_str, len); + if (char_class == CC_NO_CLASS) + return 1; + new = (struct List_element *) xmalloc (sizeof (struct List_element)); + new->next = NULL; + new->type = RE_CHAR_CLASS; + new->u.char_class = char_class; + assert (list->tail); + list->tail->next = new; + list->tail = new; + return 0; +} + +/* Append a newly allocated structure representing a [c*n] + repeated character construct to the specification list LIST. + THE_CHAR is the single character to be repeated, and REPEAT_COUNT + is a non-negative repeat count. */ + +static void +append_repeated_char (struct Spec_list *list, unsigned int the_char, + size_t repeat_count) +{ + struct List_element *new; + + new = (struct List_element *) xmalloc (sizeof (struct List_element)); + new->next = NULL; + new->type = RE_REPEATED_CHAR; + new->u.repeated_char.the_repeated_char = the_char; + new->u.repeated_char.repeat_count = repeat_count; + assert (list->tail); + list->tail->next = new; + list->tail = new; +} + +/* Given a string, EQUIV_CLASS_STR, from a [=str=] context and + the length of that string, LEN, if LEN is exactly one, append + a newly allocated structure representing the specified + equivalence class to the specification list, LIST and return zero. + If LEN is not 1, return nonzero. */ + +static int +append_equiv_class (struct Spec_list *list, + const unsigned char *equiv_class_str, size_t len) +{ + struct List_element *new; + + if (len != 1) + return 1; + new = (struct List_element *) xmalloc (sizeof (struct List_element)); + new->next = NULL; + new->type = RE_EQUIV_CLASS; + new->u.equiv_code = *equiv_class_str; + assert (list->tail); + list->tail->next = new; + list->tail = new; + return 0; +} + +/* Return a newly allocated copy of the LEN-byte prefix of P. + The returned string may contain NUL bytes and is *not* NUL-terminated. */ + +static unsigned char * +xmemdup (const unsigned char *p, size_t len) +{ + unsigned char *tmp = (unsigned char *) xmalloc (len); + + /* Use memcpy rather than strncpy because `p' may contain zero-bytes. */ + memcpy (tmp, p, len); + return tmp; +} + +/* Search forward starting at START_IDX for the 2-char sequence + (PRE_BRACKET_CHAR,']') in the string P of length P_LEN. If such + a sequence is found, set *RESULT_IDX to the index of the first + character and return nonzero. Otherwise return zero. P may contain + zero bytes. */ + +static int +find_closing_delim (const struct E_string *es, size_t start_idx, + unsigned int pre_bracket_char, size_t *result_idx) +{ + size_t i; + + for (i = start_idx; i < es->len - 1; i++) + if (es->s[i] == pre_bracket_char && es->s[i + 1] == ']' + && !es->escaped[i] && !es->escaped[i + 1]) + { + *result_idx = i; + return 1; + } + return 0; +} + +/* Parse the bracketed repeat-char syntax. If the P_LEN characters + beginning with P[ START_IDX ] comprise a valid [c*n] construct, + then set *CHAR_TO_REPEAT, *REPEAT_COUNT, and *CLOSING_BRACKET_IDX + and return zero. If the second character following + the opening bracket is not `*' or if no closing bracket can be + found, return -1. If a closing bracket is found and the + second char is `*', but the string between the `*' and `]' isn't + empty, an octal number, or a decimal number, print an error message + and return -2. */ + +static int +find_bracketed_repeat (const struct E_string *es, size_t start_idx, + unsigned int *char_to_repeat, size_t *repeat_count, + size_t *closing_bracket_idx) +{ + size_t i; + + assert (start_idx + 1 < es->len); + if (!ES_MATCH (es, start_idx + 1, '*')) + return -1; + + for (i = start_idx + 2; i < es->len; i++) + { + if (ES_MATCH (es, i, ']')) + { + size_t digit_str_len = i - start_idx - 2; + + *char_to_repeat = es->s[start_idx]; + if (digit_str_len == 0) + { + /* We've matched [c*] -- no explicit repeat count. */ + *repeat_count = 0; + *closing_bracket_idx = i; + return 0; + } + + /* Here, we have found [c*s] where s should be a string + of octal (if it starts with `0') or decimal digits. */ + { + const char *digit_str = (const char *) &es->s[start_idx + 2]; + unsigned long int tmp_ulong; + char *d_end; + int base = 10; + /* Select the base manually so we can be sure it's either 8 or 10. + If the spec allowed it to be interpreted as hexadecimal, we + could have used `0' and let xstrtoul decide. */ + if (*digit_str == '0') + { + base = 8; + ++digit_str; + --digit_str_len; + } + if (xstrtoul (digit_str, &d_end, base, &tmp_ulong, NULL) + != LONGINT_OK + || BEGIN_STATE < tmp_ulong + || digit_str + digit_str_len != d_end) + { + char *tmp = make_printable_str (es->s + start_idx + 2, + i - start_idx - 2); + error (0, 0, _("invalid repeat count `%s' in [c*n] construct"), + tmp); + free (tmp); + return -2; + } + *repeat_count = tmp_ulong; + } + *closing_bracket_idx = i; + return 0; + } + } + return -1; /* No bracket found. */ +} + +/* Return nonzero if the string at ES->s[IDX] matches the regular + expression `\*[0-9]*\]', zero otherwise. To match, the `*' and + the `]' must not be escaped. */ + +static int +star_digits_closebracket (const struct E_string *es, size_t idx) +{ + size_t i; + + if (!ES_MATCH (es, idx, '*')) + return 0; + + for (i = idx + 1; i < es->len; i++) + { + if (!ISDIGIT (es->s[i])) + { + if (ES_MATCH (es, i, ']')) + return 1; + return 0; + } + } + return 0; +} + +/* Convert string UNESCAPED_STRING (which has been preprocessed to + convert backslash-escape sequences) of length LEN characters into + a linked list of the following 5 types of constructs: + - [:str:] Character class where `str' is one of the 12 valid strings. + - [=c=] Equivalence class where `c' is any single character. + - [c*n] Repeat the single character `c' `n' times. n may be omitted. + However, if `n' is present, it must be a non-negative octal or + decimal integer. + - r-s Range of characters from `r' to `s'. The second endpoint must + not precede the first in the current collating sequence. + - c Any other character is interpreted as itself. */ + +static int +build_spec_list (const struct E_string *es, struct Spec_list *result) +{ + const unsigned char *p; + size_t i; + + p = es->s; + + /* The main for-loop below recognizes the 4 multi-character constructs. + A character that matches (in its context) none of the multi-character + constructs is classified as `normal'. Since all multi-character + constructs have at least 3 characters, any strings of length 2 or + less are composed solely of normal characters. Hence, the index of + the outer for-loop runs only as far as LEN-2. */ + + for (i = 0; i + 2 < es->len; /* empty */) + { + if (ES_MATCH (es, i, '[')) + { + int matched_multi_char_construct; + size_t closing_bracket_idx; + unsigned int char_to_repeat; + size_t repeat_count; + int err; + + matched_multi_char_construct = 1; + if (ES_MATCH (es, i + 1, ':') + || ES_MATCH (es, i + 1, '=')) + { + size_t closing_delim_idx; + int found; + + found = find_closing_delim (es, i + 2, p[i + 1], + &closing_delim_idx); + if (found) + { + int parse_failed; + size_t opnd_str_len = closing_delim_idx - 1 - (i + 2) + 1; + unsigned char *opnd_str; + + if (opnd_str_len == 0) + { + if (p[i + 1] == ':') + error (0, 0, _("missing character class name `[::]'")); + else + error (0, 0, + _("missing equivalence class character `[==]'")); + return 1; + } + + opnd_str = xmemdup (p + i + 2, opnd_str_len); + + if (p[i + 1] == ':') + { + parse_failed = append_char_class (result, opnd_str, + opnd_str_len); + + /* FIXME: big comment. */ + if (parse_failed) + { + if (star_digits_closebracket (es, i + 2)) + { + free (opnd_str); + goto try_bracketed_repeat; + } + else + { + char *tmp = make_printable_str (opnd_str, + opnd_str_len); + error (0, 0, _("invalid character class `%s'"), + tmp); + free (tmp); + return 1; + } + } + } + else + { + parse_failed = append_equiv_class (result, opnd_str, + opnd_str_len); + + /* FIXME: big comment. */ + if (parse_failed) + { + if (star_digits_closebracket (es, i + 2)) + { + free (opnd_str); + goto try_bracketed_repeat; + } + else + { + char *tmp = make_printable_str (opnd_str, + opnd_str_len); + error (0, 0, + _("%s: equivalence class operand must be a single character"), + tmp); + free (tmp); + return 1; + } + } + } + free (opnd_str); + + /* Return nonzero if append_*_class reports a problem. */ + if (parse_failed) + return 1; + else + i = closing_delim_idx + 2; + continue; + } + /* Else fall through. This could be [:*] or [=*]. */ + } + + try_bracketed_repeat: + + /* Determine whether this is a bracketed repeat range + matching the RE \[.\*(dec_or_oct_number)?\]. */ + err = find_bracketed_repeat (es, i + 1, &char_to_repeat, + &repeat_count, + &closing_bracket_idx); + if (err == 0) + { + append_repeated_char (result, char_to_repeat, repeat_count); + i = closing_bracket_idx + 1; + } + else if (err == -1) + { + matched_multi_char_construct = 0; + } + else + { + /* Found a string that looked like [c*n] but the + numeric part was invalid. */ + return 1; + } + + if (matched_multi_char_construct) + continue; + + /* We reach this point if P does not match [:str:], [=c=], + [c*n], or [c*]. Now, see if P looks like a range `[-c' + (from `[' to `c'). */ + } + + /* Look ahead one char for ranges like a-z. */ + if (ES_MATCH (es, i + 1, '-')) + { + if (append_range (result, p[i], p[i + 2])) + return 1; + i += 3; + } + else + { + append_normal_char (result, p[i]); + ++i; + } + } + + /* Now handle the (2 or fewer) remaining characters p[i]..p[es->len - 1]. */ + for (; i < es->len; i++) + append_normal_char (result, p[i]); + + return 0; +} + +/* Given a Spec_list S (with its saved state implicit in the values + of its members `tail' and `state'), return the next single character + in the expansion of S's constructs. If the last character of S was + returned on the previous call or if S was empty, this function + returns -1. For example, successive calls to get_next where S + represents the spec-string 'a-d[y*3]' will return the sequence + of values a, b, c, d, y, y, y, -1. Finally, if the construct from + which the returned character comes is [:upper:] or [:lower:], the + parameter CLASS is given a value to indicate which it was. Otherwise + CLASS is set to UL_NONE. This value is used only when constructing + the translation table to verify that any occurrences of upper and + lower class constructs in the spec-strings appear in the same relative + positions. */ + +static int +get_next (struct Spec_list *s, enum Upper_Lower_class *class) +{ + struct List_element *p; + int return_val; + int i; + + if (class) + *class = UL_NONE; + + if (s->state == BEGIN_STATE) + { + s->tail = s->head->next; + s->state = NEW_ELEMENT; + } + + p = s->tail; + if (p == NULL) + return -1; + + switch (p->type) + { + case RE_NORMAL_CHAR: + return_val = p->u.normal_char; + s->state = NEW_ELEMENT; + s->tail = p->next; + break; + + case RE_RANGE: + if (s->state == NEW_ELEMENT) + s->state = ORD (p->u.range.first_char); + else + ++(s->state); + return_val = CHR (s->state); + if (s->state == ORD (p->u.range.last_char)) + { + s->tail = p->next; + s->state = NEW_ELEMENT; + } + break; + + case RE_CHAR_CLASS: + if (class) + { + int upper_or_lower; + switch (p->u.char_class) + { + case CC_LOWER: + *class = UL_LOWER; + upper_or_lower = 1; + break; + case CC_UPPER: + *class = UL_UPPER; + upper_or_lower = 1; + break; + default: + upper_or_lower = 0; + break; + } + + if (upper_or_lower) + { + s->tail = p->next; + s->state = NEW_ELEMENT; + return_val = 0; + break; + } + } + + if (s->state == NEW_ELEMENT) + { + for (i = 0; i < N_CHARS; i++) + if (is_char_class_member (p->u.char_class, i)) + break; + assert (i < N_CHARS); + s->state = i; + } + assert (is_char_class_member (p->u.char_class, s->state)); + return_val = CHR (s->state); + for (i = s->state + 1; i < N_CHARS; i++) + if (is_char_class_member (p->u.char_class, i)) + break; + if (i < N_CHARS) + s->state = i; + else + { + s->tail = p->next; + s->state = NEW_ELEMENT; + } + break; + + case RE_EQUIV_CLASS: + /* FIXME: this assumes that each character is alone in its own + equivalence class (which appears to be correct for my + LC_COLLATE. But I don't know of any function that allows + one to determine a character's equivalence class. */ + + return_val = p->u.equiv_code; + s->state = NEW_ELEMENT; + s->tail = p->next; + break; + + case RE_REPEATED_CHAR: + /* Here, a repeat count of n == 0 means don't repeat at all. */ + if (p->u.repeated_char.repeat_count == 0) + { + s->tail = p->next; + s->state = NEW_ELEMENT; + return_val = get_next (s, class); + } + else + { + if (s->state == NEW_ELEMENT) + { + s->state = 0; + } + ++(s->state); + return_val = p->u.repeated_char.the_repeated_char; + if (p->u.repeated_char.repeat_count > 0 + && s->state == p->u.repeated_char.repeat_count) + { + s->tail = p->next; + s->state = NEW_ELEMENT; + } + } + break; + + case RE_NO_TYPE: + abort (); + break; + + default: + abort (); + break; + } + + return return_val; +} + +/* This is a minor kludge. This function is called from + get_spec_stats to determine the cardinality of a set derived + from a complemented string. It's a kludge in that some of the + same operations are (duplicated) performed in set_initialize. */ + +static int +card_of_complement (struct Spec_list *s) +{ + int c; + int cardinality = N_CHARS; + SET_TYPE in_set[N_CHARS]; + + memset (in_set, 0, N_CHARS * sizeof (in_set[0])); + s->state = BEGIN_STATE; + while ((c = get_next (s, NULL)) != -1) + if (!in_set[c]++) + --cardinality; + return cardinality; +} + +/* Gather statistics about the spec-list S in preparation for the tests + in validate that determine the consistency of the specs. This function + is called at most twice; once for string1, and again for any string2. + LEN_S1 < 0 indicates that this is the first call and that S represents + string1. When LEN_S1 >= 0, it is the length of the expansion of the + constructs in string1, and we can use its value to resolve any + indefinite repeat construct in S (which represents string2). Hence, + this function has the side-effect that it converts a valid [c*] + construct in string2 to [c*n] where n is large enough (or 0) to give + string2 the same length as string1. For example, with the command + tr a-z 'A[\n*]Z' on the second call to get_spec_stats, LEN_S1 would + be 26 and S (representing string2) would be converted to 'A[\n*24]Z'. */ + +static void +get_spec_stats (struct Spec_list *s) +{ + struct List_element *p; + int len = 0; + + s->n_indefinite_repeats = 0; + s->has_equiv_class = 0; + s->has_restricted_char_class = 0; + s->has_char_class = 0; + for (p = s->head->next; p; p = p->next) + { + switch (p->type) + { + int i; + case RE_NORMAL_CHAR: + ++len; + break; + + case RE_RANGE: + assert (p->u.range.last_char >= p->u.range.first_char); + len += p->u.range.last_char - p->u.range.first_char + 1; + break; + + case RE_CHAR_CLASS: + s->has_char_class = 1; + for (i = 0; i < N_CHARS; i++) + if (is_char_class_member (p->u.char_class, i)) + ++len; + switch (p->u.char_class) + { + case CC_UPPER: + case CC_LOWER: + break; + default: + s->has_restricted_char_class = 1; + break; + } + break; + + case RE_EQUIV_CLASS: + for (i = 0; i < N_CHARS; i++) + if (is_equiv_class_member (p->u.equiv_code, i)) + ++len; + s->has_equiv_class = 1; + break; + + case RE_REPEATED_CHAR: + if (p->u.repeated_char.repeat_count > 0) + len += p->u.repeated_char.repeat_count; + else if (p->u.repeated_char.repeat_count == 0) + { + s->indefinite_repeat_element = p; + ++(s->n_indefinite_repeats); + } + break; + + case RE_NO_TYPE: + assert (0); + break; + } + } + + s->length = len; +} + +static void +get_s1_spec_stats (struct Spec_list *s1) +{ + get_spec_stats (s1); + if (complement) + s1->length = card_of_complement (s1); +} + +static void +get_s2_spec_stats (struct Spec_list *s2, size_t len_s1) +{ + get_spec_stats (s2); + if (len_s1 >= s2->length && s2->n_indefinite_repeats == 1) + { + s2->indefinite_repeat_element->u.repeated_char.repeat_count = + len_s1 - s2->length; + s2->length = len_s1; + } +} + +static void +spec_init (struct Spec_list *spec_list) +{ + spec_list->head = spec_list->tail = + (struct List_element *) xmalloc (sizeof (struct List_element)); + spec_list->head->next = NULL; +} + +/* This function makes two passes over the argument string S. The first + one converts all \c and \ddd escapes to their one-byte representations. + The second constructs a linked specification list, SPEC_LIST, of the + characters and constructs that comprise the argument string. If either + of these passes detects an error, this function returns nonzero. */ + +static int +parse_str (const unsigned char *s, struct Spec_list *spec_list) +{ + struct E_string es; + int fail; + + fail = unquote (s, &es); + if (!fail) + fail = build_spec_list (&es, spec_list); + es_free (&es); + return fail; +} + +/* Given two specification lists, S1 and S2, and assuming that + S1->length > S2->length, append a single [c*n] element to S2 where c + is the last character in the expansion of S2 and n is the difference + between the two lengths. + Upon successful completion, S2->length is set to S1->length. The only + way this function can fail to make S2 as long as S1 is when S2 has + zero-length, since in that case, there is no last character to repeat. + So S2->length is required to be at least 1. + + Providing this functionality allows the user to do some pretty + non-BSD (and non-portable) things: For example, the command + tr -cs '[:upper:]0-9' '[:lower:]' + is almost guaranteed to give results that depend on your collating + sequence. */ + +static void +string2_extend (const struct Spec_list *s1, struct Spec_list *s2) +{ + struct List_element *p; + int char_to_repeat; + int i; + + assert (translating); + assert (s1->length > s2->length); + assert (s2->length > 0); + + p = s2->tail; + switch (p->type) + { + case RE_NORMAL_CHAR: + char_to_repeat = p->u.normal_char; + break; + case RE_RANGE: + char_to_repeat = p->u.range.last_char; + break; + case RE_CHAR_CLASS: + for (i = N_CHARS; i >= 0; i--) + if (is_char_class_member (p->u.char_class, i)) + break; + assert (i >= 0); + char_to_repeat = CHR (i); + break; + + case RE_REPEATED_CHAR: + char_to_repeat = p->u.repeated_char.the_repeated_char; + break; + + case RE_EQUIV_CLASS: + /* This shouldn't happen, because validate exits with an error + if it finds an equiv class in string2 when translating. */ + abort (); + break; + + case RE_NO_TYPE: + abort (); + break; + + default: + abort (); + break; + } + + append_repeated_char (s2, char_to_repeat, s1->length - s2->length); + s2->length = s1->length; +} + +/* Return non-zero if S is a non-empty list in which exactly one + character (but potentially, many instances of it) appears. + E.g. [X*] or xxxxxxxx. */ + +static int +homogeneous_spec_list (struct Spec_list *s) +{ + int b, c; + + s->state = BEGIN_STATE; + + if ((b = get_next (s, NULL)) == -1) + return 0; + + while ((c = get_next (s, NULL)) != -1) + if (c != b) + return 0; + + return 1; +} + +/* Die with an error message if S1 and S2 describe strings that + are not valid with the given command line switches. + A side effect of this function is that if a valid [c*] or + [c*0] construct appears in string2, it is converted to [c*n] + with a value for n that makes s2->length == s1->length. By + the same token, if the --truncate-set1 option is not + given, S2 may be extended. */ + +static void +validate (struct Spec_list *s1, struct Spec_list *s2) +{ + get_s1_spec_stats (s1); + if (s1->n_indefinite_repeats > 0) + { + error (EXIT_FAILURE, 0, + _("the [c*] repeat construct may not appear in string1")); + } + + if (s2) + { + get_s2_spec_stats (s2, s1->length); + + if (s2->n_indefinite_repeats > 1) + { + error (EXIT_FAILURE, 0, + _("only one [c*] repeat construct may appear in string2")); + } + + if (translating) + { + if (s2->has_equiv_class) + { + error (EXIT_FAILURE, 0, + _("[=c=] expressions may not appear in string2 \ +when translating")); + } + + if (s1->length > s2->length) + { + if (!truncate_set1) + { + /* string2 must be non-empty unless --truncate-set1 is + given or string1 is empty. */ + + if (s2->length == 0) + error (EXIT_FAILURE, 0, + _("when not truncating set1, string2 must be non-empty")); + string2_extend (s1, s2); + } + } + + if (complement && s1->has_char_class + && ! (s2->length == s1->length && homogeneous_spec_list (s2))) + { + error (EXIT_FAILURE, 0, + _("when translating with complemented character classes,\ +\nstring2 must map all characters in the domain to one")); + } + + if (s2->has_restricted_char_class) + { + error (EXIT_FAILURE, 0, + _("when translating, the only character classes that may \ +appear in\nstring2 are `upper' and `lower'")); + } + } + else + /* Not translating. */ + { + if (s2->n_indefinite_repeats > 0) + error (EXIT_FAILURE, 0, + _("the [c*] construct may appear in string2 only \ +when translating")); + } + } +} + +/* Read buffers of SIZE bytes via the function READER (if READER is + NULL, read from stdin) until EOF. When non-NULL, READER is either + read_and_delete or read_and_xlate. After each buffer is read, it is + processed and written to stdout. The buffers are processed so that + multiple consecutive occurrences of the same character in the input + stream are replaced by a single occurrence of that character if the + character is in the squeeze set. */ + +static void +squeeze_filter (unsigned char *buf, size_t size, Filter reader) +{ + unsigned int char_to_squeeze = NOT_A_CHAR; + size_t i = 0; + size_t nr = 0; + + for (;;) + { + size_t begin; + + if (i >= nr) + { + if (reader == NULL) + { + nr = safe_read (0, (char *) buf, size); + if (nr == SAFE_READ_ERROR) + error (EXIT_FAILURE, errno, _("read error")); + } + else + { + nr = (*reader) (buf, size, NULL); + } + + if (nr == 0) + break; + i = 0; + } + + begin = i; + + if (char_to_squeeze == NOT_A_CHAR) + { + size_t out_len; + /* Here, by being a little tricky, we can get a significant + performance increase in most cases when the input is + reasonably large. Since tr will modify the input only + if two consecutive (and identical) input characters are + in the squeeze set, we can step by two through the data + when searching for a character in the squeeze set. This + means there may be a little more work in a few cases and + perhaps twice as much work in the worst cases where most + of the input is removed by squeezing repeats. But most + uses of this functionality seem to remove less than 20-30% + of the input. */ + for (; i < nr && !in_squeeze_set[buf[i]]; i += 2) + ; /* empty */ + + /* There is a special case when i == nr and we've just + skipped a character (the last one in buf) that is in + the squeeze set. */ + if (i == nr && in_squeeze_set[buf[i - 1]]) + --i; + + if (i >= nr) + out_len = nr - begin; + else + { + char_to_squeeze = buf[i]; + /* We're about to output buf[begin..i]. */ + out_len = i - begin + 1; + + /* But since we stepped by 2 in the loop above, + out_len may be one too large. */ + if (i > 0 && buf[i - 1] == char_to_squeeze) + --out_len; + + /* Advance i to the index of first character to be + considered when looking for a char different from + char_to_squeeze. */ + ++i; + } + if (out_len > 0 + && fwrite ((char *) &buf[begin], 1, out_len, stdout) == 0) + error (EXIT_FAILURE, errno, _("write error")); + } + + if (char_to_squeeze != NOT_A_CHAR) + { + /* Advance i to index of first char != char_to_squeeze + (or to nr if all the rest of the characters in this + buffer are the same as char_to_squeeze). */ + for (; i < nr && buf[i] == char_to_squeeze; i++) + ; /* empty */ + if (i < nr) + char_to_squeeze = NOT_A_CHAR; + /* If (i >= nr) we've squeezed the last character in this buffer. + So now we have to read a new buffer and continue comparing + characters against char_to_squeeze. */ + } + } +} + +/* Read buffers of SIZE bytes from stdin until one is found that + contains at least one character not in the delete set. Store + in the array BUF, all characters from that buffer that are not + in the delete set, and return the number of characters saved + or 0 upon EOF. */ + +static size_t +read_and_delete (unsigned char *buf, size_t size, Filter not_used) +{ + size_t n_saved; + static int hit_eof = 0; + + assert (not_used == NULL); + + if (hit_eof) + return 0; + + /* This enclosing do-while loop is to make sure that + we don't return zero (indicating EOF) when we've + just deleted all the characters in a buffer. */ + do + { + size_t i; + size_t nr = safe_read (0, (char *) buf, size); + + if (nr == SAFE_READ_ERROR) + error (EXIT_FAILURE, errno, _("read error")); + if (nr == 0) + { + hit_eof = 1; + return 0; + } + + /* This first loop may be a waste of code, but gives much + better performance when no characters are deleted in + the beginning of a buffer. It just avoids the copying + of buf[i] into buf[n_saved] when it would be a NOP. */ + + for (i = 0; i < nr && !in_delete_set[buf[i]]; i++) + /* empty */ ; + n_saved = i; + + for (++i; i < nr; i++) + if (!in_delete_set[buf[i]]) + buf[n_saved++] = buf[i]; + } + while (n_saved == 0); + + return n_saved; +} + +/* Read at most SIZE bytes from stdin into the array BUF. Then + perform the in-place and one-to-one mapping specified by the global + array `xlate'. Return the number of characters read, or 0 upon EOF. */ + +static size_t +read_and_xlate (unsigned char *buf, size_t size, Filter not_used) +{ + size_t bytes_read = 0; + static int hit_eof = 0; + size_t i; + + assert (not_used == NULL); + + if (hit_eof) + return 0; + + bytes_read = safe_read (0, (char *) buf, size); + if (bytes_read == SAFE_READ_ERROR) + error (EXIT_FAILURE, errno, _("read error")); + if (bytes_read == 0) + { + hit_eof = 1; + return 0; + } + + for (i = 0; i < bytes_read; i++) + buf[i] = xlate[buf[i]]; + + return bytes_read; +} + +/* Initialize a boolean membership set IN_SET with the character + values obtained by traversing the linked list of constructs S + using the function `get_next'. If COMPLEMENT_THIS_SET is + nonzero the resulting set is complemented. */ + +static void +set_initialize (struct Spec_list *s, int complement_this_set, SET_TYPE *in_set) +{ + int c; + size_t i; + + memset (in_set, 0, N_CHARS * sizeof (in_set[0])); + s->state = BEGIN_STATE; + while ((c = get_next (s, NULL)) != -1) + in_set[c] = 1; + if (complement_this_set) + for (i = 0; i < N_CHARS; i++) + in_set[i] = (!in_set[i]); +} + +int +main (int argc, char **argv) +{ + int c; + int non_option_args; + struct Spec_list buf1, buf2; + struct Spec_list *s1 = &buf1; + struct Spec_list *s2 = &buf2; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + while ((c = getopt_long (argc, argv, "cdst", long_options, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + case 'c': + complement = 1; + break; + + case 'd': + delete = 1; + break; + + case 's': + squeeze_repeats = 1; + break; + + case 't': + truncate_set1 = 1; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (2); + break; + } + } + + posix_pedantic = (getenv ("POSIXLY_CORRECT") != NULL); + + non_option_args = argc - optind; + translating = (non_option_args == 2 && !delete); + + /* Change this test if it is valid to give tr no options and + no args at all. POSIX doesn't specifically say anything + either way, but it looks like they implied it's invalid + by omission. If you want to make tr do a slow imitation + of `cat' use `tr a a'. */ + if (non_option_args > 2) + { + error (0, 0, _("too many arguments")); + usage (2); + } + + if (!delete && !squeeze_repeats && non_option_args != 2) + error (EXIT_FAILURE, 0, _("two strings must be given when translating")); + + if (delete && squeeze_repeats && non_option_args != 2) + error (EXIT_FAILURE, 0, _("two strings must be given when both \ +deleting and squeezing repeats")); + + /* If --delete is given without --squeeze-repeats, then + only one string argument may be specified. But POSIX + says to ignore any string2 in this case, so if POSIXLY_CORRECT + is set, pretend we never saw string2. But I think + this deserves a fatal error, so that's the default. */ + if ((delete && !squeeze_repeats) && non_option_args != 1) + { + if (posix_pedantic && non_option_args == 2) + --non_option_args; + else + error (EXIT_FAILURE, 0, + _("only one string may be given when deleting \ +without squeezing repeats")); + } + + if (squeeze_repeats && non_option_args == 0) + error (EXIT_FAILURE, 0, + _("at least one string must be given when squeezing repeats")); + + spec_init (s1); + if (parse_str ((unsigned char *) argv[optind], s1)) + exit (EXIT_FAILURE); + + if (non_option_args == 2) + { + spec_init (s2); + if (parse_str ((unsigned char *) argv[optind + 1], s2)) + exit (EXIT_FAILURE); + } + else + s2 = NULL; + + validate (s1, s2); + + /* Use binary I/O, since `tr' is sometimes used to transliterate + non-printable characters, or characters which are stripped away + by text-mode reads (like CR and ^Z). */ + SET_BINARY2 (STDIN_FILENO, STDOUT_FILENO); + + if (squeeze_repeats && non_option_args == 1) + { + set_initialize (s1, complement, in_squeeze_set); + squeeze_filter (io_buf, IO_BUF_SIZE, NULL); + } + else if (delete && non_option_args == 1) + { + size_t nr; + + set_initialize (s1, complement, in_delete_set); + do + { + nr = read_and_delete (io_buf, IO_BUF_SIZE, NULL); + if (nr > 0 && fwrite ((char *) io_buf, 1, nr, stdout) == 0) + error (EXIT_FAILURE, errno, _("write error")); + } + while (nr > 0); + } + else if (squeeze_repeats && delete && non_option_args == 2) + { + set_initialize (s1, complement, in_delete_set); + set_initialize (s2, 0, in_squeeze_set); + squeeze_filter (io_buf, IO_BUF_SIZE, read_and_delete); + } + else if (translating) + { + if (complement) + { + int i; + SET_TYPE *in_s1 = in_delete_set; + + set_initialize (s1, 0, in_s1); + s2->state = BEGIN_STATE; + for (i = 0; i < N_CHARS; i++) + xlate[i] = i; + for (i = 0; i < N_CHARS; i++) + { + if (!in_s1[i]) + { + int ch = get_next (s2, NULL); + assert (ch != -1 || truncate_set1); + if (ch == -1) + { + /* This will happen when tr is invoked like e.g. + tr -cs A-Za-z0-9 '\012'. */ + break; + } + xlate[i] = ch; + } + } + assert (get_next (s2, NULL) == -1 || truncate_set1); + } + else + { + int c1, c2; + int i; + enum Upper_Lower_class class_s1; + enum Upper_Lower_class class_s2; + + for (i = 0; i < N_CHARS; i++) + xlate[i] = i; + s1->state = BEGIN_STATE; + s2->state = BEGIN_STATE; + for (;;) + { + c1 = get_next (s1, &class_s1); + c2 = get_next (s2, &class_s2); + if (!class_ok[(int) class_s1][(int) class_s2]) + error (EXIT_FAILURE, 0, + _("misaligned [:upper:] and/or [:lower:] construct")); + + if (class_s1 == UL_LOWER && class_s2 == UL_UPPER) + { + for (i = 0; i < N_CHARS; i++) + if (ISLOWER (i)) + xlate[i] = toupper (i); + } + else if (class_s1 == UL_UPPER && class_s2 == UL_LOWER) + { + for (i = 0; i < N_CHARS; i++) + if (ISUPPER (i)) + xlate[i] = tolower (i); + } + else if ((class_s1 == UL_LOWER && class_s2 == UL_LOWER) + || (class_s1 == UL_UPPER && class_s2 == UL_UPPER)) + { + /* By default, GNU tr permits the identity mappings: from + [:upper:] to [:upper:] and [:lower:] to [:lower:]. But + when POSIXLY_CORRECT is set, those evoke diagnostics. */ + if (posix_pedantic) + { + error (EXIT_FAILURE, 0, + _("\ +invalid identity mapping; when translating, any [:lower:] or [:upper:]\n\ +construct in string1 must be aligned with a corresponding construct\n\ +([:upper:] or [:lower:], respectively) in string2")); + } + } + else + { + /* The following should have been checked by validate... */ + if (c1 == -1 || c2 == -1) + break; + xlate[c1] = c2; + } + } + assert (c1 == -1 || truncate_set1); + } + if (squeeze_repeats) + { + set_initialize (s2, 0, in_squeeze_set); + squeeze_filter (io_buf, IO_BUF_SIZE, read_and_xlate); + } + else + { + size_t bytes_read; + + do + { + bytes_read = read_and_xlate (io_buf, IO_BUF_SIZE, NULL); + if (bytes_read > 0 + && fwrite ((char *) io_buf, 1, bytes_read, stdout) == 0) + error (EXIT_FAILURE, errno, _("write error")); + } + while (bytes_read > 0); + } + } + + if (close (STDIN_FILENO) != 0) + error (EXIT_FAILURE, errno, _("standard input")); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/true.c b/src/apps/bin/coreutils-5.0/src/true.c new file mode 100644 index 0000000000..ecbf451f8c --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/true.c @@ -0,0 +1,71 @@ +/* Exit with a status code indicating success. + Copyright (C) 1999-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include "system.h" +#include "version-etc.h" +#include "closeout.h" + +#define PROGRAM_NAME "true" +#define AUTHORS "Jim Meyering" + +/* The name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + printf (_("\ +Usage: %s [ignored command line arguments]\n\ + or: %s OPTION\n\ +Exit with a status code indicating success.\n\ +\n\ +These option names may not be abbreviated.\n\ +\n\ +"), + program_name, program_name); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + exit (status); +} + +int +main (int argc, char **argv) +{ + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + /* Recognize --help or --version only if it's the only command-line + argument and if POSIXLY_CORRECT is not set. */ + if (argc == 2 && getenv ("POSIXLY_CORRECT") == NULL) + { + if (STREQ (argv[1], "--help")) + usage (EXIT_SUCCESS); + + if (STREQ (argv[1], "--version")) + version_etc (stdout, PROGRAM_NAME, GNU_PACKAGE, VERSION, AUTHORS); + } + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/tsort.c b/src/apps/bin/coreutils-5.0/src/tsort.c new file mode 100644 index 0000000000..ebd1d43f9c --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/tsort.c @@ -0,0 +1,588 @@ +/* tsort - topological sort. + Copyright (C) 1998-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Mark Kettenis . */ + +/* The topological sort is done according to Algorithm T (Topological + sort) in Donald E. Knuth, The Art of Computer Programming, Volume + 1/Fundamental Algorithms, page 262. */ + +#include + +#include +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "long-options.h" +#include "error.h" +#include "readtokens.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "tsort" + +#define AUTHORS "Mark Kettenis" + +/* Token delimiters when reading from a file. */ +#define DELIM " \t\n" + +/* Members of the list of successors. */ +struct successor +{ + struct item *suc; + struct successor *next; +}; + +/* Each string is held in core as the head of a list of successors. */ +struct item +{ + const char *str; + struct item *left, *right; + int balance; + int count; + struct item *qlink; + struct successor *top; +}; + +/* The name this program was run with. */ +char *program_name; + +/* Nonzero if any of the input files are the standard input. */ +static int have_read_stdin; + +/* The error code to return to the system. */ +static int exit_status; + +/* The head of the sorted list. */ +static struct item *head = NULL; + +/* The tail of the list of `zeros', strings that have no predecessors. */ +static struct item *zeros = NULL; + +/* Used for loop detection. */ +static struct item *loop = NULL; + +/* The number of strings to sort. */ +static int n_strings = 0; + +static struct option const long_options[] = +{ + { NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION] [FILE]\n\ +Write totally ordered list consistent with the partial ordering in FILE.\n\ +With no FILE, or when FILE is -, read standard input.\n\ +\n\ +"), program_name); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Create a new item/node for STR. */ +static struct item * +new_item (const char *str) +{ + struct item *k = xmalloc (sizeof (struct item)); + + k->str = (str ? xstrdup (str): NULL); + k->left = k->right = NULL; + k->balance = 0; + + /* T1. Initialize (COUNT[k] <- 0 and TOP[k] <- ^). */ + k->count = 0; + k->qlink = NULL; + k->top = NULL; + + return k; +} + +/* Search binary tree rooted at *ROOT for STR. Allocate a new tree if + *ROOT is NULL. Insert a node/item for STR if not found. Return + the node/item found/created for STR. + + This is done according to Algorithm A (Balanced tree search and + insertion) in Donald E. Knuth, The Art of Computer Programming, + Volume 3/Searching and Sorting, pages 455--457. */ + +static struct item * +search_item (struct item *root, const char *str) +{ + struct item *p, *q, *r, *s, *t; + int a; + + assert (root); + + /* Make sure the tree is not empty, since that is what the algorithm + below expects. */ + if (root->right == NULL) + return (root->right = new_item (str)); + + /* A1. Initialize. */ + t = root; + s = p = root->right; + + for (;;) + { + /* A2. Compare. */ + a = strcmp (str, p->str); + if (a == 0) + return p; + + /* A3 & A4. Move left & right. */ + if (a < 0) + q = p->left; + else + q = p->right; + + if (q == NULL) + { + /* A5. Insert. */ + q = new_item (str); + + /* A3 & A4. (continued). */ + if (a < 0) + p->left = q; + else + p->right = q; + + /* A6. Adjust balance factors. */ + assert (!STREQ (str, s->str)); + if (strcmp (str, s->str) < 0) + { + r = p = s->left; + a = -1; + } + else + { + r = p = s->right; + a = 1; + } + + while (p != q) + { + assert (!STREQ (str, p->str)); + if (strcmp (str, p->str) < 0) + { + p->balance = -1; + p = p->left; + } + else + { + p->balance = 1; + p = p->right; + } + } + + /* A7. Balancing act. */ + if (s->balance == 0 || s->balance == -a) + { + s->balance += a; + return q; + } + + if (r->balance == a) + { + /* A8. Single Rotation. */ + p = r; + if (a < 0) + { + s->left = r->right; + r->right = s; + } + else + { + s->right = r->left; + r->left = s; + } + s->balance = r->balance = 0; + } + else + { + /* A9. Double rotation. */ + if (a < 0) + { + p = r->right; + r->right = p->left; + p->left = r; + s->left = p->right; + p->right = s; + } + else + { + p = r->left; + r->left = p->right; + p->right = r; + s->right = p->left; + p->left = s; + } + + s->balance = 0; + r->balance = 0; + if (p->balance == a) + s->balance = -a; + else if (p->balance == -a) + r->balance = a; + p->balance = 0; + } + + /* A10. Finishing touch. */ + if (s == t->right) + t->right = p; + else + t->left = p; + + return q; + } + + /* A3 & A4. (continued). */ + if (q->balance) + { + t = p; + s = q; + } + + p = q; + } + + /* NOTREACHED */ +} + +/* Record the fact that J precedes K. */ + +static void +record_relation (struct item *j, struct item *k) +{ + struct successor *p; + + if (!STREQ (j->str, k->str)) + { + k->count++; + p = xmalloc (sizeof (struct successor)); + p->suc = k; + p->next = j->top; + j->top = p; + } +} + +static int +count_items (struct item *unused ATTRIBUTE_UNUSED) +{ + n_strings++; + return 0; +} + +static int +scan_zeros (struct item *k) +{ + /* Ignore strings that have already been printed. */ + if (k->count == 0 && k->str) + { + if (head == NULL) + head = k; + else + zeros->qlink = k; + + zeros = k; + } + + return 0; +} + +/* Try to detect the loop. If we have detected that K is part of a + loop, print the loop on standard error, remove a relation to break + the loop, and return non-zero. + + The loop detection strategy is as follows: Realise that what we're + dealing with is essentially a directed graph. If we find an item + that is part of a graph that contains a cycle we traverse the graph + in backwards direction. In general there is no unique way to do + this, but that is no problem. If we encounter an item that we have + encountered before, we know that we've found a cycle. All we have + to do now is retrace our steps, printing out the items until we + encounter that item again. (This is not necessarily the item that + we started from originally.) Since the order in which the items + are stored in the tree is not related to the specified partial + ordering, we may need to walk the tree several times before the + loop has completely been constructed. If the loop was found, the + global variable LOOP will be NULL. */ + +static int +detect_loop (struct item *k) +{ + if (k->count > 0) + { + /* K does not have to be part of a cycle. It is however part of + a graph that contains a cycle. */ + + if (loop == NULL) + /* Start traversing the graph at K. */ + loop = k; + else + { + struct successor **p = &k->top; + + while (*p) + { + if ((*p)->suc == loop) + { + if (k->qlink) + { + /* We have found a loop. Retrace our steps. */ + while (loop) + { + struct item *tmp = loop->qlink; + + fprintf (stderr, "%s: %s\n", program_name, + loop->str); + + /* Until we encounter K again. */ + if (loop == k) + { + /* Remove relation. */ + (*p)->suc->count--; + *p = (*p)->next; + break; + } + + /* Tidy things up since we might have to + detect another loop. */ + loop->qlink = NULL; + loop = tmp; + } + + while (loop) + { + struct item *tmp = loop->qlink; + + loop->qlink = NULL; + loop = tmp; + } + + /* Since we have found the loop, stop walking + the tree. */ + return 1; + } + else + { + k->qlink = loop; + loop = k; + break; + } + } + + p = &(*p)->next; + } + } + } + + return 0; +} + +/* Recurse (sub)tree rooted at ROOT, calling ACTION for each node. + Stop when ACTION returns non-zero. */ + +static int +recurse_tree (struct item *root, int (*action) (struct item *)) +{ + if (root->left == NULL && root->right == NULL) + return (*action) (root); + else + { + if (root->left != NULL) + if (recurse_tree (root->left, action)) + return 1; + if ((*action) (root)) + return 1; + if (root->right != NULL) + if (recurse_tree (root->right, action)) + return 1; + } + + return 0; +} + +/* Walk the tree specified by the head ROOT, calling ACTION for + each node. */ + +static void +walk_tree (struct item *root, int (*action) (struct item *)) +{ + if (root->right) + recurse_tree (root->right, action); +} + +/* Do a topological sort on FILE. */ + +static void +tsort (const char *file) +{ + struct item *root; + struct item *j = NULL; + struct item *k = NULL; + register FILE *fp; + token_buffer tokenbuffer; + + /* Intialize the head of the tree will hold the strings we're sorting. */ + root = new_item (NULL); + + if (STREQ (file, "-")) + { + fp = stdin; + have_read_stdin = 1; + } + else + { + fp = fopen (file, "r"); + if (fp == NULL) + error (EXIT_FAILURE, errno, "%s", file); + } + + init_tokenbuffer (&tokenbuffer); + + while (1) + { + long int len; + + /* T2. Next Relation. */ + len = readtoken (fp, DELIM, sizeof (DELIM) - 1, &tokenbuffer); + if (len < 0) + break; + + assert (len != 0); + + k = search_item (root, tokenbuffer.buffer); + if (j) + { + /* T3. Record the relation. */ + record_relation (j, k); + k = NULL; + } + + j = k; + } + + /* T1. Initialize (N <- n). */ + walk_tree (root, count_items); + + while (n_strings > 0) + { + /* T4. Scan for zeros. */ + walk_tree (root, scan_zeros); + + while (head) + { + struct successor *p = head->top; + + /* T5. Output front of queue. */ + printf ("%s\n", head->str); + head->str = NULL; /* Avoid printing the same string twice. */ + n_strings--; + + /* T6. Erase relations. */ + while (p) + { + p->suc->count--; + if (p->suc->count == 0) + { + zeros->qlink = p->suc; + zeros = p->suc; + } + + p = p->next; + } + + /* T7. Remove from queue. */ + head = head->qlink; + } + + /* T8. End of process. */ + assert (n_strings >= 0); + if (n_strings > 0) + { + /* The input contains a loop. */ + error (0, 0, _("%s: input contains a loop:"), + (have_read_stdin ? "-" : file)); + exit_status = 1; + + /* Print the loop and remove a relation to break it. */ + do + walk_tree (root, detect_loop); + while (loop); + } + } +} + +int +main (int argc, char **argv) +{ + int opt; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + exit_status = 0; + + parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION, + AUTHORS, usage); + + while ((opt = getopt_long (argc, argv, "", long_options, NULL)) != -1) + switch (opt) + { + case 0: /* long option */ + break; + default: + usage (EXIT_FAILURE); + } + + have_read_stdin = 0; + + if (optind + 1 < argc) + { + error (0, 0, _("only one argument may be specified")); + usage (EXIT_FAILURE); + } + + if (optind < argc) + tsort (argv[optind]); + else + tsort ("-"); + + if (have_read_stdin && fclose (stdin) == EOF) + error (EXIT_FAILURE, errno, _("standard input")); + + exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/tty.c b/src/apps/bin/coreutils-5.0/src/tty.c new file mode 100644 index 0000000000..46c20a7709 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/tty.c @@ -0,0 +1,124 @@ +/* tty -- print the path of the terminal connected to standard input + Copyright (C) 1990-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Displays "not a tty" if stdin is not a terminal. + Displays nothing if -s option is given. + Exit status 0 if stdin is a tty, 1 if not, 2 if usage error, + 3 if write error. + + Written by David MacKenzie . */ + +#include +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "error.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "tty" + +#define AUTHORS "David MacKenzie" + +/* The name under which this program was run. */ +char *program_name; + +/* If nonzero, return an exit status but produce no output. */ +static int silent; + +static struct option const longopts[] = +{ + {"silent", no_argument, NULL, 's'}, + {"quiet", no_argument, NULL, 's'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]...\n"), program_name); + fputs (_("\ +Print the file name of the terminal connected to standard input.\n\ +\n\ + -s, --silent, --quiet print nothing, only return an exit status\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + char *tty; + int optc; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + close_stdout_set_status (3); + atexit (close_stdout); + + silent = 0; + + while ((optc = getopt_long (argc, argv, "s", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + + case 's': + silent = 1; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (2); + } + } + + if (optind != argc) + error (0, 0, _("ignoring all arguments")); + + tty = ttyname (0); + if (!silent) + { + if (tty) + puts (tty); + else + puts (_("not a tty")); + } + + exit (isatty (0) ? 0 : 1); +} diff --git a/src/apps/bin/coreutils-5.0/src/uname.c b/src/apps/bin/coreutils-5.0/src/uname.c new file mode 100644 index 0000000000..ad487e334a --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/uname.c @@ -0,0 +1,293 @@ +/* uname -- print system information + + Copyright 1989, 1992, 1993, 1996, 1997, 1999, 2000, 2001, 2002 Free + Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie */ + +#include +#include +#include +#include +#include + +#if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H +# include +#endif + +#if HAVE_SYSCTL && HAVE_SYS_SYSCTL_H +# include /* needed for OpenBSD 3.0 */ +# include +# ifdef HW_MODEL +# ifdef HW_MACHINE_ARCH +/* E.g., FreeBSD 4.5, NetBSD 1.5.2 */ +# define UNAME_HARDWARE_PLATFORM HW_MODEL +# define UNAME_PROCESSOR HW_MACHINE_ARCH +# else +/* E.g., OpenBSD 3.0 */ +# define UNAME_PROCESSOR HW_MODEL +# endif +# endif +#endif + +#include "system.h" +#include "error.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "uname" + +#define AUTHORS "David MacKenzie" + +/* Values that are bitwise or'd into `toprint'. */ +/* Kernel name. */ +#define PRINT_KERNEL_NAME 1 + +/* Node name on a communications network. */ +#define PRINT_NODENAME 2 + +/* Kernel release. */ +#define PRINT_KERNEL_RELEASE 4 + +/* Kernel version. */ +#define PRINT_KERNEL_VERSION 8 + +/* Machine hardware name. */ +#define PRINT_MACHINE 16 + +/* Processor type. */ +#define PRINT_PROCESSOR 32 + +/* Hardware platform. */ +#define PRINT_HARDWARE_PLATFORM 64 + +/* Operating system. */ +#define PRINT_OPERATING_SYSTEM 128 + +/* The name this program was run with, for error messages. */ +char *program_name; + +static struct option const long_options[] = +{ + {"all", no_argument, NULL, 'a'}, + {"kernel-name", no_argument, NULL, 's'}, + {"sysname", no_argument, NULL, 's'}, /* Obsolescent. */ + {"nodename", no_argument, NULL, 'n'}, + {"kernel-release", no_argument, NULL, 'r'}, + {"release", no_argument, NULL, 'r'}, /* Obsolescent. */ + {"kernel-version", no_argument, NULL, 'v'}, + {"machine", no_argument, NULL, 'm'}, + {"processor", no_argument, NULL, 'p'}, + {"hardware-platform", no_argument, NULL, 'i'}, + {"operating-system", no_argument, NULL, 'o'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]...\n"), program_name); + fputs (_("\ +Print certain system information. With no OPTION, same as -s.\n\ +\n\ + -a, --all print all information, in the following order:\n\ + -s, --kernel-name print the kernel name\n\ + -n, --nodename print the network node hostname\n\ + -r, --kernel-release print the kernel release\n\ +"), stdout); + fputs (_("\ + -v, --kernel-version print the kernel version\n\ + -m, --machine print the machine hardware name\n\ + -p, --processor print the processor type\n\ + -i, --hardware-platform print the hardware platform\n\ + -o, --operating-system print the operating system\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +/* Print ELEMENT, preceded by a space if something has already been + printed. */ + +static void +print_element (char const *element) +{ + static int printed; + if (printed++) + putchar (' '); + fputs (element, stdout); +} + +int +main (int argc, char **argv) +{ + int c; + static char const unknown[] = "unknown"; + + /* Mask indicating which elements to print. */ + unsigned toprint = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + while ((c = getopt_long (argc, argv, "asnrvmpio", long_options, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + case 'a': + toprint = -1; + break; + + case 's': + toprint |= PRINT_KERNEL_NAME; + break; + + case 'n': + toprint |= PRINT_NODENAME; + break; + + case 'r': + toprint |= PRINT_KERNEL_RELEASE; + break; + + case 'v': + toprint |= PRINT_KERNEL_VERSION; + break; + + case 'm': + toprint |= PRINT_MACHINE; + break; + + case 'p': + toprint |= PRINT_PROCESSOR; + break; + + case 'i': + toprint |= PRINT_HARDWARE_PLATFORM; + break; + + case 'o': + toprint |= PRINT_OPERATING_SYSTEM; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (optind != argc) + usage (EXIT_FAILURE); + + if (toprint == 0) + toprint = PRINT_KERNEL_NAME; + + if (toprint + & (PRINT_KERNEL_NAME | PRINT_NODENAME | PRINT_KERNEL_RELEASE + | PRINT_KERNEL_VERSION | PRINT_MACHINE)) + { + struct utsname name; + + if (uname (&name) == -1) + error (EXIT_FAILURE, errno, _("cannot get system name")); + + if (toprint & PRINT_KERNEL_NAME) + print_element (name.sysname); + if (toprint & PRINT_NODENAME) + print_element (name.nodename); + if (toprint & PRINT_KERNEL_RELEASE) + print_element (name.release); + if (toprint & PRINT_KERNEL_VERSION) + print_element (name.version); + if (toprint & PRINT_MACHINE) + print_element (name.machine); + } + + if (toprint & PRINT_PROCESSOR) + { + char const *element = unknown; +#if HAVE_SYSINFO && defined SI_ARCHITECTURE + { + static char processor[257]; + if (0 <= sysinfo (SI_ARCHITECTURE, processor, sizeof processor)) + element = processor; + } +#endif +#ifdef UNAME_PROCESSOR + if (element == unknown) + { + static char processor[257]; + size_t s = sizeof processor; + static int mib[] = { CTL_HW, UNAME_PROCESSOR }; + if (sysctl (mib, 2, processor, &s, 0, 0) >= 0) + element = processor; + } +#endif + print_element (element); + } + + if (toprint & PRINT_HARDWARE_PLATFORM) + { + char const *element = unknown; +#if HAVE_SYSINFO && defined SI_PLATFORM + { + static char hardware_platform[257]; + if (0 <= sysinfo (SI_PLATFORM, + hardware_platform, sizeof hardware_platform)) + element = hardware_platform; + } +#endif +#ifdef UNAME_HARDWARE_PLATFORM + if (element == unknown) + { + static char hardware_platform[257]; + size_t s = sizeof hardware_platform; + static int mib[] = { CTL_HW, UNAME_HARDWARE_PLATFORM }; + if (sysctl (mib, 2, hardware_platform, &s, 0, 0) >= 0) + element = hardware_platform; + } +#endif + print_element (element); + } + + if (toprint & PRINT_OPERATING_SYSTEM) + print_element (HOST_OPERATING_SYSTEM); + + putchar ('\n'); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/unexpand.c b/src/apps/bin/coreutils-5.0/src/unexpand.c new file mode 100644 index 0000000000..9c1e751f62 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/unexpand.c @@ -0,0 +1,496 @@ +/* unexpand - convert spaces to tabs + Copyright (C) 89, 91, 1995-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* By default, convert only maximal strings of initial blanks and tabs + into tabs. + Preserves backspace characters in the output; they decrement the + column count for tab calculations. + The default action is equivalent to -8. + + Options: + --tabs=tab1[,tab2[,...]] + -t tab1[,tab2[,...]] + -tab1[,tab2[,...]] If only one tab stop is given, set the tabs tab1 + spaces apart instead of the default 8. Otherwise, + set the tabs at columns tab1, tab2, etc. (numbered from + 0); replace any tabs beyond the tabstops given with + single spaces. + --all + -a Use tabs wherever they would replace 2 or more spaces, + not just at the beginnings of lines. + + David MacKenzie */ + +#include + +#include +#include +#include +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "posixver.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "unexpand" + +#define AUTHORS "David MacKenzie" + +/* The number of bytes added at a time to the amount of memory + allocated for the output line. */ +#define OUTPUT_BLOCK 256 + +/* The number of bytes added at a time to the amount of memory + allocated for the list of tabstops. */ +#define TABLIST_BLOCK 256 + +/* A sentinel value that's placed at the end of the list of tab stops. + This value must be a large number, but not so large that adding the + length of a line to it would cause the column variable to overflow. */ +#define TAB_STOP_SENTINEL INT_MAX + +/* The name this program was run with. */ +char *program_name; + +/* If nonzero, convert blanks even after nonblank characters have been + read on the line. */ +static int convert_entire_line; + +/* If nonzero, the size of all tab stops. If zero, use `tab_list' instead. */ +static int tab_size; + +/* Array of the explicit column numbers of the tab stops; + after `tab_list' is exhausted, the rest of the line is printed + unchanged. The first column is column 0. */ +static int *tab_list; + +/* The index of the first invalid element of `tab_list', + where the next element can be added. */ +static int first_free_tab; + +/* Null-terminated array of input filenames. */ +static char **file_list; + +/* Default for `file_list' if no files are given on the command line. */ +static char *stdin_argv[] = +{ + "-", NULL +}; + +/* Nonzero if we have ever read standard input. */ +static int have_read_stdin; + +/* Status to return to the system. */ +static int exit_status; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + CONVERT_FIRST_ONLY_OPTION = CHAR_MAX + 1 +}; + +static struct option const longopts[] = +{ + {"tabs", required_argument, NULL, 't'}, + {"all", no_argument, NULL, 'a'}, + {"first-only", no_argument, NULL, CONVERT_FIRST_ONLY_OPTION}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +/* Add tab stop TABVAL to the end of `tab_list', except + if TABVAL is -1, do nothing. */ + +static void +add_tabstop (int tabval) +{ + if (tabval == -1) + return; + if (first_free_tab % TABLIST_BLOCK == 0) + tab_list = (int *) xrealloc ((char *) tab_list, + first_free_tab + TABLIST_BLOCK); + tab_list[first_free_tab++] = tabval; +} + +/* Add the comma or blank separated list of tabstops STOPS + to the list of tabstops. */ + +static void +parse_tabstops (const char *stops) +{ + int tabval = -1; + + for (; *stops; stops++) + { + if (*stops == ',' || ISBLANK (*stops)) + { + add_tabstop (tabval); + tabval = -1; + } + else if (ISDIGIT (*stops)) + { + if (tabval == -1) + tabval = 0; + tabval = tabval * 10 + *stops - '0'; + } + else + error (EXIT_FAILURE, 0, _("tab size contains an invalid character")); + } + + add_tabstop (tabval); +} + +/* Check that the list of tabstops TABS, with ENTRIES entries, + contains only nonzero, ascending values. */ + +static void +validate_tabstops (const int *tabs, int entries) +{ + int prev_tab = 0; + int i; + + for (i = 0; i < entries; i++) + { + if (tabs[i] == 0) + error (EXIT_FAILURE, 0, _("tab size cannot be 0")); + if (tabs[i] <= prev_tab) + error (EXIT_FAILURE, 0, _("tab sizes must be ascending")); + prev_tab = tabs[i]; + } +} + +/* Close the old stream pointer FP if it is non-NULL, + and return a new one opened to read the next input file. + Open a filename of `-' as the standard input. + Return NULL if there are no more input files. */ + +static FILE * +next_file (FILE *fp) +{ + static char *prev_file; + char *file; + + if (fp) + { + if (ferror (fp)) + { + error (0, errno, "%s", prev_file); + exit_status = 1; + } + if (fp == stdin) + clearerr (fp); /* Also clear EOF. */ + else if (fclose (fp) == EOF) + { + error (0, errno, "%s", prev_file); + exit_status = 1; + } + } + + while ((file = *file_list++) != NULL) + { + if (file[0] == '-' && file[1] == '\0') + { + have_read_stdin = 1; + prev_file = file; + return stdin; + } + fp = fopen (file, "r"); + if (fp) + { + prev_file = file; + return fp; + } + error (0, errno, "%s", file); + exit_status = 1; + } + return NULL; +} + +/* Change spaces to tabs, writing to stdout. + Read each file in `file_list', in order. */ + +static void +unexpand (void) +{ + FILE *fp; /* Input stream. */ + int c; /* Each input character. */ + /* Index in `tab_list' of next tabstop: */ + int tab_index = 0; /* For calculating width of pending tabs. */ + int print_tab_index = 0; /* For printing as many tabs as possible. */ + unsigned int column = 0; /* Column on screen of next char. */ + int next_tab_column; /* Column the next tab stop is on. */ + int convert = 1; /* If nonzero, perform translations. */ + unsigned int pending = 0; /* Pending columns of blanks. */ + + fp = next_file ((FILE *) NULL); + if (fp == NULL) + return; + + /* Binary I/O will preserve the original EOL style (DOS/Unix) of files. */ + SET_BINARY2 (fileno (fp), STDOUT_FILENO); + + for (;;) + { + c = getc (fp); + + if (c == ' ' && convert && column < TAB_STOP_SENTINEL) + { + ++pending; + ++column; + } + else if (c == '\t' && convert) + { + if (tab_size == 0) + { + /* Do not let tab_index == first_free_tab; + stop when it is 1 less. */ + while (tab_index < first_free_tab - 1 + && column >= tab_list[tab_index]) + tab_index++; + next_tab_column = tab_list[tab_index]; + if (tab_index < first_free_tab - 1) + tab_index++; + if (column >= next_tab_column) + { + convert = 0; /* Ran out of tab stops. */ + goto flush_pend; + } + } + else + { + next_tab_column = column + tab_size - column % tab_size; + } + pending += next_tab_column - column; + column = next_tab_column; + } + else + { + flush_pend: + /* Flush pending spaces. Print as many tabs as possible, + then print the rest as spaces. */ + if (pending == 1) + { + putchar (' '); + pending = 0; + } + column -= pending; + while (pending > 0) + { + if (tab_size == 0) + { + /* Do not let print_tab_index == first_free_tab; + stop when it is 1 less. */ + while (print_tab_index < first_free_tab - 1 + && column >= tab_list[print_tab_index]) + print_tab_index++; + next_tab_column = tab_list[print_tab_index]; + if (print_tab_index < first_free_tab - 1) + print_tab_index++; + } + else + { + next_tab_column = column + tab_size - column % tab_size; + } + if (next_tab_column - column <= pending) + { + putchar ('\t'); + pending -= next_tab_column - column; + column = next_tab_column; + } + else + { + --print_tab_index; + column += pending; + while (pending != 0) + { + putchar (' '); + pending--; + } + } + } + + if (c == EOF) + { + fp = next_file (fp); + if (fp == NULL) + break; /* No more files. */ + else + { + SET_BINARY2 (fileno (fp), STDOUT_FILENO); + continue; + } + } + + if (convert) + { + if (c == '\b') + { + if (column > 0) + --column; + } + else + { + ++column; + if (convert_entire_line == 0) + convert = 0; + } + } + + putchar (c); + + if (c == '\n') + { + tab_index = print_tab_index = 0; + column = pending = 0; + convert = 1; + } + } + } +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + fputs (_("\ +Convert spaces in each FILE to tabs, writing to standard output.\n\ +With no FILE, or when FILE is -, read standard input.\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -a, --all convert all whitespace, instead of just initial whitespace\n\ + --first-only convert only leading sequences of whitespace (overrides -a)\n\ + -t, --tabs=N have tabs N characters apart instead of 8 (enables -a)\n\ + -t, --tabs=LIST use comma separated LIST of tab positions (enables -a)\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +int +main (int argc, char **argv) +{ + int tabval = -1; /* Value of tabstop being read, or -1. */ + int c; /* Option character. */ + + /* If nonzero, cancel the effect of any -a (explicit or implicit in -t), + so that only leading white space will be considered. */ + int convert_first_only = 0; + + bool obsolete_tablist = false; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + have_read_stdin = 0; + exit_status = 0; + convert_entire_line = 0; + tab_list = NULL; + first_free_tab = 0; + + while ((c = getopt_long (argc, argv, ",0123456789at:", longopts, NULL)) + != -1) + { + switch (c) + { + case 0: + break; + + case '?': + usage (EXIT_FAILURE); + case 'a': + convert_entire_line = 1; + break; + case 't': + convert_entire_line = 1; + parse_tabstops (optarg); + break; + case CONVERT_FIRST_ONLY_OPTION: + convert_first_only = 1; + break; + case ',': + add_tabstop (tabval); + tabval = -1; + obsolete_tablist = true; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + if (tabval == -1) + tabval = 0; + tabval = tabval * 10 + c - '0'; + obsolete_tablist = true; + break; + } + } + + if (obsolete_tablist && 200112 <= posix2_version ()) + { + error (0, 0, + _("`-LIST' option is obsolete; use `--first-only -t LIST'")); + usage (EXIT_FAILURE); + } + + if (convert_first_only) + convert_entire_line = 0; + + add_tabstop (tabval); + + validate_tabstops (tab_list, first_free_tab); + + if (first_free_tab == 0) + tab_size = 8; + else if (first_free_tab == 1) + tab_size = tab_list[0]; + else + { + /* Append a sentinel to the list of tab stop indices. */ + add_tabstop (TAB_STOP_SENTINEL); + tab_size = 0; + } + + if (optind == argc) + file_list = stdin_argv; + else + file_list = &argv[optind]; + + unexpand (); + + if (have_read_stdin && fclose (stdin) == EOF) + error (EXIT_FAILURE, errno, "-"); + exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/uniq.c b/src/apps/bin/coreutils-5.0/src/uniq.c new file mode 100644 index 0000000000..de556d7bd8 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/uniq.c @@ -0,0 +1,545 @@ +/* uniq -- remove duplicate lines from a sorted file + Copyright (C) 86, 91, 1995-2002, Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Richard Stallman and David MacKenzie. */ + +#include + +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "argmatch.h" +#include "linebuffer.h" +#include "error.h" +#include "hard-locale.h" +#include "posixver.h" +#include "xmemcoll.h" +#include "xstrtol.h" +#include "memcasecmp.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "uniq" + +#define AUTHORS N_ ("Richard Stallman and David MacKenzie") + +#define SWAP_LINES(A, B) \ + do \ + { \ + struct linebuffer *_tmp; \ + _tmp = (A); \ + (A) = (B); \ + (B) = _tmp; \ + } \ + while (0) + +/* The name this program was run with. */ +char *program_name; + +/* Nonzero if the LC_COLLATE locale is hard. */ +static int hard_LC_COLLATE; + +/* Number of fields to skip on each line when doing comparisons. */ +static size_t skip_fields; + +/* Number of chars to skip after skipping any fields. */ +static size_t skip_chars; + +/* Number of chars to compare. */ +static size_t check_chars; + +enum countmode +{ + count_occurrences, /* -c Print count before output lines. */ + count_none /* Default. Do not print counts. */ +}; + +/* Whether and how to precede the output lines with a count of the number of + times they occurred in the input. */ +static enum countmode countmode; + +enum output_mode +{ + output_repeated, /* -d Only lines that are repeated. */ + output_all_repeated, /* -D All lines that are repeated. */ + output_unique, /* -u Only lines that are not repeated. */ + output_all /* Default. Print first copy of each line. */ +}; + +/* Which lines to output. */ +static enum output_mode mode; + +/* If nonzero, ignore case when comparing. */ +static int ignore_case; + +enum delimit_method +{ + /* No delimiters output. --all-repeated[=none] */ + DM_NONE, + + /* Delimiter precedes all groups. --all-repeated=prepend */ + DM_PREPEND, + + /* Delimit all groups. --all-repeated=separate */ + DM_SEPARATE +}; + +static char const *const delimit_method_string[] = +{ + "none", "prepend", "separate", 0 +}; + +static enum delimit_method const delimit_method_map[] = +{ + DM_NONE, DM_PREPEND, DM_SEPARATE +}; + +/* Select whether/how to delimit groups of duplicate lines. */ +static enum delimit_method delimit_groups; + +static struct option const longopts[] = +{ + {"count", no_argument, NULL, 'c'}, + {"repeated", no_argument, NULL, 'd'}, + {"all-repeated", optional_argument, NULL, 'D'}, + {"ignore-case", no_argument, NULL, 'i'}, + {"unique", no_argument, NULL, 'u'}, + {"skip-fields", required_argument, NULL, 'f'}, + {"skip-chars", required_argument, NULL, 's'}, + {"check-chars", required_argument, NULL, 'w'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ +"), + program_name); + fputs (_("\ +Discard all but one of successive identical lines from INPUT (or\n\ +standard input), writing to OUTPUT (or standard output).\n\ +\n\ +"), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -c, --count prefix lines by the number of occurrences\n\ + -d, --repeated only print duplicate lines\n\ +"), stdout); + fputs (_("\ + -D, --all-repeated[=delimit-method] print all duplicate lines\n\ + delimit-method={none(default),prepend,separate}\n\ + Delimiting is done with blank lines.\n\ + -f, --skip-fields=N avoid comparing the first N fields\n\ + -i, --ignore-case ignore differences in case when comparing\n\ + -s, --skip-chars=N avoid comparing the first N characters\n\ + -u, --unique only print unique lines\n\ +"), stdout); + fputs (_("\ + -w, --check-chars=N compare no more than N characters in lines\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + fputs (_("\ +\n\ +A field is a run of whitespace, then non-whitespace characters.\n\ +Fields are skipped before chars.\n\ +"), stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* Convert OPT to size_t, reporting an error using MSGID if it does + not fit. */ + +static size_t +size_opt (char const *opt, char const *msgid) +{ + unsigned long int size; + if (xstrtoul (opt, NULL, 10, &size, "") != LONGINT_OK + || SIZE_MAX < size) + error (EXIT_FAILURE, 0, "%s: %s", opt, _(msgid)); + return size; +} + +/* Given a linebuffer LINE, + return a pointer to the beginning of the line's field to be compared. */ + +static char * +find_field (const struct linebuffer *line) +{ + register size_t count; + register char *lp = line->buffer; + register size_t size = line->length - 1; + register size_t i = 0; + + for (count = 0; count < skip_fields && i < size; count++) + { + while (i < size && ISBLANK (lp[i])) + i++; + while (i < size && !ISBLANK (lp[i])) + i++; + } + + for (count = 0; count < skip_chars && i < size; count++) + i++; + + return lp + i; +} + +/* Return zero if two strings OLD and NEW match, nonzero if not. + OLD and NEW point not to the beginnings of the lines + but rather to the beginnings of the fields to compare. + OLDLEN and NEWLEN are their lengths. */ + +static int +different (char *old, char *new, size_t oldlen, size_t newlen) +{ + if (check_chars < oldlen) + oldlen = check_chars; + if (check_chars < newlen) + newlen = check_chars; + + if (ignore_case) + { + /* FIXME: This should invoke strcoll somehow. */ + return oldlen != newlen || memcasecmp (old, new, oldlen); + } + else if (HAVE_SETLOCALE && hard_LC_COLLATE) + return xmemcoll (old, oldlen, new, newlen); + else + return oldlen != newlen || memcmp (old, new, oldlen); +} + +/* Output the line in linebuffer LINE to stream STREAM + provided that the switches say it should be output. + If requested, print the number of times it occurred, as well; + LINECOUNT + 1 is the number of times that the line occurred. */ + +static void +writeline (const struct linebuffer *line, FILE *stream, int linecount) +{ + if ((mode == output_unique && linecount != 0) + || (mode == output_repeated && linecount == 0) + || (mode == output_all_repeated && linecount == 0)) + return; + + if (countmode == count_occurrences) + fprintf (stream, "%7d\t", linecount + 1); + + fwrite (line->buffer, sizeof (char), line->length, stream); +} + +/* Process input file INFILE with output to OUTFILE. + If either is "-", use the standard I/O stream for it instead. */ + +static void +check_file (const char *infile, const char *outfile) +{ + FILE *istream; + FILE *ostream; + struct linebuffer lb1, lb2; + struct linebuffer *thisline, *prevline; + + if (STREQ (infile, "-")) + istream = stdin; + else + istream = fopen (infile, "r"); + if (istream == NULL) + error (EXIT_FAILURE, errno, "%s", infile); + + if (STREQ (outfile, "-")) + ostream = stdout; + else + ostream = fopen (outfile, "w"); + if (ostream == NULL) + error (EXIT_FAILURE, errno, "%s", outfile); + + thisline = &lb1; + prevline = &lb2; + + initbuffer (thisline); + initbuffer (prevline); + + /* The duplication in the following `if' and `else' blocks is an + optimization to distinguish the common case (in which none of + the following options has been specified: --count, -repeated, + --all-repeated, --unique) from the others. In the common case, + this optimization lets uniq output each different line right away, + without waiting to see if the next one is different. */ + + if (mode == output_all && countmode == count_none) + { + char *prevfield IF_LINT (= NULL); + size_t prevlen IF_LINT (= 0); + + while (!feof (istream)) + { + char *thisfield; + size_t thislen; + if (readline (thisline, istream) == 0) + break; + thisfield = find_field (thisline); + thislen = thisline->length - 1 - (thisfield - thisline->buffer); + if (prevline->length == 0 + || different (thisfield, prevfield, thislen, prevlen)) + { + fwrite (thisline->buffer, sizeof (char), + thisline->length, ostream); + + SWAP_LINES (prevline, thisline); + prevfield = thisfield; + prevlen = thislen; + } + } + } + else + { + char *prevfield; + size_t prevlen; + int match_count = 0; + int first_delimiter = 1; + + if (readline (prevline, istream) == 0) + goto closefiles; + prevfield = find_field (prevline); + prevlen = prevline->length - 1 - (prevfield - prevline->buffer); + + while (!feof (istream)) + { + int match; + char *thisfield; + size_t thislen; + if (readline (thisline, istream) == 0) + break; + thisfield = find_field (thisline); + thislen = thisline->length - 1 - (thisfield - thisline->buffer); + match = !different (thisfield, prevfield, thislen, prevlen); + + if (match) + ++match_count; + + if (mode == output_all_repeated && delimit_groups != DM_NONE) + { + if (!match) + { + if (match_count) /* a previous match */ + first_delimiter = 0; /* Only used when DM_SEPARATE */ + } + else if (match_count == 1) + { + if ((delimit_groups == DM_PREPEND) + || (delimit_groups == DM_SEPARATE + && !first_delimiter)) + putc ('\n', ostream); + } + } + + if (!match || mode == output_all_repeated) + { + writeline (prevline, ostream, match_count); + SWAP_LINES (prevline, thisline); + prevfield = thisfield; + prevlen = thislen; + if (!match) + match_count = 0; + } + } + + writeline (prevline, ostream, match_count); + } + + closefiles: + if (ferror (istream) || fclose (istream) == EOF) + error (EXIT_FAILURE, errno, _("error reading %s"), infile); + + /* Close ostream only if it's not stdout -- the latter is closed + via the atexit-invoked close_stdout. */ + if (ostream != stdout && (ferror (ostream) || fclose (ostream) == EOF)) + error (EXIT_FAILURE, errno, _("error writing %s"), outfile); + + free (lb1.buffer); + free (lb2.buffer); +} + +int +main (int argc, char **argv) +{ + int optc = 0; + bool posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL); + bool obsolete_skip_fields = false; + int nfiles = 0; + char const *file[2]; + + file[0] = file[1] = "-"; + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + hard_LC_COLLATE = hard_locale (LC_COLLATE); + + atexit (close_stdout); + + skip_chars = 0; + skip_fields = 0; + check_chars = SIZE_MAX; + mode = output_all; + countmode = count_none; + delimit_groups = DM_NONE; + + for (;;) + { + /* Parse an operand with leading "+" as a file after "--" was + seen; or if pedantic and a file was seen; or if not + obsolete. */ + + if (optc == -1 + || (posixly_correct && nfiles != 0) + || ((optc = getopt_long (argc, argv, + "-0123456789Dcdf:is:uw:", longopts, NULL)) + == -1)) + { + if (optind == argc) + break; + if (nfiles == 2) + { + error (0, 0, _("extra operand `%s'"), argv[optind]); + usage (EXIT_FAILURE); + } + file[nfiles++] = argv[optind++]; + } + else switch (optc) + { + case 1: + { + unsigned long int size; + if (optarg[0] == '+' + && posix2_version () < 200112 + && xstrtoul (optarg, NULL, 10, &size, "") == LONGINT_OK + && size <= SIZE_MAX) + skip_chars = size; + else if (nfiles == 2) + { + error (0, 0, _("extra operand `%s'"), optarg); + usage (EXIT_FAILURE); + } + else + file[nfiles++] = optarg; + } + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + size_t s = skip_fields; + skip_fields = s * 10 + optc - '0'; + if (SIZE_MAX / 10 < s || skip_fields < s) + error (EXIT_FAILURE, 0, "%s", + _("invalid number of fields to skip")); + obsolete_skip_fields = true; + } + break; + + case 'c': + countmode = count_occurrences; + break; + + case 'd': + mode = output_repeated; + break; + + case 'D': + mode = output_all_repeated; + if (optarg == NULL) + delimit_groups = DM_NONE; + else + delimit_groups = XARGMATCH ("--all-repeated", optarg, + delimit_method_string, + delimit_method_map); + break; + + case 'f': /* Like '-#'. */ + skip_fields = size_opt (optarg, + N_("invalid number of fields to skip")); + break; + + case 'i': + ignore_case = 1; + break; + + case 's': /* Like '+#'. */ + skip_chars = size_opt (optarg, + N_("invalid number of bytes to skip")); + break; + + case 'u': + mode = output_unique; + break; + + case 'w': + check_chars = size_opt (optarg, + N_("invalid number of bytes to compare")); + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (obsolete_skip_fields && 200112 <= posix2_version ()) + { + error (0, 0, _("`-%lu' option is obsolete; use `-f %lu'"), + (unsigned long) skip_fields, (unsigned long) skip_fields); + usage (EXIT_FAILURE); + } + + if (countmode == count_occurrences && mode == output_all_repeated) + { + error (0, 0, + _("printing all duplicated lines and repeat counts is meaningless")); + usage (EXIT_FAILURE); + } + + check_file (file[0], file[1]); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/unlink.c b/src/apps/bin/coreutils-5.0/src/unlink.c new file mode 100644 index 0000000000..7c83849518 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/unlink.c @@ -0,0 +1,102 @@ +/* unlink utility for GNU. + Copyright (C) 2001-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Michael Stone */ + +/* Implementation overview: + + Simply call the system 'unlink' function */ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "long-options.h" +#include "quote.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "unlink" + +#define AUTHORS "Michael Stone" + +/* Name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s FILE\n\ + or: %s OPTION\n"), program_name, program_name); + fputs (_("Call the unlink function to remove the specified FILE.\n\n"), + stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */ + if (getenv ("POSIXLY_CORRECT") == NULL) + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + /* The above handles --help and --version. + Since there is no other invocation of getopt, handle `--' here. */ + if (1 < argc && STREQ (argv[1], "--")) + { + --argc; + ++argv; + } + + if (argc < 2) + { + error (0, 0, _("too few arguments")); + usage (EXIT_FAILURE); + } + + if (2 < argc) + { + error (0, 0, _("too many arguments")); + usage (EXIT_FAILURE); + } + + if (unlink (argv[1]) != 0) + error (EXIT_FAILURE, errno, _("cannot unlink %s"), quote (argv[1])); + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/uptime.c b/src/apps/bin/coreutils-5.0/src/uptime.c new file mode 100644 index 0000000000..0aeb2db1d7 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/uptime.c @@ -0,0 +1,249 @@ +/* GNU's uptime. + Copyright (C) 1992-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Created by hacking who.c by Kaveh Ghazi ghazi@caip.rutgers.edu. */ + +#include +#include +#include + +#include +#include "system.h" + +#if HAVE_SYSCTL && HAVE_SYS_SYSCTL_H +# include +#endif + +#include "error.h" +#include "long-options.h" +#include "readutmp.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "uptime" + +#define AUTHORS N_ ("Joseph Arceneaux, David MacKenzie, and Kaveh Ghazi") + +int getloadavg (); + +/* The name this program was run with. */ +char *program_name; + +static struct option const longopts[] = +{ + {NULL, 0, NULL, 0} +}; + +static void +print_uptime (int n, const STRUCT_UTMP *this) +{ + register int entries = 0; + time_t boot_time = 0; + time_t time_now; + time_t uptime = 0; + int updays; + int uphours; + int upmins; + struct tm *tmn; + double avg[3]; + int loads; +#ifdef HAVE_PROC_UPTIME + FILE *fp; + double upsecs; + + fp = fopen ("/proc/uptime", "r"); + if (fp != NULL) + { + char buf[BUFSIZ]; + int res; + char *b = fgets (buf, BUFSIZ, fp); + if (b == buf) + { + /* The following sscanf must use the C locale. */ + setlocale (LC_NUMERIC, "C"); + res = sscanf (buf, "%lf", &upsecs); + setlocale (LC_NUMERIC, ""); + if (res == 1) + uptime = (time_t) upsecs; + } + + fclose (fp); + } +#endif /* HAVE_PROC_UPTIME */ + +#if HAVE_SYSCTL && defined CTL_KERN && defined KERN_BOOTTIME + { + /* FreeBSD specific: fetch sysctl "kern.boottime". */ + static int request[2] = { CTL_KERN, KERN_BOOTTIME }; + struct timeval result; + size_t result_len = sizeof result; + + if (sysctl (request, 2, &result, &result_len, NULL, 0) >= 0) + boot_time = result.tv_sec; + } +#endif + + /* Loop through all the utmp entries we just read and count up the valid + ones, also in the process possibly gleaning boottime. */ + while (n--) + { + if (UT_USER (this) [0] +#ifdef USER_PROCESS + && this->ut_type == USER_PROCESS +#endif + ) + { + ++entries; + } + /* If BOOT_MSG is defined, we can get boottime from utmp. This avoids + possibly needing special privs to read /dev/kmem. */ +#ifdef BOOT_MSG +# if HAVE_PROC_UPTIME + if (uptime == 0) +# endif /* HAVE_PROC_UPTIME */ + if (STREQ (this->ut_line, BOOT_MSG)) + boot_time = UT_TIME_MEMBER (this); +#endif /* BOOT_MSG */ + ++this; + } + time_now = time (0); +#if defined HAVE_PROC_UPTIME + if (uptime == 0) +#endif + { + if (boot_time == 0) + error (EXIT_FAILURE, errno, _("couldn't get boot time")); + uptime = time_now - boot_time; + } + updays = uptime / 86400; + uphours = (uptime - (updays * 86400)) / 3600; + upmins = (uptime - (updays * 86400) - (uphours * 3600)) / 60; + tmn = localtime (&time_now); + printf (_(" %2d:%02d%s up "), ((tmn->tm_hour % 12) == 0 + ? 12 : tmn->tm_hour % 12), + /* FIXME: use strftime, not am, pm. Uli reports that + the german translation is meaningless. */ + tmn->tm_min, (tmn->tm_hour < 12 ? _("am") : _("pm"))); + if (updays > 0) + printf (ngettext("%d day", "%d days", updays), updays); + printf (" %2d:%02d, ", uphours, upmins); + printf (ngettext ("%d user", "%d users", entries), entries); + +#if defined (HAVE_GETLOADAVG) || defined (C_GETLOADAVG) + loads = getloadavg (avg, 3); +#else + loads = -1; +#endif + + if (loads == -1) + putchar ('\n'); + else + { + if (loads > 0) + printf (_(", load average: %.2f"), avg[0]); + if (loads > 1) + printf (", %.2f", avg[1]); + if (loads > 2) + printf (", %.2f", avg[2]); + if (loads > 0) + putchar ('\n'); + } +} + +/* Display the system uptime and the number of users on the system, + according to utmp file FILENAME. */ + +static void +uptime (const char *filename) +{ + int n_users; + STRUCT_UTMP *utmp_buf; + int fail = read_utmp (filename, &n_users, &utmp_buf); + + if (fail) + error (EXIT_FAILURE, errno, "%s", filename); + + print_uptime (n_users, utmp_buf); +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [ FILE ]\n"), program_name); + printf (_("\ +Print the current time, the length of time the system has been up,\n\ +the number of users on the system, and the average number of jobs\n\ +in the run queue over the last 1, 5 and 15 minutes.\n\ +If FILE is not specified, use %s. %s as FILE is common.\n\ +\n\ +"), + UTMP_FILE, WTMP_FILE); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int optc, longind; + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + while ((optc = getopt_long (argc, argv, "", longopts, &longind)) != -1) + { + switch (optc) + { + case 0: + break; + + default: + usage (EXIT_FAILURE); + } + } + + switch (argc - optind) + { + case 0: /* uptime */ + uptime (UTMP_FILE); + break; + + case 1: /* uptime */ + uptime (argv[optind]); + break; + + default: /* lose */ + error (0, 0, _("too many arguments")); + usage (EXIT_FAILURE); + } + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/users.c b/src/apps/bin/coreutils-5.0/src/users.c new file mode 100644 index 0000000000..341c5c06d0 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/users.c @@ -0,0 +1,174 @@ +/* GNU's users. + Copyright (C) 1992-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by jla; revised by djm */ + +#include +#include +#include + +#include +#include "system.h" + +#include "error.h" +#include "long-options.h" +#include "readutmp.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "users" + +#define AUTHORS N_ ("Joseph Arceneaux and David MacKenzie") + +/* The name this program was run with. */ +char *program_name; + +static struct option const longopts[] = +{ + {NULL, 0, NULL, 0} +}; + +static int +userid_compare (const void *v_a, const void *v_b) +{ + char **a = (char **) v_a; + char **b = (char **) v_b; + return strcmp (*a, *b); +} + +static void +list_entries_users (int n, const STRUCT_UTMP *this) +{ + char **u; + int i; + int n_entries; + + n_entries = 0; + u = (char **) xmalloc (n * sizeof (u[0])); + for (i = 0; i < n; i++) + { + if (UT_USER (this) [0] +#ifdef USER_PROCESS + && this->ut_type == USER_PROCESS +#endif + ) + { + char *trimmed_name; + + trimmed_name = extract_trimmed_name (this); + + u[n_entries] = trimmed_name; + ++n_entries; + } + this++; + } + + qsort (u, n_entries, sizeof (u[0]), userid_compare); + + for (i = 0; i < n_entries; i++) + { + int c; + fputs (u[i], stdout); + c = (i < n_entries - 1 ? ' ' : '\n'); + putchar (c); + } + + for (i = 0; i < n_entries; i++) + free (u[i]); + free (u); +} + +/* Display a list of users on the system, according to utmp file FILENAME. */ + +static void +users (const char *filename) +{ + int n_users; + STRUCT_UTMP *utmp_buf; + int fail = read_utmp (filename, &n_users, &utmp_buf); + + if (fail) + error (EXIT_FAILURE, errno, "%s", filename); + + list_entries_users (n_users, utmp_buf); +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [ FILE ]\n"), program_name); + printf (_("\ +Output who is currently logged in according to FILE.\n\ +If FILE is not specified, use %s. %s as FILE is common.\n\ +\n\ +"), + UTMP_FILE, WTMP_FILE); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int optc, longind; + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + while ((optc = getopt_long (argc, argv, "", longopts, &longind)) != -1) + { + switch (optc) + { + case 0: + break; + + default: + usage (EXIT_FAILURE); + } + } + + switch (argc - optind) + { + case 0: /* users */ + users (UTMP_FILE); + break; + + case 1: /* users */ + users (argv[optind]); + break; + + default: /* lose */ + error (0, 0, _("too many arguments")); + usage (EXIT_FAILURE); + } + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/wc.c b/src/apps/bin/coreutils-5.0/src/wc.c new file mode 100644 index 0000000000..733d32d85e --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/wc.c @@ -0,0 +1,598 @@ +/* wc - print the number of bytes, words, and lines in files + Copyright (C) 85, 91, 1995-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Paul Rubin, phr@ocf.berkeley.edu + and David MacKenzie, djm@gnu.ai.mit.edu. */ + +#include + +#include +#include +#include + +/* Get mbstate_t, mbrtowc(), wcwidth(). */ +#if HAVE_WCHAR_H +# include +#endif + +/* Get iswprint(), iswspace(). */ +#if HAVE_WCTYPE_H +# include +#endif +#if !defined iswprint && !HAVE_ISWPRINT +# define iswprint(wc) 1 +#endif +#if !defined iswspace && !HAVE_ISWSPACE +# define iswspace(wc) \ + ((wc) == (unsigned char) (wc) && ISSPACE ((unsigned char) (wc))) +#endif + +/* Include this after wctype.h so that we `#undef' ISPRINT + (from Solaris's euc.h, from widec.h, from wctype.h) before + redefining and using it. */ +#include "system.h" + +#include "closeout.h" +#include "error.h" +#include "inttostr.h" +#include "safe-read.h" + +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ +#if HAVE_MBRTOWC && defined mbstate_t +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) +#endif + +#ifndef HAVE_DECL_WCWIDTH +"this configure-time declaration test was not run" +#endif +#if !HAVE_DECL_WCWIDTH +extern int wcwidth (); +#endif + +/* If wcwidth() doesn't exist, assume all printable characters have + width 1. */ +#if !defined wcwidth && !HAVE_WCWIDTH +# define wcwidth(wc) ((wc) == 0 ? 0 : iswprint (wc) ? 1 : -1) +#endif + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "wc" + +#define AUTHORS N_ ("Paul Rubin and David MacKenzie") + +/* Size of atomic reads. */ +#define BUFFER_SIZE (16 * 1024) + +/* The name this program was run with. */ +char *program_name; + +/* Cumulative number of lines, words, chars and bytes in all files so far. + max_line_length is the maximum over all files processed so far. */ +static uintmax_t total_lines; +static uintmax_t total_words; +static uintmax_t total_chars; +static uintmax_t total_bytes; +static uintmax_t max_line_length; + +/* Which counts to print. */ +static int print_lines, print_words, print_chars, print_bytes; +static int print_linelength; + +/* Nonzero if we have ever read the standard input. */ +static int have_read_stdin; + +/* The error code to return to the system. */ +static int exit_status; + +/* If nonzero, do not line up columns but instead separate numbers by + a single space as specified in Single Unix Specification and POSIX. */ +static int posixly_correct; + +static struct option const longopts[] = +{ + {"bytes", no_argument, NULL, 'c'}, + {"chars", no_argument, NULL, 'm'}, + {"lines", no_argument, NULL, 'l'}, + {"words", no_argument, NULL, 'w'}, + {"max-line-length", no_argument, NULL, 'L'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + fputs (_("\ +Print byte, word, and newline counts for each FILE, and a total line if\n\ +more than one FILE is specified. With no FILE, or when FILE is -,\n\ +read standard input.\n\ + -c, --bytes print the byte counts\n\ + -m, --chars print the character counts\n\ + -l, --lines print the newline counts\n\ +"), stdout); + fputs (_("\ + -L, --max-line-length print the length of the longest line\n\ + -w, --words print the word counts\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +static void +write_counts (uintmax_t lines, + uintmax_t words, + uintmax_t chars, + uintmax_t bytes, + uintmax_t linelength, + const char *file) +{ + char buf[INT_BUFSIZE_BOUND (uintmax_t)]; + char const *space = ""; + char const *format_int = (posixly_correct ? "%s" : "%7s"); + char const *format_sp_int = (posixly_correct ? "%s%s" : "%s%7s"); + + if (print_lines) + { + printf (format_int, umaxtostr (lines, buf)); + space = " "; + } + if (print_words) + { + printf (format_sp_int, space, umaxtostr (words, buf)); + space = " "; + } + if (print_chars) + { + printf (format_sp_int, space, umaxtostr (chars, buf)); + space = " "; + } + if (print_bytes) + { + printf (format_sp_int, space, umaxtostr (bytes, buf)); + space = " "; + } + if (print_linelength) + { + printf (format_sp_int, space, umaxtostr (linelength, buf)); + } + if (*file) + printf (" %s", file); + putchar ('\n'); +} + +static void +wc (int fd, const char *file) +{ + char buf[BUFFER_SIZE + 1]; + size_t bytes_read; + uintmax_t lines, words, chars, bytes, linelength; + int count_bytes, count_chars, count_complicated; + + lines = words = chars = bytes = linelength = 0; + + /* If in the current locale, chars are equivalent to bytes, we prefer + counting bytes, because that's easier. */ +#if HAVE_MBRTOWC && (MB_LEN_MAX > 1) + if (MB_CUR_MAX > 1) + { + count_bytes = print_bytes; + count_chars = print_chars; + } + else +#endif + { + count_bytes = print_bytes + print_chars; + count_chars = 0; + } + count_complicated = print_words + print_linelength; + + /* We need binary input, since `wc' relies on `lseek' and byte counts. */ + SET_BINARY (fd); + + /* When counting only bytes, save some line- and word-counting + overhead. If FD is a `regular' Unix file, using lseek is enough + to get its `size' in bytes. Otherwise, read blocks of BUFFER_SIZE + bytes at a time until EOF. Note that the `size' (number of bytes) + that wc reports is smaller than stats.st_size when the file is not + positioned at its beginning. That's why the lseek calls below are + necessary. For example the command + `(dd ibs=99k skip=1 count=0; ./wc -c) < /etc/group' + should make wc report `0' bytes. */ + + if (count_bytes && !count_chars && !print_lines && !count_complicated) + { + off_t current_pos, end_pos; + struct stat stats; + + if (fstat (fd, &stats) == 0 && S_ISREG (stats.st_mode) + && (current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1 + && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1) + { + off_t diff; + /* Be careful here. The current position may actually be + beyond the end of the file. As in the example above. */ + bytes = (diff = end_pos - current_pos) < 0 ? 0 : diff; + } + else + { + while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0) + { + if (bytes_read == SAFE_READ_ERROR) + { + error (0, errno, "%s", file); + exit_status = 1; + break; + } + bytes += bytes_read; + } + } + } + else if (!count_chars && !count_complicated) + { + /* Use a separate loop when counting only lines or lines and bytes -- + but not chars or words. */ + while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0) + { + register char *p = buf; + + if (bytes_read == SAFE_READ_ERROR) + { + error (0, errno, "%s", file); + exit_status = 1; + break; + } + + while ((p = memchr (p, '\n', (buf + bytes_read) - p))) + { + ++p; + ++lines; + } + bytes += bytes_read; + } + } +#if HAVE_MBRTOWC && (MB_LEN_MAX > 1) +# define SUPPORT_OLD_MBRTOWC 1 + else if (MB_CUR_MAX > 1) + { + int in_word = 0; + uintmax_t linepos = 0; + mbstate_t state; + uintmax_t last_error_line = 0; + int last_error_errno = 0; +# if SUPPORT_OLD_MBRTOWC + /* Back-up the state before each multibyte character conversion and + move the last incomplete character of the buffer to the front + of the buffer. This is needed because we don't know whether + the `mbrtowc' function updates the state when it returns -2, - + this is the ISO C 99 and glibc-2.2 behaviour - or not - amended + ANSI C, glibc-2.1 and Solaris 2.7 behaviour. We don't have an + autoconf test for this, yet. */ + size_t prev = 0; /* number of bytes carried over from previous round */ +# else + const size_t prev = 0; +# endif + + memset (&state, 0, sizeof (mbstate_t)); + while ((bytes_read = safe_read (fd, buf + prev, BUFFER_SIZE - prev)) > 0) + { + const char *p; +# if SUPPORT_OLD_MBRTOWC + mbstate_t backup_state; +# endif + if (bytes_read == SAFE_READ_ERROR) + { + error (0, errno, "%s", file); + exit_status = 1; + break; + } + + bytes += bytes_read; + p = buf; + bytes_read += prev; + do + { + wchar_t wide_char; + size_t n; + +# if SUPPORT_OLD_MBRTOWC + backup_state = state; +# endif + n = mbrtowc (&wide_char, p, bytes_read, &state); + if (n == (size_t) -2) + { +# if SUPPORT_OLD_MBRTOWC + state = backup_state; +# endif + break; + } + if (n == (size_t) -1) + { + /* Signal repeated errors only once per line. */ + if (!(lines + 1 == last_error_line + && errno == last_error_errno)) + { + char line_number_buf[INT_BUFSIZE_BOUND (uintmax_t)]; + last_error_line = lines + 1; + last_error_errno = errno; + error (0, errno, "%s:%s", file, + umaxtostr (last_error_line, line_number_buf)); + } + p++; + bytes_read--; + } + else + { + if (n == 0) + { + wide_char = 0; + n = 1; + } + p += n; + bytes_read -= n; + chars++; + switch (wide_char) + { + case '\n': + lines++; + /* Fall through. */ + case '\r': + case '\f': + if (linepos > linelength) + linelength = linepos; + linepos = 0; + goto mb_word_separator; + case '\t': + linepos += 8 - (linepos % 8); + goto mb_word_separator; + case ' ': + linepos++; + /* Fall through. */ + case '\v': + mb_word_separator: + if (in_word) + { + in_word = 0; + words++; + } + break; + default: + if (iswprint (wide_char)) + { + int width = wcwidth (wide_char); + if (width > 0) + linepos += width; + if (iswspace (wide_char)) + goto mb_word_separator; + in_word = 1; + } + break; + } + } + } + while (bytes_read > 0); + +# if SUPPORT_OLD_MBRTOWC + if (bytes_read > 0) + { + if (bytes_read == BUFFER_SIZE) + { + /* Encountered a very long redundant shift sequence. */ + p++; + bytes_read--; + } + memmove (buf, p, bytes_read); + } + prev = bytes_read; +# endif + } + if (linepos > linelength) + linelength = linepos; + if (in_word) + words++; + } +#endif + else + { + int in_word = 0; + uintmax_t linepos = 0; + + while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0) + { + const char *p = buf; + if (bytes_read == SAFE_READ_ERROR) + { + error (0, errno, "%s", file); + exit_status = 1; + break; + } + + bytes += bytes_read; + do + { + switch (*p++) + { + case '\n': + lines++; + /* Fall through. */ + case '\r': + case '\f': + if (linepos > linelength) + linelength = linepos; + linepos = 0; + goto word_separator; + case '\t': + linepos += 8 - (linepos % 8); + goto word_separator; + case ' ': + linepos++; + /* Fall through. */ + case '\v': + word_separator: + if (in_word) + { + in_word = 0; + words++; + } + break; + default: + if (ISPRINT ((unsigned char) p[-1])) + { + linepos++; + if (ISSPACE ((unsigned char) p[-1])) + goto word_separator; + in_word = 1; + } + break; + } + } + while (--bytes_read); + } + if (linepos > linelength) + linelength = linepos; + if (in_word) + words++; + } + + if (count_chars < print_chars) + chars = bytes; + + write_counts (lines, words, chars, bytes, linelength, file); + total_lines += lines; + total_words += words; + total_chars += chars; + total_bytes += bytes; + if (linelength > max_line_length) + max_line_length = linelength; +} + +static void +wc_file (const char *file) +{ + if (STREQ (file, "-")) + { + have_read_stdin = 1; + wc (0, file); + } + else + { + int fd = open (file, O_RDONLY); + if (fd == -1) + { + error (0, errno, "%s", file); + exit_status = 1; + return; + } + wc (fd, file); + if (close (fd)) + { + error (0, errno, "%s", file); + exit_status = 1; + } + } +} + +int +main (int argc, char **argv) +{ + int optc; + int nfiles; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + exit_status = 0; + posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL); + print_lines = print_words = print_chars = print_bytes = print_linelength = 0; + total_lines = total_words = total_chars = total_bytes = max_line_length = 0; + + while ((optc = getopt_long (argc, argv, "clLmw", longopts, NULL)) != -1) + switch (optc) + { + case 0: + break; + + case 'c': + print_bytes = 1; + break; + + case 'm': + print_chars = 1; + break; + + case 'l': + print_lines = 1; + break; + + case 'w': + print_words = 1; + break; + + case 'L': + print_linelength = 1; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + + if (print_lines + print_words + print_chars + print_bytes + print_linelength + == 0) + print_lines = print_words = print_bytes = 1; + + nfiles = argc - optind; + + if (nfiles == 0) + { + have_read_stdin = 1; + wc (0, ""); + } + else + { + for (; optind < argc; ++optind) + wc_file (argv[optind]); + + if (nfiles > 1) + write_counts (total_lines, total_words, total_chars, total_bytes, + max_line_length, _("total")); + } + + if (have_read_stdin && close (STDIN_FILENO) != 0) + error (EXIT_FAILURE, errno, "-"); + + exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/wheel-gen.pl b/src/apps/bin/coreutils-5.0/src/wheel-gen.pl new file mode 100755 index 0000000000..be03a6e3b0 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/wheel-gen.pl @@ -0,0 +1,97 @@ +#!/usr/bin/perl -w +# -*- perl -*- + +eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' + if 0; + +use strict; +(my $program_name = $0) =~ s|.*/||; + +sub END +{ + use POSIX qw (_exit); + # This is required if the code might send any output to stdout + # E.g., even --version or --help. So it's best to do it unconditionally. + close STDOUT + or (warn "$program_name: closing standard output: $!\n"), _exit (1); +} + +sub is_prime ($) +{ + my ($n) = @_; + use integer; + + $n == 2 + and return 1; + + my $d = 2; + my $w = 1; + while (1) + { + my $q = $n / $d; + $n == $q * $d + and return 0; + $d += $w; + $q < $d + and last; + $w = 2; + } + return 1; +} + +{ + @ARGV == 1 + or die "$program_name: missing argument\n"; + + my $wheel_size = $ARGV[0]; + + my @primes = (2); + my $product = $primes[0]; + my $n_primes = 1; + for (my $i = 3; ; $i += 2) + { + if (is_prime $i) + { + push @primes, $i; + $product *= $i; + ++$n_primes == $wheel_size + and last; + } + } + + my $ws_m1 = $wheel_size - 1; + print < +#include +#include + +#include +#include "system.h" + +#include "readutmp.h" +#include "error.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "who" + +#define AUTHORS N_ ("Joseph Arceneaux, David MacKenzie, and Michael Stone") + +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 64 +#endif + +#ifndef S_IWGRP +# define S_IWGRP 020 +#endif + +#ifndef USER_PROCESS +# define USER_PROCESS INT_MAX +#endif + +#ifndef RUN_LVL +# define RUN_LVL INT_MAX +#endif + +#ifndef INIT_PROCESS +# define INIT_PROCESS INT_MAX +#endif + +#ifndef LOGIN_PROCESS +# define LOGIN_PROCESS INT_MAX +#endif + +#ifndef DEAD_PROCESS +# define DEAD_PROCESS INT_MAX +#endif + +#ifndef BOOT_TIME +# define BOOT_TIME 0 +#endif + +#ifndef NEW_TIME +# define NEW_TIME 0 +#endif + +#define IDLESTR_LEN 6 + +#if HAVE_STRUCT_XTMP_UT_PID +# define UT_PID(U) ((U)->ut_pid) +# define PIDSTR_DECL_AND_INIT(Var, Utmp_ent) \ + char Var[INT_STRLEN_BOUND (Utmp_ent->ut_pid) + 1]; \ + sprintf (Var, "%d", (int) (Utmp_ent->ut_pid)) +#else +# define UT_PID(U) 0 +# define PIDSTR_DECL_AND_INIT(Var, Utmp_ent) \ + const char *Var = "" +#endif + +#if HAVE_STRUCT_XTMP_UT_ID +# define UT_ID(U) ((U)->ut_id) +#else + /* Of course, sizeof "whatever" is the size of a pointer (often 4), + but that's ok, since the actual string has a length of only 2. */ +# define UT_ID(U) "??" +#endif + +#define UT_TYPE_UNDEF 255 + +#if HAVE_STRUCT_XTMP_UT_TYPE +# define UT_TYPE(U) ((U)->ut_type) +#else +# define UT_TYPE(U) UT_TYPE_UNDEF +#endif + +#define IS_USER_PROCESS(U) \ + (UT_USER (utmp_buf)[0] \ + && (UT_TYPE (utmp_buf) == USER_PROCESS \ + || (UT_TYPE (utmp_buf) == UT_TYPE_UNDEF \ + && UT_TIME_MEMBER (utmp_buf) != 0))) + +int gethostname (); +char *ttyname (); +char *canon_host (); + +/* The name this program was run with. */ +char *program_name; + +/* If nonzero, attempt to canonicalize hostnames via a DNS lookup. */ +static int do_lookup; + +/* If nonzero, display only a list of usernames and count of + the users logged on. + Ignored for `who am i'. */ +static int short_list; + +/* If nonzero, display only name, line, and time fields */ +static int short_output; + +/* If nonzero, display the hours:minutes since each user has touched + the keyboard, or "." if within the last minute, or "old" if + not within the last day. */ +static int include_idle; + +/* If nonzero, display a line at the top describing each field. */ +static int include_heading; + +/* If nonzero, display a `+' for each user if mesg y, a `-' if mesg n, + or a `?' if their tty cannot be statted. */ +static int include_mesg; + +/* If nonzero, display process termination & exit status */ +static int include_exit; + +/* If nonzero, display the last boot time */ +static int need_boottime; + +/* If nonzero, display dead processes */ +static int need_deadprocs; + +/* If nonzero, display processes waiting for user login */ +static int need_login; + +/* If nonzero, display processes started by init */ +static int need_initspawn; + +/* If nonzero, display the last clock change */ +static int need_clockchange; + +/* If nonzero, display the current runlevel */ +static int need_runlevel; + +/* If nonzero, display user processes */ +static int need_users; + +/* If nonzero, display info only for the controlling tty */ +static int my_line_only; + +/* for long options with no corresponding short option, use enum */ +enum +{ + LOOKUP_OPTION = CHAR_MAX + 1, + LOGIN_OPTION +}; + +static struct option const longopts[] = { + {"all", no_argument, NULL, 'a'}, + {"boot", no_argument, NULL, 'b'}, + {"count", no_argument, NULL, 'q'}, + {"dead", no_argument, NULL, 'd'}, + {"heading", no_argument, NULL, 'H'}, + {"idle", no_argument, NULL, 'i'}, + {"login", no_argument, NULL, LOGIN_OPTION}, + {"lookup", no_argument, NULL, LOOKUP_OPTION}, + {"message", no_argument, NULL, 'T'}, + {"mesg", no_argument, NULL, 'T'}, + {"process", no_argument, NULL, 'p'}, + {"runlevel", no_argument, NULL, 'r'}, + {"short", no_argument, NULL, 's'}, + {"time", no_argument, NULL, 't'}, + {"users", no_argument, NULL, 'u'}, + {"writable", no_argument, NULL, 'T'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +/* Return a string representing the time between WHEN and the time + that this function is first run. + FIXME: locale? */ +static const char * +idle_string (time_t when) +{ + static time_t now = 0; + static char idle_hhmm[IDLESTR_LEN]; + time_t seconds_idle; + + if (now == 0) + time (&now); + + seconds_idle = now - when; + if (seconds_idle < 60) /* One minute. */ + return " . "; + if (seconds_idle < (24 * 60 * 60)) /* One day. */ + { + sprintf (idle_hhmm, "%02d:%02d", + (int) (seconds_idle / (60 * 60)), + (int) ((seconds_idle % (60 * 60)) / 60)); + return (const char *) idle_hhmm; + } + return _(" old "); +} + +/* Return a standard time string, "mon dd hh:mm" + FIXME: handle localization */ +static const char * +time_string (const STRUCT_UTMP *utmp_ent) +{ + /* Don't take the address of UT_TIME_MEMBER directly. + Ulrich Drepper wrote: + ``... GNU libc (and perhaps other libcs as well) have extended + utmp file formats which do not use a simple time_t ut_time field. + In glibc, ut_time is a macro which selects for backward compatibility + the tv_sec member of a struct timeval value.'' */ + time_t tm = UT_TIME_MEMBER (utmp_ent); + + char *ptr = ctime (&tm) + 4; + ptr[12] = '\0'; + return ptr; +} + +/* Print formatted output line. Uses mostly arbitrary field sizes, probably + will need tweaking if any of the localization stuff is done, or for 64 bit + pids, etc. */ +static void +print_line (const char *user, const char state, const char *line, + const char *time_str, const char *idle, const char *pid, + const char *comment, const char *exitstr) +{ + printf ("%-8.8s", user ? user : " ."); + if (include_mesg) + printf (" %c", state); + printf (" %-12s", line); + printf (" %-12s", time_str); + if (include_idle && !short_output) + printf (" %-6s", idle); + if (!short_output) + printf (" %10s", pid); + /* FIXME: it's not really clear whether the following should be in short_output. + a strict reading of SUSv2 would suggest not, but I haven't seen any + implementations that actually work that way... */ + printf (" %-8s", comment); + if (include_exit && exitstr && *exitstr) + printf (" %-12s", exitstr); + putchar ('\n'); +} + +/* Send properly parsed USER_PROCESS info to print_line */ +static void +print_user (const STRUCT_UTMP *utmp_ent) +{ + struct stat stats; + time_t last_change; + char mesg; + char idlestr[IDLESTR_LEN]; + static char *hoststr; + static size_t hostlen; + +#define DEV_DIR_WITH_TRAILING_SLASH "/dev/" +#define DEV_DIR_LEN (sizeof (DEV_DIR_WITH_TRAILING_SLASH) - 1) + + char line[sizeof (utmp_ent->ut_line) + DEV_DIR_LEN + 1]; + PIDSTR_DECL_AND_INIT (pidstr, utmp_ent); + + /* Copy ut_line into LINE, prepending `/dev/' if ut_line is not + already an absolute pathname. Some system may put the full, + absolute pathname in ut_line. */ + if (utmp_ent->ut_line[0] == '/') + { + strncpy (line, utmp_ent->ut_line, sizeof (utmp_ent->ut_line)); + line[sizeof (utmp_ent->ut_line)] = '\0'; + } + else + { + strcpy (line, DEV_DIR_WITH_TRAILING_SLASH); + strncpy (line + DEV_DIR_LEN, utmp_ent->ut_line, + sizeof (utmp_ent->ut_line)); + line[DEV_DIR_LEN + sizeof (utmp_ent->ut_line)] = '\0'; + } + + if (stat (line, &stats) == 0) + { + mesg = (stats.st_mode & S_IWGRP) ? '+' : '-'; + last_change = stats.st_atime; + } + else + { + mesg = '?'; + last_change = 0; + } + + if (last_change) + sprintf (idlestr, "%.6s", idle_string (last_change)); + else + sprintf (idlestr, " ?"); + +#if HAVE_UT_HOST + if (utmp_ent->ut_host[0]) + { + char ut_host[sizeof (utmp_ent->ut_host) + 1]; + char *host = 0, *display = 0; + + /* Copy the host name into UT_HOST, and ensure it's nul terminated. */ + strncpy (ut_host, utmp_ent->ut_host, (int) sizeof (utmp_ent->ut_host)); + ut_host[sizeof (utmp_ent->ut_host)] = '\0'; + + /* Look for an X display. */ + display = strrchr (ut_host, ':'); + if (display) + *display++ = '\0'; + + if (*ut_host && do_lookup) + { + /* See if we can canonicalize it. */ + host = canon_host (ut_host); + } + + if (! host) + host = ut_host; + + if (display) + { + if (hostlen < strlen (host) + strlen (display) + 4) + { + hostlen = strlen (host) + strlen (display) + 4; + hoststr = (char *) realloc (hoststr, hostlen); + } + sprintf (hoststr, "(%s:%s)", host, display); + } + else + { + if (hostlen < strlen (host) + 3) + { + hostlen = strlen (host) + 3; + hoststr = (char *) realloc (hoststr, hostlen); + } + sprintf (hoststr, "(%s)", host); + } + } + else + { + if (hostlen < 1) + { + hostlen = 1; + hoststr = (char *) realloc (hoststr, hostlen); + } + stpcpy (hoststr, ""); + } +#endif + + print_line (UT_USER (utmp_ent), mesg, utmp_ent->ut_line, + time_string (utmp_ent), idlestr, pidstr, + hoststr ? hoststr : "", ""); +} + +static void +print_boottime (const STRUCT_UTMP *utmp_ent) +{ + print_line ("", ' ', "system boot", time_string (utmp_ent), "", "", "", ""); +} + +static char * +make_id_equals_comment (STRUCT_UTMP const *utmp_ent) +{ + char *comment = xmalloc (strlen (_("id=")) + sizeof UT_ID (utmp_ent) + 1); + + /* Cast field width argument to `int' to avoid warning from gcc. */ + sprintf (comment, "%s%.*s", _("id="), (int) sizeof UT_ID (utmp_ent), + UT_ID (utmp_ent)); + return comment; +} + +static void +print_deadprocs (const STRUCT_UTMP *utmp_ent) +{ + static char *exitstr; + char *comment = make_id_equals_comment (utmp_ent); + PIDSTR_DECL_AND_INIT (pidstr, utmp_ent); + + if (!exitstr) + exitstr = xmalloc (strlen (_("term=")) + + INT_STRLEN_BOUND (UT_EXIT_E_TERMINATION (utmp_ent)) + 1 + + strlen (_("exit=")) + + INT_STRLEN_BOUND (UT_EXIT_E_EXIT (utmp_ent)) + + 1); + sprintf (exitstr, "%s%d %s%d", _("term="), UT_EXIT_E_TERMINATION (utmp_ent), + _("exit="), UT_EXIT_E_EXIT (utmp_ent)); + + /* FIXME: add idle time? */ + + print_line ("", ' ', utmp_ent->ut_line, + time_string (utmp_ent), "", pidstr, comment, exitstr); + free (comment); +} + +static void +print_login (const STRUCT_UTMP *utmp_ent) +{ + char *comment = make_id_equals_comment (utmp_ent); + PIDSTR_DECL_AND_INIT (pidstr, utmp_ent); + + /* FIXME: add idle time? */ + + print_line ("LOGIN", ' ', utmp_ent->ut_line, + time_string (utmp_ent), "", pidstr, comment, ""); + free (comment); +} + +static void +print_initspawn (const STRUCT_UTMP *utmp_ent) +{ + char *comment = make_id_equals_comment (utmp_ent); + PIDSTR_DECL_AND_INIT (pidstr, utmp_ent); + + print_line ("", ' ', utmp_ent->ut_line, + time_string (utmp_ent), "", pidstr, comment, ""); + free (comment); +} + +static void +print_clockchange (const STRUCT_UTMP *utmp_ent) +{ + /* FIXME: handle NEW_TIME & OLD_TIME both */ + print_line ("", ' ', _("clock change"), + time_string (utmp_ent), "", "", "", ""); +} + +static void +print_runlevel (const STRUCT_UTMP *utmp_ent) +{ + static char *runlevline, *comment; + int last = UT_PID (utmp_ent) / 256; + int curr = UT_PID (utmp_ent) % 256; + + if (!runlevline) + runlevline = xmalloc (strlen (_("run-level")) + 3); + sprintf (runlevline, "%s %c", _("run-level"), curr); + + if (!comment) + comment = xmalloc (strlen (_("last=")) + 2); + sprintf (comment, "%s%c", _("last="), (last == 'N') ? 'S' : last); + + print_line ("", ' ', runlevline, time_string (utmp_ent), + "", "", comment, ""); + + return; +} + +/* Print the username of each valid entry and the number of valid entries + in UTMP_BUF, which should have N elements. */ +static void +list_entries_who (int n, const STRUCT_UTMP *utmp_buf) +{ + int entries = 0; + + while (n--) + { + if (UT_USER (utmp_buf)[0] && UT_TYPE (utmp_buf) == USER_PROCESS) + { + char *trimmed_name; + + trimmed_name = extract_trimmed_name (utmp_buf); + + printf ("%s ", trimmed_name); + free (trimmed_name); + entries++; + } + utmp_buf++; + } + printf (_("\n# users=%u\n"), entries); +} + +static void +print_heading (void) +{ + print_line (_("NAME"), ' ', _("LINE"), _("TIME"), _("IDLE"), _("PID"), + _("COMMENT"), _("EXIT")); +} + +/* Display UTMP_BUF, which should have N entries. */ +static void +scan_entries (int n, const STRUCT_UTMP *utmp_buf) +{ + char *ttyname_b IF_LINT ( = NULL); + + if (include_heading) + print_heading (); + + if (my_line_only) + { + ttyname_b = ttyname (0); + if (!ttyname_b) + return; + if (strncmp (ttyname_b, DEV_DIR_WITH_TRAILING_SLASH, DEV_DIR_LEN) == 0) + ttyname_b += DEV_DIR_LEN; /* Discard /dev/ prefix. */ + } + + while (n--) + { + if (!my_line_only || + strncmp (ttyname_b, utmp_buf->ut_line, + sizeof (utmp_buf->ut_line)) == 0) + { + if (need_users && IS_USER_PROCESS (utmp_buf)) + print_user (utmp_buf); + else if (need_runlevel && UT_TYPE (utmp_buf) == RUN_LVL) + print_runlevel (utmp_buf); + else if (need_boottime && UT_TYPE (utmp_buf) == BOOT_TIME) + print_boottime (utmp_buf); + /* I've never seen one of these, so I don't know what it should + look like :^) + FIXME: handle OLD_TIME also, perhaps show the delta? */ + else if (need_clockchange && UT_TYPE (utmp_buf) == NEW_TIME) + print_clockchange (utmp_buf); + else if (need_initspawn && UT_TYPE (utmp_buf) == INIT_PROCESS) + print_initspawn (utmp_buf); + else if (need_login && UT_TYPE (utmp_buf) == LOGIN_PROCESS) + print_login (utmp_buf); + else if (need_deadprocs && UT_TYPE (utmp_buf) == DEAD_PROCESS) + print_deadprocs (utmp_buf); + } + + utmp_buf++; + } +} + +/* Display a list of who is on the system, according to utmp file filename. */ +static void +who (const char *filename) +{ + int n_users; + STRUCT_UTMP *utmp_buf; + int fail = read_utmp (filename, &n_users, &utmp_buf); + + if (fail) + error (EXIT_FAILURE, errno, "%s", filename); + + if (short_list) + list_entries_who (n_users, utmp_buf); + else + scan_entries (n_users, utmp_buf); +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [ FILE | ARG1 ARG2 ]\n"), program_name); + fputs (_("\ +\n\ + -a, --all same as -b -d --login -p -r -t -T -u\n\ + -b, --boot time of last system boot\n\ + -d, --dead print dead processes\n\ + -H, --heading print line of column headings\n\ +"), stdout); + fputs (_("\ + -i, --idle add idle time as HOURS:MINUTES, . or old\n\ + (deprecated, use -u)\n\ + --login print system login processes\n\ + (equivalent to SUS -l)\n\ +"), stdout); + fputs (_("\ + -l, --lookup attempt to canonicalize hostnames via DNS\n\ + (-l is deprecated, use --lookup)\n\ + -m only hostname and user associated with stdin\n\ + -p, --process print active processes spawned by init\n\ +"), stdout); + fputs (_("\ + -q, --count all login names and number of users logged on\n\ + -r, --runlevel print current runlevel\n\ + -s, --short print only name, line, and time (default)\n\ + -t, --time print last system clock change\n\ +"), stdout); + fputs (_("\ + -T, -w, --mesg add user's message status as +, - or ?\n\ + -u, --users list users logged in\n\ + --message same as -T\n\ + --writable same as -T\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\ +\n\ +If FILE is not specified, use %s. %s as FILE is common.\n\ +If ARG1 ARG2 given, -m presumed: `am i' or `mom likes' are usual.\n\ +"), UTMP_FILE, WTMP_FILE); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int optc, longind; + int assumptions = 1; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + while ((optc = getopt_long (argc, argv, "abdilmpqrstuwHT", longopts, + &longind)) != -1) + { + switch (optc) + { + case 0: + break; + + case 'a': + need_boottime = 1; + need_deadprocs = 1; + need_login = 1; + need_initspawn = 1; + need_runlevel = 1; + need_clockchange = 1; + need_users = 1; + include_mesg = 1; + include_idle = 1; + include_exit = 1; + assumptions = 0; + break; + + case 'b': + need_boottime = 1; + assumptions = 0; + break; + + case 'd': + need_deadprocs = 1; + include_idle = 1; + include_exit = 1; + assumptions = 0; + break; + + case 'H': + include_heading = 1; + break; + + /* FIXME: This should be -l in a future version */ + case LOGIN_OPTION: + need_login = 1; + include_idle = 1; + assumptions = 0; + break; + + case 'm': + my_line_only = 1; + break; + + case 'p': + need_initspawn = 1; + assumptions = 0; + break; + + case 'q': + short_list = 1; + break; + + case 'r': + need_runlevel = 1; + include_idle = 1; + assumptions = 0; + break; + + case 's': + short_output = 1; + break; + + case 't': + need_clockchange = 1; + assumptions = 0; + break; + + case 'T': + case 'w': + include_mesg = 1; + break; + + case 'i': + error (0, 0, + _("Warning: -i will be removed in a future release; \ + use -u instead")); + /* Fall through. */ + case 'u': + need_users = 1; + include_idle = 1; + assumptions = 0; + break; + + case 'l': + error (0, 0, + _("Warning: the meaning of '-l' will change in a future\ + release to conform to POSIX")); + case LOOKUP_OPTION: + do_lookup = 1; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + if (assumptions) + { + need_users = 1; + short_output = 1; + } + + if (include_exit) + { + short_output = 0; + } + + switch (argc - optind) + { + case 0: /* who */ + who (UTMP_FILE); + break; + + case 1: /* who */ + who (argv[optind]); + break; + + case 2: /* who */ + my_line_only = 1; + who (UTMP_FILE); + break; + + default: /* lose */ + error (0, 0, _("too many arguments")); + usage (EXIT_FAILURE); + } + + exit (EXIT_SUCCESS); +} diff --git a/src/apps/bin/coreutils-5.0/src/whoami.c b/src/apps/bin/coreutils-5.0/src/whoami.c new file mode 100644 index 0000000000..583ed02c28 --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/whoami.c @@ -0,0 +1,107 @@ +/* whoami -- print effective userid + Copyright (C) 89,90, 1991-1997, 1999-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Equivalent to `id -un'. */ +/* Written by Richard Mlynarik. */ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "long-options.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "whoami" + +#define AUTHORS "Richard Mlynarik" + +/* The name this program was run with. */ +char *program_name; + +static struct option const long_options[] = +{ + {0, 0, 0, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]...\n"), program_name); + fputs (_("\ +Print the user name associated with the current effective user id.\n\ +Same as id -un.\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + register struct passwd *pw; + register uid_t uid; + int c; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + default: + usage (EXIT_FAILURE); + } + } + + if (optind != argc) + usage (EXIT_FAILURE); + + uid = geteuid (); + pw = getpwuid (uid); + if (pw) + { + puts (pw->pw_name); + exit (EXIT_SUCCESS); + } + fprintf (stderr, _("%s: cannot find username for UID %u\n"), + program_name, (unsigned) uid); + exit (EXIT_FAILURE); +} diff --git a/src/apps/bin/coreutils-5.0/src/yes.c b/src/apps/bin/coreutils-5.0/src/yes.c new file mode 100644 index 0000000000..09d6ee9d1e --- /dev/null +++ b/src/apps/bin/coreutils-5.0/src/yes.c @@ -0,0 +1,113 @@ +/* yes - output a string repeatedly until killed + Copyright (C) 1991-1997, 1999-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* David MacKenzie */ + +#include +#include +#include +#include + +#include "error.h" +#include "system.h" +#include "long-options.h" +#include "closeout.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "yes" + +#define AUTHORS "David MacKenzie" + +/* How many iterations between ferror checks. */ +#define UNROLL 10000 + +/* The name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [STRING]...\n\ + or: %s OPTION\n\ +"), + program_name, program_name); + + fputs (_("\ +Repeatedly output a line with all specified STRING(s), or `y'.\n\ +\n\ +"), stdout); + fputs (HELP_OPTION_DESCRIPTION, stdout); + fputs (VERSION_OPTION_DESCRIPTION, stdout); + printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */ + if (getenv ("POSIXLY_CORRECT") == NULL) + parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION, + AUTHORS, usage); + + if (argc == 1) + { + while (1) + { + int i; + for (i = 0; i < UNROLL; i++) + puts ("y"); + if (ferror (stdout)) + break; + } + } + else + { + while (1) + { + int i; + for (i = 0; i < UNROLL; i++) + { + int j; + for (j = 1; j < argc; j++) + { + fputs (argv[j], stdout); + putchar (j == argc - 1 ? '\n' : ' '); + } + } + if (ferror (stdout)) + break; + } + } + + error (0, errno, "standard output"); + exit (EXIT_FAILURE); +}