changeset 14827:5e5b5b8d3078

getopt: for ambiguous options, enumerate the possibilities. * lib/getopt.c (_getopt_internal_r): Merge glibc change printing the ambiguous options when an ambiguous prefix is given. This was http://sourceware.org/bugzilla/show_bug.cgi?id=7101. The merged glibc change was http://sourceware.org/git/?p=glibc.git;a=commit;h=bd25564e1e98910ed69043ed6a6f884ce60e5780.
author James Youngman <jay@gnu.org>
date Thu, 26 May 2011 01:45:13 +0100
parents a57aca916cfd
children 90514fe74451
files ChangeLog lib/getopt.c
diffstat 2 files changed, 76 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2011-05-15  James Youngman  <jay@gnu.org>
+
+	getopt: for ambiguous options, enumerate the possibilities.
+	* lib/getopt.c (_getopt_internal_r): Merge glibc change printing
+	the ambiguous options when an ambiguous prefix is given. This was
+	http://sourceware.org/bugzilla/show_bug.cgi?id=7101.  The merged
+	glibc change was
+	http://sourceware.org/git/?p=glibc.git;a=commit;h=bd25564e1e98910ed69043ed6a6f884ce60e5780.
+
 2011-05-25  Eric Blake  <eblake@redhat.com>
 
 	getcwd: work around mingw bug
--- a/lib/getopt.c
+++ b/lib/getopt.c
@@ -479,8 +479,14 @@
                             || !strchr (optstring, argv[d->optind][1])))))
     {
       char *nameend;
+      unsigned int namelen;
       const struct option *p;
       const struct option *pfound = NULL;
+      struct option_list
+      {
+        const struct option *p;
+        struct option_list *next;
+      } *ambig_list = NULL;
       int exact = 0;
       int ambig = 0;
       int indfound = -1;
@@ -488,14 +494,14 @@
 
       for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++)
         /* Do nothing.  */ ;
+      namelen = nameend - d->__nextchar;
 
       /* Test all long options for either exact match
          or abbreviated matches.  */
       for (p = longopts, option_index = 0; p->name; p++, option_index++)
-        if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar))
+        if (!strncmp (p->name, d->__nextchar, namelen))
           {
-            if ((unsigned int) (nameend - d->__nextchar)
-                == (unsigned int) strlen (p->name))
+            if (namelen == (unsigned int) strlen (p->name))
               {
                 /* Exact match found.  */
                 pfound = p;
@@ -513,35 +519,71 @@
                      || pfound->has_arg != p->has_arg
                      || pfound->flag != p->flag
                      || pfound->val != p->val)
-              /* Second or later nonexact match found.  */
-              ambig = 1;
+              {
+                /* Second or later nonexact match found.  */
+                struct option_list *newp = malloc (sizeof (*newp));
+                newp->p = p;
+                newp->next = ambig_list;
+                ambig_list = newp;
+              }
           }
 
-      if (ambig && !exact)
+      if (ambig_list != NULL && !exact)
         {
           if (print_errors)
             {
-#if defined _LIBC && defined USE_IN_LIBIO
-              char *buf;
+              struct option_list first;
+              first.p = pfound;
+              first.next = ambig_list;
+              ambig_list = &first;
 
-              if (__asprintf (&buf, _("%s: option '%s' is ambiguous\n"),
-                              argv[0], argv[d->optind]) >= 0)
+#if defined _LIBC && defined USE_IN_LIBIO
+              char *buf = NULL;
+              size_t buflen = 0;
+
+              FILE *fp = open_memstream (&buf, &buflen);
+              if (fp != NULL)
                 {
-                  _IO_flockfile (stderr);
+                  fprintf (fp,
+                           _("%s: option '%s' is ambiguous; possibilities:"),
+                           argv[0], argv[d->optind]);
 
-                  int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
-                  ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+                  do
+                    {
+                      fprintf (fp, " '--%s'", ambig_list->p->name);
+                      ambig_list = ambig_list->next;
+                    }
+                  while (ambig_list != NULL);
 
-                  __fxprintf (NULL, "%s", buf);
+                  fputc_unlocked ('\n', fp);
 
-                  ((_IO_FILE *) stderr)->_flags2 = old_flags2;
-                  _IO_funlockfile (stderr);
+                  if (__builtin_expect (fclose (fp) != EOF, 1))
+                    {
+                      _IO_flockfile (stderr);
+
+                      int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+                      ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
 
-                  free (buf);
+                      __fxprintf (NULL, "%s", buf);
+
+                      ((_IO_FILE *) stderr)->_flags2 = old_flags2;
+                      _IO_funlockfile (stderr);
+
+                      free (buf);
+                    }
                 }
 #else
-              fprintf (stderr, _("%s: option '%s' is ambiguous\n"),
+              fprintf (stderr,
+                       _("%s: option '%s' is ambiguous; possibilities:"),
                        argv[0], argv[d->optind]);
+              do
+                {
+                  fprintf (stderr, " '--%s'", ambig_list->p->name);
+                  ambig_list = ambig_list->next;
+                }
+              while (ambig_list != NULL);
+
+              fputc ('\n', stderr);
 #endif
             }
           d->__nextchar += strlen (d->__nextchar);
@@ -550,6 +592,13 @@
           return '?';
         }
 
+      while (ambig_list != NULL)
+        {
+          struct option_list *pn = ambig_list->next;
+          free (ambig_list);
+          ambig_list = pn;
+        }
+
       if (pfound != NULL)
         {
           option_index = indfound;