X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fargmatch.c;h=9125e2af048eee7851e28f47090054fa445f4471;hb=23eecb48e39afd0d267d64d40ba6bf97aa865e13;hp=625ad26b7dce717dbf3d93d3bde244c08a2ba8da;hpb=bcd35974a9b1a46c9f0dd26d695f626379b7545e;p=gnulib.git diff --git a/lib/argmatch.c b/lib/argmatch.c index 625ad26b7..9125e2af0 100644 --- a/lib/argmatch.c +++ b/lib/argmatch.c @@ -1,10 +1,12 @@ /* 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-2013 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 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 @@ -12,124 +14,106 @@ 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 . */ /* Written by David MacKenzie Modified by Akim Demaille */ +#include + +/* Specification. */ #include "argmatch.h" +#include #include -#ifdef STDC_HEADERS -# include -#endif +#include +#include -#if HAVE_LOCALE_H -# include -#endif -#if !HAVE_SETLOCALE -# define setlocale(Category, Locale) /* empty */ -#endif - -#if ENABLE_NLS -# include -# 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 "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 -# define ARGMATCH_QUOTING_STYLE c_quoting_style +# define ARGMATCH_QUOTING_STYLE locale_quoting_style #endif -#if !HAVE_STRNCASECMP -# include -/* 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; + /* 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). - If SENSITIVE, comparison is case sensitive. If VALLIST is none null, use it to resolve ambiguities limited to synonyms, i.e., for "yes", "yop" -> 0 "no", "nope" -> 1 - "y" is a valid argument, for `0', and "n" for `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++) { - 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; @@ -137,48 +121,20 @@ __argmatch_internal (const char *arg, const char *const *arglist, 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. - 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 -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. @@ -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, - 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:")); - for (i = 0 ; arglist[i] ; i++) + fputs (_("Valid arguments are:"), stderr); + for (i = 0; arglist[i]; i++) 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", quote (arglist[i])); + last_val = vallist + valsize * i; } else { - fprintf (stderr, ", `%s'", arglist[i]); + fprintf (stderr, ", %s", quote (arglist[i])); } 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; - - 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 */ + 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 * -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; - - for (i = 0 ; arglist [i] ; i++) + size_t i; + + for (i = 0; arglist[i]; i++) if (!memcmp (value, vallist + valsize * i, valsize)) - return arglist [i]; + return arglist[i]; return NULL; } @@ -259,52 +209,51 @@ argmatch_to_argument (char * value, /* * Based on "getversion.c" by David MacKenzie */ -char * program_name; -extern const char * getenv (); +char *program_name; /* When to make backup files. */ enum backup_type { /* Never make backups. */ - none, + no_backups, /* 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. */ - numbered_existing, + numbered_existing_backups, /* Make numbered backups of every file. */ - numbered + numbered_backups }; /* Two tables describing arguments (keys) and their corresponding values */ static const char *const backup_args[] = { - "no", "none", "off", - "simple", "never", - "existing", "nil", - "numbered", "t", + "no", "none", "off", + "simple", "never", + "existing", "nil", + "numbered", "t", 0 }; 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) +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) { @@ -313,15 +262,15 @@ main (int argc, const char *const * argv) } 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) - 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)); return 0; }