mirror of
https://git.savannah.gnu.org/git/coreutils.git
synced 2025-09-10 07:59:52 +02:00
Compare commits
166 Commits
FILEUTILS-
...
FILEUTILS-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4176dd559 | ||
|
|
47d5042d1e | ||
|
|
6df632b672 | ||
|
|
6875b205d6 | ||
|
|
47306242ec | ||
|
|
83780d95f0 | ||
|
|
5b804afa6a | ||
|
|
83b9d5e9ef | ||
|
|
a2b0b9846d | ||
|
|
a0ad16498b | ||
|
|
aa084c8407 | ||
|
|
ac821ab1ef | ||
|
|
6e146d4216 | ||
|
|
e4a96fff58 | ||
|
|
aa6cde5ca1 | ||
|
|
05a5e42609 | ||
|
|
11a013bf87 | ||
|
|
de4de17bc5 | ||
|
|
b0302bb3a6 | ||
|
|
334f8dcbb7 | ||
|
|
47eaf4a1e8 | ||
|
|
1e30b2f8c4 | ||
|
|
84df8be864 | ||
|
|
f05befc26c | ||
|
|
96e22ecc78 | ||
|
|
9eb195d6a5 | ||
|
|
40f0f4d2e8 | ||
|
|
4fa07774d6 | ||
|
|
7567c84e76 | ||
|
|
a87c771012 | ||
|
|
a2535fc95f | ||
|
|
d2aaf842b4 | ||
|
|
13e93efe91 | ||
|
|
af1033c63c | ||
|
|
768f92072f | ||
|
|
8b92864e1d | ||
|
|
d97d668b69 | ||
|
|
5d1c0a2af5 | ||
|
|
b1c9ce6621 | ||
|
|
aec547d764 | ||
|
|
185c59d3bd | ||
|
|
f1c5cfd5f2 | ||
|
|
c848009e29 | ||
|
|
a0d766c204 | ||
|
|
c1f248d670 | ||
|
|
9b1d63b4a3 | ||
|
|
c7262bbe86 | ||
|
|
008028896b | ||
|
|
c5716550a6 | ||
|
|
b43f5fb25b | ||
|
|
013277d331 | ||
|
|
09eedba01f | ||
|
|
ca59b76b50 | ||
|
|
b9485b8d52 | ||
|
|
66b9285a6f | ||
|
|
470e773e76 | ||
|
|
039942bfc1 | ||
|
|
a94e341d85 | ||
|
|
db98ca11cf | ||
|
|
22a5274de9 | ||
|
|
2ee6cf8ea0 | ||
|
|
baf81e4974 | ||
|
|
bda4a5e5b7 | ||
|
|
0598102472 | ||
|
|
4aba8a55f2 | ||
|
|
6f6a35a9a1 | ||
|
|
d691ea7ebc | ||
|
|
ca63ca90ab | ||
|
|
43dd57eba9 | ||
|
|
6dd358e12d | ||
|
|
c73aa6b629 | ||
|
|
63b348b3a9 | ||
|
|
6181f175e3 | ||
|
|
5a52e61271 | ||
|
|
e74c290ac7 | ||
|
|
5ea57c875d | ||
|
|
492b177ca5 | ||
|
|
daa976fff6 | ||
|
|
871d176f15 | ||
|
|
fc2e23b1ad | ||
|
|
1cde2ceb5c | ||
|
|
539457f1ae | ||
|
|
b6ff24fb7f | ||
|
|
da20dc044a | ||
|
|
a42c7fe2d1 | ||
|
|
b792f7aa0e | ||
|
|
9242af95a3 | ||
|
|
9583179c1b | ||
|
|
d9dee002e6 | ||
|
|
434b809272 | ||
|
|
4feb3b1e06 | ||
|
|
14390d1fed | ||
|
|
8831ffbec4 | ||
|
|
45d4def5e4 | ||
|
|
b9c1393e5f | ||
|
|
c5bf4b6c9c | ||
|
|
3ac64eda17 | ||
|
|
148f37c34e | ||
|
|
9845d179b3 | ||
|
|
11b87d29cc | ||
|
|
bc7210e563 | ||
|
|
e1ab53f969 | ||
|
|
790196a645 | ||
|
|
b5c8c81d4d | ||
|
|
91a709b210 | ||
|
|
5e25ee19e4 | ||
|
|
70390f60ec | ||
|
|
c22889019c | ||
|
|
06ea91f2f3 | ||
|
|
3c7699600f | ||
|
|
c8c90bb532 | ||
|
|
6f63d53e1b | ||
|
|
cd1dbbcfc1 | ||
|
|
4bbadbb14a | ||
|
|
cc61df7131 | ||
|
|
965c0bf39d | ||
|
|
6fc3c211ec | ||
|
|
c25dcdd843 | ||
|
|
e387fd1471 | ||
|
|
1c7bc6028a | ||
|
|
74f061de82 | ||
|
|
47b91b8948 | ||
|
|
2d73c959cc | ||
|
|
9a17340b10 | ||
|
|
a9de4d485a | ||
|
|
111cb717e8 | ||
|
|
6a45f61547 | ||
|
|
026d10d369 | ||
|
|
d832bf77eb | ||
|
|
de97a7099c | ||
|
|
1d15980fb6 | ||
|
|
b3303ba072 | ||
|
|
eddb25aa26 | ||
|
|
40c6966137 | ||
|
|
4de6eab547 | ||
|
|
caa2df2274 | ||
|
|
4c8c0b69ba | ||
|
|
527d04d44b | ||
|
|
9a12d05216 | ||
|
|
77c46a6b42 | ||
|
|
744393f0f4 | ||
|
|
6f200d7982 | ||
|
|
12e85d31e2 | ||
|
|
17821cc15e | ||
|
|
0bcd6e68a9 | ||
|
|
528390fa58 | ||
|
|
a719a87508 | ||
|
|
a1fa4eff25 | ||
|
|
f344b7fab6 | ||
|
|
eca98f76ac | ||
|
|
f30618bac7 | ||
|
|
dc4a18b537 | ||
|
|
9801e9cde1 | ||
|
|
1b16c152bd | ||
|
|
3ed71a2fdd | ||
|
|
0e15d57a89 | ||
|
|
c253d247ca | ||
|
|
656fac3d80 | ||
|
|
dde2c138e9 | ||
|
|
7823351d6b | ||
|
|
b23b6bbcf7 | ||
|
|
800e219a2d | ||
|
|
ecf0d31b72 | ||
|
|
c3f476d467 | ||
|
|
7f3e86b27b | ||
|
|
b0453a43c0 |
@@ -12,8 +12,8 @@
|
||||
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
@@ -73,6 +73,7 @@ texclean:
|
||||
*.fl *.cm *.op *.cps
|
||||
|
||||
mostlyclean: texclean
|
||||
rm -f *.info
|
||||
|
||||
clean: mostlyclean
|
||||
|
||||
|
||||
@@ -2320,6 +2320,15 @@ current time and date. @var{datestr} can be in almost any common
|
||||
format. It can contain month names, timezones, @samp{am} and @samp{pm},
|
||||
@samp{yesterday}, @samp{ago}, @samp{next}, etc. @xref{Date input formats}.
|
||||
|
||||
@item -r @var{file}
|
||||
@itemx --reference=@var{file}
|
||||
@opindex -r
|
||||
@opindex --reference
|
||||
Display the time and date as obtained from a reference @var{file},
|
||||
instead of the current time and date. Each file has a few timestamps
|
||||
associated with it. In this context, the time and date of the last
|
||||
modification are used.
|
||||
|
||||
@item -f @var{datefile}
|
||||
@itemx --file=@var{datefile}
|
||||
@opindex -f
|
||||
|
||||
@@ -1054,7 +1054,7 @@ head [@var{option}]@dots{} [@var{file}]@dots{}
|
||||
head -@var{number} [@var{option}]@dots{} [@var{file}]@dots{}
|
||||
@end example
|
||||
|
||||
If more than one @var{file} is specicified, @code{head} prints a
|
||||
If more than one @var{file} is specified, @code{head} prints a
|
||||
one-line header consisting of
|
||||
@example
|
||||
==> @var{file name} <==
|
||||
@@ -1312,7 +1312,7 @@ file, so that section of the input file is effectively ignored.
|
||||
Repeat the previous pattern @var{repeat-count} additional
|
||||
times. @var{repeat-count} can either be a positive integer or an
|
||||
asterisk, meaning repeat as many times as necessary until the input is
|
||||
exausted.
|
||||
exhausted.
|
||||
|
||||
@end table
|
||||
|
||||
@@ -1603,10 +1603,23 @@ For each such line, @code{md5sum} reads the named file and computes its
|
||||
MD5 checksum. Then, if the computed message digest does not match the
|
||||
one on the line with the filename, the file is noted as having
|
||||
failed the test. Otherwise, the file passes the test.
|
||||
By default, for each valid line, one line is written to standard
|
||||
output indicating whether the named file passed the test.
|
||||
Use the @samp{--status} option to inhibit that output.
|
||||
If any listed file cannot be opened or read, if any valid line has
|
||||
a MD5 checksum inconsistent with the associated file, or if no valid
|
||||
line is found, exit with a non-zero status. Otherwise, exit successfully.
|
||||
|
||||
@itemx --status
|
||||
@opindex --status
|
||||
@cindex verifying MD5 checksums
|
||||
When verifying checksums, don't generate any output.
|
||||
If all listed files are readable and are consistent with the associated
|
||||
MD5 checksums, exit successfully. Otherwise exit with a status code
|
||||
indicating there was a failure. Failures to open or read a file still
|
||||
evoke diagnostics to standard error.
|
||||
|
||||
@item -s
|
||||
@itemx --string=@var{string}
|
||||
@opindex -s
|
||||
@opindex --string
|
||||
Compute the message digest for @var{string}, instead of for a file. The
|
||||
result is the same as for a file that contains exactly @var{string}.
|
||||
@@ -1619,11 +1632,14 @@ result is the same as for a file that contains exactly @var{string}.
|
||||
Treat all input files as text files. This is the reverse of
|
||||
@samp{--binary}.
|
||||
|
||||
@item -v
|
||||
@itemx --verbose
|
||||
@opindex -v
|
||||
@opindex --verbose
|
||||
Print progress information.
|
||||
@item -w
|
||||
@itemx --warn
|
||||
@opindex -w
|
||||
@opindex --warn
|
||||
@cindex verifying MD5 checksums
|
||||
When verifying checksums, warn about improperly formated MD5 checksum lines.
|
||||
This option is useful only if all but a few lines in the checked input
|
||||
are valid.
|
||||
|
||||
@end table
|
||||
|
||||
@@ -2021,6 +2037,9 @@ The input files must be sorted before @code{comm} can be used.
|
||||
With no options, @code{comm} produces three column output. Column one
|
||||
contains lines unique to @var{file1}, column two contains lines unique
|
||||
to @var{file2}, and column three contains lines common to both files.
|
||||
Columns are separated by @key{TAB}.
|
||||
@c FIXME: when there's an option to supply an alternative separator
|
||||
@c string, append `by default' to the above sentence.
|
||||
|
||||
@opindex -1
|
||||
@opindex -2
|
||||
@@ -2095,7 +2114,7 @@ For @samp{-f}, fields are separated by the first character in @var{delim}
|
||||
|
||||
@item -n
|
||||
@opindex -n
|
||||
Do not split multibyte characters (no-op for now).
|
||||
Do not split multi-byte characters (no-op for now).
|
||||
|
||||
@item -s
|
||||
@itemx --only-delimited
|
||||
@@ -2207,6 +2226,8 @@ Each element in @var{field-list} consists of a file number (either 1 or
|
||||
the list are separated by commas or blanks. Multiple @var{field-list}
|
||||
arguments can be given after a single @samp{-o} option; the values
|
||||
of all lists given with @samp{-o} are concatenated together.
|
||||
All output lines -- including those printed because of any -a or -v
|
||||
option -- are subject to the specified @var{field-list}.
|
||||
|
||||
@item -t @var{char}
|
||||
Use character @var{char} as the input and output field separator.
|
||||
@@ -3199,7 +3220,7 @@ much more efficient and do more than these programs do. Nevertheless, as
|
||||
exposition of good programming style, and evangelism for a still-valuable
|
||||
philosophy, these books are unparalleled, and I recommend them highly.
|
||||
|
||||
Acknowledgement: I would like to express my gratitude to Brian Kernighan
|
||||
Acknowledgment: I would like to express my gratitude to Brian Kernighan
|
||||
of Bell Labs, the original Software Toolsmith, for reviewing this column.
|
||||
|
||||
|
||||
|
||||
@@ -5,3 +5,4 @@ safe-stat.h
|
||||
safe-stat.c
|
||||
safe-lstat.c
|
||||
safe-lstat.h
|
||||
getdate.tab.c
|
||||
|
||||
@@ -38,7 +38,7 @@ modechange.c mountlist.c obstack.c safe-read.c savedir.c \
|
||||
stripslash.c xgetcwd.c xmalloc.c xstrdup.c userspec.c yesno.c \
|
||||
fileblocks.c fnmatch.c ftruncate.c mkdir.c mktime.c rename.c rmdir.c \
|
||||
save-cwd.c stpcpy.c \
|
||||
strdup.c strstr.c strtol.c alloca.c long-options.c \
|
||||
strdup.c strstr.c strtol.c strtoul.c alloca.c long-options.c \
|
||||
memcmp.c memcpy.c memset.c xstrtol.c xstrtoul.c
|
||||
|
||||
OBJECTS = getdate.o posixtm.o \
|
||||
@@ -58,8 +58,10 @@ all: libfu.a
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
|
||||
INCLUDES = -I.. -I$(srcdir)
|
||||
.c.o:
|
||||
$(CC) -c $(CPPFLAGS) $(DEFS) -I.. -I$(srcdir) $(CFLAGS) $<
|
||||
$(COMPILE) $<
|
||||
|
||||
subdir = lib
|
||||
Makefile: ../config.status Makefile.in
|
||||
@@ -83,6 +85,7 @@ mostlyclean: clean
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile *.tab.c tposixtm.c
|
||||
rm -rf .deps
|
||||
|
||||
maintainer-clean: distclean
|
||||
rm -f TAGS getdate.c posixtm.c
|
||||
@@ -140,3 +143,8 @@ installdirs maintainer-clean mostlyclean uninstall
|
||||
# Tell versions [3.59,3.63) of GNU make not to export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
|
||||
# The following include directive is uncommented automatically
|
||||
# when this package is configured with the --with-autodep option.
|
||||
# You need GNU make and a C compiler that can generate dependencies.
|
||||
@AUTODEP_COMMENT@include @top_srcdir@/mkdep-Makefile
|
||||
|
||||
@@ -56,7 +56,7 @@ void (*error_print_progname) () = NULL;
|
||||
extern char *program_name;
|
||||
|
||||
#if HAVE_STRERROR
|
||||
# ifndef strerror /* On some systems, sterror is a macro */
|
||||
# ifndef strerror /* On some systems, strerror is a macro */
|
||||
char *strerror ();
|
||||
# endif
|
||||
#else
|
||||
|
||||
168
lib/euidaccess.c
168
lib/euidaccess.c
@@ -1,21 +1,25 @@
|
||||
/* euidaccess -- check if effective user id can access file
|
||||
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
|
||||
Copyright (C) 1990, 1991, 1995 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 file is part of the GNU C Library.
|
||||
|
||||
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.
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
The GNU C Library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
/* Written by David MacKenzie and Torbjorn Granlund. */
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Written by David MacKenzie and Torbjorn Granlund.
|
||||
Adapted for GNU C library by Roland McGrath. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
@@ -36,7 +40,7 @@
|
||||
#endif
|
||||
#endif /* S_IEXEC */
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#if defined (HAVE_UNISTD_H) || defined (_LIBC)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
@@ -74,6 +78,13 @@ extern int errno;
|
||||
#define R_OK 4
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _LIBC
|
||||
|
||||
#define group_member __group_member
|
||||
|
||||
#else
|
||||
|
||||
/* The user's real user id. */
|
||||
static uid_t uid;
|
||||
|
||||
@@ -86,67 +97,17 @@ static uid_t euid;
|
||||
/* The user's effective group id. */
|
||||
static gid_t egid;
|
||||
|
||||
int group_member ();
|
||||
|
||||
/* Nonzero if UID, GID, EUID, and EGID have valid values. */
|
||||
static int have_ids = 0;
|
||||
|
||||
/* Like euidaccess, except that a pointer to a filled-in stat structure
|
||||
describing the file is provided instead of a filename.
|
||||
Because this function is almost guaranteed to fail on systems that
|
||||
use ACLs, a third argument *PATH may be used. If it is non-NULL,
|
||||
it is assumed to be the name of the file corresponding to STATP.
|
||||
Then, if the user is not running set-uid or set-gid, use access
|
||||
instead of attempting a manual and non-portable comparison. */
|
||||
|
||||
int
|
||||
eaccess_stat (statp, mode, path)
|
||||
const struct stat *statp;
|
||||
int mode;
|
||||
const char *path;
|
||||
{
|
||||
int granted;
|
||||
|
||||
mode &= (X_OK | W_OK | R_OK); /* Clear any bogus bits. */
|
||||
|
||||
if (mode == F_OK)
|
||||
return 0; /* The file exists. */
|
||||
|
||||
if (have_ids == 0)
|
||||
{
|
||||
have_ids = 1;
|
||||
uid = getuid ();
|
||||
gid = getgid ();
|
||||
euid = geteuid ();
|
||||
egid = getegid ();
|
||||
}
|
||||
|
||||
if (path && uid == euid && gid == egid)
|
||||
{
|
||||
return access (path, mode);
|
||||
}
|
||||
|
||||
/* The super-user can read and write any file, and execute any file
|
||||
that anyone can execute. */
|
||||
if (euid == 0 && ((mode & X_OK) == 0
|
||||
|| (statp->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
|
||||
return 0;
|
||||
|
||||
if (euid == statp->st_uid)
|
||||
granted = (unsigned) (statp->st_mode & (mode << 6)) >> 6;
|
||||
else if (egid == statp->st_gid
|
||||
#ifdef HAVE_GETGROUPS
|
||||
|| group_member (statp->st_gid)
|
||||
int group_member ();
|
||||
#else
|
||||
#define group_member(gid) 0
|
||||
#endif
|
||||
)
|
||||
granted = (unsigned) (statp->st_mode & (mode << 3)) >> 3;
|
||||
else
|
||||
granted = (statp->st_mode & mode);
|
||||
if (granted == mode)
|
||||
return 0;
|
||||
errno = EACCESS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Return 0 if the user has permission of type MODE on file PATH;
|
||||
otherwise, return -1 and set `errno' to EACCESS.
|
||||
@@ -160,7 +121,12 @@ euidaccess (path, mode)
|
||||
int mode;
|
||||
{
|
||||
struct stat stats;
|
||||
int granted;
|
||||
|
||||
#ifdef _LIBC
|
||||
uid_t uid = getuid (), euid = geteuid ();
|
||||
gid_t gid = getgid (), egid = getegid ();
|
||||
#else
|
||||
if (have_ids == 0)
|
||||
{
|
||||
have_ids = 1;
|
||||
@@ -169,45 +135,37 @@ euidaccess (path, mode)
|
||||
euid = geteuid ();
|
||||
egid = getegid ();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (uid == euid && gid == egid)
|
||||
{
|
||||
return access (path, mode);
|
||||
}
|
||||
/* If we are not set-uid or set-gid, access does the same. */
|
||||
return access (path, mode);
|
||||
|
||||
if (stat (path, &stats))
|
||||
return -1;
|
||||
|
||||
return eaccess_stat (&stats, mode, path);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
void error ();
|
||||
|
||||
char *program_name;
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
char *file;
|
||||
int mode;
|
||||
int err;
|
||||
|
||||
program_name = argv[0];
|
||||
if (argc < 3)
|
||||
abort ();
|
||||
file = argv[1];
|
||||
mode = atoi (argv[2]);
|
||||
|
||||
err = euidaccess (file, mode);
|
||||
printf ("%d\n", err);
|
||||
if (err != 0)
|
||||
error (0, errno, "%s", file);
|
||||
exit (0);
|
||||
}
|
||||
mode &= (X_OK | W_OK | R_OK); /* Clear any bogus bits. */
|
||||
#if R_OK != S_IROTH || W_OK != S_IWOTH || X_OK != S_IXOTH
|
||||
?error Oops, portability assumptions incorrect.
|
||||
#endif
|
||||
|
||||
if (mode == F_OK)
|
||||
return 0; /* The file exists. */
|
||||
|
||||
/* The super-user can read and write any file, and execute any file
|
||||
that anyone can execute. */
|
||||
if (euid == 0 && ((mode & X_OK) == 0
|
||||
|| (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
|
||||
return 0;
|
||||
|
||||
if (euid == stats.st_uid)
|
||||
granted = (unsigned) (stats.st_mode & (mode << 6)) >> 6;
|
||||
else if (egid == stats.st_gid || group_member (stats.st_gid))
|
||||
granted = (unsigned) (stats.st_mode & (mode << 3)) >> 3;
|
||||
else
|
||||
granted = (stats.st_mode & mode);
|
||||
if (granted == mode)
|
||||
return 0;
|
||||
errno = EACCESS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_ST_BLOCKS) && !defined(_POSIX_SOURCE)
|
||||
#if !defined (HAVE_ST_BLOCKS) && !defined(_POSIX_VERSION)
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ adjust_blocks (blocks, fromsize, tosize)
|
||||
abort ();
|
||||
if (fromsize <= 0)
|
||||
return -1;
|
||||
|
||||
|
||||
if (fromsize == tosize) /* E.g., from 512 to 512. */
|
||||
return blocks;
|
||||
else if (fromsize > tosize) /* E.g., from 2048 to 512. */
|
||||
@@ -144,6 +144,21 @@ get_fs_usage (path, disk, fsp)
|
||||
|
||||
if (statfs (path, &fsd) < 0)
|
||||
return -1;
|
||||
|
||||
#ifdef STATFS_TRUNCATES_BLOCK_COUNTS
|
||||
/* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
|
||||
struct statfs are truncated to 2GB. These conditions detect that
|
||||
truncation, presumably without botching the 4.1.1 case, in which
|
||||
the values are not truncated. The correct counts are stored in
|
||||
undocumented spare fields. */
|
||||
if (fsd.f_blocks == 0x1fffff && fsd.f_spare[0] > 0)
|
||||
{
|
||||
fsd.f_blocks = fsd.f_spare[0];
|
||||
fsd.f_bfree = fsd.f_spare[1];
|
||||
fsd.f_bavail = fsd.f_spare[2];
|
||||
}
|
||||
#endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
|
||||
|
||||
#define CONVERT_BLOCKS(b) adjust_blocks ((b), fsd.f_bsize, 512)
|
||||
#endif
|
||||
|
||||
|
||||
126
lib/getline.c
Normal file
126
lib/getline.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/* getline.c -- Replacement for GNU C library function getline
|
||||
|
||||
Copyright (C) 1993 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 of the
|
||||
License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#define NDEBUG
|
||||
#include <assert.h>
|
||||
|
||||
#if STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
char *malloc (), *realloc ();
|
||||
#endif
|
||||
|
||||
/* Always add at least this many bytes when extending the buffer. */
|
||||
#define MIN_CHUNK 64
|
||||
|
||||
/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
|
||||
+ OFFSET (and null-terminate it). *LINEPTR is a pointer returned from
|
||||
malloc (or NULL), pointing to *N characters of space. It is realloc'd
|
||||
as necessary. Return the number of characters read (not including the
|
||||
null terminator), or -1 on error or EOF. */
|
||||
|
||||
int
|
||||
getstr (lineptr, n, stream, terminator, offset)
|
||||
char **lineptr;
|
||||
size_t *n;
|
||||
FILE *stream;
|
||||
char terminator;
|
||||
int offset;
|
||||
{
|
||||
int nchars_avail; /* Allocated but unused chars in *LINEPTR. */
|
||||
char *read_pos; /* Where we're reading into *LINEPTR. */
|
||||
int ret;
|
||||
|
||||
if (!lineptr || !n || !stream)
|
||||
return -1;
|
||||
|
||||
if (!*lineptr)
|
||||
{
|
||||
*n = MIN_CHUNK;
|
||||
*lineptr = malloc (*n);
|
||||
if (!*lineptr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
nchars_avail = *n - offset;
|
||||
read_pos = *lineptr + offset;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
register int c = getc (stream);
|
||||
|
||||
/* We always want at least one char left in the buffer, since we
|
||||
always (unless we get an error while reading the first char)
|
||||
NUL-terminate the line buffer. */
|
||||
|
||||
assert(*n - nchars_avail == read_pos - *lineptr);
|
||||
if (nchars_avail < 2)
|
||||
{
|
||||
if (*n > MIN_CHUNK)
|
||||
*n *= 2;
|
||||
else
|
||||
*n += MIN_CHUNK;
|
||||
|
||||
nchars_avail = *n + *lineptr - read_pos;
|
||||
*lineptr = realloc (*lineptr, *n);
|
||||
if (!*lineptr)
|
||||
return -1;
|
||||
read_pos = *n - nchars_avail + *lineptr;
|
||||
assert(*n - nchars_avail == read_pos - *lineptr);
|
||||
}
|
||||
|
||||
if (c == EOF || ferror (stream))
|
||||
{
|
||||
/* Return partial line, if any. */
|
||||
if (read_pos == *lineptr)
|
||||
return -1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
*read_pos++ = c;
|
||||
nchars_avail--;
|
||||
|
||||
if (c == terminator)
|
||||
/* Return the line. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Done - NUL terminate and return the number of chars read. */
|
||||
*read_pos = '\0';
|
||||
|
||||
ret = read_pos - (*lineptr + offset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
getline (lineptr, n, stream)
|
||||
char **lineptr;
|
||||
size_t *n;
|
||||
FILE *stream;
|
||||
{
|
||||
return getstr (lineptr, n, stream, '\n', 0);
|
||||
}
|
||||
17
lib/getline.h
Normal file
17
lib/getline.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef _getline_h_
|
||||
#define _getline_h_ 1
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef __P
|
||||
#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
|
||||
#define __P(args) args
|
||||
#else
|
||||
#define __P(args) ()
|
||||
#endif /* GCC. */
|
||||
#endif /* Not __P. */
|
||||
|
||||
int
|
||||
getline __P ((char **_lineptr, size_t *_n, FILE *_stream));
|
||||
|
||||
#endif /* _getline_h_ */
|
||||
27
lib/getopt.c
27
lib/getopt.c
@@ -59,12 +59,15 @@
|
||||
#include <stdlib.h>
|
||||
#endif /* GNU C library. */
|
||||
|
||||
#ifndef _
|
||||
/* This is for other GNU distributions with internationalized messages.
|
||||
The GNU C Library itself does not yet support such messages. */
|
||||
#if HAVE_LIBINTL_H
|
||||
When compiling libc, the _ macro is predefined. */
|
||||
#ifdef HAVE_LIBINTL_H
|
||||
# include <libintl.h>
|
||||
# define _(msgid) gettext (msgid)
|
||||
#else
|
||||
# define gettext(msgid) (msgid)
|
||||
# define _(msgid) (msgid)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* This version of `getopt' appears to the caller like standard Unix `getopt'
|
||||
@@ -521,7 +524,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
|
||||
if (ambig && !exact)
|
||||
{
|
||||
if (opterr)
|
||||
fprintf (stderr, gettext ("%s: option `%s' is ambiguous\n"),
|
||||
fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
|
||||
argv[0], argv[optind]);
|
||||
nextchar += strlen (nextchar);
|
||||
optind++;
|
||||
@@ -544,12 +547,12 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
|
||||
if (argv[optind - 1][1] == '-')
|
||||
/* --option */
|
||||
fprintf (stderr,
|
||||
gettext ("%s: option `--%s' doesn't allow an argument\n"),
|
||||
_("%s: option `--%s' doesn't allow an argument\n"),
|
||||
argv[0], pfound->name);
|
||||
else
|
||||
/* +option or -option */
|
||||
fprintf (stderr,
|
||||
gettext ("%s: option `%c%s' doesn't allow an argument\n"),
|
||||
_("%s: option `%c%s' doesn't allow an argument\n"),
|
||||
argv[0], argv[optind - 1][0], pfound->name);
|
||||
|
||||
nextchar += strlen (nextchar);
|
||||
@@ -564,7 +567,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
|
||||
{
|
||||
if (opterr)
|
||||
fprintf (stderr,
|
||||
gettext ("%s: option `%s' requires an argument\n"),
|
||||
_("%s: option `%s' requires an argument\n"),
|
||||
argv[0], argv[optind - 1]);
|
||||
nextchar += strlen (nextchar);
|
||||
return optstring[0] == ':' ? ':' : '?';
|
||||
@@ -592,11 +595,11 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
|
||||
{
|
||||
if (argv[optind][1] == '-')
|
||||
/* --option */
|
||||
fprintf (stderr, gettext ("%s: unrecognized option `--%s'\n"),
|
||||
fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
|
||||
argv[0], nextchar);
|
||||
else
|
||||
/* +option or -option */
|
||||
fprintf (stderr, gettext ("%s: unrecognized option `%c%s'\n"),
|
||||
fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
|
||||
argv[0], argv[optind][0], nextchar);
|
||||
}
|
||||
nextchar = (char *) "";
|
||||
@@ -621,10 +624,10 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
|
||||
{
|
||||
if (posixly_correct)
|
||||
/* 1003.2 specifies the format of this message. */
|
||||
fprintf (stderr, gettext ("%s: illegal option -- %c\n"),
|
||||
fprintf (stderr, _("%s: illegal option -- %c\n"),
|
||||
argv[0], c);
|
||||
else
|
||||
fprintf (stderr, gettext ("%s: invalid option -- %c\n"),
|
||||
fprintf (stderr, _("%s: invalid option -- %c\n"),
|
||||
argv[0], c);
|
||||
}
|
||||
optopt = c;
|
||||
@@ -660,7 +663,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
|
||||
{
|
||||
/* 1003.2 specifies the format of this message. */
|
||||
fprintf (stderr,
|
||||
gettext ("%s: option requires an argument -- %c\n"),
|
||||
_("%s: option requires an argument -- %c\n"),
|
||||
argv[0], c);
|
||||
}
|
||||
optopt = c;
|
||||
|
||||
807
lib/mktime.c
807
lib/mktime.c
@@ -1,45 +1,54 @@
|
||||
/* Copyright (C) 1993, 1994 Free Software Foundation, Inc.
|
||||
Contributed by Noel Cragg (noel@cs.oberlin.edu), with fixes by
|
||||
Michael E. Calwas (calwas@ttd.teradyne.com) and
|
||||
Wade Hampton (tasi029@tmn.com).
|
||||
/* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
|
||||
Contributed by Paul Eggert (eggert@twinsun.com).
|
||||
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
NOTE: The canonical source of this file is maintained with the GNU C Library.
|
||||
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
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,
|
||||
The GNU C Library 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.
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Define this to have a standalone program to test this implementation of
|
||||
mktime. */
|
||||
/* #define DEBUG */
|
||||
/* #define DEBUG 1 */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
/* Assume that leap seconds are possible, unless told otherwise.
|
||||
If the host has a `zic' command with a `-L leapsecondfilename' option,
|
||||
then it supports leap seconds; otherwise it probably doesn't. */
|
||||
#ifndef LEAP_SECONDS_POSSIBLE
|
||||
#define LEAP_SECONDS_POSSIBLE 1
|
||||
#endif
|
||||
|
||||
#include <sys/types.h> /* Some systems define `time_t' here. */
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#ifndef __isleap
|
||||
/* Nonzero if YEAR is a leap year (every 4 years,
|
||||
except every 100th isn't, and every 400th is). */
|
||||
#define __isleap(year) \
|
||||
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
|
||||
#if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
#include <stdio.h>
|
||||
#if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
/* Make it work even if the system's libc has its own mktime routine. */
|
||||
#define mktime my_mktime
|
||||
#endif /* DEBUG */
|
||||
|
||||
#ifndef __P
|
||||
#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
|
||||
#define __P(args) args
|
||||
@@ -48,456 +57,352 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#endif /* GCC. */
|
||||
#endif /* Not __P. */
|
||||
|
||||
/* How many days are in each month. */
|
||||
const unsigned short int __mon_lengths[2][12] =
|
||||
#ifndef CHAR_BIT
|
||||
#define CHAR_BIT 8
|
||||
#endif
|
||||
|
||||
#ifndef INT_MIN
|
||||
#define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
|
||||
#endif
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX (~0 - INT_MIN)
|
||||
#endif
|
||||
|
||||
#ifndef TIME_T_MIN
|
||||
#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
|
||||
: ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
|
||||
#endif
|
||||
#ifndef TIME_T_MAX
|
||||
#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
|
||||
#endif
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
#define EPOCH_YEAR 1970
|
||||
|
||||
#ifndef __isleap
|
||||
/* Nonzero if YEAR is a leap year (every 4 years,
|
||||
except every 100th isn't, and every 400th is). */
|
||||
#define __isleap(year) \
|
||||
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
|
||||
#endif
|
||||
|
||||
/* How many days come before each month (0-12). */
|
||||
const unsigned short int __mon_yday[2][13] =
|
||||
{
|
||||
/* Normal years. */
|
||||
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
|
||||
/* Leap years. */
|
||||
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
|
||||
};
|
||||
|
||||
|
||||
static int times_through_search; /* This library routine should never
|
||||
hang -- make sure we always return
|
||||
when we're searching for a value */
|
||||
static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
|
||||
time_t __mktime_internal __P ((struct tm *,
|
||||
struct tm *(*) (const time_t *, struct tm *),
|
||||
time_t *));
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int debugging_enabled = 0;
|
||||
|
||||
/* Print the values in a `struct tm'. */
|
||||
static void
|
||||
printtm (it)
|
||||
struct tm *it;
|
||||
{
|
||||
printf ("%02d/%02d/%04d %02d:%02d:%02d (%s) yday:%03d dst:%d gmtoffset:%ld",
|
||||
it->tm_mon + 1,
|
||||
it->tm_mday,
|
||||
it->tm_year + 1900,
|
||||
it->tm_hour,
|
||||
it->tm_min,
|
||||
it->tm_sec,
|
||||
it->tm_zone,
|
||||
it->tm_yday,
|
||||
it->tm_isdst,
|
||||
it->tm_gmtoff);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static time_t
|
||||
dist_tm (t1, t2)
|
||||
struct tm *t1;
|
||||
struct tm *t2;
|
||||
{
|
||||
time_t distance = 0;
|
||||
unsigned long int v1, v2;
|
||||
int diff_flag = 0;
|
||||
|
||||
v1 = v2 = 0;
|
||||
|
||||
#define doit(x, secs) \
|
||||
v1 += t1->x * secs; \
|
||||
v2 += t2->x * secs; \
|
||||
if (!diff_flag) \
|
||||
{ \
|
||||
if (t1->x < t2->x) \
|
||||
diff_flag = -1; \
|
||||
else if (t1->x > t2->x) \
|
||||
diff_flag = 1; \
|
||||
}
|
||||
|
||||
doit (tm_year, 31536000); /* Okay, not all years have 365 days. */
|
||||
doit (tm_mon, 2592000); /* Okay, not all months have 30 days. */
|
||||
doit (tm_mday, 86400);
|
||||
doit (tm_hour, 3600);
|
||||
doit (tm_min, 60);
|
||||
doit (tm_sec, 1);
|
||||
|
||||
#undef doit
|
||||
|
||||
/* We should also make sure that the sign of DISTANCE is correct -- if
|
||||
DIFF_FLAG is positive, the distance should be positive and vice versa. */
|
||||
|
||||
distance = (v1 > v2) ? (v1 - v2) : (v2 - v1);
|
||||
if (diff_flag < 0)
|
||||
distance = -distance;
|
||||
|
||||
if (times_through_search > 20) /* Arbitrary # of calls, but makes sure we
|
||||
never hang if there's a problem with
|
||||
this algorithm. */
|
||||
{
|
||||
distance = diff_flag;
|
||||
}
|
||||
|
||||
/* We need this DIFF_FLAG business because it is forseeable that the
|
||||
distance may be zero when, in actuality, the two structures are
|
||||
different. This is usually the case when the dates are 366 days apart
|
||||
and one of the years is a leap year. */
|
||||
|
||||
if (distance == 0 && diff_flag)
|
||||
distance = 86400 * diff_flag;
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
|
||||
/* MKTIME converts the values in a struct tm to a time_t. The values
|
||||
in tm_wday and tm_yday are ignored; other values can be put outside
|
||||
of legal ranges since they will be normalized. This routine takes
|
||||
care of that normalization. */
|
||||
|
||||
void
|
||||
do_normalization (tmptr)
|
||||
struct tm *tmptr;
|
||||
{
|
||||
|
||||
#define normalize(foo,x,y,bar); \
|
||||
while (tmptr->foo < x) \
|
||||
{ \
|
||||
tmptr->bar--; \
|
||||
tmptr->foo = (y - (x - tmptr->foo) + 1); \
|
||||
} \
|
||||
while (tmptr->foo > y) \
|
||||
{ \
|
||||
tmptr->foo = (x + (tmptr->foo - y) - 1); \
|
||||
tmptr->bar++; \
|
||||
}
|
||||
|
||||
normalize (tm_sec, 0, 59, tm_min);
|
||||
normalize (tm_min, 0, 59, tm_hour);
|
||||
normalize (tm_hour, 0, 23, tm_mday);
|
||||
|
||||
/* Do the month first, so day range can be found. */
|
||||
normalize (tm_mon, 0, 11, tm_year);
|
||||
|
||||
/* Since the day range modifies the month, we should be careful how
|
||||
we reference the array of month lengths -- it is possible that
|
||||
the month will go negative, hence the modulo...
|
||||
|
||||
Also, tm_year is the year - 1900, so we have to 1900 to have it
|
||||
work correctly. */
|
||||
|
||||
normalize (tm_mday, 1,
|
||||
__mon_lengths[__isleap (tmptr->tm_year + 1900)]
|
||||
[((tmptr->tm_mon < 0)
|
||||
? (12 + (tmptr->tm_mon % 12))
|
||||
: (tmptr->tm_mon % 12)) ],
|
||||
tm_mon);
|
||||
|
||||
/* Do the month again, because the day may have pushed it out of range. */
|
||||
normalize (tm_mon, 0, 11, tm_year);
|
||||
|
||||
/* Do the day again, because the month may have changed the range. */
|
||||
normalize (tm_mday, 1,
|
||||
__mon_lengths[__isleap (tmptr->tm_year + 1900)]
|
||||
[((tmptr->tm_mon < 0)
|
||||
? (12 + (tmptr->tm_mon % 12))
|
||||
: (tmptr->tm_mon % 12)) ],
|
||||
tm_mon);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (debugging_enabled)
|
||||
{
|
||||
printf (" After normalizing:\n ");
|
||||
printtm (tmptr);
|
||||
putchar ('\n');
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Here's where the work gets done. */
|
||||
|
||||
#define BAD_STRUCT_TM ((time_t) -1)
|
||||
|
||||
time_t
|
||||
_mktime_internal (timeptr, producer)
|
||||
struct tm *timeptr;
|
||||
struct tm *(*producer) __P ((const time_t *));
|
||||
{
|
||||
struct tm our_tm; /* our working space */
|
||||
struct tm *me = &our_tm; /* a pointer to the above */
|
||||
time_t result; /* the value we return */
|
||||
|
||||
*me = *timeptr; /* copy the struct tm that was passed
|
||||
in by the caller */
|
||||
|
||||
|
||||
/***************************/
|
||||
/* Normalize the structure */
|
||||
/***************************/
|
||||
|
||||
/* This routine assumes that the value of TM_ISDST is -1, 0, or 1.
|
||||
If the user didn't pass it in that way, fix it. */
|
||||
|
||||
if (me->tm_isdst > 0)
|
||||
me->tm_isdst = 1;
|
||||
else if (me->tm_isdst < 0)
|
||||
me->tm_isdst = -1;
|
||||
|
||||
do_normalization (me);
|
||||
|
||||
/* Get out of here if it's not possible to represent this struct.
|
||||
If any of the values in the normalized struct tm are negative,
|
||||
our algorithms won't work. Luckily, we only need to check the
|
||||
year at this point; normalization guarantees that all values will
|
||||
be in correct ranges EXCEPT the year. */
|
||||
|
||||
if (me->tm_year < 0)
|
||||
return BAD_STRUCT_TM;
|
||||
|
||||
/*************************************************/
|
||||
/* Find the appropriate time_t for the structure */
|
||||
/*************************************************/
|
||||
|
||||
/* Modified b-search -- make intelligent guesses as to where the
|
||||
time might lie along the timeline, assuming that our target time
|
||||
lies a linear distance (w/o considering time jumps of a
|
||||
particular region).
|
||||
|
||||
Assume that time does not fluctuate at all along the timeline --
|
||||
e.g., assume that a day will always take 86400 seconds, etc. --
|
||||
and come up with a hypothetical value for the time_t
|
||||
representation of the struct tm TARGET, in relation to the guess
|
||||
variable -- it should be pretty close!
|
||||
|
||||
After testing this, the maximum number of iterations that I had
|
||||
on any number that I tried was 3! Not bad.
|
||||
|
||||
The reason this is not a subroutine is that we will modify some
|
||||
fields in the struct tm (yday and mday). I've never felt good
|
||||
about side-effects when writing structured code... */
|
||||
|
||||
{
|
||||
struct tm *guess_tm;
|
||||
time_t guess = 0;
|
||||
time_t distance = 0;
|
||||
time_t last_distance = 0;
|
||||
|
||||
times_through_search = 0;
|
||||
|
||||
do
|
||||
{
|
||||
guess += distance;
|
||||
|
||||
times_through_search++;
|
||||
|
||||
guess_tm = (*producer) (&guess);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (debugging_enabled)
|
||||
{
|
||||
printf (" Guessing time_t == %d\n ", (int) guess);
|
||||
printtm (guess_tm);
|
||||
putchar ('\n');
|
||||
}
|
||||
#endif
|
||||
|
||||
/* How far is our guess from the desired struct tm? */
|
||||
distance = dist_tm (me, guess_tm);
|
||||
|
||||
/* Handle periods of time where a period of time is skipped.
|
||||
For example, 2:15 3 April 1994 does not exist, because DST
|
||||
is in effect. The distance function will alternately
|
||||
return values of 3600 and -3600, because it doesn't know
|
||||
that the requested time doesn't exist. In these situations
|
||||
(even if the skip is not exactly an hour) the distances
|
||||
returned will be the same, but alternating in sign. We
|
||||
want the later time, so check to see that the distance is
|
||||
oscillating and we've chosen the correct of the two
|
||||
possibilities.
|
||||
|
||||
Useful: 3 Apr 94 765356300, 30 Oct 94 783496000 */
|
||||
|
||||
if ((distance == -last_distance) && (distance < last_distance))
|
||||
{
|
||||
/* If the caller specified that the DST flag was off, it's
|
||||
not possible to represent this time. */
|
||||
if (me->tm_isdst == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf (" Distance is oscillating -- dst flag nixes struct!\n");
|
||||
#endif
|
||||
return BAD_STRUCT_TM;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf (" Distance is oscillating -- chose the later time.\n");
|
||||
#endif
|
||||
distance = 0;
|
||||
}
|
||||
|
||||
if ((distance == 0) && (me->tm_isdst != -1)
|
||||
&& (me->tm_isdst != guess_tm->tm_isdst))
|
||||
{
|
||||
/* If we're in this code, we've got the right time but the
|
||||
wrong daylight savings flag. We need to move away from
|
||||
the time that we have and approach the other time from
|
||||
the other direction. That is, if I've requested the
|
||||
non-DST version of a time and I get the DST version
|
||||
instead, I want to put us forward in time and search
|
||||
backwards to get the other time. I checked all of the
|
||||
configuration files for the tz package -- no entry
|
||||
saves more than two hours, so I think we'll be safe by
|
||||
moving 24 hours in one direction. IF THE AMOUNT OF
|
||||
TIME SAVED IN THE CONFIGURATION FILES CHANGES, THIS
|
||||
VALUE MAY NEED TO BE ADJUSTED. Luckily, we can never
|
||||
have more than one level of overlaps, or this would
|
||||
never work. */
|
||||
|
||||
#define SKIP_VALUE 86400
|
||||
|
||||
if (guess_tm->tm_isdst == 0)
|
||||
/* we got the later one, but want the earlier one */
|
||||
distance = -SKIP_VALUE;
|
||||
else
|
||||
distance = SKIP_VALUE;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf (" Got the right time, wrong DST value -- adjusting\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
last_distance = distance;
|
||||
|
||||
} while (distance != 0);
|
||||
|
||||
/* Check to see that the dst flag matches */
|
||||
|
||||
if (me->tm_isdst != -1)
|
||||
{
|
||||
if (me->tm_isdst != guess_tm->tm_isdst)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf (" DST flag doesn't match! FIXME?\n");
|
||||
#endif
|
||||
return BAD_STRUCT_TM;
|
||||
}
|
||||
}
|
||||
|
||||
result = guess; /* Success! */
|
||||
|
||||
/* On successful completion, the values of tm_wday and tm_yday
|
||||
have to be set appropriately. */
|
||||
|
||||
/* me->tm_yday = guess_tm->tm_yday;
|
||||
me->tm_mday = guess_tm->tm_mday; */
|
||||
|
||||
*me = *guess_tm;
|
||||
}
|
||||
|
||||
/* Update the caller's version of the structure */
|
||||
|
||||
*timeptr = *me;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
time_t
|
||||
#ifdef DEBUG /* make it work even if the system's
|
||||
libc has it's own mktime routine */
|
||||
my_mktime (timeptr)
|
||||
#if ! HAVE_LOCALTIME_R && ! defined (localtime_r)
|
||||
#ifdef _LIBC
|
||||
#define localtime_r __localtime_r
|
||||
#else
|
||||
mktime (timeptr)
|
||||
#endif
|
||||
struct tm *timeptr;
|
||||
/* Approximate localtime_r as best we can in its absence. */
|
||||
#define localtime_r my_localtime_r
|
||||
static struct tm *localtime_r __P ((const time_t *, struct tm *));
|
||||
static struct tm *
|
||||
localtime_r (t, tp)
|
||||
const time_t *t;
|
||||
struct tm *tp;
|
||||
{
|
||||
return _mktime_internal (timeptr, localtime);
|
||||
struct tm *l = localtime (t);
|
||||
if (! l)
|
||||
return 0;
|
||||
*tp = *l;
|
||||
return tp;
|
||||
}
|
||||
#endif /* ! _LIBC */
|
||||
#endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
|
||||
|
||||
|
||||
/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
|
||||
measured in seconds, ignoring leap seconds.
|
||||
YEAR uses the same numbering as TM->tm_year.
|
||||
All values are in range, except possibly YEAR.
|
||||
If overflow occurs, yield the low order bits of the correct answer. */
|
||||
static time_t
|
||||
ydhms_tm_diff (year, yday, hour, min, sec, tp)
|
||||
int year, yday, hour, min, sec;
|
||||
const struct tm *tp;
|
||||
{
|
||||
time_t ay = year + (time_t) (TM_YEAR_BASE - 1);
|
||||
time_t by = tp->tm_year + (time_t) (TM_YEAR_BASE - 1);
|
||||
time_t intervening_leap_days =
|
||||
(ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
|
||||
time_t years = ay - by;
|
||||
time_t days = (365 * years + intervening_leap_days
|
||||
+ (yday - tp->tm_yday));
|
||||
return (60 * (60 * (24 * days + (hour - tp->tm_hour))
|
||||
+ (min - tp->tm_min))
|
||||
+ (sec - tp->tm_sec));
|
||||
}
|
||||
|
||||
|
||||
/* Convert *TP to a time_t value. */
|
||||
time_t
|
||||
mktime (tp)
|
||||
struct tm *tp;
|
||||
{
|
||||
static time_t localtime_offset;
|
||||
return __mktime_internal (tp, localtime_r, &localtime_offset);
|
||||
}
|
||||
|
||||
/* Convert *TP to a time_t value, inverting
|
||||
the monotonic and mostly-unit-linear conversion function CONVERT.
|
||||
Use *OFFSET to keep track of a guess at the offset of the result,
|
||||
compared to what the result would be for UTC without leap seconds.
|
||||
If *OFFSET's guess is correct, only one CONVERT call is needed. */
|
||||
time_t
|
||||
__mktime_internal (tp, convert, offset)
|
||||
struct tm *tp;
|
||||
struct tm *(*convert) __P ((const time_t *, struct tm *));
|
||||
time_t *offset;
|
||||
{
|
||||
time_t t, dt, t0;
|
||||
struct tm tm;
|
||||
|
||||
/* The maximum number of probes (calls to CONVERT) should be enough
|
||||
to handle any combinations of time zone rule changes, solar time,
|
||||
and leap seconds. Posix.1 prohibits leap seconds, but some hosts
|
||||
have them anyway. */
|
||||
int remaining_probes = 4;
|
||||
|
||||
/* Time requested. Copy it in case CONVERT modifies *TP; this can
|
||||
occur if TP is localtime's returned value and CONVERT is localtime. */
|
||||
int sec = tp->tm_sec;
|
||||
int min = tp->tm_min;
|
||||
int hour = tp->tm_hour;
|
||||
int mday = tp->tm_mday;
|
||||
int mon = tp->tm_mon;
|
||||
int year_requested = tp->tm_year;
|
||||
int isdst = tp->tm_isdst;
|
||||
|
||||
/* Ensure that mon is in range, and set year accordingly. */
|
||||
int mon_remainder = mon % 12;
|
||||
int negative_mon_remainder = mon_remainder < 0;
|
||||
int mon_years = mon / 12 - negative_mon_remainder;
|
||||
int year = year_requested + mon_years;
|
||||
|
||||
/* The other values need not be in range:
|
||||
the remaining code handles minor overflows correctly,
|
||||
assuming int and time_t arithmetic wraps around.
|
||||
Major overflows are caught at the end. */
|
||||
|
||||
/* Calculate day of year from year, month, and day of month.
|
||||
The result need not be in range. */
|
||||
int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
|
||||
[mon_remainder + 12 * negative_mon_remainder])
|
||||
+ mday - 1);
|
||||
|
||||
#if LEAP_SECONDS_POSSIBLE
|
||||
/* Handle out-of-range seconds specially,
|
||||
since ydhms_tm_diff assumes every minute has 60 seconds. */
|
||||
int sec_requested = sec;
|
||||
if (sec < 0)
|
||||
sec = 0;
|
||||
if (59 < sec)
|
||||
sec = 59;
|
||||
#endif
|
||||
|
||||
/* Invert CONVERT by probing. First assume the same offset as last time.
|
||||
Then repeatedly use the error to improve the guess. */
|
||||
|
||||
tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
|
||||
tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
|
||||
t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
|
||||
|
||||
for (t = t0 + *offset;
|
||||
(dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
|
||||
t += dt)
|
||||
if (--remaining_probes == 0)
|
||||
return -1;
|
||||
|
||||
/* Check whether tm.tm_isdst has the requested value, if any. */
|
||||
if (0 <= isdst && 0 <= tm.tm_isdst)
|
||||
{
|
||||
int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
|
||||
if (dst_diff)
|
||||
{
|
||||
/* Move two hours in the direction indicated by the disagreement,
|
||||
probe some more, and switch to a new time if found.
|
||||
The largest known fallback due to daylight savings is two hours:
|
||||
once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
|
||||
time_t ot = t - 2 * 60 * 60 * dst_diff;
|
||||
while (--remaining_probes != 0)
|
||||
{
|
||||
struct tm otm;
|
||||
if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
|
||||
(*convert) (&ot, &otm))))
|
||||
{
|
||||
t = ot;
|
||||
tm = otm;
|
||||
break;
|
||||
}
|
||||
if ((ot += dt) == t)
|
||||
break; /* Avoid a redundant probe. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*offset = t - t0;
|
||||
|
||||
#if LEAP_SECONDS_POSSIBLE
|
||||
if (sec_requested != tm.tm_sec)
|
||||
{
|
||||
/* Adjust time to reflect the tm_sec requested, not the normalized value.
|
||||
Also, repair any damage from a false match due to a leap second. */
|
||||
t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
|
||||
(*convert) (&t, &tm);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
|
||||
{
|
||||
/* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
|
||||
so check for major overflows. A gross check suffices,
|
||||
since if t has overflowed, it is off by a multiple of
|
||||
TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
|
||||
the difference that is bounded by a small value. */
|
||||
|
||||
double dyear = (double) year_requested + mon_years - tm.tm_year;
|
||||
double dday = 366 * dyear + mday;
|
||||
double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
|
||||
|
||||
if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
|
||||
return -1;
|
||||
}
|
||||
|
||||
*tp = tm;
|
||||
return t;
|
||||
}
|
||||
|
||||
#ifdef weak_alias
|
||||
weak_alias (mktime, timelocal)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
#if DEBUG
|
||||
|
||||
static int
|
||||
not_equal_tm (a, b)
|
||||
struct tm *a;
|
||||
struct tm *b;
|
||||
{
|
||||
return ((a->tm_sec ^ b->tm_sec)
|
||||
| (a->tm_min ^ b->tm_min)
|
||||
| (a->tm_hour ^ b->tm_hour)
|
||||
| (a->tm_mday ^ b->tm_mday)
|
||||
| (a->tm_mon ^ b->tm_mon)
|
||||
| (a->tm_year ^ b->tm_year)
|
||||
| (a->tm_mday ^ b->tm_mday)
|
||||
| (a->tm_yday ^ b->tm_yday)
|
||||
| (a->tm_isdst ^ b->tm_isdst));
|
||||
}
|
||||
|
||||
static void
|
||||
print_tm (tp)
|
||||
struct tm *tp;
|
||||
{
|
||||
printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
|
||||
tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
|
||||
tp->tm_hour, tp->tm_min, tp->tm_sec,
|
||||
tp->tm_yday, tp->tm_wday, tp->tm_isdst);
|
||||
}
|
||||
|
||||
static int
|
||||
check_result (tk, tmk, tl, tml)
|
||||
time_t tk;
|
||||
struct tm tmk;
|
||||
time_t tl;
|
||||
struct tm tml;
|
||||
{
|
||||
if (tk != tl || not_equal_tm (&tmk, &tml))
|
||||
{
|
||||
printf ("mktime (");
|
||||
print_tm (&tmk);
|
||||
printf (")\nyields (");
|
||||
print_tm (&tml);
|
||||
printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
char **argv;
|
||||
{
|
||||
int time;
|
||||
int result_time;
|
||||
struct tm *tmptr;
|
||||
|
||||
if (argc == 1)
|
||||
int status = 0;
|
||||
struct tm tm, tmk, tml;
|
||||
time_t tk, tl;
|
||||
char trailer;
|
||||
|
||||
if ((argc == 3 || argc == 4)
|
||||
&& (sscanf (argv[1], "%d-%d-%d%c",
|
||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
|
||||
== 3)
|
||||
&& (sscanf (argv[2], "%d:%d:%d%c",
|
||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
|
||||
== 3))
|
||||
{
|
||||
long q;
|
||||
|
||||
printf ("starting long test...\n");
|
||||
|
||||
for (q = 10000000; q < 1000000000; q += 599)
|
||||
{
|
||||
struct tm *tm = localtime ((time_t *) &q);
|
||||
if ((q % 10000) == 0) { printf ("%ld\n", q); fflush (stdout); }
|
||||
if (q != my_mktime (tm))
|
||||
{ printf ("failed for %ld\n", q); fflush (stdout); }
|
||||
}
|
||||
|
||||
printf ("test finished\n");
|
||||
|
||||
exit (0);
|
||||
tm.tm_year -= TM_YEAR_BASE;
|
||||
tm.tm_mon--;
|
||||
tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
|
||||
tmk = tm;
|
||||
tl = mktime (&tmk);
|
||||
tml = *localtime (&tl);
|
||||
printf ("mktime returns %ld == ", (long) tl);
|
||||
print_tm (&tmk);
|
||||
printf ("\n");
|
||||
status = check_result (tl, tmk, tl, tml);
|
||||
}
|
||||
|
||||
if (argc != 2)
|
||||
else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
|
||||
{
|
||||
printf ("wrong # of args\n");
|
||||
exit (0);
|
||||
time_t from = atol (argv[1]);
|
||||
time_t by = atol (argv[2]);
|
||||
time_t to = atol (argv[3]);
|
||||
|
||||
if (argc == 4)
|
||||
for (tl = from; tl <= to; tl += by)
|
||||
{
|
||||
tml = *localtime (&tl);
|
||||
tmk = tml;
|
||||
tk = mktime (&tmk);
|
||||
status |= check_result (tk, tmk, tl, tml);
|
||||
}
|
||||
else
|
||||
for (tl = from; tl <= to; tl += by)
|
||||
{
|
||||
/* Null benchmark. */
|
||||
tml = *localtime (&tl);
|
||||
tmk = tml;
|
||||
tk = tl;
|
||||
status |= check_result (tk, tmk, tl, tml);
|
||||
}
|
||||
}
|
||||
|
||||
debugging_enabled = 1; /* We want to see the info */
|
||||
else
|
||||
printf ("Usage:\
|
||||
\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
|
||||
\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
|
||||
\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
|
||||
argv[0], argv[0], argv[0]);
|
||||
|
||||
++argv;
|
||||
time = atoi (*argv);
|
||||
|
||||
tmptr = localtime ((time_t *) &time);
|
||||
printf ("Localtime tells us that a time_t of %d represents\n ", time);
|
||||
printtm (tmptr);
|
||||
putchar ('\n');
|
||||
|
||||
printf (" Given localtime's return val, mktime returns %d which is\n ",
|
||||
(int) my_mktime (tmptr));
|
||||
printtm (tmptr);
|
||||
putchar ('\n');
|
||||
|
||||
#if 0
|
||||
tmptr->tm_sec -= 20;
|
||||
tmptr->tm_min -= 20;
|
||||
tmptr->tm_hour -= 20;
|
||||
tmptr->tm_mday -= 20;
|
||||
tmptr->tm_mon -= 20;
|
||||
tmptr->tm_year -= 20;
|
||||
tmptr->tm_gmtoff -= 20000; /* This has no effect! */
|
||||
tmptr->tm_zone = NULL; /* Nor does this! */
|
||||
tmptr->tm_isdst = -1;
|
||||
#endif
|
||||
|
||||
tmptr->tm_hour += 1;
|
||||
tmptr->tm_isdst = -1;
|
||||
|
||||
printf ("\n\nchanged ranges: ");
|
||||
printtm (tmptr);
|
||||
putchar ('\n');
|
||||
|
||||
result_time = my_mktime (tmptr);
|
||||
printf ("\nmktime: %d\n", result_time);
|
||||
|
||||
tmptr->tm_isdst = 0;
|
||||
|
||||
printf ("\n\nchanged ranges: ");
|
||||
printtm (tmptr);
|
||||
putchar ('\n');
|
||||
|
||||
result_time = my_mktime (tmptr);
|
||||
printf ("\nmktime: %d\n", result_time);
|
||||
return status;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
compile-command: "gcc -g mktime.c -o mktime -DDEBUG"
|
||||
compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime"
|
||||
End:
|
||||
*/
|
||||
|
||||
@@ -225,7 +225,7 @@ read_filesystem_list (need_fs_type, all_fs)
|
||||
me->me_dev = xatoi (devopt + 4);
|
||||
}
|
||||
else
|
||||
me->me_dev = -1; /* Magic; means not known yet. */
|
||||
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
|
||||
me->me_next = NULL;
|
||||
|
||||
/* Add to the linked list. */
|
||||
@@ -256,7 +256,7 @@ read_filesystem_list (need_fs_type, all_fs)
|
||||
#else
|
||||
me->me_type = fstype_to_string (fsp->f_type);
|
||||
#endif
|
||||
me->me_dev = -1; /* Magic; means not known yet. */
|
||||
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
|
||||
me->me_next = NULL;
|
||||
|
||||
/* Add to the linked list. */
|
||||
@@ -317,7 +317,7 @@ read_filesystem_list (need_fs_type, all_fs)
|
||||
me->me_devname = xstrdup (stats[counter].f_mntfromname);
|
||||
me->me_mountdir = xstrdup (stats[counter].f_mntonname);
|
||||
me->me_type = mnt_names[stats[counter].f_type];
|
||||
me->me_dev = -1; /* Magic; means not known yet. */
|
||||
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
|
||||
me->me_next = NULL;
|
||||
|
||||
/* Add to the linked list. */
|
||||
@@ -350,7 +350,7 @@ read_filesystem_list (need_fs_type, all_fs)
|
||||
strcpy (me->me_devname + 5, mnt.mt_dev);
|
||||
#endif
|
||||
me->me_mountdir = xstrdup (mnt.mt_filsys);
|
||||
me->me_dev = -1; /* Magic; means not known yet. */
|
||||
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
|
||||
me->me_type = "";
|
||||
#ifdef GETFSTYP /* SVR3. */
|
||||
if (need_fs_type)
|
||||
@@ -384,7 +384,7 @@ read_filesystem_list (need_fs_type, all_fs)
|
||||
me->me_devname = xstrdup ( (*ent)->mt_resource);
|
||||
me->me_mountdir = xstrdup( (*ent)->mt_directory);
|
||||
me->me_type = xstrdup ((*ent)->mt_fstype);
|
||||
me->me_dev = -1; /* Magic; means not known yet. */
|
||||
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
|
||||
me->me_next = NULL;
|
||||
|
||||
/* Add to the linked list. */
|
||||
@@ -412,7 +412,7 @@ read_filesystem_list (need_fs_type, all_fs)
|
||||
me->me_devname = xstrdup (mnt.mnt_special);
|
||||
me->me_mountdir = xstrdup (mnt.mnt_mountp);
|
||||
me->me_type = xstrdup (mnt.mnt_fstype);
|
||||
me->me_dev = -1; /* Magic; means not known yet. */
|
||||
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
|
||||
me->me_next = NULL;
|
||||
|
||||
/* Add to the linked list. */
|
||||
@@ -464,7 +464,7 @@ read_filesystem_list (need_fs_type, all_fs)
|
||||
}
|
||||
me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
|
||||
me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
|
||||
me->me_dev = -1; /* vmt_fsid might be the info we want. */
|
||||
me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
|
||||
me->me_next = NULL;
|
||||
|
||||
/* Add to the linked list. */
|
||||
|
||||
146
lib/regex.c
146
lib/regex.c
@@ -264,7 +264,8 @@ char *alloca ();
|
||||
|
||||
/* Define how to allocate the failure stack. */
|
||||
|
||||
#ifdef REL_ALLOC
|
||||
#if defined (REL_ALLOC) && defined (REGEX_MALLOC)
|
||||
|
||||
#define REGEX_ALLOCATE_STACK(size) \
|
||||
r_alloc (&failure_stack_ptr, (size))
|
||||
#define REGEX_REALLOCATE_STACK(source, osize, nsize) \
|
||||
@@ -272,7 +273,7 @@ char *alloca ();
|
||||
#define REGEX_FREE_STACK(ptr) \
|
||||
r_alloc_free (&failure_stack_ptr)
|
||||
|
||||
#else /* not REL_ALLOC */
|
||||
#else /* not using relocating allocator */
|
||||
|
||||
#ifdef REGEX_MALLOC
|
||||
|
||||
@@ -290,7 +291,7 @@ char *alloca ();
|
||||
#define REGEX_FREE_STACK(arg)
|
||||
|
||||
#endif /* not REGEX_MALLOC */
|
||||
#endif /* not REL_ALLOC */
|
||||
#endif /* not using relocating allocator */
|
||||
|
||||
|
||||
/* True if `size1' is non-NULL and PTR is pointing anywhere inside
|
||||
@@ -1156,29 +1157,30 @@ typedef struct
|
||||
/* Push the info, starting with the registers. */ \
|
||||
DEBUG_PRINT1 ("\n"); \
|
||||
\
|
||||
for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
|
||||
this_reg++) \
|
||||
{ \
|
||||
DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \
|
||||
DEBUG_STATEMENT (num_regs_pushed++); \
|
||||
if (!(RE_NO_POSIX_BACKTRACKING & bufp->syntax)) \
|
||||
for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
|
||||
this_reg++) \
|
||||
{ \
|
||||
DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \
|
||||
DEBUG_STATEMENT (num_regs_pushed++); \
|
||||
\
|
||||
DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
|
||||
PUSH_FAILURE_POINTER (regstart[this_reg]); \
|
||||
\
|
||||
DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
|
||||
PUSH_FAILURE_POINTER (regend[this_reg]); \
|
||||
DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
|
||||
PUSH_FAILURE_POINTER (regstart[this_reg]); \
|
||||
\
|
||||
DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \
|
||||
DEBUG_PRINT2 (" match_null=%d", \
|
||||
REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \
|
||||
DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \
|
||||
DEBUG_PRINT2 (" matched_something=%d", \
|
||||
MATCHED_SOMETHING (reg_info[this_reg])); \
|
||||
DEBUG_PRINT2 (" ever_matched=%d", \
|
||||
EVER_MATCHED_SOMETHING (reg_info[this_reg])); \
|
||||
DEBUG_PRINT1 ("\n"); \
|
||||
PUSH_FAILURE_ELT (reg_info[this_reg].word); \
|
||||
} \
|
||||
DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
|
||||
PUSH_FAILURE_POINTER (regend[this_reg]); \
|
||||
\
|
||||
DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \
|
||||
DEBUG_PRINT2 (" match_null=%d", \
|
||||
REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \
|
||||
DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \
|
||||
DEBUG_PRINT2 (" matched_something=%d", \
|
||||
MATCHED_SOMETHING (reg_info[this_reg])); \
|
||||
DEBUG_PRINT2 (" ever_matched=%d", \
|
||||
EVER_MATCHED_SOMETHING (reg_info[this_reg])); \
|
||||
DEBUG_PRINT1 ("\n"); \
|
||||
PUSH_FAILURE_ELT (reg_info[this_reg].word); \
|
||||
} \
|
||||
\
|
||||
DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\
|
||||
PUSH_FAILURE_INT (lowest_active_reg); \
|
||||
@@ -1215,9 +1217,11 @@ typedef struct
|
||||
#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
|
||||
|
||||
/* We actually push this many items. */
|
||||
#define NUM_FAILURE_ITEMS \
|
||||
((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \
|
||||
+ NUM_NONREG_ITEMS)
|
||||
#define NUM_FAILURE_ITEMS \
|
||||
(((RE_NO_POSIX_BACKTRACKING & bufp->syntax \
|
||||
? 0 : highest_active_reg - lowest_active_reg + 1) \
|
||||
* NUM_REG_ITEMS) \
|
||||
+ NUM_NONREG_ITEMS)
|
||||
|
||||
/* How many items can still be added to the stack without overflowing it. */
|
||||
#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
|
||||
@@ -1275,18 +1279,29 @@ typedef struct
|
||||
low_reg = (unsigned) POP_FAILURE_INT (); \
|
||||
DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \
|
||||
\
|
||||
for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \
|
||||
if (!(RE_NO_POSIX_BACKTRACKING & bufp->syntax)) \
|
||||
for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \
|
||||
{ \
|
||||
DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \
|
||||
\
|
||||
reg_info[this_reg].word = POP_FAILURE_ELT (); \
|
||||
DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \
|
||||
\
|
||||
regend[this_reg] = (const char *) POP_FAILURE_POINTER (); \
|
||||
DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
|
||||
\
|
||||
regstart[this_reg] = (const char *) POP_FAILURE_POINTER (); \
|
||||
DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \
|
||||
\
|
||||
reg_info[this_reg].word = POP_FAILURE_ELT (); \
|
||||
DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \
|
||||
\
|
||||
regend[this_reg] = (const char *) POP_FAILURE_POINTER (); \
|
||||
DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
|
||||
\
|
||||
regstart[this_reg] = (const char *) POP_FAILURE_POINTER (); \
|
||||
DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
|
||||
for (this_reg = highest_active_reg; this_reg > high_reg; this_reg--) \
|
||||
{ \
|
||||
reg_info[this_reg].word = 0; \
|
||||
regend[this_reg] = 0; \
|
||||
regstart[this_reg] = 0; \
|
||||
} \
|
||||
highest_active_reg = high_reg; \
|
||||
} \
|
||||
\
|
||||
set_regs_matched_done = 0; \
|
||||
@@ -1364,11 +1379,13 @@ static reg_errcode_t compile_range ();
|
||||
if necessary. Also cast from a signed character in the constant
|
||||
string passed to us by the user to an unsigned char that we can use
|
||||
as an array index (in, e.g., `translate'). */
|
||||
#ifndef PATFETCH
|
||||
#define PATFETCH(c) \
|
||||
do {if (p == pend) return REG_EEND; \
|
||||
c = (unsigned char) *p++; \
|
||||
if (translate) c = translate[c]; \
|
||||
if (translate) c = (unsigned char) translate[c]; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* Fetch the next character in the uncompiled pattern, with no
|
||||
translation. */
|
||||
@@ -1385,7 +1402,10 @@ static reg_errcode_t compile_range ();
|
||||
cast the subscript to translate because some data is declared as
|
||||
`char *', to avoid warnings when a string constant is passed. But
|
||||
when we use a character as a subscript we must make it unsigned. */
|
||||
#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
|
||||
#ifndef TRANSLATE
|
||||
#define TRANSLATE(d) \
|
||||
(translate ? (char) translate[(unsigned char) (d)] : (d))
|
||||
#endif
|
||||
|
||||
|
||||
/* Macros for outputting the compiled pattern into `buffer'. */
|
||||
@@ -1651,7 +1671,7 @@ regex_compile (pattern, size, syntax, bufp)
|
||||
const char *pend = pattern + size;
|
||||
|
||||
/* How to translate the characters in the pattern. */
|
||||
char *translate = bufp->translate;
|
||||
RE_TRANSLATE_TYPE translate = bufp->translate;
|
||||
|
||||
/* Address of the count-byte of the most recently inserted `exactn'
|
||||
command. This makes it possible to tell if a new exact-match
|
||||
@@ -2817,7 +2837,7 @@ group_in_compile_stack (compile_stack, regnum)
|
||||
static reg_errcode_t
|
||||
compile_range (p_ptr, pend, translate, syntax, b)
|
||||
const char **p_ptr, *pend;
|
||||
char *translate;
|
||||
RE_TRANSLATE_TYPE translate;
|
||||
reg_syntax_t syntax;
|
||||
unsigned char *b;
|
||||
{
|
||||
@@ -3037,7 +3057,7 @@ re_compile_fastmap (bufp)
|
||||
case at_dot:
|
||||
case after_dot:
|
||||
continue;
|
||||
#endif /* not emacs */
|
||||
#endif /* emacs */
|
||||
|
||||
|
||||
case no_op:
|
||||
@@ -3251,7 +3271,7 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
|
||||
{
|
||||
int val;
|
||||
register char *fastmap = bufp->fastmap;
|
||||
register char *translate = bufp->translate;
|
||||
register RE_TRANSLATE_TYPE translate = bufp->translate;
|
||||
int total_size = size1 + size2;
|
||||
int endpos = startpos + range;
|
||||
|
||||
@@ -3260,9 +3280,10 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
|
||||
return -1;
|
||||
|
||||
/* Fix up RANGE if it might eventually take us outside
|
||||
the virtual concatenation of STRING1 and STRING2. */
|
||||
if (endpos < -1)
|
||||
range = -1 - startpos;
|
||||
the virtual concatenation of STRING1 and STRING2.
|
||||
Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE. */
|
||||
if (endpos < 0)
|
||||
range = 0 - startpos;
|
||||
else if (endpos > total_size)
|
||||
range = total_size - startpos;
|
||||
|
||||
@@ -3276,6 +3297,17 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
|
||||
range = 1;
|
||||
}
|
||||
|
||||
#ifdef emacs
|
||||
/* In a forward search for something that starts with \=.
|
||||
don't keep searching past point. */
|
||||
if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0)
|
||||
{
|
||||
range = PT - startpos;
|
||||
if (range <= 0)
|
||||
return -1;
|
||||
}
|
||||
#endif /* emacs */
|
||||
|
||||
/* Update the fastmap now if not correct already. */
|
||||
if (fastmap && !bufp->fastmap_accurate)
|
||||
if (re_compile_fastmap (bufp) == -2)
|
||||
@@ -3527,7 +3559,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
|
||||
unsigned char *just_past_start_mem = 0;
|
||||
|
||||
/* We use this to map every character in the string. */
|
||||
char *translate = bufp->translate;
|
||||
RE_TRANSLATE_TYPE translate = bufp->translate;
|
||||
|
||||
/* Failure point stack. Each place that can handle a failure further
|
||||
down the line pushes a failure point on this stack. It consists of
|
||||
@@ -3928,7 +3960,8 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
|
||||
do
|
||||
{
|
||||
PREFETCH ();
|
||||
if (translate[(unsigned char) *d++] != (char) *p++)
|
||||
if ((unsigned char) translate[(unsigned char) *d++]
|
||||
!= (unsigned char) *p++)
|
||||
goto fail;
|
||||
}
|
||||
while (--mcnt);
|
||||
@@ -4342,7 +4375,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
|
||||
for that group and all inner ones, so that if we fail back
|
||||
to this point, the group's information will be correct.
|
||||
For example, in \(a*\)*\1, we need the preceding group,
|
||||
and in \(\(a*\)b*\)\2, we need the inner group. */
|
||||
and in \(zz\(a*\)b*\)\2, we need the inner group. */
|
||||
|
||||
/* We can't use `p' to check ahead because we push
|
||||
a failure point to `p + mcnt' after we do this. */
|
||||
@@ -4681,13 +4714,6 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
|
||||
if (PTR_CHAR_POS ((unsigned char *) d) <= point)
|
||||
goto fail;
|
||||
break;
|
||||
#if 0 /* not emacs19 */
|
||||
case at_dot:
|
||||
DEBUG_PRINT1 ("EXECUTING at_dot.\n");
|
||||
if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
|
||||
goto fail;
|
||||
break;
|
||||
#endif /* not emacs19 */
|
||||
|
||||
case syntaxspec:
|
||||
DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
|
||||
@@ -5057,7 +5083,7 @@ static int
|
||||
bcmp_translate (s1, s2, len, translate)
|
||||
unsigned char *s1, *s2;
|
||||
register int len;
|
||||
char *translate;
|
||||
RE_TRANSLATE_TYPE translate;
|
||||
{
|
||||
register unsigned char *p1 = s1, *p2 = s2;
|
||||
while (len)
|
||||
@@ -5229,7 +5255,9 @@ regcomp (preg, pattern, cflags)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
preg->translate = (char *) malloc (CHAR_SET_SIZE);
|
||||
preg->translate
|
||||
= (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE
|
||||
* sizeof (*(RE_TRANSLATE_TYPE)0));
|
||||
if (preg->translate == NULL)
|
||||
return (int) REG_ESPACE;
|
||||
|
||||
|
||||
@@ -279,6 +279,10 @@ typedef enum
|
||||
compiled, the `re_nsub' field is available. All other fields are
|
||||
private to the regex routines. */
|
||||
|
||||
#ifndef RE_TRANSLATE_TYPE
|
||||
#define RE_TRANSLATE_TYPE char *
|
||||
#endif
|
||||
|
||||
struct re_pattern_buffer
|
||||
{
|
||||
/* [[[begin pattern_buffer]]] */
|
||||
@@ -305,7 +309,7 @@ struct re_pattern_buffer
|
||||
comparing them, or zero for no translation. The translation
|
||||
is applied to a pattern when it is compiled and to a string
|
||||
when it is matched. */
|
||||
char *translate;
|
||||
RE_TRANSLATE_TYPE translate;
|
||||
|
||||
/* Number of subexpressions found by the compiler. */
|
||||
size_t re_nsub;
|
||||
|
||||
39
lib/strpbrk.c
Normal file
39
lib/strpbrk.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/* Copyright (C) 1991, 1994 Free Software Foundation, Inc.
|
||||
NOTE: The canonical source of this file is maintained with the GNU C Library.
|
||||
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
|
||||
|
||||
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
/* Find the first ocurrence in S of any character in ACCEPT. */
|
||||
char *
|
||||
strpbrk (s, accept)
|
||||
register const char *s;
|
||||
register const char *accept;
|
||||
{
|
||||
while (*s != '\0')
|
||||
{
|
||||
const char *a = accept;
|
||||
while (*a != '\0')
|
||||
if (*a++ == *s)
|
||||
return (char *) s;
|
||||
++s;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -63,9 +63,12 @@ struct group *getgrnam ();
|
||||
struct group *getgrgid ();
|
||||
#endif
|
||||
|
||||
#ifdef _POSIX_SOURCE
|
||||
#define endpwent()
|
||||
#define endgrent()
|
||||
#ifndef HAVE_ENDGRENT
|
||||
# define endgrent() ((void) 0)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ENDPWENT
|
||||
# define endpwent() ((void) 0)
|
||||
#endif
|
||||
|
||||
/* Perform the equivalent of the statement `dest = strdup (src);',
|
||||
|
||||
@@ -24,15 +24,15 @@ extern int errno;
|
||||
#endif
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#ifndef ULONG_MAX
|
||||
#define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
|
||||
# define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
|
||||
#endif
|
||||
|
||||
#ifndef LONG_MAX
|
||||
#define LONG_MAX ((long int) (ULONG_MAX >> 1))
|
||||
# define LONG_MAX ((long int) (ULONG_MAX >> 1))
|
||||
#endif
|
||||
|
||||
#include "xstrtol.h"
|
||||
|
||||
@@ -1,3 +1,109 @@
|
||||
Wed Nov 1 23:11:05 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* cp.c (copy): Use euidaccess instead of euidaccess_stat.
|
||||
* mv.c (do_move): Likewise.
|
||||
* rm.c (remove_file, remove_dir): Likewise.
|
||||
|
||||
Sun Oct 29 06:06:13 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* aclocal.m4 (jm_WITH_AUTODEPS): New directive.
|
||||
* configure.in: Use it.
|
||||
|
||||
* lib/Makefile.in (INCLUDE, COMPILE): New variables.
|
||||
(.c.o): Rewrite to be more like src/Makefile.in.
|
||||
Add line that (--with-autodeps) will include mkdep-Makefile.
|
||||
(distclean): Remove .deps.
|
||||
* src/Makefile.in: Likewise.
|
||||
|
||||
* src/Makefile.in (test.o): Remove special rule.
|
||||
|
||||
* mkdep-Makefile: New file.
|
||||
* Makefile.in (DISTFILES): Add mkdep-Makefile.
|
||||
|
||||
* doc/Makefile.in (mostlyclean): Remove *.info.
|
||||
|
||||
* touch.c: Change long option name `--file' to `--reference'.
|
||||
Leave --file as an alias, for now. It will be removed later.
|
||||
(usage): Reflect option name change. From Franc,ois Pinard.
|
||||
|
||||
Wed Oct 18 23:09:55 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* configure.in (AC_CHECK_HEADERS): Add sys/wait.h and sys/ioctl.h.
|
||||
(AC_CHECK_FUNCS): Add endpwent.
|
||||
|
||||
* fileblocks.c: Use _POSIX_VERSION, not _POSIX_SOURCE.
|
||||
|
||||
* userspec.c [endgrent]: Test !HAVE_ENDGRENT rather than _POSIX_SOURCE.
|
||||
[endpwent]: Test !HAVE_ENDPWENT rather than _POSIX_SOURCE.
|
||||
|
||||
* chgrp.c [endgrent]: Test !HAVE_ENDGRENT rather than _POSIX_SOURCE.
|
||||
|
||||
* chown.c [endpwent]: Test !HAVE_ENDPWENT rather than _POSIX_SOURCE.
|
||||
[endgrent]: Remove unused definition.
|
||||
|
||||
* df.c (main): Fail if the same file system type was both selected
|
||||
and excluded. Reported by Paul Close pdc@lunch.engr.sgi.com.
|
||||
|
||||
* rm.c (duplicate_entry): Always return 0 if !D_INO_IN_DIRENT,
|
||||
rather than if _POSIX_SOURCE.
|
||||
|
||||
* install.c: Use HAVE_SYS_WAIT_H, not _POSIX_VERSION in conditional
|
||||
inclusion of sys/wait.h.
|
||||
[endgrent]: Test !HAVE_ENDGRENT rather than _POSIX_SOURCE.
|
||||
[endpwent]: Test !HAVE_ENDPWENT rather than _POSIX_SOURCE.
|
||||
|
||||
* ls.c Use HAVE_SYS_IOCTL_H, rather than !_POSIX_SOURCE || _AIX.
|
||||
|
||||
Thu Oct 5 21:49:34 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* configure.in (HAVE_STRUCT_UTIMBUF): Add new test. Testing for
|
||||
the existence of <utime.h> is insufficient on some Next systems.
|
||||
* acconfig.h (HAVE_STRUCT_UTIMBUF): Add it.
|
||||
* system.h [!HAVE_UTIME_H]: Don't declare struct utimbuf here.
|
||||
[!HAVE_STRUCT_UTIMBUF]: Declare struct utimbuf here instead.
|
||||
|
||||
* chgrp.c: Include limits.h.
|
||||
[!INT_MAX]: Define it.
|
||||
|
||||
* df.c (show_point): Cast -2 to dev_t before assignment.
|
||||
* mountlist.c (read_filesystem_list): Cast -1 to dev_t before
|
||||
assignment.
|
||||
|
||||
Sun Oct 1 13:22:36 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* configure.in (AC_REPLACE_FUNCS): Add strtoul.
|
||||
* strtoul.c: New file.
|
||||
* lib/Makefile.in (SOURCES): Add strtoul.c.
|
||||
|
||||
* acconfig.h (STATFS_TRUNCATES_BLOCK_COUNTS): Add it.
|
||||
* configure.in (STATFS_TRUNCATES_BLOCK_COUNTS): New check to enable
|
||||
workaround for SunOS statfs brokenness. Block counts in struct
|
||||
statfs for partitions 2GB and larger are truncated, but correct
|
||||
values are stored in f_spare array member.
|
||||
|
||||
* fsusage.c (get_fs_usage) [STATFS_TRUNCATES_BLOCK_COUNTS]: Copy
|
||||
untruncated block counts from f_spare array into proper members
|
||||
of struct statfs. From Eirik Fuller (eirik@netapp.com);
|
||||
|
||||
* ls.c (dired_dump_obstack): Don't generate any output if the
|
||||
obstack is empty.
|
||||
(main): Always initialize and dump subdired_obstack, not just if -R.
|
||||
`ls -lDR dir dir2' was using uninitialized subdired_obstack.
|
||||
Reported by Samuli K{rkk{inen <hskarkka@snakemail.hut.fi>.
|
||||
|
||||
Tue Sep 26 23:05:01 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* man/Makefile.in (install-data, uninstall): Use sed not basename.
|
||||
The GNU Coding Standard suggests that only a select set of
|
||||
relatively standard utilities be used in Makefiles. basename is
|
||||
not among them. Suggested by Ulrich Drepper.
|
||||
|
||||
Mon Sep 25 23:12:37 1995 Jim Meyering <meyering@gremlin.comco.com>
|
||||
|
||||
* src/df.c (show_point): Ignore mtab entries with either
|
||||
nonexistent mount points or with inconsistent device number.
|
||||
From Eirik Fuller <eirik@synopsys.com>.
|
||||
|
||||
Wed Aug 9 00:33:05 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* mknod.c (my_strtol): Remove function.
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
User-visible changes in release 3.13:
|
||||
* rename touch long option name --file to --reference.
|
||||
`touch --file' will continue to work a little longer.
|
||||
* df fails if the same file system type is both selected and excluded.
|
||||
* df works around SunOS statfs brokenness wrt filesystems larger than 2GB
|
||||
* df better handles inconsistent mtab entries
|
||||
* `ls -lDR dir dir2' works
|
||||
* `ls -c' does what it's supposed to
|
||||
* all programs include program name in --version output
|
||||
* `ls --quote-name' works
|
||||
* mv properly determines whether src and dest are the same file
|
||||
Before, it could (though with very low probability) fail to do the move,
|
||||
reporting that distinct source and destination are the same file.
|
||||
* du --dereference (-L) works with directory symlinks
|
||||
* du works on SunOS 4 systems even when accounting is enabled
|
||||
* many programs that convert strings to integers now use strtol or strtoul
|
||||
and detect overflow
|
||||
User-visible changes in release 3.12:
|
||||
* None.
|
||||
User-visible changes in release 3.11:
|
||||
@@ -52,7 +69,7 @@ Major changes in release 3.9:
|
||||
They used to succeed, ignoring the implicitly contradictory trailing slash.
|
||||
|
||||
Major changes in release 3.8:
|
||||
* install isn't as likely to produce spurious errors
|
||||
* install isn't as likely to produce spurious errors
|
||||
* avoid redundant compilations for `dir' and `vdir';
|
||||
* configure properly defines STAT_STATFS2_BSIZE on a Pyramid MIServer
|
||||
running OSx 5.1
|
||||
@@ -78,7 +95,7 @@ Major changes in release 3.5:
|
||||
|
||||
Major changes in release 3.4:
|
||||
* cp -p and mv preserve setuid and setgid bits
|
||||
* chown works on systems where sizeof(uid_t) != sizeof(int)
|
||||
* chown works on systems where sizeof(uid_t) != sizeof(int)
|
||||
or sizeof(uid) != sizeof(gid)
|
||||
* catch errors from spurious slashes at ends of arguments
|
||||
|
||||
|
||||
@@ -1,3 +1,40 @@
|
||||
Sun Oct 29 08:47:50 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* test.c [TEST_STANDALONE]: Define.
|
||||
* src/Makefile.in (test.o): Remove special rule.
|
||||
|
||||
Sat Oct 28 00:49:13 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* aclocal.m4 (jm_WITH_AUTODEPS): New directive.
|
||||
* configure.in: Use it.
|
||||
|
||||
* lib/Makefile.in (INCLUDE, COMPILE): New variables.
|
||||
(.c.o): Rewrite to be more like src/Makefile.in.
|
||||
Add line that (--with-autodeps) will include mkdep-Makefile.
|
||||
(distclean): Remove .deps.
|
||||
* src/Makefile.in: Likewise.
|
||||
|
||||
* mkdep-Makefile: New file.
|
||||
* Makefile.in (DISTFILES): Add mkdep-Makefile.
|
||||
|
||||
* doc/Makefile.in (mostlyclean): Remove *.info.
|
||||
|
||||
* date.c: New option --reference=FILE (-r FILE) analogous to the
|
||||
like-named touch option.
|
||||
(main): Recognize it and give diagnostic for misuse.
|
||||
(usage): Describe briefly.
|
||||
From Franc,ois Pinard.
|
||||
|
||||
* date.c (batch_convert): Close input stream also when it's not stdin.
|
||||
(main): Reorganize to do option-consistency checks before all else.
|
||||
|
||||
Tue Sep 26 23:05:01 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* man/Makefile.in (install-data, uninstall): Use sed not basename.
|
||||
The GNU Coding Standard suggests that only a select set of
|
||||
relatively standard utilities be used in Makefiles. basename is
|
||||
not among them. Suggested by Ulrich Drepper.
|
||||
|
||||
Tue Aug 8 22:57:34 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* yes.c: Include system.h to get definition of _.
|
||||
|
||||
@@ -1,3 +1,204 @@
|
||||
* unexpand.c: Reorder functions to obviate forward dcls. Remove
|
||||
forward dcls. Protoize. Add `const' attribute to some parameters.
|
||||
|
||||
Mon Oct 30 23:15:56 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* wc.c: Reorder functions to obviate forward dcls. Remove
|
||||
forward dcls. Protoize. Add `const' attribute to some parameters.
|
||||
* uniq.c: Likewise.
|
||||
* split.c: Likewise.
|
||||
|
||||
* split.c (isdigits, convint): Remove these.
|
||||
(main): Use xstrtol instead.
|
||||
|
||||
Sun Oct 29 14:04:36 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* paste.c (main): Move function body to end of file.
|
||||
Remove forward dcls and protoize.
|
||||
* sum.c (main): Likewise.
|
||||
* nl.c: Protoize. Reorder functions to obviate forward dcls.
|
||||
Remove forward dcls.
|
||||
* tac.c: Likewise.
|
||||
* src/Makefile.in (OBJECTS): Reflect that all of the above
|
||||
now use prototypes.
|
||||
|
||||
* sum.c (bsd_sum_file): Give file name parameter const attribute.
|
||||
(sysv_sum_file): Likewise.
|
||||
|
||||
* tac.c (xwrite): Give output buffer parameter const attribute.
|
||||
(output): Likewise for both parameters.
|
||||
(tac): Likewise for file name parameter.
|
||||
(tac_file): Likewise.
|
||||
|
||||
Sat Oct 28 16:02:39 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* md5sum.c (md5_check): Use the same message format when there is
|
||||
a single file and it gets a read error or checksum mismatch as when
|
||||
there are more. Suggestion from Greg Troxel (gdt@b-sgi.bbn.com).
|
||||
|
||||
Thu Oct 26 00:11:35 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* sort.c (xtmpfopen): New function to set proper permissions on
|
||||
temporary files. Use it instead of xfopen. Reported by Erik Corry
|
||||
(erik@kroete2.freinet.de).
|
||||
|
||||
Mon Oct 23 23:17:04 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* aclocal.m4 (jm_WITH_AUTODEPS): New directive.
|
||||
* configure.in: Use it.
|
||||
|
||||
* lib/Makefile.in (INCLUDE, COMPILE): New variables.
|
||||
(.c.o): Rewrite to be more like src/Makefile.in.
|
||||
|
||||
* src/Makefile.in (distclean): Remove .deps.
|
||||
Include @top_srcdir@/mkdep-Makefile.
|
||||
|
||||
* mkdep.Makefile: New file.
|
||||
* Makefile.in (DISTFILES): Add mkdep-Makefile.
|
||||
* doc/Makefile.in (mostlyclean): Also remove *.info.
|
||||
|
||||
Thu Oct 19 17:38:28 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* od.c: Indent cpp directives.
|
||||
|
||||
* tr.c (BEGIN_STATE): Use INT_MAX - 1 so as not to interfere
|
||||
with large repeat counts.
|
||||
(struct E_string): New struct.
|
||||
(find_closing_delim): Take E_string arg rather than char* and length.
|
||||
(find_bracketed_repeat): Likewise.
|
||||
(star_digits_closebracket): New function.
|
||||
(append_char_class): No longer give diagnostic.
|
||||
(append_equiv_class): Likewise.
|
||||
(build_spec_list): Give them here instead, allowing string1 like
|
||||
[:*][:upper:] that got errors before.
|
||||
Take E_string arg rather than char*.
|
||||
Convert switch stmts into if-then so as to use ES_MATCH.
|
||||
|
||||
Tue Oct 17 22:48:00 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* cat.c: Protoize. Reorder functions to obviate forward dcls.
|
||||
Remove forward dcls.
|
||||
* expand.c: Likewise.
|
||||
* fold.c: Likewise.
|
||||
* head.c: Likewise.
|
||||
* od.c: Likewise.
|
||||
* sort.c: Likewise.
|
||||
* tail.c: Likewise.
|
||||
|
||||
* src/Makefile.in (OBJECTS): Reflect that all of the above
|
||||
now use prototypes.
|
||||
|
||||
* head.c: Add `const' attribute to dcls of lots of formals.
|
||||
|
||||
* sort.c: Add `const' attribute to dcls of lots of formals.
|
||||
Move struct dcls to precede dcls of file-scope variables.
|
||||
(monthtab, keyhead): Separate variable dcls from type dcls.
|
||||
|
||||
Fri Oct 13 20:38:39 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* join.c (add_field_list): Allow SPACE and TAB as well as `,' as
|
||||
list item separators, per POSIX spec.
|
||||
(prjoin): Rewrite loop that iterates over field specs.
|
||||
Handle case in which file spec is 0.
|
||||
|
||||
Sun Oct 8 22:41:15 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* strpbrk.c: New file.
|
||||
* lib/Makefile.in (SOURCES): Add strpbrk.c.
|
||||
Remove bcopy.c.
|
||||
|
||||
Sat Oct 7 22:27:01 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* join.c (add_field): No longer return a value.
|
||||
(decode_field_spec): New function.
|
||||
(add_field_list): Rewrite to be more strict.
|
||||
Before, `,1.2' was accepted as valid.
|
||||
(main): Use xstrtol instead atoi.
|
||||
Combine nearly identical -a and -v cases.
|
||||
Close input files.
|
||||
|
||||
Fri Oct 6 23:10:01 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* join.c (main): Report `too few/many non-option arguments'
|
||||
then print --help output rather than just the latter.
|
||||
Properly interpret obsolescent usage like `join -o 2.1 2.1 2.2'.
|
||||
(usage): Describe POSIX -1, -2 options and deprecate -j* ones
|
||||
|
||||
* join.c (usage): Move to precede all other functions.
|
||||
|
||||
* join.c: Protoize.
|
||||
|
||||
Tue Oct 3 22:44:05 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* csplit.c, sort.c, tac.c: Test SA_INTERRUPT, not _POSIX_VERSION,
|
||||
to determine whether `sigaction' functions are available.
|
||||
Reported by Paul Nevai <nevai@ops.mps.ohio-state.edu>.
|
||||
Fix suggested by Karl Berry.
|
||||
|
||||
* md5sum.c (main): Declare counter, N_STRINGS, to be an integral
|
||||
type, not `char'.
|
||||
|
||||
* cut.c: Convert many declarations using `int' to use `unsigned int'
|
||||
to avoid warnings from `gcc -Wall' about comparing signed and
|
||||
unsigned types.
|
||||
(set_fields): Use memset (not open coded loop) to initialize array.
|
||||
|
||||
Thu Sep 28 23:16:05 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* Version 1.13.
|
||||
|
||||
* Makefile.in (DISTFILES): Remove README.alpha for major release.
|
||||
|
||||
* od.c (decode_one_format): Remove spurious semicolon.
|
||||
From John Kodis (kodis@daacdev1.stx.com).
|
||||
|
||||
Tue Sep 26 23:05:01 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* man/Makefile.in (install-data, uninstall): Use sed not basename.
|
||||
The GNU Coding Standard suggests that only a select set of
|
||||
relatively standard utilities be used in Makefiles. basename is
|
||||
not among them. Suggested by Ulrich Drepper.
|
||||
|
||||
Sun Sep 24 08:36:47 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* cksum.c: Protoize.
|
||||
* cut.c: Protoize.
|
||||
|
||||
* src/Makefile.in (OBJECTS): Reflect that cksum.c and cut.c use
|
||||
prototypes.
|
||||
(cksum): Depend on cksum$O.
|
||||
(cut): Depend on cut$O.
|
||||
|
||||
Sat Sep 23 15:43:46 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* Version 1.12.2.
|
||||
|
||||
* Makefile.in (DISTFILES): Add README.alpha.
|
||||
|
||||
* lib/Makfile.in: (GETOPT, MEMCHR, REGEX): New variables.
|
||||
(OBJECTS): Use them instead of hardcoding object file names.
|
||||
Suggested by Ulrich Drepper.
|
||||
|
||||
* md5sum.c (md5_check): Distinguish between open/read failure
|
||||
and checksum mismatch.
|
||||
|
||||
Mon Sep 18 23:15:05 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* md5sum.c: Protoize.
|
||||
* src/Makefile.in (OBJECTS): Change md5sum.o to md5sum$O.
|
||||
(join.o, md5sum$O, sort.o) Depend on ../lib/long-options.h.
|
||||
(md5sum): Depend on md5sum$O.
|
||||
|
||||
* md5sum.c (main, usage): Remove -h, -s, -v short options.
|
||||
Rename --verbose to --warn, --quiet to --status.
|
||||
(main): Handle --help and --version using parse_long_options.
|
||||
(md5_check): Check ferror.
|
||||
|
||||
* sort.c (tempname): Replace `16' with a more readable expansion.
|
||||
Make sure that counter never exceeds 99999.
|
||||
(checkfp): Rearrange loop to avoid duplicate test.
|
||||
Move a couple dcls from function scope into inner block.
|
||||
|
||||
Tue Aug 8 21:49:27 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* md5sum.c (main): Fail if either --verbose or --quiet is specified
|
||||
@@ -5,7 +206,7 @@ Tue Aug 8 21:49:27 1995 Jim Meyering (meyering@comco.com)
|
||||
|
||||
* md5sum.c (md5_check): Fail if no valid line is found.
|
||||
Don't use the word `fail' unless there were failures --
|
||||
say `all N tests passed.'
|
||||
instead, say `all N tests passed.'
|
||||
|
||||
* md5sum.c (main) [handling --string option]: Don't output
|
||||
nonstandard `b' binary flag. From Greg Troxel (gdt@bbn.com).
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
User-visible changes in release 1.14
|
||||
* join accepts POSIX `-o 0' field specifier.
|
||||
* tr 'a[b*512]' '[a*]' < /dev/null terminates
|
||||
* tr '[:*3][:digit:]' 'a-m' and tr 'a[=*2][=c=]' 'xyyz' no longer fail
|
||||
* special characters in tr's string1 and string2 may be escaped with backslash
|
||||
User-visible changes in release 1.13
|
||||
* md5sum: with --check, distinguish between open/read failure and bad checksum
|
||||
* md5sum: remove -h, -s, -v short options
|
||||
* md5sum: rename --verbose to --warn, --quiet to --status
|
||||
* md5sum --check fails if it finds no properly formatted checksum lines
|
||||
* sort -c prints `disorder on...' message on standard error, not stdout
|
||||
* sort -k works as described in the texinfo documentation
|
||||
* tail works on NetBSD
|
||||
|
||||
681
src/cat.c
681
src/cat.c
@@ -14,11 +14,11 @@
|
||||
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.
|
||||
* 100 times faster with -v -u.
|
||||
* 20 times faster with -v.
|
||||
* 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. */
|
||||
|
||||
@@ -43,10 +43,6 @@ char *xmalloc ();
|
||||
int full_write ();
|
||||
int safe_read ();
|
||||
|
||||
static void cat ();
|
||||
static void next_line_num ();
|
||||
static void simple_cat ();
|
||||
|
||||
/* Name under which this program was invoked. */
|
||||
char *program_name;
|
||||
|
||||
@@ -80,8 +76,7 @@ static int newlines2 = 0;
|
||||
static int exit_stat = 0;
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
int status;
|
||||
usage (int status)
|
||||
{
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
@@ -114,11 +109,338 @@ With no FILE, or when FILE is -, read standard input.\n\
|
||||
exit (status);
|
||||
}
|
||||
|
||||
|
||||
/* 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);
|
||||
*--line_num_start = '1';
|
||||
if (line_num_start < line_num_print)
|
||||
line_num_print--;
|
||||
}
|
||||
|
||||
/* Plain cat. Copies the file behind `input_desc' to the file behind
|
||||
`output_desc'. */
|
||||
|
||||
static void
|
||||
simple_cat (
|
||||
/* Pointer to the buffer, used by reads and writes. */
|
||||
unsigned 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. */
|
||||
int 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 < 0)
|
||||
{
|
||||
error (0, errno, "%s", infile);
|
||||
exit_stat = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* End of this file? */
|
||||
|
||||
if (n_read == 0)
|
||||
break;
|
||||
|
||||
/* Write this block out. */
|
||||
|
||||
if (full_write (output_desc, buf, n_read) < 0)
|
||||
error (1, 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. */
|
||||
unsigned char *inbuf,
|
||||
|
||||
/* Number of characters read in each read call. */
|
||||
int insize,
|
||||
|
||||
/* Pointer to the beginning of the output buffer. */
|
||||
unsigned char *outbuf,
|
||||
|
||||
/* Number of characters written by each write call. */
|
||||
int 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. */
|
||||
unsigned char *bpin;
|
||||
|
||||
/* Pointer to the first non-valid byte in the input buffer, i.e. the
|
||||
current end of the buffer. */
|
||||
unsigned char *eob;
|
||||
|
||||
/* Pointer to the position where the next character shall be written. */
|
||||
unsigned char *bpout;
|
||||
|
||||
/* Number of characters read by the last read call. */
|
||||
int 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 (bpout - outbuf >= outsize)
|
||||
{
|
||||
unsigned char *wp = outbuf;
|
||||
do
|
||||
{
|
||||
if (full_write (output_desc, wp, outsize) < 0)
|
||||
error (1, errno, _("write error"));
|
||||
wp += outsize;
|
||||
}
|
||||
while (bpout - wp >= outsize);
|
||||
|
||||
/* Move the remaining bytes to the beginning of the
|
||||
buffer. */
|
||||
|
||||
memmove (outbuf, wp, bpout - wp);
|
||||
bpout = outbuf + (bpout - wp);
|
||||
}
|
||||
|
||||
/* 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_stat = 1;
|
||||
newlines2 = newlines;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (n_to_read == 0)
|
||||
#endif
|
||||
{
|
||||
int n_write = bpout - outbuf;
|
||||
|
||||
if (full_write (output_desc, outbuf, n_write) < 0)
|
||||
error (1, errno, _("write error"));
|
||||
bpout = outbuf;
|
||||
}
|
||||
|
||||
/* Read more input into INBUF. */
|
||||
|
||||
n_read = safe_read (input_desc, inbuf, insize);
|
||||
if (n_read < 0)
|
||||
{
|
||||
error (0, errno, "%s", infile);
|
||||
exit_stat = 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)
|
||||
{
|
||||
/* Are multiple adjacent empty lines to be substituted by
|
||||
single ditto (-s), and this was the second empty line? */
|
||||
|
||||
if (squeeze_empty_lines && newlines >= 2)
|
||||
{
|
||||
ch = *bpin++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Are line numbers to be written at empty lines (-n)? */
|
||||
|
||||
if (numbers && numbers_at_empty_lines)
|
||||
{
|
||||
next_line_num ();
|
||||
bpout = (unsigned char *) 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 = (unsigned char *) 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
/* Optimal size of i/o operations of output. */
|
||||
int outsize;
|
||||
@@ -397,336 +719,3 @@ main (argc, argv)
|
||||
|
||||
exit (exit_stat);
|
||||
}
|
||||
|
||||
/* Plain cat. Copies the file behind `input_desc' to the file behind
|
||||
`output_desc'. */
|
||||
|
||||
static void
|
||||
simple_cat (buf, bufsize)
|
||||
/* Pointer to the buffer, used by reads and writes. */
|
||||
unsigned 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. */
|
||||
int 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 < 0)
|
||||
{
|
||||
error (0, errno, "%s", infile);
|
||||
exit_stat = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* End of this file? */
|
||||
|
||||
if (n_read == 0)
|
||||
break;
|
||||
|
||||
/* Write this block out. */
|
||||
|
||||
if (full_write (output_desc, buf, n_read) < 0)
|
||||
error (1, 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 (inbuf, insize, outbuf, outsize, quote,
|
||||
output_tabs, numbers, numbers_at_empty_lines,
|
||||
mark_line_ends, squeeze_empty_lines)
|
||||
|
||||
/* Pointer to the beginning of the input buffer. */
|
||||
unsigned char *inbuf;
|
||||
|
||||
/* Number of characters read in each read call. */
|
||||
int insize;
|
||||
|
||||
/* Pointer to the beginning of the output buffer. */
|
||||
unsigned char *outbuf;
|
||||
|
||||
/* Number of characters written by each write call. */
|
||||
int 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. */
|
||||
unsigned char *bpin;
|
||||
|
||||
/* Pointer to the first non-valid byte in the input buffer, i.e. the
|
||||
current end of the buffer. */
|
||||
unsigned char *eob;
|
||||
|
||||
/* Pointer to the position where the next character shall be written. */
|
||||
unsigned char *bpout;
|
||||
|
||||
/* Number of characters read by the last read call. */
|
||||
int 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 (bpout - outbuf >= outsize)
|
||||
{
|
||||
unsigned char *wp = outbuf;
|
||||
do
|
||||
{
|
||||
if (full_write (output_desc, wp, outsize) < 0)
|
||||
error (1, errno, _("write error"));
|
||||
wp += outsize;
|
||||
}
|
||||
while (bpout - wp >= outsize);
|
||||
|
||||
/* Move the remaining bytes to the beginning of the
|
||||
buffer. */
|
||||
|
||||
memmove (outbuf, wp, bpout - wp);
|
||||
bpout = outbuf + (bpout - wp);
|
||||
}
|
||||
|
||||
/* 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_stat = 1;
|
||||
newlines2 = newlines;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (n_to_read == 0)
|
||||
#endif
|
||||
{
|
||||
int n_write = bpout - outbuf;
|
||||
|
||||
if (full_write (output_desc, outbuf, n_write) < 0)
|
||||
error (1, errno, _("write error"));
|
||||
bpout = outbuf;
|
||||
}
|
||||
|
||||
/* Read more input into INBUF. */
|
||||
|
||||
n_read = safe_read (input_desc, inbuf, insize);
|
||||
if (n_read < 0)
|
||||
{
|
||||
error (0, errno, "%s", infile);
|
||||
exit_stat = 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)
|
||||
{
|
||||
/* Are multiple adjacent empty lines to be substituted by
|
||||
single ditto (-s), and this was the second empty line? */
|
||||
|
||||
if (squeeze_empty_lines && newlines >= 2)
|
||||
{
|
||||
ch = *bpin++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Are line numbers to be written at empty lines (-n)? */
|
||||
|
||||
if (numbers && numbers_at_empty_lines)
|
||||
{
|
||||
next_line_num ();
|
||||
bpout = (unsigned char *) 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 = (unsigned char *) 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute the next line number. */
|
||||
|
||||
static void
|
||||
next_line_num ()
|
||||
{
|
||||
char *endp = line_num_end;
|
||||
do
|
||||
{
|
||||
if ((*endp)++ < '9')
|
||||
return;
|
||||
*endp-- = '0';
|
||||
}
|
||||
while (endp >= line_num_start);
|
||||
*--line_num_start = '1';
|
||||
if (line_num_start < line_num_print)
|
||||
line_num_print--;
|
||||
}
|
||||
|
||||
16
src/chgrp.c
16
src/chgrp.c
@@ -23,6 +23,18 @@
|
||||
#include <grp.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#ifndef UINT_MAX
|
||||
# define UINT_MAX ((unsigned int) ~(unsigned int) 0)
|
||||
#endif
|
||||
|
||||
#ifndef INT_MAX
|
||||
# define INT_MAX ((int) (UINT_MAX >> 1))
|
||||
#endif
|
||||
|
||||
#include "system.h"
|
||||
#include "version.h"
|
||||
#include "xstrtoul.h"
|
||||
@@ -32,8 +44,8 @@
|
||||
struct group *getgrnam ();
|
||||
#endif
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
#define endgrent()
|
||||
#ifndef HAVE_ENDGRENT
|
||||
# define endgrent() ((void) 0)
|
||||
#endif
|
||||
|
||||
char *group_member ();
|
||||
|
||||
@@ -45,9 +45,8 @@ struct group *getgrnam ();
|
||||
struct group *getgrgid ();
|
||||
#endif
|
||||
|
||||
#ifdef _POSIX_SOURCE
|
||||
#define endgrent()
|
||||
#define endpwent()
|
||||
#ifndef HAVE_ENDPWENT
|
||||
# define endpwent() ((void) 0)
|
||||
#endif
|
||||
|
||||
char *savedir ();
|
||||
|
||||
11
src/cksum.c
11
src/cksum.c
@@ -195,9 +195,7 @@ static int have_read_stdin;
|
||||
Return 0 if successful, -1 if an error occurs. */
|
||||
|
||||
static int
|
||||
cksum (file, print_name)
|
||||
char *file;
|
||||
int print_name;
|
||||
cksum (char *file, int print_name)
|
||||
{
|
||||
unsigned char buf[BUFLEN];
|
||||
unsigned long crc = 0;
|
||||
@@ -261,8 +259,7 @@ cksum (file, print_name)
|
||||
}
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
int status;
|
||||
usage (int status)
|
||||
{
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
@@ -284,9 +281,7 @@ Print CRC checksum and byte counts of each FILE.\n\
|
||||
}
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int i, c;
|
||||
int errors = 0;
|
||||
|
||||
9
src/cp.c
9
src/cp.c
@@ -42,10 +42,13 @@ struct dir_attr
|
||||
struct dir_attr *next;
|
||||
};
|
||||
|
||||
int stat ();
|
||||
int lstat ();
|
||||
|
||||
char *dirname ();
|
||||
char *xstrdup ();
|
||||
enum backup_type get_version ();
|
||||
int eaccess_stat ();
|
||||
int euidaccess ();
|
||||
int full_write ();
|
||||
|
||||
static int do_copy ();
|
||||
@@ -553,7 +556,7 @@ copy (src_path, dst_path, new_dst, device, ancestors)
|
||||
{
|
||||
if (flag_interactive)
|
||||
{
|
||||
if (eaccess_stat (&dst_sb, W_OK, dst_path) != 0)
|
||||
if (euidaccess (dst_path, W_OK) != 0)
|
||||
fprintf (stderr,
|
||||
"%s: overwrite `%s', overriding mode %04o? ",
|
||||
program_name, dst_path,
|
||||
@@ -591,7 +594,7 @@ copy (src_path, dst_path, new_dst, device, ancestors)
|
||||
if (S_ISDIR (dst_sb.st_mode))
|
||||
{
|
||||
/* Temporarily change mode to allow overwriting. */
|
||||
if (eaccess_stat (&dst_sb, W_OK | X_OK) != 0)
|
||||
if (euidaccess (dst_path, W_OK | X_OK) != 0)
|
||||
{
|
||||
if (chmod (dst_path, 0700))
|
||||
{
|
||||
|
||||
@@ -1435,9 +1435,9 @@ main (argc, argv)
|
||||
char **argv;
|
||||
{
|
||||
int optc;
|
||||
#ifdef _POSIX_VERSION
|
||||
#ifdef SA_INTERRUPT
|
||||
struct sigaction oldact, newact;
|
||||
#endif /* _POSIX_VERSION */
|
||||
#endif /* SA_INTERRUPT */
|
||||
|
||||
program_name = argv[0];
|
||||
global_argv = argv;
|
||||
@@ -1447,7 +1447,7 @@ main (argc, argv)
|
||||
remove_files = TRUE;
|
||||
prefix = DEFAULT_PREFIX;
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
#ifdef SA_INTERRUPT
|
||||
newact.sa_handler = interrupt_handler;
|
||||
sigemptyset (&newact.sa_mask);
|
||||
newact.sa_flags = 0;
|
||||
@@ -1467,7 +1467,7 @@ main (argc, argv)
|
||||
sigaction (SIGTERM, NULL, &oldact);
|
||||
if (oldact.sa_handler != SIG_IGN)
|
||||
sigaction (SIGTERM, &newact, NULL);
|
||||
#else /* !_POSIX_VERSION */
|
||||
#else
|
||||
if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
|
||||
signal (SIGHUP, interrupt_handler);
|
||||
if (signal (SIGINT, SIG_IGN) != SIG_IGN)
|
||||
|
||||
56
src/cut.c
56
src/cut.c
@@ -104,8 +104,8 @@
|
||||
|
||||
struct range_pair
|
||||
{
|
||||
int lo;
|
||||
int hi;
|
||||
unsigned int lo;
|
||||
unsigned int hi;
|
||||
};
|
||||
|
||||
char *xmalloc ();
|
||||
@@ -127,11 +127,11 @@ static int field_1_bufsize;
|
||||
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 int max_range_endpoint;
|
||||
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 int eol_range_start;
|
||||
static unsigned int eol_range_start;
|
||||
|
||||
/* In byte mode, which bytes to output.
|
||||
In field mode, which DELIM-separated fields to output.
|
||||
@@ -188,8 +188,7 @@ static struct option const longopts[] =
|
||||
};
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
int status;
|
||||
usage (int status)
|
||||
{
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
@@ -243,11 +242,7 @@ With no FILE, or when FILE is -, read standard input.\n\
|
||||
including the null terminator), or -1 on error or EOF. */
|
||||
|
||||
static int
|
||||
getstr (lineptr, n, stream, terminator)
|
||||
char **lineptr;
|
||||
int *n;
|
||||
FILE *stream;
|
||||
char terminator;
|
||||
getstr (char **lineptr, int *n, FILE *stream, char terminator)
|
||||
{
|
||||
int nchars_avail; /* Allocated but unused chars in *LINEPTR. */
|
||||
char *read_pos; /* Where we're reading into *LINEPTR. */
|
||||
@@ -314,10 +309,9 @@ getstr (lineptr, n, stream, terminator)
|
||||
}
|
||||
|
||||
static int
|
||||
print_kth (k)
|
||||
int k;
|
||||
print_kth (unsigned int k)
|
||||
{
|
||||
return ((eol_range_start > 0 && eol_range_start <= k)
|
||||
return ((0 < eol_range_start && eol_range_start <= k)
|
||||
|| (k <= max_range_endpoint && printable_field[k]));
|
||||
}
|
||||
|
||||
@@ -338,12 +332,11 @@ print_kth (k)
|
||||
one bit per field index instead of a whole `int' per index. */
|
||||
|
||||
static int
|
||||
set_fields (fieldstr)
|
||||
const char *fieldstr;
|
||||
set_fields (const char *fieldstr)
|
||||
{
|
||||
int initial = 1; /* Value of first number in a range. */
|
||||
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 value = 0; /* If nonzero, a number being accumulated. */
|
||||
int field_found = 0; /* Non-zero if at least one field spec
|
||||
has been processed. */
|
||||
|
||||
@@ -409,7 +402,7 @@ set_fields (fieldstr)
|
||||
/* No, the new sequence starts before the
|
||||
old. Does the old range going to end of line
|
||||
extend into the new range? */
|
||||
if (value >= eol_range_start - 1)
|
||||
if (value + 1 >= eol_range_start)
|
||||
{
|
||||
/* Yes. Simply move the end of line marker. */
|
||||
eol_range_start = initial;
|
||||
@@ -471,13 +464,12 @@ set_fields (fieldstr)
|
||||
(i.e. `2-6' or `-4', but not `5-') in FIELDSTR. */
|
||||
|
||||
printable_field = (int *) xmalloc ((max_range_endpoint + 1) * sizeof (int));
|
||||
for (i = 1; i <= max_range_endpoint; i++)
|
||||
printable_field[i] = 0;
|
||||
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++)
|
||||
{
|
||||
int j;
|
||||
unsigned int j;
|
||||
for (j = rp[i].lo; j <= rp[i].hi; j++)
|
||||
{
|
||||
printable_field[j] = 1;
|
||||
@@ -492,10 +484,9 @@ set_fields (fieldstr)
|
||||
/* Read from stream STREAM, printing to standard output any selected bytes. */
|
||||
|
||||
static void
|
||||
cut_bytes (stream)
|
||||
FILE *stream;
|
||||
cut_bytes (FILE *stream)
|
||||
{
|
||||
int byte_idx; /* Number of chars in the line so far. */
|
||||
unsigned int byte_idx; /* Number of chars in the line so far. */
|
||||
|
||||
byte_idx = 0;
|
||||
while (1)
|
||||
@@ -529,11 +520,10 @@ cut_bytes (stream)
|
||||
/* Read from stream STREAM, printing to standard output any selected fields. */
|
||||
|
||||
static void
|
||||
cut_fields (stream)
|
||||
FILE *stream;
|
||||
cut_fields (FILE *stream)
|
||||
{
|
||||
int c;
|
||||
int field_idx;
|
||||
unsigned int field_idx;
|
||||
int found_any_selected_field;
|
||||
int buffer_first_field;
|
||||
|
||||
@@ -632,8 +622,7 @@ cut_fields (stream)
|
||||
}
|
||||
|
||||
static void
|
||||
cut_stream (stream)
|
||||
FILE *stream;
|
||||
cut_stream (FILE *stream)
|
||||
{
|
||||
if (operating_mode == byte_mode)
|
||||
cut_bytes (stream);
|
||||
@@ -645,8 +634,7 @@ cut_stream (stream)
|
||||
Return 0 if successful, 1 if not. */
|
||||
|
||||
static int
|
||||
cut_file (file)
|
||||
char *file;
|
||||
cut_file (char *file)
|
||||
{
|
||||
FILE *stream;
|
||||
|
||||
@@ -683,9 +671,7 @@ cut_file (file)
|
||||
}
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int optc, exit_status = 0;
|
||||
|
||||
|
||||
64
src/date.c
64
src/date.c
@@ -64,6 +64,7 @@ static struct option const long_options[] =
|
||||
{"date", required_argument, NULL, 'd'},
|
||||
{"file", required_argument, NULL, 'f'},
|
||||
{"help", no_argument, &show_help, 1},
|
||||
{"reference", required_argument, NULL, 'r'},
|
||||
{"set", required_argument, NULL, 's'},
|
||||
{"uct", no_argument, NULL, 'u'},
|
||||
{"utc", no_argument, NULL, 'u'},
|
||||
@@ -82,7 +83,6 @@ batch_convert (input_filename, format)
|
||||
const char *input_filename;
|
||||
const char *format;
|
||||
{
|
||||
int have_read_stdin;
|
||||
int status;
|
||||
FILE *in_stream;
|
||||
char *line;
|
||||
@@ -94,7 +94,6 @@ batch_convert (input_filename, format)
|
||||
{
|
||||
input_filename = _("standard input");
|
||||
in_stream = stdin;
|
||||
have_read_stdin = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -103,7 +102,6 @@ batch_convert (input_filename, format)
|
||||
{
|
||||
error (0, errno, "%s", input_filename);
|
||||
}
|
||||
have_read_stdin = 0;
|
||||
}
|
||||
|
||||
line = NULL;
|
||||
@@ -132,8 +130,8 @@ batch_convert (input_filename, format)
|
||||
}
|
||||
}
|
||||
|
||||
if (have_read_stdin && fclose (stdin) == EOF)
|
||||
error (2, errno, _("standard input"));
|
||||
if (fclose (in_stream) == EOF)
|
||||
error (2, errno, input_filename);
|
||||
|
||||
if (line != NULL)
|
||||
free (line);
|
||||
@@ -148,31 +146,36 @@ main (argc, argv)
|
||||
{
|
||||
int optc;
|
||||
const char *datestr = NULL;
|
||||
const char *set_datestr = NULL;
|
||||
time_t when;
|
||||
int set_date = 0;
|
||||
int print_date = 0;
|
||||
char *format;
|
||||
char *batch_file = NULL;
|
||||
char *reference = NULL;
|
||||
struct stat refstats;
|
||||
int n_args;
|
||||
int status;
|
||||
int option_specified_date;
|
||||
|
||||
program_name = argv[0];
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "d:f:s:u", long_options, (int *) 0))
|
||||
!= EOF)
|
||||
while (optc = getopt_long (argc, argv, "d:f:r:s:u", long_options, (int *) 0),
|
||||
optc != EOF)
|
||||
switch (optc)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 'd':
|
||||
datestr = optarg;
|
||||
print_date = 1;
|
||||
break;
|
||||
case 'f':
|
||||
batch_file = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
reference = optarg;
|
||||
break;
|
||||
case 's':
|
||||
datestr = optarg;
|
||||
set_datestr = optarg;
|
||||
set_date = 1;
|
||||
break;
|
||||
case 'u':
|
||||
@@ -193,7 +196,18 @@ main (argc, argv)
|
||||
|
||||
n_args = argc - optind;
|
||||
|
||||
if (set_date && print_date)
|
||||
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 (1);
|
||||
}
|
||||
|
||||
if (set_date && option_specified_date)
|
||||
{
|
||||
error (0, 0,
|
||||
_("the options to print and set the time may not be used together"));
|
||||
@@ -206,23 +220,20 @@ main (argc, argv)
|
||||
usage (1);
|
||||
}
|
||||
|
||||
if ((set_date || print_date || batch_file != NULL)
|
||||
if ((set_date || option_specified_date)
|
||||
&& n_args == 1 && argv[optind][0] != '+')
|
||||
{
|
||||
error (0, 0, _("\
|
||||
when using the print, set time, or batch options, any\n\
|
||||
when using an option to specify date(s), any\n\
|
||||
non-option argument must be a format string beginning with `+'"));
|
||||
usage (1);
|
||||
}
|
||||
|
||||
if (set_date)
|
||||
datestr = set_datestr;
|
||||
|
||||
if (batch_file != NULL)
|
||||
{
|
||||
if (set_date || print_date)
|
||||
{
|
||||
error (0, 0, _("\
|
||||
neither print nor set options may be used when reading dates from a file"));
|
||||
usage (1);
|
||||
}
|
||||
status = batch_convert (batch_file,
|
||||
(n_args == 1 ? argv[optind] + 1 : NULL));
|
||||
}
|
||||
@@ -230,7 +241,7 @@ neither print nor set options may be used when reading dates from a file"));
|
||||
{
|
||||
status = 0;
|
||||
|
||||
if (!print_date && !set_date)
|
||||
if (!option_specified_date && !set_date)
|
||||
{
|
||||
if (n_args == 1 && argv[optind][0] != '+')
|
||||
{
|
||||
@@ -244,7 +255,6 @@ neither print nor set options may be used when reading dates from a file"));
|
||||
else
|
||||
{
|
||||
/* Prepare to print the current date/time. */
|
||||
print_date = 1;
|
||||
datestr = _("undefined");
|
||||
time (&when);
|
||||
format = (n_args == 1 ? argv[optind] + 1 : NULL);
|
||||
@@ -252,8 +262,15 @@ neither print nor set options may be used when reading dates from a file"));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* (print_date || set_date) */
|
||||
when = get_date (datestr, NULL);
|
||||
/* (option_specified_date || set_date) */
|
||||
if (reference != NULL)
|
||||
{
|
||||
if (stat (reference, &refstats))
|
||||
error (1, errno, "%s", reference);
|
||||
when = refstats.st_mtime;
|
||||
}
|
||||
else
|
||||
when = get_date (datestr, NULL);
|
||||
format = (n_args == 1 ? argv[optind] + 1 : NULL);
|
||||
}
|
||||
|
||||
@@ -337,6 +354,7 @@ 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\
|
||||
-r, --reference=FILE display the last modification time of FILE\n\
|
||||
-s, --set=STRING set time described by STRING\n\
|
||||
-u, --utc, --universal print or set Coordinated Universal Time\n\
|
||||
--help display this help and exit\n\
|
||||
|
||||
34
src/df.c
34
src/df.c
@@ -213,6 +213,29 @@ main (argc, argv)
|
||||
if (show_help)
|
||||
usage (0);
|
||||
|
||||
/* Fail if the same file system type was both selected and excluded. */
|
||||
{
|
||||
int match = 0;
|
||||
struct fs_type_list *i;
|
||||
for (i = fs_select_list; i; i = i->fs_next)
|
||||
{
|
||||
struct fs_type_list *j;
|
||||
for (j = fs_exclude_list; j; j = j->fs_next)
|
||||
{
|
||||
if (strcmp (i->fs_name, j->fs_name) == 0)
|
||||
{
|
||||
error (0, 0,
|
||||
"file system type `%s' both selected and excluded",
|
||||
i->fs_name);
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (optind == argc)
|
||||
{
|
||||
#ifdef lint
|
||||
@@ -346,12 +369,17 @@ show_point (point, statp)
|
||||
{
|
||||
error (0, errno, "%s", me->me_mountdir);
|
||||
exit_status = 1;
|
||||
me->me_dev = -2; /* So we won't try and fail repeatedly. */
|
||||
/* 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)
|
||||
continue;
|
||||
show_dev (me->me_devname, me->me_mountdir, me->me_type);
|
||||
return;
|
||||
}
|
||||
@@ -526,8 +554,8 @@ or all filesystems by default.\n\
|
||||
-k, --kilobytes use 1024 blocks, not 512 despite POSIXLY_CORRECT\n\
|
||||
--sync invoke sync before getting usage info (default)\n\
|
||||
--no-sync do not invoke sync before getting usage info\n\
|
||||
-t, --type=TYPE limit the listing to TYPE filesystems type\n\
|
||||
-x, --exclude-type=TYPE limit the listing to not TYPE filesystems type\n\
|
||||
-t, --type=TYPE limit listing to filesystems of type TYPE\n\
|
||||
-x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\
|
||||
-v (ignored)\n\
|
||||
-P, --portability use the POSIX output format\n\
|
||||
-T, --print-type print filesystem type\n\
|
||||
|
||||
3
src/du.c
3
src/du.c
@@ -90,6 +90,9 @@ typedef struct
|
||||
char *text; /* Pointer to the text. */
|
||||
} *string, stringstruct;
|
||||
|
||||
int stat ();
|
||||
int lstat ();
|
||||
|
||||
char *savedir ();
|
||||
char *xmalloc ();
|
||||
char *xrealloc ();
|
||||
|
||||
313
src/expand.c
313
src/expand.c
@@ -56,13 +56,6 @@
|
||||
char *xmalloc ();
|
||||
char *xrealloc ();
|
||||
|
||||
static FILE *next_file ();
|
||||
static void add_tabstop ();
|
||||
static void expand ();
|
||||
static void parse_tabstops ();
|
||||
static void usage ();
|
||||
static void validate_tabstops ();
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
@@ -112,90 +105,53 @@ static struct option const longopts[] =
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
static void
|
||||
usage (int status)
|
||||
{
|
||||
int tabval = -1; /* Value of tabstop being read, or -1. */
|
||||
int c; /* Option character. */
|
||||
|
||||
have_read_stdin = 0;
|
||||
exit_status = 0;
|
||||
convert_entire_line = 1;
|
||||
tab_list = NULL;
|
||||
first_free_tab = 0;
|
||||
program_name = argv[0];
|
||||
|
||||
while ((c = getopt_long (argc, argv, "it:,0123456789", longopts, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case '?':
|
||||
usage (1);
|
||||
case 'i':
|
||||
convert_entire_line = 0;
|
||||
break;
|
||||
case 't':
|
||||
parse_tabstops (optarg);
|
||||
break;
|
||||
case ',':
|
||||
add_tabstop (tabval);
|
||||
tabval = -1;
|
||||
break;
|
||||
default:
|
||||
if (tabval == -1)
|
||||
tabval = 0;
|
||||
tabval = tabval * 10 + c - '0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (show_version)
|
||||
{
|
||||
printf ("expand - %s\n", version_string);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (show_help)
|
||||
usage (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];
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
program_name);
|
||||
else
|
||||
tab_size = 0;
|
||||
{
|
||||
printf (_("\
|
||||
Usage: %s [OPTION]... [FILE]...\n\
|
||||
"),
|
||||
program_name);
|
||||
printf (_("\
|
||||
Convert tabs in each FILE to spaces, writing to standard output.\n\
|
||||
With no FILE, or when FILE is -, read standard input.\n\
|
||||
\n\
|
||||
-i, --initial do not convert TABs after non whitespace\n\
|
||||
-t, --tabs=NUMBER have tabs NUMBER characters apart, not 8\n\
|
||||
-t, --tabs=LIST use comma separated list of explicit tab positions\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
\n\
|
||||
Instead of -t NUMBER or -t LIST, -NUMBER or -LIST may be used.\n\
|
||||
"));
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
if (optind == argc)
|
||||
file_list = stdin_argv;
|
||||
else
|
||||
file_list = &argv[optind];
|
||||
/* Add tab stop TABVAL to the end of `tab_list', except
|
||||
if TABVAL is -1, do nothing. */
|
||||
|
||||
expand ();
|
||||
|
||||
if (have_read_stdin && fclose (stdin) == EOF)
|
||||
error (1, errno, "-");
|
||||
if (ferror (stdout) || fclose (stdout) == EOF)
|
||||
error (1, errno, _("write error"));
|
||||
|
||||
exit (exit_status);
|
||||
static void
|
||||
add_tabstop (int tabval)
|
||||
{
|
||||
if (tabval == -1)
|
||||
return;
|
||||
if (first_free_tab % TABLIST_BLOCK == 0)
|
||||
tab_list = (int *) xrealloc (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 (stops)
|
||||
char *stops;
|
||||
parse_tabstops (char *stops)
|
||||
{
|
||||
int tabval = -1;
|
||||
|
||||
@@ -219,28 +175,11 @@ parse_tabstops (stops)
|
||||
add_tabstop (tabval);
|
||||
}
|
||||
|
||||
/* Add tab stop TABVAL to the end of `tab_list', except
|
||||
if TABVAL is -1, do nothing. */
|
||||
|
||||
static void
|
||||
add_tabstop (tabval)
|
||||
int tabval;
|
||||
{
|
||||
if (tabval == -1)
|
||||
return;
|
||||
if (first_free_tab % TABLIST_BLOCK == 0)
|
||||
tab_list = (int *) xrealloc (tab_list, first_free_tab
|
||||
+ TABLIST_BLOCK * sizeof (tab_list[0]));
|
||||
tab_list[first_free_tab++] = tabval;
|
||||
}
|
||||
|
||||
/* Check that the list of tabstops TABS, with ENTRIES entries,
|
||||
contains only nonzero, ascending values. */
|
||||
|
||||
static void
|
||||
validate_tabstops (tabs, entries)
|
||||
int *tabs;
|
||||
int entries;
|
||||
validate_tabstops (int *tabs, int entries)
|
||||
{
|
||||
int prev_tab = 0;
|
||||
int i;
|
||||
@@ -255,11 +194,58 @@ validate_tabstops (tabs, entries)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 ()
|
||||
expand (void)
|
||||
{
|
||||
FILE *fp; /* Input stream. */
|
||||
int c; /* Each input character. */
|
||||
@@ -336,79 +322,78 @@ expand ()
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 (fp)
|
||||
FILE *fp;
|
||||
void
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
static char *prev_file;
|
||||
char *file;
|
||||
int tabval = -1; /* Value of tabstop being read, or -1. */
|
||||
int c; /* Option character. */
|
||||
|
||||
if (fp)
|
||||
have_read_stdin = 0;
|
||||
exit_status = 0;
|
||||
convert_entire_line = 1;
|
||||
tab_list = NULL;
|
||||
first_free_tab = 0;
|
||||
program_name = argv[0];
|
||||
|
||||
while ((c = getopt_long (argc, argv, "it:,0123456789", longopts, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
if (ferror (fp))
|
||||
switch (c)
|
||||
{
|
||||
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;
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case '?':
|
||||
usage (1);
|
||||
case 'i':
|
||||
convert_entire_line = 0;
|
||||
break;
|
||||
case 't':
|
||||
parse_tabstops (optarg);
|
||||
break;
|
||||
case ',':
|
||||
add_tabstop (tabval);
|
||||
tabval = -1;
|
||||
break;
|
||||
default:
|
||||
if (tabval == -1)
|
||||
tabval = 0;
|
||||
tabval = tabval * 10 + c - '0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while ((file = *file_list++) != NULL)
|
||||
if (show_version)
|
||||
{
|
||||
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;
|
||||
printf ("expand - %s\n", version_string);
|
||||
exit (0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
int status;
|
||||
{
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
program_name);
|
||||
if (show_help)
|
||||
usage (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
|
||||
{
|
||||
printf (_("\
|
||||
Usage: %s [OPTION]... [FILE]...\n\
|
||||
"),
|
||||
program_name);
|
||||
printf (_("\
|
||||
Convert tabs in each FILE to spaces, writing to standard output.\n\
|
||||
With no FILE, or when FILE is -, read standard input.\n\
|
||||
\n\
|
||||
-i, --initial do not convert TABs after non whitespace\n\
|
||||
-t, --tabs=NUMBER have tabs NUMBER characters apart, not 8\n\
|
||||
-t, --tabs=LIST use comma separated list of explicit tab positions\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
\n\
|
||||
Instead of -t NUMBER or -t LIST, -NUMBER or -LIST may be used.\n\
|
||||
"));
|
||||
}
|
||||
exit (status);
|
||||
tab_size = 0;
|
||||
|
||||
if (optind == argc)
|
||||
file_list = stdin_argv;
|
||||
else
|
||||
file_list = &argv[optind];
|
||||
|
||||
expand ();
|
||||
|
||||
if (have_read_stdin && fclose (stdin) == EOF)
|
||||
error (1, errno, "-");
|
||||
if (ferror (stdout) || fclose (stdout) == EOF)
|
||||
error (1, errno, _("write error"));
|
||||
|
||||
exit (exit_status);
|
||||
}
|
||||
|
||||
188
src/fold.c
188
src/fold.c
@@ -35,9 +35,6 @@ char *xmalloc ();
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
static int adjust_column ();
|
||||
static int fold_file ();
|
||||
|
||||
/* If nonzero, try to break on whitespace. */
|
||||
static int break_spaces;
|
||||
|
||||
@@ -62,10 +59,9 @@ static struct option const longopts[] =
|
||||
{"version", no_argument, &show_version, 1},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
int status;
|
||||
usage (int status)
|
||||
{
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
@@ -88,82 +84,30 @@ standard output.\n\
|
||||
exit (status);
|
||||
}
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
/* 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)
|
||||
{
|
||||
int width = 80;
|
||||
int i;
|
||||
int optc;
|
||||
int errs = 0;
|
||||
|
||||
program_name = argv[0];
|
||||
break_spaces = count_bytes = have_read_stdin = 0;
|
||||
|
||||
/* Turn any numeric options into -w options. */
|
||||
for (i = 1; i < argc; i++)
|
||||
if (!count_bytes)
|
||||
{
|
||||
if (argv[i][0] == '-' && ISDIGIT (argv[i][1]))
|
||||
if (c == '\b')
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = xmalloc (strlen (argv[i]) + 2);
|
||||
s[0] = '-';
|
||||
s[1] = 'w';
|
||||
strcpy (s + 2, argv[i] + 1);
|
||||
argv[i] = s;
|
||||
if (column > 0)
|
||||
column--;
|
||||
}
|
||||
else if (c == '\r')
|
||||
column = 0;
|
||||
else if (c == '\t')
|
||||
column = column + 8 - column % 8;
|
||||
else /* if (isprint (c)) */
|
||||
column++;
|
||||
}
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "bsw:", longopts, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
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. */
|
||||
width = atoi (optarg);
|
||||
if (width < 1)
|
||||
error (1, 0, _("%s: invalid line width"), optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
usage (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (show_version)
|
||||
{
|
||||
printf ("fold - %s\n", version_string);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (show_help)
|
||||
usage (0);
|
||||
|
||||
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 (1, errno, "-");
|
||||
if (fclose (stdout) == EOF)
|
||||
error (1, errno, _("write error"));
|
||||
|
||||
exit (errs);
|
||||
column++;
|
||||
return column;
|
||||
}
|
||||
|
||||
/* Fold file FILENAME, or standard input if FILENAME is "-",
|
||||
@@ -171,9 +115,7 @@ main (argc, argv)
|
||||
Return 0 if successful, 1 if an error occurs. */
|
||||
|
||||
static int
|
||||
fold_file (filename, width)
|
||||
char *filename;
|
||||
int width;
|
||||
fold_file (char *filename, int width)
|
||||
{
|
||||
FILE *istream;
|
||||
register int c;
|
||||
@@ -289,30 +231,78 @@ fold_file (filename, width)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 (column, c)
|
||||
int column;
|
||||
char c;
|
||||
void
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
if (!count_bytes)
|
||||
int width = 80;
|
||||
int i;
|
||||
int optc;
|
||||
int errs = 0;
|
||||
|
||||
program_name = argv[0];
|
||||
break_spaces = count_bytes = have_read_stdin = 0;
|
||||
|
||||
/* Turn any numeric options into -w options. */
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (c == '\b')
|
||||
if (argv[i][0] == '-' && ISDIGIT (argv[i][1]))
|
||||
{
|
||||
if (column > 0)
|
||||
column--;
|
||||
char *s;
|
||||
|
||||
s = xmalloc (strlen (argv[i]) + 2);
|
||||
s[0] = '-';
|
||||
s[1] = 'w';
|
||||
strcpy (s + 2, argv[i] + 1);
|
||||
argv[i] = s;
|
||||
}
|
||||
else if (c == '\r')
|
||||
column = 0;
|
||||
else if (c == '\t')
|
||||
column = column + 8 - column % 8;
|
||||
else /* if (isprint (c)) */
|
||||
column++;
|
||||
}
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "bsw:", longopts, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
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. */
|
||||
width = atoi (optarg);
|
||||
if (width < 1)
|
||||
error (1, 0, _("%s: invalid line width"), optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
usage (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (show_version)
|
||||
{
|
||||
printf ("fold - %s\n", version_string);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (show_help)
|
||||
usage (0);
|
||||
|
||||
if (argc == optind)
|
||||
errs |= fold_file ("-", width);
|
||||
else
|
||||
column++;
|
||||
return column;
|
||||
for (i = optind; i < argc; i++)
|
||||
errs |= fold_file (argv[i], width);
|
||||
|
||||
if (have_read_stdin && fclose (stdin) == EOF)
|
||||
error (1, errno, "-");
|
||||
if (fclose (stdout) == EOF)
|
||||
error (1, errno, _("write error"));
|
||||
|
||||
exit (errs);
|
||||
}
|
||||
|
||||
371
src/head.c
371
src/head.c
@@ -54,15 +54,6 @@ enum header_mode
|
||||
|
||||
int safe_read ();
|
||||
|
||||
static int head ();
|
||||
static int head_bytes ();
|
||||
static int head_file ();
|
||||
static int head_lines ();
|
||||
static long atou ();
|
||||
static void parse_unit ();
|
||||
static void usage ();
|
||||
static void write_header ();
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
@@ -87,10 +78,179 @@ static struct option const long_options[] =
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static 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 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\
|
||||
-c, --bytes=SIZE print first SIZE bytes\n\
|
||||
-n, --lines=NUMBER print first NUMBER lines instead of first 10\n\
|
||||
-q, --quiet, --silent never print headers giving file names\n\
|
||||
-v, --verbose always print headers giving file names\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
\n\
|
||||
SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
|
||||
If -VALUE is used as first OPTION, read -c VALUE when one of\n\
|
||||
multipliers bkm follows concatenated, else read -n VALUE.\n\
|
||||
"));
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
/* Convert STR, a string of ASCII digits, into an unsigned integer.
|
||||
Return -1 if STR does not represent a valid unsigned integer. */
|
||||
|
||||
static long
|
||||
atou (const char *str)
|
||||
{
|
||||
int value;
|
||||
|
||||
for (value = 0; ISDIGIT (*str); ++str)
|
||||
value = value * 10 + *str - '0';
|
||||
return *str ? -1 : value;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_unit (char *str)
|
||||
{
|
||||
int arglen = strlen (str);
|
||||
|
||||
if (arglen == 0)
|
||||
return;
|
||||
|
||||
switch (str[arglen - 1])
|
||||
{
|
||||
case 'b':
|
||||
unit_size = 512;
|
||||
str[arglen - 1] = '\0';
|
||||
break;
|
||||
case 'k':
|
||||
unit_size = 1024;
|
||||
str[arglen - 1] = '\0';
|
||||
break;
|
||||
case 'm':
|
||||
unit_size = 1048576;
|
||||
str[arglen - 1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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, long int bytes_to_write)
|
||||
{
|
||||
char buffer[BUFSIZE];
|
||||
int bytes_read;
|
||||
|
||||
while (bytes_to_write)
|
||||
{
|
||||
bytes_read = safe_read (fd, buffer, BUFSIZE);
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
error (0, errno, "%s", filename);
|
||||
return 1;
|
||||
}
|
||||
if (bytes_read == 0)
|
||||
break;
|
||||
if (bytes_read > bytes_to_write)
|
||||
bytes_read = bytes_to_write;
|
||||
if (fwrite (buffer, 1, bytes_read, stdout) == 0)
|
||||
error (1, errno, _("write error"));
|
||||
bytes_to_write -= bytes_read;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
head_lines (const char *filename, int fd, long int lines_to_write)
|
||||
{
|
||||
char buffer[BUFSIZE];
|
||||
int bytes_read;
|
||||
int bytes_to_write;
|
||||
|
||||
while (lines_to_write)
|
||||
{
|
||||
bytes_read = safe_read (fd, buffer, BUFSIZE);
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
error (0, errno, "%s", filename);
|
||||
return 1;
|
||||
}
|
||||
if (bytes_read == 0)
|
||||
break;
|
||||
bytes_to_write = 0;
|
||||
while (bytes_to_write < bytes_read)
|
||||
if (buffer[bytes_to_write++] == '\n' && --lines_to_write == 0)
|
||||
break;
|
||||
if (fwrite (buffer, 1, bytes_to_write, stdout) == 0)
|
||||
error (1, errno, _("write error"));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
head (const char *filename, int fd, long int number)
|
||||
{
|
||||
if (unit_size)
|
||||
return head_bytes (filename, fd, number);
|
||||
else
|
||||
return head_lines (filename, fd, number);
|
||||
}
|
||||
|
||||
static int
|
||||
head_file (const char *filename, long int number)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (!strcmp (filename, "-"))
|
||||
{
|
||||
have_read_stdin = 1;
|
||||
filename = _("standard input");
|
||||
if (print_headers)
|
||||
write_header (filename);
|
||||
return head (filename, 0, number);
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = open (filename, O_RDONLY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
int errors;
|
||||
|
||||
if (print_headers)
|
||||
write_header (filename);
|
||||
errors = head (filename, fd, number);
|
||||
if (close (fd) == 0)
|
||||
return errors;
|
||||
}
|
||||
error (0, errno, "%s", filename);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
enum header_mode header_mode = multiple_files;
|
||||
int exit_status = 0;
|
||||
@@ -168,6 +328,7 @@ main (argc, argv)
|
||||
case 'n':
|
||||
unit_size = 0;
|
||||
getnum:
|
||||
/* FIXME: use xstrtoul instead. */
|
||||
number = atou (optarg);
|
||||
if (number == -1)
|
||||
error (1, 0, _("invalid number `%s'"), optarg);
|
||||
@@ -218,189 +379,3 @@ main (argc, argv)
|
||||
|
||||
exit (exit_status);
|
||||
}
|
||||
|
||||
static int
|
||||
head_file (filename, number)
|
||||
char *filename;
|
||||
long number;
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (!strcmp (filename, "-"))
|
||||
{
|
||||
have_read_stdin = 1;
|
||||
filename = _("standard input");
|
||||
if (print_headers)
|
||||
write_header (filename);
|
||||
return head (filename, 0, number);
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = open (filename, O_RDONLY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
int errors;
|
||||
|
||||
if (print_headers)
|
||||
write_header (filename);
|
||||
errors = head (filename, fd, number);
|
||||
if (close (fd) == 0)
|
||||
return errors;
|
||||
}
|
||||
error (0, errno, "%s", filename);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_header (filename)
|
||||
char *filename;
|
||||
{
|
||||
static int first_file = 1;
|
||||
|
||||
printf ("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
|
||||
first_file = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
head (filename, fd, number)
|
||||
char *filename;
|
||||
int fd;
|
||||
long number;
|
||||
{
|
||||
if (unit_size)
|
||||
return head_bytes (filename, fd, number);
|
||||
else
|
||||
return head_lines (filename, fd, number);
|
||||
}
|
||||
|
||||
static int
|
||||
head_bytes (filename, fd, bytes_to_write)
|
||||
char *filename;
|
||||
int fd;
|
||||
long bytes_to_write;
|
||||
{
|
||||
char buffer[BUFSIZE];
|
||||
int bytes_read;
|
||||
|
||||
while (bytes_to_write)
|
||||
{
|
||||
bytes_read = safe_read (fd, buffer, BUFSIZE);
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
error (0, errno, "%s", filename);
|
||||
return 1;
|
||||
}
|
||||
if (bytes_read == 0)
|
||||
break;
|
||||
if (bytes_read > bytes_to_write)
|
||||
bytes_read = bytes_to_write;
|
||||
if (fwrite (buffer, 1, bytes_read, stdout) == 0)
|
||||
error (1, errno, _("write error"));
|
||||
bytes_to_write -= bytes_read;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
head_lines (filename, fd, lines_to_write)
|
||||
char *filename;
|
||||
int fd;
|
||||
long lines_to_write;
|
||||
{
|
||||
char buffer[BUFSIZE];
|
||||
int bytes_read;
|
||||
int bytes_to_write;
|
||||
|
||||
while (lines_to_write)
|
||||
{
|
||||
bytes_read = safe_read (fd, buffer, BUFSIZE);
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
error (0, errno, "%s", filename);
|
||||
return 1;
|
||||
}
|
||||
if (bytes_read == 0)
|
||||
break;
|
||||
bytes_to_write = 0;
|
||||
while (bytes_to_write < bytes_read)
|
||||
if (buffer[bytes_to_write++] == '\n' && --lines_to_write == 0)
|
||||
break;
|
||||
if (fwrite (buffer, 1, bytes_to_write, stdout) == 0)
|
||||
error (1, errno, _("write error"));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_unit (str)
|
||||
char *str;
|
||||
{
|
||||
int arglen = strlen (str);
|
||||
|
||||
if (arglen == 0)
|
||||
return;
|
||||
|
||||
switch (str[arglen - 1])
|
||||
{
|
||||
case 'b':
|
||||
unit_size = 512;
|
||||
str[arglen - 1] = '\0';
|
||||
break;
|
||||
case 'k':
|
||||
unit_size = 1024;
|
||||
str[arglen - 1] = '\0';
|
||||
break;
|
||||
case 'm':
|
||||
unit_size = 1048576;
|
||||
str[arglen - 1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert STR, a string of ASCII digits, into an unsigned integer.
|
||||
Return -1 if STR does not represent a valid unsigned integer. */
|
||||
|
||||
static long
|
||||
atou (str)
|
||||
char *str;
|
||||
{
|
||||
int value;
|
||||
|
||||
for (value = 0; ISDIGIT (*str); ++str)
|
||||
value = value * 10 + *str - '0';
|
||||
return *str ? -1 : value;
|
||||
}
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
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 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\
|
||||
-c, --bytes=SIZE print first SIZE bytes\n\
|
||||
-n, --lines=NUMBER print first NUMBER lines instead of first 10\n\
|
||||
-q, --quiet, --silent never print headers giving file names\n\
|
||||
-v, --verbose always print headers giving file names\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
\n\
|
||||
SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
|
||||
If -VALUE is used as first OPTION, read -c VALUE when one of\n\
|
||||
multipliers bkm follows concatenated, else read -n VALUE.\n\
|
||||
"));
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
@@ -65,19 +65,25 @@
|
||||
#include "makepath.h"
|
||||
#include "error.h"
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
#if HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#else
|
||||
#endif
|
||||
|
||||
struct passwd *getpwnam ();
|
||||
struct group *getgrnam ();
|
||||
|
||||
#ifndef _POSIX_VERSION
|
||||
uid_t getuid ();
|
||||
gid_t getgid ();
|
||||
int wait ();
|
||||
#endif
|
||||
|
||||
#ifdef _POSIX_SOURCE
|
||||
#define endgrent()
|
||||
#define endpwent()
|
||||
#ifndef HAVE_ENDGRENT
|
||||
# define endgrent() ((void) 0)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ENDPWENT
|
||||
# define endpwent() ((void) 0)
|
||||
#endif
|
||||
|
||||
/* True if C is an ASCII octal digit. */
|
||||
|
||||
484
src/join.c
484
src/join.c
@@ -15,26 +15,55 @@
|
||||
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. */
|
||||
Written by Mike Haertel, mike@gnu.ai.mit.edu. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define alloca __builtin_alloca
|
||||
#else /* not __GNUC__ */
|
||||
#if HAVE_ALLOCA_H
|
||||
#include <alloca.h>
|
||||
#else /* not HAVE_ALLOCA_H */
|
||||
#ifdef _AIX
|
||||
#pragma alloca
|
||||
#else /* not _AIX */
|
||||
char *alloca ();
|
||||
#endif /* not _AIX */
|
||||
#endif /* not HAVE_ALLOCA_H */
|
||||
#endif /* not __GNUC__ */
|
||||
|
||||
/* Get isblank from GNU libc. */
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#define NDEBUG
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#ifndef UINT_MAX
|
||||
# define UINT_MAX ((unsigned int) ~(unsigned int) 0)
|
||||
#endif
|
||||
|
||||
#ifndef INT_MAX
|
||||
# define INT_MAX ((int) (UINT_MAX >> 1))
|
||||
#endif
|
||||
|
||||
#include "system.h"
|
||||
#include "version.h"
|
||||
#include "long-options.h"
|
||||
#include "xstrtol.h"
|
||||
#include "error.h"
|
||||
|
||||
#define join system_join
|
||||
|
||||
char *xmalloc ();
|
||||
char *xrealloc ();
|
||||
static void usage ();
|
||||
|
||||
/* Undefine, to avoid warning about redefinition on some systems. */
|
||||
#undef min
|
||||
@@ -42,69 +71,74 @@ static void usage ();
|
||||
#define min(A, B) ((A) < (B) ? (A) : (B))
|
||||
#define max(A, B) ((A) > (B) ? (A) : (B))
|
||||
|
||||
/* An element of the list describing the format of each
|
||||
output line. */
|
||||
/* An element of the list identifying which fields to print for each
|
||||
output line. */
|
||||
struct outlist
|
||||
{
|
||||
int file; /* File to take field from (1 or 2). */
|
||||
int field; /* Field number to print. */
|
||||
/* 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. */
|
||||
/* A field of a line. */
|
||||
struct field
|
||||
{
|
||||
const char *beg; /* First character in field. */
|
||||
size_t len; /* The length of the field. */
|
||||
const char *beg; /* First character in field. */
|
||||
size_t len; /* The length of the field. */
|
||||
};
|
||||
|
||||
/* A line read from an input file. Newlines are not stored. */
|
||||
/* A line read from an input file. Newlines are not stored. */
|
||||
struct line
|
||||
{
|
||||
char *beg; /* First character in line. */
|
||||
char *lim; /* Character after last character in line. */
|
||||
int nfields; /* Number of elements in `fields'. */
|
||||
int nfields_allocated; /* Number of elements in `fields'. */
|
||||
char *beg; /* First character in line. */
|
||||
char *lim; /* Character after last character in line. */
|
||||
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. */
|
||||
same join field value. */
|
||||
struct seq
|
||||
{
|
||||
int count; /* Elements used in `lines'. */
|
||||
int alloc; /* Elements allocated in `lines'. */
|
||||
int count; /* Elements used in `lines'. */
|
||||
int alloc; /* Elements allocated in `lines'. */
|
||||
struct line *lines;
|
||||
};
|
||||
|
||||
/* The name this program was run with. */
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
/* If nonzero, print unpairable lines in file 1 or 2. */
|
||||
/* If nonzero, print unpairable lines in file 1 or 2. */
|
||||
static int print_unpairables_1, print_unpairables_2;
|
||||
|
||||
/* If nonzero, print pairable lines. */
|
||||
/* If nonzero, print pairable lines. */
|
||||
static int print_pairables;
|
||||
|
||||
/* Empty output field filler. */
|
||||
/* Empty output field filler. */
|
||||
static char *empty_filler;
|
||||
|
||||
/* Field to join on. */
|
||||
/* Field to join on. */
|
||||
static int join_field_1, join_field_2;
|
||||
|
||||
/* List of fields to print. */
|
||||
static struct outlist *outlist;
|
||||
/* 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;
|
||||
/* 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. */
|
||||
tab character. */
|
||||
static char tab;
|
||||
|
||||
/* When using getopt_long_only, no long option can start with
|
||||
a character that is a short option. */
|
||||
a character that is a short option. */
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{"j", required_argument, NULL, 'j'},
|
||||
@@ -117,10 +151,48 @@ static struct option const longopts[] =
|
||||
static struct line uni_blank;
|
||||
|
||||
static void
|
||||
ADD_FIELD (line, field, len)
|
||||
struct line *line;
|
||||
const char *field;
|
||||
size_t len;
|
||||
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);
|
||||
printf (_("\
|
||||
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 SIDE print unpairable lines coming from file SIDE\n\
|
||||
-e EMPTY replace missing input fields with EMPTY\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\
|
||||
-1 FIELD join on this FIELD of file 1\n\
|
||||
-2 FIELD join on this FIELD of file 2\n\
|
||||
-o FORMAT obey FORMAT while constructing output line\n\
|
||||
-t CHAR use CHAR as input and output field separator\n\
|
||||
-v SIDE like -a SIDE, but suppress joined output lines\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
\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 `SIDE.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\
|
||||
"));
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
static void
|
||||
ADD_FIELD (struct line *line, const char *field, size_t len)
|
||||
{
|
||||
if (line->nfields >= line->nfields_allocated)
|
||||
{
|
||||
@@ -134,11 +206,10 @@ ADD_FIELD (line, field, len)
|
||||
++(line->nfields);
|
||||
}
|
||||
|
||||
/* Fill in the `fields' structure in LINE. */
|
||||
/* Fill in the `fields' structure in LINE. */
|
||||
|
||||
static void
|
||||
xfields (line)
|
||||
struct line *line;
|
||||
xfields (struct line *line)
|
||||
{
|
||||
int i;
|
||||
register char *ptr, *lim;
|
||||
@@ -181,12 +252,10 @@ xfields (line)
|
||||
}
|
||||
|
||||
/* Read a line from FP into LINE and split it into fields.
|
||||
Return 0 if EOF, 1 otherwise. */
|
||||
Return 0 if EOF, 1 otherwise. */
|
||||
|
||||
static int
|
||||
get_line (fp, line)
|
||||
FILE *fp;
|
||||
struct line *line;
|
||||
get_line (FILE *fp, struct line *line)
|
||||
{
|
||||
static int linesize = 80;
|
||||
int c, i;
|
||||
@@ -223,8 +292,7 @@ get_line (fp, line)
|
||||
}
|
||||
|
||||
static void
|
||||
freeline (line)
|
||||
struct line *line;
|
||||
freeline (struct line *line)
|
||||
{
|
||||
free ((char *) line->fields);
|
||||
free (line->beg);
|
||||
@@ -232,20 +300,17 @@ freeline (line)
|
||||
}
|
||||
|
||||
static void
|
||||
initseq (seq)
|
||||
struct seq *seq;
|
||||
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. */
|
||||
/* Read a line from FP and add it to SEQ. Return 0 if EOF, 1 otherwise. */
|
||||
|
||||
static int
|
||||
getseq (fp, seq)
|
||||
FILE *fp;
|
||||
struct seq *seq;
|
||||
getseq (FILE *fp, struct seq *seq)
|
||||
{
|
||||
if (seq->count == seq->alloc)
|
||||
{
|
||||
@@ -263,8 +328,7 @@ getseq (fp, seq)
|
||||
}
|
||||
|
||||
static void
|
||||
delseq (seq)
|
||||
struct seq *seq;
|
||||
delseq (struct seq *seq)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < seq->count; i++)
|
||||
@@ -274,15 +338,13 @@ delseq (seq)
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
>0 if it compares greater; 0 if it compares equal. */
|
||||
|
||||
static int
|
||||
keycmp (line1, line2)
|
||||
struct line *line1;
|
||||
struct line *line2;
|
||||
keycmp (struct line *line1, struct line *line2)
|
||||
{
|
||||
const char *beg1, *beg2; /* Start of field to compare in each file. */
|
||||
int len1, len2; /* Length of fields to compare. */
|
||||
const char *beg1, *beg2; /* Start of field to compare in each file. */
|
||||
int len1, len2; /* Length of fields to compare. */
|
||||
int diff;
|
||||
|
||||
if (join_field_1 < line1->nfields)
|
||||
@@ -318,12 +380,10 @@ keycmp (line1, line2)
|
||||
}
|
||||
|
||||
/* Print field N of LINE if it exists and is nonempty, otherwise
|
||||
`empty_filler' if it is nonempty. */
|
||||
`empty_filler' if it is nonempty. */
|
||||
|
||||
static void
|
||||
prfield (n, line)
|
||||
int n;
|
||||
struct line *line;
|
||||
prfield (int n, struct line *line)
|
||||
{
|
||||
int len;
|
||||
|
||||
@@ -339,22 +399,47 @@ prfield (n, line)
|
||||
fputs (empty_filler, stdout);
|
||||
}
|
||||
|
||||
/* Print the join of LINE1 and LINE2. */
|
||||
/* Print the join of LINE1 and LINE2. */
|
||||
|
||||
static void
|
||||
prjoin (line1, line2)
|
||||
struct line *line1;
|
||||
struct line *line2;
|
||||
prjoin (struct line *line1, struct line *line2)
|
||||
{
|
||||
const struct outlist *outlist;
|
||||
|
||||
outlist = outlist_head.next;
|
||||
if (outlist)
|
||||
{
|
||||
struct outlist *o;
|
||||
const struct outlist *o;
|
||||
|
||||
prfield (outlist->field - 1, outlist->file == 1 ? line1 : line2);
|
||||
for (o = outlist->next; o; o = o->next)
|
||||
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);
|
||||
field = o->field;
|
||||
}
|
||||
prfield (field, line);
|
||||
o = o->next;
|
||||
if (o == NULL)
|
||||
break;
|
||||
putchar (tab ? tab : ' ');
|
||||
prfield (o->field - 1, o->file == 1 ? line1 : line2);
|
||||
}
|
||||
putchar ('\n');
|
||||
}
|
||||
@@ -395,7 +480,7 @@ prjoin (line1, line2)
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the join of the files in FP1 and FP2. */
|
||||
/* Print the join of the files in FP1 and FP2. */
|
||||
|
||||
static void
|
||||
join (fp1, fp2)
|
||||
@@ -406,7 +491,7 @@ join (fp1, fp2)
|
||||
struct line line;
|
||||
int diff, i, j, eof1, eof2;
|
||||
|
||||
/* Read the first line of each file. */
|
||||
/* Read the first line of each file. */
|
||||
initseq (&seq1);
|
||||
getseq (fp1, &seq1);
|
||||
initseq (&seq2);
|
||||
@@ -435,7 +520,7 @@ join (fp1, fp2)
|
||||
}
|
||||
|
||||
/* Keep reading lines from file1 as long as they continue to
|
||||
match the current line from file2. */
|
||||
match the current line from file2. */
|
||||
eof1 = 0;
|
||||
do
|
||||
if (!getseq (fp1, &seq1))
|
||||
@@ -447,7 +532,7 @@ join (fp1, fp2)
|
||||
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. */
|
||||
match the current line from file1. */
|
||||
eof2 = 0;
|
||||
do
|
||||
if (!getseq (fp2, &seq2))
|
||||
@@ -512,85 +597,118 @@ join (fp1, fp2)
|
||||
delseq (&seq2);
|
||||
}
|
||||
|
||||
/* Add a field spec for field FIELD of file FILE to `outlist' and return 1,
|
||||
unless either argument is invalid; then just return 0. */
|
||||
/* Add a field spec for field FIELD of file FILE to `outlist'. */
|
||||
|
||||
static int
|
||||
add_field (file, field)
|
||||
int file;
|
||||
int field;
|
||||
static void
|
||||
add_field (int file, int field)
|
||||
{
|
||||
struct outlist *o;
|
||||
|
||||
if (file < 1 || file > 2 || field < 1)
|
||||
return 0;
|
||||
assert (file == 0 || file == 1 || file == 2);
|
||||
assert (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. */
|
||||
if (outlist == NULL)
|
||||
outlist = o;
|
||||
else
|
||||
outlist_end->next = o;
|
||||
/* Add to the end of the list so the fields are in the right order. */
|
||||
outlist_end->next = o;
|
||||
outlist_end = o;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Add the comma or blank separated field spec(s) in STR to `outlist'.
|
||||
Return the number of fields added. */
|
||||
/* 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 non-zero. */
|
||||
|
||||
static int
|
||||
add_field_list (str)
|
||||
char *str;
|
||||
decode_field_spec (const char *s, int *file_index, int *field_index)
|
||||
{
|
||||
int added = 0;
|
||||
int file = -1, field = -1;
|
||||
int dot_found = 0;
|
||||
int valid = 0;
|
||||
|
||||
for (; *str; str++)
|
||||
/* The first character must be 0, 1, or 2. */
|
||||
switch (s[0])
|
||||
{
|
||||
if (*str == ',' || ISBLANK (*str))
|
||||
case '0':
|
||||
if (s[1] == '\0')
|
||||
{
|
||||
added += add_field (file, field);
|
||||
uni_blank.nfields = max (uni_blank.nfields, field);
|
||||
file = field = -1;
|
||||
dot_found = 0;
|
||||
*file_index = 0;
|
||||
/* Leave *field_index undefined. */
|
||||
valid = 1;
|
||||
}
|
||||
else if (*str == '.')
|
||||
dot_found = 1;
|
||||
else if (ISDIGIT (*str))
|
||||
{
|
||||
if (!dot_found)
|
||||
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, NULL);
|
||||
if (s_err != LONGINT_OK || tmp_long <= 0 || tmp_long > INT_MAX)
|
||||
{
|
||||
if (file == -1)
|
||||
file = 0;
|
||||
file = file * 10 + *str - '0';
|
||||
error (0, 0, _("invalid field number: `%s'"), s + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (field == -1)
|
||||
field = 0;
|
||||
field = field * 10 + *str - '0';
|
||||
*file_index = s[0] - '0';
|
||||
/* Convert to a zero-based index. */
|
||||
*field_index = (int) tmp_long - 1;
|
||||
valid = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
uni_blank.nfields = max (uni_blank.nfields, field);
|
||||
added += add_field (file, field);
|
||||
return added;
|
||||
default:
|
||||
error (0, 0, _("invalid file number in field spec: `%s'"), s);
|
||||
break;
|
||||
}
|
||||
return !valid;
|
||||
}
|
||||
|
||||
/* Create a blank line with COUNT fields separated by tabs. */
|
||||
/* Add the comma or blank separated field spec(s) in STR to `outlist'.
|
||||
Return non-zero 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. */
|
||||
|
||||
void
|
||||
make_blank (blank, count)
|
||||
struct line *blank;
|
||||
int count;
|
||||
make_blank (struct line *blank, int count)
|
||||
{
|
||||
int i;
|
||||
blank->nfields = count;
|
||||
@@ -607,13 +725,11 @@ make_blank (blank, count)
|
||||
}
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
char *names[2];
|
||||
FILE *fp1, *fp2;
|
||||
int optc, prev_optc = 0, nfiles, val;
|
||||
int optc, prev_optc = 0, nfiles;
|
||||
|
||||
program_name = argv[0];
|
||||
|
||||
@@ -629,19 +745,25 @@ main (argc, argv)
|
||||
while ((optc = getopt_long_only (argc, argv, "-a:e:1:2:o:t:v:", longopts,
|
||||
(int *) 0)) != EOF)
|
||||
{
|
||||
long int val;
|
||||
|
||||
switch (optc)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
print_pairables = 0;
|
||||
/* Fall through. */
|
||||
|
||||
case 'a':
|
||||
val = atoi (optarg);
|
||||
if (xstrtol (optarg, NULL, 10, &val, NULL) != LONGINT_OK
|
||||
|| (val != 1 && val != 2))
|
||||
error (2, 0, _("invalid field number: `%s'"), optarg);
|
||||
if (val == 1)
|
||||
print_unpairables_1 = 1;
|
||||
else if (val == 2)
|
||||
print_unpairables_2 = 1;
|
||||
else
|
||||
error (2, 0, _("invalid file number for `-a'"));
|
||||
print_unpairables_2 = 1;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
@@ -649,56 +771,52 @@ main (argc, argv)
|
||||
break;
|
||||
|
||||
case '1':
|
||||
val = atoi (optarg);
|
||||
if (val <= 0)
|
||||
error (2, 0, _("invalid field number for `-1'"));
|
||||
join_field_1 = val - 1;
|
||||
if (xstrtol (optarg, NULL, 10, &val, NULL) != LONGINT_OK
|
||||
|| val <= 0 || val > INT_MAX)
|
||||
{
|
||||
error (2, 0, _("invalid field number for file 1: `%s'"), optarg);
|
||||
}
|
||||
join_field_1 = (int) val - 1;
|
||||
break;
|
||||
|
||||
case '2':
|
||||
val = atoi (optarg);
|
||||
if (val <= 0)
|
||||
error (2, 0, _("invalid field number for `-2'"));
|
||||
join_field_2 = val - 1;
|
||||
if (xstrtol (optarg, NULL, 10, &val, NULL) != LONGINT_OK
|
||||
|| val <= 0 || val > INT_MAX)
|
||||
error (2, 0, _("invalid field number for file 2: `%s'"), optarg);
|
||||
join_field_2 = (int) val - 1;
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
val = atoi (optarg);
|
||||
if (val <= 0)
|
||||
error (2, 0, _("invalid field number for `-j'"));
|
||||
join_field_1 = join_field_2 = val - 1;
|
||||
if (xstrtol (optarg, NULL, 10, &val, NULL) != LONGINT_OK
|
||||
|| val <= 0 || val > INT_MAX)
|
||||
error (2, 0, _("invalid field number: `%s'"), optarg);
|
||||
join_field_1 = join_field_2 = (int) val - 1;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (add_field_list (optarg) == 0)
|
||||
error (2, 0, _("invalid field list for `-o'"));
|
||||
if (add_field_list (optarg))
|
||||
exit (1);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
tab = *optarg;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
val = atoi (optarg);
|
||||
if (val == 1)
|
||||
print_unpairables_1 = 1;
|
||||
else if (val == 2)
|
||||
print_unpairables_2 = 1;
|
||||
else
|
||||
error (2, 0, _("invalid file number for `-v'"));
|
||||
print_pairables = 0;
|
||||
break;
|
||||
|
||||
case 1: /* Non-option argument. */
|
||||
if (prev_optc == 'o')
|
||||
case 1: /* Non-option argument. */
|
||||
if (prev_optc == 'o' && optind <= argc - 2)
|
||||
{
|
||||
/* Might be continuation of args to -o. */
|
||||
if (add_field_list (optarg) > 0)
|
||||
continue; /* Don't change `prev_optc'. */
|
||||
if (add_field_list (optarg))
|
||||
exit (1);
|
||||
|
||||
/* Might be continuation of args to -o. */
|
||||
continue; /* Don't change `prev_optc'. */
|
||||
}
|
||||
|
||||
if (nfiles > 1)
|
||||
usage (1);
|
||||
{
|
||||
error (0, 0, "too many non-option arguments");
|
||||
usage (1);
|
||||
}
|
||||
names[nfiles++] = optarg;
|
||||
break;
|
||||
|
||||
@@ -713,7 +831,10 @@ main (argc, argv)
|
||||
make_blank (&uni_blank, uni_blank.nfields);
|
||||
|
||||
if (nfiles != 2)
|
||||
usage (1);
|
||||
{
|
||||
error (0, 0, "too few non-option arguments");
|
||||
usage (1);
|
||||
}
|
||||
|
||||
fp1 = strcmp (names[0], "-") ? fopen (names[0], "r") : stdin;
|
||||
if (!fp1)
|
||||
@@ -725,6 +846,10 @@ main (argc, argv)
|
||||
error (1, errno, _("both files cannot be standard input"));
|
||||
join (fp1, fp2);
|
||||
|
||||
if (fp1 != stdin && fclose (fp1) == EOF)
|
||||
error (1, errno, "%s", names[0]);
|
||||
if (fp2 != stdin && fclose (fp2) == EOF)
|
||||
error (1, errno, "%s", names[1]);
|
||||
if ((fp1 == stdin || fp2 == stdin) && fclose (stdin) == EOF)
|
||||
error (1, errno, "-");
|
||||
if (ferror (stdout) || fclose (stdout) == EOF)
|
||||
@@ -732,42 +857,3 @@ main (argc, argv)
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
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);
|
||||
printf (_("\
|
||||
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 SIDE print unpairable lines coming from file SIDE\n\
|
||||
-e EMPTY replace missing input fields with EMPTY\n\
|
||||
-j FIELD join on this FIELD for both files\n\
|
||||
-[j]SIDE FIELD join on this FIELD for file SIDE\n\
|
||||
-o FORMAT obey FORMAT while constructing output line\n\
|
||||
-t CHAR use CHAR as input and output field separator\n\
|
||||
-v SIDE like -a SIDE, but suppress joined output lines\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
\n\
|
||||
SIDE is 1 for FILE1 or 2 for FILE2. Unless -t CHAR is given, leading blanks\n\
|
||||
separate fields and are ignored, else fields are separated by CHAR.\n\
|
||||
Any FIELD is a field number counted from 1. FORMAT is one or more\n\
|
||||
comma or blank separated specifications, each being `SIDE.FIELD'.\n\
|
||||
Default FORMAT outputs the join field, the remaining fields from\n\
|
||||
FILE1, the remaining fields from FILE2, all separated by CHAR.\n\
|
||||
"));
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
39
src/ls.c
39
src/ls.c
@@ -38,13 +38,16 @@
|
||||
|
||||
#include <config.h>
|
||||
#include <sys/types.h>
|
||||
#if !defined(_POSIX_SOURCE) || defined(_AIX)
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if HAVE_SYS_IOCTL_H
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
/* limits.h must come before system.h because limits.h on some systems
|
||||
undefs PATH_MAX, whereas system.h includes pathmax.h which sets
|
||||
@@ -548,8 +551,11 @@ static size_t dired_pos;
|
||||
/* With --dired, store pairs of beginning and ending indices of filenames. */
|
||||
static struct obstack dired_obstack;
|
||||
|
||||
/* With --dired and --recursive, store pairs of beginning and ending
|
||||
indices of directory names. */
|
||||
/* 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. */
|
||||
@@ -586,15 +592,20 @@ dired_dump_obstack (prefix, os)
|
||||
const char *prefix;
|
||||
struct obstack *os;
|
||||
{
|
||||
int i, n_pos;
|
||||
size_t *pos;
|
||||
int n_pos;
|
||||
|
||||
fputs (prefix, stdout);
|
||||
n_pos = obstack_object_size (os) / sizeof (size_t);
|
||||
pos = (size_t *) obstack_finish (os);
|
||||
for (i = 0; i < n_pos; i++)
|
||||
printf (" %d", (int) pos[i]);
|
||||
fputs ("\n", stdout);
|
||||
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 (" %d", (int) pos[i]);
|
||||
fputs ("\n", stdout);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -631,8 +642,7 @@ main (argc, argv)
|
||||
if (dired && format == long_format)
|
||||
{
|
||||
obstack_init (&dired_obstack);
|
||||
if (trace_dirs)
|
||||
obstack_init (&subdired_obstack);
|
||||
obstack_init (&subdired_obstack);
|
||||
}
|
||||
|
||||
nfiles = 100;
|
||||
@@ -686,8 +696,7 @@ main (argc, argv)
|
||||
{
|
||||
/* No need to free these since we're about to exit. */
|
||||
dired_dump_obstack ("//DIRED//", &dired_obstack);
|
||||
if (trace_dirs)
|
||||
dired_dump_obstack ("//SUBDIRED//", &subdired_obstack);
|
||||
dired_dump_obstack ("//SUBDIRED//", &subdired_obstack);
|
||||
}
|
||||
|
||||
exit (exit_status);
|
||||
|
||||
226
src/md5sum.c
226
src/md5sum.c
@@ -26,6 +26,7 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "long-options.h"
|
||||
#include "md5.h"
|
||||
#include "getline.h"
|
||||
#include "system.h"
|
||||
@@ -62,11 +63,13 @@
|
||||
/* Nonzero if any of the files read were the standard input. */
|
||||
static int have_read_stdin;
|
||||
|
||||
/* FIXME: comment. */
|
||||
static int quiet = 0;
|
||||
/* With --check, don't generate any output.
|
||||
The exit code indicates success or failure. */
|
||||
static int status_only = 0;
|
||||
|
||||
/* FIXME: comment. */
|
||||
static int verbose = 0;
|
||||
/* With --check, print a message to standard error warning about each
|
||||
improperly formatted MD5 checksum line. */
|
||||
static int warn = 0;
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
@@ -75,20 +78,17 @@ static const struct option long_options[] =
|
||||
{
|
||||
{ "binary", no_argument, 0, 'b' },
|
||||
{ "check", no_argument, 0, 'c' },
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ "quiet", no_argument, 0, 'q' },
|
||||
{ "string", required_argument, 0, 's' },
|
||||
{ "status", no_argument, 0, 2 },
|
||||
{ "string", required_argument, 0, 1 },
|
||||
{ "text", no_argument, 0, 't' },
|
||||
{ "verbose", no_argument, 0, 'v' },
|
||||
{ "version", no_argument, 0, 'V' },
|
||||
{ "warn", no_argument, 0, 'w' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
char *xmalloc ();
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
int status;
|
||||
usage (int status)
|
||||
{
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
@@ -100,22 +100,23 @@ Usage: %s [OPTION] [FILE]...\n\
|
||||
or: %s [OPTION] --string=STRING ...\n\
|
||||
Print or check MD5 checksums.\n\
|
||||
With no FILE, or when FILE is -, read standard input.\n\
|
||||
\n\
|
||||
-h, --help display this help and exit\n\
|
||||
-q, --quiet don't output anything, status code shows success\n\
|
||||
-v, --verbose verbose output level\n\
|
||||
-V, --version output version information and exit\n\
|
||||
\n\
|
||||
-b, --binary read files in binary mode\n\
|
||||
-t, --text read files in text mode (default)\n\
|
||||
\n\
|
||||
-c, --check check MD5 sums against given list\n\
|
||||
-s, --string=STRING compute checksum for STRING\n\
|
||||
\n\
|
||||
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 MD5 checksum lines\n\
|
||||
\n\
|
||||
--string=STRING compute checksum for STRING\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
\n\
|
||||
The sums are computed as described in RFC 1321. 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. The --quiet and --verbose options are\n\
|
||||
text), and name for each FILE. The --status and --warn options are\n\
|
||||
meaningful only when verifying checksums.\n"),
|
||||
program_name, program_name, program_name);
|
||||
|
||||
@@ -125,9 +126,7 @@ meaningful only when verifying checksums.\n"),
|
||||
/* FIXME: this format loses with filenames containing newline. */
|
||||
|
||||
static int
|
||||
split_3 (s, u, binary, w)
|
||||
char *s, **u, **w;
|
||||
int *binary;
|
||||
split_3 (char *s, char **u, int *binary, char **w)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
@@ -167,11 +166,8 @@ split_3 (s, u, binary, w)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME: use strcspn. */
|
||||
|
||||
static int
|
||||
hex_digits (s)
|
||||
const char *s;
|
||||
hex_digits (const char *s)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
@@ -183,12 +179,11 @@ hex_digits (s)
|
||||
}
|
||||
|
||||
/* FIXME: allow newline in filename by encoding it. */
|
||||
/* FIXME: distinguish between file open/read failure and inconsistent
|
||||
checksum. */
|
||||
|
||||
static int
|
||||
md5_file (filename, binary, md5_result)
|
||||
const char *filename;
|
||||
int binary;
|
||||
unsigned char *md5_result;
|
||||
md5_file (const char *filename, int binary, unsigned char *md5_result)
|
||||
{
|
||||
FILE *fp;
|
||||
int err;
|
||||
@@ -231,13 +226,12 @@ md5_file (filename, binary, md5_result)
|
||||
}
|
||||
|
||||
static int
|
||||
md5_check (checkfile_name, binary)
|
||||
const char *checkfile_name;
|
||||
int binary;
|
||||
md5_check (const char *checkfile_name, int binary)
|
||||
{
|
||||
FILE *checkfile_stream;
|
||||
int n_tests = 0;
|
||||
int n_tests_failed = 0;
|
||||
int n_properly_formated_lines = 0;
|
||||
int n_mismatched_checksums = 0;
|
||||
int n_open_or_read_failures = 0;
|
||||
unsigned char md5buffer[16];
|
||||
size_t line_number;
|
||||
char *line;
|
||||
@@ -287,9 +281,10 @@ md5_check (checkfile_name, binary)
|
||||
err = split_3 (line, &md5num, &type_flag, &filename);
|
||||
if (err || !hex_digits (md5num))
|
||||
{
|
||||
if (verbose)
|
||||
if (warn)
|
||||
{
|
||||
error (0, 0, _("%s: %lu: invalid MD5 checksum line"),
|
||||
error (0, 0,
|
||||
_("%s: %lu: improperly formatted MD5 checksum line"),
|
||||
checkfile_name, (unsigned long) line_number);
|
||||
}
|
||||
}
|
||||
@@ -301,11 +296,20 @@ md5_check (checkfile_name, binary)
|
||||
'c', 'd', 'e', 'f' };
|
||||
int fail;
|
||||
|
||||
++n_tests;
|
||||
++n_properly_formated_lines;
|
||||
|
||||
fail = md5_file (filename, binary, md5buffer);
|
||||
|
||||
if (!fail)
|
||||
if (fail)
|
||||
{
|
||||
++n_open_or_read_failures;
|
||||
if (!status_only)
|
||||
{
|
||||
printf (_("%s: FAILED open or read\n"), filename);
|
||||
fflush (stdout);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t cnt;
|
||||
/* Compare generated binary number with text representation
|
||||
@@ -318,100 +322,96 @@ md5_check (checkfile_name, binary)
|
||||
break;
|
||||
}
|
||||
if (cnt != 16)
|
||||
fail = 1;
|
||||
}
|
||||
++n_mismatched_checksums;
|
||||
|
||||
if (fail)
|
||||
++n_tests_failed;
|
||||
|
||||
if (!quiet)
|
||||
{
|
||||
printf ("%s: %s\n", filename, (fail ? _("FAILED") : _("OK")));
|
||||
fflush (stdout);
|
||||
if (!status_only)
|
||||
{
|
||||
printf ("%s: %s\n", filename,
|
||||
(cnt != 16 ? _("FAILED") : _("OK")));
|
||||
fflush (stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!feof (checkfile_stream) && !ferror (checkfile_stream));
|
||||
|
||||
/* FIXME: check ferror!! */
|
||||
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_tests == 0)
|
||||
if (n_properly_formated_lines == 0)
|
||||
{
|
||||
/* FIXME: warn (or even fail?) if no tests are found? */
|
||||
/* Warn if no tests are found. */
|
||||
error (0, 0, _("%s: no properly formatted MD5 checksum lines found"),
|
||||
checkfile_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!quiet)
|
||||
if (!status_only)
|
||||
{
|
||||
if (n_tests_failed == 0)
|
||||
int n_computed_checkums = (n_properly_formated_lines
|
||||
- n_open_or_read_failures);
|
||||
|
||||
if (n_open_or_read_failures > 0)
|
||||
{
|
||||
printf (n_tests == 1
|
||||
? _("the single test passed\n")
|
||||
: _("all %d tests passed\n"), n_tests);
|
||||
error (0, 0,
|
||||
_("WARNING: %d of %d listed file%s could not be read\n"),
|
||||
n_open_or_read_failures, n_properly_formated_lines,
|
||||
(n_properly_formated_lines == 1 ? "" : "s"));
|
||||
}
|
||||
else
|
||||
|
||||
if (n_mismatched_checksums > 0)
|
||||
{
|
||||
printf (n_tests == 1
|
||||
? _("the single test failed\n")
|
||||
: _("%d out of %d tests failed\n"),
|
||||
n_tests_failed, n_tests);
|
||||
error (0, 0,
|
||||
_("WARNING: %d of %d computed checksum%s did NOT match\n"),
|
||||
n_mismatched_checksums, n_computed_checkums,
|
||||
(n_computed_checkums == 1 ? "" : "s"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ((n_tests > 0 && n_tests_failed == 0) ? 0 : 1);
|
||||
return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0
|
||||
&& n_open_or_read_failures == 0) ? 0 : 1);
|
||||
}
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
unsigned char md5buffer[16];
|
||||
int do_check = 0;
|
||||
int do_help = 0;
|
||||
int do_version = 0;
|
||||
int opt;
|
||||
char **string = NULL;
|
||||
char n_strings = 0;
|
||||
size_t n_strings = 0;
|
||||
size_t i;
|
||||
size_t err = 0;
|
||||
|
||||
/* FIXME: comment. */
|
||||
/* Text is default of the Plumb/Lankester format. */
|
||||
int binary = 0;
|
||||
|
||||
/* Setting values of global variables. */
|
||||
program_name = argv[0];
|
||||
|
||||
while ((opt = getopt_long (argc, argv, "bchqs:tvV", long_options, NULL))
|
||||
parse_long_options (argc, argv, "md5sum", version_string, usage);
|
||||
|
||||
while ((opt = getopt_long (argc, argv, "bctw", long_options, NULL))
|
||||
!= EOF)
|
||||
switch (opt)
|
||||
{
|
||||
case 0: /* long option */
|
||||
break;
|
||||
case 'b':
|
||||
binary = 1;
|
||||
break;
|
||||
case 'c':
|
||||
do_check = 1;
|
||||
break;
|
||||
case 'h':
|
||||
do_help = 1;
|
||||
break;
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
verbose = 0;
|
||||
break;
|
||||
case 's':
|
||||
case 1: /* --string */
|
||||
{
|
||||
if (string == NULL)
|
||||
string = (char **) xmalloc ((argc - 1) * sizeof (char *));
|
||||
@@ -421,15 +421,22 @@ main (argc, argv)
|
||||
string[n_strings++] = optarg;
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
binary = 1;
|
||||
break;
|
||||
case 'c':
|
||||
do_check = 1;
|
||||
break;
|
||||
case 2:
|
||||
status_only = 1;
|
||||
warn = 0;
|
||||
break;
|
||||
case 't':
|
||||
binary = 0;
|
||||
break;
|
||||
case 'v':
|
||||
quiet = 0;
|
||||
verbose = 1;
|
||||
break;
|
||||
case 'V':
|
||||
do_version = 1;
|
||||
case 'w':
|
||||
status_only = 0;
|
||||
warn = 1;
|
||||
break;
|
||||
default:
|
||||
usage (EXIT_FAILURE);
|
||||
@@ -441,21 +448,24 @@ main (argc, argv)
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (do_help)
|
||||
usage (EXIT_SUCCESS);
|
||||
|
||||
if (n_strings > 0 && do_check != 0)
|
||||
if (n_strings > 0 && do_check)
|
||||
{
|
||||
error (0, 0,
|
||||
_("the --string and --check options are mutually exclusive"));
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if ((quiet || verbose) && do_check == 0)
|
||||
if (status_only && !do_check)
|
||||
{
|
||||
error (0, 0,
|
||||
_("the --quiet and --verbose options are meaningful only\n\
|
||||
when verifying checksums"));
|
||||
_("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);
|
||||
}
|
||||
|
||||
@@ -477,7 +487,18 @@ when verifying checksums"));
|
||||
printf (" \"%s\"\n", string[i]);
|
||||
}
|
||||
}
|
||||
else if (do_check == 0)
|
||||
else if (do_check)
|
||||
{
|
||||
if (optind + 1 < argc)
|
||||
{
|
||||
error (0, 0,
|
||||
_("only one argument may be specified when using --check"));
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
err = md5_check ((optind == argc) ? "-" : argv[optind], binary);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (optind == argc)
|
||||
argv[argc++] = "-";
|
||||
@@ -498,17 +519,6 @@ when verifying checksums"));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (optind + 1 < argc)
|
||||
{
|
||||
error (0, 0,
|
||||
_("only one argument may be specified when using --check"));
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
err = md5_check ((optind == argc) ? "-" : argv[optind], binary);
|
||||
}
|
||||
|
||||
if (fclose (stdout) == EOF)
|
||||
error (EXIT_FAILURE, errno, _("write error"));
|
||||
|
||||
4
src/mv.c
4
src/mv.c
@@ -62,7 +62,7 @@ int yesno ();
|
||||
int safe_read ();
|
||||
int full_write ();
|
||||
void strip_trailing_slashes ();
|
||||
int eaccess_stat ();
|
||||
int euidaccess ();
|
||||
char *stpcpy ();
|
||||
|
||||
static int copy_reg ();
|
||||
@@ -276,7 +276,7 @@ do_move (source, dest)
|
||||
return 0;
|
||||
|
||||
if (!override_mode && (interactive || stdin_tty)
|
||||
&& eaccess_stat (&dest_stats, W_OK, dest))
|
||||
&& euidaccess (dest, W_OK))
|
||||
{
|
||||
fprintf (stderr, "%s: replace `%s', overriding mode %04o? ",
|
||||
program_name, dest,
|
||||
|
||||
577
src/nl.c
577
src/nl.c
@@ -55,18 +55,6 @@ enum section
|
||||
char *xmalloc ();
|
||||
char *xrealloc ();
|
||||
|
||||
static enum section check_section ();
|
||||
static int build_type_arg ();
|
||||
static int nl_file ();
|
||||
static void usage ();
|
||||
static void process_file ();
|
||||
static void proc_header ();
|
||||
static void proc_body ();
|
||||
static void proc_footer ();
|
||||
static void proc_text ();
|
||||
static void print_lineno ();
|
||||
static void build_print_fmt ();
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
@@ -175,10 +163,286 @@ static struct option const longopts[] =
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* Print a usage message and quit. */
|
||||
|
||||
static 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 (_("\
|
||||
Write each FILE to standard output, with line numbers added.\n\
|
||||
With no FILE, or when FILE is -, read standard input.\n\
|
||||
\n\
|
||||
-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\
|
||||
-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\
|
||||
-v, --first-page=NUMBER first line number on each logical page\n\
|
||||
-w, --number-width=NUMBER use NUMBER columns for line numbers\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
\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\
|
||||
\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\
|
||||
"));
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
/* Build the printf format string, based on `lineno_format'. */
|
||||
|
||||
static void
|
||||
build_print_fmt (void)
|
||||
{
|
||||
/* 12 = 10 chars for lineno_width, 1 for %, 1 for \0. */
|
||||
print_fmt = xmalloc (strlen (separator_str) + 12);
|
||||
switch (lineno_format)
|
||||
{
|
||||
case FORMAT_RIGHT_NOLZ:
|
||||
sprintf (print_fmt, "%%%dd%s", lineno_width, separator_str);
|
||||
break;
|
||||
case FORMAT_RIGHT_LZ:
|
||||
sprintf (print_fmt, "%%0%dd%s", lineno_width, separator_str);
|
||||
break;
|
||||
case FORMAT_LEFT:
|
||||
sprintf (print_fmt, "%%-%dd%s", lineno_width, separator_str);
|
||||
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 (1, 0, "%s", errmsg);
|
||||
break;
|
||||
default:
|
||||
rval = FALSE;
|
||||
break;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* Print and increment the line number. */
|
||||
|
||||
static void
|
||||
print_lineno (void)
|
||||
{
|
||||
printf (print_fmt, line_no);
|
||||
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 = page_start;
|
||||
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 (line_buf.length || ++blank_lines == blank_join)
|
||||
{
|
||||
print_lineno ();
|
||||
blank_lines = 0;
|
||||
}
|
||||
else
|
||||
printf (print_no_line_fmt);
|
||||
}
|
||||
else
|
||||
print_lineno ();
|
||||
break;
|
||||
case 't':
|
||||
if (line_buf.length)
|
||||
print_lineno ();
|
||||
else
|
||||
printf (print_no_line_fmt);
|
||||
break;
|
||||
case 'n':
|
||||
printf (print_no_line_fmt);
|
||||
break;
|
||||
case 'p':
|
||||
if (re_search (current_regex, line_buf.buffer, line_buf.length,
|
||||
0, line_buf.length, (struct re_registers *) 0) < 0)
|
||||
printf (print_no_line_fmt);
|
||||
else
|
||||
print_lineno ();
|
||||
break;
|
||||
}
|
||||
fwrite (line_buf.buffer, sizeof (char), line_buf.length, stdout);
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
/* Return the type of line in `line_buf'. */
|
||||
|
||||
static enum section
|
||||
check_section (void)
|
||||
{
|
||||
if (line_buf.length < 2 || memcmp (line_buf.buffer, section_del, 2))
|
||||
return Text;
|
||||
if (line_buf.length == header_del_len
|
||||
&& !memcmp (line_buf.buffer, header_del, header_del_len))
|
||||
return Header;
|
||||
if (line_buf.length == body_del_len
|
||||
&& !memcmp (line_buf.buffer, body_del, body_del_len))
|
||||
return Body;
|
||||
if (line_buf.length == 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 (!strcmp (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 (!strcmp (file, "-"))
|
||||
clearerr (stream); /* Also clear EOF. */
|
||||
else if (fclose (stream) == EOF)
|
||||
{
|
||||
error (0, errno, "%s", file);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int c, exit_status = 0;
|
||||
|
||||
@@ -320,286 +584,3 @@ main (argc, argv)
|
||||
|
||||
exit (exit_status);
|
||||
}
|
||||
|
||||
/* Process file FILE to standard output.
|
||||
Return 0 if successful, 1 if not. */
|
||||
|
||||
static int
|
||||
nl_file (file)
|
||||
char *file;
|
||||
{
|
||||
FILE *stream;
|
||||
|
||||
if (!strcmp (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 (!strcmp (file, "-"))
|
||||
clearerr (stream); /* Also clear EOF. */
|
||||
else if (fclose (stream) == EOF)
|
||||
{
|
||||
error (0, errno, "%s", file);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read and process the file pointed to by FP. */
|
||||
|
||||
static void
|
||||
process_file (fp)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the type of line in `line_buf'. */
|
||||
|
||||
static enum section
|
||||
check_section ()
|
||||
{
|
||||
if (line_buf.length < 2 || memcmp (line_buf.buffer, section_del, 2))
|
||||
return Text;
|
||||
if (line_buf.length == header_del_len
|
||||
&& !memcmp (line_buf.buffer, header_del, header_del_len))
|
||||
return Header;
|
||||
if (line_buf.length == body_del_len
|
||||
&& !memcmp (line_buf.buffer, body_del, body_del_len))
|
||||
return Body;
|
||||
if (line_buf.length == footer_del_len
|
||||
&& !memcmp (line_buf.buffer, footer_del, footer_del_len))
|
||||
return Footer;
|
||||
return Text;
|
||||
}
|
||||
|
||||
/* Switch to a header section. */
|
||||
|
||||
static void
|
||||
proc_header ()
|
||||
{
|
||||
current_type = header_type;
|
||||
current_regex = &header_regex;
|
||||
if (reset_numbers)
|
||||
line_no = page_start;
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
/* Switch to a body section. */
|
||||
|
||||
static void
|
||||
proc_body ()
|
||||
{
|
||||
current_type = body_type;
|
||||
current_regex = &body_regex;
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
/* Switch to a footer section. */
|
||||
|
||||
static void
|
||||
proc_footer ()
|
||||
{
|
||||
current_type = footer_type;
|
||||
current_regex = &footer_regex;
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
/* Process a regular text line in `line_buf'. */
|
||||
|
||||
static void
|
||||
proc_text ()
|
||||
{
|
||||
static int blank_lines = 0; /* Consecutive blank lines so far. */
|
||||
|
||||
switch (*current_type)
|
||||
{
|
||||
case 'a':
|
||||
if (blank_join > 1)
|
||||
{
|
||||
if (line_buf.length || ++blank_lines == blank_join)
|
||||
{
|
||||
print_lineno ();
|
||||
blank_lines = 0;
|
||||
}
|
||||
else
|
||||
printf (print_no_line_fmt);
|
||||
}
|
||||
else
|
||||
print_lineno ();
|
||||
break;
|
||||
case 't':
|
||||
if (line_buf.length)
|
||||
print_lineno ();
|
||||
else
|
||||
printf (print_no_line_fmt);
|
||||
break;
|
||||
case 'n':
|
||||
printf (print_no_line_fmt);
|
||||
break;
|
||||
case 'p':
|
||||
if (re_search (current_regex, line_buf.buffer, line_buf.length,
|
||||
0, line_buf.length, (struct re_registers *) 0) < 0)
|
||||
printf (print_no_line_fmt);
|
||||
else
|
||||
print_lineno ();
|
||||
break;
|
||||
}
|
||||
fwrite (line_buf.buffer, sizeof (char), line_buf.length, stdout);
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
/* Print and increment the line number. */
|
||||
|
||||
static void
|
||||
print_lineno ()
|
||||
{
|
||||
printf (print_fmt, line_no);
|
||||
line_no += page_incr;
|
||||
}
|
||||
|
||||
/* Build the printf format string, based on `lineno_format'. */
|
||||
|
||||
static void
|
||||
build_print_fmt ()
|
||||
{
|
||||
/* 12 = 10 chars for lineno_width, 1 for %, 1 for \0. */
|
||||
print_fmt = xmalloc (strlen (separator_str) + 12);
|
||||
switch (lineno_format)
|
||||
{
|
||||
case FORMAT_RIGHT_NOLZ:
|
||||
sprintf (print_fmt, "%%%dd%s", lineno_width, separator_str);
|
||||
break;
|
||||
case FORMAT_RIGHT_LZ:
|
||||
sprintf (print_fmt, "%%0%dd%s", lineno_width, separator_str);
|
||||
break;
|
||||
case FORMAT_LEFT:
|
||||
sprintf (print_fmt, "%%-%dd%s", lineno_width, separator_str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the command line flag TYPEP and possibly the regex pointer REGEXP,
|
||||
according to `optarg'. */
|
||||
|
||||
static int
|
||||
build_type_arg (typep, regexp)
|
||||
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 (1, 0, "%s", errmsg);
|
||||
break;
|
||||
default:
|
||||
rval = FALSE;
|
||||
break;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* Print a usage message and quit. */
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
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 (_("\
|
||||
Write each FILE to standard output, with line numbers added.\n\
|
||||
With no FILE, or when FILE is -, read standard input.\n\
|
||||
\n\
|
||||
-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\
|
||||
-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\
|
||||
-v, --first-page=NUMBER first line number on each logical page\n\
|
||||
-w, --number-width=NUMBER use NUMBER columns for line numbers\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
\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\
|
||||
\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\
|
||||
"));
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
162
src/od.c
162
src/od.c
@@ -12,8 +12,8 @@
|
||||
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. */
|
||||
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. */
|
||||
|
||||
@@ -54,37 +54,37 @@ typedef double LONG_DOUBLE;
|
||||
#endif
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
# include <limits.h>
|
||||
#endif
|
||||
#ifndef SCHAR_MAX
|
||||
#define SCHAR_MAX 127
|
||||
# define SCHAR_MAX 127
|
||||
#endif
|
||||
#ifndef SCHAR_MIN
|
||||
#define SCHAR_MIN (-128)
|
||||
# define SCHAR_MIN (-128)
|
||||
#endif
|
||||
#ifndef SHRT_MAX
|
||||
#define SHRT_MAX 32767
|
||||
# define SHRT_MAX 32767
|
||||
#endif
|
||||
#ifndef SHRT_MIN
|
||||
#define SHRT_MIN (-32768)
|
||||
# define SHRT_MIN (-32768)
|
||||
#endif
|
||||
#ifndef ULONG_MAX
|
||||
#define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
|
||||
# define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
|
||||
#endif
|
||||
#ifndef OFF_T_MAX
|
||||
/* FIXME: is there a way to do this without relying on the
|
||||
`8 bits per byte' assumption? */
|
||||
#define OFF_T_MAX (~((off_t)1 << (sizeof (off_t) * 8 - 1)))
|
||||
# define OFF_T_MAX (~((off_t)1 << (sizeof (off_t) * 8 - 1)))
|
||||
#endif
|
||||
|
||||
#define STREQ(a,b) (strcmp((a), (b)) == 0)
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
# define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/* The default number of input bytes per output line. */
|
||||
@@ -92,17 +92,17 @@ typedef double LONG_DOUBLE;
|
||||
|
||||
/* The number of decimal digits of precision in a float. */
|
||||
#ifndef FLT_DIG
|
||||
#define FLT_DIG 7
|
||||
# define FLT_DIG 7
|
||||
#endif
|
||||
|
||||
/* The number of decimal digits of precision in a double. */
|
||||
#ifndef DBL_DIG
|
||||
#define DBL_DIG 15
|
||||
# define DBL_DIG 15
|
||||
#endif
|
||||
|
||||
/* The number of decimal digits of precision in a long double. */
|
||||
#ifndef LDBL_DIG
|
||||
#define LDBL_DIG DBL_DIG
|
||||
# define LDBL_DIG DBL_DIG
|
||||
#endif
|
||||
|
||||
char *xmalloc ();
|
||||
@@ -298,8 +298,7 @@ static struct option const long_options[] =
|
||||
};
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
int status;
|
||||
usage (int status)
|
||||
{
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
@@ -374,9 +373,7 @@ uses -A o -t d2 -w 16.\n\
|
||||
using Euclid's algorithm. */
|
||||
|
||||
static unsigned int
|
||||
gcd (u, v)
|
||||
unsigned int u;
|
||||
unsigned int v;
|
||||
gcd (unsigned int u, unsigned int v)
|
||||
{
|
||||
unsigned int t;
|
||||
while (v != 0)
|
||||
@@ -391,9 +388,7 @@ gcd (u, v)
|
||||
/* Compute the least common multiple of U and V. */
|
||||
|
||||
static unsigned int
|
||||
lcm (u, v)
|
||||
unsigned int u;
|
||||
unsigned int v;
|
||||
lcm (unsigned int u, unsigned int v)
|
||||
{
|
||||
unsigned int t = gcd (u, v);
|
||||
if (t == 0)
|
||||
@@ -402,10 +397,8 @@ lcm (u, v)
|
||||
}
|
||||
|
||||
static void
|
||||
print_s_char (n_bytes, block, fmt_string)
|
||||
long unsigned int n_bytes;
|
||||
const char *block;
|
||||
const char *fmt_string;
|
||||
print_s_char (long unsigned int n_bytes, const char *block,
|
||||
const char *fmt_string)
|
||||
{
|
||||
int i;
|
||||
for (i = n_bytes; i > 0; i--)
|
||||
@@ -420,10 +413,8 @@ print_s_char (n_bytes, block, fmt_string)
|
||||
}
|
||||
|
||||
static void
|
||||
print_char (n_bytes, block, fmt_string)
|
||||
long unsigned int n_bytes;
|
||||
const char *block;
|
||||
const char *fmt_string;
|
||||
print_char (long unsigned int n_bytes, const char *block,
|
||||
const char *fmt_string)
|
||||
{
|
||||
int i;
|
||||
for (i = n_bytes; i > 0; i--)
|
||||
@@ -435,10 +426,8 @@ print_char (n_bytes, block, fmt_string)
|
||||
}
|
||||
|
||||
static void
|
||||
print_s_short (n_bytes, block, fmt_string)
|
||||
long unsigned int n_bytes;
|
||||
const char *block;
|
||||
const char *fmt_string;
|
||||
print_s_short (long unsigned int n_bytes, const char *block,
|
||||
const char *fmt_string)
|
||||
{
|
||||
int i;
|
||||
for (i = n_bytes / sizeof (unsigned short); i > 0; i--)
|
||||
@@ -452,10 +441,8 @@ print_s_short (n_bytes, block, fmt_string)
|
||||
}
|
||||
}
|
||||
static void
|
||||
print_short (n_bytes, block, fmt_string)
|
||||
long unsigned int n_bytes;
|
||||
const char *block;
|
||||
const char *fmt_string;
|
||||
print_short (long unsigned int n_bytes, const char *block,
|
||||
const char *fmt_string)
|
||||
{
|
||||
int i;
|
||||
for (i = n_bytes / sizeof (unsigned short); i > 0; i--)
|
||||
@@ -467,10 +454,8 @@ print_short (n_bytes, block, fmt_string)
|
||||
}
|
||||
|
||||
static void
|
||||
print_int (n_bytes, block, fmt_string)
|
||||
long unsigned int n_bytes;
|
||||
const char *block;
|
||||
const char *fmt_string;
|
||||
print_int (long unsigned int n_bytes, const char *block,
|
||||
const char *fmt_string)
|
||||
{
|
||||
int i;
|
||||
for (i = n_bytes / sizeof (unsigned int); i > 0; i--)
|
||||
@@ -482,10 +467,8 @@ print_int (n_bytes, block, fmt_string)
|
||||
}
|
||||
|
||||
static void
|
||||
print_long (n_bytes, block, fmt_string)
|
||||
long unsigned int n_bytes;
|
||||
const char *block;
|
||||
const char *fmt_string;
|
||||
print_long (long unsigned int n_bytes, const char *block,
|
||||
const char *fmt_string)
|
||||
{
|
||||
int i;
|
||||
for (i = n_bytes / sizeof (unsigned long); i > 0; i--)
|
||||
@@ -497,10 +480,8 @@ print_long (n_bytes, block, fmt_string)
|
||||
}
|
||||
|
||||
static void
|
||||
print_float (n_bytes, block, fmt_string)
|
||||
long unsigned int n_bytes;
|
||||
const char *block;
|
||||
const char *fmt_string;
|
||||
print_float (long unsigned int n_bytes, const char *block,
|
||||
const char *fmt_string)
|
||||
{
|
||||
int i;
|
||||
for (i = n_bytes / sizeof (float); i > 0; i--)
|
||||
@@ -512,10 +493,8 @@ print_float (n_bytes, block, fmt_string)
|
||||
}
|
||||
|
||||
static void
|
||||
print_double (n_bytes, block, fmt_string)
|
||||
long unsigned int n_bytes;
|
||||
const char *block;
|
||||
const char *fmt_string;
|
||||
print_double (long unsigned int n_bytes, const char *block,
|
||||
const char *fmt_string)
|
||||
{
|
||||
int i;
|
||||
for (i = n_bytes / sizeof (double); i > 0; i--)
|
||||
@@ -528,10 +507,8 @@ print_double (n_bytes, block, fmt_string)
|
||||
|
||||
#ifdef HAVE_LONG_DOUBLE
|
||||
static void
|
||||
print_long_double (n_bytes, block, fmt_string)
|
||||
long unsigned int n_bytes;
|
||||
const char *block;
|
||||
const char *fmt_string;
|
||||
print_long_double (long unsigned int n_bytes, const char *block,
|
||||
const char *fmt_string)
|
||||
{
|
||||
int i;
|
||||
for (i = n_bytes / sizeof (LONG_DOUBLE); i > 0; i--)
|
||||
@@ -545,10 +522,8 @@ print_long_double (n_bytes, block, fmt_string)
|
||||
#endif
|
||||
|
||||
static void
|
||||
print_named_ascii (n_bytes, block, unused_fmt_string)
|
||||
long unsigned int n_bytes;
|
||||
const char *block;
|
||||
const char *unused_fmt_string;
|
||||
print_named_ascii (long unsigned int n_bytes, const char *block,
|
||||
const char *unused_fmt_string)
|
||||
{
|
||||
int i;
|
||||
for (i = n_bytes; i > 0; i--)
|
||||
@@ -574,10 +549,8 @@ print_named_ascii (n_bytes, block, unused_fmt_string)
|
||||
}
|
||||
|
||||
static void
|
||||
print_ascii (n_bytes, block, unused_fmt_string)
|
||||
long unsigned int n_bytes;
|
||||
const char *block;
|
||||
const char *unused_fmt_string;
|
||||
print_ascii (long unsigned int n_bytes, const char *block,
|
||||
const char *unused_fmt_string)
|
||||
{
|
||||
int i;
|
||||
for (i = n_bytes; i > 0; i--)
|
||||
@@ -639,10 +612,7 @@ print_ascii (n_bytes, block, unused_fmt_string)
|
||||
the result of the conversion and return zero. */
|
||||
|
||||
static int
|
||||
simple_strtoul (s, p, val)
|
||||
const char *s;
|
||||
const char **p;
|
||||
long unsigned int *val;
|
||||
simple_strtoul (const char *s, const char **p, long unsigned int *val)
|
||||
{
|
||||
unsigned long int sum;
|
||||
|
||||
@@ -674,10 +644,7 @@ simple_strtoul (s, p, val)
|
||||
*/
|
||||
|
||||
static int
|
||||
decode_one_format (s, next, tspec)
|
||||
const char *s;
|
||||
const char **next;
|
||||
struct tspec *tspec;
|
||||
decode_one_format (const char *s, const char **next, struct tspec *tspec)
|
||||
{
|
||||
enum size_spec size_spec;
|
||||
unsigned long int size;
|
||||
@@ -787,7 +754,7 @@ decode_one_format (s, next, tspec)
|
||||
case SHORT:
|
||||
print_function = (fmt == SIGNED_DECIMAL
|
||||
? print_s_short
|
||||
: print_short);;
|
||||
: print_short);
|
||||
break;
|
||||
|
||||
case INT:
|
||||
@@ -909,8 +876,7 @@ decode_one_format (s, next, tspec)
|
||||
necessary. Return zero if S is valid, non-zero otherwise. */
|
||||
|
||||
static int
|
||||
decode_format_string (s)
|
||||
const char *s;
|
||||
decode_format_string (const char *s)
|
||||
{
|
||||
assert (s != NULL);
|
||||
|
||||
@@ -948,8 +914,7 @@ decode_format_string (s)
|
||||
input. */
|
||||
|
||||
static int
|
||||
skip (n_skip)
|
||||
off_t n_skip;
|
||||
skip (off_t n_skip)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -1050,15 +1015,13 @@ skip (n_skip)
|
||||
}
|
||||
|
||||
static const char *
|
||||
format_address_none (address)
|
||||
long unsigned int address;
|
||||
format_address_none (long unsigned int address)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
static const char *
|
||||
format_address_std (address)
|
||||
long unsigned int address;
|
||||
format_address_std (long unsigned int address)
|
||||
{
|
||||
const char *address_string;
|
||||
|
||||
@@ -1068,8 +1031,7 @@ format_address_std (address)
|
||||
}
|
||||
|
||||
static const char *
|
||||
format_address_label (address)
|
||||
long unsigned int address;
|
||||
format_address_label (long unsigned int address)
|
||||
{
|
||||
const char *address_string;
|
||||
assert (output_address_fmt_string != NULL);
|
||||
@@ -1092,11 +1054,8 @@ format_address_label (address)
|
||||
only when it has not been padded to length BYTES_PER_BLOCK. */
|
||||
|
||||
static void
|
||||
write_block (current_offset, n_bytes, prev_block, curr_block)
|
||||
long unsigned int current_offset;
|
||||
long unsigned int n_bytes;
|
||||
const char *prev_block;
|
||||
const char *curr_block;
|
||||
write_block (long unsigned int current_offset, long unsigned int n_bytes,
|
||||
const char *prev_block, const char *curr_block)
|
||||
{
|
||||
static int first = 1;
|
||||
static int prev_pair_equal = 0;
|
||||
@@ -1141,7 +1100,7 @@ write_block (current_offset, n_bytes, prev_block, curr_block)
|
||||
have occurred. */
|
||||
|
||||
static int
|
||||
check_and_close ()
|
||||
check_and_close (void)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -1181,8 +1140,7 @@ check_and_close ()
|
||||
occured, zero otherwise. */
|
||||
|
||||
static int
|
||||
read_char (c)
|
||||
int *c;
|
||||
read_char (int *c)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -1244,10 +1202,7 @@ read_char (c)
|
||||
Otherwise return zero. */
|
||||
|
||||
static int
|
||||
read_block (n, block, n_bytes_in_buffer)
|
||||
size_t n;
|
||||
char *block;
|
||||
size_t *n_bytes_in_buffer;
|
||||
read_block (size_t n, char *block, size_t *n_bytes_in_buffer)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -1308,7 +1263,7 @@ read_block (n, block, n_bytes_in_buffer)
|
||||
with the format specs. */
|
||||
|
||||
static int
|
||||
get_lcm ()
|
||||
get_lcm (void)
|
||||
{
|
||||
unsigned int i;
|
||||
int l_c_m = 1;
|
||||
@@ -1322,8 +1277,7 @@ get_lcm ()
|
||||
return the offset it denotes. Otherwise, return -1. */
|
||||
|
||||
off_t
|
||||
parse_old_offset (s)
|
||||
const char *s;
|
||||
parse_old_offset (const char *s)
|
||||
{
|
||||
int radix;
|
||||
off_t offset;
|
||||
@@ -1373,7 +1327,7 @@ parse_old_offset (s)
|
||||
Otherwise, return zero. */
|
||||
|
||||
static int
|
||||
dump ()
|
||||
dump (void)
|
||||
{
|
||||
char *block[2];
|
||||
off_t current_offset;
|
||||
@@ -1466,7 +1420,7 @@ dump ()
|
||||
occurs. Otherwise, return zero. */
|
||||
|
||||
static int
|
||||
dump_strings ()
|
||||
dump_strings (void)
|
||||
{
|
||||
size_t bufsize = MAX (100, string_min);
|
||||
char *buf = xmalloc (bufsize);
|
||||
@@ -1581,9 +1535,7 @@ dump_strings ()
|
||||
}
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
int n_files;
|
||||
|
||||
145
src/paste.c
145
src/paste.c
@@ -50,11 +50,6 @@
|
||||
char *xmalloc ();
|
||||
char *xrealloc ();
|
||||
|
||||
static char *collapse_escapes ();
|
||||
static int paste_parallel ();
|
||||
static int paste_serial ();
|
||||
static void usage ();
|
||||
|
||||
/* Indicates that no delimiter should be added in the current position. */
|
||||
#define EMPTY_DELIM '\0'
|
||||
|
||||
@@ -97,70 +92,6 @@ static struct option const longopts[] =
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int optc, exit_status;
|
||||
char default_delims[2], zero_delims[3];
|
||||
|
||||
program_name = argv[0];
|
||||
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, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
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;
|
||||
|
||||
default:
|
||||
usage (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (show_version)
|
||||
{
|
||||
printf ("paste - %s\n", version_string);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (show_help)
|
||||
usage (0);
|
||||
|
||||
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 (1, errno, "-");
|
||||
if (ferror (stdout) || fclose (stdout) == EOF)
|
||||
error (1, errno, _("write error"));
|
||||
exit (exit_status);
|
||||
}
|
||||
|
||||
/* Replace backslash representations of special characters in
|
||||
STRPTR with their actual values.
|
||||
The set of possible backslash characters has been expanded beyond
|
||||
@@ -169,8 +100,7 @@ main (argc, argv)
|
||||
Return a pointer to the character after the new end of STRPTR. */
|
||||
|
||||
static char *
|
||||
collapse_escapes (strptr)
|
||||
char *strptr;
|
||||
collapse_escapes (char *strptr)
|
||||
{
|
||||
register char *strout;
|
||||
|
||||
@@ -227,9 +157,7 @@ collapse_escapes (strptr)
|
||||
opened or read. */
|
||||
|
||||
static int
|
||||
paste_parallel (nfiles, fnamptr)
|
||||
int nfiles;
|
||||
char **fnamptr;
|
||||
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'.
|
||||
@@ -399,9 +327,7 @@ paste_parallel (nfiles, fnamptr)
|
||||
opened or read. */
|
||||
|
||||
static int
|
||||
paste_serial (nfiles, fnamptr)
|
||||
int nfiles;
|
||||
char **fnamptr;
|
||||
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. */
|
||||
@@ -478,8 +404,7 @@ paste_serial (nfiles, fnamptr)
|
||||
}
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
int status;
|
||||
usage (int status)
|
||||
{
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
@@ -504,3 +429,65 @@ With no FILE, or when FILE is -, read standard input.\n\
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
void
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int optc, exit_status;
|
||||
char default_delims[2], zero_delims[3];
|
||||
|
||||
program_name = argv[0];
|
||||
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, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
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;
|
||||
|
||||
default:
|
||||
usage (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (show_version)
|
||||
{
|
||||
printf ("paste - %s\n", version_string);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (show_help)
|
||||
usage (0);
|
||||
|
||||
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 (1, errno, "-");
|
||||
if (ferror (stdout) || fclose (stdout) == EOF)
|
||||
error (1, errno, _("write error"));
|
||||
exit (exit_status);
|
||||
}
|
||||
|
||||
94
src/rm.c
94
src/rm.c
@@ -15,7 +15,7 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Written by Paul Rubin, David MacKenzie, and Richard Stallman. */
|
||||
/* Written by Paul Rubin, David MacKenzie, and Richard Stallman. */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
@@ -27,17 +27,17 @@
|
||||
#include "error.h"
|
||||
|
||||
#ifdef D_INO_IN_DIRENT
|
||||
#define D_INO(dp) ((dp)->d_ino)
|
||||
# define D_INO(dp) ((dp)->d_ino)
|
||||
#else
|
||||
/* POSIX.1 doesn't have inodes, so fake them to avoid lots of ifdefs. */
|
||||
#define D_INO(dp) 1
|
||||
/* Some systems don't have inodes, so fake them to avoid lots of ifdefs. */
|
||||
# define D_INO(dp) 1
|
||||
#endif
|
||||
|
||||
char *basename ();
|
||||
char *stpcpy ();
|
||||
char *xmalloc ();
|
||||
char *xrealloc ();
|
||||
int eaccess_stat ();
|
||||
int euidaccess ();
|
||||
int yesno ();
|
||||
void strip_trailing_slashes ();
|
||||
|
||||
@@ -51,31 +51,31 @@ static void usage ();
|
||||
/* Name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
/* Path of file now being processed; extended as necessary. */
|
||||
/* Path of file now being processed; extended as necessary. */
|
||||
static char *pathname;
|
||||
|
||||
/* Number of bytes currently allocated for `pathname';
|
||||
made larger when necessary, but never smaller. */
|
||||
static int pnsize;
|
||||
|
||||
/* If nonzero, display the name of each file removed. */
|
||||
/* If nonzero, display the name of each file removed. */
|
||||
static int verbose;
|
||||
|
||||
/* If nonzero, ignore nonexistant files. */
|
||||
/* If nonzero, ignore nonexistant files. */
|
||||
static int ignore_missing_files;
|
||||
|
||||
/* If nonzero, recursively remove directories. */
|
||||
/* If nonzero, recursively remove directories. */
|
||||
static int recursive;
|
||||
|
||||
/* If nonzero, query the user about whether to remove each file. */
|
||||
/* If nonzero, query the user about whether to remove each file. */
|
||||
static int interactive;
|
||||
|
||||
/* 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. */
|
||||
Only works for the super-user. */
|
||||
static int unlink_dirs;
|
||||
|
||||
/* If nonzero, stdin is a tty. */
|
||||
/* If nonzero, stdin is a tty. */
|
||||
static int stdin_tty;
|
||||
|
||||
/* If non-zero, display usage information and exit. */
|
||||
@@ -114,7 +114,7 @@ main (argc, argv)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 0: /* Long option. */
|
||||
case 0: /* Long option. */
|
||||
break;
|
||||
case 'd':
|
||||
unlink_dirs = 1;
|
||||
@@ -183,7 +183,7 @@ main (argc, argv)
|
||||
}
|
||||
|
||||
/* Remove file or directory `pathname' after checking appropriate things.
|
||||
Return 0 if `pathname' is removed, 1 if not. */
|
||||
Return 0 if `pathname' is removed, 1 if not. */
|
||||
|
||||
static int
|
||||
rm ()
|
||||
@@ -214,14 +214,14 @@ rm ()
|
||||
|
||||
/* Query the user if appropriate, and if ok try to remove the
|
||||
non-directory `pathname', which STATP contains info about.
|
||||
Return 0 if `pathname' is removed, 1 if not. */
|
||||
Return 0 if `pathname' is removed, 1 if not. */
|
||||
|
||||
static int
|
||||
remove_file (statp)
|
||||
struct stat *statp;
|
||||
{
|
||||
if (!ignore_missing_files && (interactive || stdin_tty)
|
||||
&& eaccess_stat (statp, W_OK, pathname)
|
||||
&& euidaccess (pathname, W_OK)
|
||||
#ifdef S_ISLNK
|
||||
&& !S_ISLNK (statp->st_mode)
|
||||
#endif
|
||||
@@ -258,7 +258,7 @@ remove_file (statp)
|
||||
/* If not in recursive mode, print an error message and return 1.
|
||||
Otherwise, query the user if appropriate, then try to recursively
|
||||
remove directory `pathname', which STATP contains info about.
|
||||
Return 0 if `pathname' is removed, 1 if not. */
|
||||
Return 0 if `pathname' is removed, 1 if not. */
|
||||
|
||||
static int
|
||||
remove_dir (statp)
|
||||
@@ -273,7 +273,7 @@ remove_dir (statp)
|
||||
}
|
||||
|
||||
if (!ignore_missing_files && (interactive || stdin_tty)
|
||||
&& eaccess_stat (statp, W_OK, pathname))
|
||||
&& euidaccess (pathname, W_OK))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"%s: descend directory `%s', overriding mode %04o? ",
|
||||
@@ -317,7 +317,7 @@ remove_dir (statp)
|
||||
|
||||
/* An element in a stack of pointers into `pathname'.
|
||||
`pathp' points to where in `pathname' the terminating '\0' goes
|
||||
for this level's directory name. */
|
||||
for this level's directory name. */
|
||||
struct pathstack
|
||||
{
|
||||
struct pathstack *next;
|
||||
@@ -327,7 +327,7 @@ struct pathstack
|
||||
|
||||
/* Linked list of pathnames of directories in progress in recursive rm.
|
||||
The entries actually contain pointers into `pathname'.
|
||||
`pathstack' is the current deepest level. */
|
||||
`pathstack' is the current deepest level. */
|
||||
static struct pathstack *pathstack = NULL;
|
||||
|
||||
/* Read directory `pathname' and remove all of its entries,
|
||||
@@ -336,7 +336,7 @@ static struct pathstack *pathstack = NULL;
|
||||
Return 0 for success, error count for failure.
|
||||
Upon return, `pathname' will have the same contents as before,
|
||||
but its address might be different; in that case, `pnsize' will
|
||||
be larger, as well. */
|
||||
be larger, as well. */
|
||||
|
||||
static int
|
||||
clear_directory (statp)
|
||||
@@ -344,18 +344,18 @@ clear_directory (statp)
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
char *name_space; /* Copy of directory's filenames. */
|
||||
char *namep; /* Current entry in `name_space'. */
|
||||
unsigned name_size; /* Bytes allocated for `name_space'. */
|
||||
int name_length; /* Length of filename in `namep' plus '\0'. */
|
||||
int pathname_length; /* Length of `pathname'. */
|
||||
ino_t *inode_space; /* Copy of directory's inodes. */
|
||||
ino_t *inodep; /* Current entry in `inode_space'. */
|
||||
char *name_space; /* Copy of directory's filenames. */
|
||||
char *namep; /* Current entry in `name_space'. */
|
||||
unsigned name_size; /* Bytes allocated for `name_space'. */
|
||||
int name_length; /* Length of filename in `namep' plus '\0'. */
|
||||
int pathname_length; /* Length of `pathname'. */
|
||||
ino_t *inode_space; /* Copy of directory's inodes. */
|
||||
ino_t *inodep; /* Current entry in `inode_space'. */
|
||||
unsigned n_inodes_allocated; /* There is space for this many inodes
|
||||
in `inode_space'. */
|
||||
int err = 0; /* Return status. */
|
||||
struct pathstack pathframe; /* New top of stack. */
|
||||
struct pathstack *pp; /* Temporary. */
|
||||
in `inode_space'. */
|
||||
int err = 0; /* Return status. */
|
||||
struct pathstack pathframe; /* New top of stack. */
|
||||
struct pathstack *pp; /* Temporary. */
|
||||
|
||||
name_size = statp->st_size;
|
||||
name_space = (char *) xmalloc (name_size);
|
||||
@@ -384,7 +384,7 @@ clear_directory (statp)
|
||||
|
||||
while ((dp = readdir (dirp)) != NULL)
|
||||
{
|
||||
/* Skip "." and ".." (some NFS filesystems' directories lack them). */
|
||||
/* Skip "." and "..". */
|
||||
if (dp->d_name[0] != '.'
|
||||
|| (dp->d_name[1] != '\0'
|
||||
&& (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
|
||||
@@ -431,43 +431,43 @@ clear_directory (statp)
|
||||
{
|
||||
name_length = strlen (namep) + 1;
|
||||
|
||||
/* Satisfy GNU requirement that filenames can be arbitrarily long. */
|
||||
/* Handle arbitrarily long filenames. */
|
||||
if (pathname_length + 1 + name_length > pnsize)
|
||||
{
|
||||
char *new_pathname;
|
||||
|
||||
pnsize = (pathname_length + 1 + name_length) * 2;
|
||||
new_pathname = xrealloc (pathname, pnsize);
|
||||
/* Update the all the pointers in the stack to use the new area. */
|
||||
/* Update all pointers in the stack to use the new area. */
|
||||
for (pp = pathstack; pp != NULL; pp = pp->next)
|
||||
pp->pathp += new_pathname - pathname;
|
||||
pathname = new_pathname;
|
||||
}
|
||||
|
||||
/* Add a new frame to the top of the path stack. */
|
||||
/* Add a new frame to the top of the path stack. */
|
||||
pathframe.pathp = pathname + pathname_length;
|
||||
pathframe.inum = *inodep;
|
||||
pathframe.next = pathstack;
|
||||
pathstack = &pathframe;
|
||||
|
||||
/* Append '/' and the filename to current pathname, take care of the
|
||||
file (which could result in recursive calls), and take the filename
|
||||
back off. */
|
||||
/* Append '/' and the filename to current pathname, take care of
|
||||
the file (which could result in recursive calls), and take
|
||||
the filename back off. */
|
||||
|
||||
*pathstack->pathp = '/';
|
||||
strcpy (pathstack->pathp + 1, namep);
|
||||
|
||||
/* If the i-number has already appeared, there's an error. */
|
||||
/* If the i-number has already appeared, there's an error. */
|
||||
if (duplicate_entry (pathstack->next, pathstack->inum))
|
||||
err++;
|
||||
else if (rm ())
|
||||
err++;
|
||||
|
||||
*pathstack->pathp = '\0';
|
||||
pathstack = pathstack->next; /* Pop the stack. */
|
||||
pathstack = pathstack->next; /* Pop the stack. */
|
||||
}
|
||||
}
|
||||
/* Keep trying while there are still files to remove. */
|
||||
/* Keep trying while there are still files to remove. */
|
||||
while (namep > name_space && err == 0);
|
||||
|
||||
free (name_space);
|
||||
@@ -480,14 +480,14 @@ clear_directory (statp)
|
||||
if yes, return 1, and if no, exit.
|
||||
This assumes that no one tries to remove filesystem mount points;
|
||||
doing so could cause duplication of i-numbers that would not indicate
|
||||
a corrupted file system. */
|
||||
a corrupted file system. */
|
||||
|
||||
static int
|
||||
duplicate_entry (stack, inum)
|
||||
struct pathstack *stack;
|
||||
ino_t inum;
|
||||
{
|
||||
#ifndef _POSIX_SOURCE
|
||||
#ifdef D_INO_IN_DIRENT
|
||||
struct pathstack *p;
|
||||
|
||||
for (p = stack; p != NULL; p = p->next)
|
||||
@@ -501,9 +501,9 @@ NOTIFY YOUR SYSTEM MANAGER.\n\
|
||||
Cycle detected:\n\
|
||||
%s\n\
|
||||
is the same file as\n", program_name, pathname);
|
||||
*p->pathp = '\0'; /* Truncate pathname. */
|
||||
*p->pathp = '\0'; /* Truncate pathname. */
|
||||
fprintf (stderr, "%s\n", pathname);
|
||||
*p->pathp = '/'; /* Put it back. */
|
||||
*p->pathp = '/'; /* Put it back. */
|
||||
if (interactive)
|
||||
{
|
||||
fprintf (stderr, "%s: continue? ", program_name);
|
||||
@@ -515,7 +515,7 @@ is the same file as\n", program_name, pathname);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* D_INO_IN_DIRENT */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
491
src/sort.c
491
src/sort.c
@@ -32,7 +32,7 @@
|
||||
#include "long-options.h"
|
||||
#include "error.h"
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#else
|
||||
#ifndef UCHAR_MAX
|
||||
@@ -45,8 +45,6 @@ char *realloc ();
|
||||
void free ();
|
||||
#endif
|
||||
|
||||
static void usage ();
|
||||
|
||||
/* Undefine, to avoid warning about redefinition on some systems. */
|
||||
#undef min
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
@@ -61,6 +59,55 @@ static void usage ();
|
||||
/* The kind of blanks for '-b' to skip in various options. */
|
||||
enum blanktype { bl_start, bl_end, bl_both };
|
||||
|
||||
/* Lines are held in core as counted strings. */
|
||||
struct line
|
||||
{
|
||||
char *text; /* Text of the line. */
|
||||
int length; /* Length not including final newline. */
|
||||
char *keybeg; /* Start of first key. */
|
||||
char *keylim; /* Limit of first key. */
|
||||
};
|
||||
|
||||
/* Arrays of lines. */
|
||||
struct lines
|
||||
{
|
||||
struct line *lines; /* Dynamically allocated array of lines. */
|
||||
int used; /* Number of slots used. */
|
||||
int alloc; /* Number of slots allocated. */
|
||||
int limit; /* Max number of slots to allocate. */
|
||||
};
|
||||
|
||||
/* Input buffers. */
|
||||
struct buffer
|
||||
{
|
||||
char *buf; /* Dynamically allocated buffer. */
|
||||
int used; /* Number of bytes used. */
|
||||
int alloc; /* Number of bytes allocated. */
|
||||
int left; /* Number of bytes left after line parsing. */
|
||||
};
|
||||
|
||||
struct keyfield
|
||||
{
|
||||
int sword; /* Zero-origin 'word' to start at. */
|
||||
int schar; /* Additional characters to skip. */
|
||||
int skipsblanks; /* Skip leading white space at start. */
|
||||
int eword; /* Zero-origin first word after field. */
|
||||
int 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. */
|
||||
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;
|
||||
|
||||
@@ -81,11 +128,7 @@ static char fold_toupper[UCHAR_LIM];
|
||||
|
||||
/* Table mapping 3-letter month names to integers.
|
||||
Alphabetic order allows binary search. */
|
||||
static struct month
|
||||
{
|
||||
char *name;
|
||||
int val;
|
||||
} const monthtab[] =
|
||||
static struct month const monthtab[] =
|
||||
{
|
||||
{"APR", 4},
|
||||
{"AUG", 8},
|
||||
@@ -141,49 +184,54 @@ static int unique;
|
||||
/* Nonzero if any of the input files are the standard input. */
|
||||
static int have_read_stdin;
|
||||
|
||||
/* Lines are held in core as counted strings. */
|
||||
struct line
|
||||
{
|
||||
char *text; /* Text of the line. */
|
||||
int length; /* Length not including final newline. */
|
||||
char *keybeg; /* Start of first key. */
|
||||
char *keylim; /* Limit of first key. */
|
||||
};
|
||||
|
||||
/* Arrays of lines. */
|
||||
struct lines
|
||||
{
|
||||
struct line *lines; /* Dynamically allocated array of lines. */
|
||||
int used; /* Number of slots used. */
|
||||
int alloc; /* Number of slots allocated. */
|
||||
int limit; /* Max number of slots to allocate. */
|
||||
};
|
||||
|
||||
/* Input buffers. */
|
||||
struct buffer
|
||||
{
|
||||
char *buf; /* Dynamically allocated buffer. */
|
||||
int used; /* Number of bytes used. */
|
||||
int alloc; /* Number of bytes allocated. */
|
||||
int left; /* Number of bytes left after line parsing. */
|
||||
};
|
||||
|
||||
/* Lists of key field comparisons to be tried. */
|
||||
static struct keyfield
|
||||
static struct keyfield keyhead;
|
||||
|
||||
static void
|
||||
usage (int status)
|
||||
{
|
||||
int sword; /* Zero-origin 'word' to start at. */
|
||||
int schar; /* Additional characters to skip. */
|
||||
int skipsblanks; /* Skip leading white space at start. */
|
||||
int eword; /* Zero-origin first word after field. */
|
||||
int 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. */
|
||||
int month; /* Flag for comparison by month name. */
|
||||
int reverse; /* Reverse the sense of comparison. */
|
||||
struct keyfield *next; /* Next keyfield to try. */
|
||||
} keyhead;
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
program_name);
|
||||
else
|
||||
{
|
||||
printf (_("\
|
||||
Usage: %s [OPTION]... [FILE]...\n\
|
||||
"),
|
||||
program_name);
|
||||
printf (_("\
|
||||
Write sorted concatenation of all FILE(s) to standard output.\n\
|
||||
\n\
|
||||
+POS1 [-POS2] start a key at POS1, end it before POS2\n\
|
||||
-M compare (unknown) < `JAN' < ... < `DEC', imply -b\n\
|
||||
-T DIRECT use DIRECT for temporary files, not $TMPDIR or %s\n\
|
||||
-b ignore leading blanks in sort fields or keys\n\
|
||||
-c check if given files already sorted, do not sort\n\
|
||||
-d consider only [a-zA-Z0-9 ] characters in keys\n\
|
||||
-f fold lower case to upper case characters in keys\n\
|
||||
-i consider only [\\040-\\0176] characters in keys\n\
|
||||
-k POS1[,POS2] same as +POS1 [-POS2], but all positions counted from 1\n\
|
||||
-m merge already sorted files, do not sort\n\
|
||||
-n compare according to string numerical value, imply -b\n\
|
||||
-o FILE write result on FILE instead of standard output\n\
|
||||
-r reverse the result of comparisons\n\
|
||||
-s stabilize sort by disabling last resort comparison\n\
|
||||
-t SEP use SEParator instead of non- to whitespace transition\n\
|
||||
-u with -c, check for strict ordering\n\
|
||||
-u with -m, only output the first of an equal sequence\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
\n\
|
||||
POS is F[.C][OPTS], where F is the field number and C the character\n\
|
||||
position in the field, both counted from zero. OPTS is made up of one\n\
|
||||
or more of Mbdfinr, this effectively disable global -Mbdfinr settings\n\
|
||||
for that key. If no key given, use the entire line as key. With no\n\
|
||||
FILE, or when FILE is -, read standard input.\n\
|
||||
")
|
||||
, DEFAULT_TMPDIR);
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
/* The list of temporary files. */
|
||||
static struct tempnode
|
||||
@@ -195,7 +243,7 @@ static struct tempnode
|
||||
/* Clean up any remaining temporary files. */
|
||||
|
||||
static void
|
||||
cleanup ()
|
||||
cleanup (void)
|
||||
{
|
||||
struct tempnode *node;
|
||||
|
||||
@@ -206,8 +254,7 @@ cleanup ()
|
||||
/* Allocate N bytes of memory dynamically, with error checking. */
|
||||
|
||||
char *
|
||||
xmalloc (n)
|
||||
unsigned n;
|
||||
xmalloc (unsigned int n)
|
||||
{
|
||||
char *p;
|
||||
|
||||
@@ -227,9 +274,7 @@ xmalloc (n)
|
||||
If N is 0, run free and return NULL. */
|
||||
|
||||
char *
|
||||
xrealloc (p, n)
|
||||
char *p;
|
||||
unsigned n;
|
||||
xrealloc (char *p, unsigned int n)
|
||||
{
|
||||
if (p == 0)
|
||||
return xmalloc (n);
|
||||
@@ -249,25 +294,48 @@ xrealloc (p, n)
|
||||
}
|
||||
|
||||
static FILE *
|
||||
xfopen (file, how)
|
||||
char *file, *how;
|
||||
xtmpfopen (const char *file)
|
||||
{
|
||||
FILE *fp = strcmp (file, "-") ? fopen (file, how) : stdin;
|
||||
FILE *fp;
|
||||
int fd;
|
||||
|
||||
if (fp == 0)
|
||||
fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
if (fd < 0 || (fp = fdopen (fd, "w")) == NULL)
|
||||
{
|
||||
error (0, errno, "%s", file);
|
||||
cleanup ();
|
||||
exit (2);
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
static FILE *
|
||||
xfopen (const char *file, const char *how)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if (strcmp (file, "-") == 0)
|
||||
{
|
||||
fp = stdin;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((fp = fopen (file, how)) == NULL)
|
||||
{
|
||||
error (0, errno, "%s", file);
|
||||
cleanup ();
|
||||
exit (2);
|
||||
}
|
||||
}
|
||||
|
||||
if (fp == stdin)
|
||||
have_read_stdin = 1;
|
||||
return fp;
|
||||
}
|
||||
|
||||
static void
|
||||
xfclose (fp)
|
||||
FILE *fp;
|
||||
xfclose (FILE *fp)
|
||||
{
|
||||
if (fp == stdin)
|
||||
{
|
||||
@@ -296,10 +364,7 @@ xfclose (fp)
|
||||
}
|
||||
|
||||
static void
|
||||
xfwrite (buf, size, nelem, fp)
|
||||
char *buf;
|
||||
int size, nelem;
|
||||
FILE *fp;
|
||||
xfwrite (const char *buf, int size, int nelem, FILE *fp)
|
||||
{
|
||||
if (fwrite (buf, size, nelem, fp) != nelem)
|
||||
{
|
||||
@@ -312,19 +377,25 @@ xfwrite (buf, size, nelem, fp)
|
||||
/* Return a name for a temporary file. */
|
||||
|
||||
static char *
|
||||
tempname ()
|
||||
tempname (void)
|
||||
{
|
||||
static int seq;
|
||||
static unsigned int seq;
|
||||
int len = strlen (temp_file_prefix);
|
||||
char *name = xmalloc (len + 16);
|
||||
struct tempnode *node =
|
||||
(struct tempnode *) xmalloc (sizeof (struct tempnode));
|
||||
char *name = xmalloc (len + 1 + sizeof ("sort") - 1 + 5 + 5 + 1);
|
||||
struct tempnode *node;
|
||||
|
||||
node = (struct tempnode *) xmalloc (sizeof (struct tempnode));
|
||||
sprintf (name,
|
||||
"%s%ssort%5.5d%5.5d",
|
||||
temp_file_prefix,
|
||||
(len && temp_file_prefix[len - 1] != '/') ? "/" : "",
|
||||
(unsigned int) getpid () & 0xffff, ++seq);
|
||||
(unsigned int) getpid () & 0xffff, seq);
|
||||
|
||||
/* Make sure that SEQ's value fits in 5 digits. */
|
||||
++seq;
|
||||
if (seq >= 100000)
|
||||
seq = 0;
|
||||
|
||||
node->name = name;
|
||||
node->next = temphead.next;
|
||||
temphead.next = node;
|
||||
@@ -335,8 +406,7 @@ tempname ()
|
||||
remove it if it is found on the list. */
|
||||
|
||||
static void
|
||||
zaptemp (name)
|
||||
char *name;
|
||||
zaptemp (char *name)
|
||||
{
|
||||
struct tempnode *node, *temp;
|
||||
|
||||
@@ -356,7 +426,7 @@ zaptemp (name)
|
||||
/* Initialize the character class tables. */
|
||||
|
||||
static void
|
||||
inittables ()
|
||||
inittables (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -380,9 +450,7 @@ inittables ()
|
||||
/* Initialize BUF, allocating ALLOC bytes initially. */
|
||||
|
||||
static void
|
||||
initbuf (buf, alloc)
|
||||
struct buffer *buf;
|
||||
int alloc;
|
||||
initbuf (struct buffer *buf, int alloc)
|
||||
{
|
||||
buf->alloc = alloc;
|
||||
buf->buf = xmalloc (buf->alloc);
|
||||
@@ -395,9 +463,7 @@ initbuf (buf, alloc)
|
||||
of bytes buffered. */
|
||||
|
||||
static int
|
||||
fillbuf (buf, fp)
|
||||
struct buffer *buf;
|
||||
FILE *fp;
|
||||
fillbuf (struct buffer *buf, FILE *fp)
|
||||
{
|
||||
int cc;
|
||||
|
||||
@@ -439,10 +505,7 @@ fillbuf (buf, fp)
|
||||
for, ever. */
|
||||
|
||||
static void
|
||||
initlines (lines, alloc, limit)
|
||||
struct lines *lines;
|
||||
int alloc;
|
||||
int limit;
|
||||
initlines (struct lines *lines, int alloc, int limit)
|
||||
{
|
||||
lines->alloc = alloc;
|
||||
lines->lines = (struct line *) xmalloc (lines->alloc * sizeof (struct line));
|
||||
@@ -454,9 +517,7 @@ initlines (lines, alloc, limit)
|
||||
by KEY in LINE. */
|
||||
|
||||
static char *
|
||||
begfield (line, key)
|
||||
struct line *line;
|
||||
struct keyfield *key;
|
||||
begfield (const struct line *line, const struct keyfield *key)
|
||||
{
|
||||
register char *ptr = line->text, *lim = ptr + line->length;
|
||||
register int sword = key->sword, schar = key->schar;
|
||||
@@ -492,9 +553,7 @@ begfield (line, key)
|
||||
in LINE specified by KEY. */
|
||||
|
||||
static char *
|
||||
limfield (line, key)
|
||||
struct line *line;
|
||||
struct keyfield *key;
|
||||
limfield (const struct line *line, const struct keyfield *key)
|
||||
{
|
||||
register char *ptr = line->text, *lim = ptr + line->length;
|
||||
register int eword = key->eword, echar = key->echar;
|
||||
@@ -527,12 +586,10 @@ limfield (line, key)
|
||||
}
|
||||
|
||||
/* Find the lines in BUF, storing pointers and lengths in LINES.
|
||||
Also replace newlines with NULs. */
|
||||
Also replace newlines in BUF with NULs. */
|
||||
|
||||
static void
|
||||
findlines (buf, lines)
|
||||
struct buffer *buf;
|
||||
struct lines *lines;
|
||||
findlines (struct buffer *buf, struct lines *lines)
|
||||
{
|
||||
register char *beg = buf->buf, *lim = buf->buf + buf->used, *ptr;
|
||||
struct keyfield *key = keyhead.next;
|
||||
@@ -596,8 +653,7 @@ findlines (buf, lines)
|
||||
of the fraction. Strings not of this form are considered to be zero. */
|
||||
|
||||
static int
|
||||
fraccompare (a, b)
|
||||
register char *a, *b;
|
||||
fraccompare (register const char *a, register const char *b)
|
||||
{
|
||||
register tmpa = UCHAR (*a), tmpb = UCHAR (*b);
|
||||
|
||||
@@ -652,12 +708,12 @@ fraccompare (a, b)
|
||||
hideously fast. */
|
||||
|
||||
static int
|
||||
numcompare (a, b)
|
||||
register char *a, *b;
|
||||
numcompare (register const char *a, register const char *b)
|
||||
{
|
||||
register int tmpa, tmpb, loga, logb, tmp;
|
||||
|
||||
tmpa = UCHAR (*a), tmpb = UCHAR (*b);
|
||||
tmpa = UCHAR (*a);
|
||||
tmpb = UCHAR (*b);
|
||||
|
||||
while (blanks[tmpa])
|
||||
tmpa = UCHAR (*++a);
|
||||
@@ -751,9 +807,7 @@ numcompare (a, b)
|
||||
0 if the name in S is not recognized. */
|
||||
|
||||
static int
|
||||
getmonth (s, len)
|
||||
char *s;
|
||||
int len;
|
||||
getmonth (const char *s, int len)
|
||||
{
|
||||
char month[4];
|
||||
register int i, lo = 0, hi = 12;
|
||||
@@ -782,8 +836,7 @@ getmonth (s, len)
|
||||
are no more keys or a difference is found. */
|
||||
|
||||
static int
|
||||
keycompare (a, b)
|
||||
struct line *a, *b;
|
||||
keycompare (const struct line *a, const struct line *b)
|
||||
{
|
||||
register char *texta, *textb, *lima, *limb, *translate;
|
||||
register int *ignore;
|
||||
@@ -913,8 +966,7 @@ keycompare (a, b)
|
||||
depending on whether A compares less than, equal to, or greater than B. */
|
||||
|
||||
static int
|
||||
compare (a, b)
|
||||
register struct line *a, *b;
|
||||
compare (register const struct line *a, register const struct line *b)
|
||||
{
|
||||
int diff, tmpa, tmpb, mini;
|
||||
|
||||
@@ -953,19 +1005,17 @@ compare (a, b)
|
||||
}
|
||||
|
||||
/* Check that the lines read from the given FP come in order. Return
|
||||
1 if they do and 0 if there is a disorder. */
|
||||
1 if they do and 0 if there is a disorder.
|
||||
FIXME: return number of first out-of-order line if not sorted. */
|
||||
|
||||
static int
|
||||
checkfp (fp)
|
||||
FILE *fp;
|
||||
checkfp (FILE *fp)
|
||||
{
|
||||
struct buffer buf; /* Input buffer. */
|
||||
struct lines lines; /* Lines scanned from the buffer. */
|
||||
struct line *prev_line; /* Pointer to previous line. */
|
||||
struct line temp; /* Copy of previous line. */
|
||||
int cc; /* Character count. */
|
||||
int cmp; /* Result of calling compare. */
|
||||
int alloc, i, success = 1;
|
||||
int alloc, sorted = 1;
|
||||
|
||||
initbuf (&buf, mergealloc);
|
||||
initlines (&lines, mergealloc / linelength + 1,
|
||||
@@ -974,66 +1024,69 @@ checkfp (fp)
|
||||
temp.text = xmalloc (alloc);
|
||||
|
||||
cc = fillbuf (&buf, fp);
|
||||
if (cc == 0)
|
||||
goto finish;
|
||||
|
||||
findlines (&buf, &lines);
|
||||
|
||||
if (cc)
|
||||
do
|
||||
{
|
||||
/* Compare each line in the buffer with its successor. */
|
||||
for (i = 0; i < lines.used - 1; ++i)
|
||||
{
|
||||
cmp = compare (&lines.lines[i], &lines.lines[i + 1]);
|
||||
if ((unique && cmp >= 0) || (cmp > 0))
|
||||
{
|
||||
success = 0;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
struct line *prev_line; /* Pointer to previous line. */
|
||||
int cmp; /* Result of calling compare. */
|
||||
int i;
|
||||
|
||||
/* Save the last line of the buffer and refill the buffer. */
|
||||
prev_line = lines.lines + lines.used - 1;
|
||||
if (prev_line->length > alloc)
|
||||
{
|
||||
while (prev_line->length + 1 > alloc)
|
||||
alloc *= 2;
|
||||
temp.text = xrealloc (temp.text, alloc);
|
||||
}
|
||||
memcpy (temp.text, prev_line->text, prev_line->length + 1);
|
||||
temp.length = prev_line->length;
|
||||
temp.keybeg = temp.text + (prev_line->keybeg - prev_line->text);
|
||||
temp.keylim = temp.text + (prev_line->keylim - prev_line->text);
|
||||
/* Compare each line in the buffer with its successor. */
|
||||
for (i = 0; i < lines.used - 1; ++i)
|
||||
{
|
||||
cmp = compare (&lines.lines[i], &lines.lines[i + 1]);
|
||||
if ((unique && cmp >= 0) || (cmp > 0))
|
||||
{
|
||||
sorted = 0;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
cc = fillbuf (&buf, fp);
|
||||
if (cc)
|
||||
{
|
||||
findlines (&buf, &lines);
|
||||
/* Make sure the line saved from the old buffer contents is
|
||||
less than or equal to the first line of the new buffer. */
|
||||
cmp = compare (&temp, &lines.lines[0]);
|
||||
if ((unique && cmp >= 0) || (cmp > 0))
|
||||
{
|
||||
success = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (cc);
|
||||
/* Save the last line of the buffer and refill the buffer. */
|
||||
prev_line = lines.lines + (lines.used - 1);
|
||||
if (prev_line->length > alloc)
|
||||
{
|
||||
while (prev_line->length + 1 > alloc)
|
||||
alloc *= 2;
|
||||
temp.text = xrealloc (temp.text, alloc);
|
||||
}
|
||||
memcpy (temp.text, prev_line->text, prev_line->length + 1);
|
||||
temp.length = prev_line->length;
|
||||
temp.keybeg = temp.text + (prev_line->keybeg - prev_line->text);
|
||||
temp.keylim = temp.text + (prev_line->keylim - prev_line->text);
|
||||
|
||||
cc = fillbuf (&buf, fp);
|
||||
if (cc == 0)
|
||||
break;
|
||||
|
||||
findlines (&buf, &lines);
|
||||
/* Make sure the line saved from the old buffer contents is
|
||||
less than or equal to the first line of the new buffer. */
|
||||
cmp = compare (&temp, &lines.lines[0]);
|
||||
if ((unique && cmp >= 0) || (cmp > 0))
|
||||
{
|
||||
sorted = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
xfclose (fp);
|
||||
free (buf.buf);
|
||||
free ((char *) lines.lines);
|
||||
free (temp.text);
|
||||
return success;
|
||||
return sorted;
|
||||
}
|
||||
|
||||
/* Merge lines from FPS onto OFP. NFPS cannot be greater than NMERGE.
|
||||
Close FPS before returning. */
|
||||
|
||||
static void
|
||||
mergefps (fps, nfps, ofp)
|
||||
FILE *fps[], *ofp;
|
||||
register int nfps;
|
||||
mergefps (FILE **fps, register int nfps, FILE *ofp)
|
||||
{
|
||||
struct buffer buffer[NMERGE]; /* Input buffers for each file. */
|
||||
struct lines lines[NMERGE]; /* Line tables for each buffer. */
|
||||
@@ -1195,9 +1248,7 @@ mergefps (fps, nfps, ofp)
|
||||
/* Sort the array LINES with NLINES members, using TEMP for temporary space. */
|
||||
|
||||
static void
|
||||
sortlines (lines, nlines, temp)
|
||||
struct line *lines, *temp;
|
||||
int nlines;
|
||||
sortlines (struct line *lines, int nlines, struct line *temp)
|
||||
{
|
||||
register struct line *lo, *hi, *t;
|
||||
register int nlo, nhi;
|
||||
@@ -1238,9 +1289,7 @@ sortlines (lines, nlines, temp)
|
||||
Return a count of disordered files. */
|
||||
|
||||
static int
|
||||
check (files, nfiles)
|
||||
char *files[];
|
||||
int nfiles;
|
||||
check (char **files, int nfiles)
|
||||
{
|
||||
int i, disorders = 0;
|
||||
FILE *fp;
|
||||
@@ -1260,10 +1309,7 @@ check (files, nfiles)
|
||||
/* Merge NFILES FILES onto OFP. */
|
||||
|
||||
static void
|
||||
merge (files, nfiles, ofp)
|
||||
char *files[];
|
||||
int nfiles;
|
||||
FILE *ofp;
|
||||
merge (char **files, int nfiles, FILE *ofp)
|
||||
{
|
||||
int i, j, t;
|
||||
char *temp;
|
||||
@@ -1276,7 +1322,7 @@ merge (files, nfiles, ofp)
|
||||
{
|
||||
for (j = 0; j < NMERGE; ++j)
|
||||
fps[j] = xfopen (files[i * NMERGE + j], "r");
|
||||
tfp = xfopen (temp = tempname (), "w");
|
||||
tfp = xtmpfopen (temp = tempname ());
|
||||
mergefps (fps, NMERGE, tfp);
|
||||
xfclose (tfp);
|
||||
for (j = 0; j < NMERGE; ++j)
|
||||
@@ -1285,7 +1331,7 @@ merge (files, nfiles, ofp)
|
||||
}
|
||||
for (j = 0; j < nfiles % NMERGE; ++j)
|
||||
fps[j] = xfopen (files[i * NMERGE + j], "r");
|
||||
tfp = xfopen (temp = tempname (), "w");
|
||||
tfp = xtmpfopen (temp = tempname ());
|
||||
mergefps (fps, nfiles % NMERGE, tfp);
|
||||
xfclose (tfp);
|
||||
for (j = 0; j < nfiles % NMERGE; ++j)
|
||||
@@ -1304,10 +1350,7 @@ merge (files, nfiles, ofp)
|
||||
/* Sort NFILES FILES onto OFP. */
|
||||
|
||||
static void
|
||||
sort (files, nfiles, ofp)
|
||||
char **files;
|
||||
int nfiles;
|
||||
FILE *ofp;
|
||||
sort (char **files, int nfiles, FILE *ofp)
|
||||
{
|
||||
struct buffer buf;
|
||||
struct lines lines;
|
||||
@@ -1315,7 +1358,7 @@ sort (files, nfiles, ofp)
|
||||
int i, ntmp;
|
||||
FILE *fp, *tfp;
|
||||
struct tempnode *node;
|
||||
int ntemp = 0;
|
||||
int n_temp_files = 0;
|
||||
char **tempfiles;
|
||||
|
||||
initbuf (&buf, sortalloc);
|
||||
@@ -1338,12 +1381,12 @@ sort (files, nfiles, ofp)
|
||||
xrealloc ((char *) tmp, ntmp * sizeof (struct line));
|
||||
}
|
||||
sortlines (lines.lines, lines.used, tmp);
|
||||
if (feof (fp) && !nfiles && !ntemp && !buf.left)
|
||||
if (feof (fp) && !nfiles && !n_temp_files && !buf.left)
|
||||
tfp = ofp;
|
||||
else
|
||||
{
|
||||
++ntemp;
|
||||
tfp = xfopen (tempname (), "w");
|
||||
++n_temp_files;
|
||||
tfp = xtmpfopen (tempname ());
|
||||
}
|
||||
for (i = 0; i < lines.used; ++i)
|
||||
if (!unique || i == 0
|
||||
@@ -1362,13 +1405,13 @@ sort (files, nfiles, ofp)
|
||||
free ((char *) lines.lines);
|
||||
free ((char *) tmp);
|
||||
|
||||
if (ntemp)
|
||||
if (n_temp_files)
|
||||
{
|
||||
tempfiles = (char **) xmalloc (ntemp * sizeof (char *));
|
||||
i = ntemp;
|
||||
tempfiles = (char **) xmalloc (n_temp_files * sizeof (char *));
|
||||
i = n_temp_files;
|
||||
for (node = temphead.next; i > 0; node = node->next)
|
||||
tempfiles[--i] = node->name;
|
||||
merge (tempfiles, ntemp, ofp);
|
||||
merge (tempfiles, n_temp_files, ofp);
|
||||
free ((char *) tempfiles);
|
||||
}
|
||||
}
|
||||
@@ -1376,8 +1419,7 @@ sort (files, nfiles, ofp)
|
||||
/* Insert key KEY at the end of the list (`keyhead'). */
|
||||
|
||||
static void
|
||||
insertkey (key)
|
||||
struct keyfield *key;
|
||||
insertkey (struct keyfield *key)
|
||||
{
|
||||
struct keyfield *k = &keyhead;
|
||||
|
||||
@@ -1388,8 +1430,7 @@ insertkey (key)
|
||||
}
|
||||
|
||||
static void
|
||||
badfieldspec (s)
|
||||
char *s;
|
||||
badfieldspec (const char *s)
|
||||
{
|
||||
error (2, 0, _("invalid field specification `%s'"), s);
|
||||
}
|
||||
@@ -1397,19 +1438,18 @@ badfieldspec (s)
|
||||
/* Handle interrupts and hangups. */
|
||||
|
||||
static void
|
||||
sighandler (sig)
|
||||
int sig;
|
||||
sighandler (int sig)
|
||||
{
|
||||
#ifdef _POSIX_VERSION
|
||||
#ifdef SA_INTERRUPT
|
||||
struct sigaction sigact;
|
||||
|
||||
sigact.sa_handler = SIG_DFL;
|
||||
sigemptyset (&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
sigaction (sig, &sigact, NULL);
|
||||
#else /* !_POSIX_VERSION */
|
||||
#else /* !SA_INTERRUPT */
|
||||
signal (sig, SIG_DFL);
|
||||
#endif /* _POSIX_VERSION */
|
||||
#endif /* SA_INTERRUPT */
|
||||
cleanup ();
|
||||
kill (getpid (), sig);
|
||||
}
|
||||
@@ -1420,10 +1460,8 @@ sighandler (sig)
|
||||
BLANKTYPE is the kind of blanks that 'b' should skip. */
|
||||
|
||||
static char *
|
||||
set_ordering (s, key, blanktype)
|
||||
register char *s;
|
||||
struct keyfield *key;
|
||||
enum blanktype blanktype;
|
||||
set_ordering (register const char *s, struct keyfield *key,
|
||||
enum blanktype blanktype)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
@@ -1463,17 +1501,15 @@ set_ordering (s, key, blanktype)
|
||||
key->reverse = 1;
|
||||
break;
|
||||
default:
|
||||
return s;
|
||||
return (char *) s;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
return s;
|
||||
return (char *) s;
|
||||
}
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
struct keyfield *key = NULL, gkey;
|
||||
char *s;
|
||||
@@ -1481,9 +1517,9 @@ main (argc, argv)
|
||||
int checkonly = 0, mergeonly = 0, nfiles = 0;
|
||||
char *minus = "-", *outfile = minus, **files, *tmp;
|
||||
FILE *ofp;
|
||||
#ifdef _POSIX_VERSION
|
||||
#ifdef SA_INTERRUPT
|
||||
struct sigaction oldact, newact;
|
||||
#endif /* _POSIX_VERSION */
|
||||
#endif /* SA_INTERRUPT */
|
||||
|
||||
program_name = argv[0];
|
||||
|
||||
@@ -1496,7 +1532,7 @@ main (argc, argv)
|
||||
if (temp_file_prefix == NULL)
|
||||
temp_file_prefix = DEFAULT_TMPDIR;
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
#ifdef SA_INTERRUPT
|
||||
newact.sa_handler = sighandler;
|
||||
sigemptyset (&newact.sa_mask);
|
||||
newact.sa_flags = 0;
|
||||
@@ -1513,7 +1549,7 @@ main (argc, argv)
|
||||
sigaction (SIGTERM, NULL, &oldact);
|
||||
if (oldact.sa_handler != SIG_IGN)
|
||||
sigaction (SIGTERM, &newact, NULL);
|
||||
#else /* !_POSIX_VERSION */
|
||||
#else /* !SA_INTERRUPT */
|
||||
if (signal (SIGINT, SIG_IGN) != SIG_IGN)
|
||||
signal (SIGINT, sighandler);
|
||||
if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
|
||||
@@ -1522,7 +1558,7 @@ main (argc, argv)
|
||||
signal (SIGPIPE, sighandler);
|
||||
if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
|
||||
signal (SIGTERM, sighandler);
|
||||
#endif /* !_POSIX_VERSION */
|
||||
#endif /* !SA_INTERRUPT */
|
||||
|
||||
gkey.sword = gkey.eword = -1;
|
||||
gkey.ignore = NULL;
|
||||
@@ -1807,7 +1843,7 @@ main (argc, argv)
|
||||
|
||||
fp = xfopen (files[i], "r");
|
||||
tmp = tempname ();
|
||||
ofp = xfopen (tmp, "w");
|
||||
ofp = xtmpfopen (tmp);
|
||||
while ((cc = fread (buf, 1, sizeof buf, fp)) > 0)
|
||||
xfwrite (buf, 1, cc, ofp);
|
||||
if (ferror (fp))
|
||||
@@ -1847,50 +1883,3 @@ main (argc, argv)
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
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 (_("\
|
||||
Write sorted concatenation of all FILE(s) to standard output.\n\
|
||||
\n\
|
||||
+POS1 [-POS2] start a key at POS1, end it before POS2\n\
|
||||
-M compare (unknown) < `JAN' < ... < `DEC', imply -b\n\
|
||||
-T DIRECT use DIRECT for temporary files, not $TMPDIR or %s\n\
|
||||
-b ignore leading blanks in sort fields or keys\n\
|
||||
-c check if given files already sorted, do not sort\n\
|
||||
-d consider only [a-zA-Z0-9 ] characters in keys\n\
|
||||
-f fold lower case to upper case characters in keys\n\
|
||||
-i consider only [\\040-\\0176] characters in keys\n\
|
||||
-k POS1[,POS2] same as +POS1 [-POS2], but all positions counted from 1\n\
|
||||
-m merge already sorted files, do not sort\n\
|
||||
-n compare according to string numerical value, imply -b\n\
|
||||
-o FILE write result on FILE instead of standard output\n\
|
||||
-r reverse the result of comparisons\n\
|
||||
-s stabilize sort by disabling last resort comparison\n\
|
||||
-t SEP use SEParator instead of non- to whitespace transition\n\
|
||||
-u with -c, check for strict ordering\n\
|
||||
-u with -m, only output the first of an equal sequence\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
\n\
|
||||
POS is F[.C][OPTS], where F is the field number and C the character\n\
|
||||
position in the field, both counted from zero. OPTS is made up of one\n\
|
||||
or more of Mbdfinr, this effectively disable global -Mbdfinr settings\n\
|
||||
for that key. If no key given, use the entire line as key. With no\n\
|
||||
FILE, or when FILE is -, read standard input.\n\
|
||||
")
|
||||
, DEFAULT_TMPDIR);
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
562
src/split.c
562
src/split.c
@@ -26,23 +26,28 @@
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#ifndef UINT_MAX
|
||||
# define UINT_MAX ((unsigned int) ~(unsigned int) 0)
|
||||
#endif
|
||||
|
||||
#ifndef INT_MAX
|
||||
# define INT_MAX ((int) (UINT_MAX >> 1))
|
||||
#endif
|
||||
|
||||
#include "system.h"
|
||||
#include "version.h"
|
||||
#include "error.h"
|
||||
#include "xstrtol.h"
|
||||
|
||||
char *xmalloc ();
|
||||
int full_write ();
|
||||
int safe_read ();
|
||||
|
||||
static int convint ();
|
||||
static int isdigits ();
|
||||
static int stdread ();
|
||||
static void line_bytes_split ();
|
||||
static void bytes_split ();
|
||||
static void cwrite ();
|
||||
static void lines_split ();
|
||||
static void next_file_name ();
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
@@ -82,9 +87,7 @@ static struct option const longopts[] =
|
||||
};
|
||||
|
||||
static void
|
||||
usage (status, reason)
|
||||
int status;
|
||||
char *reason;
|
||||
usage (int status, const char *reason)
|
||||
{
|
||||
if (reason != NULL)
|
||||
fprintf (stderr, "%s: %s\n", program_name, reason);
|
||||
@@ -115,10 +118,234 @@ SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
|
||||
exit (status);
|
||||
}
|
||||
|
||||
/* Compute the next sequential output file name suffix and store it
|
||||
into the string `outfile' at the position pointed to by `outfile_mid'. */
|
||||
|
||||
static void
|
||||
next_file_name (void)
|
||||
{
|
||||
int x;
|
||||
char *ne;
|
||||
unsigned int i;
|
||||
|
||||
static int first_call = 1;
|
||||
|
||||
/* Status for outfile name generation. */
|
||||
static unsigned outfile_count = 0;
|
||||
static unsigned outfile_name_limit = 25 * 26;
|
||||
static unsigned outfile_name_generation = 1;
|
||||
|
||||
if (!first_call)
|
||||
outfile_count++;
|
||||
first_call = 0;
|
||||
if (outfile_count < outfile_name_limit)
|
||||
{
|
||||
for (ne = outfile_end - 1; ; ne--)
|
||||
{
|
||||
x = *ne;
|
||||
if (x != 'z')
|
||||
break;
|
||||
*ne = 'a';
|
||||
}
|
||||
*ne = x + 1;
|
||||
return;
|
||||
}
|
||||
|
||||
outfile_count = 0;
|
||||
outfile_name_limit *= 26;
|
||||
outfile_name_generation++;
|
||||
*outfile_mid++ = 'z';
|
||||
for (i = 0; i <= outfile_name_generation; i++)
|
||||
outfile_mid[i] = 'a';
|
||||
outfile_end += 2;
|
||||
}
|
||||
|
||||
/* 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, int bytes)
|
||||
{
|
||||
if (new_file_flag)
|
||||
{
|
||||
if (output_desc >= 0 && close (output_desc) < 0)
|
||||
error (1, errno, "%s", outfile);
|
||||
|
||||
next_file_name ();
|
||||
output_desc = open (outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (output_desc < 0)
|
||||
error (1, errno, "%s", outfile);
|
||||
}
|
||||
if (full_write (output_desc, bp, bytes) < 0)
|
||||
error (1, errno, "%s", outfile);
|
||||
}
|
||||
|
||||
/* Read NCHARS bytes from the input file into BUF.
|
||||
Return the number of bytes successfully read.
|
||||
If this is less than NCHARS, do not call `stdread' again. */
|
||||
|
||||
static int
|
||||
stdread (char *buf, int nchars)
|
||||
{
|
||||
int n_read;
|
||||
int to_be_read = nchars;
|
||||
|
||||
while (to_be_read)
|
||||
{
|
||||
n_read = safe_read (input_desc, buf, to_be_read);
|
||||
if (n_read < 0)
|
||||
return -1;
|
||||
if (n_read == 0)
|
||||
break;
|
||||
to_be_read -= n_read;
|
||||
buf += n_read;
|
||||
}
|
||||
return nchars - to_be_read;
|
||||
}
|
||||
|
||||
/* Split into pieces of exactly NCHARS bytes.
|
||||
Use buffer BUF, whose size is BUFSIZE. */
|
||||
|
||||
static void
|
||||
bytes_split (int nchars, char *buf, int bufsize)
|
||||
{
|
||||
int n_read;
|
||||
int new_file_flag = 1;
|
||||
int to_read;
|
||||
int to_write = nchars;
|
||||
char *bp_out;
|
||||
|
||||
do
|
||||
{
|
||||
n_read = stdread (buf, bufsize);
|
||||
if (n_read < 0)
|
||||
error (1, 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;
|
||||
}
|
||||
else
|
||||
{
|
||||
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 (int nlines, char *buf, int bufsize)
|
||||
{
|
||||
int n_read;
|
||||
char *bp, *bp_out, *eob;
|
||||
int new_file_flag = 1;
|
||||
int n = 0;
|
||||
|
||||
do
|
||||
{
|
||||
n_read = stdread (buf, bufsize);
|
||||
if (n_read < 0)
|
||||
error (1, errno, "%s", infile);
|
||||
bp = bp_out = buf;
|
||||
eob = bp + n_read;
|
||||
*eob = '\n';
|
||||
for (;;)
|
||||
{
|
||||
while (*bp++ != '\n')
|
||||
; /* this semicolon takes most of the time */
|
||||
if (bp > eob)
|
||||
{
|
||||
if (eob != bp_out) /* do not write 0 bytes! */
|
||||
{
|
||||
cwrite (new_file_flag, bp_out, eob - bp_out);
|
||||
new_file_flag = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
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 (int nchars)
|
||||
{
|
||||
int n_read;
|
||||
char *bp;
|
||||
int eof = 0;
|
||||
int n_buffered = 0;
|
||||
char *buf = (char *) xmalloc (nchars);
|
||||
|
||||
do
|
||||
{
|
||||
/* Fill up the full buffer size from the input file. */
|
||||
|
||||
n_read = stdread (buf + n_buffered, nchars - n_buffered);
|
||||
if (n_read < 0)
|
||||
error (1, 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);
|
||||
}
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
int num; /* numeric argument from command line */
|
||||
@@ -144,6 +371,7 @@ main (argc, argv)
|
||||
{
|
||||
/* 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, "0123456789b:l:C:", longopts, (int *) 0);
|
||||
if (c == EOF)
|
||||
@@ -158,25 +386,30 @@ main (argc, argv)
|
||||
if (split_type != type_undef)
|
||||
usage (2, _("cannot split in more than one way"));
|
||||
split_type = type_bytes;
|
||||
if (convint (optarg, &accum) == -1)
|
||||
if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
|
||||
|| tmp_long < 0 || tmp_long > INT_MAX)
|
||||
usage (2, _("invalid number of bytes"));
|
||||
accum = (int) tmp_long;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
if (split_type != type_undef)
|
||||
usage (2, _("cannot split in more than one way"));
|
||||
split_type = type_lines;
|
||||
if (!isdigits (optarg))
|
||||
if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
|
||||
|| tmp_long < 0 || tmp_long > INT_MAX)
|
||||
usage (2, _("invalid number of lines"));
|
||||
accum = atoi (optarg);
|
||||
accum = (int) tmp_long;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
if (split_type != type_undef)
|
||||
usage (2, _("cannot split in more than one way"));
|
||||
split_type = type_byteslines;
|
||||
if (convint (optarg, &accum) == -1)
|
||||
if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
|
||||
|| tmp_long < 0 || tmp_long > INT_MAX)
|
||||
usage (2, _("invalid number of bytes"));
|
||||
accum = (int) tmp_long;
|
||||
break;
|
||||
|
||||
case '0':
|
||||
@@ -292,294 +525,3 @@ main (argc, argv)
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
/* Return nonzero if the string STR is composed entirely of decimal digits. */
|
||||
|
||||
static int
|
||||
isdigits (str)
|
||||
char *str;
|
||||
{
|
||||
do
|
||||
{
|
||||
if (!ISDIGIT (*str))
|
||||
return 0;
|
||||
str++;
|
||||
}
|
||||
while (*str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Put the value of the number in STR into *VAL.
|
||||
STR can specify a positive integer, optionally ending in `k'
|
||||
to mean kilo or `m' to mean mega.
|
||||
Return 0 if STR is valid, -1 if not. */
|
||||
|
||||
static int
|
||||
convint (str, val)
|
||||
char *str;
|
||||
int *val;
|
||||
{
|
||||
int multiplier = 1;
|
||||
int arglen = strlen (str);
|
||||
|
||||
if (arglen > 1)
|
||||
{
|
||||
switch (str[arglen - 1])
|
||||
{
|
||||
case 'b':
|
||||
multiplier = 512;
|
||||
str[arglen - 1] = '\0';
|
||||
break;
|
||||
case 'k':
|
||||
multiplier = 1024;
|
||||
str[arglen - 1] = '\0';
|
||||
break;
|
||||
case 'm':
|
||||
multiplier = 1048576;
|
||||
str[arglen - 1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isdigits (str))
|
||||
return -1;
|
||||
*val = atoi (str) * multiplier;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Split into pieces of exactly NCHARS bytes.
|
||||
Use buffer BUF, whose size is BUFSIZE. */
|
||||
|
||||
static void
|
||||
bytes_split (nchars, buf, bufsize)
|
||||
int nchars;
|
||||
char *buf;
|
||||
int bufsize;
|
||||
{
|
||||
int n_read;
|
||||
int new_file_flag = 1;
|
||||
int to_read;
|
||||
int to_write = nchars;
|
||||
char *bp_out;
|
||||
|
||||
do
|
||||
{
|
||||
n_read = stdread (buf, bufsize);
|
||||
if (n_read < 0)
|
||||
error (1, 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;
|
||||
}
|
||||
else
|
||||
{
|
||||
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 (nlines, buf, bufsize)
|
||||
int nlines;
|
||||
char *buf;
|
||||
int bufsize;
|
||||
{
|
||||
int n_read;
|
||||
char *bp, *bp_out, *eob;
|
||||
int new_file_flag = 1;
|
||||
int n = 0;
|
||||
|
||||
do
|
||||
{
|
||||
n_read = stdread (buf, bufsize);
|
||||
if (n_read < 0)
|
||||
error (1, errno, "%s", infile);
|
||||
bp = bp_out = buf;
|
||||
eob = bp + n_read;
|
||||
*eob = '\n';
|
||||
for (;;)
|
||||
{
|
||||
while (*bp++ != '\n')
|
||||
; /* this semicolon takes most of the time */
|
||||
if (bp > eob)
|
||||
{
|
||||
if (eob != bp_out) /* do not write 0 bytes! */
|
||||
{
|
||||
cwrite (new_file_flag, bp_out, eob - bp_out);
|
||||
new_file_flag = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
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 (nchars)
|
||||
int nchars;
|
||||
{
|
||||
int n_read;
|
||||
char *bp;
|
||||
int eof = 0;
|
||||
int n_buffered = 0;
|
||||
char *buf = (char *) xmalloc (nchars);
|
||||
|
||||
do
|
||||
{
|
||||
/* Fill up the full buffer size from the input file. */
|
||||
|
||||
n_read = stdread (buf + n_buffered, nchars - n_buffered);
|
||||
if (n_read < 0)
|
||||
error (1, 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);
|
||||
}
|
||||
|
||||
/* 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 (new_file_flag, bp, bytes)
|
||||
int new_file_flag;
|
||||
char *bp;
|
||||
int bytes;
|
||||
{
|
||||
if (new_file_flag)
|
||||
{
|
||||
if (output_desc >= 0 && close (output_desc) < 0)
|
||||
error (1, errno, "%s", outfile);
|
||||
|
||||
next_file_name ();
|
||||
output_desc = open (outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (output_desc < 0)
|
||||
error (1, errno, "%s", outfile);
|
||||
}
|
||||
if (full_write (output_desc, bp, bytes) < 0)
|
||||
error (1, errno, "%s", outfile);
|
||||
}
|
||||
|
||||
/* Read NCHARS bytes from the input file into BUF.
|
||||
Return the number of bytes successfully read.
|
||||
If this is less than NCHARS, do not call `stdread' again. */
|
||||
|
||||
static int
|
||||
stdread (buf, nchars)
|
||||
char *buf;
|
||||
int nchars;
|
||||
{
|
||||
int n_read;
|
||||
int to_be_read = nchars;
|
||||
|
||||
while (to_be_read)
|
||||
{
|
||||
n_read = safe_read (input_desc, buf, to_be_read);
|
||||
if (n_read < 0)
|
||||
return -1;
|
||||
if (n_read == 0)
|
||||
break;
|
||||
to_be_read -= n_read;
|
||||
buf += n_read;
|
||||
}
|
||||
return nchars - to_be_read;
|
||||
}
|
||||
|
||||
/* Compute the next sequential output file name suffix and store it
|
||||
into the string `outfile' at the position pointed to by `outfile_mid'. */
|
||||
|
||||
static void
|
||||
next_file_name ()
|
||||
{
|
||||
int x;
|
||||
char *ne;
|
||||
unsigned int i;
|
||||
|
||||
static int first_call = 1;
|
||||
|
||||
/* Status for outfile name generation. */
|
||||
static unsigned outfile_count = 0;
|
||||
static unsigned outfile_name_limit = 25 * 26;
|
||||
static unsigned outfile_name_generation = 1;
|
||||
|
||||
if (!first_call)
|
||||
outfile_count++;
|
||||
first_call = 0;
|
||||
if (outfile_count < outfile_name_limit)
|
||||
{
|
||||
for (ne = outfile_end - 1; ; ne--)
|
||||
{
|
||||
x = *ne;
|
||||
if (x != 'z')
|
||||
break;
|
||||
*ne = 'a';
|
||||
}
|
||||
*ne = x + 1;
|
||||
return;
|
||||
}
|
||||
|
||||
outfile_count = 0;
|
||||
outfile_name_limit *= 26;
|
||||
outfile_name_generation++;
|
||||
*outfile_mid++ = 'z';
|
||||
for (i = 0; i <= outfile_name_generation; i++)
|
||||
outfile_mid[i] = 'a';
|
||||
outfile_end += 2;
|
||||
}
|
||||
|
||||
129
src/sum.c
129
src/sum.c
@@ -28,9 +28,6 @@
|
||||
#include "version.h"
|
||||
#include "error.h"
|
||||
|
||||
static int bsd_sum_file ();
|
||||
static int sysv_sum_file ();
|
||||
|
||||
int safe_read ();
|
||||
|
||||
/* The name this program was run with. */
|
||||
@@ -57,8 +54,7 @@ static struct option const longopts[] =
|
||||
};
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
int status;
|
||||
usage (int status)
|
||||
{
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
@@ -83,64 +79,6 @@ With no FILE, or when FILE is -, read standard input.\n\
|
||||
exit (status);
|
||||
}
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int errors = 0;
|
||||
int optc;
|
||||
int files_given;
|
||||
int (*sum_func) () = bsd_sum_file;
|
||||
|
||||
program_name = argv[0];
|
||||
have_read_stdin = 0;
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "rs", longopts, (int *) 0)) != -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;
|
||||
|
||||
default:
|
||||
usage (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (show_version)
|
||||
{
|
||||
printf ("sum - %s\n", version_string);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (show_help)
|
||||
usage (0);
|
||||
|
||||
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 (1, errno, "-");
|
||||
exit (errors);
|
||||
}
|
||||
|
||||
/* 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.
|
||||
@@ -148,9 +86,7 @@ main (argc, argv)
|
||||
Return 0 if successful, -1 if an error occurs. */
|
||||
|
||||
static int
|
||||
bsd_sum_file (file, print_name)
|
||||
char *file;
|
||||
int print_name;
|
||||
bsd_sum_file (const char *file, int print_name)
|
||||
{
|
||||
register FILE *fp;
|
||||
register unsigned long checksum = 0; /* The checksum mod 2^16. */
|
||||
@@ -210,9 +146,7 @@ bsd_sum_file (file, print_name)
|
||||
Return 0 if successful, -1 if an error occurs. */
|
||||
|
||||
static int
|
||||
sysv_sum_file (file, print_name)
|
||||
char *file;
|
||||
int print_name;
|
||||
sysv_sum_file (const char *file, int print_name)
|
||||
{
|
||||
int fd;
|
||||
unsigned char buf[8192];
|
||||
@@ -265,3 +199,60 @@ sysv_sum_file (file, print_name)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int errors = 0;
|
||||
int optc;
|
||||
int files_given;
|
||||
int (*sum_func) () = bsd_sum_file;
|
||||
|
||||
program_name = argv[0];
|
||||
have_read_stdin = 0;
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "rs", longopts, (int *) 0)) != -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;
|
||||
|
||||
default:
|
||||
usage (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (show_version)
|
||||
{
|
||||
printf ("sum - %s\n", version_string);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (show_help)
|
||||
usage (0);
|
||||
|
||||
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 (1, errno, "-");
|
||||
exit (errors);
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +141,11 @@ off_t lseek ();
|
||||
|
||||
#ifdef HAVE_UTIME_H
|
||||
#include <utime.h>
|
||||
#else
|
||||
#endif
|
||||
|
||||
/* Some systems (even some that do have <utime.h>) don't declare this
|
||||
structure anywhere. */
|
||||
#ifndef HAVE_STRUCT_UTIMBUF
|
||||
struct utimbuf
|
||||
{
|
||||
long actime;
|
||||
|
||||
626
src/tac.c
626
src/tac.c
@@ -63,16 +63,6 @@ char *realloc ();
|
||||
|
||||
char *mktemp ();
|
||||
|
||||
static RETSIGTYPE cleanup ();
|
||||
static int tac ();
|
||||
static int tac_file ();
|
||||
static int tac_stdin ();
|
||||
static char *xmalloc ();
|
||||
static char *xrealloc ();
|
||||
static void output ();
|
||||
static void save_stdin ();
|
||||
static void xwrite ();
|
||||
|
||||
int full_write ();
|
||||
int safe_read ();
|
||||
|
||||
@@ -110,6 +100,9 @@ static unsigned buffer_size;
|
||||
/* The compiled regular expression representing `separator'. */
|
||||
static struct re_pattern_buffer compiled_separator;
|
||||
|
||||
/* The name of a temporary file containing a copy of pipe input. */
|
||||
static char *tempfile;
|
||||
|
||||
/* If non-zero, display usage information and exit. */
|
||||
static int show_help;
|
||||
|
||||
@@ -127,8 +120,7 @@ static struct option const longopts[] =
|
||||
};
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
int status;
|
||||
usage (int status)
|
||||
{
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
@@ -153,281 +145,91 @@ With no FILE, or when FILE is -, read standard input.\n\
|
||||
exit (status);
|
||||
}
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
static RETSIGTYPE
|
||||
cleanup (void)
|
||||
{
|
||||
const char *error_message; /* Return value from re_compile_pattern. */
|
||||
int optc, errors;
|
||||
int have_read_stdin = 0;
|
||||
|
||||
program_name = argv[0];
|
||||
errors = 0;
|
||||
separator = "\n";
|
||||
sentinel_length = 1;
|
||||
separator_ends_record = 1;
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "brs:", longopts, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
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 (1, 0, _("separator cannot be empty"));
|
||||
break;
|
||||
default:
|
||||
usage (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (show_version)
|
||||
{
|
||||
printf ("tac - %s\n", version_string);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (show_help)
|
||||
usage (0);
|
||||
|
||||
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 (1, 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;
|
||||
buffer_size = read_size * 2 + sentinel_length + 2;
|
||||
buffer = xmalloc (buffer_size);
|
||||
if (sentinel_length)
|
||||
{
|
||||
strcpy (buffer, separator);
|
||||
buffer += sentinel_length;
|
||||
}
|
||||
else
|
||||
++buffer;
|
||||
|
||||
if (optind == argc)
|
||||
{
|
||||
have_read_stdin = 1;
|
||||
errors = tac_stdin ();
|
||||
}
|
||||
else
|
||||
for (; optind < argc; ++optind)
|
||||
{
|
||||
if (strcmp (argv[optind], "-") == 0)
|
||||
{
|
||||
have_read_stdin = 1;
|
||||
errors |= tac_stdin ();
|
||||
}
|
||||
else
|
||||
errors |= tac_file (argv[optind]);
|
||||
}
|
||||
|
||||
/* Flush the output buffer. */
|
||||
output ((char *) NULL, (char *) NULL);
|
||||
|
||||
if (have_read_stdin && close (0) < 0)
|
||||
error (1, errno, "-");
|
||||
if (close (1) < 0)
|
||||
error (1, errno, _("write error"));
|
||||
exit (errors);
|
||||
}
|
||||
|
||||
/* The name of a temporary file containing a copy of pipe input. */
|
||||
char *tempfile;
|
||||
|
||||
/* Print the standard input in reverse, saving it to temporary
|
||||
file `tempfile' first if it is a pipe.
|
||||
Return 0 if ok, 1 if an error occurs. */
|
||||
|
||||
static int
|
||||
tac_stdin ()
|
||||
{
|
||||
/* Previous values of signal handlers. */
|
||||
RETSIGTYPE (*sigint) (), (*sighup) (), (*sigpipe) (), (*sigterm) ();
|
||||
int errors;
|
||||
struct stat stats;
|
||||
#ifdef _POSIX_VERSION
|
||||
struct sigaction oldact, newact;
|
||||
#endif /* _POSIX_VERSION */
|
||||
|
||||
/* 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 (0, &stats))
|
||||
{
|
||||
error (0, errno, _("standard input"));
|
||||
return 1;
|
||||
}
|
||||
if (S_ISREG (stats.st_mode))
|
||||
return tac (0, _("standard input"));
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
newact.sa_handler = cleanup;
|
||||
sigemptyset (&newact.sa_mask);
|
||||
newact.sa_flags = 0;
|
||||
|
||||
sigaction (SIGINT, NULL, &oldact);
|
||||
sigint = oldact.sa_handler;
|
||||
if (sigint != SIG_IGN)
|
||||
sigaction (SIGINT, &newact, NULL);
|
||||
|
||||
sigaction (SIGHUP, NULL, &oldact);
|
||||
sighup = oldact.sa_handler;
|
||||
if (sighup != SIG_IGN)
|
||||
sigaction (SIGHUP, &newact, NULL);
|
||||
|
||||
sigaction (SIGPIPE, NULL, &oldact);
|
||||
sigpipe = oldact.sa_handler;
|
||||
if (sigpipe != SIG_IGN)
|
||||
sigaction (SIGPIPE, &newact, NULL);
|
||||
|
||||
sigaction (SIGTERM, NULL, &oldact);
|
||||
sigterm = oldact.sa_handler;
|
||||
if (sigterm != SIG_IGN)
|
||||
sigaction (SIGTERM, &newact, NULL);
|
||||
#else /* !_POSIX_VERSION */
|
||||
sigint = signal (SIGINT, SIG_IGN);
|
||||
if (sigint != SIG_IGN)
|
||||
signal (SIGINT, cleanup);
|
||||
|
||||
sighup = signal (SIGHUP, SIG_IGN);
|
||||
if (sighup != SIG_IGN)
|
||||
signal (SIGHUP, cleanup);
|
||||
|
||||
sigpipe = signal (SIGPIPE, SIG_IGN);
|
||||
if (sigpipe != SIG_IGN)
|
||||
signal (SIGPIPE, cleanup);
|
||||
|
||||
sigterm = signal (SIGTERM, SIG_IGN);
|
||||
if (sigterm != SIG_IGN)
|
||||
signal (SIGTERM, cleanup);
|
||||
#endif /* _POSIX_VERSION */
|
||||
|
||||
save_stdin ();
|
||||
|
||||
errors = tac_file (tempfile);
|
||||
|
||||
unlink (tempfile);
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
newact.sa_handler = sigint;
|
||||
sigaction (SIGINT, &newact, NULL);
|
||||
newact.sa_handler = sighup;
|
||||
sigaction (SIGHUP, &newact, NULL);
|
||||
newact.sa_handler = sigterm;
|
||||
sigaction (SIGTERM, &newact, NULL);
|
||||
newact.sa_handler = sigpipe;
|
||||
sigaction (SIGPIPE, &newact, NULL);
|
||||
#else /* !_POSIX_VERSION */
|
||||
signal (SIGINT, sigint);
|
||||
signal (SIGHUP, sighup);
|
||||
signal (SIGTERM, sigterm);
|
||||
signal (SIGPIPE, sigpipe);
|
||||
#endif /* _POSIX_VERSION */
|
||||
|
||||
return errors;
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Make a copy of the standard input in `tempfile'. */
|
||||
/* Allocate N bytes of memory dynamically, with error checking. */
|
||||
|
||||
static char *
|
||||
xmalloc (unsigned int n)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = malloc (n);
|
||||
if (p == 0)
|
||||
{
|
||||
error (0, 0, _("virtual memory exhausted"));
|
||||
cleanup ();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Change the size of memory area P to N bytes, with error checking. */
|
||||
|
||||
static char *
|
||||
xrealloc (char *p, unsigned int n)
|
||||
{
|
||||
p = realloc (p, n);
|
||||
if (p == 0)
|
||||
{
|
||||
error (0, 0, _("virtual memory exhausted"));
|
||||
cleanup ();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
save_stdin ()
|
||||
xwrite (int desc, const char *buffer, int size)
|
||||
{
|
||||
static char *template = NULL;
|
||||
static char *tempdir;
|
||||
int fd;
|
||||
int bytes_read;
|
||||
|
||||
if (template == NULL)
|
||||
if (full_write (desc, buffer, size) < 0)
|
||||
{
|
||||
tempdir = getenv ("TMPDIR");
|
||||
if (tempdir == NULL)
|
||||
tempdir = DEFAULT_TMPDIR;
|
||||
template = xmalloc (strlen (tempdir) + 11);
|
||||
}
|
||||
sprintf (template, "%s/tacXXXXXX", tempdir);
|
||||
tempfile = mktemp (template);
|
||||
|
||||
fd = creat (tempfile, 0600);
|
||||
if (fd == -1)
|
||||
{
|
||||
error (0, errno, "%s", tempfile);
|
||||
cleanup ();
|
||||
}
|
||||
while ((bytes_read = safe_read (0, buffer, read_size)) > 0)
|
||||
if (full_write (fd, buffer, bytes_read) < 0)
|
||||
{
|
||||
error (0, errno, "%s", tempfile);
|
||||
cleanup ();
|
||||
}
|
||||
if (close (fd) < 0)
|
||||
{
|
||||
error (0, errno, "%s", tempfile);
|
||||
cleanup ();
|
||||
}
|
||||
if (bytes_read == -1)
|
||||
{
|
||||
error (0, errno, _("read error"));
|
||||
error (0, errno, _("write error"));
|
||||
cleanup ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Print FILE in reverse.
|
||||
Return 0 if ok, 1 if an error occurs. */
|
||||
/* Print the characters from START to PAST_END - 1.
|
||||
If START is NULL, just flush the buffer. */
|
||||
|
||||
static int
|
||||
tac_file (file)
|
||||
char *file;
|
||||
static void
|
||||
output (const char *start, const char *past_end)
|
||||
{
|
||||
int fd, errors;
|
||||
static char buffer[WRITESIZE];
|
||||
static int bytes_in_buffer = 0;
|
||||
int bytes_to_add = past_end - start;
|
||||
int bytes_available = WRITESIZE - bytes_in_buffer;
|
||||
|
||||
fd = open (file, O_RDONLY);
|
||||
if (fd == -1)
|
||||
if (start == 0)
|
||||
{
|
||||
error (0, errno, "%s", file);
|
||||
return 1;
|
||||
xwrite (STDOUT_FILENO, buffer, bytes_in_buffer);
|
||||
bytes_in_buffer = 0;
|
||||
return;
|
||||
}
|
||||
errors = tac (fd, file);
|
||||
if (close (fd) < 0)
|
||||
|
||||
/* Write out as many full buffers as possible. */
|
||||
while (bytes_to_add >= bytes_available)
|
||||
{
|
||||
error (0, errno, "%s", file);
|
||||
return 1;
|
||||
memcpy (buffer + bytes_in_buffer, start, bytes_available);
|
||||
bytes_to_add -= bytes_available;
|
||||
start += bytes_available;
|
||||
xwrite (STDOUT_FILENO, buffer, WRITESIZE);
|
||||
bytes_in_buffer = 0;
|
||||
bytes_available = WRITESIZE;
|
||||
}
|
||||
return errors;
|
||||
|
||||
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 (fd, file)
|
||||
int fd;
|
||||
char *file;
|
||||
tac (int fd, const char *file)
|
||||
{
|
||||
/* Pointer to the location in `buffer' where the search for
|
||||
the next separator will begin. */
|
||||
@@ -590,90 +392,264 @@ tac (fd, file)
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the characters from START to PAST_END - 1.
|
||||
If START is NULL, just flush the buffer. */
|
||||
/* Print FILE in reverse.
|
||||
Return 0 if ok, 1 if an error occurs. */
|
||||
|
||||
static void
|
||||
output (start, past_end)
|
||||
char *start;
|
||||
char *past_end;
|
||||
static int
|
||||
tac_file (const char *file)
|
||||
{
|
||||
static char buffer[WRITESIZE];
|
||||
static int bytes_in_buffer = 0;
|
||||
int bytes_to_add = past_end - start;
|
||||
int bytes_available = WRITESIZE - bytes_in_buffer;
|
||||
int fd, errors;
|
||||
|
||||
if (start == 0)
|
||||
fd = open (file, O_RDONLY);
|
||||
if (fd == -1)
|
||||
{
|
||||
xwrite (STDOUT_FILENO, buffer, bytes_in_buffer);
|
||||
bytes_in_buffer = 0;
|
||||
return;
|
||||
error (0, errno, "%s", file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write out as many full buffers as possible. */
|
||||
while (bytes_to_add >= bytes_available)
|
||||
errors = tac (fd, file);
|
||||
if (close (fd) < 0)
|
||||
{
|
||||
memcpy (buffer + bytes_in_buffer, start, bytes_available);
|
||||
bytes_to_add -= bytes_available;
|
||||
start += bytes_available;
|
||||
xwrite (STDOUT_FILENO, buffer, WRITESIZE);
|
||||
bytes_in_buffer = 0;
|
||||
bytes_available = WRITESIZE;
|
||||
error (0, errno, "%s", file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy (buffer + bytes_in_buffer, start, bytes_to_add);
|
||||
bytes_in_buffer += bytes_to_add;
|
||||
return errors;
|
||||
}
|
||||
|
||||
static RETSIGTYPE
|
||||
cleanup ()
|
||||
/* Make a copy of the standard input in `tempfile'. */
|
||||
|
||||
static void
|
||||
save_stdin (void)
|
||||
{
|
||||
static char *template = NULL;
|
||||
static char *tempdir;
|
||||
int fd;
|
||||
int bytes_read;
|
||||
|
||||
if (template == NULL)
|
||||
{
|
||||
tempdir = getenv ("TMPDIR");
|
||||
if (tempdir == NULL)
|
||||
tempdir = DEFAULT_TMPDIR;
|
||||
template = xmalloc (strlen (tempdir) + 11);
|
||||
}
|
||||
sprintf (template, "%s/tacXXXXXX", tempdir);
|
||||
tempfile = mktemp (template);
|
||||
|
||||
fd = creat (tempfile, 0600);
|
||||
if (fd == -1)
|
||||
{
|
||||
error (0, errno, "%s", tempfile);
|
||||
cleanup ();
|
||||
}
|
||||
while ((bytes_read = safe_read (0, buffer, read_size)) > 0)
|
||||
if (full_write (fd, buffer, bytes_read) < 0)
|
||||
{
|
||||
error (0, errno, "%s", tempfile);
|
||||
cleanup ();
|
||||
}
|
||||
if (close (fd) < 0)
|
||||
{
|
||||
error (0, errno, "%s", tempfile);
|
||||
cleanup ();
|
||||
}
|
||||
if (bytes_read == -1)
|
||||
{
|
||||
error (0, errno, _("read error"));
|
||||
cleanup ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the standard input in reverse, saving it to temporary
|
||||
file `tempfile' first if it is a pipe.
|
||||
Return 0 if ok, 1 if an error occurs. */
|
||||
|
||||
static int
|
||||
tac_stdin (void)
|
||||
{
|
||||
/* Previous values of signal handlers. */
|
||||
RETSIGTYPE (*sigint) (), (*sighup) (), (*sigpipe) (), (*sigterm) ();
|
||||
int errors;
|
||||
struct stat stats;
|
||||
#ifdef SA_INTERRUPT
|
||||
struct sigaction oldact, newact;
|
||||
#endif /* SA_INTERRUPT */
|
||||
|
||||
/* 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 (0, &stats))
|
||||
{
|
||||
error (0, errno, _("standard input"));
|
||||
return 1;
|
||||
}
|
||||
if (S_ISREG (stats.st_mode))
|
||||
return tac (0, _("standard input"));
|
||||
|
||||
#ifdef SA_INTERRUPT
|
||||
newact.sa_handler = cleanup;
|
||||
sigemptyset (&newact.sa_mask);
|
||||
newact.sa_flags = 0;
|
||||
|
||||
sigaction (SIGINT, NULL, &oldact);
|
||||
sigint = oldact.sa_handler;
|
||||
if (sigint != SIG_IGN)
|
||||
sigaction (SIGINT, &newact, NULL);
|
||||
|
||||
sigaction (SIGHUP, NULL, &oldact);
|
||||
sighup = oldact.sa_handler;
|
||||
if (sighup != SIG_IGN)
|
||||
sigaction (SIGHUP, &newact, NULL);
|
||||
|
||||
sigaction (SIGPIPE, NULL, &oldact);
|
||||
sigpipe = oldact.sa_handler;
|
||||
if (sigpipe != SIG_IGN)
|
||||
sigaction (SIGPIPE, &newact, NULL);
|
||||
|
||||
sigaction (SIGTERM, NULL, &oldact);
|
||||
sigterm = oldact.sa_handler;
|
||||
if (sigterm != SIG_IGN)
|
||||
sigaction (SIGTERM, &newact, NULL);
|
||||
#else /* !SA_INTERRUPT */
|
||||
sigint = signal (SIGINT, SIG_IGN);
|
||||
if (sigint != SIG_IGN)
|
||||
signal (SIGINT, cleanup);
|
||||
|
||||
sighup = signal (SIGHUP, SIG_IGN);
|
||||
if (sighup != SIG_IGN)
|
||||
signal (SIGHUP, cleanup);
|
||||
|
||||
sigpipe = signal (SIGPIPE, SIG_IGN);
|
||||
if (sigpipe != SIG_IGN)
|
||||
signal (SIGPIPE, cleanup);
|
||||
|
||||
sigterm = signal (SIGTERM, SIG_IGN);
|
||||
if (sigterm != SIG_IGN)
|
||||
signal (SIGTERM, cleanup);
|
||||
#endif /* SA_INTERRUPT */
|
||||
|
||||
save_stdin ();
|
||||
|
||||
errors = tac_file (tempfile);
|
||||
|
||||
unlink (tempfile);
|
||||
exit (1);
|
||||
|
||||
#ifdef SA_INTERRUPT
|
||||
newact.sa_handler = sigint;
|
||||
sigaction (SIGINT, &newact, NULL);
|
||||
newact.sa_handler = sighup;
|
||||
sigaction (SIGHUP, &newact, NULL);
|
||||
newact.sa_handler = sigterm;
|
||||
sigaction (SIGTERM, &newact, NULL);
|
||||
newact.sa_handler = sigpipe;
|
||||
sigaction (SIGPIPE, &newact, NULL);
|
||||
#else /* !SA_INTERRUPT */
|
||||
signal (SIGINT, sigint);
|
||||
signal (SIGHUP, sighup);
|
||||
signal (SIGTERM, sigterm);
|
||||
signal (SIGPIPE, sigpipe);
|
||||
#endif /* SA_INTERRUPT */
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
static void
|
||||
xwrite (desc, buffer, size)
|
||||
int desc;
|
||||
char *buffer;
|
||||
int size;
|
||||
void
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
if (full_write (desc, buffer, size) < 0)
|
||||
const char *error_message; /* Return value from re_compile_pattern. */
|
||||
int optc, errors;
|
||||
int have_read_stdin = 0;
|
||||
|
||||
program_name = argv[0];
|
||||
errors = 0;
|
||||
separator = "\n";
|
||||
sentinel_length = 1;
|
||||
separator_ends_record = 1;
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "brs:", longopts, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
error (0, errno, _("write error"));
|
||||
cleanup ();
|
||||
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 (1, 0, _("separator cannot be empty"));
|
||||
break;
|
||||
default:
|
||||
usage (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate N bytes of memory dynamically, with error checking. */
|
||||
|
||||
static char *
|
||||
xmalloc (n)
|
||||
unsigned n;
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = malloc (n);
|
||||
if (p == 0)
|
||||
if (show_version)
|
||||
{
|
||||
error (0, 0, _("virtual memory exhausted"));
|
||||
cleanup ();
|
||||
printf ("tac - %s\n", version_string);
|
||||
exit (0);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Change the size of memory area P to N bytes, with error checking. */
|
||||
if (show_help)
|
||||
usage (0);
|
||||
|
||||
static char *
|
||||
xrealloc (p, n)
|
||||
char *p;
|
||||
unsigned n;
|
||||
{
|
||||
p = realloc (p, n);
|
||||
if (p == 0)
|
||||
if (sentinel_length == 0)
|
||||
{
|
||||
error (0, 0, _("virtual memory exhausted"));
|
||||
cleanup ();
|
||||
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 (1, 0, "%s", error_message);
|
||||
}
|
||||
return p;
|
||||
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;
|
||||
buffer_size = read_size * 2 + sentinel_length + 2;
|
||||
buffer = xmalloc (buffer_size);
|
||||
if (sentinel_length)
|
||||
{
|
||||
strcpy (buffer, separator);
|
||||
buffer += sentinel_length;
|
||||
}
|
||||
else
|
||||
++buffer;
|
||||
|
||||
if (optind == argc)
|
||||
{
|
||||
have_read_stdin = 1;
|
||||
errors = tac_stdin ();
|
||||
}
|
||||
else
|
||||
for (; optind < argc; ++optind)
|
||||
{
|
||||
if (strcmp (argv[optind], "-") == 0)
|
||||
{
|
||||
have_read_stdin = 1;
|
||||
errors |= tac_stdin ();
|
||||
}
|
||||
else
|
||||
errors |= tac_file (argv[optind]);
|
||||
}
|
||||
|
||||
/* Flush the output buffer. */
|
||||
output ((char *) NULL, (char *) NULL);
|
||||
|
||||
if (have_read_stdin && close (0) < 0)
|
||||
error (1, errno, "-");
|
||||
if (close (1) < 0)
|
||||
error (1, errno, _("write error"));
|
||||
exit (errors);
|
||||
}
|
||||
|
||||
1451
src/tail.c
1451
src/tail.c
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,8 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define TEST_STANDALONE 1
|
||||
|
||||
#if !defined (TEST_STANDALONE)
|
||||
# include "shell.h"
|
||||
# include "posixstat.h"
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-d, --date=TIME Specify time and date in various formats.
|
||||
-f Ignored.
|
||||
-m, --time={mtime,modify} Change modification time only.
|
||||
-r, --file=FILE Use the time and date of reference file FILE.
|
||||
-r, --reference=FILE Use the time and date of reference file FILE.
|
||||
-t TIME Specify time and date in the form
|
||||
`MMDDhhmm[[CC]YY][.ss]'.
|
||||
|
||||
@@ -107,6 +107,7 @@ static struct option const longopts[] =
|
||||
{"no-create", no_argument, 0, 'c'},
|
||||
{"date", required_argument, 0, 'd'},
|
||||
{"file", required_argument, 0, 'r'},
|
||||
{"reference", required_argument, 0, 'r'},
|
||||
{"help", no_argument, &show_help, 1},
|
||||
{"version", no_argument, &show_version, 1},
|
||||
{0, 0, 0, 0}
|
||||
@@ -385,7 +386,7 @@ Update the access and modification times of each FILE to the current time.\n\
|
||||
-d, --date=STRING parse STRING and use it instead of current time\n\
|
||||
-f (ignored)\n\
|
||||
-m change only the modification time\n\
|
||||
-r, --file=REFERENCE use this file's times instead of current time\n\
|
||||
-r, --reference=FILE use this file's times instead of current time\n\
|
||||
-t STAMP use MMDDhhmm[[CC]YY][.ss] instead of current time\n\
|
||||
--help display this help and exit\n\
|
||||
--time=WORD access -a, atime -a, mtime -m, modify -m, use -a\n\
|
||||
|
||||
319
src/tr.c
319
src/tr.c
@@ -12,8 +12,8 @@
|
||||
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. */
|
||||
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, meyering@cs.utexas.edu. */
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
#include <sys/types.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#include "system.h"
|
||||
#include "version.h"
|
||||
#include "error.h"
|
||||
@@ -41,6 +45,14 @@
|
||||
#define LONG_MAX ((long int) (ULONG_MAX >> 1))
|
||||
#endif
|
||||
|
||||
#ifndef UINT_MAX
|
||||
# define UINT_MAX ((unsigned int) ~(unsigned int) 0)
|
||||
#endif
|
||||
|
||||
#ifndef INT_MAX
|
||||
# define INT_MAX ((int) (UINT_MAX >> 1))
|
||||
#endif
|
||||
|
||||
#ifndef UCHAR_MAX
|
||||
#define UCHAR_MAX 0xFF
|
||||
#endif
|
||||
@@ -60,9 +72,10 @@ typedef int (*PFI) ();
|
||||
|
||||
/* The value for Spec_list->state that indicates to
|
||||
get_next that it should initialize the tail pointer.
|
||||
Its value doesn't matter as long as it can't be
|
||||
confused with a valid character code. */
|
||||
#define BEGIN_STATE (2 * N_CHARS)
|
||||
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
|
||||
@@ -201,6 +214,22 @@ struct Spec_list
|
||||
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 non-zero 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)])
|
||||
|
||||
|
||||
char *xmalloc ();
|
||||
char *stpcpy ();
|
||||
int safe_read ();
|
||||
@@ -460,9 +489,17 @@ is_char_class_member (enum Char_class char_class, unsigned int c)
|
||||
cannot contain actual (non-escaped) zero bytes. */
|
||||
|
||||
static int
|
||||
unquote (unsigned char *s, size_t *len)
|
||||
unquote (const unsigned char *s, struct E_string *es)
|
||||
{
|
||||
size_t i, j;
|
||||
size_t len;
|
||||
|
||||
len = strlen (s);
|
||||
|
||||
es->s = 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++)
|
||||
@@ -542,18 +579,26 @@ unquote (unsigned char *s, size_t *len)
|
||||
return 1;
|
||||
|
||||
default:
|
||||
error (0, 0, _("invalid backslash escape `\\%c'"), s[i + 1]);
|
||||
return 1;
|
||||
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;
|
||||
s[j++] = c;
|
||||
es->s[j++] = c;
|
||||
break;
|
||||
default:
|
||||
s[j++] = s[i];
|
||||
es->s[j++] = s[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
*len = j;
|
||||
es->len = j;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -709,23 +754,18 @@ append_range (struct Spec_list *list, unsigned int first, unsigned int last)
|
||||
/* 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, print an error message and return non-zero. */
|
||||
a valid string return non-zero. */
|
||||
|
||||
static int
|
||||
append_char_class (struct Spec_list *list, const unsigned char *char_class_str, size_t len)
|
||||
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)
|
||||
{
|
||||
char *tmp = make_printable_str (char_class_str, len);
|
||||
|
||||
error (0, 0, _("invalid character class `%s'"), tmp);
|
||||
free (tmp);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
new = (struct List_element *) xmalloc (sizeof (struct List_element));
|
||||
new->next = NULL;
|
||||
new->type = RE_CHAR_CLASS;
|
||||
@@ -742,7 +782,8 @@ append_char_class (struct Spec_list *list, const unsigned char *char_class_str,
|
||||
is a non-negative repeat count. */
|
||||
|
||||
static void
|
||||
append_repeated_char (struct Spec_list *list, unsigned int the_char, size_t repeat_count)
|
||||
append_repeated_char (struct Spec_list *list, unsigned int the_char,
|
||||
size_t repeat_count)
|
||||
{
|
||||
struct List_element *new;
|
||||
|
||||
@@ -760,22 +801,16 @@ append_repeated_char (struct Spec_list *list, unsigned int the_char, size_t repe
|
||||
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, issue an error message and return non-zero. */
|
||||
If LEN is not 1, return non-zero. */
|
||||
|
||||
static int
|
||||
append_equiv_class (struct Spec_list *list, const unsigned char *equiv_class_str, size_t len)
|
||||
append_equiv_class (struct Spec_list *list,
|
||||
const unsigned char *equiv_class_str, size_t len)
|
||||
{
|
||||
struct List_element *new;
|
||||
|
||||
if (len != 1)
|
||||
{
|
||||
char *tmp = make_printable_str (equiv_class_str, len);
|
||||
|
||||
error (0, 0, _("%s: equivalence class operand must be a single character"),
|
||||
tmp);
|
||||
free (tmp);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
new = (struct List_element *) xmalloc (sizeof (struct List_element));
|
||||
new->next = NULL;
|
||||
new->type = RE_EQUIV_CLASS;
|
||||
@@ -813,12 +848,14 @@ substr (const unsigned char *p, size_t first_idx, size_t last_idx)
|
||||
zero bytes. */
|
||||
|
||||
static int
|
||||
find_closing_delim (const unsigned char *p, size_t start_idx, size_t p_len, unsigned int pre_bracket_char, size_t *result_idx)
|
||||
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 < p_len - 1; i++)
|
||||
if (p[i] == pre_bracket_char && p[i + 1] == ']')
|
||||
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;
|
||||
@@ -879,22 +916,24 @@ non_neg_strtol (const unsigned char *s, size_t len, size_t *val)
|
||||
and return -2. */
|
||||
|
||||
static int
|
||||
find_bracketed_repeat (const unsigned char *p, size_t start_idx, size_t p_len, unsigned int *char_to_repeat, size_t *repeat_count, size_t *closing_bracket_idx)
|
||||
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 < p_len);
|
||||
if (p[start_idx + 1] != '*')
|
||||
assert (start_idx + 1 < es->len);
|
||||
if (!ES_MATCH (es, start_idx + 1, '*'))
|
||||
return -1;
|
||||
|
||||
for (i = start_idx + 2; i < p_len; i++)
|
||||
for (i = start_idx + 2; i < es->len; i++)
|
||||
{
|
||||
if (p[i] == ']')
|
||||
if (ES_MATCH (es, i, ']'))
|
||||
{
|
||||
const unsigned char *digit_str;
|
||||
size_t digit_str_len = i - start_idx - 2;
|
||||
|
||||
*char_to_repeat = p[start_idx];
|
||||
*char_to_repeat = es->s[start_idx];
|
||||
if (digit_str_len == 0)
|
||||
{
|
||||
/* We've matched [c*] -- no explicit repeat count. */
|
||||
@@ -905,8 +944,9 @@ find_bracketed_repeat (const unsigned char *p, size_t start_idx, size_t p_len, u
|
||||
|
||||
/* Here, we have found [c*s] where s should be a string
|
||||
of octal or decimal digits. */
|
||||
digit_str = &p[start_idx + 2];
|
||||
if (non_neg_strtol (digit_str, digit_str_len, repeat_count))
|
||||
digit_str = &es->s[start_idx + 2];
|
||||
if (non_neg_strtol (digit_str, digit_str_len, repeat_count)
|
||||
|| *repeat_count > BEGIN_STATE)
|
||||
{
|
||||
char *tmp = make_printable_str (digit_str, digit_str_len);
|
||||
error (0, 0, _("invalid repeat count `%s' in [c*n] construct"),
|
||||
@@ -921,6 +961,30 @@ find_bracketed_repeat (const unsigned char *p, size_t start_idx, size_t p_len, u
|
||||
return -1; /* No bracket found. */
|
||||
}
|
||||
|
||||
/* Return non-zero 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, int idx)
|
||||
{
|
||||
int 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 UNESACPED_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:
|
||||
@@ -934,12 +998,12 @@ find_bracketed_repeat (const unsigned char *p, size_t start_idx, size_t p_len, u
|
||||
- c Any other character is interpreted as itself. */
|
||||
|
||||
static int
|
||||
build_spec_list (const unsigned char *unescaped_string, size_t len, struct Spec_list *result)
|
||||
build_spec_list (const struct E_string *es, struct Spec_list *result)
|
||||
{
|
||||
const unsigned char *p;
|
||||
size_t i;
|
||||
|
||||
p = unescaped_string;
|
||||
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
|
||||
@@ -948,38 +1012,81 @@ build_spec_list (const unsigned char *unescaped_string, size_t len, struct Spec_
|
||||
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 < len;)
|
||||
for (i = 0; i + 2 < es->len; /* empty */)
|
||||
{
|
||||
switch (p[i])
|
||||
if (ES_MATCH (es, i, '['))
|
||||
{
|
||||
int fall_through;
|
||||
int matched_multi_char_construct;
|
||||
size_t closing_bracket_idx;
|
||||
unsigned int char_to_repeat;
|
||||
size_t repeat_count;
|
||||
int err;
|
||||
|
||||
case '[':
|
||||
fall_through = 0;
|
||||
switch (p[i + 1])
|
||||
matched_multi_char_construct = 1;
|
||||
if (ES_MATCH (es, i + 1, ':')
|
||||
|| ES_MATCH (es, i + 1, '='))
|
||||
{
|
||||
size_t closing_delim_idx;
|
||||
size_t closing_bracket_idx;
|
||||
unsigned int char_to_repeat;
|
||||
size_t repeat_count;
|
||||
int found;
|
||||
|
||||
case ':':
|
||||
case '=':
|
||||
found = find_closing_delim (p, i + 2, len, p[i + 1],
|
||||
found = find_closing_delim (es, i + 2, p[i + 1],
|
||||
&closing_delim_idx);
|
||||
if (found)
|
||||
{
|
||||
int parse_failed;
|
||||
unsigned char *opnd_str = substr (p, i + 2,
|
||||
closing_delim_idx - 1);
|
||||
size_t opnd_str_len = closing_delim_idx - 1 - (i + 2) + 1;
|
||||
|
||||
if (p[i + 1] == ':')
|
||||
parse_failed = append_char_class (result, opnd_str,
|
||||
(closing_delim_idx - 1) - (i + 2) + 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,
|
||||
(closing_delim_idx - 1) - (i + 2) + 1);
|
||||
{
|
||||
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 non-zero if append_*_class reports a problem. */
|
||||
@@ -987,56 +1094,58 @@ build_spec_list (const unsigned char *unescaped_string, size_t len, struct Spec_
|
||||
return 1;
|
||||
else
|
||||
i = closing_delim_idx + 2;
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
/* Else fall through. This could be [:*] or [=*]. */
|
||||
default:
|
||||
/* Determine whether this is a bracketed repeat range
|
||||
matching the RE \[.\*(dec_or_oct_number)?\]. */
|
||||
err = find_bracketed_repeat (p, i + 1, len, &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;
|
||||
break;
|
||||
}
|
||||
else if (err == -1)
|
||||
{
|
||||
fall_through = 1;
|
||||
}
|
||||
else
|
||||
/* Found a string that looked like [c*n] but the
|
||||
numeric part was invalid. */
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
if (!fall_through)
|
||||
break;
|
||||
|
||||
/* Here if we've tried to match [c*n], [:str:], and [=c=]
|
||||
and none of them fit. So we still have to consider the
|
||||
range `[-c' (from `[' to `c'). */
|
||||
default:
|
||||
/* Look ahead one char for ranges like a-z. */
|
||||
if (p[i + 1] == '-')
|
||||
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)
|
||||
{
|
||||
if (append_range (result, p[i], p[i + 2]))
|
||||
return 1;
|
||||
i += 3;
|
||||
append_repeated_char (result, char_to_repeat, repeat_count);
|
||||
i = closing_bracket_idx + 1;
|
||||
}
|
||||
else if (err == -1)
|
||||
{
|
||||
matched_multi_char_construct = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
append_normal_char (result, p[i]);
|
||||
++i;
|
||||
/* Found a string that looked like [c*n] but the
|
||||
numeric part was invalid. */
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
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[len - 1]. */
|
||||
for (; i < len; 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;
|
||||
@@ -1317,13 +1426,13 @@ spec_init (struct Spec_list *spec_list)
|
||||
of these passes detects an error, this function returns non-zero. */
|
||||
|
||||
static int
|
||||
parse_str (unsigned char *s, struct Spec_list *spec_list)
|
||||
parse_str (const unsigned char *s, struct Spec_list *spec_list)
|
||||
{
|
||||
size_t len;
|
||||
struct E_string es;
|
||||
|
||||
if (unquote (s, &len))
|
||||
if (unquote (s, &es))
|
||||
return 1;
|
||||
if (build_spec_list (s, len, spec_list))
|
||||
if (build_spec_list (&es, spec_list))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -1433,7 +1542,8 @@ appear in\n\tstring2 are `upper' and `lower'"));
|
||||
|
||||
if (s2->n_indefinite_repeats > 1)
|
||||
{
|
||||
error (1, 0, _("only one [c*] repeat construct may appear in string2"));
|
||||
error (1, 0,
|
||||
_("only one [c*] repeat construct may appear in string2"));
|
||||
}
|
||||
|
||||
if (translating)
|
||||
@@ -1765,7 +1875,8 @@ without squeezing repeats"));
|
||||
}
|
||||
|
||||
if (squeeze_repeats && non_option_args == 0)
|
||||
error (1, 0, _("at least one string must be given when squeezing repeats"));
|
||||
error (1, 0,
|
||||
_("at least one string must be given when squeezing repeats"));
|
||||
|
||||
spec_init (s1);
|
||||
if (parse_str ((unsigned char *) argv[optind], s1))
|
||||
|
||||
289
src/unexpand.c
289
src/unexpand.c
@@ -58,13 +58,6 @@
|
||||
char *xmalloc ();
|
||||
char *xrealloc ();
|
||||
|
||||
static FILE *next_file ();
|
||||
static void add_tabstop ();
|
||||
static void parse_tabstops ();
|
||||
static void unexpand ();
|
||||
static void usage ();
|
||||
static void validate_tabstops ();
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
@@ -114,90 +107,24 @@ static struct option const longopts[] =
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
/* Add tab stop TABVAL to the end of `tab_list', except
|
||||
if TABVAL is -1, do nothing. */
|
||||
|
||||
static void
|
||||
add_tabstop (int tabval)
|
||||
{
|
||||
int tabval = -1; /* Value of tabstop being read, or -1. */
|
||||
int c; /* Option character. */
|
||||
|
||||
have_read_stdin = 0;
|
||||
exit_status = 0;
|
||||
convert_entire_line = 0;
|
||||
tab_list = NULL;
|
||||
first_free_tab = 0;
|
||||
program_name = argv[0];
|
||||
|
||||
while ((c = getopt_long (argc, argv, "at:,0123456789", longopts, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case '?':
|
||||
usage (1);
|
||||
case 'a':
|
||||
convert_entire_line = 1;
|
||||
break;
|
||||
case 't':
|
||||
convert_entire_line = 1;
|
||||
parse_tabstops (optarg);
|
||||
break;
|
||||
case ',':
|
||||
add_tabstop (tabval);
|
||||
tabval = -1;
|
||||
break;
|
||||
default:
|
||||
if (tabval == -1)
|
||||
tabval = 0;
|
||||
tabval = tabval * 10 + c - '0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (show_version)
|
||||
{
|
||||
printf ("unexpand - %s\n", version_string);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (show_help)
|
||||
usage (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
|
||||
tab_size = 0;
|
||||
|
||||
if (optind == argc)
|
||||
file_list = stdin_argv;
|
||||
else
|
||||
file_list = &argv[optind];
|
||||
|
||||
unexpand ();
|
||||
|
||||
if (have_read_stdin && fclose (stdin) == EOF)
|
||||
error (1, errno, "-");
|
||||
if (fclose (stdout) == EOF)
|
||||
error (1, errno, _("write error"));
|
||||
exit (exit_status);
|
||||
if (tabval == -1)
|
||||
return;
|
||||
if (first_free_tab % TABLIST_BLOCK == 0)
|
||||
tab_list = (int *) xrealloc (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 (stops)
|
||||
char *stops;
|
||||
parse_tabstops (const char *stops)
|
||||
{
|
||||
int tabval = -1;
|
||||
|
||||
@@ -221,27 +148,11 @@ parse_tabstops (stops)
|
||||
add_tabstop (tabval);
|
||||
}
|
||||
|
||||
/* Add tab stop TABVAL to the end of `tab_list', except
|
||||
if TABVAL is -1, do nothing. */
|
||||
|
||||
static void
|
||||
add_tabstop (tabval)
|
||||
int tabval;
|
||||
{
|
||||
if (tabval == -1)
|
||||
return;
|
||||
if (first_free_tab % TABLIST_BLOCK == 0)
|
||||
tab_list = (int *) xrealloc (tab_list, first_free_tab + TABLIST_BLOCK);
|
||||
tab_list[first_free_tab++] = tabval;
|
||||
}
|
||||
|
||||
/* Check that the list of tabstops TABS, with ENTRIES entries,
|
||||
contains only nonzero, ascending values. */
|
||||
|
||||
static void
|
||||
validate_tabstops (tabs, entries)
|
||||
int *tabs;
|
||||
int entries;
|
||||
validate_tabstops (const int *tabs, int entries)
|
||||
{
|
||||
int prev_tab = 0;
|
||||
int i;
|
||||
@@ -256,11 +167,58 @@ validate_tabstops (tabs, entries)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 ()
|
||||
unexpand (void)
|
||||
{
|
||||
FILE *fp; /* Input stream. */
|
||||
int c; /* Each input character. */
|
||||
@@ -391,57 +349,8 @@ unexpand ()
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 (fp)
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
int status;
|
||||
usage (int status)
|
||||
{
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
@@ -467,3 +376,79 @@ Instead of -t NUMBER or -t LIST, -NUMBER or -LIST may be used.\n\
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
void
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int tabval = -1; /* Value of tabstop being read, or -1. */
|
||||
int c; /* Option character. */
|
||||
|
||||
have_read_stdin = 0;
|
||||
exit_status = 0;
|
||||
convert_entire_line = 0;
|
||||
tab_list = NULL;
|
||||
first_free_tab = 0;
|
||||
program_name = argv[0];
|
||||
|
||||
while ((c = getopt_long (argc, argv, "at:,0123456789", longopts, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case '?':
|
||||
usage (1);
|
||||
case 'a':
|
||||
convert_entire_line = 1;
|
||||
break;
|
||||
case 't':
|
||||
convert_entire_line = 1;
|
||||
parse_tabstops (optarg);
|
||||
break;
|
||||
case ',':
|
||||
add_tabstop (tabval);
|
||||
tabval = -1;
|
||||
break;
|
||||
default:
|
||||
if (tabval == -1)
|
||||
tabval = 0;
|
||||
tabval = tabval * 10 + c - '0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (show_version)
|
||||
{
|
||||
printf ("unexpand - %s\n", version_string);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (show_help)
|
||||
usage (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
|
||||
tab_size = 0;
|
||||
|
||||
if (optind == argc)
|
||||
file_list = stdin_argv;
|
||||
else
|
||||
file_list = &argv[optind];
|
||||
|
||||
unexpand ();
|
||||
|
||||
if (have_read_stdin && fclose (stdin) == EOF)
|
||||
error (1, errno, "-");
|
||||
if (fclose (stdout) == EOF)
|
||||
error (1, errno, _("write error"));
|
||||
exit (exit_status);
|
||||
}
|
||||
|
||||
368
src/uniq.c
368
src/uniq.c
@@ -34,12 +34,6 @@
|
||||
#undef min
|
||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
static char *find_field ();
|
||||
static int different ();
|
||||
static void check_file ();
|
||||
static void usage ();
|
||||
static void writeline ();
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
@@ -90,11 +84,183 @@ static struct option const longopts[] =
|
||||
{"version", no_argument, &show_version, 1},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static 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);
|
||||
printf (_("\
|
||||
Discard all but one of successive identical lines from INPUT (or\n\
|
||||
standard input), writing to OUTPUT (or standard output).\n\
|
||||
\n\
|
||||
-c, --count prefix lines by the number of occurrences\n\
|
||||
-d, --repeated only print duplicate lines\n\
|
||||
-f, --skip-fields=N avoid comparing the N first fields\n\
|
||||
-s, --skip-chars=N avoid comparing the N first characters\n\
|
||||
-u, --unique only print unique lines\n\
|
||||
-w, --check-chars=N compare no more than N characters in lines\n\
|
||||
-N same as -f N\n\
|
||||
+N same as -s N\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
\n\
|
||||
A field is a run of whitespace, than non-whitespace characters.\n\
|
||||
Fields are skipped before chars. \n\
|
||||
"));
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
/* 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 int count;
|
||||
register char *lp = line->buffer;
|
||||
register int size = line->length;
|
||||
register int 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 (const char *old, const char *new, int oldlen, int newlen)
|
||||
{
|
||||
register int order;
|
||||
|
||||
if (check_chars)
|
||||
{
|
||||
if (oldlen > check_chars)
|
||||
oldlen = check_chars;
|
||||
if (newlen > check_chars)
|
||||
newlen = check_chars;
|
||||
}
|
||||
order = memcmp (old, new, min (oldlen, newlen));
|
||||
if (order == 0)
|
||||
return oldlen - newlen;
|
||||
return order;
|
||||
}
|
||||
|
||||
/* 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))
|
||||
return;
|
||||
|
||||
if (countmode == count_occurrences)
|
||||
fprintf (stream, "%7d\t", linecount + 1);
|
||||
|
||||
fwrite (line->buffer, sizeof (char), line->length, stream);
|
||||
putc ('\n', 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, *exch;
|
||||
char *prevfield, *thisfield;
|
||||
int prevlen, thislen;
|
||||
int match_count = 0;
|
||||
|
||||
if (!strcmp (infile, "-"))
|
||||
istream = stdin;
|
||||
else
|
||||
istream = fopen (infile, "r");
|
||||
if (istream == NULL)
|
||||
error (1, errno, "%s", infile);
|
||||
|
||||
if (!strcmp (outfile, "-"))
|
||||
ostream = stdout;
|
||||
else
|
||||
ostream = fopen (outfile, "w");
|
||||
if (ostream == NULL)
|
||||
error (1, errno, "%s", outfile);
|
||||
|
||||
thisline = &lb1;
|
||||
prevline = &lb2;
|
||||
|
||||
initbuffer (thisline);
|
||||
initbuffer (prevline);
|
||||
|
||||
if (readline (prevline, istream) == 0)
|
||||
goto closefiles;
|
||||
prevfield = find_field (prevline);
|
||||
prevlen = prevline->length - (prevfield - prevline->buffer);
|
||||
|
||||
while (!feof (istream))
|
||||
{
|
||||
if (readline (thisline, istream) == 0)
|
||||
break;
|
||||
thisfield = find_field (thisline);
|
||||
thislen = thisline->length - (thisfield - thisline->buffer);
|
||||
if (!different (thisfield, prevfield, thislen, prevlen))
|
||||
match_count++;
|
||||
else
|
||||
{
|
||||
writeline (prevline, ostream, match_count);
|
||||
match_count = 0;
|
||||
|
||||
exch = prevline;
|
||||
prevline = thisline;
|
||||
thisline = exch;
|
||||
prevfield = thisfield;
|
||||
prevlen = thislen;
|
||||
}
|
||||
}
|
||||
|
||||
writeline (prevline, ostream, match_count);
|
||||
|
||||
closefiles:
|
||||
if (ferror (istream) || fclose (istream) == EOF)
|
||||
error (1, errno, _("error reading %s"), infile);
|
||||
|
||||
if (ferror (ostream) || fclose (ostream) == EOF)
|
||||
error (1, errno, _("error writing %s"), outfile);
|
||||
|
||||
free (lb1.buffer);
|
||||
free (lb2.buffer);
|
||||
}
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int optc;
|
||||
char *infile = "-", *outfile = "-";
|
||||
@@ -186,187 +352,3 @@ main (argc, argv)
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
/* Process input file INFILE with output to OUTFILE.
|
||||
If either is "-", use the standard I/O stream for it instead. */
|
||||
|
||||
static void
|
||||
check_file (infile, outfile)
|
||||
char *infile, *outfile;
|
||||
{
|
||||
FILE *istream;
|
||||
FILE *ostream;
|
||||
struct linebuffer lb1, lb2;
|
||||
struct linebuffer *thisline, *prevline, *exch;
|
||||
char *prevfield, *thisfield;
|
||||
int prevlen, thislen;
|
||||
int match_count = 0;
|
||||
|
||||
if (!strcmp (infile, "-"))
|
||||
istream = stdin;
|
||||
else
|
||||
istream = fopen (infile, "r");
|
||||
if (istream == NULL)
|
||||
error (1, errno, "%s", infile);
|
||||
|
||||
if (!strcmp (outfile, "-"))
|
||||
ostream = stdout;
|
||||
else
|
||||
ostream = fopen (outfile, "w");
|
||||
if (ostream == NULL)
|
||||
error (1, errno, "%s", outfile);
|
||||
|
||||
thisline = &lb1;
|
||||
prevline = &lb2;
|
||||
|
||||
initbuffer (thisline);
|
||||
initbuffer (prevline);
|
||||
|
||||
if (readline (prevline, istream) == 0)
|
||||
goto closefiles;
|
||||
prevfield = find_field (prevline);
|
||||
prevlen = prevline->length - (prevfield - prevline->buffer);
|
||||
|
||||
while (!feof (istream))
|
||||
{
|
||||
if (readline (thisline, istream) == 0)
|
||||
break;
|
||||
thisfield = find_field (thisline);
|
||||
thislen = thisline->length - (thisfield - thisline->buffer);
|
||||
if (!different (thisfield, prevfield, thislen, prevlen))
|
||||
match_count++;
|
||||
else
|
||||
{
|
||||
writeline (prevline, ostream, match_count);
|
||||
match_count = 0;
|
||||
|
||||
exch = prevline;
|
||||
prevline = thisline;
|
||||
thisline = exch;
|
||||
prevfield = thisfield;
|
||||
prevlen = thislen;
|
||||
}
|
||||
}
|
||||
|
||||
writeline (prevline, ostream, match_count);
|
||||
|
||||
closefiles:
|
||||
if (ferror (istream) || fclose (istream) == EOF)
|
||||
error (1, errno, _("error reading %s"), infile);
|
||||
|
||||
if (ferror (ostream) || fclose (ostream) == EOF)
|
||||
error (1, errno, _("error writing %s"), outfile);
|
||||
|
||||
free (lb1.buffer);
|
||||
free (lb2.buffer);
|
||||
}
|
||||
|
||||
/* Given a linebuffer LINE,
|
||||
return a pointer to the beginning of the line's field to be compared. */
|
||||
|
||||
static char *
|
||||
find_field (line)
|
||||
struct linebuffer *line;
|
||||
{
|
||||
register int count;
|
||||
register char *lp = line->buffer;
|
||||
register int size = line->length;
|
||||
register int 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 (old, new, oldlen, newlen)
|
||||
char *old;
|
||||
char *new;
|
||||
int oldlen;
|
||||
int newlen;
|
||||
{
|
||||
register int order;
|
||||
|
||||
if (check_chars)
|
||||
{
|
||||
if (oldlen > check_chars)
|
||||
oldlen = check_chars;
|
||||
if (newlen > check_chars)
|
||||
newlen = check_chars;
|
||||
}
|
||||
order = memcmp (old, new, min (oldlen, newlen));
|
||||
if (order == 0)
|
||||
return oldlen - newlen;
|
||||
return order;
|
||||
}
|
||||
|
||||
/* 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 (line, stream, linecount)
|
||||
struct linebuffer *line;
|
||||
FILE *stream;
|
||||
int linecount;
|
||||
{
|
||||
if ((mode == output_unique && linecount != 0)
|
||||
|| (mode == output_repeated && linecount == 0))
|
||||
return;
|
||||
|
||||
if (countmode == count_occurrences)
|
||||
fprintf (stream, "%7d\t", linecount + 1);
|
||||
|
||||
fwrite (line->buffer, sizeof (char), line->length, stream);
|
||||
putc ('\n', stream);
|
||||
}
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
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);
|
||||
printf (_("\
|
||||
Discard all but one of successive identical lines from INPUT (or\n\
|
||||
standard input), writing to OUTPUT (or standard output).\n\
|
||||
\n\
|
||||
-c, --count prefix lines by the number of occurrences\n\
|
||||
-d, --repeated only print duplicate lines\n\
|
||||
-f, --skip-fields=N avoid comparing the N first fields\n\
|
||||
-s, --skip-chars=N avoid comparing the N first characters\n\
|
||||
-u, --unique only print unique lines\n\
|
||||
-w, --check-chars=N compare no more than N characters in lines\n\
|
||||
-N same as -f N\n\
|
||||
+N same as -s N\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
\n\
|
||||
A field is a run of whitespace, than non-whitespace characters.\n\
|
||||
Fields are skipped before chars. \n\
|
||||
"));
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
217
src/wc.c
217
src/wc.c
@@ -32,10 +32,6 @@
|
||||
|
||||
int safe_read ();
|
||||
|
||||
static void wc ();
|
||||
static void wc_file ();
|
||||
static void write_counts ();
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
@@ -69,8 +65,7 @@ static struct option const longopts[] =
|
||||
};
|
||||
|
||||
static void
|
||||
usage (status)
|
||||
int status;
|
||||
usage (int status)
|
||||
{
|
||||
if (status != 0)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
@@ -95,106 +90,31 @@ read standard input.\n\
|
||||
exit (status);
|
||||
}
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
static void
|
||||
write_counts (long unsigned int lines, long unsigned int words,
|
||||
long unsigned int chars, const char *file)
|
||||
{
|
||||
int optc;
|
||||
int nfiles;
|
||||
|
||||
program_name = argv[0];
|
||||
exit_status = 0;
|
||||
print_lines = print_words = print_chars = 0;
|
||||
total_lines = total_words = total_chars = 0;
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "clw", longopts, (int *) 0)) != EOF)
|
||||
switch (optc)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
print_chars = 1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
print_lines = 1;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
print_words = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage (1);
|
||||
}
|
||||
|
||||
if (show_version)
|
||||
if (print_lines)
|
||||
printf ("%7lu", lines);
|
||||
if (print_words)
|
||||
{
|
||||
printf ("wc - %s\n", version_string);
|
||||
exit (0);
|
||||
if (print_lines)
|
||||
putchar (' ');
|
||||
printf ("%7lu", words);
|
||||
}
|
||||
|
||||
if (show_help)
|
||||
usage (0);
|
||||
|
||||
if (print_lines + print_words + print_chars == 0)
|
||||
print_lines = print_words = print_chars = 1;
|
||||
|
||||
nfiles = argc - optind;
|
||||
|
||||
if (nfiles == 0)
|
||||
if (print_chars)
|
||||
{
|
||||
have_read_stdin = 1;
|
||||
wc (0, "");
|
||||
if (print_lines || print_words)
|
||||
putchar (' ');
|
||||
printf ("%7lu", chars);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; optind < argc; ++optind)
|
||||
wc_file (argv[optind]);
|
||||
|
||||
if (nfiles > 1)
|
||||
write_counts (total_lines, total_words, total_chars, _("total"));
|
||||
}
|
||||
|
||||
if (have_read_stdin && close (0))
|
||||
error (1, errno, "-");
|
||||
|
||||
exit (exit_status);
|
||||
if (*file)
|
||||
printf (" %s", file);
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
static void
|
||||
wc_file (file)
|
||||
char *file;
|
||||
{
|
||||
if (!strcmp (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wc (fd, file)
|
||||
int fd;
|
||||
char *file;
|
||||
wc (int fd, const char *file)
|
||||
{
|
||||
char buf[BUFFER_SIZE + 1];
|
||||
register int bytes_read;
|
||||
@@ -309,25 +229,94 @@ wc (fd, file)
|
||||
}
|
||||
|
||||
static void
|
||||
write_counts (lines, words, chars, file)
|
||||
unsigned long lines, words, chars;
|
||||
char *file;
|
||||
wc_file (const char *file)
|
||||
{
|
||||
if (print_lines)
|
||||
printf ("%7lu", lines);
|
||||
if (print_words)
|
||||
if (!strcmp (file, "-"))
|
||||
{
|
||||
if (print_lines)
|
||||
putchar (' ');
|
||||
printf ("%7lu", words);
|
||||
have_read_stdin = 1;
|
||||
wc (0, file);
|
||||
}
|
||||
if (print_chars)
|
||||
else
|
||||
{
|
||||
if (print_lines || print_words)
|
||||
putchar (' ');
|
||||
printf ("%7lu", chars);
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (*file)
|
||||
printf (" %s", file);
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
void
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int optc;
|
||||
int nfiles;
|
||||
|
||||
program_name = argv[0];
|
||||
exit_status = 0;
|
||||
print_lines = print_words = print_chars = 0;
|
||||
total_lines = total_words = total_chars = 0;
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "clw", longopts, (int *) 0)) != EOF)
|
||||
switch (optc)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
print_chars = 1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
print_lines = 1;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
print_words = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage (1);
|
||||
}
|
||||
|
||||
if (show_version)
|
||||
{
|
||||
printf ("wc - %s\n", version_string);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (show_help)
|
||||
usage (0);
|
||||
|
||||
if (print_lines + print_words + print_chars == 0)
|
||||
print_lines = print_words = print_chars = 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"));
|
||||
}
|
||||
|
||||
if (have_read_stdin && close (0))
|
||||
error (1, errno, "-");
|
||||
|
||||
exit (exit_status);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
t??.[12]
|
||||
t*.log
|
||||
t*.out
|
||||
t*.in
|
||||
t*.exp
|
||||
|
||||
@@ -43,5 +43,7 @@
|
||||
('6b', '-a1 -e -', "a 1\nb 2\nd 4\n", "a 21\nb 22\nc 23\nf 26\n", "a 1 21\nb 2 22\nd 4\n", 0);
|
||||
('6c', '-a1 -e -', "a 21\nb 22\nc 23\nf 26\n", "a 1\nb 2\nd 4\n", "a 21 1\nb 22 2\nc 23\nf 26\n", 0);
|
||||
|
||||
|
||||
('7a', '-a1 -e . -o 2.7', "a\nb\nc\n", "a x y\nb\nc\n", ".\n.\n.\n", 0);
|
||||
|
||||
('8a', '-a1 -e . -o 0,1.2', "a\nb\nc\nd G\n", "a x y\nb\nc\ne\n", "a .\nb .\nc .\nd G\n", 0);
|
||||
('8b', '-a1 -a2 -e . -o 0,1.2', "a\nb\nc\nd G\n", "a x y\nb\nc\ne\n", "a .\nb .\nc .\nd G\ne .\n", 0);
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
("u", "aabbaa", '-ds', 'b','a', "a", 0);
|
||||
("v", "ZZ0123456789acbdefABCDEFZZ", \
|
||||
'-ds', '[:xdigit:]','Z', "Z", 0);
|
||||
# Try some data with 8th bit set in case something is mistakenly sign-extended.
|
||||
# Try some data with 8th bit set in case something is mistakenly sign-extended.
|
||||
("w", "\300\301\377\345\345\350\345", \
|
||||
'-ds', '\350','\345', "\300\301\377\345", 0);
|
||||
("x", "abcdefghijklmnop", '-s', 'abcdefghijklmn','[:*016]', ":op", 0);
|
||||
@@ -61,3 +61,9 @@
|
||||
("B", "", '', 'a',"''", "", 1);
|
||||
("C", "abcxyzABCXYZ", '', '[:lower:]', '[:upper:]', "ABCXYZABCXYZ", 0);
|
||||
("D", "abcxyzABCXYZ", '', '[:upper:]', '[:lower:]', "abcxyzabcxyz", 0);
|
||||
|
||||
("E", "a=c", '', 'a[=*2][=c=]', 'xyyz', "xyz", 0);
|
||||
("F", ":1239", '', '[:*3][:digit:]', 'a-m', "cefgm", 0);
|
||||
("G", "abc", '', 'a[b*512]c', '1[x*]2', "1x2", 0);
|
||||
("H", "abc", '', 'a[b*513]c', '1[x*]2', "1x2", 0);
|
||||
("I", "abc-z", '', 'a\-z', 'A-Z', "AbcBC", 0);
|
||||
|
||||
Reference in New Issue
Block a user