New module 'striconveh'.
[gnulib.git] / lib / argmatch.c
index ed18c18..c6cdfcc 100644 (file)
@@ -1,5 +1,7 @@
 /* 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, 1999 Free Software Foundation, Inc.
+
+   Copyright (C) 1990, 1998, 1999, 2001, 2002, 2003, 2004, 2005, 2006
+   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
 
    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
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software Foundation,
 
    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.  */
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 /* 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
+#include <stdlib.h>
+#include <string.h>
 
 
-#if HAVE_LOCALE_H
-# include <locale.h>
-#endif
-
-#if ENABLE_NLS
-# include <libintl.h>
-# define _(Text) gettext (Text)
-#else
-# define _(Text) Text
-#endif
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
 
 
+#include "error.h"
+#include "exit.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 escape_quoting_style
+# define ARGMATCH_QUOTING_STYLE locale_quoting_style
+#endif
+
+/* Non failing version of argmatch call this function after failing. */
+#ifndef ARGMATCH_DIE
+# include "exitfail.h"
+# define ARGMATCH_DIE exit (exit_failure)
 #endif
 
 #endif
 
-extern char *program_name;
+#ifdef ARGMATCH_DIE_DECL
+ARGMATCH_DIE_DECL;
+#endif
+
+static void
+__argmatch_die (void)
+{
+  ARGMATCH_DIE;
+}
+
+/* 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
@@ -60,24 +81,21 @@ 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 case_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 i;                    /* Temporary index in ARGLIST.  */
   size_t arglen;               /* Length of ARG.  */
   size_t arglen;               /* Length of ARG.  */
-  int matchind = -1;           /* Index of first nonexact match.  */
-  int ambiguous = 0;           /* If nonzero, multiple nonexact match(es).  */
+  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 (case_sensitive
-         ? !strncmp (arglist[i], arg, arglen)
-         : !strncasecmp (arglist[i], arg, arglen))
+      if (!strncmp (arglist[i], arg, arglen))
        {
          if (strlen (arglist[i]) == arglen)
            /* Exact match found.  */
        {
          if (strlen (arglist[i]) == arglen)
            /* Exact match found.  */
@@ -94,7 +112,7 @@ __argmatch_internal (const char *arg, const char *const *arglist,
                {
                  /* There is a real ambiguity, or we could not
                     disambiguate. */
                {
                  /* There is a real ambiguity, or we could not
                     disambiguate. */
-                 ambiguous = 1;
+                 ambiguous = true;
                }
            }
        }
                }
            }
        }
@@ -105,45 +123,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;
-  char const *format;
-
-  /* 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);
+  char const *format = (problem == -1
+                       ? _("invalid argument %s for %s")
+                       : _("ambiguous argument %s for %s"));
 
 
-  format = (problem == -1
-           ? _("%s: invalid argument `%s' for `%s'\n")
-           : _("%s: ambiguous argument `%s' for `%s'\n"));
-
-  fprintf (stderr, format, program_name, quotearg (value), kind);
-
-  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.
@@ -154,7 +147,7 @@ void
 argmatch_valid (const char *const *arglist,
                const char *vallist, size_t valsize)
 {
 argmatch_valid (const char *const *arglist,
                const char *vallist, size_t valsize)
 {
-  int i;
+  size_t i;
   const char *last_val = NULL;
 
   /* We try to put synonyms on the same line.  The assumption is that
   const char *last_val = NULL;
 
   /* We try to put synonyms on the same line.  The assumption is that
@@ -174,6 +167,31 @@ argmatch_valid (const char *const *arglist,
   putc ('\n', stderr);
 }
 
   putc ('\n', stderr);
 }
 
+/* Never failing versions of the previous functions.
+
+   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)
+{
+  ptrdiff_t res = argmatch (arg, arglist, vallist, valsize);
+  if (res >= 0)
+    /* Success. */
+    return res;
+
+  /* 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 *
@@ -181,7 +199,7 @@ argmatch_to_argument (const char *value,
                      const char *const *arglist,
                      const char *vallist, size_t valsize)
 {
                      const char *const *arglist,
                      const char *vallist, size_t valsize)
 {
-  int i;
+  size_t i;
 
   for (i = 0; arglist[i]; i++)
     if (!memcmp (value, vallist + valsize * i, valsize))
 
   for (i = 0; arglist[i]; i++)
     if (!memcmp (value, vallist + valsize * i, valsize))
@@ -193,24 +211,23 @@ argmatch_to_argument (const 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 *rogram_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
@@ -226,17 +243,17 @@ 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
 main (int argc, const char *const *argv)
 {
   const char *cp;
 };
 
 int
 main (int argc, const char *const *argv)
 {
   const char *cp;
-  enum backup_type backup_type = none;
+  enum backup_type backup_type = no_backups;
 
   program_name = (char *) argv[0];
 
 
   program_name = (char *) argv[0];
 
@@ -247,12 +264,12 @@ 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",
          ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
 
   printf ("The version control is `%s'\n",
          ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));