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