Blame src/libopts/find.c

Packit aea12f
/**
Packit aea12f
 * @file check.c
Packit aea12f
 *
Packit aea12f
 * @brief Hunt for options in the option descriptor list
Packit aea12f
 *
Packit aea12f
 *  This file contains the routines that deal with processing quoted strings
Packit aea12f
 *  into an internal format.
Packit aea12f
 *
Packit aea12f
 * @addtogroup autoopts
Packit aea12f
 * @{
Packit aea12f
 */
Packit aea12f
/*
Packit aea12f
 *  This file is part of AutoOpts, a companion to AutoGen.
Packit aea12f
 *  AutoOpts is free software.
Packit Service 991b93
 *  AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
Packit aea12f
 *
Packit aea12f
 *  AutoOpts is available under any one of two licenses.  The license
Packit aea12f
 *  in use must be one of these two and the choice is under the control
Packit aea12f
 *  of the user of the license.
Packit aea12f
 *
Packit aea12f
 *   The GNU Lesser General Public License, version 3 or later
Packit aea12f
 *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
Packit aea12f
 *
Packit aea12f
 *   The Modified Berkeley Software Distribution License
Packit aea12f
 *      See the file "COPYING.mbsd"
Packit aea12f
 *
Packit aea12f
 *  These files have the following sha256 sums:
Packit aea12f
 *
Packit aea12f
 *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
Packit aea12f
 *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
Packit aea12f
 *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
Packit aea12f
 */
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * find the name and name length we are looking for
Packit aea12f
 */
Packit aea12f
static int
Packit aea12f
parse_opt(char const ** nm_pp, char ** arg_pp, char * buf, size_t bufsz)
Packit aea12f
{
Packit aea12f
    int  res = 0;
Packit aea12f
    char const * p = *nm_pp;
Packit aea12f
    *arg_pp  = NULL;
Packit aea12f
Packit aea12f
    for (;;) {
Packit aea12f
        switch (*(p++)) {
Packit aea12f
        case NUL: return res;
Packit aea12f
Packit aea12f
        case '=':
Packit aea12f
            memcpy(buf, *nm_pp, (size_t)res);
Packit aea12f
Packit aea12f
            buf[res] = NUL;
Packit aea12f
            *nm_pp   = buf;
Packit aea12f
            *arg_pp  = (char *)p;
Packit aea12f
            return res;
Packit aea12f
Packit aea12f
        default:
Packit aea12f
            if (++res >= (int)bufsz)
Packit aea12f
                return -1;
Packit aea12f
        }
Packit aea12f
    }
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 *  print out the options that match the given name.
Packit aea12f
 *
Packit aea12f
 * @param pOpts      option data
Packit aea12f
 * @param opt_name   name of option to look for
Packit aea12f
 */
Packit aea12f
static void
Packit aea12f
opt_ambiguities(tOptions * opts, char const * name, int nm_len)
Packit aea12f
{
Packit aea12f
    char const * const hyph =
Packit aea12f
        NAMED_OPTS(opts) ? "" : LONG_OPT_MARKER;
Packit aea12f
Packit aea12f
    tOptDesc * pOD = opts->pOptDesc;
Packit aea12f
    int        idx = 0;
Packit aea12f
Packit aea12f
    fputs(zambig_list_msg, stderr);
Packit aea12f
    do  {
Packit aea12f
        if (pOD->pz_Name == NULL)
Packit aea12f
            continue; /* doc option */
Packit aea12f
Packit aea12f
        if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0)
Packit aea12f
            fprintf(stderr, zambig_file, hyph, pOD->pz_Name);
Packit aea12f
Packit aea12f
        else if (  (pOD->pz_DisableName != NULL)
Packit aea12f
                && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0)
Packit aea12f
                )
Packit aea12f
            fprintf(stderr, zambig_file, hyph, pOD->pz_DisableName);
Packit aea12f
    } while (pOD++, (++idx < opts->optCt));
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 *  Determine the number of options that match the name
Packit aea12f
 *
Packit aea12f
 * @param pOpts      option data
Packit aea12f
 * @param opt_name   name of option to look for
Packit aea12f
 * @param nm_len     length of provided name
Packit aea12f
 * @param index      pointer to int for option index
Packit aea12f
 * @param disable    pointer to bool to mark disabled option
Packit aea12f
 * @return count of options that match
Packit aea12f
 */
Packit aea12f
static int
Packit aea12f
opt_match_ct(tOptions * opts, char const * name, int nm_len,
Packit aea12f
             int * ixp, bool * disable)
Packit aea12f
{
Packit aea12f
    int   matchCt  = 0;
Packit aea12f
    int   idx      = 0;
Packit aea12f
    int   idxLim   = opts->optCt;
Packit aea12f
    tOptDesc * pOD = opts->pOptDesc;
Packit aea12f
Packit aea12f
    do  {
Packit aea12f
        /*
Packit aea12f
         *  If option disabled or a doc option, skip to next
Packit aea12f
         */
Packit aea12f
        if (pOD->pz_Name == NULL)
Packit aea12f
            continue;
Packit aea12f
Packit aea12f
        if (  SKIP_OPT(pOD)
Packit aea12f
           && (pOD->fOptState != (OPTST_OMITTED | OPTST_NO_INIT)))
Packit aea12f
            continue;
Packit aea12f
Packit aea12f
        if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0) {
Packit aea12f
            /*
Packit aea12f
             *  IF we have a complete match
Packit aea12f
             *  THEN it takes priority over any already located partial
Packit aea12f
             */
Packit aea12f
            if (pOD->pz_Name[ nm_len ] == NUL) {
Packit aea12f
                *ixp = idx;
Packit aea12f
                return 1;
Packit aea12f
            }
Packit aea12f
        }
Packit aea12f
Packit aea12f
        /*
Packit aea12f
         *  IF       there is a disable name
Packit aea12f
         *     *AND* the option name matches the disable name
Packit aea12f
         *  THEN ...
Packit aea12f
         */
Packit aea12f
        else if (  (pOD->pz_DisableName != NULL)
Packit aea12f
                && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0)
Packit aea12f
                )  {
Packit aea12f
            *disable = true;
Packit aea12f
Packit aea12f
            /*
Packit aea12f
             *  IF we have a complete match
Packit aea12f
             *  THEN it takes priority over any already located partial
Packit aea12f
             */
Packit aea12f
            if (pOD->pz_DisableName[ nm_len ] == NUL) {
Packit aea12f
                *ixp = idx;
Packit aea12f
                return 1;
Packit aea12f
            }
Packit aea12f
        }
Packit aea12f
Packit aea12f
        else
Packit aea12f
            continue; /* does not match any option */
Packit aea12f
Packit aea12f
        /*
Packit aea12f
         *  We found a full or partial match, either regular or disabling.
Packit aea12f
         *  Remember the index for later.
Packit aea12f
         */
Packit aea12f
        *ixp = idx;
Packit aea12f
        ++matchCt;
Packit aea12f
Packit aea12f
    } while (pOD++, (++idx < idxLim));
Packit aea12f
Packit aea12f
    return matchCt;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 *  Set the option to the indicated option number.
Packit aea12f
 *
Packit aea12f
 * @param opts      option data
Packit aea12f
 * @param arg       option argument (if glued to name)
Packit aea12f
 * @param idx       option index
Packit aea12f
 * @param disable   mark disabled option
Packit aea12f
 * @param st        state about current option
Packit aea12f
 */
Packit aea12f
static tSuccess
Packit aea12f
opt_set(tOptions * opts, char * arg, int idx, bool disable, tOptState * st)
Packit aea12f
{
Packit aea12f
    tOptDesc * pOD = opts->pOptDesc + idx;
Packit aea12f
Packit aea12f
    if (SKIP_OPT(pOD)) {
Packit aea12f
        if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0)
Packit aea12f
            return FAILURE;
Packit aea12f
Packit aea12f
        fprintf(stderr, zDisabledErr, opts->pzProgName, pOD->pz_Name);
Packit aea12f
        if (pOD->pzText != NULL)
Packit aea12f
            fprintf(stderr, SET_OFF_FMT, pOD->pzText);
Packit aea12f
        fputc(NL, stderr);
Packit aea12f
        (*opts->pUsageProc)(opts, EXIT_FAILURE);
Packit aea12f
        /* NOTREACHED */
Packit aea12f
        _exit(EXIT_FAILURE); /* to be certain */
Packit aea12f
    }
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  IF we found a disablement name,
Packit aea12f
     *  THEN set the bit in the callers' flag word
Packit aea12f
     */
Packit aea12f
    if (disable)
Packit aea12f
        st->flags |= OPTST_DISABLED;
Packit aea12f
Packit aea12f
    st->pOD      = pOD;
Packit aea12f
    st->pzOptArg = arg;
Packit aea12f
    st->optType  = TOPT_LONG;
Packit aea12f
Packit aea12f
    return SUCCESS;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 *  An option was not found.  Check for default option and set it
Packit aea12f
 *  if there is one.  Otherwise, handle the error.
Packit aea12f
 *
Packit aea12f
 * @param opts   option data
Packit aea12f
 * @param name   name of option to look for
Packit aea12f
 * @param arg    option argument
Packit aea12f
 * @param st     state about current option
Packit aea12f
 *
Packit aea12f
 * @return success status
Packit aea12f
 */
Packit aea12f
static tSuccess
Packit aea12f
opt_unknown(tOptions * opts, char const * name, char * arg, tOptState * st)
Packit aea12f
{
Packit aea12f
    /*
Packit aea12f
     *  IF there is no equal sign
Packit aea12f
     *     *AND* we are using named arguments
Packit aea12f
     *     *AND* there is a default named option,
Packit aea12f
     *  THEN return that option.
Packit aea12f
     */
Packit aea12f
    if (  (arg == NULL)
Packit aea12f
       && NAMED_OPTS(opts)
Packit aea12f
       && (opts->specOptIdx.default_opt != NO_EQUIVALENT)) {
Packit aea12f
Packit aea12f
        st->pOD      = opts->pOptDesc + opts->specOptIdx.default_opt;
Packit aea12f
        st->pzOptArg = name;
Packit aea12f
        st->optType  = TOPT_DEFAULT;
Packit aea12f
        return SUCCESS;
Packit aea12f
    }
Packit aea12f
Packit aea12f
    if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) {
Packit aea12f
        fprintf(stderr, zIllOptStr, opts->pzProgPath, name);
Packit aea12f
        (*opts->pUsageProc)(opts, EXIT_FAILURE);
Packit aea12f
        /* NOTREACHED */
Packit aea12f
        _exit(EXIT_FAILURE); /* to be certain */
Packit aea12f
    }
Packit aea12f
Packit aea12f
    return FAILURE;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 *  Several options match the provided name.
Packit aea12f
 *
Packit aea12f
 * @param opts      option data
Packit aea12f
 * @param name      name of option to look for
Packit aea12f
 * @param match_ct  number of matching options
Packit aea12f
 *
Packit aea12f
 * @return success status (always FAILURE, if it returns)
Packit aea12f
 */
Packit aea12f
static tSuccess
Packit aea12f
opt_ambiguous(tOptions * opts, char const * name, int match_ct)
Packit aea12f
{
Packit aea12f
    if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) {
Packit aea12f
        fprintf(stderr, zambig_opt_fmt, opts->pzProgPath, name, match_ct);
Packit aea12f
        if (match_ct <= 4)
Packit aea12f
            opt_ambiguities(opts, name, (int)strlen(name));
Packit aea12f
        (*opts->pUsageProc)(opts, EXIT_FAILURE);
Packit aea12f
        /* NOTREACHED */
Packit aea12f
        _exit(EXIT_FAILURE); /* to be certain */
Packit aea12f
    }
Packit aea12f
    return FAILURE;
Packit aea12f
}
Packit aea12f
Packit aea12f
/*=export_func  optionVendorOption
Packit aea12f
 * private:
Packit aea12f
 *
Packit aea12f
 * what:  Process a vendor option
Packit aea12f
 * arg:   + tOptions * + pOpts    + program options descriptor +
Packit aea12f
 * arg:   + tOptDesc * + pOptDesc + the descriptor for this arg +
Packit aea12f
 *
Packit aea12f
 * doc:
Packit aea12f
 *  For POSIX specified utilities, the options are constrained to the options,
Packit aea12f
 *  @xref{config attributes, Program Configuration}.  AutoOpts clients should
Packit aea12f
 *  never specify this directly.  It gets referenced when the option
Packit aea12f
 *  definitions contain a "vendor-opt" attribute.
Packit aea12f
=*/
Packit aea12f
void
Packit aea12f
optionVendorOption(tOptions * pOpts, tOptDesc * pOD)
Packit aea12f
{
Packit aea12f
    tOptState     opt_st   = OPTSTATE_INITIALIZER(PRESET);
Packit aea12f
    char const *  vopt_str = pOD->optArg.argString;
Packit aea12f
Packit aea12f
    if (pOpts <= OPTPROC_EMIT_LIMIT)
Packit aea12f
        return;
Packit aea12f
Packit aea12f
    if ((pOD->fOptState & OPTST_RESET) != 0)
Packit aea12f
        return;
Packit aea12f
Packit aea12f
    if ((pOD->fOptState & OPTPROC_IMMEDIATE) == 0)
Packit aea12f
        opt_st.flags = OPTST_DEFINED;
Packit aea12f
Packit aea12f
    if (  ((pOpts->fOptSet & OPTPROC_VENDOR_OPT) == 0)
Packit aea12f
       || ! SUCCESSFUL(opt_find_long(pOpts, vopt_str, &opt_st))
Packit aea12f
       || ! SUCCESSFUL(get_opt_arg(pOpts, &opt_st)) )
Packit aea12f
    {
Packit aea12f
        fprintf(stderr, zIllVendOptStr, pOpts->pzProgName, vopt_str);
Packit aea12f
        (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
Packit aea12f
        /* NOTREACHED */
Packit aea12f
        _exit(EXIT_FAILURE); /* to be certain */
Packit aea12f
    }
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  See if we are in immediate handling state.
Packit aea12f
     */
Packit aea12f
    if (pOpts->fOptSet & OPTPROC_IMMEDIATE) {
Packit aea12f
        /*
Packit aea12f
         *  See if the enclosed option is okay with that state.
Packit aea12f
         */
Packit aea12f
        if (DO_IMMEDIATELY(opt_st.flags))
Packit aea12f
            (void)handle_opt(pOpts, &opt_st);
Packit aea12f
Packit aea12f
    } else {
Packit aea12f
        /*
Packit aea12f
         *  non-immediate direction.
Packit aea12f
         *  See if the enclosed option is okay with that state.
Packit aea12f
         */
Packit aea12f
        if (DO_NORMALLY(opt_st.flags) || DO_SECOND_TIME(opt_st.flags))
Packit aea12f
            (void)handle_opt(pOpts, &opt_st);
Packit aea12f
    }
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 *  Find the option descriptor by full name.
Packit aea12f
 *
Packit aea12f
 * @param opts      option data
Packit aea12f
 * @param opt_name  name of option to look for
Packit aea12f
 * @param state     state about current option
Packit aea12f
 *
Packit aea12f
 * @return success status
Packit aea12f
 */
Packit Service 991b93
static tSuccess
Packit aea12f
opt_find_long(tOptions * opts, char const * opt_name, tOptState * state)
Packit aea12f
{
Packit aea12f
    char    name_buf[128];
Packit aea12f
    char *  opt_arg;
Packit aea12f
    int     nm_len = parse_opt(&opt_name, &opt_arg, name_buf, sizeof(name_buf));
Packit aea12f
Packit aea12f
    int     idx = 0;
Packit aea12f
    bool    disable  = false;
Packit aea12f
    int     ct;
Packit aea12f
Packit aea12f
    if (nm_len <= 1) {
Packit aea12f
        if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0)
Packit aea12f
            return FAILURE;
Packit aea12f
        
Packit aea12f
        fprintf(stderr, zInvalOptName, opts->pzProgName, opt_name);
Packit aea12f
        (*opts->pUsageProc)(opts, EXIT_FAILURE);
Packit aea12f
        /* NOTREACHED */
Packit aea12f
        _exit(EXIT_FAILURE); /* to be certain */
Packit aea12f
    }
Packit aea12f
Packit aea12f
    ct = opt_match_ct(opts, opt_name, nm_len, &idx, &disable);
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  See if we found one match, no matches or multiple matches.
Packit aea12f
     */
Packit aea12f
    switch (ct) {
Packit aea12f
    case 1:  return opt_set(opts, opt_arg, idx, disable, state);
Packit aea12f
    case 0:  return opt_unknown(opts, opt_name, opt_arg, state);
Packit aea12f
    default: return opt_ambiguous(opts, opt_name, ct);
Packit aea12f
    }
Packit aea12f
}
Packit aea12f
Packit aea12f
Packit aea12f
/**
Packit aea12f
 *  Find the short option descriptor for the current option
Packit aea12f
 *
Packit aea12f
 * @param pOpts      option data
Packit aea12f
 * @param optValue   option flag character
Packit aea12f
 * @param pOptState  state about current option
Packit aea12f
 */
Packit Service 991b93
static tSuccess
Packit aea12f
opt_find_short(tOptions * pOpts, uint_t optValue, tOptState * pOptState)
Packit aea12f
{
Packit aea12f
    tOptDesc * pRes = pOpts->pOptDesc;
Packit aea12f
    int        ct   = pOpts->optCt;
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  Search the option list
Packit aea12f
     */
Packit aea12f
    do  {
Packit aea12f
        if (optValue != pRes->optValue)
Packit aea12f
            continue;
Packit aea12f
Packit aea12f
        if (SKIP_OPT(pRes)) {
Packit aea12f
            if (  (pRes->fOptState == (OPTST_OMITTED | OPTST_NO_INIT))
Packit aea12f
               && (pRes->pz_Name != NULL)) {
Packit aea12f
                if ((pOpts->fOptSet & OPTPROC_ERRSTOP) == 0)
Packit aea12f
                    return FAILURE;
Packit aea12f
        
Packit aea12f
                fprintf(stderr, zDisabledErr, pOpts->pzProgPath, pRes->pz_Name);
Packit aea12f
                if (pRes->pzText != NULL)
Packit aea12f
                    fprintf(stderr, SET_OFF_FMT, pRes->pzText);
Packit aea12f
                fputc(NL, stderr);
Packit aea12f
                (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
Packit aea12f
                /* NOTREACHED */
Packit aea12f
                _exit(EXIT_FAILURE); /* to be certain */
Packit aea12f
            }
Packit aea12f
            goto short_opt_error;
Packit aea12f
        }
Packit aea12f
Packit aea12f
        pOptState->pOD     = pRes;
Packit aea12f
        pOptState->optType = TOPT_SHORT;
Packit aea12f
        return SUCCESS;
Packit aea12f
Packit aea12f
    } while (pRes++, --ct > 0);
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  IF    the character value is a digit
Packit aea12f
     *    AND there is a special number option ("-n")
Packit aea12f
     *  THEN the result is the "option" itself and the
Packit aea12f
     *       option is the specially marked "number" option.
Packit aea12f
     */
Packit aea12f
    if (  IS_DEC_DIGIT_CHAR(optValue)
Packit aea12f
       && (pOpts->specOptIdx.number_option != NO_EQUIVALENT) ) {
Packit aea12f
        pOptState->pOD = \
Packit aea12f
        pRes           = pOpts->pOptDesc + pOpts->specOptIdx.number_option;
Packit aea12f
        (pOpts->pzCurOpt)--;
Packit aea12f
        pOptState->optType = TOPT_SHORT;
Packit aea12f
        return SUCCESS;
Packit aea12f
    }
Packit aea12f
Packit aea12f
 short_opt_error:
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  IF we are to stop on errors (the default, actually)
Packit aea12f
     *  THEN call the usage procedure.
Packit aea12f
     */
Packit aea12f
    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
Packit aea12f
        fprintf(stderr, zIllOptChr, pOpts->pzProgPath, optValue);
Packit aea12f
        (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
Packit aea12f
        /* NOTREACHED */
Packit aea12f
        _exit(EXIT_FAILURE); /* to be certain */
Packit aea12f
    }
Packit aea12f
Packit aea12f
    return FAILURE;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 *  Process option with a required argument.  Long options can either have a
Packit aea12f
 *  separate command line argument, or an argument attached by the '='
Packit aea12f
 *  character.  Figure out which.
Packit aea12f
 *
Packit aea12f
 *  @param[in,out] opts  the program option descriptor
Packit aea12f
 *  @param[in,out] o_st  the option processing state
Packit aea12f
 *  @returns SUCCESS or FAILURE
Packit aea12f
 */
Packit aea12f
static tSuccess
Packit aea12f
get_opt_arg_must(tOptions * opts, tOptState * o_st)
Packit aea12f
{
Packit aea12f
    switch (o_st->optType) {
Packit aea12f
    case TOPT_SHORT:
Packit aea12f
        /*
Packit aea12f
         *  See if an arg string follows the flag character
Packit aea12f
         */
Packit aea12f
        if (*++(opts->pzCurOpt) == NUL)
Packit aea12f
            opts->pzCurOpt = opts->origArgVect[ opts->curOptIdx++ ];
Packit aea12f
        o_st->pzOptArg = opts->pzCurOpt;
Packit aea12f
        break;
Packit aea12f
Packit aea12f
    case TOPT_LONG:
Packit aea12f
        /*
Packit aea12f
         *  See if an arg string has already been assigned (glued on
Packit aea12f
         *  with an `=' character)
Packit aea12f
         */
Packit aea12f
        if (o_st->pzOptArg == NULL)
Packit aea12f
            o_st->pzOptArg = opts->origArgVect[ opts->curOptIdx++ ];
Packit aea12f
        break;
Packit aea12f
Packit aea12f
    default:
Packit aea12f
#ifdef DEBUG
Packit aea12f
        fputs("AutoOpts lib error: option type not selected\n", stderr);
Packit aea12f
        option_exits(EXIT_FAILURE);
Packit aea12f
#endif
Packit aea12f
Packit aea12f
    case TOPT_DEFAULT:
Packit aea12f
        /*
Packit aea12f
         *  The option was selected by default.  The current token is
Packit aea12f
         *  the option argument.
Packit aea12f
         */
Packit aea12f
        break;
Packit aea12f
    }
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  Make sure we did not overflow the argument list.
Packit aea12f
     */
Packit aea12f
    if (opts->curOptIdx > opts->origArgCt) {
Packit aea12f
        fprintf(stderr, zMisArg, opts->pzProgPath, o_st->pOD->pz_Name);
Packit aea12f
        return FAILURE;
Packit aea12f
    }
Packit aea12f
Packit aea12f
    opts->pzCurOpt = NULL;  /* next time advance to next arg */
Packit aea12f
    return SUCCESS;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 * Process an option with an optional argument.  For short options, it looks
Packit aea12f
 * at the character after the option character, or it consumes the next full
Packit aea12f
 * argument.  For long options, it looks for an '=' character attachment to
Packit aea12f
 * the long option name before deciding to take the next command line
Packit aea12f
 * argument.
Packit aea12f
 *
Packit aea12f
 * @param pOpts      the option descriptor
Packit aea12f
 * @param o_st  a structure for managing the current processing state
Packit aea12f
 * @returns SUCCESS or does not return
Packit aea12f
 */
Packit aea12f
static tSuccess
Packit aea12f
get_opt_arg_may(tOptions * pOpts, tOptState * o_st)
Packit aea12f
{
Packit aea12f
    /*
Packit aea12f
     *  An option argument is optional.
Packit aea12f
     */
Packit aea12f
    switch (o_st->optType) {
Packit aea12f
    case TOPT_SHORT:
Packit aea12f
        if (*++pOpts->pzCurOpt != NUL)
Packit aea12f
            o_st->pzOptArg = pOpts->pzCurOpt;
Packit aea12f
        else {
Packit aea12f
            char * pzLA = pOpts->origArgVect[ pOpts->curOptIdx ];
Packit aea12f
Packit aea12f
            /*
Packit aea12f
             *  BECAUSE it is optional, we must make sure
Packit aea12f
             *  we did not find another flag and that there
Packit aea12f
             *  is such an argument.
Packit aea12f
             */
Packit aea12f
            if ((pzLA == NULL) || (*pzLA == '-'))
Packit aea12f
                o_st->pzOptArg = NULL;
Packit aea12f
            else {
Packit aea12f
                pOpts->curOptIdx++; /* argument found */
Packit aea12f
                o_st->pzOptArg = pzLA;
Packit aea12f
            }
Packit aea12f
        }
Packit aea12f
        break;
Packit aea12f
Packit aea12f
    case TOPT_LONG:
Packit aea12f
        /*
Packit aea12f
         *  Look for an argument if we don't already have one (glued on
Packit aea12f
         *  with a `=' character) *AND* we are not in named argument mode
Packit aea12f
         */
Packit aea12f
        if (  (o_st->pzOptArg == NULL)
Packit aea12f
           && (! NAMED_OPTS(pOpts))) {
Packit aea12f
            char * pzLA = pOpts->origArgVect[ pOpts->curOptIdx ];
Packit aea12f
Packit aea12f
            /*
Packit aea12f
             *  BECAUSE it is optional, we must make sure
Packit aea12f
             *  we did not find another flag and that there
Packit aea12f
             *  is such an argument.
Packit aea12f
             */
Packit aea12f
            if ((pzLA == NULL) || (*pzLA == '-'))
Packit aea12f
                o_st->pzOptArg = NULL;
Packit aea12f
            else {
Packit aea12f
                pOpts->curOptIdx++; /* argument found */
Packit aea12f
                o_st->pzOptArg = pzLA;
Packit aea12f
            }
Packit aea12f
        }
Packit aea12f
        break;
Packit aea12f
Packit aea12f
    default:
Packit aea12f
    case TOPT_DEFAULT:
Packit aea12f
        ao_bug(zbad_default_msg);
Packit aea12f
    }
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  After an option with an optional argument, we will
Packit aea12f
     *  *always* start with the next option because if there
Packit aea12f
     *  were any characters following the option name/flag,
Packit aea12f
     *  they would be interpreted as the argument.
Packit aea12f
     */
Packit aea12f
    pOpts->pzCurOpt = NULL;
Packit aea12f
    return SUCCESS;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 *  Process option that does not have an argument.
Packit aea12f
 *
Packit aea12f
 *  @param[in,out] opts  the program option descriptor
Packit aea12f
 *  @param[in,out] o_st  the option processing state
Packit aea12f
 *  @returns SUCCESS or FAILURE
Packit aea12f
 */
Packit aea12f
static tSuccess
Packit aea12f
get_opt_arg_none(tOptions * pOpts, tOptState * o_st)
Packit aea12f
{
Packit aea12f
    /*
Packit aea12f
     *  No option argument.  Make sure next time around we find
Packit aea12f
     *  the correct option flag character for short options
Packit aea12f
     */
Packit aea12f
    if (o_st->optType == TOPT_SHORT)
Packit aea12f
        (pOpts->pzCurOpt)++;
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  It is a long option.  Make sure there was no ``=xxx'' argument
Packit aea12f
     */
Packit aea12f
    else if (o_st->pzOptArg != NULL) {
Packit aea12f
        fprintf(stderr, zNoArg, pOpts->pzProgPath, o_st->pOD->pz_Name);
Packit aea12f
        return FAILURE;
Packit aea12f
    }
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  It is a long option.  Advance to next command line argument.
Packit aea12f
     */
Packit aea12f
    else
Packit aea12f
        pOpts->pzCurOpt = NULL;
Packit Service 991b93
Packit aea12f
    return SUCCESS;
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 *  Process option.  Figure out whether or not to look for an option argument.
Packit aea12f
 *
Packit aea12f
 *  @param[in,out] opts  the program option descriptor
Packit aea12f
 *  @param[in,out] o_st  the option processing state
Packit aea12f
 *  @returns SUCCESS or FAILURE
Packit aea12f
 */
Packit Service 991b93
static tSuccess
Packit aea12f
get_opt_arg(tOptions * opts, tOptState * o_st)
Packit aea12f
{
Packit aea12f
    o_st->flags |= (o_st->pOD->fOptState & OPTST_PERSISTENT_MASK);
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     * Disabled options and options specified to not have arguments
Packit aea12f
     * are handled with the "none" procedure.  Otherwise, check the
Packit aea12f
     * optional flag and call either the "may" or "must" function.
Packit aea12f
     */
Packit Service 991b93
    if ((o_st->flags & OPTST_DISABLED) != 0)
Packit aea12f
        return get_opt_arg_none(opts, o_st);
Packit Service 991b93
Packit Service 991b93
    switch (OPTST_GET_ARGTYPE(o_st->flags)) {
Packit Service 991b93
    case OPARG_TYPE_STATIC:
Packit Service 991b93
    {
Packit Service 991b93
        /*
Packit Service 991b93
         * Propagate the static arg
Packit Service 991b93
         */
Packit Service 991b93
        tSuccess res = get_opt_arg_none(opts, o_st);
Packit Service 991b93
        o_st->pzOptArg = o_st->pOD->optArg.argString;
Packit Service 991b93
        return res;
Packit Service 991b93
    }
Packit Service 991b93
Packit Service 991b93
    case OPARG_TYPE_NONE:
Packit Service 991b93
        return get_opt_arg_none(opts, o_st);
Packit Service 991b93
    }
Packit Service 991b93
Packit aea12f
    if (o_st->flags & OPTST_ARG_OPTIONAL)
Packit aea12f
        return get_opt_arg_may( opts, o_st);
Packit aea12f
    
Packit aea12f
    return get_opt_arg_must(opts, o_st);
Packit aea12f
}
Packit aea12f
Packit aea12f
/**
Packit aea12f
 *  Find the option descriptor for the current option.
Packit aea12f
 *
Packit aea12f
 *  @param[in,out] opts  the program option descriptor
Packit aea12f
 *  @param[in,out] o_st  the option processing state
Packit aea12f
 *  @returns SUCCESS or FAILURE
Packit aea12f
 */
Packit Service 991b93
static tSuccess
Packit aea12f
find_opt(tOptions * opts, tOptState * o_st)
Packit aea12f
{
Packit aea12f
    /*
Packit aea12f
     *  IF we are continuing a short option list (e.g. -xyz...)
Packit aea12f
     *  THEN continue a single flag option.
Packit aea12f
     *  OTHERWISE see if there is room to advance and then do so.
Packit aea12f
     */
Packit aea12f
    if ((opts->pzCurOpt != NULL) && (*opts->pzCurOpt != NUL))
Packit aea12f
        return opt_find_short(opts, (uint8_t)*(opts->pzCurOpt), o_st);
Packit aea12f
Packit aea12f
    if (opts->curOptIdx >= opts->origArgCt)
Packit aea12f
        return PROBLEM; /* NORMAL COMPLETION */
Packit aea12f
Packit aea12f
    opts->pzCurOpt = opts->origArgVect[ opts->curOptIdx ];
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  IF all arguments must be named options, ...
Packit aea12f
     */
Packit aea12f
    if (NAMED_OPTS(opts)) {
Packit aea12f
        char *      pz  = opts->pzCurOpt;
Packit aea12f
        int         def;
Packit aea12f
        tSuccess    res;
Packit aea12f
        uint16_t *  def_opt;
Packit aea12f
Packit aea12f
        opts->curOptIdx++;
Packit aea12f
Packit aea12f
        if (*pz != '-')
Packit aea12f
            return opt_find_long(opts, pz, o_st);
Packit aea12f
Packit aea12f
        /*
Packit aea12f
         *  The name is prefixed with one or more hyphens.  Strip them off
Packit aea12f
         *  and disable the "default_opt" setting.  Use heavy recasting to
Packit aea12f
         *  strip off the "const" quality of the "default_opt" field.
Packit aea12f
         */
Packit aea12f
        while (*(++pz) == '-')   ;
Packit aea12f
        def_opt  = VOIDP(&(opts->specOptIdx.default_opt));
Packit aea12f
        def      = *def_opt;
Packit aea12f
        *def_opt = NO_EQUIVALENT;
Packit aea12f
        res      = opt_find_long(opts, pz, o_st);
Packit aea12f
        *def_opt = (uint16_t)def;
Packit aea12f
        return res;
Packit aea12f
    }
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  Note the kind of flag/option marker
Packit aea12f
     */
Packit aea12f
    if (*((opts->pzCurOpt)++) != '-')
Packit aea12f
        return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  Special hack for a hyphen by itself
Packit aea12f
     */
Packit aea12f
    if (*(opts->pzCurOpt) == NUL)
Packit aea12f
        return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  The current argument is to be processed as an option argument
Packit aea12f
     */
Packit aea12f
    opts->curOptIdx++;
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  We have an option marker.
Packit aea12f
     *  Test the next character for long option indication
Packit aea12f
     */
Packit aea12f
    if (opts->pzCurOpt[0] == '-') {
Packit aea12f
        if (*++(opts->pzCurOpt) == NUL)
Packit aea12f
            /*
Packit aea12f
             *  NORMAL COMPLETION - NOT this arg, but rest are operands
Packit aea12f
             */
Packit aea12f
            return PROBLEM;
Packit aea12f
Packit aea12f
        /*
Packit aea12f
         *  We do not allow the hyphen to be used as a flag value.
Packit aea12f
         *  Therefore, if long options are not to be accepted, we punt.
Packit aea12f
         */
Packit aea12f
        if ((opts->fOptSet & OPTPROC_LONGOPT) == 0) {
Packit aea12f
            fprintf(stderr, zIllOptStr, opts->pzProgPath, opts->pzCurOpt-2);
Packit aea12f
            return FAILURE;
Packit aea12f
        }
Packit aea12f
Packit aea12f
        return opt_find_long(opts, opts->pzCurOpt, o_st);
Packit aea12f
    }
Packit aea12f
Packit aea12f
    /*
Packit aea12f
     *  If short options are not allowed, then do long
Packit aea12f
     *  option processing.  Otherwise the character must be a
Packit aea12f
     *  short (i.e. single character) option.
Packit aea12f
     */
Packit aea12f
    if ((opts->fOptSet & OPTPROC_SHORTOPT) != 0)
Packit aea12f
        return opt_find_short(opts, (uint8_t)*(opts->pzCurOpt), o_st);
Packit aea12f
Packit aea12f
    return opt_find_long(opts, opts->pzCurOpt, o_st);
Packit aea12f
}
Packit aea12f
Packit aea12f
/** @}
Packit aea12f
 *
Packit aea12f
 * Local Variables:
Packit aea12f
 * mode: C
Packit aea12f
 * c-file-style: "stroustrup"
Packit aea12f
 * indent-tabs-mode: nil
Packit aea12f
 * End:
Packit aea12f
 * end of autoopts/find.c */