1 /*
2 * Copyright (C) 1997-2004, Michael Jennings
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies of the Software, its documentation and marketing & publicity
13 * materials, and acknowledgment shall be given in the documentation, materials
14 * and software packages that this Software was used.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 /**
25 * @file options.c
26 * Command Line Option Parser Source File
27 *
28 * This file contains the functions which comprise the command line
29 * option parser.
30 *
31 * @author Michael Jennings <mej@eterm.org>
32 * $Revision: 1.18 $
33 * $Date: 2004/10/26 18:01:53 $
34 */
35
36 static const char __attribute__((unused)) cvs_ident[] = "$Id: options.c,v 1.18 2004/10/26 18:01:53 mej Exp $";
37
38 #ifdef HAVE_CONFIG_H
39 # include <config.h>
40 #endif
41
42 #include <libast_internal.h>
43
44 /*@{*/
45 /**
46 * @name Internal Parser Macros
47 * Macros to simply certain parser operations.
48 *
49 * This group of macros is used internally by the command line option
50 * parser. They are not available for use by client programs and are
51 * documented here solely for completeness and clarity.
52 *
53 * @see @link DOXGRP_OPT Command Line Option Parser @endlink
54 * @ingroup DOXGRP_OPT
55 */
56
57 /** Next argument. Proceed to parsing the next argument in the argv[] list. */
58 #define NEXT_ARG() D_OPTIONS(("NEXT_ARG()\n")); i++; opt = SPIF_CHARPTR(argv[i]); continue
59 /** Next letter. Proceed to the next letter in a bundled option series. */
60 #define NEXT_LETTER() D_OPTIONS(("NEXT_LETTER(%s)\n", opt)); if (*(opt + 1)) {opt++;} else {NEXT_ARG();} continue
61 /** Next loop. Proceed to the next parsing stage (letter or word). */
62 #define NEXT_LOOP() D_OPTIONS(("NEXT_LOOP()\n")); if (islong || val_ptr) {NEXT_ARG();} else {NEXT_LETTER();} NOP
63 /** Option parse test. Returns true IFF the option should be parsed on this pass. */
64 #define SHOULD_PARSE(j) ((SPIFOPT_FLAGS_IS_SET(SPIFOPT_SETTING_PREPARSE) && SPIFOPT_OPT_IS_PREPARSE(j)) \
65 || (!SPIFOPT_FLAGS_IS_SET(SPIFOPT_SETTING_PREPARSE) && !SPIFOPT_OPT_IS_PREPARSE(j)))
66 /*@}*/
67
68 /**
69 * Internal option parser settings.
70 *
71 * This variable holds the actual structure containing the settings
72 * for the option parser. It should never be accessed directly, but
73 * rather through use of the Option Parser Settings Macros.
74 *
75 * @see @link DOXGRP_OPT Command Line Option Parser @endlink
76 * @ingroup DOXGRP_OPT
77 */
78 spifopt_settings_t spifopt_settings = { NULL, 0, 0, 0, 0, 0, NULL };
79
80 /**
81 * Option-type-to-string translator.
82 *
83 * This function is used internally by spifopt_usage() to convert an
84 * option's numerical type to a short string representing that type of
85 * option.
86 *
87 * @param type The numeric option type (SPIFOPT_OPT_FLAGS()).
88 * @return A 6-char-max string describing the option type.
89 *
90 * @see @link DOXGRP_OPT Command Line Option Parser @endlink
91 * @ingroup DOXGRP_OPT
92 */
93 static spif_charptr_t
get_option_type_string(spif_uint16_t type)94 get_option_type_string(spif_uint16_t type)
95 {
96 switch (type) {
97 case SPIFOPT_FLAG_BOOLEAN: return SPIF_CHARPTR("(bool)"); break;
98 case SPIFOPT_FLAG_INTEGER: return SPIF_CHARPTR("(int)"); break;
99 case SPIFOPT_FLAG_ARGLIST: return SPIF_CHARPTR("(strs)"); break;
100 default: return SPIF_CHARPTR("(str)");
101 }
102 ASSERT_NOTREACHED_RVAL(NULL);
103 }
104
105 /**
106 * Built-in default function for displaying help information.
107 *
108 * This is the default "help handler" function. It displays a list of
109 * long and short options along with the description of each. It also
110 * prints out a brief type identifier as produced by
111 * get_option_type_string().
112 *
113 * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, SPIFOPT_HELPHANDLER_SET(), spifopt_helphandler_t
114 * @ingroup DOXGRP_MEM
115 */
116 void
spifopt_usage(void)117 spifopt_usage(void)
118 {
119 spif_uint16_t i, col, l_long = 0, l_desc = 0;
120
121 /* Find the longest long option and the longest description. */
122 for (i = 0; i < SPIFOPT_NUMOPTS_GET(); i++) {
123 MAX_IT(l_long, strlen(SPIFOPT_OPT_LONG(i)));
124 MAX_IT(l_desc, strlen(SPIFOPT_OPT_DESC(i)));
125 }
126 l_long += 2; /* Add 2 for the "--" */
127 l_desc += 7; /* Add 7 for the type and a space */
128
129 printf("%s %s\n", libast_program_name, libast_program_version);
130 printf("Usage:\n\n");
131 printf("POSIX ");
132
133 for (col = 0; col < (l_long - 3) / 2; col++) printf(" ");
134 printf("GNU");
135 for (col = 0; col < (l_long - 3) / 2; col++) printf(" ");
136 if (!(l_long % 2)) {
137 printf(" ");
138 }
139 printf(" ");
140
141 for (col = 0; col < (l_desc - 11) / 2; col++) printf(" ");
142 printf("Description");
143 for (col = 0; col < (l_desc - 11) / 2; col++) printf(" ");
144 if (!(l_desc % 2)) {
145 printf(" ");
146 }
147
148 printf("\n");
149 printf("----- ");
150
151 for (col = 0; col < l_long; col++) printf("-");
152 printf(" ");
153 for (col = 0; col < l_desc; col++) printf("-");
154 printf("\n");
155
156 for (i = 0, l_long -= 2; i < SPIFOPT_NUMOPTS_GET(); i++) {
157 if (SPIFOPT_OPT_SHORT(i)) {
158 printf(" -%c ", SPIFOPT_OPT_SHORT(i));
159 } else {
160 printf(" ");
161 }
162 printf("--%s", SPIFOPT_OPT_LONG(i));
163 for (col = strlen(SPIF_CAST_C(char *) SPIFOPT_OPT_LONG(i)); col < l_long; col++) {
164 printf(" ");
165 }
166 printf(" %-6s %s\n", get_option_type_string(SPIFOPT_OPT_TYPE(i)), SPIFOPT_OPT_DESC(i));
167 }
168 exit(EXIT_FAILURE);
169 }
170
171 /**
172 * Find matching long option.
173 *
174 * This function searches the option list for a long option which
175 * matches the given string.
176 *
177 * @param opt The long option string to match against.
178 * @return The index of the matching option, or -1 if not found.
179 *
180 * @see @link DOXGRP_OPT Command Line Option Parser @endlink, is_valid_option()
181 * @ingroup DOXGRP_OPT
182 */
183 static spif_int32_t
find_long_option(spif_charptr_t opt)184 find_long_option(spif_charptr_t opt)
185 {
186 spif_int32_t j;
187
188 D_OPTIONS(("opt == \"%s\"\n", NONULL(opt)));
189 /* Check to see if we have a long option that matches this. */
190 for (j = 0; j < SPIFOPT_NUMOPTS_GET(); j++) {
191 size_t l;
192
193 l = strlen(SPIF_CHARPTR_C(SPIFOPT_OPT_LONG(j)));
194 /* Look for matches to the part before the =, if any. */
195 if (!strncasecmp(SPIF_CHARPTR_C(SPIFOPT_OPT_LONG(j)), SPIF_CHARPTR_C(opt), l)
196 && (opt[l] == '=' || !opt[l])) {
197 /* Got one. */
198 D_OPTIONS(("Match found at %d: %s == %s\n", j, SPIFOPT_OPT_LONG(j), opt));
199 return j;
200 }
201 }
202 /* No matching long option found. Report an error and
203 continue with the next arg. */
204 libast_print_error("Unrecognized long option --%s\n", opt);
205 CHECK_BAD();
206 return ((spif_int32_t) -1);
207 }
208
209 /**
210 * Find matching short option.
211 *
212 * This function searches the option list for a short option which
213 * matches the given character.
214 *
215 * @param opt The short option character to match against.
216 * @return The index of the matching option, or -1 if not found.
217 *
218 * @see @link DOXGRP_OPT Command Line Option Parser @endlink, is_valid_option()
219 * @ingroup DOXGRP_OPT
220 */
221 static spif_int32_t
find_short_option(char opt)222 find_short_option(char opt)
223 {
224 spif_int32_t j;
225
226 D_OPTIONS(("opt == \"%c\"\n", opt));
227 for (j = 0; j < SPIFOPT_NUMOPTS_GET(); j++) {
228 if (SPIFOPT_OPT_SHORT(j) == opt) {
229 D_OPTIONS(("Match found at %d: %c == %c\n", j, SPIFOPT_OPT_SHORT(j), opt));
230 return j;
231 }
232 }
233 libast_print_error("unrecognized option -%c\n", opt);
234 CHECK_BAD();
235 return ((spif_int32_t) -1);
236 }
237
238 /**
239 * Find the value for a long option.
240 *
241 * This function looks for and returns the value associated with a
242 * long option, or NULL if one is not found.
243 *
244 * @param arg The argument containing the long option.
245 * @param next_arg The next word on the command line.
246 * @param hasequal Address of a toggle variable to return whether or
247 * not the value was appended to the option with an
248 * equals sign ('=').
249 * @return The option's value string, or NULL if no value is
250 * found.
251 *
252 * @see @link DOXGRP_OPT Command Line Option Parser @endlink, spifopt_parse()
253 * @ingroup DOXGRP_OPT
254 */
255 static spif_charptr_t
find_value_long(spif_charptr_t arg,spif_charptr_t next_arg,spif_charptr_t hasequal)256 find_value_long(spif_charptr_t arg, spif_charptr_t next_arg, spif_charptr_t hasequal)
257 {
258 spif_charptr_t val_ptr;
259
260 if ((val_ptr = SPIF_CHARPTR(strchr(SPIF_CHARPTR_C(arg), '='))) != NULL) {
261 val_ptr++;
262 *hasequal = 1;
263 } else {
264 if (next_arg) {
265 val_ptr = next_arg;
266 }
267 *hasequal = 0;
268 }
269 D_OPTIONS(("hasequal == %d val_ptr == %10.8p \"%s\"\n", *hasequal, val_ptr, NONULL(val_ptr)));
270 return val_ptr;
271 }
272
273 /**
274 * Find the value for a short option.
275 *
276 * This function looks for and returns the value associated with a
277 * short option, or NULL if one is not found.
278 *
279 * @param arg The argument containing the short option.
280 * @param next_arg The next word on the command line.
281 * @return The option's value string, or NULL if no value is
282 * found.
283 *
284 * @see @link DOXGRP_OPT Command Line Option Parser @endlink, spifopt_parse()
285 * @ingroup DOXGRP_OPT
286 */
287 static spif_charptr_t
find_value_short(spif_charptr_t arg,spif_charptr_t next_arg)288 find_value_short(spif_charptr_t arg, spif_charptr_t next_arg)
289 {
290 spif_charptr_t val_ptr = NULL;
291
292 if (arg[1]) {
293 val_ptr = arg + 1;
294 } else if (next_arg != NULL) {
295 val_ptr = next_arg;
296 }
297 D_OPTIONS(("val_ptr == %10.8p \"%s\"\n", val_ptr, NONULL(val_ptr)));
298 return val_ptr;
299 }
300
301 /**
302 * Test for a valid boolean value.
303 *
304 * This function compares the given value pointer to the possible
305 * values for a boolean option.
306 *
307 * @param val_ptr The value to be tested.
308 * @return TRUE if boolean, FALSE if not.
309 *
310 * @see @link DOXGRP_OPT Command Line Option Parser @endlink, spifopt_parse()
311 * @ingroup DOXGRP_OPT
312 */
313 static spif_bool_t
is_boolean_value(spif_charptr_t val_ptr)314 is_boolean_value(spif_charptr_t val_ptr)
315 {
316 if (!(val_ptr) || !(*val_ptr)) {
317 return FALSE;
318 }
319 return ((BOOL_OPT_ISTRUE(val_ptr) || BOOL_OPT_ISFALSE(val_ptr)) ? (TRUE) : (FALSE));
320 }
321
322 /**
323 * Check for a match to the current option.
324 *
325 * This function does some initial parsing, then calls the appropriate
326 * sub-function to look for matches.
327 *
328 * @param opt The argument string.
329 * @return TRUE if a match is found, FALSE otherwise.
330 *
331 * @see @link DOXGRP_OPT Command Line Option Parser @endlink, spifopt_parse(), find_long_option(),
332 * find_short_option()
333 * @ingroup DOXGRP_OPT
334 */
335 static spif_bool_t
is_valid_option(spif_charptr_t opt)336 is_valid_option(spif_charptr_t opt)
337 {
338 REQUIRE_RVAL(opt != NULL, FALSE);
339
340 if (*opt != '-') {
341 return FALSE;
342 }
343 opt++;
344 if (*opt == '-') {
345 opt++;
346 if (find_long_option(opt) >= 0) {
347 return TRUE;
348 }
349 } else {
350 if (find_short_option(*opt) >= 0) {
351 return TRUE;
352 }
353 }
354 return FALSE;
355 }
356
357 /**
358 * Handle a boolean option.
359 *
360 * This function is reponsible for taking the proper action for a
361 * boolean option. It sets the appropriate bitfield on the
362 * appropriate variable as defined by the settings for that option.
363 *
364 * @param n The index for the option within the option list.
365 * @param val_ptr A pointer (possibly NULL) to the value specified
366 * with the option.
367 * @param islong 0 if the option was short, non-zero otherwise.
368 * @return TRUE if a match is found, FALSE otherwise.
369 *
370 * @see @link DOXGRP_OPT Command Line Option Parser @endlink, spifopt_parse(), find_long_option(),
371 * find_short_option()
372 * @ingroup DOXGRP_OPT
373 */
374 static spif_bool_t
handle_boolean(spif_int32_t n,spif_charptr_t val_ptr,unsigned char islong)375 handle_boolean(spif_int32_t n, spif_charptr_t val_ptr, unsigned char islong)
376 {
377 D_OPTIONS(("Boolean option detected\n"));
378 if (val_ptr && islong) {
379 /* There's a value, so let's see what it is. */
380 if (BOOL_OPT_ISTRUE(val_ptr)) {
381 if (SHOULD_PARSE(n)) {
382 D_OPTIONS(("\"%s\" == TRUE\n", val_ptr));
383 *((unsigned long *) SPIFOPT_OPT_VALUE(n)) |= SPIFOPT_OPT_MASK(n);
384 }
385 } else if (BOOL_OPT_ISFALSE(val_ptr)) {
386 if (SHOULD_PARSE(n)) {
387 D_OPTIONS(("\"%s\" == FALSE\n", val_ptr));
388 *((unsigned long *) SPIFOPT_OPT_VALUE(n)) &= ~SPIFOPT_OPT_MASK(n);
389 }
390 } else {
391 if (SHOULD_PARSE(n)) {
392 D_OPTIONS(("Forcing option --%s to TRUE\n", SPIFOPT_OPT_LONG(n)));
393 *((unsigned long *) SPIFOPT_OPT_VALUE(n)) |= SPIFOPT_OPT_MASK(n);
394 }
395 return FALSE;
396 }
397 } else {
398 if (SHOULD_PARSE(n)) {
399 /* No value, or it was a short option, so pretend it was true. */
400 if (islong) {
401 D_OPTIONS(("Forcing option --%s to TRUE\n", SPIFOPT_OPT_LONG(n)));
402 } else {
403 val_ptr = NULL;
404 D_OPTIONS(("Forcing option -%c to TRUE\n", SPIFOPT_OPT_SHORT(n)));
405 }
406 *((unsigned long *) SPIFOPT_OPT_VALUE(n)) |= SPIFOPT_OPT_MASK(n);
407 }
408 }
409 return TRUE;
410 }
411
412 /**
413 * Handle an integer option.
414 *
415 * This function is responsible for taking the appropriate action when
416 * an integer option is encountered. The variable whose address was
417 * given to the option structure is assigned the value of the option.
418 *
419 * @param n The index of the option.
420 * @param val_ptr The value passed to the option.
421 *
422 * @see @link DOXGRP_OPT Command Line Option Parser @endlink, spifopt_parse(), find_long_option(),
423 * find_short_option()
424 * @ingroup DOXGRP_OPT
425 */
426 static void
handle_integer(spif_int32_t n,spif_charptr_t val_ptr)427 handle_integer(spif_int32_t n, spif_charptr_t val_ptr)
428 {
429 D_OPTIONS(("Integer option detected\n"));
430 *((int *) SPIFOPT_OPT_VALUE(n)) = strtol(SPIF_CHARPTR_C(val_ptr), (char **) NULL, 0);
431 }
432
433 /**
434 * Handle a string option.
435 *
436 * This function is responsible for taking the appropriate action when
437 * a string option is encountered. The variable whose address was
438 * given to the option structure is assigned the value of the option.
439 *
440 * @param n The index of the option.
441 * @param val_ptr The value passed to the option.
442 *
443 * @see @link DOXGRP_OPT Command Line Option Parser @endlink, spifopt_parse(), find_long_option(),
444 * find_short_option()
445 * @ingroup DOXGRP_OPT
446 */
447 static void
handle_string(spif_int32_t n,spif_charptr_t val_ptr)448 handle_string(spif_int32_t n, spif_charptr_t val_ptr)
449 {
450 D_OPTIONS(("String option detected\n"));
451 *((const char **) SPIFOPT_OPT_VALUE(n)) = SPIF_CAST_C(char *) STRDUP(val_ptr);
452 }
453
454
455 /**
456 * Handle an argument list option.
457 *
458 * This function is responsible for taking the appropriate action when
459 * an argument list option is encountered. An array of arguments is
460 * created at the specified address. There can be only one of these.
461 *
462 * @param n The index of the option.
463 * @param val_ptr The value passed to the option.
464 * @param hasequal TRUE if the long option used '=', FALSE otherwise.
465 * @param i The index of the current option within argc[].
466 * @param argc The argument count.
467 * @param argv The argument list.
468 *
469 * @see @link DOXGRP_OPT Command Line Option Parser @endlink, spifopt_parse(), find_long_option(),
470 * find_short_option()
471 * @ingroup DOXGRP_OPT
472 */
473 static void
handle_arglist(spif_int32_t n,spif_charptr_t val_ptr,unsigned char hasequal,spif_int32_t i,int argc,char * argv[])474 handle_arglist(spif_int32_t n, spif_charptr_t val_ptr, unsigned char hasequal,
475 spif_int32_t i, int argc, char *argv[])
476 {
477 spif_charptr_t *tmp;
478 register unsigned short k;
479
480 D_OPTIONS(("Argument list option detected\n"));
481 if (hasequal) {
482 /* There's an equals sign, so just parse the rest of this option into words. */
483 tmp = SPIF_CAST_PTR(charptr) MALLOC(sizeof(spif_charptr_t) * (spiftool_num_words(val_ptr) + 1));
484
485 for (k = 0; val_ptr; k++) {
486 tmp[k] = spiftool_get_word(1, val_ptr);
487 val_ptr = spiftool_get_pword(2, val_ptr);
488 D_OPTIONS(("tmp[%d] == %s\n", k, tmp[k]));
489 }
490 tmp[k] = SPIF_NULL_TYPE(charptr);
491 *(SPIF_CAST_C(spif_charptr_t **) SPIFOPT_OPT_VALUE(n)) = tmp;
492 } else {
493 unsigned short len = argc - i;
494
495 /* No equals sign, so use the rest of the command line and break. */
496 tmp = SPIF_CAST_PTR(charptr) MALLOC(sizeof(spif_charptr_t ) * (argc - i + 1));
497
498 for (k = 0; k < len; k++) {
499 tmp[k] = SPIF_CAST(charptr) STRDUP(argv[k + i]);
500 D_OPTIONS(("tmp[%d] == %s\n", k, tmp[k]));
501 argv[k + i] = NULL;
502 }
503 tmp[k] = SPIF_NULL_TYPE(charptr);
504 *(SPIF_CAST_C(spif_charptr_t **) SPIFOPT_OPT_VALUE(n)) = tmp;
505 }
506 }
507
508 /**
509 * Parse the command line arguments for options.
510 *
511 * This function iterates through the command line arguments looking
512 * for options which have been defined. Each option encountered is
513 * handled according to its type.
514 *
515 * @param argc The number of arguments.
516 * @param argv The array of argument strings.
517 *
518 * @see @link DOXGRP_OPT Command Line Option Parser @endlink
519 * @ingroup DOXGRP_OPT
520 */
521 void
spifopt_parse(int argc,char * argv[])522 spifopt_parse(int argc, char *argv[])
523 {
524 spif_int32_t i, j;
525 spif_charptr_t opt;
526
527 REQUIRE(argc > 1);
528 REQUIRE(argv != NULL);
529
530 /* Process each command line arg one-by-one. */
531 for (i = 1, opt = SPIF_CHARPTR(argv[1]); i < argc; ) {
532 spif_charptr_t val_ptr = NULL;
533 spif_char_t islong = 0, hasequal = 0;
534
535 D_OPTIONS(("argv[%d] == \"%s\", opt == \"%s\"\n", i, argv[i], opt));
536
537 if (SPIF_PTR_ISNULL(opt)) {
538 /* NEXT_ARG(); */
539 break;
540 } else if (opt == SPIF_CHARPTR(argv[i])) {
541 /* If it's not an option, skip it. */
542 if (*opt != '-') {
543 NEXT_ARG();
544 } else {
545 opt++;
546 }
547 }
548
549 /* If the second character is also a hyphen, it's a long option. */
550 if (*opt == '-') {
551 islong = 1;
552 /* Skip the leading "--" */
553 opt++;
554 D_OPTIONS(("Long option detected\n"));
555 if ((j = find_long_option(opt)) == -1) {
556 NEXT_ARG();
557 }
558 } else {
559 if ((j = find_short_option(*opt)) == -1) {
560 NEXT_LETTER();
561 }
562 }
563 if (!SPIFOPT_FLAGS_IS_SET(SPIFOPT_SETTING_PREPARSE)) {
564 argv[i] = NULL;
565 }
566
567 /* If a value was passed to this option, set val_ptr to point to it. */
568 if (islong) {
569 val_ptr = find_value_long(SPIF_CHARPTR(opt), SPIF_CHARPTR(argv[i + 1]), &hasequal);
570 } else {
571 val_ptr = find_value_short(opt, SPIF_CHARPTR(argv[i + 1]));
572 }
573
574 /* Boolean options may or may not have a value... */
575 if (val_ptr) {
576 if (SPIFOPT_OPT_IS_BOOLEAN(j) && !is_boolean_value(val_ptr)) {
577 val_ptr = NULL;
578 } else if (SPIFOPT_OPT_IS_ABSTRACT(j) && is_valid_option(val_ptr)) {
579 val_ptr = NULL;
580 }
581 }
582 if (val_ptr) {
583 if (val_ptr == SPIF_CHARPTR(argv[i + 1])) {
584 i++;
585 opt += strlen(SPIF_CHARPTR_C(opt));
586 }
587 }
588
589 /* If this option is deprecated, print a warning before continuing. */
590 if (SPIFOPT_OPT_IS_DEPRECATED(j)) {
591 spif_str_t warn;
592
593 warn = spif_str_new_from_buff(SPIF_CHARPTR("The "), 128);
594 if (SPIFOPT_OPT_SHORT(j)) {
595 spif_str_append_char(warn, '-');
596 spif_str_append_char(warn, SPIFOPT_OPT_SHORT(j));
597 spif_str_append_from_ptr(warn, SPIF_CHARPTR(" / --"));
598 } else {
599 spif_str_append_from_ptr(warn, SPIF_CHARPTR("--"));
600 }
601 spif_str_append_from_ptr(warn, SPIFOPT_OPT_LONG(j));
602 spif_str_append_from_ptr(warn, SPIF_CHARPTR(" option is deprecated and should not be used.\n"));
603 libast_print_warning(SPIF_CHARPTR_C(SPIF_STR_STR(warn)));
604 spif_str_del(warn);
605 }
606
607 /* Make sure that options which require a parameter have them. */
608 if (SPIFOPT_OPT_NEEDS_VALUE(j)) {
609 if (val_ptr == NULL) {
610 if (islong) {
611 libast_print_error("long option --%s requires a%s value\n", SPIFOPT_OPT_LONG(j),
612 (SPIFOPT_OPT_IS_INTEGER(j)
613 ? ("n integer")
614 : (SPIFOPT_OPT_IS_STRING(j)
615 ? " string"
616 : (SPIFOPT_OPT_IS_ARGLIST(j)
617 ? "n argument list"
618 : ""))));
619 } else {
620 libast_print_error("option -%c requires a%s value\n", SPIFOPT_OPT_SHORT(j),
621 (SPIFOPT_OPT_IS_INTEGER(j)
622 ? ("n integer")
623 : (SPIFOPT_OPT_IS_STRING(j)
624 ? " string"
625 : (SPIFOPT_OPT_IS_ARGLIST(j)
626 ? "n argument list"
627 : ""))));
628 }
629 CHECK_BAD();
630 continue;
631 }
632 /* Also make sure we know what to do with the value. */
633 if (SPIFOPT_OPT_VALUE(j) == NULL) {
634 NEXT_LOOP();
635 }
636 } else if (SPIFOPT_OPT_IS_ABSTRACT(j) && SPIFOPT_OPT_VALUE(j) == NULL) {
637 /* Also make sure that abstract options have a function pointer. */
638 NEXT_LOOP();
639 }
640
641 if (SPIFOPT_OPT_IS_BOOLEAN(j)) {
642 if (!handle_boolean(j, val_ptr, islong)) {
643 i--;
644 }
645 } else if (SPIFOPT_OPT_IS_STRING(j)) {
646 if (SHOULD_PARSE(j)) {
647 handle_string(j, val_ptr);
648 }
649 } else if (SPIFOPT_OPT_IS_INTEGER(j)) {
650 if (SHOULD_PARSE(j)) {
651 handle_integer(j, val_ptr);
652 }
653 } else if (SPIFOPT_OPT_IS_ARGLIST(j)) {
654 if (SHOULD_PARSE(j)) {
655 handle_arglist(j, val_ptr, hasequal, i, argc, argv);
656 }
657 if (!hasequal) {
658 break;
659 }
660 } else if (SPIFOPT_OPT_IS_ABSTRACT(j)) {
661 if (SHOULD_PARSE(j)) {
662 D_OPTIONS(("Abstract option detected\n"));
663 ((spifopt_abstract_handler_t) SPIFOPT_OPT_VALUE(j))(val_ptr);
664 }
665 }
666 if (!SPIFOPT_FLAGS_IS_SET(SPIFOPT_SETTING_PREPARSE)) {
667 argv[i] = NULL;
668 }
669 NEXT_LOOP();
670 }
671
672 if (SPIFOPT_FLAGS_IS_SET(SPIFOPT_SETTING_PREPARSE)) {
673 SPIFOPT_FLAGS_CLEAR(SPIFOPT_SETTING_PREPARSE);
674 } else {
675 for (i = 1, j = 1; i < argc; i++) {
676 if (argv[i]) {
677 argv[j] = argv[i];
678 j++;
679 }
680 }
681 if (j > 1) {
682 argv[j] = NULL;
683 }
684 }
685 }
686
687 /**
688 * @defgroup DOXGRP_OPT Command Line Option Parser
689 *
690 * This group of functions/defines/macros comprises the command line
691 * option parser.
692 *
693 *
694 * A small sample program demonstrating some of these routines can be
695 * found @link opt_example.c here @endlink.
696 */
697
698 /**
699 * @example opt_example.c
700 * Example code for using the options parser.
701 *
702 */
703