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