frexpl: Update autoconf test.
[gnulib.git] / lib / argmatch.c
index 1364292..9a3eca4 100644 (file)
@@ -1,10 +1,12 @@
 /* argmatch.c -- find a match for a string in an array
 /* argmatch.c -- find a match for a string in an array
-   Copyright (C) 1990, 1998 Free Software Foundation, Inc.
 
 
-   This program is free software; you can redistribute it and/or modify
+   Copyright (C) 1990, 1998-1999, 2001-2007, 2009-2011 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
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
+   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
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    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, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* Written by David MacKenzie <djm@ai.mit.edu>
    Modified by Akim Demaille <demaille@inf.enst.fr> */
 
 
 /* Written by David MacKenzie <djm@ai.mit.edu>
    Modified by Akim Demaille <demaille@inf.enst.fr> */
 
+#include <config.h>
+
+/* Specification.  */
 #include "argmatch.h"
 
 #include "argmatch.h"
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdio.h>
-#ifdef STDC_HEADERS
-# include <string.h>
-#endif
-
-#if HAVE_LOCALE_H
-# include <locale.h>
-#endif
-#if !HAVE_SETLOCALE
-# define setlocale(Category, Locale) /* empty */
-#endif
+#include <stdlib.h>
+#include <string.h>
 
 
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define bindtextdomain(Domain, Directory) /* empty */
-# define textdomain(Domain) /* empty */
-# define _(Text) Text
-#endif
-
-#ifndef EXIT_BADARG
-# define EXIT_BADARG 1
-#endif
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
 
 
+#include "error.h"
 #include "quotearg.h"
 #include "quotearg.h"
+#include "quote.h"
 
 
-/* When reporting a failing argument, make sure to show invisible
-   characters hidden using the quoting style
-   ARGMATCH_QUOTING_STYLE. literal_quoting_style is not good.*/
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#endif
 
 
+/* When reporting an invalid argument, show nonprinting characters
+   by using the quoting style ARGMATCH_QUOTING_STYLE.  Do not use
+   literal_quoting_style.  */
 #ifndef ARGMATCH_QUOTING_STYLE
 #ifndef ARGMATCH_QUOTING_STYLE
-# define ARGMATCH_QUOTING_STYLE c_quoting_style
+# define ARGMATCH_QUOTING_STYLE locale_quoting_style
 #endif
 
 #endif
 
-#if !HAVE_STRNCASECMP
-# include <ctype.h>
-/* Compare no more than N characters of S1 and S2,
-   ignoring case, returning less than, equal to or
-   greater than zero if S1 is lexicographically less
-   than, equal to or greater than S2.  */
-int
-strncasecmp (const char *s1, const char *s2, size_t n)
-{
-  register const unsigned char *p1 = (const unsigned char *) s1;
-  register const unsigned char *p2 = (const unsigned char *) s2;
-  unsigned char c1, c2;
-
-  if (p1 == p2 || n == 0)
-    return 0;
+/* Non failing version of argmatch call this function after failing. */
+#ifndef ARGMATCH_DIE
+# include "exitfail.h"
+# define ARGMATCH_DIE exit (exit_failure)
+#endif
 
 
-  do
-    {
-      c1 = tolower (*p1++);
-      c2 = tolower (*p2++);
-      if (c1 == '\0' || c1 != c2)
-        return c1 - c2;
-    } while (--n > 0);
+#ifdef ARGMATCH_DIE_DECL
+ARGMATCH_DIE_DECL;
+#endif
 
 
-  return c1 - c2;
+static void
+__argmatch_die (void)
+{
+  ARGMATCH_DIE;
 }
 }
-#endif
 
 
-extern char *program_name;
+/* Used by XARGMATCH and XARGCASEMATCH.  See description in argmatch.h.
+   Default to __argmatch_die, but allow caller to change this at run-time. */
+argmatch_exit_fn argmatch_die = __argmatch_die;
 
 
+\f
 /* If ARG is an unambiguous match for an element of the
 /* If ARG is an unambiguous match for an element of the
-   null-terminated array ARGLIST, return the index in ARGLIST
+   NULL-terminated array ARGLIST, return the index in ARGLIST
    of the matched element, else -1 if it does not match any element
    or -2 if it is ambiguous (is a prefix of more than one element).
    of the matched element, else -1 if it does not match any element
    or -2 if it is ambiguous (is a prefix of more than one element).
-   If SENSITIVE, comparison is case sensitive.
 
    If VALLIST is none null, use it to resolve ambiguities limited to
    synonyms, i.e., for
 
    If VALLIST is none null, use it to resolve ambiguities limited to
    synonyms, i.e., for
@@ -97,39 +79,41 @@ extern char *program_name;
      "no", "nope" -> 1
    "y" is a valid argument, for `0', and "n" for `1'.  */
 
      "no", "nope" -> 1
    "y" is a valid argument, for `0', and "n" for `1'.  */
 
-static int
-__argmatch_internal (const char *arg, const char *const *arglist,
-                    const char *vallist, size_t valsize,
-                    int sensitive)
+ptrdiff_t
+argmatch (const char *arg, const char *const *arglist,
+          const char *vallist, size_t valsize)
 {
 {
-  int i;                       /* Temporary index in ARGLIST.  */
-  size_t arglen;               /* Length of ARG.  */
-  int matchind = -1;           /* Index of first nonexact match.  */
-  int ambiguous = 0;           /* If nonzero, multiple nonexact match(es).  */
+  size_t i;                     /* Temporary index in ARGLIST.  */
+  size_t arglen;                /* Length of ARG.  */
+  ptrdiff_t matchind = -1;      /* Index of first nonexact match.  */
+  bool ambiguous = false;       /* If true, multiple nonexact match(es).  */
 
   arglen = strlen (arg);
 
   /* Test all elements for either exact match or abbreviated matches.  */
   for (i = 0; arglist[i]; i++)
     {
 
   arglen = strlen (arg);
 
   /* Test all elements for either exact match or abbreviated matches.  */
   for (i = 0; arglist[i]; i++)
     {
-      if (sensitive ? !strncmp (arglist[i], arg, arglen)
-                   : !strncasecmp (arglist[i], arg, arglen))
-       {
-         if (strlen (arglist[i]) == arglen)
-           /* Exact match found.  */
-           return i;
-         else if (matchind == -1)
-           /* First nonexact match found.  */
-           matchind = i;
-         else
-           /* Second nonexact match found.  */
-           if (vallist == NULL
-               || memcmp (vallist + valsize * matchind,
-                          vallist + valsize * i, valsize))
-             /* There is a real ambiguity, or we could not
-                 desambiguise. */
-             ambiguous = 1;
-       }
+      if (!strncmp (arglist[i], arg, arglen))
+        {
+          if (strlen (arglist[i]) == arglen)
+            /* Exact match found.  */
+            return i;
+          else if (matchind == -1)
+            /* First nonexact match found.  */
+            matchind = i;
+          else
+            {
+              /* Second nonexact match found.  */
+              if (vallist == NULL
+                  || memcmp (vallist + valsize * matchind,
+                             vallist + valsize * i, valsize))
+                {
+                  /* There is a real ambiguity, or we could not
+                     disambiguate. */
+                  ambiguous = true;
+                }
+            }
+        }
     }
   if (ambiguous)
     return -2;
     }
   if (ambiguous)
     return -2;
@@ -137,48 +121,20 @@ __argmatch_internal (const char *arg, const char *const *arglist,
     return matchind;
 }
 
     return matchind;
 }
 
-/* argmatch - case sensitive version */
-int
-argmatch (const char *arg, const char *const *arglist,
-         const char *vallist, size_t valsize)
-{
-  return __argmatch_internal (arg, arglist, vallist, valsize, 1);
-}
-
-/* argcasematch - case insensitive version */
-int
-argcasematch (const char *arg, const char *const *arglist,
-             const char *vallist, size_t valsize)
-{
-  return __argmatch_internal (arg, arglist, vallist, valsize, 0);
-}
-
 /* Error reporting for argmatch.
 /* Error reporting for argmatch.
-   KIND is a description of the type of entity that was being matched.
+   CONTEXT is a description of the type of entity that was being matched.
    VALUE is the invalid value that was given.
    PROBLEM is the return value from argmatch.  */
 
 void
    VALUE is the invalid value that was given.
    PROBLEM is the return value from argmatch.  */
 
 void
-argmatch_invalid (const char *kind, const char *value, int problem)
+argmatch_invalid (const char *context, const char *value, ptrdiff_t problem)
 {
 {
-  enum quoting_style saved_quoting_style;
-
-  /* Make sure to have a good quoting style to report errors.
-     literal is insane here. */
-  saved_quoting_style = get_quoting_style (NULL);
-  set_quoting_style (NULL, ARGMATCH_QUOTING_STYLE);
-
-  /* There is an error */
-  fprintf (stderr, "%s: ", program_name);
-  if (problem == -1)
-    fprintf (stderr,  _("invalid argument %s for `%s'"),
-            quotearg (value), kind);
-  else                         /* Assume -2.  */
-    fprintf (stderr, _("ambiguous argument %s for `%s'"),
-            quotearg (value), kind);
-  putc ('\n', stderr);
+  char const *format = (problem == -1
+                        ? _("invalid argument %s for %s")
+                        : _("ambiguous argument %s for %s"));
 
 
-  set_quoting_style (NULL, saved_quoting_style);
+  error (0, 0, format, quotearg_n_style (0, ARGMATCH_QUOTING_STYLE, value),
+         quote_n (1, context));
 }
 
 /* List the valid arguments for argmatch.
 }
 
 /* List the valid arguments for argmatch.
@@ -187,71 +143,65 @@ argmatch_invalid (const char *kind, const char *value, int problem)
    VALSIZE is the size of the elements of VALLIST */
 void
 argmatch_valid (const char *const *arglist,
    VALSIZE is the size of the elements of VALLIST */
 void
 argmatch_valid (const char *const *arglist,
-               const char *vallist, size_t valsize)
+                const char *vallist, size_t valsize)
 {
 {
-  int i;
-  const char * last_val = NULL;
+  size_t i;
+  const char *last_val = NULL;
 
   /* We try to put synonyms on the same line.  The assumption is that
      synonyms follow each other */
   fprintf (stderr, _("Valid arguments are:"));
 
   /* We try to put synonyms on the same line.  The assumption is that
      synonyms follow each other */
   fprintf (stderr, _("Valid arguments are:"));
-  for (i = 0 ; arglist[i] ; i++)
+  for (i = 0; arglist[i]; i++)
     if ((i == 0)
     if ((i == 0)
-       || memcmp (last_val, vallist + valsize * i, valsize))
+        || memcmp (last_val, vallist + valsize * i, valsize))
       {
       {
-       fprintf (stderr, "\n  - `%s'", arglist[i]);
-       last_val = vallist + valsize * i;
+        fprintf (stderr, "\n  - `%s'", arglist[i]);
+        last_val = vallist + valsize * i;
       }
     else
       {
       }
     else
       {
-       fprintf (stderr, ", `%s'", arglist[i]);
+        fprintf (stderr, ", `%s'", arglist[i]);
       }
   putc ('\n', stderr);
 }
 
       }
   putc ('\n', stderr);
 }
 
-/* Call __argmatch_internal, but handle the error so that it never
-   returns.  Errors are reported to the users with a list of valid
-   values.
+/* Never failing versions of the previous functions.
 
 
-   KIND is a description of the type of entity that was being matched.
-   ARG, ARGLIST, and SENSITIVE are the same as in __argmatch_internal
-   VALIST, and VALSIZE are the same as in valid_args */
-int
-__xargmatch_internal (const char *kind, const char *arg,
-                     const char *const *arglist,
-                     const char *vallist, size_t valsize,
-                     int sensitive)
+   CONTEXT is the context for which argmatch is called (e.g.,
+   "--version-control", or "$VERSION_CONTROL" etc.).  Upon failure,
+   calls the (supposed never to return) function EXIT_FN. */
+
+ptrdiff_t
+__xargmatch_internal (const char *context,
+                      const char *arg, const char *const *arglist,
+                      const char *vallist, size_t valsize,
+                      argmatch_exit_fn exit_fn)
 {
 {
-  int i;
+  ptrdiff_t res = argmatch (arg, arglist, vallist, valsize);
+  if (res >= 0)
+    /* Success. */
+    return res;
 
 
-  i = __argmatch_internal (arg, arglist, vallist, valsize, sensitive);
-  if (i >= 0)
-    {
-      /* Success */
-      return i;
-    }
-  else
-    {
-      /* Failure */
-      argmatch_invalid (kind, arg, i);
-      argmatch_valid (arglist, vallist, valsize);
-      exit (EXIT_BADARG);
-    }
-  return -1;   /* To please some compilers */
+  /* We failed.  Explain why. */
+  argmatch_invalid (context, arg, res);
+  argmatch_valid (arglist, vallist, valsize);
+  (*exit_fn) ();
+
+  return -1; /* To please the compilers. */
 }
 
 /* Look for VALUE in VALLIST, an array of objects of size VALSIZE and
    return the first corresponding argument in ARGLIST */
 const char *
 }
 
 /* Look for VALUE in VALLIST, an array of objects of size VALSIZE and
    return the first corresponding argument in ARGLIST */
 const char *
-argmatch_to_argument (char * value,
-                     const char *const *arglist,
-                     const char *vallist, size_t valsize)
+argmatch_to_argument (const char *value,
+                      const char *const *arglist,
+                      const char *vallist, size_t valsize)
 {
 {
-  int i;
+  size_t i;
 
 
-  for (i = 0 ; arglist [i] ; i++)
+  for (i = 0; arglist[i]; i++)
     if (!memcmp (value, vallist + valsize * i, valsize))
     if (!memcmp (value, vallist + valsize * i, valsize))
-      return arglist [i];
+      return arglist[i];
   return NULL;
 }
 
   return NULL;
 }
 
@@ -259,24 +209,23 @@ argmatch_to_argument (char * value,
 /*
  * Based on "getversion.c" by David MacKenzie <djm@gnu.ai.mit.edu>
  */
 /*
  * Based on "getversion.c" by David MacKenzie <djm@gnu.ai.mit.edu>
  */
-char * program_name;
-extern const char * getenv ();
+char *program_name;
 
 /* When to make backup files.  */
 enum backup_type
 {
   /* Never make backups.  */
 
 /* When to make backup files.  */
 enum backup_type
 {
   /* Never make backups.  */
-  none,
+  no_backups,
 
   /* Make simple backups of every file.  */
 
   /* Make simple backups of every file.  */
-  simple,
+  simple_backups,
 
   /* Make numbered backups of files that already have numbered backups,
      and simple backups of the others.  */
 
   /* Make numbered backups of files that already have numbered backups,
      and simple backups of the others.  */
-  numbered_existing,
+  numbered_existing_backups,
 
   /* Make numbered backups of every file.  */
 
   /* Make numbered backups of every file.  */
-  numbered
+  numbered_backups
 };
 
 /* Two tables describing arguments (keys) and their corresponding
 };
 
 /* Two tables describing arguments (keys) and their corresponding
@@ -292,19 +241,19 @@ static const char *const backup_args[] =
 
 static const enum backup_type backup_vals[] =
 {
 
 static const enum backup_type backup_vals[] =
 {
-  none, none, none,
-  simple, simple,
-  numbered_existing, numbered_existing,
-  numbered, numbered
+  no_backups, no_backups, no_backups,
+  simple_backups, simple_backups,
+  numbered_existing_backups, numbered_existing_backups,
+  numbered_backups, numbered_backups
 };
 
 int
 };
 
 int
-main (int argc, const char *const * argv)
+main (int argc, const char *const *argv)
 {
 {
-  const char * cp;
-  enum backup_type backup_type = none;
+  const char *cp;
+  enum backup_type backup_type = no_backups;
 
 
-  program_name = (char *) argv [0];
+  program_name = (char *) argv[0];
 
   if (argc > 2)
     {
 
   if (argc > 2)
     {
@@ -313,15 +262,15 @@ main (int argc, const char *const * argv)
     }
 
   if ((cp = getenv ("VERSION_CONTROL")))
     }
 
   if ((cp = getenv ("VERSION_CONTROL")))
-    backup_type = XARGCASEMATCH ("$VERSION_CONTROL", cp,
-                                backup_args, backup_vals);
+    backup_type = XARGMATCH ("$VERSION_CONTROL", cp,
+                             backup_args, backup_vals);
 
   if (argc == 2)
 
   if (argc == 2)
-    backup_type = XARGCASEMATCH (program_name, argv [1],
-                                backup_args, backup_vals);
+    backup_type = XARGMATCH (program_name, argv[1],
+                             backup_args, backup_vals);
 
   printf ("The version control is `%s'\n",
 
   printf ("The version control is `%s'\n",
-         ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
+          ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
 
   return 0;
 }
 
   return 0;
 }