*** empty log message ***
[coreutils.git] / lib / argmatch.c
blobf08fba35e91386f8a777d5b4d15199aaaef5df37
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 escape_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 enum quoting_style saved_quoting_style;
159 char const *format;
161 /* Make sure to have a good quoting style to report errors.
162 literal is insane here. */
163 saved_quoting_style = get_quoting_style (NULL);
164 set_quoting_style (NULL, ARGMATCH_QUOTING_STYLE);
166 format = (problem == -1
167 ? _("invalid argument `%s' for `%s'")
168 : _("ambiguous argument `%s' for `%s'"));
170 error (0, 0, format, quotearg (value), context);
172 set_quoting_style (NULL, saved_quoting_style);
175 /* List the valid arguments for argmatch.
176 ARGLIST is the same as in argmatch.
177 VALLIST is a pointer to an array of values.
178 VALSIZE is the size of the elements of VALLIST */
179 void
180 argmatch_valid (const char *const *arglist,
181 const char *vallist, size_t valsize)
183 int i;
184 const char *last_val = NULL;
186 /* We try to put synonyms on the same line. The assumption is that
187 synonyms follow each other */
188 fprintf (stderr, _("Valid arguments are:"));
189 for (i = 0; arglist[i]; i++)
190 if ((i == 0)
191 || memcmp (last_val, vallist + valsize * i, valsize))
193 fprintf (stderr, "\n - `%s'", arglist[i]);
194 last_val = vallist + valsize * i;
196 else
198 fprintf (stderr, ", `%s'", arglist[i]);
200 putc ('\n', stderr);
203 /* Never failing versions of the previous functions.
205 CONTEXT is the context for which argmatch is called (e.g.,
206 "--version-control", or "$VERSION_CONTROL" etc.). Upon failure,
207 calls the (supposed never to return) function EXIT_FN. */
210 __xargmatch_internal (const char *context,
211 const char *arg, const char *const *arglist,
212 const char *vallist, size_t valsize,
213 int case_sensitive,
214 argmatch_exit_fn exit_fn)
216 int res = __argmatch_internal (arg, arglist,
217 vallist, valsize,
218 case_sensitive);
219 if (res >= 0)
220 /* Success. */
221 return res;
223 /* We failed. Explain why. */
224 argmatch_invalid (context, arg, res);
225 argmatch_valid (arglist, vallist, valsize);
226 (*exit_fn) ();
228 return -1; /* To please the compilers. */
231 /* Look for VALUE in VALLIST, an array of objects of size VALSIZE and
232 return the first corresponding argument in ARGLIST */
233 const char *
234 argmatch_to_argument (const char *value,
235 const char *const *arglist,
236 const char *vallist, size_t valsize)
238 int i;
240 for (i = 0; arglist[i]; i++)
241 if (!memcmp (value, vallist + valsize * i, valsize))
242 return arglist[i];
243 return NULL;
246 #ifdef TEST
248 * Based on "getversion.c" by David MacKenzie <djm@gnu.ai.mit.edu>
250 char *program_name;
251 extern const char *getenv ();
253 /* When to make backup files. */
254 enum backup_type
256 /* Never make backups. */
257 none,
259 /* Make simple backups of every file. */
260 simple,
262 /* Make numbered backups of files that already have numbered backups,
263 and simple backups of the others. */
264 numbered_existing,
266 /* Make numbered backups of every file. */
267 numbered
270 /* Two tables describing arguments (keys) and their corresponding
271 values */
272 static const char *const backup_args[] =
274 "no", "none", "off",
275 "simple", "never",
276 "existing", "nil",
277 "numbered", "t",
281 static const enum backup_type backup_vals[] =
283 none, none, none,
284 simple, simple,
285 numbered_existing, numbered_existing,
286 numbered, numbered
290 main (int argc, const char *const *argv)
292 const char *cp;
293 enum backup_type backup_type = none;
295 program_name = (char *) argv[0];
297 if (argc > 2)
299 fprintf (stderr, "Usage: %s [VERSION_CONTROL]\n", program_name);
300 exit (1);
303 if ((cp = getenv ("VERSION_CONTROL")))
304 backup_type = XARGCASEMATCH ("$VERSION_CONTROL", cp,
305 backup_args, backup_vals);
307 if (argc == 2)
308 backup_type = XARGCASEMATCH (program_name, argv[1],
309 backup_args, backup_vals);
311 printf ("The version control is `%s'\n",
312 ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
314 return 0;
316 #endif