Ejemplo n.º 1
0
/**
 * Process all the options from our current position onward.  (This allows
 * interspersed options and arguments for the few non-standard programs that
 * require it.)  Thus, do not rewind option indexes because some programs
 * choose to re-invoke after a non-option.
 */
LOCAL tSuccess
doRegularOpts(tOptions* pOpts)
{
    for (;;) {
        tOptState optState = OPTSTATE_INITIALIZER(DEFINED);

        switch (nextOption(pOpts, &optState)) {
        case FAILURE: goto   failed_option;
        case PROBLEM: return SUCCESS; /* no more args */
        case SUCCESS: break;
        }

        /*
         *  IF this is an immediate action option,
         *  THEN skip it (unless we are supposed to do it a second time).
         */
        if (! DO_NORMALLY(optState.flags)) {
            if (! DO_SECOND_TIME(optState.flags))
                continue;
            optState.pOD->optOccCt--; /* don't count this repetition */
        }

        if (! SUCCESSFUL(handle_opt(pOpts, &optState)))
            break;
    } failed_option:;

    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0)
        (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);

    return FAILURE;
}
Ejemplo n.º 2
0
/*=export_func  optionResetOpt
 * private:
 *
 * what:  Reset the value of an option
 * arg:   + tOptions* + pOpts    + program options descriptor  +
 * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
 *
 * doc:
 *  This code will cause another option to be reset to its initial state.
 *  For example, --reset=foo will cause the --foo option to be reset.
=*/
void
optionResetOpt( tOptions* pOpts, tOptDesc* pOD )
{
    static ag_bool reset_active = AG_FALSE;

    tOptState opt_state = OPTSTATE_INITIALIZER(DEFINED);
    char const * pzArg = pOD->optArg.argString;
    tSuccess     succ;

    if (reset_active)
        return;

    if (  (! HAS_originalOptArgArray(pOpts))
       || (pOpts->originalOptArgCookie == NULL)) {
        fputs(zResetNotConfig, stderr);
        _exit(EX_SOFTWARE);
    }

    if ((pzArg == NULL) || (*pzArg == NUL)) {
        fputs(zNoResetArg, stderr);
        pOpts->pUsageProc(pOpts, EXIT_FAILURE);
        /* NOTREACHED */
        assert(0 == 1);
    }

    reset_active = AG_TRUE;

    if (pzArg[1] == NUL) {
        if (*pzArg == '*') {
            optionResetEverything(pOpts);
            reset_active = AG_FALSE;
            return;
        }

        succ = shortOptionFind(pOpts, (tAoUC)*pzArg, &opt_state);
        if (! SUCCESSFUL(succ)) {
            fprintf(stderr, zIllOptChr, pOpts->pzProgPath, *pzArg);
            pOpts->pUsageProc(pOpts, EXIT_FAILURE);
            /* NOTREACHED */
            assert(0 == 1);
        }
    } else {
        succ = longOptionFind(pOpts, (char *)pzArg, &opt_state);
        if (! SUCCESSFUL(succ)) {
            fprintf(stderr, zIllOptStr, pOpts->pzProgPath, pzArg);
            pOpts->pUsageProc(pOpts, EXIT_FAILURE);
            /* NOTREACHED */
            assert(0 == 1);
        }
    }

    /*
     *  We've found the indicated option.  Turn off all non-persistent
     *  flags because we're forcing the option back to its initialized state.
     *  Call any callout procedure to handle whatever it needs to.
     *  Finally, clear the reset flag, too.
     */
    optionReset(pOpts, opt_state.pOD);
    reset_active = AG_FALSE;
}
Ejemplo n.º 3
0
/**
 *  scan the command line for immediate action options.
 *  This is only called the first time through.
 */
LOCAL tSuccess
doImmediateOpts(tOptions* pOpts)
{
    pOpts->curOptIdx = 1;     /* start by skipping program name */
    pOpts->pzCurOpt  = NULL;

    /*
     *  Examine all the options from the start.  We process any options that
     *  are marked for immediate processing.
     */
    for (;;) {
        tOptState optState = OPTSTATE_INITIALIZER(PRESET);

        switch (nextOption(pOpts, &optState)) {
        case FAILURE: goto   failed_option;
        case PROBLEM: return SUCCESS; /* no more args */
        case SUCCESS: break;
        }

        /*
         *  IF this is an immediate-attribute option, then do it.
         */
        if (! DO_IMMEDIATELY(optState.flags))
            continue;

        if (! SUCCESSFUL(handle_opt(pOpts, &optState)))
            break;
    } failed_option:;

    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0)
        (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);

    return FAILURE;
}
Ejemplo n.º 4
0
/*=export_func  optionLoadLine
 *
 * what:  process a string for an option name and value
 *
 * arg:   tOptions*,   pOpts,  program options descriptor
 * arg:   char const*, pzLine, NUL-terminated text
 *
 * doc:
 *
 *  This is a client program callable routine for setting options from, for
 *  example, the contents of a file that they read in.  Only one option may
 *  appear in the text.  It will be treated as a normal (non-preset) option.
 *
 *  When passed a pointer to the option struct and a string, it will find
 *  the option named by the first token on the string and set the option
 *  argument to the remainder of the string.  The caller must NUL terminate
 *  the string.  Any embedded new lines will be included in the option
 *  argument.  If the input looks like one or more quoted strings, then the
 *  input will be "cooked".  The "cooking" is identical to the string
 *  formation used in AutoGen definition files (@pxref{basic expression}),
 *  except that you may not use backquotes.
 *
 * err:   Invalid options are silently ignored.  Invalid option arguments
 *        will cause a warning to print, but the function should return.
=*/
void
optionLoadLine(tOptions * pOpts, char const * pzLine)
{
    tOptState st = OPTSTATE_INITIALIZER(SET);
    char* pz;
    AGDUPSTR(pz, pzLine, "user option line");
    loadOptionLine(pOpts, &st, pz, DIRECTION_PROCESS, OPTION_LOAD_COOKED);
    AGFREE(pz);
}
Ejemplo n.º 5
0
/*=export_func  optionLoadLine
 *
 * what:  process a string for an option name and value
 *
 * arg:   tOptions *,   opts,  program options descriptor
 * arg:   char const *, line,  NUL-terminated text
 *
 * doc:
 *
 *  This is a client program callable routine for setting options from, for
 *  example, the contents of a file that they read in.  Only one option may
 *  appear in the text.  It will be treated as a normal (non-preset) option.
 *
 *  When passed a pointer to the option struct and a string, it will find
 *  the option named by the first token on the string and set the option
 *  argument to the remainder of the string.  The caller must NUL terminate
 *  the string.  The caller need not skip over any introductory hyphens.
 *  Any embedded new lines will be included in the option
 *  argument.  If the input looks like one or more quoted strings, then the
 *  input will be "cooked".  The "cooking" is identical to the string
 *  formation used in AutoGen definition files (@pxref{basic expression}),
 *  except that you may not use backquotes.
 *
 * err:   Invalid options are silently ignored.  Invalid option arguments
 *        will cause a warning to print, but the function should return.
=*/
void
optionLoadLine(tOptions * opts, char const * line)
{
    tOptState st = OPTSTATE_INITIALIZER(SET);
    char *    pz;
    proc_state_mask_t sv_flags = opts->fOptSet;
    opts->fOptSet &= ~OPTPROC_ERRSTOP;
    AGDUPSTR(pz, line, "opt line");
    load_opt_line(opts, &st, pz, DIRECTION_CALLED, OPTION_LOAD_COOKED);
    AGFREE(pz);
    opts->fOptSet = sv_flags;
}
Ejemplo n.º 6
0
/*=export_func  optionVendorOption
 * private:
 *
 * what:  Process a vendor option
 * arg:   + tOptions * + pOpts    + program options descriptor +
 * arg:   + tOptDesc * + pOptDesc + the descriptor for this arg +
 *
 * doc:
 *  For POSIX specified utilities, the options are constrained to the options,
 *  @xref{config attributes, Program Configuration}.  AutoOpts clients should
 *  never specify this directly.  It gets referenced when the option
 *  definitions contain a "vendor-opt" attribute.
=*/
void
optionVendorOption(tOptions * pOpts, tOptDesc * pOD)
{
    tOptState     opt_st   = OPTSTATE_INITIALIZER(PRESET);
    char const *  vopt_str = pOD->optArg.argString;

    if (pOpts <= OPTPROC_EMIT_LIMIT)
        return;

    if ((pOD->fOptState & OPTST_RESET) != 0)
        return;

    if ((pOD->fOptState & OPTPROC_IMMEDIATE) == 0)
        opt_st.flags = OPTST_DEFINED;

    if (  ((pOpts->fOptSet & OPTPROC_VENDOR_OPT) == 0)
       || ! SUCCESSFUL(opt_find_long(pOpts, vopt_str, &opt_st))
       || ! SUCCESSFUL(get_opt_arg(pOpts, &opt_st)) )
    {
        fprintf(stderr, zIllVendOptStr, pOpts->pzProgName, vopt_str);
        (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
        /* NOTREACHED */
        _exit(EXIT_FAILURE); /* to be certain */
    }

    /*
     *  See if we are in immediate handling state.
     */
    if (pOpts->fOptSet & OPTPROC_IMMEDIATE) {
        /*
         *  See if the enclosed option is okay with that state.
         */
        if (DO_IMMEDIATELY(opt_st.flags))
            (void)handle_opt(pOpts, &opt_st);

    } else {
        /*
         *  non-immediate direction.
         *  See if the enclosed option is okay with that state.
         */
        if (DO_NORMALLY(opt_st.flags) || DO_SECOND_TIME(opt_st.flags))
            (void)handle_opt(pOpts, &opt_st);
    }
}
Ejemplo n.º 7
0
/**
 *  scan the command line for immediate action options.
 *  This is only called the first time through.
 *  While this procedure is active, the OPTPROC_IMMEDIATE is true.
 *
 *  @param pOpts   program options descriptor
 *  @returns SUCCESS or FAILURE
 */
LOCAL tSuccess
immediate_opts(tOptions * opts)
{
    tSuccess  res;

    opts->fOptSet  |= OPTPROC_IMMEDIATE;
    opts->curOptIdx = 1;     /* start by skipping program name */
    opts->pzCurOpt  = NULL;

    /*
     *  Examine all the options from the start.  We process any options that
     *  are marked for immediate processing.
     */
    for (;;) {
        tOptState opt_st = OPTSTATE_INITIALIZER(PRESET);

        res = next_opt(opts, &opt_st);
        switch (res) {
        case FAILURE: goto   failed_option;
        case PROBLEM: res = SUCCESS; goto leave;
        case SUCCESS: break;
        }

        /*
         *  IF this is an immediate-attribute option, then do it.
         */
        if (! DO_IMMEDIATELY(opt_st.flags))
            continue;

        if (! SUCCESSFUL(handle_opt(opts, &opt_st)))
            break;
    } failed_option:;

    if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0)
        (*opts->pUsageProc)(opts, EXIT_FAILURE);

 leave:

    opts->fOptSet &= ~OPTPROC_IMMEDIATE;
    return res;
}
Ejemplo n.º 8
0
/**
 *  Load a file containing presetting information (a configuration file).
 */
static void
file_preset(tOptions * opts, char const * fname, int dir)
{
    tmap_info_t       cfgfile;
    tOptState         optst = OPTSTATE_INITIALIZER(PRESET);
    opt_state_mask_t  st_flags = optst.flags;
    char *            ftext =
        text_mmap(fname, PROT_READ|PROT_WRITE, MAP_PRIVATE, &cfgfile);

    if (TEXT_MMAP_FAILED_ADDR(ftext))
        return;

    if (dir == DIRECTION_CALLED) {
        st_flags = OPTST_DEFINED;
        dir   = DIRECTION_PROCESS;
    }

    /*
     *  IF this is called via "optionProcess", then we are presetting.
     *  This is the default and the PRESETTING bit will be set.
     *  If this is called via "optionFileLoad", then the bit is not set
     *  and we consider stuff set herein to be "set" by the client program.
     */
    if ((opts->fOptSet & OPTPROC_PRESETTING) == 0)
        st_flags = OPTST_SET;

    do  {
        optst.flags = st_flags;
        ftext = SPN_WHITESPACE_CHARS(ftext);

        if (IS_VAR_FIRST_CHAR(*ftext)) {
            ftext = handle_cfg(opts, &optst, ftext, dir);

        } else switch (*ftext) {
        case '<':
            if (IS_VAR_FIRST_CHAR(ftext[1]))
                ftext = handle_struct(opts, &optst, ftext, dir);

            else switch (ftext[1]) {
            case '?':
                ftext = handle_directive(opts, ftext);
                break;

            case '!':
                ftext = handle_comment(ftext);
                break;

            case '/':
                ftext = strchr(ftext + 2, '>');
                if (ftext++ != NULL)
                    break;

            default:
                ftext = NULL;
            }
            if (ftext == NULL)
                goto all_done;
            break;

        case '[':
            ftext = handle_section(opts, ftext);
            break;

        case '#':
            ftext = strchr(ftext + 1, NL);
            break;

        default:
            goto all_done; /* invalid format */
        }
    } while (ftext != NULL);

 all_done:
    text_munmap(&cfgfile);
}
Ejemplo n.º 9
0
/*
 *  If the program wants sorted options (separated operands and options),
 *  then this routine will to the trick.
 */
LOCAL void
optionSort( tOptions* pOpts )
{
    char** ppzOpts;
    char** ppzOpds;
    int    optsIdx = 0;
    int    opdsIdx = 0;

    tOptState os = OPTSTATE_INITIALIZER(DEFINED);

    /*
     *  Disable for POSIX conformance, or if there are no operands.
     */
    if (  (getenv( "POSIXLY_CORRECT" ) != NULL)
       || NAMED_OPTS(pOpts))
        return;

    /*
     *  Make sure we can allocate two full-sized arg vectors.
     */
    ppzOpts = malloc( pOpts->origArgCt * sizeof( char* ));
    if (ppzOpts == NULL)
        goto exit_no_mem;

    ppzOpds = malloc( pOpts->origArgCt * sizeof( char* ));
    if (ppzOpds == NULL) {
        free( ppzOpts );
        goto exit_no_mem;
    }

    pOpts->curOptIdx = 1;
    pOpts->pzCurOpt  = NULL;

    /*
     *  Now, process all the options from our current position onward.
     *  (This allows interspersed options and arguments for the few
     *  non-standard programs that require it.)
     */
    for (;;) {
        char* pzArg;
        tSuccess res;

        /*
         *  If we're out of arguments, we're done.  Join the option and
         *  operand lists into the original argument vector.
         */
        if (pOpts->curOptIdx >= pOpts->origArgCt) {
            errno = 0;
            goto joinLists;
        }

        pzArg = pOpts->origArgVect[ pOpts->curOptIdx ];
        if (*pzArg != '-') {
            ppzOpds[ opdsIdx++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
            continue;
        }

        switch (pzArg[1]) {
        case NUL:
            /*
             *  A single hyphen is an operand.
             */
            ppzOpds[ opdsIdx++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
            continue;

        case '-':
            /*
             *  Two consecutive hypens.  Put them on the options list and then
             *  _always_ force the remainder of the arguments to be operands.
             */
            if (pzArg[2] == NUL) {
                ppzOpts[ optsIdx++ ] =
                    pOpts->origArgVect[ (pOpts->curOptIdx)++ ];
                goto restOperands;
            }
            res = longOptionFind( pOpts, pzArg+2, &os );
            break;

        default:
            /*
             *  If short options are not allowed, then do long
             *  option processing.  Otherwise the character must be a
             *  short (i.e. single character) option.
             */
            if ((pOpts->fOptSet & OPTPROC_SHORTOPT) == 0) {
                res = longOptionFind( pOpts, pzArg+1, &os );
            } else {
                res = shortOptionFind( pOpts, (tAoUC)pzArg[1], &os );
            }
            break;
        }
        if (FAILED( res )) {
            errno = EINVAL;
            goto freeTemps;
        }

        /*
         *  We've found an option.  Add the argument to the option list.
         *  Next, we have to see if we need to pull another argument to be
         *  used as the option argument.
         */
        ppzOpts[ optsIdx++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];

        if (OPTST_GET_ARGTYPE(os.pOD->fOptState) == OPARG_TYPE_NONE) {
            /*
             *  No option argument.  If we have a short option here,
             *  then scan for short options until we get to the end
             *  of the argument string.
             */
            if (  (os.optType == TOPT_SHORT)
               && FAILED( checkShortOpts( pOpts, pzArg+2, &os,
                                          ppzOpts, &optsIdx )) )  {
                errno = EINVAL;
                goto freeTemps;
            }

        } else if (os.pOD->fOptState & OPTST_ARG_OPTIONAL) {
            switch (mayHandleArg( pOpts, pzArg+2, &os, ppzOpts, &optsIdx )) {
            case FAILURE: errno = EIO; goto freeTemps;
            case PROBLEM: errno = 0;   goto joinLists;
            }

        } else {
            switch (mustHandleArg( pOpts, pzArg+2, &os, ppzOpts, &optsIdx )) {
            case PROBLEM:
            case FAILURE: errno = EIO; goto freeTemps;
            }
        }
    } /* for (;;) */

 restOperands:
    while (pOpts->curOptIdx < pOpts->origArgCt)
        ppzOpds[ opdsIdx++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ];

 joinLists:
    if (optsIdx > 0)
        memcpy( pOpts->origArgVect + 1, ppzOpts, optsIdx * sizeof( char* ));
    if (opdsIdx > 0)
        memcpy( pOpts->origArgVect + 1 + optsIdx,
                ppzOpds, opdsIdx * sizeof( char* ));

 freeTemps:
    free( ppzOpts );
    free( ppzOpds );
    return;

 exit_no_mem:
    errno = ENOMEM;
    return;
}
Ejemplo n.º 10
0
/*  filePreset
 *
 *  Load a file containing presetting information (a configuration file).
 */
static void
filePreset(
    tOptions*     pOpts,
    char const*   pzFileName,
    int           direction )
{
    tmap_info_t   cfgfile;
    tOptState     st = OPTSTATE_INITIALIZER(PRESET);
    char*         pzFileText =
        text_mmap( pzFileName, PROT_READ|PROT_WRITE, MAP_PRIVATE, &cfgfile );

    if (TEXT_MMAP_FAILED_ADDR(pzFileText))
        return;

    if (direction == DIRECTION_CALLED) {
        st.flags  = OPTST_DEFINED;
        direction = DIRECTION_PROCESS;
    }

    /*
     *  IF this is called via "optionProcess", then we are presetting.
     *  This is the default and the PRESETTING bit will be set.
     *  If this is called via "optionFileLoad", then the bit is not set
     *  and we consider stuff set herein to be "set" by the client program.
     */
    if ((pOpts->fOptSet & OPTPROC_PRESETTING) == 0)
        st.flags = OPTST_SET;

    do  {
        while (isspace( (int)*pzFileText ))  pzFileText++;

        if (isalpha( (int)*pzFileText )) {
            pzFileText = handleConfig( pOpts, &st, pzFileText, direction );

        } else switch (*pzFileText) {
        case '<':
            if (isalpha( (int)pzFileText[1] ))
                pzFileText = handleStructure(pOpts, &st, pzFileText, direction);

            else switch (pzFileText[1]) {
            case '?':
                pzFileText = handleDirective( pOpts, pzFileText );
                break;

            case '!':
                pzFileText = handleComment( pzFileText );
                break;

            case '/':
                pzFileText = strchr( pzFileText+2, '>' );
                if (pzFileText++ != NULL)
                    break;

            default:
                goto all_done;
            }
            break;

        case '[':
            pzFileText = handleProgramSection( pOpts, pzFileText );
            break;

        case '#':
            pzFileText = strchr( pzFileText+1, '\n' );
            break;

        default:
            goto all_done; /* invalid format */
        }
    } while (pzFileText != NULL);

 all_done:
    text_munmap( &cfgfile );
}
Ejemplo n.º 11
0
/*=export_func  optionResetOpt
 * private:
 *
 * what:  Reset the value of an option
 * arg:   + tOptions* + pOpts    + program options descriptor  +
 * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
 *
 * doc:
 *  This code will cause another option to be reset to its initial state.
 *  For example, --reset=foo will cause the --foo option to be reset.
=*/
void
optionResetOpt(tOptions * pOpts, tOptDesc * pOD)
{
    static bool reset_active = false;

    tOptState opt_state = OPTSTATE_INITIALIZER(DEFINED);
    char const * pzArg = pOD->optArg.argString;
    tSuccess     succ;

    if (pOpts <= OPTPROC_EMIT_LIMIT)
        return;

    if (reset_active)
        return;

    if (  (! HAS_originalOptArgArray(pOpts))
       || (pOpts->originalOptArgCookie == NULL))
        ao_bug(zno_reset);

    if ((pzArg == NULL) || (*pzArg == NUL)) {
        fprintf(stderr, zreset_arg, pOpts->pzProgName, pOD->pz_Name);
        pOpts->pUsageProc(pOpts, EXIT_FAILURE);
        /* NOTREACHED */
        assert(0 == 1);
    }

    reset_active = true;

    if (pzArg[1] == NUL) {
        if (*pzArg == '*') {
            optionResetEverything(pOpts);
            reset_active = false;
            return;
        }

        succ = opt_find_short(pOpts, (uint8_t)*pzArg, &opt_state);
        if (! SUCCESSFUL(succ)) {
            fprintf(stderr, zIllOptChr, pOpts->pzProgPath, *pzArg);
            pOpts->pUsageProc(pOpts, EXIT_FAILURE);
            /* NOTREACHED */
            assert(0 == 1);
        }
    } else {
        succ = opt_find_long(pOpts, (char *)pzArg, &opt_state);
        if (! SUCCESSFUL(succ)) {
            fprintf(stderr, zIllOptStr, pOpts->pzProgPath, pzArg);
            pOpts->pUsageProc(pOpts, EXIT_FAILURE);
            /* NOTREACHED */
            assert(0 == 1);
        }
    }

    /*
     *  We've found the indicated option.  Turn off all non-persistent
     *  flags because we're forcing the option back to its initialized state.
     *  Call any callout procedure to handle whatever it needs to.
     *  Finally, clear the reset flag, too.
     */
    optionReset(pOpts, opt_state.pOD);
    reset_active = false;
}