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