xref: /freebsd/contrib/ntp/sntp/libopts/find.c (revision 63d1fd5970ec814904aa0f4580b10a0d302d08b2)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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