]> git.ipfire.org Git - thirdparty/util-linux.git/blame - hwclock/shhopt.c
Imported from util-linux-2.10s tarball.
[thirdparty/util-linux.git] / hwclock / shhopt.c
CommitLineData
fd6b7a7f
KZ
1/* $Id: shhopt.c,v 2.2 1997/07/06 23:11:55 aebr Exp $ */
2/**************************************************************************
3 *
4 * FILE shhopt.c
5 *
6 * DESCRIPTION Functions for parsing command line arguments. Values
7 * of miscellaneous types may be stored in variables,
8 * or passed to functions as specified.
9 *
10 * REQUIREMENTS Some systems lack the ANSI C -function strtoul. If your
11 * system is one of those, you'll ned to write one yourself,
12 * or get the GNU liberty-library (from prep.ai.mit.edu).
13 *
14 * WRITTEN BY Sverre H. Huseby <sverrehu@ifi.uio.no>
15 *
16 **************************************************************************/
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <stdarg.h>
21#include <string.h>
22#include <ctype.h>
23#include <limits.h>
24#include <errno.h>
25
26#include "shhopt.h"
7eda085c 27#include "nls.h"
fd6b7a7f
KZ
28
29/**************************************************************************
30 * *
31 * P R I V A T E D A T A *
32 * *
33 **************************************************************************/
34
35static void optFatalFunc(const char *, ...);
36static void (*optFatal)(const char *format, ...) = optFatalFunc;
37
38
39
40/**************************************************************************
41 * *
42 * P R I V A T E F U N C T I O N S *
43 * *
44 **************************************************************************/
45
46/*-------------------------------------------------------------------------
47 *
48 * NAME optFatalFunc
49 *
50 * FUNCTION Show given message and abort the program.
51 *
52 * INPUT format, ...
53 * Arguments used as with printf().
54 *
55 * RETURNS Never returns. The program is aborted.
56 *
57 */
58void optFatalFunc(const char *format, ...)
59{
60 va_list ap;
61
62 fflush(stdout);
63 va_start(ap, format);
64 vfprintf(stderr, format, ap);
65 va_end(ap);
66 exit(99);
67}
68
69
70
71/*-------------------------------------------------------------------------
72 *
73 * NAME optStructCount
74 *
75 * FUNCTION Get number of options in a optStruct.
76 *
77 * INPUT opt array of possible options.
78 *
79 * RETURNS Number of options in the given array.
80 *
81 * DESCRIPTION Count elements in an optStruct-array. The strcture must
82 * be ended using an element of type OPT_END.
83 *
84 */
85static int optStructCount(const optStruct opt[])
86{
87 int ret = 0;
88
89 while (opt[ret].type != OPT_END)
90 ++ret;
91 return ret;
92}
93
94
95
96/*-------------------------------------------------------------------------
97 *
98 * NAME optMatch
99 *
100 * FUNCTION Find a matching option.
101 *
102 * INPUT opt array of possible options.
103 * s string to match, without `-' or `--'.
104 * lng match long option, otherwise short.
105 *
106 * RETURNS Index to the option if found, -1 if not found.
107 *
108 * DESCRIPTION Short options are matched from the first character in
109 * the given string.
110 *
111 */
112static int optMatch(const optStruct opt[], const char *s, int lng)
113{
114 int nopt, q, matchlen = 0;
115 char *p;
116
117 nopt = optStructCount(opt);
118 if (lng) {
119 if ((p = strchr(s, '=')) != NULL)
120 matchlen = p - s;
121 else
122 matchlen = strlen(s);
123 }
124 for (q = 0; q < nopt; q++) {
125 if (lng) {
126 if (!opt[q].longName)
127 continue;
128 if (strncmp(s, opt[q].longName, matchlen) == 0)
129 return q;
130 } else {
131 if (!opt[q].shortName)
132 continue;
133 if (*s == opt[q].shortName)
134 return q;
135 }
136 }
137 return -1;
138}
139
140
141
142/*-------------------------------------------------------------------------
143 *
144 * NAME optString
145 *
146 * FUNCTION Return a (static) string with the option name.
147 *
148 * INPUT opt the option to stringify.
149 * lng is it a long option?
150 *
151 * RETURNS Pointer to static string.
152 *
153 */
154static char *optString(const optStruct *opt, int lng)
155{
156 static char ret[31];
157
158 if (lng) {
159 strcpy(ret, "--");
160 strncpy(ret + 2, opt->longName, 28);
161 } else {
162 ret[0] = '-';
163 ret[1] = opt->shortName;
164 ret[2] = '\0';
165 }
166 return ret;
167}
168
169
170
171/*-------------------------------------------------------------------------
172 *
173 * NAME optNeedsArgument
174 *
175 * FUNCTION Check if an option requires an argument.
176 *
177 * INPUT opt the option to check.
178 *
179 * RETURNS Boolean value.
180 *
181 */
182static int optNeedsArgument(const optStruct *opt)
183{
184 return opt->type == OPT_STRING
185 || opt->type == OPT_INT
186 || opt->type == OPT_UINT
187 || opt->type == OPT_LONG
188 || opt->type == OPT_ULONG;
189}
190
191
192
193/*-------------------------------------------------------------------------
194 *
195 * NAME argvRemove
196 *
197 * FUNCTION Remove an entry from an argv-array.
198 *
199 * INPUT argc pointer to number of options.
200 * argv array of option-/argument-strings.
201 * i index of option to remove.
202 *
203 * OUTPUT argc new argument count.
204 * argv array with given argument removed.
205 *
206 */
207static void argvRemove(int *argc, char *argv[], int i)
208{
209 if (i >= *argc)
210 return;
211 while (i++ < *argc)
212 argv[i - 1] = argv[i];
213 --*argc;
214}
215
216
217
218/*-------------------------------------------------------------------------
219 *
220 * NAME optExecute
221 *
222 * FUNCTION Perform the action of an option.
223 *
224 * INPUT opt array of possible options.
225 * arg argument to option, if it applies.
226 * lng was the option given as a long option?
227 *
228 * RETURNS Nothing. Aborts in case of error.
229 *
230 */
22853e4a 231static void optExecute(const optStruct *opt, char *arg, int lng)
fd6b7a7f
KZ
232{
233 switch (opt->type) {
234 case OPT_FLAG:
235 if (opt->flags & OPT_CALLFUNC)
236 ((void (*)(void)) opt->arg)();
237 else
238 *((int *) opt->arg) = 1;
239 break;
240
241 case OPT_STRING:
242 if (opt->flags & OPT_CALLFUNC)
243 ((void (*)(char *)) opt->arg)(arg);
244 else
245 *((char **) opt->arg) = arg;
246 break;
247
248 case OPT_INT:
249 case OPT_LONG: {
250 long tmp;
251 char *e;
252
253 tmp = strtol(arg, &e, 10);
254 if (*e)
7eda085c 255 optFatal(_("invalid number `%s'\n"), arg);
fd6b7a7f
KZ
256 if (errno == ERANGE
257 || (opt->type == OPT_INT && (tmp > INT_MAX || tmp < INT_MIN)))
7eda085c 258 optFatal(_("number `%s' to `%s' out of range\n"),
fd6b7a7f
KZ
259 arg, optString(opt, lng));
260 if (opt->type == OPT_INT) {
261 if (opt->flags & OPT_CALLFUNC)
262 ((void (*)(int)) opt->arg)((int) tmp);
263 else
264 *((int *) opt->arg) = (int) tmp;
265 } else /* OPT_LONG */ {
266 if (opt->flags & OPT_CALLFUNC)
267 ((void (*)(long)) opt->arg)(tmp);
268 else
269 *((long *) opt->arg) = tmp;
270 }
271 break;
272 }
273
274 case OPT_UINT:
275 case OPT_ULONG: {
276 unsigned long tmp;
277 char *e;
278
279 tmp = strtoul(arg, &e, 10);
280 if (*e)
7eda085c 281 optFatal(_("invalid number `%s'\n"), arg);
fd6b7a7f
KZ
282 if (errno == ERANGE
283 || (opt->type == OPT_UINT && tmp > UINT_MAX))
7eda085c 284 optFatal(_("number `%s' to `%s' out of range\n"),
fd6b7a7f
KZ
285 arg, optString(opt, lng));
286 if (opt->type == OPT_UINT) {
287 if (opt->flags & OPT_CALLFUNC)
288 ((void (*)(unsigned)) opt->arg)((unsigned) tmp);
289 else
290 *((unsigned *) opt->arg) = (unsigned) tmp;
291 } else /* OPT_ULONG */ {
292 if (opt->flags & OPT_CALLFUNC)
293 ((void (*)(unsigned long)) opt->arg)(tmp);
294 else
295 *((unsigned long *) opt->arg) = tmp;
296 }
297 break;
298 }
299
300 default:
301 break;
302 }
303}
304
305
306
307/**************************************************************************
308 * *
309 * P U B L I C F U N C T I O N S *
310 * *
311 **************************************************************************/
312
313/*-------------------------------------------------------------------------
314 *
315 * NAME optSetFatalFunc
316 *
317 * FUNCTION Set function used to display error message and exit.
318 *
319 * SYNOPSIS #include "shhmsg.h"
320 * void optSetFatalFunc(void (*f)(const char *, ...));
321 *
322 * INPUT f function accepting printf()'like parameters,
323 * that _must_ abort the program.
324 *
325 */
326void optSetFatalFunc(void (*f)(const char *, ...))
327{
328 optFatal = f;
329}
330
331
332
333/*-------------------------------------------------------------------------
334 *
335 * NAME optParseOptions
336 *
337 * FUNCTION Parse commandline options.
338 *
339 * SYNOPSIS #include "shhopt.h"
340 * void optParseOptions(int *argc, char *argv[],
341 * const optStruct opt[], int allowNegNum);
342 *
343 * INPUT argc Pointer to number of options.
344 * argv Array of option-/argument-strings.
345 * opt Array of possible options.
346 * allowNegNum
347 * a negative number is not to be taken as
348 * an option.
349 *
350 * OUTPUT argc new argument count.
351 * argv array with arguments removed.
352 *
353 * RETURNS Nothing. Aborts in case of error.
354 *
355 * DESCRIPTION This function checks each option in the argv-array
356 * against strings in the opt-array, and `executes' any
357 * matching action. Any arguments to the options are
358 * extracted and stored in the variables or passed to
359 * functions pointed to by entries in opt.
360 *
361 * Options and arguments used are removed from the argv-
362 * array, and argc is decreased accordingly.
363 *
364 * Any error leads to program abortion.
365 *
366 */
367void optParseOptions(int *argc, char *argv[],
368 const optStruct opt[], int allowNegNum)
369{
370 int ai, /* argv index. */
371 optarg, /* argv index of option argument, or -1 if none. */
372 mi, /* Match index in opt. */
373 done;
374 char *arg, /* Pointer to argument to an option. */
375 *o, /* pointer to an option character */
376 *p;
377
378 /*
379 * Loop through all arguments.
380 */
381 for (ai = 0; ai < *argc; ) {
382 /*
383 * "--" indicates that the rest of the argv-array does not
384 * contain options.
385 */
386 if (strcmp(argv[ai], "--") == 0) {
387 argvRemove(argc, argv, ai);
388 break;
389 }
390
391 if (allowNegNum && argv[ai][0] == '-' && isdigit(argv[ai][1])) {
392 ++ai;
393 continue;
394 } else if (strncmp(argv[ai], "--", 2) == 0) {
395 /* long option */
396 /* find matching option */
397 if ((mi = optMatch(opt, argv[ai] + 2, 1)) < 0)
7eda085c 398 optFatal(_("unrecognized option `%s'\n"), argv[ai]);
fd6b7a7f
KZ
399
400 /* possibly locate the argument to this option. */
401 arg = NULL;
402 if ((p = strchr(argv[ai], '=')) != NULL)
403 arg = p + 1;
404
405 /* does this option take an argument? */
406 optarg = -1;
407 if (optNeedsArgument(&opt[mi])) {
408 /* option needs an argument. find it. */
409 if (!arg) {
410 if ((optarg = ai + 1) == *argc)
7eda085c 411 optFatal(_("option `%s' requires an argument\n"),
fd6b7a7f
KZ
412 optString(&opt[mi], 1));
413 arg = argv[optarg];
414 }
415 } else {
416 if (arg)
7eda085c 417 optFatal(_("option `%s' doesn't allow an argument\n"),
fd6b7a7f
KZ
418 optString(&opt[mi], 1));
419 }
420 /* perform the action of this option. */
421 optExecute(&opt[mi], arg, 1);
422 /* remove option and any argument from the argv-array. */
423 if (optarg >= 0)
424 argvRemove(argc, argv, ai);
425 argvRemove(argc, argv, ai);
426 } else if (*argv[ai] == '-') {
427 /* A dash by itself is not considered an option. */
428 if (argv[ai][1] == '\0') {
429 ++ai;
430 continue;
431 }
432 /* Short option(s) following */
433 o = argv[ai] + 1;
434 done = 0;
435 optarg = -1;
436 while (*o && !done) {
437 /* find matching option */
438 if ((mi = optMatch(opt, o, 0)) < 0)
7eda085c 439 optFatal(_("unrecognized option `-%c'\n"), *o);
fd6b7a7f
KZ
440
441 /* does this option take an argument? */
442 optarg = -1;
443 arg = NULL;
444 if (optNeedsArgument(&opt[mi])) {
445 /* option needs an argument. find it. */
446 arg = o + 1;
447 if (!*arg) {
448 if ((optarg = ai + 1) == *argc)
7eda085c 449 optFatal(_("option `%s' requires an argument\n"),
fd6b7a7f
KZ
450 optString(&opt[mi], 0));
451 arg = argv[optarg];
452 }
453 done = 1;
454 }
455 /* perform the action of this option. */
456 optExecute(&opt[mi], arg, 0);
457 ++o;
458 }
459 /* remove option and any argument from the argv-array. */
460 if (optarg >= 0)
461 argvRemove(argc, argv, ai);
462 argvRemove(argc, argv, ai);
463 } else {
464 /* a non-option argument */
465 ++ai;
466 }
467 }
468}