X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fargmatch.c;h=4e879691f4ce7799af51c512862223f584f9f8b0;hb=ac5e11c593de9d8a862193b328a2def30e6d3447;hp=5f47711c6daa26c9e85eba0e7c2cea39fd7f26cd;hpb=6d8337bfc808cddc275899c03482eceb6aff8547;p=gnulib.git diff --git a/lib/argmatch.c b/lib/argmatch.c index 5f47711c6..4e879691f 100644 --- a/lib/argmatch.c +++ b/lib/argmatch.c @@ -1,5 +1,5 @@ /* argmatch.c -- find a match for a string in an array - Copyright (C) 1990 Free Software Foundation, Inc. + Copyright (C) 1990, 1998, 1999 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 @@ -15,32 +15,57 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* Written by David MacKenzie */ +/* Written by David MacKenzie + Modified by Akim Demaille */ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include +#include "argmatch.h" #include #ifdef STDC_HEADERS -#include +# include +#endif + +#if HAVE_LOCALE_H +# include +#endif + +#if ENABLE_NLS +# include +# define _(Text) gettext (Text) +#else +# define _(Text) Text +#endif + +#include "quotearg.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. */ + +#ifndef ARGMATCH_QUOTING_STYLE +# define ARGMATCH_QUOTING_STYLE c_quoting_style #endif extern char *program_name; /* If ARG is an unambiguous match for an element of the - null-terminated array OPTLIST, return the index in OPTLIST + 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). */ + or -2 if it is ambiguous (is a prefix of more than one element). + If SENSITIVE, comparison is case sensitive. -int -argmatch (arg, optlist) - const char *arg; - const char *const *optlist; + 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'. */ + +static int +__argmatch_internal (const char *arg, const char *const *arglist, + const char *vallist, size_t valsize, + int case_sensitive) { - int i; /* Temporary index in OPTLIST. */ + 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). */ @@ -48,19 +73,30 @@ argmatch (arg, optlist) arglen = strlen (arg); /* Test all elements for either exact match or abbreviated matches. */ - for (i = 0; optlist[i]; i++) + for (i = 0; arglist[i]; i++) { - if (!strncmp (optlist[i], arg, arglen)) + if (case_sensitive + ? !strncmp (arglist[i], arg, arglen) + : !strncasecmp (arglist[i], arg, arglen)) { - if (strlen (optlist[i]) == 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. */ - ambiguous = 1; + { + /* 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 = 1; + } + } } } if (ambiguous) @@ -69,21 +105,161 @@ argmatch (arg, optlist) 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. VALUE is the invalid value that was given. PROBLEM is the return value from argmatch. */ void -invalid_arg (kind, value, problem) - const char *kind; - const char *value; - int problem; +argmatch_invalid (const char *kind, const char *value, int 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"); + fprintf (stderr, _("invalid argument %s for `%s'"), + quotearg (value), kind); else /* Assume -2. */ - fprintf (stderr, "ambiguous"); - fprintf (stderr, " %s `%s'\n", kind, value); + fprintf (stderr, _("ambiguous argument %s for `%s'"), + quotearg (value), kind); + putc ('\n', stderr); + + set_quoting_style (NULL, saved_quoting_style); +} + +/* List the valid arguments for argmatch. + ARGLIST is the same as in argmatch. + VALLIST is a pointer to an array of values. + VALSIZE is the size of the elements of VALLIST */ +void +argmatch_valid (const char *const *arglist, + const char *vallist, size_t valsize) +{ + int 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++) + if ((i == 0) + || memcmp (last_val, vallist + valsize * i, valsize)) + { + fprintf (stderr, "\n - `%s'", arglist[i]); + last_val = vallist + valsize * i; + } + else + { + fprintf (stderr, ", `%s'", arglist[i]); + } + putc ('\n', stderr); } + +/* 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 (const char *value, + const char *const *arglist, + const char *vallist, size_t valsize) +{ + int i; + + for (i = 0; arglist[i]; i++) + if (!memcmp (value, vallist + valsize * i, valsize)) + return arglist[i]; + return NULL; +} + +#ifdef TEST +/* + * Based on "getversion.c" by David MacKenzie + */ +char *rogram_name; +extern const char *getenv (); + +/* When to make backup files. */ +enum backup_type +{ + /* Never make backups. */ + none, + + /* Make simple backups of every file. */ + simple, + + /* Make numbered backups of files that already have numbered backups, + and simple backups of the others. */ + numbered_existing, + + /* Make numbered backups of every file. */ + numbered +}; + +/* Two tables describing arguments (keys) and their corresponding + values */ +static const char *const backup_args[] = +{ + "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 +}; + +int +main (int argc, const char *const *argv) +{ + const char *cp; + enum backup_type backup_type = none; + + program_name = (char *) argv[0]; + + if (argc > 2) + { + fprintf (stderr, "Usage: %s [VERSION_CONTROL]\n", program_name); + exit (1); + } + + if ((cp = getenv ("VERSION_CONTROL"))) + backup_type = XARGCASEMATCH ("$VERSION_CONTROL", cp, + backup_args, backup_vals); + + if (argc == 2) + backup_type = XARGCASEMATCH (program_name, argv[1], + backup_args, backup_vals); + + printf ("The version control is `%s'\n", + ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals)); + + return 0; +} +#endif