* jm-macros.m4 (jm_MACROS): check for rpmatch.
[findutils.git] / lib / argmatch.c
blob964270650c2b72150ba8f1375c8857378dd5be16
1 /* argmatch.c -- find a match for a string in an array
2 Copyright (C) 1990, 1998, 1999 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Written by David MacKenzie <djm@ai.mit.edu>
19 Modified by Akim Demaille <demaille@inf.enst.fr> */
21 #include "argmatch.h"
23 #include <stdio.h>
24 #ifdef STDC_HEADERS
25 # include <string.h>
26 #endif
28 #if HAVE_LOCALE_H
29 # include <locale.h>
30 #endif
32 #if ENABLE_NLS
33 # include <libintl.h>
34 # define _(Text) gettext (Text)
35 #else
36 # define _(Text) Text
37 #endif
39 #include "error.h"
40 #include "quotearg.h"
42 /* When reporting an invalid argument, show nonprinting characters
43 by using the quoting style ARGMATCH_QUOTING_STYLE. Do not use
44 literal_quoting_style. */
45 #ifndef ARGMATCH_QUOTING_STYLE
46 # define ARGMATCH_QUOTING_STYLE locale_quoting_style
47 #endif
49 /* The following test is to work around the gross typo in
50 systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE
51 is defined to 0, not 1. */
52 #if !EXIT_FAILURE
53 # undef EXIT_FAILURE
54 # define EXIT_FAILURE 1
55 #endif
57 /* Non failing version of argmatch call this function after failing. */
58 #ifndef ARGMATCH_DIE
59 # define ARGMATCH_DIE exit (EXIT_FAILURE)
60 #endif
62 #ifdef ARGMATCH_DIE_DECL
63 ARGMATCH_DIE_DECL;
64 #endif
66 static void
67 __argmatch_die (void)
69 ARGMATCH_DIE;
72 /* Used by XARGMATCH and XARGCASEMATCH. See description in argmatch.h.
73 Default to __argmatch_die, but allow caller to change this at run-time. */
74 argmatch_exit_fn argmatch_die = __argmatch_die;
77 /* If ARG is an unambiguous match for an element of the
78 null-terminated array ARGLIST, return the index in ARGLIST
79 of the matched element, else -1 if it does not match any element
80 or -2 if it is ambiguous (is a prefix of more than one element).
81 If SENSITIVE, comparison is case sensitive.
83 If VALLIST is none null, use it to resolve ambiguities limited to
84 synonyms, i.e., for
85 "yes", "yop" -> 0
86 "no", "nope" -> 1
87 "y" is a valid argument, for `0', and "n" for `1'. */
89 static int
90 __argmatch_internal (const char *arg, const char *const *arglist,
91 const char *vallist, size_t valsize,
92 int case_sensitive)
94 int i; /* Temporary index in ARGLIST. */
95 size_t arglen; /* Length of ARG. */
96 int matchind = -1; /* Index of first nonexact match. */
97 int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */
99 arglen = strlen (arg);
101 /* Test all elements for either exact match or abbreviated matches. */
102 for (i = 0; arglist[i]; i++)
104 if (case_sensitive
105 ? !strncmp (arglist[i], arg, arglen)
106 : !strncasecmp (arglist[i], arg, arglen))
108 if (strlen (arglist[i]) == arglen)
109 /* Exact match found. */
110 return i;
111 else if (matchind == -1)
112 /* First nonexact match found. */
113 matchind = i;
114 else
116 /* Second nonexact match found. */
117 if (vallist == NULL
118 || memcmp (vallist + valsize * matchind,
119 vallist + valsize * i, valsize))
121 /* There is a real ambiguity, or we could not
122 disambiguate. */
123 ambiguous = 1;
128 if (ambiguous)
129 return -2;
130 else
131 return matchind;
134 /* argmatch - case sensitive version */
136 argmatch (const char *arg, const char *const *arglist,
137 const char *vallist, size_t valsize)
139 return __argmatch_internal (arg, arglist, vallist, valsize, 1);
142 /* argcasematch - case insensitive version */
144 argcasematch (const char *arg, const char *const *arglist,
145 const char *vallist, size_t valsize)
147 return __argmatch_internal (arg, arglist, vallist, valsize, 0);
150 /* Error reporting for argmatch.
151 CONTEXT is a description of the type of entity that was being matched.
152 VALUE is the invalid value that was given.
153 PROBLEM is the return value from argmatch. */
155 void
156 argmatch_invalid (const char *context, const char *value, int problem)
158 char const *format = (problem == -1
159 ? _("invalid argument %s for `%s'")
160 : _("ambiguous argument %s for `%s'"));
162 error (0, 0, format, quotearg_style (ARGMATCH_QUOTING_STYLE, value), context);
165 /* List the valid arguments for argmatch.
166 ARGLIST is the same as in argmatch.
167 VALLIST is a pointer to an array of values.
168 VALSIZE is the size of the elements of VALLIST */
169 void
170 argmatch_valid (const char *const *arglist,
171 const char *vallist, size_t valsize)
173 int i;
174 const char *last_val = NULL;
176 /* We try to put synonyms on the same line. The assumption is that
177 synonyms follow each other */
178 fprintf (stderr, _("Valid arguments are:"));
179 for (i = 0; arglist[i]; i++)
180 if ((i == 0)
181 || memcmp (last_val, vallist + valsize * i, valsize))
183 fprintf (stderr, "\n - `%s'", arglist[i]);
184 last_val = vallist + valsize * i;
186 else
188 fprintf (stderr, ", `%s'", arglist[i]);
190 putc ('\n', stderr);
193 /* Never failing versions of the previous functions.
195 CONTEXT is the context for which argmatch is called (e.g.,
196 "--version-control", or "$VERSION_CONTROL" etc.). Upon failure,
197 calls the (supposed never to return) function EXIT_FN. */
200 __xargmatch_internal (const char *context,
201 const char *arg, const char *const *arglist,
202 const char *vallist, size_t valsize,
203 int case_sensitive,
204 argmatch_exit_fn exit_fn)
206 int res = __argmatch_internal (arg, arglist,
207 vallist, valsize,
208 case_sensitive);
209 if (res >= 0)
210 /* Success. */
211 return res;
213 /* We failed. Explain why. */
214 argmatch_invalid (context, arg, res);
215 argmatch_valid (arglist, vallist, valsize);
216 (*exit_fn) ();
218 return -1; /* To please the compilers. */
221 /* Look for VALUE in VALLIST, an array of objects of size VALSIZE and
222 return the first corresponding argument in ARGLIST */
223 const char *
224 argmatch_to_argument (const char *value,
225 const char *const *arglist,
226 const char *vallist, size_t valsize)
228 int i;
230 for (i = 0; arglist[i]; i++)
231 if (!memcmp (value, vallist + valsize * i, valsize))
232 return arglist[i];
233 return NULL;
236 #ifdef TEST
238 * Based on "getversion.c" by David MacKenzie <djm@gnu.ai.mit.edu>
240 char *program_name;
241 extern const char *getenv ();
243 /* When to make backup files. */
244 enum backup_type
246 /* Never make backups. */
247 none,
249 /* Make simple backups of every file. */
250 simple,
252 /* Make numbered backups of files that already have numbered backups,
253 and simple backups of the others. */
254 numbered_existing,
256 /* Make numbered backups of every file. */
257 numbered
260 /* Two tables describing arguments (keys) and their corresponding
261 values */
262 static const char *const backup_args[] =
264 "no", "none", "off",
265 "simple", "never",
266 "existing", "nil",
267 "numbered", "t",
271 static const enum backup_type backup_vals[] =
273 none, none, none,
274 simple, simple,
275 numbered_existing, numbered_existing,
276 numbered, numbered
280 main (int argc, const char *const *argv)
282 const char *cp;
283 enum backup_type backup_type = none;
285 program_name = (char *) argv[0];
287 if (argc > 2)
289 fprintf (stderr, "Usage: %s [VERSION_CONTROL]\n", program_name);
290 exit (1);
293 if ((cp = getenv ("VERSION_CONTROL")))
294 backup_type = XARGCASEMATCH ("$VERSION_CONTROL", cp,
295 backup_args, backup_vals);
297 if (argc == 2)
298 backup_type = XARGCASEMATCH (program_name, argv[1],
299 backup_args, backup_vals);
301 printf ("The version control is `%s'\n",
302 ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
304 return 0;
306 #endif