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