]> git.saurik.com Git - bison.git/blob - lib/argmatch.c
Typo.
[bison.git] / lib / argmatch.c
1 /* argmatch.c -- find a match for a string in an array
2 Copyright (C) 1990, 1998, 1999, 2001 Free Software Foundation, Inc.
3
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.
8
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.
13
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. */
17
18 /* Written by David MacKenzie <djm@ai.mit.edu>
19 Modified by Akim Demaille <demaille@inf.enst.fr> */
20
21 #include "argmatch.h"
22
23 #include <stdio.h>
24 #ifdef STDC_HEADERS
25 # include <stdlib.h>
26 # include <string.h>
27 #endif
28
29 #if HAVE_LOCALE_H
30 # include <locale.h>
31 #endif
32
33 #if ENABLE_NLS
34 # include <libintl.h>
35 # define _(Text) gettext (Text)
36 #else
37 # define _(Text) Text
38 #endif
39
40 #include "error.h"
41 #include "quotearg.h"
42 #include "quote.h"
43
44 /* When reporting an invalid argument, show nonprinting characters
45 by using the quoting style ARGMATCH_QUOTING_STYLE. Do not use
46 literal_quoting_style. */
47 #ifndef ARGMATCH_QUOTING_STYLE
48 # define ARGMATCH_QUOTING_STYLE locale_quoting_style
49 #endif
50
51 /* The following test is to work around the gross typo in
52 systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE
53 is defined to 0, not 1. */
54 #if !EXIT_FAILURE
55 # undef EXIT_FAILURE
56 # define EXIT_FAILURE 1
57 #endif
58
59 /* Non failing version of argmatch call this function after failing. */
60 #ifndef ARGMATCH_DIE
61 # define ARGMATCH_DIE exit (EXIT_FAILURE)
62 #endif
63
64 #ifdef ARGMATCH_DIE_DECL
65 ARGMATCH_DIE_DECL;
66 #endif
67
68 static void
69 __argmatch_die (void)
70 {
71 ARGMATCH_DIE;
72 }
73
74 /* Used by XARGMATCH and XARGCASEMATCH. See description in argmatch.h.
75 Default to __argmatch_die, but allow caller to change this at run-time. */
76 argmatch_exit_fn argmatch_die = __argmatch_die;
77
78 \f
79 /* If ARG is an unambiguous match for an element of the
80 null-terminated array ARGLIST, return the index in ARGLIST
81 of the matched element, else -1 if it does not match any element
82 or -2 if it is ambiguous (is a prefix of more than one element).
83 If SENSITIVE, comparison is case sensitive.
84
85 If VALLIST is none null, use it to resolve ambiguities limited to
86 synonyms, i.e., for
87 "yes", "yop" -> 0
88 "no", "nope" -> 1
89 "y" is a valid argument, for `0', and "n" for `1'. */
90
91 static int
92 __argmatch_internal (const char *arg, const char *const *arglist,
93 const char *vallist, size_t valsize,
94 int case_sensitive)
95 {
96 int i; /* Temporary index in ARGLIST. */
97 size_t arglen; /* Length of ARG. */
98 int matchind = -1; /* Index of first nonexact match. */
99 int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */
100
101 arglen = strlen (arg);
102
103 /* Test all elements for either exact match or abbreviated matches. */
104 for (i = 0; arglist[i]; i++)
105 {
106 if (case_sensitive
107 ? !strncmp (arglist[i], arg, arglen)
108 : !strncasecmp (arglist[i], arg, arglen))
109 {
110 if (strlen (arglist[i]) == arglen)
111 /* Exact match found. */
112 return i;
113 else if (matchind == -1)
114 /* First nonexact match found. */
115 matchind = i;
116 else
117 {
118 /* Second nonexact match found. */
119 if (vallist == NULL
120 || memcmp (vallist + valsize * matchind,
121 vallist + valsize * i, valsize))
122 {
123 /* There is a real ambiguity, or we could not
124 disambiguate. */
125 ambiguous = 1;
126 }
127 }
128 }
129 }
130 if (ambiguous)
131 return -2;
132 else
133 return matchind;
134 }
135
136 /* argmatch - case sensitive version */
137 int
138 argmatch (const char *arg, const char *const *arglist,
139 const char *vallist, size_t valsize)
140 {
141 return __argmatch_internal (arg, arglist, vallist, valsize, 1);
142 }
143
144 /* argcasematch - case insensitive version */
145 int
146 argcasematch (const char *arg, const char *const *arglist,
147 const char *vallist, size_t valsize)
148 {
149 return __argmatch_internal (arg, arglist, vallist, valsize, 0);
150 }
151
152 /* Error reporting for argmatch.
153 CONTEXT is a description of the type of entity that was being matched.
154 VALUE is the invalid value that was given.
155 PROBLEM is the return value from argmatch. */
156
157 void
158 argmatch_invalid (const char *context, const char *value, int problem)
159 {
160 char const *format = (problem == -1
161 ? _("invalid argument %s for %s")
162 : _("ambiguous argument %s for %s"));
163
164 error (0, 0, format, quotearg_n_style (0, ARGMATCH_QUOTING_STYLE, value),
165 quote_n (1, context));
166 }
167
168 /* List the valid arguments for argmatch.
169 ARGLIST is the same as in argmatch.
170 VALLIST is a pointer to an array of values.
171 VALSIZE is the size of the elements of VALLIST */
172 void
173 argmatch_valid (const char *const *arglist,
174 const char *vallist, size_t valsize)
175 {
176 int i;
177 const char *last_val = NULL;
178
179 /* We try to put synonyms on the same line. The assumption is that
180 synonyms follow each other */
181 fprintf (stderr, _("Valid arguments are:"));
182 for (i = 0; arglist[i]; i++)
183 if ((i == 0)
184 || memcmp (last_val, vallist + valsize * i, valsize))
185 {
186 fprintf (stderr, "\n - `%s'", arglist[i]);
187 last_val = vallist + valsize * i;
188 }
189 else
190 {
191 fprintf (stderr, ", `%s'", arglist[i]);
192 }
193 putc ('\n', stderr);
194 }
195
196 /* Never failing versions of the previous functions.
197
198 CONTEXT is the context for which argmatch is called (e.g.,
199 "--version-control", or "$VERSION_CONTROL" etc.). Upon failure,
200 calls the (supposed never to return) function EXIT_FN. */
201
202 int
203 __xargmatch_internal (const char *context,
204 const char *arg, const char *const *arglist,
205 const char *vallist, size_t valsize,
206 int case_sensitive,
207 argmatch_exit_fn exit_fn)
208 {
209 int res = __argmatch_internal (arg, arglist,
210 vallist, valsize,
211 case_sensitive);
212 if (res >= 0)
213 /* Success. */
214 return res;
215
216 /* We failed. Explain why. */
217 argmatch_invalid (context, arg, res);
218 argmatch_valid (arglist, vallist, valsize);
219 (*exit_fn) ();
220
221 return -1; /* To please the compilers. */
222 }
223
224 /* Look for VALUE in VALLIST, an array of objects of size VALSIZE and
225 return the first corresponding argument in ARGLIST */
226 const char *
227 argmatch_to_argument (const char *value,
228 const char *const *arglist,
229 const char *vallist, size_t valsize)
230 {
231 int i;
232
233 for (i = 0; arglist[i]; i++)
234 if (!memcmp (value, vallist + valsize * i, valsize))
235 return arglist[i];
236 return NULL;
237 }
238
239 #ifdef TEST
240 /*
241 * Based on "getversion.c" by David MacKenzie <djm@gnu.ai.mit.edu>
242 */
243 char *program_name;
244 extern const char *getenv ();
245
246 /* When to make backup files. */
247 enum backup_type
248 {
249 /* Never make backups. */
250 none,
251
252 /* Make simple backups of every file. */
253 simple,
254
255 /* Make numbered backups of files that already have numbered backups,
256 and simple backups of the others. */
257 numbered_existing,
258
259 /* Make numbered backups of every file. */
260 numbered
261 };
262
263 /* Two tables describing arguments (keys) and their corresponding
264 values */
265 static const char *const backup_args[] =
266 {
267 "no", "none", "off",
268 "simple", "never",
269 "existing", "nil",
270 "numbered", "t",
271 0
272 };
273
274 static const enum backup_type backup_vals[] =
275 {
276 none, none, none,
277 simple, simple,
278 numbered_existing, numbered_existing,
279 numbered, numbered
280 };
281
282 int
283 main (int argc, const char *const *argv)
284 {
285 const char *cp;
286 enum backup_type backup_type = none;
287
288 program_name = (char *) argv[0];
289
290 if (argc > 2)
291 {
292 fprintf (stderr, "Usage: %s [VERSION_CONTROL]\n", program_name);
293 exit (1);
294 }
295
296 if ((cp = getenv ("VERSION_CONTROL")))
297 backup_type = XARGCASEMATCH ("$VERSION_CONTROL", cp,
298 backup_args, backup_vals);
299
300 if (argc == 2)
301 backup_type = XARGCASEMATCH (program_name, argv[1],
302 backup_args, backup_vals);
303
304 printf ("The version control is `%s'\n",
305 ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
306
307 return 0;
308 }
309 #endif