1 /* $Id: shhopt.c 1418 2002-07-22 17:06:19Z schoenw $ */
2 /*------------------------------------------------------------------------
5 | DESCRIPTION Functions for parsing command line arguments. Values
6 | of miscellaneous types may be stored in variables,
7 | or passed to functions as specified.
9 | REQUIREMENTS Some systems lack the ANSI C -function strtoul. If your
10 | system is one of those, you'll ned to write one yourself,
11 | or get the GNU liberty-library (from prep.ai.mit.edu).
13 | WRITTEN BY Sverre H. Huseby <sverrehu@online.no>
14 +----------------------------------------------------------------------*/
26 /*-----------------------------------------------------------------------+
28 +-----------------------------------------------------------------------*/
30 static void optFatalFunc(const char *, ...);
31 static void (*optFatal)(const char *format, ...) = optFatalFunc;
33 /*-----------------------------------------------------------------------+
35 +-----------------------------------------------------------------------*/
37 /*------------------------------------------------------------------------
40 | FUNCTION Show given message and abort the program.
43 | Arguments used as with printf().
45 | RETURNS Never returns. The program is aborted.
48 optFatalFunc(const char *format, ...)
54 vfprintf(stderr, format, ap);
59 /*------------------------------------------------------------------------
62 | FUNCTION Get number of options in a optStruct.
64 | INPUT opt array of possible options.
66 | RETURNS Number of options in the given array.
68 | DESCRIPTION Count elements in an optStruct-array. The strcture must
69 | be ended using an element of type OPT_END.
72 optStructCount(optStruct opt[])
76 while (opt[ret].type != OPT_END)
81 /*------------------------------------------------------------------------
84 | FUNCTION Find a matching option.
86 | INPUT opt array of possible options.
87 | s string to match, without `-' or `--'.
88 | lng match long option, otherwise short.
90 | RETURNS Index to the option if found, -1 if not found.
92 | DESCRIPTION Short options are matched from the first character in
96 optMatch(optStruct opt[], const char *s, int lng)
102 nopt = optStructCount(opt);
104 if ((p = strchr(s, '=')) != NULL)
107 matchlen = strlen(s);
109 for (q = 0; q < nopt; q++) {
111 if (!opt[q].longName)
113 if (strncmp(s, opt[q].longName, matchlen) == 0)
116 if (!opt[q].shortName)
118 if (*s == opt[q].shortName)
125 /*------------------------------------------------------------------------
128 | FUNCTION Return a (static) string with the option name.
130 | INPUT opt the option to stringify.
131 | lng is it a long option?
133 | RETURNS Pointer to static string.
136 optString(optStruct *opt, int lng)
142 strncpy(ret + 2, opt->longName, 28);
145 ret[1] = opt->shortName;
151 /*------------------------------------------------------------------------
152 | NAME optNeedsArgument
154 | FUNCTION Check if an option requires an argument.
156 | INPUT opt the option to check.
158 | RETURNS Boolean value.
161 optNeedsArgument(optStruct *opt)
163 return opt->type == OPT_STRING
164 || opt->type == OPT_INT
165 || opt->type == OPT_UINT
166 || opt->type == OPT_LONG
167 || opt->type == OPT_ULONG;
170 /*------------------------------------------------------------------------
173 | FUNCTION Remove an entry from an argv-array.
175 | INPUT argc pointer to number of options.
176 | argv array of option-/argument-strings.
177 | i index of option to remove.
179 | OUTPUT argc new argument count.
180 | argv array with given argument removed.
183 argvRemove(int *argc, char *argv[], int i)
188 argv[i - 1] = argv[i];
192 /*------------------------------------------------------------------------
195 | FUNCTION Perform the action of an option.
197 | INPUT opt array of possible options.
198 | arg argument to option, if it applies.
199 | lng was the option given as a long option?
201 | RETURNS Nothing. Aborts in case of error.
204 optExecute(optStruct *opt, char *arg, int lng)
208 if (opt->flags & OPT_CALLFUNC)
209 ((void (*)(void)) opt->arg)();
211 *((int *) opt->arg) = 1;
215 if (opt->flags & OPT_CALLFUNC)
216 ((void (*)(char *)) opt->arg)(arg);
218 *((char **) opt->arg) = arg;
226 tmp = strtol(arg, &e, 10);
228 optFatal("invalid number `%s'\n", arg);
230 || (opt->type == OPT_INT && (tmp > INT_MAX || tmp < INT_MIN)))
231 optFatal("number `%s' to `%s' out of range\n",
232 arg, optString(opt, lng));
233 if (opt->type == OPT_INT) {
234 if (opt->flags & OPT_CALLFUNC)
235 ((void (*)(int)) opt->arg)((int) tmp);
237 *((int *) opt->arg) = (int) tmp;
238 } else /* OPT_LONG */ {
239 if (opt->flags & OPT_CALLFUNC)
240 ((void (*)(long)) opt->arg)(tmp);
242 *((long *) opt->arg) = tmp;
252 tmp = strtoul(arg, &e, 10);
254 optFatal("invalid number `%s'\n", arg);
256 || (opt->type == OPT_UINT && tmp > UINT_MAX))
257 optFatal("number `%s' to `%s' out of range\n",
258 arg, optString(opt, lng));
259 if (opt->type == OPT_UINT) {
260 if (opt->flags & OPT_CALLFUNC)
261 ((void (*)(unsigned)) opt->arg)((unsigned) tmp);
263 *((unsigned *) opt->arg) = (unsigned) tmp;
264 } else /* OPT_ULONG */ {
265 if (opt->flags & OPT_CALLFUNC)
266 ((void (*)(unsigned long)) opt->arg)(tmp);
268 *((unsigned long *) opt->arg) = tmp;
278 /*-----------------------------------------------------------------------+
280 +-----------------------------------------------------------------------*/
282 /*------------------------------------------------------------------------
283 | NAME optSetFatalFunc
285 | FUNCTION Set function used to display error message and exit.
287 | SYNOPSIS #include "shhopt.h"
288 | void optSetFatalFunc(void (*f)(const char *, ...));
290 | INPUT f function accepting printf()'like parameters,
291 | that _must_ abort the program.
294 optSetFatalFunc(void (*f)(const char *, ...))
299 /*------------------------------------------------------------------------
300 | NAME optParseOptions
302 | FUNCTION Parse commandline options.
304 | SYNOPSIS #include "shhopt.h"
305 | void optParseOptions(int *argc, char *argv[],
306 | optStruct opt[], int allowNegNum);
308 | INPUT argc Pointer to number of options.
309 | argv Array of option-/argument-strings.
310 | opt Array of possible options.
312 | a negative number is not to be taken as
315 | OUTPUT argc new argument count.
316 | argv array with arguments removed.
318 | RETURNS Nothing. Aborts in case of error.
320 | DESCRIPTION This function checks each option in the argv-array
321 | against strings in the opt-array, and `executes' any
322 | matching action. Any arguments to the options are
323 | extracted and stored in the variables or passed to
324 | functions pointed to by entries in opt.
326 | Options and arguments used are removed from the argv-
327 | array, and argc is decreased accordingly.
329 | Any error leads to program abortion.
332 optParseOptions(int *argc, char *argv[], optStruct opt[], int allowNegNum)
334 int ai, /* argv index. */
335 optarg, /* argv index of option argument, or -1 if none. */
336 mi, /* Match index in opt. */
338 char *arg, /* Pointer to argument to an option. */
339 *o, /* pointer to an option character */
343 * Loop through all arguments.
345 for (ai = 0; ai < *argc; ) {
347 * "--" indicates that the rest of the argv-array does not
350 if (strcmp(argv[ai], "--") == 0) {
351 argvRemove(argc, argv, ai);
355 if (allowNegNum && argv[ai][0] == '-' && isdigit(argv[ai][1])) {
358 } else if (strncmp(argv[ai], "--", 2) == 0) {
360 /* find matching option */
361 if ((mi = optMatch(opt, argv[ai] + 2, 1)) < 0)
362 optFatal("unrecognized option `%s'\n", argv[ai]);
364 /* possibly locate the argument to this option. */
366 if ((p = strchr(argv[ai], '=')) != NULL)
369 /* does this option take an argument? */
371 if (optNeedsArgument(&opt[mi])) {
372 /* option needs an argument. find it. */
374 if ((optarg = ai + 1) == *argc)
375 optFatal("option `%s' requires an argument\n",
376 optString(&opt[mi], 1));
381 optFatal("option `%s' doesn't allow an argument\n",
382 optString(&opt[mi], 1));
384 /* perform the action of this option. */
385 optExecute(&opt[mi], arg, 1);
386 /* remove option and any argument from the argv-array. */
388 argvRemove(argc, argv, ai);
389 argvRemove(argc, argv, ai);
390 } else if (*argv[ai] == '-') {
391 /* A dash by itself is not considered an option. */
392 if (argv[ai][1] == '\0') {
396 /* Short option(s) following */
400 while (*o && !done) {
401 /* find matching option */
402 if ((mi = optMatch(opt, o, 0)) < 0)
403 optFatal("unrecognized option `-%c'\n", *o);
405 /* does this option take an argument? */
408 if (optNeedsArgument(&opt[mi])) {
409 /* option needs an argument. find it. */
412 if ((optarg = ai + 1) == *argc)
413 optFatal("option `%s' requires an argument\n",
414 optString(&opt[mi], 0));
419 /* perform the action of this option. */
420 optExecute(&opt[mi], arg, 0);
423 /* remove option and any argument from the argv-array. */
425 argvRemove(argc, argv, ai);
426 argvRemove(argc, argv, ai);
428 /* a non-option argument */