[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
tail fixes for conformance to POSIX 1003.2-1992
From: |
Paul Eggert |
Subject: |
tail fixes for conformance to POSIX 1003.2-1992 |
Date: |
Fri, 10 Sep 2004 13:57:41 -0700 |
User-agent: |
Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3 (gnu/linux) |
The recent discussion in austin-review-l caused me to look again at
"tail", and I found that it didn't conform to POSIX 1003.2-1992
correctly in obscure cases like "tail - file". I installed this
patch.
2004-09-10 Paul Eggert <address@hidden>
* NEWS: "tail" now handles obscure POSIX 1003.2-1992 cases better.
* src/tail.c (parse_obsolete_option): Renamed from
parse_obsolescent_option, since the options are obsolete now.
Remove bool *arg; just exit if there's an error. Revamp to follow
POSIX 1003.2-1992 more precisely, to handle cases like "tail -
file" and "tail -10 -- file" correctly when we are conforming to
the older standard.
(main): Adjust to this change.
* tests/tail/Test.pm (test_vector): minus-* requires
_POSIX2_VERSION=199209 now, to work correctly if there is
an input file. err-1 and err-3 no longer errors if there
is another file.
Index: NEWS
===================================================================
RCS file: /home/eggert/coreutils/cu/NEWS,v
retrieving revision 1.233
diff -p -u -r1.233 NEWS
--- NEWS 9 Sep 2004 00:27:45 -0000 1.233
+++ NEWS 10 Sep 2004 20:52:35 -0000
@@ -98,6 +98,10 @@ GNU coreutils NEWS
"tail -f" no longer mishandles pipes and fifos. With no operands,
tail now ignores -f if standard input is a pipe, as POSIX requires.
+ When conforming to POSIX 1003.2-1992, tail now handles some obscure
+ cases more correctly, e.g., "tail +cl file" now reads the file "+cl"
+ rather than reporting an error, and "tail - file" no longer reads
+ standard input.
tee now exits when it gets a SIGPIPE signal, as POSIX requires.
To get tee's old behavior, use the shell command "(trap '' PIPE; tee)".
Index: src/tail.c
===================================================================
RCS file: /home/eggert/coreutils/cu/src/tail.c,v
retrieving revision 1.226
diff -p -u -r1.226 tail.c
--- src/tail.c 2 Aug 2004 22:20:24 -0000 1.226
+++ src/tail.c 10 Sep 2004 20:36:53 -0000
@@ -1359,147 +1359,107 @@ tail_file (struct File_spec *f, uintmax_
return ok;
}
-/* If the command line arguments are of the obsolescent form and the
- option string is well-formed, set *OK to true, set *N_UNITS, the
- globals COUNT_LINES, FOREVER, and FROM_START, and return true.
- Otherwise, if the command line arguments appear to be of the
- obsolescent form but the option string is malformed, set *OK to
- false, don't modify any other parameter or global variable, and
- return true. Otherwise, return false and don't modify any parameter
- or global variable. */
+/* If obsolete usage is allowed, and the command line arguments are of
+ the obsolete form and the option string is well-formed, set
+ *N_UNITS, the globals COUNT_LINES, FOREVER, and FROM_START, and
+ return true. If the command line arguments are obviously incorrect
+ (e.g., because obsolete usage is not allowed and the arguments are
+ incorrect for non-obsolete usage), report an error and exit.
+ Otherwise, return false and don't modify any parameter or global
+ variable. */
static bool
-parse_obsolescent_option (int argc, const char *const *argv,
- uintmax_t *n_units, bool *ok)
+parse_obsolete_option (int argc, char * const *argv, uintmax_t *n_units)
{
const char *p = argv[1];
- const char *n_string = NULL;
+ const char *n_string;
const char *n_string_end;
bool obsolete_usage;
-
bool t_from_start;
- bool t_count_lines;
- bool t_forever;
-
- /* With the obsolescent form, there is one option string and
- (technically) at most one file argument. But we allow two or more
- by default. */
- if (argc < 2)
+ bool t_count_lines = true;
+ bool t_forever = false;
+ int len;
+
+ /* With the obsolete form, there is one option string and
+ at most one file argument, possibly preceded by "--". */
+ if (! ((2 <= argc && argc <= 3) || (argc == 4 && STREQ (argv[2], "--"))))
return false;
obsolete_usage = (posix2_version () < 200112);
- /* If P starts with `+' and the POSIX version predates 1003.1-2001,
- or if P starts with `-N' (where N is a digit), or `-l', then it
- is obsolescent. Return false otherwise. */
- if (! ((p[0] == '+' && obsolete_usage)
- || (p[0] == '-' && (p[1] == 'l' || ISDIGIT (p[1])))))
- return false;
+ switch (*p++)
+ {
+ default:
+ return false;
- if (*p == '+')
- t_from_start = true;
- else if (*p == '-')
- t_from_start = false;
- else
- return false;
+ case '+':
+ /* Leading "+" is a file name in the non-obsolete form. */
+ if (!obsolete_usage)
+ return false;
+
+ t_from_start = true;
+ break;
+
+ case '-':
+ /* Plain "-" is standard input in the non-obsolete form. */
+ if (!obsolete_usage && !*p)
+ return false;
+
+ /* Plain "-c" is required to be the non-obsolete option. For
+ plain "-f" POSIX 1003.2-1992 is ambiguous; assume the
+ non-obsolete form. */
+ if ((p[0] == 'c' || p[0] == 'f') && !p[1])
+ return false;
- ++p;
- if (ISDIGIT (*p))
- {
- n_string = p;
- do
- {
- ++p;
- }
- while (ISDIGIT (*p));
+ t_from_start = false;
+ break;
}
+
+ n_string = p;
+ while (ISDIGIT (*p))
+ p++;
n_string_end = p;
- t_count_lines = true;
- if (*p == 'c' || *p == 'b')
+ switch (*p)
{
- t_count_lines = false;
- ++p;
- }
- else if (*p == 'l')
- {
- ++p;
+ case 'c': t_count_lines = false; /* Fall through. */
+ case 'l': p++; break;
}
- t_forever = false;
if (*p == 'f')
{
t_forever = true;
++p;
}
- if (*p != '\0')
- {
- /* If (argv[1] begins with a `+' or if it begins with `-' followed
- by a digit), but has an invalid suffix character, give a diagnostic
- and indicate to caller that this *is* of the obsolescent form,
- but that it's an invalid option. */
- if (t_from_start || n_string)
- {
- error (0, 0,
- _("%c: invalid suffix character in obsolescent option"), *p);
- *ok = false;
- return true;
- }
+ if (*p)
+ return false;
- /* Otherwise, it might be a valid non-obsolescent option like -n. */
- return false;
- }
+ len = n_string_end - n_string;
- *ok = true;
- if (n_string == NULL)
+ if (n_string == n_string_end)
*n_units = DEFAULT_N_LINES;
- else
- {
- strtol_error s_err;
- uintmax_t tmp;
- char *end;
-
- s_err = xstrtoumax (n_string, &end, 10, &tmp,
- *n_string_end == 'b' ? "b" : NULL);
- if (s_err == LONGINT_OK)
- *n_units = tmp;
- else
- {
- /* Extract a NUL-terminated string for the error message. */
- size_t len = n_string_end - n_string;
- char *n_string_tmp = xmalloc (len + 1);
+ else if (xstrtoumax (n_string, NULL, 10, n_units, NULL) != LONGINT_OK)
+ error (EXIT_FAILURE, 0, _("number `%.*s' too large"), len, n_string);
- strncpy (n_string_tmp, n_string, len);
- n_string_tmp[len] = '\0';
-
- error (0, 0,
- _("%s: %s is so large that it is not representable"),
- n_string_tmp, (t_count_lines
- ? _("number of lines")
- : _("number of bytes")));
- free (n_string_tmp);
- *ok = false;
- }
- }
-
- if (*ok)
+ if (!obsolete_usage)
{
- if (! obsolete_usage)
+ if (len == 0)
{
- int n_string_len = n_string_end - n_string;
- error (0, 0, _("`%s' option is obsolete; use `%s-%c %.*s'"),
- argv[1], t_forever ? " -f" : "", t_count_lines ? 'n' : 'c',
- n_string_len, n_string);
- usage (EXIT_FAILURE);
+ len = 2;
+ n_string = "10";
}
-
- /* Set globals. */
- from_start = t_from_start;
- count_lines = t_count_lines;
- forever = t_forever;
+ error (0, 0, _("`%s' option is obsolete; use `%s-%c %.*s'"),
+ argv[1], t_forever ? "-f " : "", t_count_lines ? 'n' : 'c',
+ len, n_string);
+ usage (EXIT_FAILURE);
}
+ /* Set globals. */
+ from_start = t_from_start;
+ count_lines = t_count_lines;
+ forever = t_forever;
+
return true;
}
@@ -1665,22 +1625,10 @@ main (int argc, char **argv)
have_read_stdin = false;
- {
- bool ok;
-
- if (parse_obsolescent_option (argc,
- (const char *const *) argv,
- &n_units, &ok))
- {
- if (!ok)
- exit (EXIT_FAILURE);
- optind = 2;
- }
- else
- {
- parse_options (argc, argv, &n_units, &header_mode, &sleep_interval);
- }
- }
+ if (parse_obsolete_option (argc, argv, &n_units))
+ optind = 2;
+ else
+ parse_options (argc, argv, &n_units, &header_mode, &sleep_interval);
/* To start printing with item N_UNITS from the start of the file, skip
N_UNITS - 1 items. `tail -n +0' is actually meaningless, but for Unix
Index: tests/tail/Test.pm
===================================================================
RCS file: /home/eggert/coreutils/cu/tests/tail/Test.pm,v
retrieving revision 1.12
diff -p -u -r1.12 Test.pm
--- tests/tail/Test.pm 22 Jul 2004 20:54:53 -0000 1.12
+++ tests/tail/Test.pm 10 Sep 2004 20:38:07 -0000
@@ -79,11 +79,13 @@ sub test_vector
{
my ($test_name, $flags, $in, $exp, $ret) = @$t;
- $test_name =~ /^(obs|err-[134])/
+ $test_name =~ /^(obs|err-[134]|minus-)/
and $Test::env{$test_name} = ['_POSIX2_VERSION=199209'];
# If you run the minus* tests with a FILE arg they'd hang.
- if ($test_name =~ /^minus/)
+ # If you run the err-1 or err-3 tests with a FILE, they'd misinterpret
+ # the arg unless we are using the obsolete form.
+ if ($test_name =~ /^(minus|err-[13])/)
{
$Test::input_via{$test_name} = {REDIR => 0, PIPE => 0};
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- tail fixes for conformance to POSIX 1003.2-1992,
Paul Eggert <=