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 = = = */
35static int
36parse_opt(char const ** nm_pp, char ** arg_pp, char * buf, size_t bufsz);
37
38static void
39opt_ambiguities(tOptions * opts, char const * name, int nm_len);
40
41static int
42opt_match_ct(tOptions * opts, char const * name, int nm_len,
43             int * ixp, bool * disable);
44
45static tSuccess
46opt_set(tOptions * opts, char * arg, int idx, bool disable, tOptState * st);
47
48static tSuccess
49opt_unknown(tOptions * opts, char const * name, char * arg, tOptState * st);
50
51static tSuccess
52opt_ambiguous(tOptions * opts, char const * name, int match_ct);
53
54static tSuccess
55get_opt_arg_must(tOptions * opts, tOptState * o_st);
56
57static tSuccess
58get_opt_arg_may(tOptions * pOpts, tOptState * o_st);
59
60static tSuccess
61get_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 */
67static int
68parse_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 */
99static void
100opt_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 */
133static int
134opt_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 */
208static tSuccess
209opt_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 */
251static tSuccess
252opt_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 */
289static tSuccess
290opt_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=*/
316void
317optionVendorOption(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 */
370LOCAL tSuccess
371opt_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 */
411LOCAL tSuccess
412opt_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 */
487static tSuccess
488get_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 */
546static tSuccess
547get_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 */
618static tSuccess
619get_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 */
651LOCAL tSuccess
652get_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 */
678LOCAL tSuccess
679find_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