contains a list of NUL-separated file names.
* src/wc.c: Include "readtokens.h".
(usage): Describe the new option, and adjust the `Usage':
with this option, no FILE may be specified on the command line.
(main): Handle the new option.
* tests/misc/wc-files0: New tests, for the above.
* tests/misc/wc-files0-from: Likewise.
* tests/misc/Makefile.am (TESTS): Add wc-files0.
+2006-06-25 Jim Meyering <jim@meyering.net>
+
+ * NEWS: wc accepts a new option --files0-from=FILE, where FILE
+ contains a list of NUL-separated file names.
+
+ * src/wc.c: Include "readtokens.h".
+ (usage): Describe the new option, and adjust the `Usage':
+ with this option, no FILE may be specified on the command line.
+ (main): Handle the new option.
+ * tests/misc/wc-files0: New tests, for the above.
+ * tests/misc/wc-files0-from: Likewise.
+ * tests/misc/Makefile.am (TESTS): Add wc-files0.
+
2006-06-24 Jim Meyering <jim@meyering.net>
* src/md5sum.c (DIGEST_BUFFER): Remove now-unused definitions.
sort now accepts the --random-sort (-R) option and `R' ordering option.
+ wc accepts a new option --files0-from=FILE, where FILE contains a
+ list of NUL-terminated file names.
+
** Bug fixes
cat with any of the options, -A -v -e -E -T, when applied to a
tail -f once again works on a file with the append-only
attribute (affects at least Linux ext2, ext3, xfs file systems)
+* Major changes in release 5.97 (2006-06-24) [stable]
+* Major changes in release 5.96 (2006-05-22) [stable]
+* Major changes in release 5.95 (2006-05-12) [stable]
* Major changes in release 5.94 (2006-02-13) [stable]
-[see branch for details]
+[see the b5_9x branch for details]
* Major changes in release 5.93 (2005-11-06) [stable]
/* wc - print the number of lines, words, and bytes in files
- Copyright (C) 85, 91, 1995-2005 Free Software Foundation, Inc.
+ Copyright (C) 85, 91, 1995-2006 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
#include "error.h"
#include "inttostr.h"
+#include "quote.h"
+#include "readtokens0.h"
#include "safe-read.h"
#ifndef HAVE_DECL_WCWIDTH
struct stat st;
};
+/* For long options that have no equivalent short option, use a
+ non-character as a pseudo short option, starting with CHAR_MAX + 1. */
+enum
+{
+ FILES0_FROM_OPTION = CHAR_MAX + 1
+};
static struct option const longopts[] =
{
{"chars", no_argument, NULL, 'm'},
{"lines", no_argument, NULL, 'l'},
{"words", no_argument, NULL, 'w'},
+ {"files0-from", required_argument, NULL, FILES0_FROM_OPTION},
{"max-line-length", no_argument, NULL, 'L'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{
printf (_("\
Usage: %s [OPTION]... [FILE]...\n\
+ or: %s [OPTION]... --files0-from=F\n\
"),
- program_name);
+ program_name, program_name);
fputs (_("\
Print newline, word, and byte counts for each FILE, and a total line if\n\
more than one FILE is specified. With no FILE, or when FILE is -,\n\
-l, --lines print the newline counts\n\
"), stdout);
fputs (_("\
+ --files0-from=F read input from the files specified by\n\
+ NUL-terminated names in file F\n\
-L, --max-line-length print the length of the longest line\n\
-w, --words print the word counts\n\
"), stdout);
bool ok;
int optc;
int nfiles;
+ char **files;
+ char *files_from = NULL;
struct fstatus *fstatus;
+ struct Tokens tok;
initialize_main (&argc, &argv);
program_name = argv[0];
print_linelength = true;
break;
+ case FILES0_FROM_OPTION:
+ files_from = optarg;
+ break;
+
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
| print_linelength))
print_lines = print_words = print_bytes = true;
- nfiles = argc - optind;
- nfiles += (nfiles == 0);
+ if (files_from)
+ {
+ FILE *stream;
+
+ /* When using --files0-from=F, you may not specify any files
+ on the command-line. */
+ if (optind < argc)
+ {
+ error (0, 0, _("extra operand %s"), quote (argv[optind]));
+ fprintf (stderr, "%s\n",
+ _("File operands cannot be combined with --files0-from."));
+ usage (EXIT_FAILURE);
+ }
+
+ if (STREQ (files_from, "-"))
+ stream = stdin;
+ else
+ {
+ stream = fopen (files_from, "r");
+ if (stream == NULL)
+ error (EXIT_FAILURE, errno, _("cannot open %s for reading"),
+ quote (files_from));
+ }
- fstatus = get_input_fstatus (nfiles, argv + optind);
+ readtokens0_init (&tok);
+
+ if (! readtokens0 (stream, &tok) || fclose (stream) != 0)
+ error (EXIT_FAILURE, 0, _("cannot read file names from %s"),
+ quote (files_from));
+
+ files = tok.tok;
+ nfiles = tok.n_tok;
+ }
+ else
+ {
+ static char *stdin_only[2];
+ files = (optind < argc ? argv + optind : stdin_only);
+ nfiles = (optind < argc ? argc - optind : 1);
+ stdin_only[0] = NULL;
+ }
+
+ fstatus = get_input_fstatus (nfiles, files);
number_width = compute_number_width (nfiles, fstatus);
ok = true;
for (i = 0; i < nfiles; i++)
- ok &= wc_file (argv[optind + i], &fstatus[i]);
+ {
+ if (files_from && STREQ (files_from, "-") && STREQ (files[i], "-"))
+ {
+ ok = false;
+ error (0, 0,
+ _("when reading file names from stdin, "
+ "no file name of %s allowed"),
+ quote ("-"));
+ continue;
+ }
+ ok &= wc_file (files[i], &fstatus[i]);
+ }
if (1 < nfiles)
write_counts (total_lines, total_words, total_chars, total_bytes,
# will execute the test script rather than the standard utility.
TESTS = \
+ wc-files0-from \
+ wc-files0 \
cat-proc \
base64 \
basename \
--- /dev/null
+#!/bin/sh
+# Show that wc's new --files0-from option works.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ wc --version
+fi
+
+. $srcdir/../lang-default
+
+pwd=`pwd`
+t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
+trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0
+trap '(exit $?); exit $?' 1 2 13 15
+
+framework_failure=0
+mkdir -p $tmp || framework_failure=1
+cd $tmp || framework_failure=1
+
+echo 2 > 2b || framework_failure=1
+echo 2 words > 2w || framework_failure=1
+printf '2b\n2w\n' |tr '\n' '\0' > names || framework_failure=1
+
+if test $framework_failure = 1; then
+ echo "$0: failure in testing framework" 1>&2
+ (exit 1); exit 1
+fi
+
+fail=0
+
+wc --files0-from=names > out || fail=1
+cat <<\EOF > exp || fail=1
+ 1 1 2 2b
+ 1 2 8 2w
+ 2 3 10 total
+EOF
+
+cmp out exp || fail=1
+test $fail = 1 && diff out exp 2> /dev/null
+
+if test "$fail" = ''; then
+ # Repeat the above test, but read the file name list from stdin.
+ rm -f out
+ wc --files0-from=- < names > out || fail=1
+ cmp out exp || fail=1
+ test $fail = 1 && diff out exp 2> /dev/null
+fi
+
+(exit $fail); exit $fail
--- /dev/null
+#!/bin/sh
+# -*- perl -*-
+# Exercise wc's --files0-from option.
+# This file bears a striking resemblance to tests/du/files0-from.
+
+: ${PERL=perl}
+: ${srcdir=.}
+
+. $srcdir/../envvar-check
+
+$PERL -e 1 > /dev/null 2>&1 || {
+ echo 1>&2 "$0: configure didn't find a usable version of Perl," \
+ "so can't run this test"
+ exit 77
+}
+
+exec $PERL -w -I$srcdir/.. -MCoreutils -- - <<\EOF
+#/
+require 5.003;
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+$ENV{PROG} = 'wc';
+my $ME = $ENV{PROG};
+
+# Turn off localization of executable's ouput.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ # invalid extra command line argument
+ ['f-extra-arg', '--files0-from=- no-such', {IN=>"a"}, {EXIT=>1},
+ {ERR => "$ME: extra operand `no-such'\n"
+ . "File operands cannot be combined with --files0-from.\n"
+ . "Try `$ME --help' for more information.\n"}
+ ],
+
+ # missing input file
+ ['missing', '--files0-from=missing', {EXIT=>1},
+ {ERR => "$ME: cannot open `missing' for reading: "
+ . "No such file or directory\n"}],
+
+ # empty input
+ ['empty', '--files0-from=-'],
+
+ # empty input, from non-regular file
+ ['empty-nonreg', '--files0-from=/dev/null'],
+
+ # one NUL
+ ['nul-1', '--files0-from=-', '<', {IN=>"\0"}, {EXIT=>1},
+ {ERR => "$ME: : No such file or directory\n"}],
+
+ # two NULs
+ ['nul-2', '--files0-from=-', '<', {IN=>"\0\0"}, {EXIT=>1},
+ {OUT=>"0 0 0 total\n"},
+ {ERR => "$ME: : No such file or directory\n"
+ . "$ME: : No such file or directory\n"}],
+
+ # one file name, no NUL
+ ['1', '--files0-from=-', '<',
+ {IN=>{f=>"g"}}, {AUX=>{g=>''}}, {OUT=>"0 0 0 g\n"} ],
+
+ # one file name, with NUL
+ ['1a', '--files0-from=-', '<',
+ {IN=>{f=>"g\0"}}, {AUX=>{g=>''}}, {OUT=>"0 0 0 g\n"} ],
+
+ # two file names, no final NUL
+ ['2', '--files0-from=-', '<',
+ {IN=>{f=>"g\0g"}}, {AUX=>{g=>''}},
+ {OUT=>"0 0 0 g\n0 0 0 g\n0 0 0 total\n"} ],
+
+ # two file names, with final NUL
+ ['2a', '--files0-from=-', '<',
+ {IN=>{f=>"g\0g\0"}}, {AUX=>{g=>''}},
+ {OUT=>"0 0 0 g\n0 0 0 g\n0 0 0 total\n"} ],
+
+ # Ensure that wc processes FILEs following a zero-length name.
+ ['zero-len', '--files0-from=-', '<',
+ {IN=>{f=>"\0g\0"}}, {AUX=>{g=>''}},
+ {OUT=>"0 0 0 g\n0 0 0 total\n"},
+ {ERR => "$ME: : No such file or directory\n"}, {EXIT=>1} ],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = $ENV{PROG} || die "$0: \$PROG not specified in environment\n";
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
+EOF