]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
all: detect --help and --version more consistently
authorBernhard Voelker <mail@bernhard-voelker.de>
Mon, 26 Nov 2018 08:05:37 +0000 (09:05 +0100)
committerBernhard Voelker <mail@bernhard-voelker.de>
Sun, 24 Feb 2019 18:32:29 +0000 (19:32 +0100)
For select programs which accept only --help and --version options
(in addition to non-option arguments), process these options before
any other options.

Before:

  $ dd bs=1 --help
  dd: unrecognized option '--help'
  Try 'dd --help' for more information.

  $ yes me --help
  me --help
  me --help
  ...

After:
Any occurrence of '--help' in the arguments (prior to '--') will
show the help screen.

Discussed in https://bugs.gnu.org/33468 .

* NEWS: Mention change.
* src/cksum.c, src/dd.c, src/hostid.c, src/hostname.c, src/link.c,
src/logname.c, src/nohup.c, src/sleep.c, src/tsort.c, src/unlink.c,
src/uptime.c, src/users.c, src/whoami.c, src/yes.c (main): Replace
parse_long_options() + getopt_long() calls with
parse_gnu_standard_options_only(); Remove <getopt.h> inclusion;
Remove empty 'struct long_options' variable;
* tests/misc/help-version-getopt.sh: Add test.
* tests/local.mk (all_tests): Reference it.

17 files changed:
NEWS
src/cksum.c
src/dd.c
src/hostid.c
src/hostname.c
src/link.c
src/logname.c
src/nohup.c
src/sleep.c
src/tsort.c
src/unlink.c
src/uptime.c
src/users.c
src/whoami.c
src/yes.c
tests/local.mk
tests/misc/help-version-getopt.sh [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index e400554bbb41638588d222aabba005e05e79db43..5d9956854e59271ce382024108ac61df6b94cd95 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -37,6 +37,17 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 ** Changes in behavior
 
+  cksum, dd, hostid, hostname, link, logname, sleep, tsort, unlink,
+  uptime, users, whoami, yes: now always process --help and --version options,
+  regardless of any other arguments present before any optional '--'
+  end-of-options marker.
+
+  nohup: now process --help and --version as first options even if other
+  parameters follow.
+
+  'yes a -- b' now outputs 'a b' instead of including the end-of-options
+  marker as before: 'a -- b'.
+
   echo now always processes backslash escapes when the POSIXLY_CORRECT
   environment variable is set.
 
index 6974724edb952211a56ec2418676fe26b5dc5daa..c60510b4fc6fb5bcf445b76e3e3f024ad2d48a9a 100644 (file)
@@ -102,16 +102,10 @@ main (void)
 
 #else /* !CRCTAB */
 
-# include <getopt.h>
 # include "long-options.h"
 # include "die.h"
 # include "error.h"
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 /* Number of bytes to read at once.  */
 # define BUFLEN (1 << 16)
 
@@ -294,10 +288,8 @@ main (int argc, char **argv)
      so that processes running in parallel do not intersperse their output.  */
   setvbuf (stdout, NULL, _IOLBF, 0);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "", long_options, NULL) != -1)
-    usage (EXIT_FAILURE);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE, Version,
+                                   true, usage, AUTHORS, (char const *) NULL);
 
   have_read_stdin = false;
 
index 28611b3e6826800c6b9c47d586254896f5f4ded9..2888b8e33ce9993970fb733f8f0cc076d1463351 100644 (file)
--- a/src/dd.c
+++ b/src/dd.c
@@ -22,7 +22,6 @@
 
 #include <sys/types.h>
 #include <signal.h>
-#include <getopt.h>
 
 #include "system.h"
 #include "close-stream.h"
   proper_name ("David MacKenzie"), \
   proper_name ("Stuart Kemp")
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 /* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
    present.  */
 #ifndef SA_NOCLDSTOP
@@ -2396,13 +2390,10 @@ main (int argc, char **argv)
 
   page_size = getpagesize ();
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, Version,
-                      usage, AUTHORS, (char const *) NULL);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE, Version,
+                                   true, usage, AUTHORS, (char const *) NULL);
   close_stdout_required = false;
 
-  if (getopt_long (argc, argv, "", long_options, NULL) != -1)
-    usage (EXIT_FAILURE);
-
   /* Initialize translation table to identity translation. */
   for (i = 0; i < 256; i++)
     trans_table[i] = i;
index 06b05b9c357e2186d9e209e60ad1dc1d798ea8f5..a80fe21264c72adbee368884d9f9b8fe4ea2b702 100644 (file)
@@ -18,7 +18,6 @@
 /* Written by Jim Meyering.  */
 
 #include <config.h>
-#include <getopt.h>
 #include <stdio.h>
 #include <sys/types.h>
 
 
 #define AUTHORS proper_name ("Jim Meyering")
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 void
 usage (int status)
 {
@@ -69,10 +63,9 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "", long_options, NULL) != -1)
-    usage (EXIT_FAILURE);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE_NAME,
+                                   Version, true, usage, AUTHORS,
+                                   (char const *) NULL);
 
   if (optind < argc)
     {
index b23df32b184a3c60d77eb307db791ef22ba56706..4d9574be08f86728d23c4fb531d32726a1f383a2 100644 (file)
@@ -17,7 +17,6 @@
 /* Written by Jim Meyering.  */
 
 #include <config.h>
-#include <getopt.h>
 #include <stdio.h>
 #include <sys/types.h>
 
 
 #define AUTHORS proper_name ("Jim Meyering")
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 #if !defined HAVE_SETHOSTNAME && defined HAVE_SYSINFO && \
      defined HAVE_SYS_SYSTEMINFO_H
 # include <sys/systeminfo.h>
@@ -86,10 +80,9 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "", long_options, NULL) != -1)
-    usage (EXIT_FAILURE);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE_NAME,
+                                   Version, true, usage, AUTHORS,
+                                   (char const *) NULL);
 
   if (argc == optind + 1)
     {
index 84b916be2721c2c5def5b96a71caa6bf81aa6973..7f8d158af00f6ffa901d4f81b84e6508d0371a92 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <config.h>
 #include <stdio.h>
-#include <getopt.h>
 #include <sys/types.h>
 
 #include "system.h"
 
 #define AUTHORS proper_name ("Michael Stone")
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 void
 usage (int status)
 {
@@ -72,10 +66,9 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "", long_options, NULL) != -1)
-    usage (EXIT_FAILURE);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE_NAME,
+                                   Version, true, usage, AUTHORS,
+                                   (char const *) NULL);
 
   if (argc < optind + 2)
     {
index da97db864d285b4281135bee19e6a989d7bbb2b9..c6c665241ed00c648b82cba4f76fde911806ef40 100644 (file)
@@ -17,7 +17,6 @@
 #include <config.h>
 #include <stdio.h>
 #include <sys/types.h>
-#include <getopt.h>
 
 #include "system.h"
 #include "die.h"
 
 #define AUTHORS proper_name ("FIXME: unknown")
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 void
 usage (int status)
 {
@@ -67,10 +61,9 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "", long_options, NULL) != -1)
-    usage (EXIT_FAILURE);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE_NAME,
+                                   Version, true, usage, AUTHORS,
+                                   (char const *) NULL);
 
   if (optind < argc)
     {
index d5ee0f2df09fb94459d23e194b535085437711e4..53fdaf941af9c98a346627ecb1a820c573e330ea 100644 (file)
@@ -17,7 +17,6 @@
 /* Written by Jim Meyering  */
 
 #include <config.h>
-#include <getopt.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <signal.h>
 
 #define AUTHORS proper_name ("Jim Meyering")
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 /* Exit statuses.  */
 enum
   {
@@ -104,10 +98,9 @@ main (int argc, char **argv)
   initialize_exit_failure (exit_internal_failure);
   atexit (close_stdout);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "+", long_options, NULL) != -1)
-    usage (exit_internal_failure);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE_NAME,
+                                   Version, false, usage, AUTHORS,
+                                   (char const *) NULL);
 
   if (argc <= optind)
     {
index a634f1ae65f95518f76135e47aec850ebcebe20c..1c5f7c607aa9f1754df3dd92fb1d122310957dca 100644 (file)
@@ -17,7 +17,6 @@
 #include <config.h>
 #include <stdio.h>
 #include <sys/types.h>
-#include <getopt.h>
 
 #include "system.h"
 #include "cl-strtod.h"
   proper_name ("Jim Meyering"), \
   proper_name ("Paul Eggert")
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 void
 usage (int status)
 {
@@ -113,10 +107,9 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "", long_options, NULL) != -1)
-    usage (EXIT_FAILURE);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE_NAME,
+                                   Version, true, usage, AUTHORS,
+                                   (char const *) NULL);
 
   if (argc == 1)
     {
index 7db35503dadb98c0856bde22df1d42344b7abe7b..e3dd29acb1c67049e5d85d612df087e9da631551 100644 (file)
@@ -23,7 +23,6 @@
 #include <config.h>
 
 #include <assert.h>
-#include <getopt.h>
 #include <sys/types.h>
 
 #include "system.h"
 
 #define AUTHORS proper_name ("Mark Kettenis")
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 /* Token delimiters when reading from a file.  */
 #define DELIM " \t\n"
 
@@ -556,10 +550,9 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "", long_options, NULL) != -1)
-    usage (EXIT_FAILURE);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE_NAME,
+                                   Version, true, usage, AUTHORS,
+                                   (char const *) NULL);
 
   if (1 < argc - optind)
     {
index 6ee3d670a70c516e804c105ceaebb6a7e953728c..11b643096481cecd9a287c435475be123fc7307f 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <config.h>
 #include <stdio.h>
-#include <getopt.h>
 #include <sys/types.h>
 
 #include "system.h"
 
 #define AUTHORS proper_name ("Michael Stone")
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 void
 usage (int status)
 {
@@ -71,10 +65,9 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "", long_options, NULL) != -1)
-    usage (EXIT_FAILURE);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE_NAME,
+                                   Version, true, usage, AUTHORS,
+                                   (char const *) NULL);
 
   if (argc < optind + 1)
     {
index ff1e8796a9d11f483ff321f8da5e45cce1087073..c0869dbc4f939e65ea967b8ba840010e9009e40b 100644 (file)
@@ -17,7 +17,6 @@
 /* Created by hacking who.c by Kaveh Ghazi ghazi@caip.rutgers.edu.  */
 
 #include <config.h>
-#include <getopt.h>
 #include <stdio.h>
 
 #include <sys/types.h>
   proper_name ("David MacKenzie"), \
   proper_name ("Kaveh Ghazi")
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 static void
 print_uptime (size_t n, const STRUCT_UTMP *this)
 {
@@ -239,10 +233,9 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "", long_options, NULL) != -1)
-    usage (EXIT_FAILURE);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE_NAME,
+                                   Version, true, usage, AUTHORS,
+                                   (char const *) NULL);
 
   switch (argc - optind)
     {
index bf0706ca5344d7d694a7136246ef5dcf52abd307..749284aa8e65c87896b4764989e0a1d173aa7d84 100644 (file)
@@ -17,7 +17,6 @@
 /* Written by jla; revised by djm */
 
 #include <config.h>
-#include <getopt.h>
 #include <stdio.h>
 
 #include <sys/types.h>
   proper_name ("Joseph Arceneaux"), \
   proper_name ("David MacKenzie")
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 static int
 userid_compare (const void *v_a, const void *v_b)
 {
@@ -133,10 +127,9 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "", long_options, NULL) != -1)
-    usage (EXIT_FAILURE);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE_NAME,
+                                   Version, true, usage, AUTHORS,
+                                   (char const *) NULL);
 
   switch (argc - optind)
     {
index 65a360bb7a1de3c93f4276b8d44a130f3926d96e..19f7f03180806488df218fdb13eadd8395ab12ab 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <sys/types.h>
 #include <pwd.h>
-#include <getopt.h>
 
 #include "system.h"
 #include "die.h"
 
 #define AUTHORS proper_name ("Richard Mlynarik")
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 void
 usage (int status)
 {
@@ -75,10 +69,9 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "", long_options, NULL) != -1)
-    usage (EXIT_FAILURE);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE_NAME,
+                                   Version, true, usage, AUTHORS,
+                                   (char const *) NULL);
 
   if (optind != argc)
     {
index a808bb95317f6995900961c8453df004dcf0a7cd..0864186f98416b9b5a937309244fe350e6543572 100644 (file)
--- a/src/yes.c
+++ b/src/yes.c
@@ -19,7 +19,6 @@
 #include <config.h>
 #include <stdio.h>
 #include <sys/types.h>
-#include <getopt.h>
 
 #include "system.h"
 
 
 #define AUTHORS proper_name ("David MacKenzie")
 
-static struct option const long_options[] =
-{
-  {NULL, 0, NULL, 0}
-};
-
 void
 usage (int status)
 {
@@ -72,10 +66,9 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "+", long_options, NULL) != -1)
-    usage (EXIT_FAILURE);
+  parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE_NAME,
+                                   Version, true, usage, AUTHORS,
+                                   (char const *) NULL);
 
   char **operands = argv + optind;
   char **operand_lim = argv + argc;
index 4751886b2a318880534df329cf1162b5ccb8b819..bcb61edc7da7ccbe745f2acfd5d0e12166c54632 100644 (file)
@@ -163,6 +163,7 @@ check-root:
 
 all_tests =                                    \
   tests/misc/help-version.sh                   \
+  tests/misc/help-version-getopt.sh            \
   tests/tail-2/inotify-race.sh                 \
   tests/tail-2/inotify-race2.sh                        \
   tests/misc/invalid-opt.pl                    \
diff --git a/tests/misc/help-version-getopt.sh b/tests/misc/help-version-getopt.sh
new file mode 100755 (executable)
index 0000000..d15c9ce
--- /dev/null
@@ -0,0 +1,74 @@
+#!/bin/sh
+# Ensure --version and --help options are processed before
+# any other options by some programs.
+
+# Copyright (C) 2019 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ yes
+
+programs="cksum dd hostid hostname link logname nohup
+sleep tsort unlink uptime users whoami yes"
+
+# All these variations should show the help/version screen
+# regardless of their position on the command line arguments.
+for prog in $programs; do
+  # skip if the program is not built (e.g., hostname)
+  case " $built_programs " in
+  *" $prog "*) ;;
+  *) continue;;
+  esac
+
+  for opt in --help --version; do
+    rm -f exp out1 out2 out3 || framework_failure_
+
+    # Get the reference output
+    env $prog $opt >exp || fail=1
+
+    # Test: some other argument AFTER --help/--version.
+    env $prog $opt AFTER > out1 || fail=1
+    compare exp out1 || fail=1
+
+    # nohup is an exception: stops processing after first non-option parameter.
+    # E.g., "nohup df --help" should run "df --help", not "df --help".
+    if [ "$prog" = nohup ]; then
+      rm -f exp  || framework_failure_
+      df $opt > exp || framework_failure_
+      BEFORE=df
+    else
+      BEFORE=BEFORE
+    fi
+
+    # Test: some other argument BEFORE --help/--version.
+    env $prog $BEFORE $opt > out2 || fail=1
+    compare exp out2 || fail=1
+
+    # Test: some other arguments BEFORE and AFTER --help/--version.
+    env $prog $BEFORE $opt AFTER > out3 || fail=1
+    compare exp out3 || fail=1
+  done
+done
+
+# After end-of-options marker (--), the options should not be parsed.
+# Test with 'yes', and assume the common code will work the
+# same for the other programs.
+cat >exp <<\EOF || framework_failure_
+--help
+EOF
+env yes -- --help | head -n1 > out
+compare exp out || fail=1
+
+Exit $fail