]> Dogcows Code - chaz/tar/blob - lib/argmatch.c
1.13.25
[chaz/tar] / lib / argmatch.c
1 /* argmatch.c -- find a match for a string in an array
2 Copyright (C) 1990, 1998, 1999 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 <string.h>
26 #endif
27
28 #if HAVE_LOCALE_H
29 # include <locale.h>
30 #endif
31
32 #if ENABLE_NLS
33 # include <libintl.h>
34 # define _(Text) gettext (Text)
35 #else
36 # define _(Text) Text
37 #endif
38
39 #include "error.h"
40 #include "quotearg.h"
41
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
48
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
56
57 /* Non failing version of argmatch call this function after failing. */
58 #ifndef ARGMATCH_DIE
59 # define ARGMATCH_DIE exit (EXIT_FAILURE)
60 #endif
61
62 #ifdef ARGMATCH_DIE_DECL
63 ARGMATCH_DIE_DECL;
64 #endif
65
66 static void
67 __argmatch_die (void)
68 {
69 ARGMATCH_DIE;
70 }
71
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;
75
76 \f
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.
82
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'. */
88
89 static int
90 __argmatch_internal (const char *arg, const char *const *arglist,
91 const char *vallist, size_t valsize,
92 int case_sensitive)
93 {
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). */
98
99 arglen = strlen (arg);
100
101 /* Test all elements for either exact match or abbreviated matches. */
102 for (i = 0; arglist[i]; i++)
103 {
104 if (case_sensitive
105 ? !strncmp (arglist[i], arg, arglen)
106 : !strncasecmp (arglist[i], arg, arglen))
107 {
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
115 {
116 /* Second nonexact match found. */
117 if (vallist == NULL
118 || memcmp (vallist + valsize * matchind,
119 vallist + valsize * i, valsize))
120 {
121 /* There is a real ambiguity, or we could not
122 disambiguate. */
123 ambiguous = 1;
124 }
125 }
126 }
127 }
128 if (ambiguous)
129 return -2;
130 else
131 return matchind;
132 }
133
134 /* argmatch - case sensitive version */
135 int
136 argmatch (const char *arg, const char *const *arglist,
137 const char *vallist, size_t valsize)
138 {
139 return __argmatch_internal (arg, arglist, vallist, valsize, 1);
140 }
141
142 /* argcasematch - case insensitive version */
143 int
144 argcasematch (const char *arg, const char *const *arglist,
145 const char *vallist, size_t valsize)
146 {
147 return __argmatch_internal (arg, arglist, vallist, valsize, 0);
148 }
149
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. */
154
155 void
156 argmatch_invalid (const char *context, const char *value, int problem)
157 {
158 enum quoting_style saved_quoting_style;
159 char const *format;
160
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);
165
166 format = (problem == -1
167 ? _("invalid argument `%s' for `%s'")
168 : _("ambiguous argument `%s' for `%s'"));
169
170 error (0, 0, format, quotearg (value), context);
171
172 set_quoting_style (NULL, saved_quoting_style);
173 }
174
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)
182 {
183 int i;
184 const char *last_val = NULL;
185
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))
192 {
193 fprintf (stderr, "\n - `%s'", arglist[i]);
194 last_val = vallist + valsize * i;
195 }
196 else
197 {
198 fprintf (stderr, ", `%s'", arglist[i]);
199 }
200 putc ('\n', stderr);
201 }
202
203 /* Never failing versions of the previous functions.
204
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. */
208
209 int
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)
215 {
216 int res = __argmatch_internal (arg, arglist,
217 vallist, valsize,
218 case_sensitive);
219 if (res >= 0)
220 /* Success. */
221 return res;
222
223 /* We failed. Explain why. */
224 argmatch_invalid (context, arg, res);
225 argmatch_valid (arglist, vallist, valsize);
226 (*exit_fn) ();
227
228 return -1; /* To please the compilers. */
229 }
230
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)
237 {
238 int i;
239
240 for (i = 0; arglist[i]; i++)
241 if (!memcmp (value, vallist + valsize * i, valsize))
242 return arglist[i];
243 return NULL;
244 }
245
246 #ifdef TEST
247 /*
248 * Based on "getversion.c" by David MacKenzie <djm@gnu.ai.mit.edu>
249 */
250 char *program_name;
251 extern const char *getenv ();
252
253 /* When to make backup files. */
254 enum backup_type
255 {
256 /* Never make backups. */
257 none,
258
259 /* Make simple backups of every file. */
260 simple,
261
262 /* Make numbered backups of files that already have numbered backups,
263 and simple backups of the others. */
264 numbered_existing,
265
266 /* Make numbered backups of every file. */
267 numbered
268 };
269
270 /* Two tables describing arguments (keys) and their corresponding
271 values */
272 static const char *const backup_args[] =
273 {
274 "no", "none", "off",
275 "simple", "never",
276 "existing", "nil",
277 "numbered", "t",
278 0
279 };
280
281 static const enum backup_type backup_vals[] =
282 {
283 none, none, none,
284 simple, simple,
285 numbered_existing, numbered_existing,
286 numbered, numbered
287 };
288
289 int
290 main (int argc, const char *const *argv)
291 {
292 const char *cp;
293 enum backup_type backup_type = none;
294
295 program_name = (char *) argv[0];
296
297 if (argc > 2)
298 {
299 fprintf (stderr, "Usage: %s [VERSION_CONTROL]\n", program_name);
300 exit (1);
301 }
302
303 if ((cp = getenv ("VERSION_CONTROL")))
304 backup_type = XARGCASEMATCH ("$VERSION_CONTROL", cp,
305 backup_args, backup_vals);
306
307 if (argc == 2)
308 backup_type = XARGCASEMATCH (program_name, argv[1],
309 backup_args, backup_vals);
310
311 printf ("The version control is `%s'\n",
312 ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
313
314 return 0;
315 }
316 #endif
This page took 0.045612 seconds and 4 git commands to generate.