1 /**
2 * @file check.c
3 *
4 * @brief Hunt for options in the option descriptor list
5 *
6 * This file contains the routines that deal with processing quoted strings
7 * into an internal format.
8 *
9 * @addtogroup autoopts
10 * @{
11 */
12 /*
13 * This file is part of AutoOpts, a companion to AutoGen.
14 * AutoOpts is free software.
15 * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved
16 *
17 * AutoOpts is available under any one of two licenses. The license
18 * in use must be one of these two and the choice is under the control
19 * of the user of the license.
20 *
21 * The GNU Lesser General Public License, version 3 or later
22 * See the files "COPYING.lgplv3" and "COPYING.gplv3"
23 *
24 * The Modified Berkeley Software Distribution License
25 * See the file "COPYING.mbsd"
26 *
27 * These files have the following sha256 sums:
28 *
29 * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3
30 * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3
31 * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd
32 */
33
34 /* = = = START-STATIC-FORWARD = = = */
35 static int
36 parse_opt(char const ** nm_pp, char ** arg_pp, char * buf, size_t bufsz);
37
38 static void
39 opt_ambiguities(tOptions * opts, char const * name, int nm_len);
40
41 static int
42 opt_match_ct(tOptions * opts, char const * name, int nm_len,
43 int * ixp, bool * disable);
44
45 static tSuccess
46 opt_set(tOptions * opts, char * arg, int idx, bool disable, tOptState * st);
47
48 static tSuccess
49 opt_unknown(tOptions * opts, char const * name, char * arg, tOptState * st);
50
51 static tSuccess
52 opt_ambiguous(tOptions * opts, char const * name, int match_ct);
53
54 static tSuccess
55 get_opt_arg_must(tOptions * opts, tOptState * o_st);
56
57 static tSuccess
58 get_opt_arg_may(tOptions * pOpts, tOptState * o_st);
59
60 static tSuccess
61 get_opt_arg_none(tOptions * pOpts, tOptState * o_st);
62 /* = = = END-STATIC-FORWARD = = = */
63
64 /**
65 * find the name and name length we are looking for
66 */
67 static int
parse_opt(char const ** nm_pp,char ** arg_pp,char * buf,size_t bufsz)68 parse_opt(char const ** nm_pp, char ** arg_pp, char * buf, size_t bufsz)
69 {
70 int res = 0;
71 char const * p = *nm_pp;
72 *arg_pp = NULL;
73
74 for (;;) {
75 switch (*(p++)) {
76 case NUL: return res;
77
78 case '=':
79 memcpy(buf, *nm_pp, (size_t)res);
80
81 buf[res] = NUL;
82 *nm_pp = buf;
83 *arg_pp = VOIDP(p);
84 return res;
85
86 default:
87 if (++res >= (int)bufsz)
88 return -1;
89 }
90 }
91 }
92
93 /**
94 * print out the options that match the given name.
95 *
96 * @param pOpts option data
97 * @param opt_name name of option to look for
98 */
99 static void
opt_ambiguities(tOptions * opts,char const * name,int nm_len)100 opt_ambiguities(tOptions * opts, char const * name, int nm_len)
101 {
102 char const * const hyph =
103 NAMED_OPTS(opts) ? "" : LONG_OPT_MARKER;
104
105 tOptDesc * pOD = opts->pOptDesc;
106 int idx = 0;
107
108 fputs(zambig_list_msg, stderr);
109 do {
110 if (pOD->pz_Name == NULL)
111 continue; /* doc option */
112
113 if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0)
114 fprintf(stderr, zambig_file, hyph, pOD->pz_Name);
115
116 else if ( (pOD->pz_DisableName != NULL)
117 && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0)
118 )
119 fprintf(stderr, zambig_file, hyph, pOD->pz_DisableName);
120 } while (pOD++, (++idx < opts->optCt));
121 }
122
123 /**
124 * Determine the number of options that match the name
125 *
126 * @param pOpts option data
127 * @param opt_name name of option to look for
128 * @param nm_len length of provided name
129 * @param index pointer to int for option index
130 * @param disable pointer to bool to mark disabled option
131 * @return count of options that match
132 */
133 static int
opt_match_ct(tOptions * opts,char const * name,int nm_len,int * ixp,bool * disable)134 opt_match_ct(tOptions * opts, char const * name, int nm_len,
135 int * ixp, bool * disable)
136 {
137 int matchCt = 0;
138 int idx = 0;
139 int idxLim = opts->optCt;
140 tOptDesc * pOD = opts->pOptDesc;
141
142 do {
143 /*
144 * If option disabled or a doc option, skip to next
145 */
146 if (pOD->pz_Name == NULL)
147 continue;
148
149 if ( SKIP_OPT(pOD)
150 && (pOD->fOptState != (OPTST_OMITTED | OPTST_NO_INIT)))
151 continue;
152
153 if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0) {
154 /*
155 * IF we have a complete match
156 * THEN it takes priority over any already located partial
157 */
158 if (pOD->pz_Name[ nm_len ] == NUL) {
159 *ixp = idx;
160 return 1;
161 }
162 }
163
164 /*
165 * IF there is a disable name
166 * *AND* the option name matches the disable name
167 * THEN ...
168 */
169 else if ( (pOD->pz_DisableName != NULL)
170 && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0)
171 ) {
172 *disable = true;
173
174 /*
175 * IF we have a complete match
176 * THEN it takes priority over any already located partial
177 */
178 if (pOD->pz_DisableName[ nm_len ] == NUL) {
179 *ixp = idx;
180 return 1;
181 }
182 }
183
184 else
185 continue; /* does not match any option */
186
187 /*
188 * We found a full or partial match, either regular or disabling.
189 * Remember the index for later.
190 */
191 *ixp = idx;
192 ++matchCt;
193
194 } while (pOD++, (++idx < idxLim));
195
196 return matchCt;
197 }
198
199 /**
200 * Set the option to the indicated option number.
201 *
202 * @param opts option data
203 * @param arg option argument (if glued to name)
204 * @param idx option index
205 * @param disable mark disabled option
206 * @param st state about current option
207 */
208 static tSuccess
opt_set(tOptions * opts,char * arg,int idx,bool disable,tOptState * st)209 opt_set(tOptions * opts, char * arg, int idx, bool disable, tOptState * st)
210 {
211 tOptDesc * pOD = opts->pOptDesc + idx;
212
213 if (SKIP_OPT(pOD)) {
214 if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0)
215 return FAILURE;
216
217 fprintf(stderr, zDisabledErr, opts->pzProgName, pOD->pz_Name);
218 if (pOD->pzText != NULL)
219 fprintf(stderr, SET_OFF_FMT, pOD->pzText);
220 fputc(NL, stderr);
221 (*opts->pUsageProc)(opts, EXIT_FAILURE);
222 /* NOTREACHED */
223 _exit(EXIT_FAILURE); /* to be certain */
224 }
225
226 /*
227 * IF we found a disablement name,
228 * THEN set the bit in the callers' flag word
229 */
230 if (disable)
231 st->flags |= OPTST_DISABLED;
232
233 st->pOD = pOD;
234 st->pzOptArg = arg;
235 st->optType = TOPT_LONG;
236
237 return SUCCESS;
238 }
239
240 /**
241 * An option was not found. Check for default option and set it
242 * if there is one. Otherwise, handle the error.
243 *
244 * @param opts option data
245 * @param name name of option to look for
246 * @param arg option argument
247 * @param st state about current option
248 *
249 * @return success status
250 */
251 static tSuccess
opt_unknown(tOptions * opts,char const * name,char * arg,tOptState * st)252 opt_unknown(tOptions * opts, char const * name, char * arg, tOptState * st)
253 {
254 /*
255 * IF there is no equal sign
256 * *AND* we are using named arguments
257 * *AND* there is a default named option,
258 * THEN return that option.
259 */
260 if ( (arg == NULL)
261 && NAMED_OPTS(opts)
262 && (opts->specOptIdx.default_opt != NO_EQUIVALENT)) {
263
264 st->pOD = opts->pOptDesc + opts->specOptIdx.default_opt;
265 st->pzOptArg = name;
266 st->optType = TOPT_DEFAULT;
267 return SUCCESS;
268 }
269
270 if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) {
271 fprintf(stderr, zIllOptStr, opts->pzProgPath, name);
272 (*opts->pUsageProc)(opts, EXIT_FAILURE);
273 /* NOTREACHED */
274 _exit(EXIT_FAILURE); /* to be certain */
275 }
276
277 return FAILURE;
278 }
279
280 /**
281 * Several options match the provided name.
282 *
283 * @param opts option data
284 * @param name name of option to look for
285 * @param match_ct number of matching options
286 *
287 * @return success status (always FAILURE, if it returns)
288 */
289 static tSuccess
opt_ambiguous(tOptions * opts,char const * name,int match_ct)290 opt_ambiguous(tOptions * opts, char const * name, int match_ct)
291 {
292 if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) {
293 fprintf(stderr, zambig_opt_fmt, opts->pzProgPath, name, match_ct);
294 if (match_ct <= 4)
295 opt_ambiguities(opts, name, (int)strlen(name));
296 (*opts->pUsageProc)(opts, EXIT_FAILURE);
297 /* NOTREACHED */
298 _exit(EXIT_FAILURE); /* to be certain */
299 }
300 return FAILURE;
301 }
302
303 /*=export_func optionVendorOption
304 * private:
305 *
306 * what: Process a vendor option
307 * arg: + tOptions * + pOpts + program options descriptor +
308 * arg: + tOptDesc * + pOptDesc + the descriptor for this arg +
309 *
310 * doc:
311 * For POSIX specified utilities, the options are constrained to the options,
312 * @xref{config attributes, Program Configuration}. AutoOpts clients should
313 * never specify this directly. It gets referenced when the option
314 * definitions contain a "vendor-opt" attribute.
315 =*/
316 void
optionVendorOption(tOptions * pOpts,tOptDesc * pOD)317 optionVendorOption(tOptions * pOpts, tOptDesc * pOD)
318 {
319 tOptState opt_st = OPTSTATE_INITIALIZER(PRESET);
320 char const * vopt_str = pOD->optArg.argString;
321
322 if (pOpts <= OPTPROC_EMIT_LIMIT)
323 return;
324
325 if ((pOD->fOptState & OPTST_RESET) != 0)
326 return;
327
328 if ((pOD->fOptState & OPTPROC_IMMEDIATE) == 0)
329 opt_st.flags = OPTST_DEFINED;
330
331 if ( ((pOpts->fOptSet & OPTPROC_VENDOR_OPT) == 0)
332 || ! SUCCESSFUL(opt_find_long(pOpts, vopt_str, &opt_st))
333 || ! SUCCESSFUL(get_opt_arg(pOpts, &opt_st)) )
334 {
335 fprintf(stderr, zIllVendOptStr, pOpts->pzProgName, vopt_str);
336 (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
337 /* NOTREACHED */
338 _exit(EXIT_FAILURE); /* to be certain */
339 }
340
341 /*
342 * See if we are in immediate handling state.
343 */
344 if (pOpts->fOptSet & OPTPROC_IMMEDIATE) {
345 /*
346 * See if the enclosed option is okay with that state.
347 */
348 if (DO_IMMEDIATELY(opt_st.flags))
349 (void)handle_opt(pOpts, &opt_st);
350
351 } else {
352 /*
353 * non-immediate direction.
354 * See if the enclosed option is okay with that state.
355 */
356 if (DO_NORMALLY(opt_st.flags) || DO_SECOND_TIME(opt_st.flags))
357 (void)handle_opt(pOpts, &opt_st);
358 }
359 }
360
361 /**
362 * Find the option descriptor by full name.
363 *
364 * @param opts option data
365 * @param opt_name name of option to look for
366 * @param state state about current option
367 *
368 * @return success status
369 */
370 LOCAL tSuccess
opt_find_long(tOptions * opts,char const * opt_name,tOptState * state)371 opt_find_long(tOptions * opts, char const * opt_name, tOptState * state)
372 {
373 char name_buf[128];
374 char * opt_arg;
375 int nm_len = parse_opt(&opt_name, &opt_arg, name_buf, sizeof(name_buf));
376
377 int idx = 0;
378 bool disable = false;
379 int ct;
380
381 if (nm_len <= 1) {
382 if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0)
383 return FAILURE;
384
385 fprintf(stderr, zInvalOptName, opts->pzProgName, opt_name);
386 (*opts->pUsageProc)(opts, EXIT_FAILURE);
387 /* NOTREACHED */
388 _exit(EXIT_FAILURE); /* to be certain */
389 }
390
391 ct = opt_match_ct(opts, opt_name, nm_len, &idx, &disable);
392
393 /*
394 * See if we found one match, no matches or multiple matches.
395 */
396 switch (ct) {
397 case 1: return opt_set(opts, opt_arg, idx, disable, state);
398 case 0: return opt_unknown(opts, opt_name, opt_arg, state);
399 default: return opt_ambiguous(opts, opt_name, ct);
400 }
401 }
402
403
404 /**
405 * Find the short option descriptor for the current option
406 *
407 * @param pOpts option data
408 * @param optValue option flag character
409 * @param pOptState state about current option
410 */
411 LOCAL tSuccess
opt_find_short(tOptions * pOpts,uint_t optValue,tOptState * pOptState)412 opt_find_short(tOptions * pOpts, uint_t optValue, tOptState * pOptState)
413 {
414 tOptDesc * pRes = pOpts->pOptDesc;
415 int ct = pOpts->optCt;
416
417 /*
418 * Search the option list
419 */
420 do {
421 if (optValue != pRes->optValue)
422 continue;
423
424 if (SKIP_OPT(pRes)) {
425 if ( (pRes->fOptState == (OPTST_OMITTED | OPTST_NO_INIT))
426 && (pRes->pz_Name != NULL)) {
427 if ((pOpts->fOptSet & OPTPROC_ERRSTOP) == 0)
428 return FAILURE;
429
430 fprintf(stderr, zDisabledErr, pOpts->pzProgPath, pRes->pz_Name);
431 if (pRes->pzText != NULL)
432 fprintf(stderr, SET_OFF_FMT, pRes->pzText);
433 fputc(NL, stderr);
434 (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
435 /* NOTREACHED */
436 _exit(EXIT_FAILURE); /* to be certain */
437 }
438 goto short_opt_error;
439 }
440
441 pOptState->pOD = pRes;
442 pOptState->optType = TOPT_SHORT;
443 return SUCCESS;
444
445 } while (pRes++, --ct > 0);
446
447 /*
448 * IF the character value is a digit
449 * AND there is a special number option ("-n")
450 * THEN the result is the "option" itself and the
451 * option is the specially marked "number" option.
452 */
453 if ( IS_DEC_DIGIT_CHAR(optValue)
454 && (pOpts->specOptIdx.number_option != NO_EQUIVALENT) ) {
455 pOptState->pOD = \
456 pRes = pOpts->pOptDesc + pOpts->specOptIdx.number_option;
457 (pOpts->pzCurOpt)--;
458 pOptState->optType = TOPT_SHORT;
459 return SUCCESS;
460 }
461
462 short_opt_error:
463
464 /*
465 * IF we are to stop on errors (the default, actually)
466 * THEN call the usage procedure.
467 */
468 if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
469 fprintf(stderr, zIllOptChr, pOpts->pzProgPath, optValue);
470 (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
471 /* NOTREACHED */
472 _exit(EXIT_FAILURE); /* to be certain */
473 }
474
475 return FAILURE;
476 }
477
478 /**
479 * Process option with a required argument. Long options can either have a
480 * separate command line argument, or an argument attached by the '='
481 * character. Figure out which.
482 *
483 * @param[in,out] opts the program option descriptor
484 * @param[in,out] o_st the option processing state
485 * @returns SUCCESS or FAILURE
486 */
487 static tSuccess
get_opt_arg_must(tOptions * opts,tOptState * o_st)488 get_opt_arg_must(tOptions * opts, tOptState * o_st)
489 {
490 switch (o_st->optType) {
491 case TOPT_SHORT:
492 /*
493 * See if an arg string follows the flag character
494 */
495 if (*++(opts->pzCurOpt) == NUL)
496 opts->pzCurOpt = opts->origArgVect[ opts->curOptIdx++ ];
497 o_st->pzOptArg = opts->pzCurOpt;
498 break;
499
500 case TOPT_LONG:
501 /*
502 * See if an arg string has already been assigned (glued on
503 * with an `=' character)
504 */
505 if (o_st->pzOptArg == NULL)
506 o_st->pzOptArg = opts->origArgVect[ opts->curOptIdx++ ];
507 break;
508
509 default:
510 #ifdef DEBUG
511 fputs("AutoOpts lib error: option type not selected\n", stderr);
512 option_exits(EXIT_FAILURE);
513 #endif
514
515 case TOPT_DEFAULT:
516 /*
517 * The option was selected by default. The current token is
518 * the option argument.
519 */
520 break;
521 }
522
523 /*
524 * Make sure we did not overflow the argument list.
525 */
526 if (opts->curOptIdx > opts->origArgCt) {
527 fprintf(stderr, zMisArg, opts->pzProgPath, o_st->pOD->pz_Name);
528 return FAILURE;
529 }
530
531 opts->pzCurOpt = NULL; /* next time advance to next arg */
532 return SUCCESS;
533 }
534
535 /**
536 * Process an option with an optional argument. For short options, it looks
537 * at the character after the option character, or it consumes the next full
538 * argument. For long options, it looks for an '=' character attachment to
539 * the long option name before deciding to take the next command line
540 * argument.
541 *
542 * @param pOpts the option descriptor
543 * @param o_st a structure for managing the current processing state
544 * @returns SUCCESS or does not return
545 */
546 static tSuccess
get_opt_arg_may(tOptions * pOpts,tOptState * o_st)547 get_opt_arg_may(tOptions * pOpts, tOptState * o_st)
548 {
549 /*
550 * An option argument is optional.
551 */
552 switch (o_st->optType) {
553 case TOPT_SHORT:
554 if (*++pOpts->pzCurOpt != NUL)
555 o_st->pzOptArg = pOpts->pzCurOpt;
556 else {
557 char * pzLA = pOpts->origArgVect[ pOpts->curOptIdx ];
558
559 /*
560 * BECAUSE it is optional, we must make sure
561 * we did not find another flag and that there
562 * is such an argument.
563 */
564 if ((pzLA == NULL) || (*pzLA == '-'))
565 o_st->pzOptArg = NULL;
566 else {
567 pOpts->curOptIdx++; /* argument found */
568 o_st->pzOptArg = pzLA;
569 }
570 }
571 break;
572
573 case TOPT_LONG:
574 /*
575 * Look for an argument if we don't already have one (glued on
576 * with a `=' character) *AND* we are not in named argument mode
577 */
578 if ( (o_st->pzOptArg == NULL)
579 && (! NAMED_OPTS(pOpts))) {
580 char * pzLA = pOpts->origArgVect[ pOpts->curOptIdx ];
581
582 /*
583 * BECAUSE it is optional, we must make sure
584 * we did not find another flag and that there
585 * is such an argument.
586 */
587 if ((pzLA == NULL) || (*pzLA == '-'))
588 o_st->pzOptArg = NULL;
589 else {
590 pOpts->curOptIdx++; /* argument found */
591 o_st->pzOptArg = pzLA;
592 }
593 }
594 break;
595
596 default:
597 case TOPT_DEFAULT:
598 ao_bug(zbad_default_msg);
599 }
600
601 /*
602 * After an option with an optional argument, we will
603 * *always* start with the next option because if there
604 * were any characters following the option name/flag,
605 * they would be interpreted as the argument.
606 */
607 pOpts->pzCurOpt = NULL;
608 return SUCCESS;
609 }
610
611 /**
612 * Process option that does not have an argument.
613 *
614 * @param[in,out] opts the program option descriptor
615 * @param[in,out] o_st the option processing state
616 * @returns SUCCESS or FAILURE
617 */
618 static tSuccess
get_opt_arg_none(tOptions * pOpts,tOptState * o_st)619 get_opt_arg_none(tOptions * pOpts, tOptState * o_st)
620 {
621 /*
622 * No option argument. Make sure next time around we find
623 * the correct option flag character for short options
624 */
625 if (o_st->optType == TOPT_SHORT)
626 (pOpts->pzCurOpt)++;
627
628 /*
629 * It is a long option. Make sure there was no ``=xxx'' argument
630 */
631 else if (o_st->pzOptArg != NULL) {
632 fprintf(stderr, zNoArg, pOpts->pzProgPath, o_st->pOD->pz_Name);
633 return FAILURE;
634 }
635
636 /*
637 * It is a long option. Advance to next command line argument.
638 */
639 else
640 pOpts->pzCurOpt = NULL;
641 return SUCCESS;
642 }
643
644 /**
645 * Process option. Figure out whether or not to look for an option argument.
646 *
647 * @param[in,out] opts the program option descriptor
648 * @param[in,out] o_st the option processing state
649 * @returns SUCCESS or FAILURE
650 */
651 LOCAL tSuccess
get_opt_arg(tOptions * opts,tOptState * o_st)652 get_opt_arg(tOptions * opts, tOptState * o_st)
653 {
654 o_st->flags |= (o_st->pOD->fOptState & OPTST_PERSISTENT_MASK);
655
656 /*
657 * Disabled options and options specified to not have arguments
658 * are handled with the "none" procedure. Otherwise, check the
659 * optional flag and call either the "may" or "must" function.
660 */
661 if ( ((o_st->flags & OPTST_DISABLED) != 0)
662 || (OPTST_GET_ARGTYPE(o_st->flags) == OPARG_TYPE_NONE))
663 return get_opt_arg_none(opts, o_st);
664
665 if (o_st->flags & OPTST_ARG_OPTIONAL)
666 return get_opt_arg_may( opts, o_st);
667
668 return get_opt_arg_must(opts, o_st);
669 }
670
671 /**
672 * Find the option descriptor for the current option.
673 *
674 * @param[in,out] opts the program option descriptor
675 * @param[in,out] o_st the option processing state
676 * @returns SUCCESS or FAILURE
677 */
678 LOCAL tSuccess
find_opt(tOptions * opts,tOptState * o_st)679 find_opt(tOptions * opts, tOptState * o_st)
680 {
681 /*
682 * IF we are continuing a short option list (e.g. -xyz...)
683 * THEN continue a single flag option.
684 * OTHERWISE see if there is room to advance and then do so.
685 */
686 if ((opts->pzCurOpt != NULL) && (*opts->pzCurOpt != NUL))
687 return opt_find_short(opts, (uint8_t)*(opts->pzCurOpt), o_st);
688
689 if (opts->curOptIdx >= opts->origArgCt)
690 return PROBLEM; /* NORMAL COMPLETION */
691
692 opts->pzCurOpt = opts->origArgVect[ opts->curOptIdx ];
693
694 /*
695 * IF all arguments must be named options, ...
696 */
697 if (NAMED_OPTS(opts)) {
698 char * pz = opts->pzCurOpt;
699 int def;
700 tSuccess res;
701 uint16_t * def_opt;
702
703 opts->curOptIdx++;
704
705 if (*pz != '-')
706 return opt_find_long(opts, pz, o_st);
707
708 /*
709 * The name is prefixed with one or more hyphens. Strip them off
710 * and disable the "default_opt" setting. Use heavy recasting to
711 * strip off the "const" quality of the "default_opt" field.
712 */
713 while (*(++pz) == '-') ;
714 def_opt = VOIDP(&(opts->specOptIdx.default_opt));
715 def = *def_opt;
716 *def_opt = NO_EQUIVALENT;
717 res = opt_find_long(opts, pz, o_st);
718 *def_opt = (uint16_t)def;
719 return res;
720 }
721
722 /*
723 * Note the kind of flag/option marker
724 */
725 if (*((opts->pzCurOpt)++) != '-')
726 return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */
727
728 /*
729 * Special hack for a hyphen by itself
730 */
731 if (*(opts->pzCurOpt) == NUL)
732 return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */
733
734 /*
735 * The current argument is to be processed as an option argument
736 */
737 opts->curOptIdx++;
738
739 /*
740 * We have an option marker.
741 * Test the next character for long option indication
742 */
743 if (opts->pzCurOpt[0] == '-') {
744 if (*++(opts->pzCurOpt) == NUL)
745 /*
746 * NORMAL COMPLETION - NOT this arg, but rest are operands
747 */
748 return PROBLEM;
749
750 /*
751 * We do not allow the hyphen to be used as a flag value.
752 * Therefore, if long options are not to be accepted, we punt.
753 */
754 if ((opts->fOptSet & OPTPROC_LONGOPT) == 0) {
755 fprintf(stderr, zIllOptStr, opts->pzProgPath, opts->pzCurOpt-2);
756 return FAILURE;
757 }
758
759 return opt_find_long(opts, opts->pzCurOpt, o_st);
760 }
761
762 /*
763 * If short options are not allowed, then do long
764 * option processing. Otherwise the character must be a
765 * short (i.e. single character) option.
766 */
767 if ((opts->fOptSet & OPTPROC_SHORTOPT) != 0)
768 return opt_find_short(opts, (uint8_t)*(opts->pzCurOpt), o_st);
769
770 return opt_find_long(opts, opts->pzCurOpt, o_st);
771 }
772
773 /** @}
774 *
775 * Local Variables:
776 * mode: C
777 * c-file-style: "stroustrup"
778 * indent-tabs-mode: nil
779 * End:
780 * end of autoopts/find.c */
781