Home | History | Annotate | Line # | Download | only in libopts
find.c revision 1.8
      1 /*	$NetBSD: find.c,v 1.8 2020/05/25 20:47:34 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-2015 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  = VOIDP(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  = VOIDP(&(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