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