coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Priority of --help


From: Bernhard Voelker
Subject: Re: Priority of --help
Date: Wed, 21 Oct 2015 16:03:40 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.3.0

On 10/21/2015 02:56 PM, Eric Blake wrote:
On the libvirt list, the question was raised on what happens if you have
a long command line, but then forget the arguments of an option that
requires an argument, so you try to add --help in-place to learn them.
For example:

$ ls --block-size --help
ls: invalid --block-size argument '--help'

Okay, this makes sense, '--help' is appearing in the argument position,
not as an option, so it got eaten by --block-size, and we don't get
help.  So let's try again, by placing a filler for the option argument,
then our real --help attempt; and since --help is idempotent, it doesn't
matter how often it appears up front, so let's use --help as the filler:

$ ls --block-size --help --help
ls: invalid --block-size argument '--help'

Bummer. --block-size is being parsed so early that it overrides all
later options.

I mentioned on the libvirt list that use of '--help --help' is a nice
trick for getting help at more points in a command line, but which only
works for programs where option parsing cannot cause failure unless all
options have been parsed first (that is, where option parsing is a
two-pass operation, one to collect arguments and give priority to
--help, and a second to act on the collected arguments).  Libvirt
happens to be an example of this:

$ virsh migrate --copy-storage-all --migrate-disks --help
error: command 'migrate' requires <domain> option
error: command 'migrate' requires <desturi> option
$ virsh migrate --copy-storage-all --migrate-disks --help --help \
    | head -n2
   NAME
     migrate - migrate domain to another host


In the name of a better user experience, should we audit all coreutils
to find places where we have early exits during option parsing, and fix
them to be a two-pass parse so that 'program --option-that-takes-arg
--help --help' universally prints help (from the second --help that
landed in the option position) rather than complaining about the first
--help being an invalid argument to the option?


One approach would be to have another first-pass getopt_long()
loop for searching --help only:

  $ src/chmod-OLD --reference --help
  src/chmod-OLD: missing operand
  Try 'src/chmod-OLD --help' for more information.

  $ src/chmod --reference --help | head -n3
  src/chmod: unrecognized option '--reference'
  Usage: src/chmod [OPTION]... MODE[,MODE]... FILE...
    or:  src/chmod [OPTION]... OCTAL-MODE FILE...
    or:  src/chmod [OPTION]... --reference=RFILE FILE...

Down below's the diff.
However, I'm not sure if it's worth adding to all utils.

Have a nice day,
Berny

diff --git a/src/chmod.c b/src/chmod.c
index 5c6881c..bdcf4f0 100644
--- a/src/chmod.c
+++ b/src/chmod.c
@@ -92,6 +92,12 @@ enum
   REFERENCE_FILE_OPTION
 };

+static struct option const long_options_help[] =
+{
+  {GETOPT_HELP_OPTION_DECL},
+  {NULL, 0, NULL, 0}
+};
+
 static struct option const long_options[] =
 {
   {"changes", no_argument, NULL, 'c'},
@@ -102,7 +108,6 @@ static struct option const long_options[] =
   {"reference", required_argument, NULL, REFERENCE_FILE_OPTION},
   {"silent", no_argument, NULL, 'f'},
   {"verbose", no_argument, NULL, 'v'},
-  {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
 };
@@ -432,6 +437,15 @@ main (int argc, char **argv)

   recurse = force_silent = diagnose_surprises = false;

+  while ((c = getopt_long (argc, argv, (""), long_options_help, NULL)) != -1)
+    {
+      switch (c)
+        {
+        case_GETOPT_HELP_CHAR;
+        }
+    }
+  optind = 1;
+
   while ((c = getopt_long (argc, argv,
                            ("Rcfvr::w::x::X::s::t::u::g::o::a::,::+::=::"
                             "0::1::2::3::4::5::6::7::"),
@@ -502,7 +516,6 @@ main (int argc, char **argv)
         case 'v':
           verbosity = V_high;
           break;
-        case_GETOPT_HELP_CHAR;
         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
         default:
           usage (EXIT_FAILURE);




reply via email to

[Prev in Thread] Current Thread [Next in Thread]