예제 #1
0
파일: restore.c 프로젝트: cernekee/ocserv
/*=export_func optionRestore
 *
 * what:  restore option state from memory copy
 * arg:   tOptions*, pOpts, program options descriptor
 *
 * doc:  Copy back the option state from saved memory.
 *       The allocated memory is left intact, so this routine can be
 *       called repeatedly without having to call optionSaveState again.
 *       If you are restoring a state that was saved before the first call
 *       to optionProcess(3AO), then you may change the contents of the
 *       argc/argv parameters to optionProcess.
 *
 * err:  If you have not called @code{optionSaveState} before, a diagnostic is
 *       printed to @code{stderr} and exit is called.
=*/
void
optionRestore(tOptions* pOpts)
{
    tOptions* p = (tOptions*)pOpts->pSavedState;

    if (p == NULL) {
        char const * pzName = pOpts->pzProgName;
        if (pzName == NULL) {
            pzName = pOpts->pzPROGNAME;
            if (pzName == NULL)
                pzName = zNil;
        }
        fprintf(stderr, zNoState, pzName);
        option_exits(EXIT_FAILURE);
    }

    pOpts->pSavedState = NULL;
    optionFree(pOpts);

    memcpy(pOpts, p, sizeof(*p));
    memcpy(pOpts->pOptDesc, p+1, (size_t)p->optCt * sizeof(tOptDesc));
    pOpts->pSavedState = p;

    fixupSavedOptionArgs(pOpts);
}
예제 #2
0
/*=export_func optionProcess
 *
 * what: this is the main option processing routine
 *
 * arg:  + tOptions* + opts  + program options descriptor +
 * arg:  + int       + a_ct  + program arg count  +
 * arg:  + char**    + a_v   + program arg vector +
 *
 * ret_type:  int
 * ret_desc:  the count of the arguments processed
 *
 * doc:
 *
 * This is the main entry point for processing options.  It is intended
 * that this procedure be called once at the beginning of the execution of
 * a program.  Depending on options selected earlier, it is sometimes
 * necessary to stop and restart option processing, or to select completely
 * different sets of options.  This can be done easily, but you generally
 * do not want to do this.
 *
 * The number of arguments processed always includes the program name.
 * If one of the arguments is "--", then it is counted and the processing
 * stops.  If an error was encountered and errors are to be tolerated, then
 * the returned value is the index of the argument causing the error.
 * A hyphen by itself ("-") will also cause processing to stop and will
 * @emph{not} be counted among the processed arguments.  A hyphen by itself
 * is treated as an operand.  Encountering an operand stops option
 * processing.
 *
 * err:  Errors will cause diagnostics to be printed.  @code{exit(3)} may
 *       or may not be called.  It depends upon whether or not the options
 *       were generated with the "allow-errors" attribute, or if the
 *       ERRSKIP_OPTERR or ERRSTOP_OPTERR macros were invoked.
=*/
int
optionProcess(tOptions * opts, int a_ct, char ** a_v)
{
    if (! SUCCESSFUL(validate_struct(opts, a_v[0])))
        ao_bug(zbad_data_msg);

    /*
     *  Establish the real program name, the program full path,
     *  and do all the presetting the first time thru only.
     */
    if (! ao_initialize(opts, a_ct, a_v))
        return 0;

    /*
     *  IF we are (re)starting,
     *  THEN reset option location
     */
    if (opts->curOptIdx <= 0) {
        opts->curOptIdx = 1;
        opts->pzCurOpt  = NULL;
    }

    if (! SUCCESSFUL(regular_opts(opts)))
        return (int)opts->origArgCt;

    /*
     *  IF    there were no errors
     *    AND we have RC/INI files
     *    AND there is a request to save the files
     *  THEN do that now before testing for conflicts.
     *       (conflicts are ignored in preset options)
     */
    switch (opts->specOptIdx.save_opts) {
    case 0:
    case NO_EQUIVALENT:
        break;
    default:
    {
        tOptDesc * od = opts->pOptDesc + opts->specOptIdx.save_opts;

        if (SELECTED_OPT(od)) {
            optionSaveFile(opts);
            option_exits(EXIT_SUCCESS);
        }
    }
    }

    /*
     *  IF we are checking for errors,
     *  THEN look for too few occurrences of required options
     */
    if (((opts->fOptSet & OPTPROC_ERRSTOP) != 0)
            && (! is_consistent(opts)))
        (*opts->pUsageProc)(opts, EXIT_FAILURE);

    return (int)opts->curOptIdx;
}
예제 #3
0
LOCAL char *
ao_strdup(char const *str)
{
    char * res = strdup(str);
    if (res == NULL) {
        fprintf(stderr, zalloc_fail, (int)strlen(str));
        option_exits(EXIT_FAILURE);
    }
    return res;
}
예제 #4
0
LOCAL void *
ao_realloc(void *p, size_t sz)
{
    void * res = (p == NULL) ? malloc(sz) : realloc(p, sz);
    if (res == NULL) {
        fprintf(stderr, zrealloc_fail, (int)sz, p);
        option_exits(EXIT_FAILURE);
    }
    return res;
}
예제 #5
0
LOCAL void *
ao_malloc(size_t sz)
{
    void * res = malloc(sz);
    if (res == NULL) {
        fprintf(stderr, zalloc_fail, (int)sz);
        option_exits(EXIT_FAILURE);
    }
    return res;
}
예제 #6
0
파일: usage.c 프로젝트: Distrotech/autogen
/**
 *  Print the usage information for a single option.
 *
 * @param opts  the program option descriptor
 * @param od    the option descriptor
 * @param at    names of the option argument types
 */
static void
prt_one_usage(tOptions * opts, tOptDesc * od, arg_types_t * at)
{
    prt_preamble(opts, od, at);

    {
        char z[80];
        char const * atyp;

        /*
         *  Determine the argument type string first on its usage, then,
         *  when the option argument is required, base the type string on the
         *  argument type.
         */
        if (od->fOptState & OPTST_ARG_OPTIONAL) {
            atyp = at->pzOpt;

        } else switch (OPTST_GET_ARGTYPE(od->fOptState)) {
        case OPARG_TYPE_NONE:        atyp = at->pzNo;   break;
        case OPARG_TYPE_ENUMERATION: atyp = at->pzKey;  break;
        case OPARG_TYPE_FILE:        atyp = at->pzFile; break;
        case OPARG_TYPE_MEMBERSHIP:  atyp = at->pzKeyL; break;
        case OPARG_TYPE_BOOLEAN:     atyp = at->pzBool; break;
        case OPARG_TYPE_NUMERIC:     atyp = at->pzNum;  break;
        case OPARG_TYPE_HIERARCHY:   atyp = at->pzNest; break;
        case OPARG_TYPE_STRING:      atyp = at->pzStr;  break;
        case OPARG_TYPE_TIME:        atyp = at->pzTime; break;
        default:                     goto bogus_desc;
        }

#ifdef _WIN32
        if (at->pzOptFmt == zGnuOptFmt)
            snprintf(z, sizeof(z), "--%s%s", od->pz_Name, atyp);
        else if (at->pzOptFmt == zGnuOptFmt + 2)
            snprintf(z, sizeof(z), "%s%s", od->pz_Name, atyp);
        else
#endif
        snprintf(z, sizeof(z), at->pzOptFmt, atyp, od->pz_Name,
                 (od->optMinCt != 0) ? at->pzReq : at->pzOpt);

        fprintf(option_usage_fp, line_fmt_buf, z, od->pzText);

        switch (OPTST_GET_ARGTYPE(od->fOptState)) {
        case OPARG_TYPE_ENUMERATION:
        case OPARG_TYPE_MEMBERSHIP:
            displayEnum = (od->pOptProc != NULL) ? true : displayEnum;
        }
    }

    return;

 bogus_desc:
    fprintf(stderr, zbad_od, opts->pzProgName, od->pz_Name);
    option_exits(EX_SOFTWARE);
}
예제 #7
0
/**
 *  Process option with a required argument.  Long options can either have a
 *  separate command line argument, or an argument attached by the '='
 *  character.  Figure out which.
 *
 *  @param[in,out] opts  the program option descriptor
 *  @param[in,out] o_st  the option processing state
 *  @returns SUCCESS or FAILURE
 */
static tSuccess
get_opt_arg_must(tOptions * opts, tOptState * o_st)
{
    switch (o_st->optType) {
    case TOPT_SHORT:
        /*
         *  See if an arg string follows the flag character
         */
        if (*++(opts->pzCurOpt) == NUL)
            opts->pzCurOpt = opts->origArgVect[ opts->curOptIdx++ ];
        o_st->pzOptArg = opts->pzCurOpt;
        break;

    case TOPT_LONG:
        /*
         *  See if an arg string has already been assigned (glued on
         *  with an `=' character)
         */
        if (o_st->pzOptArg == NULL)
            o_st->pzOptArg = opts->origArgVect[ opts->curOptIdx++ ];
        break;

    default:
#ifdef DEBUG
        fputs("AutoOpts lib error: option type not selected\n", stderr);
        option_exits(EXIT_FAILURE);
#endif

    case TOPT_DEFAULT:
        /*
         *  The option was selected by default.  The current token is
         *  the option argument.
         */
        break;
    }

    /*
     *  Make sure we did not overflow the argument list.
     */
    if (opts->curOptIdx > opts->origArgCt) {
        fprintf(stderr, zMisArg, opts->pzProgPath, o_st->pOD->pz_Name);
        return FAILURE;
    }

    opts->pzCurOpt = NULL;  /* next time advance to next arg */
    return SUCCESS;
}
예제 #8
0
/*=export_func  optionAlias
 * private:
 *
 * what:  relay an option to its alias
 * arg:   + tOptions *   + opts   + program options descriptor  +
 * arg:   + tOptDesc *   + old_od + the descriptor for this arg +
 * arg:   + unsigned int + alias  + the aliased-to option index +
 * ret-type: int
 *
 * doc:
 *  Handle one option as if it had been specified as another.  Exactly.
 *  Returns "-1" if the aliased-to option has appeared too many times.
=*/
int
optionAlias(tOptions * opts, tOptDesc * old_od, unsigned int alias)
{
    tOptDesc * new_od;

    if (opts <= OPTPROC_EMIT_LIMIT)
        return 0;

    new_od = opts->pOptDesc + alias;
    if ((unsigned)opts->optCt <= alias) {
        fputs(zbad_alias_id, stderr);
        option_exits(EXIT_FAILURE);
    }

    /*
     *  Copy over the option instance flags
     */
    new_od->fOptState &= OPTST_PERSISTENT_MASK;
    new_od->fOptState |= (old_od->fOptState & ~OPTST_PERSISTENT_MASK);
    new_od->optArg.argString = old_od->optArg.argString;

    /*
     *  Keep track of count only for DEFINED (command line) options.
     *  IF we have too many, build up an error message and bail.
     */
    if (  (new_od->fOptState & OPTST_DEFINED)
       && (++new_od->optOccCt > new_od->optMaxCt)  )
        return too_many_occurrences(opts, new_od);

    /*
     *  Clear the state bits and counters
     */
    old_od->fOptState &= OPTST_PERSISTENT_MASK;
    old_od->optOccCt   = 0;

    /*
     *  If there is a procedure to call, call it
     */
    if (new_od->pOptProc != NULL)
        (*new_od->pOptProc)(opts, new_od);
    return 0;
}
예제 #9
0
/*=export_func  optionQuoteString
 * private:
 *
 * what:  Print a string as quoted text suitable for a C compiler.
 * arg:   + char const * + text  + a block of text to quote +
 * arg:   + char const * + nl    + line splice text         +
 *
 * ret_type:  char const *
 * ret_desc:  the allocated input string as a quoted string
 *
 * doc:
 *  This is for internal use by autogen and autoopts.
 *  It takes an input string and produces text the C compiler can process
 *  to produce an exact copy of the original string.
 *  The caller must deallocate the result.  Standard C strings and
 *  K&R strings are distinguished by the "nl" string.
=*/
char const *
optionQuoteString(char const * text, char const * nl)
{
    size_t   nl_len = strlen(nl);
    size_t   out_sz = string_size(text, nl_len);
    char *   out;
    char *   res    = out = AGALOC(out_sz, "quot str");

    *(out++) = '"';

    for (;;) {
        unsigned char ch = (unsigned char)*text;
        if ((ch >= ' ') && (ch <= '~')) {
            if ((ch == '"') || (ch == '\\'))
                /*
                 *  We must escape these characters in the output string
                 */
                *(out++) = '\\';
            *(out++) = (char)ch;

        } else switch (ch) {
#       define   add_esc_ch(_ch)  { *(out++) = '\\'; *(out++) = (_ch); }
        case BEL: add_esc_ch('a'); break;
        case BS:  add_esc_ch('b'); break;
        case HT:  add_esc_ch('t'); break;
        case VT:  add_esc_ch('v'); break;
        case FF:  add_esc_ch('f'); break;
        case CR:  add_esc_ch('r'); break;

        case LF:
            /*
             *  Place contiguous new-lines on a single line.
             *  The current character is a NL, check the next one.
             */
            while (*++text == NL)
                add_esc_ch('n');

            /*
             *  Insert a splice before starting next line
             */
            if (*text != NUL) {
                memcpy(out, nl, nl_len);
                out += nl_len;

                continue; /* text is already at the next character */
            }

            add_esc_ch('n');
            /* FALLTHROUGH */

        case NUL:
            /*
             *  End of string.  Terminate the quoted output.  If necessary,
             *  deallocate the text string.  Return the scan resumption point.
             */
            *(out++) = '"';
            *(out++) = NUL;
#ifndef NDEBUG
            if ((out - res) > out_sz) {
                fputs(misguess_len, stderr);
                option_exits(EXIT_FAILURE);
            }
#endif
            return res;

        default:
            /*
             *  sprintf is safe here, because we already computed
             *  the amount of space we will be using.  Assertion is above.
             */
            out += sprintf(out, MK_STR_OCT_FMT, ch);
        }

        text++;
#       undef add_esc_ch
    }
}
예제 #10
0
LOCAL noreturn void
fserr_exit(char const * prog, char const * op, char const * fname)
{
    fserr_warn(prog, op, fname);
    option_exits(EXIT_FAILURE);
}
예제 #11
0
/*=export_func genshelloptUsage
 * private:
 * what: The usage function for the genshellopt generated program
 *
 * arg:  + tOptions * + opts    + program options descriptor +
 * arg:  + int        + exit_cd + usage text type to produce +
 *
 * doc:
 *  This function is used to create the usage strings for the option
 *  processing shell script code.  Two child processes are spawned
 *  each emitting the usage text in either the short (error exit)
 *  style or the long style.  The generated program will capture this
 *  and create shell script variables containing the two types of text.
=*/
void
genshelloptUsage(tOptions * opts, int exit_cd)
{
#if ! defined(HAVE_WORKING_FORK)
    optionUsage(opts, exit_cd);
#else
    /*
     *  IF not EXIT_SUCCESS,
     *  THEN emit the short form of usage.
     */
    if (exit_cd != EXIT_SUCCESS)
        optionUsage(opts, exit_cd);
    fflush(stderr);
    fflush(stdout);
    if (ferror(stdout) || ferror(stderr))
        option_exits(EXIT_FAILURE);

    option_usage_fp = stdout;

    /*
     *  First, print our usage
     */
    switch (fork()) {
    case -1:
        optionUsage(opts, EXIT_FAILURE);
        /* NOTREACHED */

    case 0:
        pagerState = PAGER_STATE_CHILD;
        optionUsage(opts, EXIT_SUCCESS);
        /* NOTREACHED */
        _exit(EXIT_FAILURE);

    default:
    {
        int  sts;
        wait(&sts);
    }
    }

    /*
     *  Generate the pzProgName, since optionProcess() normally
     *  gets it from the command line
     */
    {
        char *  pz;
        char ** pp = VOIDP(&(optionParseShellOptions->pzProgName));
        AGDUPSTR(pz, optionParseShellOptions->pzPROGNAME, "prog name");
        *pp = pz;
        while (*pz != NUL) {
            *pz = (char)LOWER(*pz);
            pz++;
        }
    }

    /*
     *  Separate the makeshell usage from the client usage
     */
    fprintf(option_usage_fp, zGenshell, optionParseShellOptions->pzProgName);
    fflush(option_usage_fp);

    /*
     *  Now, print the client usage.
     */
    switch (fork()) {
    case 0:
        pagerState = PAGER_STATE_CHILD;
        /*FALLTHROUGH*/
    case -1:
        optionUsage(optionParseShellOptions, EXIT_FAILURE);

    default:
    {
        int  sts;
        wait(&sts);
    }
    }

    fflush(stdout);
    if (ferror(stdout))
        fserr_exit(opts->pzProgName, zwriting, zstdout_name);

    option_exits(EXIT_SUCCESS);
#endif
}
예제 #12
0
LOCAL noreturn void
ao_bug(char const * msg)
{
    fprintf(stderr, zao_bug_msg, msg);
    option_exits(EX_SOFTWARE);
}
예제 #13
0
/**
 *  The purpose of this function is to assign "long usage", short usage
 *  and version information to a shell variable.  Rather than wind our
 *  way through all the logic necessary to emit the text directly, we
 *  fork(), have our child process emit the text the normal way and
 *  capture the output in the parent process.
 *
 * @param[in] opts  the program options
 * @param[in] which what to print: long usage, usage or version
 * @param[in] od    for TT_VERSION, it is the version option
 */
static void
text_to_var(tOptions * opts, teTextTo which, tOptDesc * od)
{
#   define _TT_(n) static char const z ## n [] = #n;
    TEXTTO_TABLE
#   undef _TT_
#   define _TT_(n) z ## n ,
      static char const * ttnames[] = { TEXTTO_TABLE };
#   undef _TT_

#if ! defined(HAVE_WORKING_FORK)
    printf(SET_NO_TEXT_FMT, opts->pzPROGNAME, ttnames[which]);
#else
    int  fdpair[2];

    fflush(stdout);
    fflush(stderr);

    if (pipe(fdpair) != 0)
        fserr_exit(opts->pzProgName, "pipe", zinter_proc_pipe);

    switch (fork()) {
    case -1:
        fserr_exit(opts->pzProgName, "fork", opts->pzProgName);
        /* NOTREACHED */

    case 0:
        /*
         * Send both stderr and stdout to the pipe.  No matter which
         * descriptor is used, we capture the output on the read end.
         */
        dup2(fdpair[1], STDERR_FILENO);
        dup2(fdpair[1], STDOUT_FILENO);
        close(fdpair[0]);

        switch (which) {
        case TT_LONGUSAGE:
            (*(opts->pUsageProc))(opts, EXIT_SUCCESS);
            /* NOTREACHED */

        case TT_USAGE:
            (*(opts->pUsageProc))(opts, EXIT_FAILURE);
            /* NOTREACHED */

        case TT_VERSION:
            if (od->fOptState & OPTST_ALLOC_ARG) {
                AGFREE(od->optArg.argString);
                od->fOptState &= ~OPTST_ALLOC_ARG;
            }
            od->optArg.argString = "c";
            optionPrintVersion(opts, od);
            /* NOTREACHED */

        default:
            option_exits(EXIT_FAILURE);
            /* NOTREACHED */
        }
        /* NOTREACHED */

    default:
        close(fdpair[1]);
    }

    emit_var_text(opts->pzPROGNAME, ttnames[which], fdpair[0]);
#endif
}
예제 #14
0
파일: usage.c 프로젝트: Distrotech/autogen
/*=export_func  optionUsage
 * private:
 *
 * what:  Print usage text
 * arg:   + tOptions * + opts + program options descriptor +
 * arg:   + int        + exitCode + exit code for calling exit(3) +
 *
 * doc:
 *  This routine will print usage in both GNU-standard and AutoOpts-expanded
 *  formats.  The descriptor specifies the default, but AUTOOPTS_USAGE will
 *  over-ride this, providing the value of it is set to either "gnu" or
 *  "autoopts".  This routine will @strong{not} return.
 *
 *  If "exitCode" is "AO_EXIT_REQ_USAGE" (normally 64), then output will to
 *  to stdout and the actual exit code will be "EXIT_SUCCESS".
=*/
void
optionUsage(tOptions * opts, int usage_exit_code)
{
    int exit_code = (usage_exit_code == AO_EXIT_REQ_USAGE)
        ? EXIT_SUCCESS : usage_exit_code;

    displayEnum = false;
    set_usage_flags(opts, NULL);

    /*
     *  Paged usage will preset option_usage_fp to an output file.
     *  If it hasn't already been set, then set it to standard output
     *  on successful exit (help was requested), otherwise error out.
     *
     *  Test the version before obtaining pzFullUsage or pzShortUsage.
     *  These fields do not exist before revision 30.
     */
    {
        char const * pz;

        if (exit_code == EXIT_SUCCESS) {
            pz = (opts->structVersion >= 30 * 4096)
                ? opts->pzFullUsage : NULL;

            if (option_usage_fp == NULL)
                option_usage_fp = print_exit ? stderr : stdout;

        } else {
            pz = (opts->structVersion >= 30 * 4096)
                ? opts->pzShortUsage : NULL;

            if (option_usage_fp == NULL)
                option_usage_fp = stderr;
        }

        if (((opts->fOptSet & OPTPROC_COMPUTE) == 0) && (pz != NULL)) {
            if ((opts->fOptSet & OPTPROC_TRANSLATE) != 0)
                optionPrintParagraphs(pz, true, option_usage_fp);
            else
                fputs(pz, option_usage_fp);
            goto flush_and_exit;
        }
    }

    fprintf(option_usage_fp, opts->pzUsageTitle, opts->pzProgName);

    if ((exit_code == EXIT_SUCCESS) ||
        (! skip_misuse_usage(opts)))

        print_usage_details(opts, usage_exit_code);
    else
        print_offer_usage(opts);
    
 flush_and_exit:
    fflush(option_usage_fp);
    if (ferror(option_usage_fp) != 0)
        fserr_exit(opts->pzProgName, zwriting, (option_usage_fp == stdout)
                   ? zstdout_name : zstderr_name);

    option_exits(exit_code);
}
예제 #15
0
/*=export_func  optionTimeDate
 * private:
 *
 * what:  process an option with a time and date.
 * arg:   + tOptions * + opts + program options descriptor +
 * arg:   + tOptDesc * + od   + the descriptor for this arg +
 *
 * doc:
 *  Decipher a time and date value.
=*/
void
optionTimeDate(tOptions * opts, tOptDesc * od)
{
#if defined(HAVE_GETDATE_R) && defined(HAVE_PUTENV)
    if (INQUERY_CALL(opts, od))
        return;

    if ((! HAS_pzPkgDataDir(opts)) || (opts->pzPkgDataDir == NULL))
        goto default_action;

    /*
     *  Export the DATEMSK environment variable.  getdate_r() uses it to
     *  find the file with the strptime formats.  If we cannot find the file
     *  we need ($PKGDATADIR/datemsk), then fall back to just a time duration.
     */
    {
        static char * envptr = NULL;

        if (envptr == NULL) {
            static char const fmt[] = "DATEMSK=%s/datemsk";
            size_t sz = sizeof(fmt) + strlen(opts->pzPkgDataDir);
            envptr = AGALOC(sz, fmt);
            if (snprintf(envptr, sz, fmt, opts->pzPkgDataDir) >= (int)sz)
                option_exits(EXIT_FAILURE);

            putenv(envptr);
        }

        if (access(envptr+8, R_OK) != 0)
            goto default_action;
    }

    /*
     *  Convert the date to a time since the epoch and stash it in a long int.
     */
    {
        struct tm stm;
        time_t tm;

        if (getdate_r(od->optArg.argString, &stm) != 0) {
            fprintf(stderr, zNotDate, opts->pzProgName,
                    od->optArg.argString);
            if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0)
                (*(opts->pUsageProc))(opts, EXIT_FAILURE);
            return;
        }

        tm = mktime(&stm);

        if (od->fOptState & OPTST_ALLOC_ARG) {
            AGFREE(od->optArg.argString);
            od->fOptState &= ~OPTST_ALLOC_ARG;
        }

        od->optArg.argInt = tm;
    }
    return;

 default_action:

#endif
    optionTimeVal(opts, od);
    if (od->optArg.argInt != BAD_TIME)
        od->optArg.argInt += (long)time(NULL);
}
예제 #16
0
파일: enum.c 프로젝트: Distrotech/autogen
static void
enum_err(tOptions * pOpts, tOptDesc * pOD,
         char const * const * paz_names, int name_ct)
{
    size_t max_len = 0;
    size_t ttl_len = 0;
    int    ct_down = name_ct;
    int    hidden  = 0;

    /*
     *  A real "pOpts" pointer means someone messed up.  Give a real error.
     */
    if (pOpts > OPTPROC_EMIT_LIMIT)
        fprintf(option_usage_fp, pz_enum_err_fmt, pOpts->pzProgName,
                pOD->optArg.argString, pOD->pz_Name);

    fprintf(option_usage_fp, zValidKeys, pOD->pz_Name);

    /*
     *  If the first name starts with this funny character, then we have
     *  a first value with an unspellable name.  You cannot specify it.
     *  So, we don't list it either.
     */
    if (**paz_names == 0x7F) {
        paz_names++;
        hidden  = 1;
        ct_down = --name_ct;
    }

    /*
     *  Figure out the maximum length of any name, plus the total length
     *  of all the names.
     */
    {
        char const * const * paz = paz_names;

        do  {
            size_t len = strlen(*(paz++)) + 1;
            if (len > max_len)
                max_len = len;
            ttl_len += len;
        } while (--ct_down > 0);

        ct_down = name_ct;
    }

    /*
     *  IF any one entry is about 1/2 line or longer, print one per line
     */
    if (max_len > 35) {
        do  {
            fprintf(option_usage_fp, ENUM_ERR_LINE, *(paz_names++));
        } while (--ct_down > 0);
    }

    /*
     *  ELSE IF they all fit on one line, then do so.
     */
    else if (ttl_len < 76) {
        fputc(' ', option_usage_fp);
        do  {
            fputc(' ', option_usage_fp);
            fputs(*(paz_names++), option_usage_fp);
        } while (--ct_down > 0);
        fputc(NL, option_usage_fp);
    }

    /*
     *  Otherwise, columnize the output
     */
    else {
        unsigned int ent_no = 0;
        char fmt[16];  /* format for all-but-last entries on a line */

        if (snprintf(fmt, 16, ENUM_ERR_WIDTH, (int)max_len) >= 16)
            option_exits(EXIT_FAILURE);
        max_len = 78 / max_len; /* max_len is now max entries on a line */
        fputs(TWO_SPACES_STR, option_usage_fp);

        /*
         *  Loop through all but the last entry
         */
        ct_down = name_ct;
        while (--ct_down > 0) {
            if (++ent_no == max_len) {
                /*
                 *  Last entry on a line.  Start next line, too.
                 */
                fprintf(option_usage_fp, NLSTR_SPACE_FMT, *(paz_names++));
                ent_no = 0;
            }

            else
                fprintf(option_usage_fp, fmt, *(paz_names++) );
        }
        fprintf(option_usage_fp, NLSTR_FMT, *paz_names);
    }

    if (pOpts > OPTPROC_EMIT_LIMIT) {
        fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden);

        (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE);
        /* NOTREACHED */
    }

    if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) {
        fprintf(option_usage_fp, zLowerBits, name_ct);
        fputs(zSetMemberSettings, option_usage_fp);
    } else {
        fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden);
    }
}