/** * 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); exit(EX_SOFTWARE); }
/** * Print the usage information for a single vendor option. * * @param pOpts the program option descriptor * @param pOD the option descriptor * @param pAT names of the option argument types */ static void prt_one_vendor(tOptions * pOptions, tOptDesc * pOD, arg_types_t * pAT, char const * usefmt) { prt_preamble(pOptions, pOD, pAT); { char z[ 80 ]; char const * pzArgType; /* * 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 (pOD->fOptState & OPTST_ARG_OPTIONAL) { pzArgType = pAT->pzOpt; } else switch (OPTST_GET_ARGTYPE(pOD->fOptState)) { case OPARG_TYPE_NONE: pzArgType = pAT->pzNo; break; case OPARG_TYPE_ENUMERATION: pzArgType = pAT->pzKey; break; case OPARG_TYPE_FILE: pzArgType = pAT->pzFile; break; case OPARG_TYPE_MEMBERSHIP: pzArgType = pAT->pzKeyL; break; case OPARG_TYPE_BOOLEAN: pzArgType = pAT->pzBool; break; case OPARG_TYPE_NUMERIC: pzArgType = pAT->pzNum; break; case OPARG_TYPE_HIERARCHY: pzArgType = pAT->pzNest; break; case OPARG_TYPE_STRING: pzArgType = pAT->pzStr; break; case OPARG_TYPE_TIME: pzArgType = pAT->pzTime; break; default: goto bogus_desc; } while (IS_WHITESPACE_CHAR(*pzArgType)) pzArgType++; if (*pzArgType == NUL) snprintf(z, sizeof(z), "%s", pOD->pz_Name); else snprintf(z, sizeof(z), "%s=%s", pOD->pz_Name, pzArgType); fprintf(option_usage_fp, usefmt, z, pOD->pzText); switch (OPTST_GET_ARGTYPE(pOD->fOptState)) { case OPARG_TYPE_ENUMERATION: case OPARG_TYPE_MEMBERSHIP: displayEnum = (pOD->pOptProc != NULL) ? AG_TRUE : displayEnum; } } return; bogus_desc: fprintf(stderr, zInvalOptDesc, pOD->pz_Name); exit(EX_SOFTWARE); }
/** * Print the usage information for a single vendor option. * * @param[in] opts the program option descriptor * @param[in] od the option descriptor * @param[in] argtp names of the option argument types * @param[in] usefmt format for primary usage line */ static void prt_one_vendor(tOptions * opts, tOptDesc * od, arg_types_t * argtp, char const * usefmt) { prt_preamble(opts, od, argtp); { char z[ 80 ]; char const * pzArgType; /* * 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) { pzArgType = argtp->pzOpt; } else switch (OPTST_GET_ARGTYPE(od->fOptState)) { case OPARG_TYPE_NONE: pzArgType = argtp->pzNo; break; case OPARG_TYPE_ENUMERATION: pzArgType = argtp->pzKey; break; case OPARG_TYPE_FILE: pzArgType = argtp->pzFile; break; case OPARG_TYPE_MEMBERSHIP: pzArgType = argtp->pzKeyL; break; case OPARG_TYPE_BOOLEAN: pzArgType = argtp->pzBool; break; case OPARG_TYPE_NUMERIC: pzArgType = argtp->pzNum; break; case OPARG_TYPE_HIERARCHY: pzArgType = argtp->pzNest; break; case OPARG_TYPE_STRING: pzArgType = argtp->pzStr; break; case OPARG_TYPE_TIME: pzArgType = argtp->pzTime; break; default: goto bogus_desc; } pzArgType = SPN_WHITESPACE_CHARS(pzArgType); if (*pzArgType == NUL) snprintf(z, sizeof(z), "%s", od->pz_Name); else snprintf(z, sizeof(z), "%s=%s", od->pz_Name, pzArgType); fprintf(option_usage_fp, usefmt, 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); ao_bug(zbad_arg_type_msg); }
/* * optionFixupSavedOpts Really, it just wipes out option state for * options that are troublesome to copy. viz., stacked strings and * hierarcicaly valued option args. We do duplicate string args that * have been marked as allocated though. */ static void fixupSavedOptionArgs(tOptions* pOpts) { tOptions* p = pOpts->pSavedState; tOptDesc* pOD = pOpts->pOptDesc; int ct = pOpts->optCt; /* * Make sure that allocated stuff is only referenced in the * archived copy of the data. */ for (; ct-- > 0; pOD++) { switch (OPTST_GET_ARGTYPE(pOD->fOptState)) { case OPARG_TYPE_STRING: if (pOD->fOptState & OPTST_STACKED) { tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc); q->optCookie = NULL; } if (pOD->fOptState & OPTST_ALLOC_ARG) { tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc); AGDUPSTR(q->optArg.argString, pOD->optArg.argString, "arg"); } break; case OPARG_TYPE_HIERARCHY: { tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc); q->optCookie = NULL; } } } }
static void emit_action(tOptions * opts, tOptDesc * od) { if (od->pOptProc == optionPrintVersion) printf(ECHO_N_EXIT, opts->pzPROGNAME, VER_STR); else if (od->pOptProc == optionPagedUsage) printf(PAGE_USAGE_TEXT, opts->pzPROGNAME); else if (od->pOptProc == optionLoadOpt) { printf(LVL3_CMD, NO_LOAD_WARN); printf(LVL3_CMD, YES_NEED_OPT_ARG); } else if (od->pz_NAME == NULL) { if (od->pOptProc == NULL) { printf(LVL3_CMD, NO_SAVE_OPTS); printf(LVL3_CMD, OK_NEED_OPT_ARG); } else printf(ECHO_N_EXIT, opts->pzPROGNAME, LONG_USE_STR); } else { if (od->optMaxCt == 1) printf(SGL_ARG_FMT, opts->pzPROGNAME, od->pz_NAME); else { if ((unsigned)od->optMaxCt < NOLIMIT) printf(CHK_MAX_COUNT, opts->pzPROGNAME, od->pz_NAME, od->optMaxCt); printf(MULTI_ARG_FMT, opts->pzPROGNAME, od->pz_NAME); } /* * Fix up the args. */ if (OPTST_GET_ARGTYPE(od->fOptState) == OPARG_TYPE_NONE) { printf(SET_MULTI_ARG, opts->pzPROGNAME, od->pz_NAME); printf(LVL3_CMD, NO_ARG_NEEDED); } else if (od->fOptState & OPTST_ARG_OPTIONAL) { printf(SET_MULTI_ARG, opts->pzPROGNAME, od->pz_NAME); printf(LVL3_CMD, OK_NEED_OPT_ARG); } else { printf(LVL3_CMD, YES_NEED_OPT_ARG); } } fputs(zOptionEndSelect, stdout); }
/** * Print program details. * @param[in] opts the program option descriptor */ static void prt_prog_detail(tOptions * opts) { bool need_intro = (opts->papzHomeList == NULL); /* * Display all the places we look for config files, if we have * a list of directories to search. */ if (! need_intro) prt_ini_list(opts->papzHomeList, opts->pzRcName, opts->pzProgPath); /* * Let the user know about environment variable settings */ if ((opts->fOptSet & OPTPROC_ENVIRON) != 0) { if (need_intro) fputs(zPresetIntro, option_usage_fp); fprintf(option_usage_fp, zExamineFmt, opts->pzPROGNAME); } /* * IF we found an enumeration, * THEN hunt for it again. Call the handler proc with a NULL * option struct pointer. That tells it to display the keywords. */ if (displayEnum) { int ct = opts->optCt; int optNo = 0; tOptDesc * od = opts->pOptDesc; fputc(NL, option_usage_fp); fflush(option_usage_fp); do { switch (OPTST_GET_ARGTYPE(od->fOptState)) { case OPARG_TYPE_ENUMERATION: case OPARG_TYPE_MEMBERSHIP: (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od); } } while (od++, optNo++, (--ct > 0)); } /* * If there is a detail string, now is the time for that. */ if (opts->pzDetail != NULL) fputs(opts->pzDetail, option_usage_fp); }
/* * nextOption * * Find the option descriptor and option argument (if any) for the * next command line argument. DO NOT modify the descriptor. Put * all the state in the state argument so that the option can be skipped * without consequence (side effect). */ static tSuccess nextOption(tOptions* pOpts, tOptState* pOptState) { { tSuccess res; res = findOptDesc(pOpts, pOptState); if (! SUCCESSFUL(res)) return res; } if ( ((pOptState->flags & OPTST_DEFINED) != 0) && ((pOptState->pOD->fOptState & OPTST_NO_COMMAND) != 0)) { fprintf(stderr, zNotCmdOpt, pOptState->pOD->pz_Name); return FAILURE; } pOptState->flags |= (pOptState->pOD->fOptState & OPTST_PERSISTENT_MASK); /* * Figure out what to do about option arguments. An argument may be * required, not associated with the option, or be optional. We detect the * latter by examining for an option marker on the next possible argument. * Disabled mode option selection also disables option arguments. */ { enum { ARG_NONE, ARG_MAY, ARG_MUST } arg_type = ARG_NONE; tSuccess res; if ((pOptState->flags & OPTST_DISABLED) != 0) arg_type = ARG_NONE; else if (OPTST_GET_ARGTYPE(pOptState->flags) == OPARG_TYPE_NONE) arg_type = ARG_NONE; else if (pOptState->flags & OPTST_ARG_OPTIONAL) arg_type = ARG_MAY; else arg_type = ARG_MUST; switch (arg_type) { case ARG_MUST: res = next_opt_arg_must(pOpts, pOptState); break; case ARG_MAY: res = next_opt_arg_may( pOpts, pOptState); break; case ARG_NONE: res = next_opt_arg_none(pOpts, pOptState); break; } return res; } }
/*=export_func optionFindValue * * what: find a hierarcicaly valued option instance * arg: + const tOptDesc* + pOptDesc + an option with a nested arg type + * arg: + char const* + name + name of value to find + * arg: + char const* + value + the matching value + * * ret_type: const tOptionValue* * ret_desc: a compound value structure * * doc: * This routine will find an entry in a nested value option or configurable. * It will search through the list and return a matching entry. * * err: * The returned result is NULL and errno is set: * @itemize @bullet * @item * @code{EINVAL} - the @code{pOptValue} does not point to a valid * hierarchical option value. * @item * @code{ENOENT} - no entry matched the given name. * @end itemize =*/ const tOptionValue* optionFindValue( const tOptDesc* pOptDesc, char const* pzName, char const* pzVal ) { const tOptionValue* pRes = NULL; if ( (pOptDesc == NULL) || (OPTST_GET_ARGTYPE(pOptDesc->fOptState) != OPARG_TYPE_HIERARCHY)) { errno = EINVAL; } else if (pOptDesc->optCookie == NULL) { errno = ENOENT; } else do { tArgList* pAL = pOptDesc->optCookie; int ct = pAL->useCt; void** ppOV = (void**)(pAL->apzArgs); if (ct == 0) { errno = ENOENT; break; } if (pzName == NULL) { pRes = (tOptionValue*)*ppOV; break; } while (--ct >= 0) { const tOptionValue* pOV = *(ppOV++); const tOptionValue* pRV = optionGetValue( pOV, pzName ); if (pRV == NULL) continue; if (pzVal == NULL) { pRes = pOV; break; } } if (pRes == NULL) errno = ENOENT; } while (0); return pRes; }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * PROGRAM DETAILS */ static void printProgramDetails( tOptions* pOptions ) { ag_bool initIntro = AG_TRUE; /* * Display all the places we look for config files */ printInitList( pOptions->papzHomeList, &initIntro, pOptions->pzRcName, pOptions->pzProgPath ); /* * Let the user know about environment variable settings */ if ((pOptions->fOptSet & OPTPROC_ENVIRON) != 0) { if (initIntro) fputs( zPresetIntro, option_usage_fp ); fprintf( option_usage_fp, zExamineFmt, pOptions->pzPROGNAME ); } /* * IF we found an enumeration, * THEN hunt for it again. Call the handler proc with a NULL * option struct pointer. That tells it to display the keywords. */ if (displayEnum) { int ct = pOptions->optCt; int optNo = 0; tOptDesc* pOD = pOptions->pOptDesc; fputc( '\n', option_usage_fp ); fflush( option_usage_fp ); do { switch (OPTST_GET_ARGTYPE(pOD->fOptState)) { case OPARG_TYPE_ENUMERATION: case OPARG_TYPE_MEMBERSHIP: (*(pOD->pOptProc))( NULL, pOD ); } } while (pOD++, optNo++, (--ct > 0)); } /* * If there is a detail string, now is the time for that. */ if (pOptions->pzDetail != NULL) fputs( pOptions->pzDetail, option_usage_fp ); }
static void printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc ) { if (pOptDesc->pOptProc == optionPrintVersion) printf( zTextExit, pOpts->pzPROGNAME, "VERSION" ); else if (pOptDesc->pOptProc == optionPagedUsage) printf( zPagedUsageExit, pOpts->pzPROGNAME ); else if (pOptDesc->pOptProc == optionLoadOpt) { printf( zCmdFmt, "echo 'Warning: Cannot load options files' >&2" ); printf( zCmdFmt, "OPT_ARG_NEEDED=YES" ); } else if (pOptDesc->pz_NAME == NULL) { if (pOptDesc->pOptProc == NULL) { printf( zCmdFmt, "echo 'Warning: Cannot save options files' " ">&2" ); printf( zCmdFmt, "OPT_ARG_NEEDED=OK" ); } else printf( zTextExit, pOpts->pzPROGNAME, "LONGUSAGE" ); } else { if (pOptDesc->optMaxCt == 1) printf( zSingleArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME ); else { if ((unsigned)pOptDesc->optMaxCt < NOLIMIT) printf( zCountTest, pOpts->pzPROGNAME, pOptDesc->pz_NAME, pOptDesc->optMaxCt ); printf( zMultiArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME ); } /* * Fix up the args. */ if (OPTST_GET_ARGTYPE(pOptDesc->fOptState) == OPARG_TYPE_NONE) { printf( zCantArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME ); } else if (pOptDesc->fOptState & OPTST_ARG_OPTIONAL) { printf( zMayArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME ); } else { fputs( zMustArg, stdout ); } } fputs( zOptionEndSelect, stdout ); }
/*=export_func optionFindValue * * what: find a hierarcicaly valued option instance * arg: + const tOptDesc* + odesc + an option with a nested arg type + * arg: + char const* + name + name of value to find + * arg: + char const* + val + the matching value + * * ret_type: const tOptionValue* * ret_desc: a compound value structure * * doc: * This routine will find an entry in a nested value option or configurable. * It will search through the list and return a matching entry. * * err: * The returned result is NULL and errno is set: * @itemize @bullet * @item * @code{EINVAL} - the @code{pOptValue} does not point to a valid * hierarchical option value. * @item * @code{ENOENT} - no entry matched the given name. * @end itemize =*/ const tOptionValue * optionFindValue(const tOptDesc * odesc, char const * name, char const * val) { const tOptionValue * res = NULL; if ( (odesc == NULL) || (OPTST_GET_ARGTYPE(odesc->fOptState) != OPARG_TYPE_HIERARCHY)) { errno = EINVAL; } else if (odesc->optCookie == NULL) { errno = ENOENT; } else do { tArgList* argl = odesc->optCookie; int argct = argl->useCt; void ** poptv = (void**)(argl->apzArgs); if (argct == 0) { errno = ENOENT; break; } if (name == NULL) { res = (tOptionValue*)*poptv; break; } while (--argct >= 0) { const tOptionValue * ov = *(poptv++); const tOptionValue * rv = optionGetValue(ov, name); if (rv == NULL) continue; if (val == NULL) { res = ov; break; } } if (res == NULL) errno = ENOENT; } while (false); return res; }
static void emit_action(tOptions * pOpts, tOptDesc* pOptDesc) { if (pOptDesc->pOptProc == optionPrintVersion) printf(zTextExit, pOpts->pzPROGNAME, VER_STR); else if (pOptDesc->pOptProc == optionPagedUsage) printf(zPagedUsageExit, pOpts->pzPROGNAME); else if (pOptDesc->pOptProc == optionLoadOpt) { printf(zCmdFmt, NO_LOAD_WARN); printf(zCmdFmt, YES_NEED_OPT_ARG); } else if (pOptDesc->pz_NAME == NULL) { if (pOptDesc->pOptProc == NULL) { printf(zCmdFmt, NO_SAVE_OPTS); printf(zCmdFmt, OK_NEED_OPT_ARG); } else printf(zTextExit, pOpts->pzPROGNAME, LONG_USE_STR); } else { if (pOptDesc->optMaxCt == 1) printf(SGL_ARG_FMT, pOpts->pzPROGNAME, pOptDesc->pz_NAME); else { if ((unsigned)pOptDesc->optMaxCt < NOLIMIT) printf(zCountTest, pOpts->pzPROGNAME, pOptDesc->pz_NAME, pOptDesc->optMaxCt); printf(MULTI_ARG_FMT, pOpts->pzPROGNAME, pOptDesc->pz_NAME); } /* * Fix up the args. */ if (OPTST_GET_ARGTYPE(pOptDesc->fOptState) == OPARG_TYPE_NONE) { printf(zCantArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME); } else if (pOptDesc->fOptState & OPTST_ARG_OPTIONAL) { printf(zMayArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME); } else { fputs(zMustArg, stdout); } } fputs(zOptionEndSelect, stdout); }
/*=export_func optionFree * * what: free allocated option processing memory * arg: tOptions*, pOpts, program options descriptor * * doc: AutoOpts sometimes allocates memory and puts pointers to it in the * option state structures. This routine deallocates all such memory. * * err: As long as memory has not been corrupted, * this routine is always successful. =*/ void optionFree(tOptions* pOpts) { free_saved_state: { tOptDesc* p = pOpts->pOptDesc; int ct = pOpts->optCt; do { if (p->fOptState & OPTST_ALLOC_ARG) { AGFREE(p->optArg.argString); p->optArg.argString = NULL; p->fOptState &= ~OPTST_ALLOC_ARG; } switch (OPTST_GET_ARGTYPE(p->fOptState)) { case OPARG_TYPE_STRING: #ifdef WITH_LIBREGEX if ( (p->fOptState & OPTST_STACKED) && (p->optCookie != NULL)) { p->optArg.argString = ".*"; optionUnstackArg(pOpts, p); } #else /* leak memory */; #endif break; case OPARG_TYPE_HIERARCHY: if (p->optCookie != NULL) unload_arg_list(p->optCookie); break; } p->optCookie = NULL; } while (p++, --ct > 0); } if (pOpts->pSavedState != NULL) { tOptions * p = (tOptions*)pOpts->pSavedState; memcpy(pOpts, p, sizeof(*p)); memcpy(pOpts->pOptDesc, p+1, (size_t)p->optCt * sizeof(tOptDesc)); AGFREE(pOpts->pSavedState); pOpts->pSavedState = NULL; goto free_saved_state; } }
/* * Process a string of short options glued together. If the last one * does or may take an argument, the do the argument processing and leave. */ static tSuccess checkShortOpts( tOptions* pOpts, char* pzArg, tOptState* pOS, char** ppzOpts, int* pOptsIdx ) { while (*pzArg != NUL) { if (FAILED( shortOptionFind( pOpts, (tAoUC)*pzArg, pOS ))) return FAILURE; /* * See if we can have an arg. */ if (OPTST_GET_ARGTYPE(pOS->pOD->fOptState) == OPARG_TYPE_NONE) { pzArg++; } else if (pOS->pOD->fOptState & OPTST_ARG_OPTIONAL) { /* * Take an argument if it is not attached and it does not * start with a hyphen. */ if (pzArg[1] != NUL) return SUCCESS; pzArg = pOpts->origArgVect[ pOpts->curOptIdx ]; if (*pzArg != '-') ppzOpts[ (*pOptsIdx)++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ]; return SUCCESS; } else { /* * IF we need another argument, be sure it is there and * take it. */ if (pzArg[1] == NUL) { if (pOpts->curOptIdx >= pOpts->origArgCt) return FAILURE; ppzOpts[ (*pOptsIdx)++ ] = pOpts->origArgVect[ (pOpts->curOptIdx)++ ]; } return SUCCESS; } } return SUCCESS; }
/* * Process a string of short options glued together. If the last one * does or may take an argument, the do the argument processing and leave. */ static tSuccess short_opt_ck(tOptions * opts, char * arg_txt, tOptState * pOS, char ** opt_txt, uint32_t * opt_idx) { while (*arg_txt != NUL) { if (FAILED(opt_find_short(opts, (uint8_t)*arg_txt, pOS))) return FAILURE; /* * See if we can have an arg. */ if (OPTST_GET_ARGTYPE(pOS->pOD->fOptState) == OPARG_TYPE_NONE) { arg_txt++; } else if (pOS->pOD->fOptState & OPTST_ARG_OPTIONAL) { /* * Take an argument if it is not attached and it does not * start with a hyphen. */ if (arg_txt[1] != NUL) return SUCCESS; arg_txt = opts->origArgVect[ opts->curOptIdx ]; if (*arg_txt != '-') opt_txt[ (*opt_idx)++ ] = opts->origArgVect[ (opts->curOptIdx)++ ]; return SUCCESS; } else { /* * IF we need another argument, be sure it is there and * take it. */ if (arg_txt[1] == NUL) { if (opts->curOptIdx >= opts->origArgCt) return FAILURE; opt_txt[ (*opt_idx)++ ] = opts->origArgVect[ (opts->curOptIdx)++ ]; } return SUCCESS; } } return SUCCESS; }
/** * Process option. Figure out whether or not to look for an option argument. * * @param[in,out] opts the program option descriptor * @param[in,out] o_st the option processing state * @returns SUCCESS or FAILURE */ LOCAL tSuccess get_opt_arg(tOptions * opts, tOptState * o_st) { o_st->flags |= (o_st->pOD->fOptState & OPTST_PERSISTENT_MASK); /* * Disabled options and options specified to not have arguments * are handled with the "none" procedure. Otherwise, check the * optional flag and call either the "may" or "must" function. */ if ( ((o_st->flags & OPTST_DISABLED) != 0) || (OPTST_GET_ARGTYPE(o_st->flags) == OPARG_TYPE_NONE)) return get_opt_arg_none(opts, o_st); if (o_st->flags & OPTST_ARG_OPTIONAL) return get_opt_arg_may( opts, o_st); return get_opt_arg_must(opts, o_st); }
/*=export_func optionFindNextValue * * what: find a hierarcicaly valued option instance * arg: + const tOptDesc* + pOptDesc + an option with a nested arg type + * arg: + const tOptionValue* + pPrevVal + the last entry + * arg: + char const* + name + name of value to find + * arg: + char const* + value + the matching value + * * ret_type: const tOptionValue* * ret_desc: a compound value structure * * doc: * This routine will find the next entry in a nested value option or * configurable. It will search through the list and return the next entry * that matches the criteria. * * err: * The returned result is NULL and errno is set: * @itemize @bullet * @item * @code{EINVAL} - the @code{pOptValue} does not point to a valid * hierarchical option value. * @item * @code{ENOENT} - no entry matched the given name. * @end itemize =*/ const tOptionValue* optionFindNextValue( const tOptDesc* pOptDesc, const tOptionValue* pPrevVal, char const* pzName, char const* pzVal ) { int foundOldVal = 0; tOptionValue* pRes = NULL; if ( (pOptDesc == NULL) || (OPTST_GET_ARGTYPE(pOptDesc->fOptState) != OPARG_TYPE_HIERARCHY)) { errno = EINVAL; } else if (pOptDesc->optCookie == NULL) { errno = ENOENT; } else do { tArgList* pAL = pOptDesc->optCookie; int ct = pAL->useCt; void** ppOV = (void**)pAL->apzArgs; if (ct == 0) { errno = ENOENT; break; } while (--ct >= 0) { tOptionValue* pOV = *(ppOV++); if (foundOldVal) { pRes = pOV; break; } if (pOV == pPrevVal) foundOldVal = 1; } if (pRes == NULL) errno = ENOENT; } while (0); return pRes; }
/*=export_func optionFindNextValue * * FIXME: the handling of 'pzName' and 'pzVal' is just wrong. * * what: find a hierarcicaly valued option instance * arg: + const tOptDesc* + odesc + an option with a nested arg type + * arg: + const tOptionValue* + pPrevVal + the last entry + * arg: + char const* + name + name of value to find + * arg: + char const* + value + the matching value + * * ret_type: const tOptionValue* * ret_desc: a compound value structure * * doc: * This routine will find the next entry in a nested value option or * configurable. It will search through the list and return the next entry * that matches the criteria. * * err: * The returned result is NULL and errno is set: * @itemize @bullet * @item * @code{EINVAL} - the @code{pOptValue} does not point to a valid * hierarchical option value. * @item * @code{ENOENT} - no entry matched the given name. * @end itemize =*/ tOptionValue const * optionFindNextValue(const tOptDesc * odesc, const tOptionValue * pPrevVal, char const * pzName, char const * pzVal) { bool old_found = false; tOptionValue* res = NULL; (void)pzName; (void)pzVal; if ( (odesc == NULL) || (OPTST_GET_ARGTYPE(odesc->fOptState) != OPARG_TYPE_HIERARCHY)) { errno = EINVAL; } else if (odesc->optCookie == NULL) { errno = ENOENT; } else do { tArgList* argl = odesc->optCookie; int ct = argl->useCt; void** poptv = (void**)argl->apzArgs; while (--ct >= 0) { tOptionValue* pOV = *(poptv++); if (old_found) { res = pOV; break; } if (pOV == pPrevVal) old_found = true; } if (res == NULL) errno = ENOENT; } while (false); return res; }
/** * Print extended usage. Usage/help was requested. * * @param opts the program option descriptor * @param od the option descriptor * @param title the title for the options */ static void prt_extd_usage(tOptions * opts, tOptDesc * od, char const * title) { if ( ((opts->fOptSet & OPTPROC_VENDOR_OPT) != 0) && (od->optActualValue == VENDOR_OPTION_VALUE)) { prt_vendor_opts(opts, title); return; } /* * IF there are option conflicts or dependencies, * THEN print them here. */ if ((od->pOptMust != NULL) || (od->pOptCant != NULL)) prt_conflicts(opts, od); /* * IF there is a disablement string * THEN print the disablement info */ if (od->pz_DisableName != NULL ) fprintf(option_usage_fp, zDis + tab_skip_ct, od->pz_DisableName); /* * Check for argument types that have callbacks with magical properties */ switch (OPTST_GET_ARGTYPE(od->fOptState)) { case OPARG_TYPE_NUMERIC: /* * IF the numeric option has a special callback, * THEN call it, requesting the range or other special info */ if ( (od->pOptProc != NULL) && (od->pOptProc != optionNumericVal) ) { (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od); } break; case OPARG_TYPE_FILE: (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od); break; } /* * IF the option defaults to being enabled, * THEN print that out */ if (od->fOptState & OPTST_INITENABLED) fputs(zEnab + tab_skip_ct, option_usage_fp); /* * IF the option is in an equivalence class * AND not the designated lead * THEN print equivalence and leave it at that. */ if ( (od->optEquivIndex != NO_EQUIVALENT) && (od->optEquivIndex != od->optActualIndex ) ) { fprintf(option_usage_fp, zalt_opt + tab_skip_ct, opts->pOptDesc[ od->optEquivIndex ].pz_Name); return; } /* * IF this particular option can NOT be preset * AND some form of presetting IS allowed, * AND it is not an auto-managed option (e.g. --help, et al.) * THEN advise that this option may not be preset. */ if ( ((od->fOptState & OPTST_NO_INIT) != 0) && ( (opts->papzHomeList != NULL) || (opts->pzPROGNAME != NULL) ) && (od->optIndex < opts->presetOptCt) ) fputs(zNoPreset + tab_skip_ct, option_usage_fp); /* * Print the appearance requirements. */ if (OPTST_GET_ARGTYPE(od->fOptState) == OPARG_TYPE_MEMBERSHIP) fputs(zMembers + tab_skip_ct, option_usage_fp); else switch (od->optMinCt) { case 1: case 0: switch (od->optMaxCt) { case 0: fputs(zPreset + tab_skip_ct, option_usage_fp); break; case NOLIMIT: fputs(zNoLim + tab_skip_ct, option_usage_fp); break; case 1: break; /* * IF the max is more than one but limited, print "UP TO" message */ default: fprintf(option_usage_fp, zUpTo + tab_skip_ct, od->optMaxCt); break; } break; default: /* * More than one is required. Print the range. */ fprintf(option_usage_fp, zMust + tab_skip_ct, od->optMinCt, od->optMaxCt); } if ( NAMED_OPTS(opts) && (opts->specOptIdx.default_opt == od->optIndex)) fputs(zDefaultOpt + tab_skip_ct, option_usage_fp); }
/** * print one option entry to the save file. * * @param[in] fp the file pointer for the save file * @param[in] od the option descriptor to print * @param[in] l_arg the last argument for the option */ static void prt_entry(FILE * fp, tOptDesc * od, char const * l_arg) { int space_ct; /* * There is an argument. Pad the name so values line up. * Not disabled *OR* this got equivalenced to another opt, * then use current option name. * Otherwise, there must be a disablement name. */ { char const * pz = (! DISABLED_OPT(od) || (od->optEquivIndex != NO_EQUIVALENT)) ? od->pz_Name : od->pz_DisableName; space_ct = 17 - strlen(pz); fputs(pz, fp); } if ( (l_arg == NULL) && (OPTST_GET_ARGTYPE(od->fOptState) != OPARG_TYPE_NUMERIC)) goto end_entry; fputs(" = ", fp); while (space_ct-- > 0) fputc(' ', fp); /* * IF the option is numeric only, * THEN the char pointer is really the number */ if (OPTST_GET_ARGTYPE(od->fOptState) == OPARG_TYPE_NUMERIC) fprintf(fp, "%d", (int)(t_word)l_arg); else { for (;;) { char const * eol = strchr(l_arg, NL); /* * IF this is the last line * THEN bail and print it */ if (eol == NULL) break; /* * Print the continuation and the text from the current line */ (void)fwrite(l_arg, (size_t)(eol - l_arg), (size_t)1, fp); l_arg = eol+1; /* advance the Last Arg pointer */ fputs("\\\n", fp); } /* * Terminate the entry */ fputs(l_arg, fp); } end_entry: fputc(NL, fp); }
/*=export_func optionSaveFile * * what: saves the option state to a file * * arg: tOptions*, opts, program options descriptor * * doc: * * This routine will save the state of option processing to a file. The name * of that file can be specified with the argument to the @code{--save-opts} * option, or by appending the @code{rcfile} attribute to the last * @code{homerc} attribute. If no @code{rcfile} attribute was specified, it * will default to @code{.@i{programname}rc}. If you wish to specify another * file, you should invoke the @code{SET_OPT_SAVE_OPTS(@i{filename})} macro. * * The recommend usage is as follows: * @example * optionProcess(&progOptions, argc, argv); * if (i_want_a_non_standard_place_for_this) * SET_OPT_SAVE_OPTS("myfilename"); * optionSaveFile(&progOptions); * @end example * * err: * * If no @code{homerc} file was specified, this routine will silently return * and do nothing. If the output file cannot be created or updated, a message * will be printed to @code{stderr} and the routine will return. =*/ void optionSaveFile(tOptions * opts) { tOptDesc * od; int ct; FILE * fp = open_sv_file(opts); if (fp == NULL) return; /* * FOR each of the defined options, ... */ ct = opts->presetOptCt; od = opts->pOptDesc; do { tOptDesc * p; /* * IF the option has not been defined * OR it does not take an initialization value * OR it is equivalenced to another option * THEN continue (ignore it) * * Equivalenced options get picked up when the equivalenced-to * option is processed. */ if (UNUSED_OPT(od)) continue; if ((od->fOptState & OPTST_DO_NOT_SAVE_MASK) != 0) continue; if ( (od->optEquivIndex != NO_EQUIVALENT) && (od->optEquivIndex != od->optIndex)) continue; /* * The option argument data are found at the equivalenced-to option, * but the actual option argument type comes from the original * option descriptor. Be careful! */ p = ((od->fOptState & OPTST_EQUIVALENCE) != 0) ? (opts->pOptDesc + od->optActualIndex) : od; switch (OPTST_GET_ARGTYPE(od->fOptState)) { case OPARG_TYPE_NONE: prt_no_arg_opt(fp, p, od); break; case OPARG_TYPE_NUMERIC: prt_entry(fp, p, (void*)(p->optArg.argInt)); break; case OPARG_TYPE_STRING: prt_str_arg(fp, p); break; case OPARG_TYPE_ENUMERATION: prt_enum_arg(fp, p); break; case OPARG_TYPE_MEMBERSHIP: prt_set_arg(fp, p); break; case OPARG_TYPE_BOOLEAN: prt_entry(fp, p, p->optArg.argBool ? "true" : "false"); break; case OPARG_TYPE_HIERARCHY: prt_nested(fp, p); break; case OPARG_TYPE_FILE: prt_file_arg(fp, p, opts); break; default: break; /* cannot handle - skip it */ } } while (od++, (--ct > 0)); fclose(fp); }
static void emitSetup( tOptions* pOpts ) { tOptDesc* pOptDesc = pOpts->pOptDesc; int optionCt = pOpts->presetOptCt; char const* pzFmt; char const* pzDefault; for (;optionCt > 0; pOptDesc++, --optionCt) { char zVal[16]; /* * Options that are either usage documentation or are compiled out * are not to be processed. */ if (SKIP_OPT(pOptDesc) || (pOptDesc->pz_NAME == NULL)) continue; if (pOptDesc->optMaxCt > 1) pzFmt = zMultiDef; else pzFmt = zSingleDef; /* * IF this is an enumeration/bitmask option, then convert the value * to a string before printing the default value. */ switch (OPTST_GET_ARGTYPE(pOptDesc->fOptState)) { case OPARG_TYPE_ENUMERATION: (*(pOptDesc->pOptProc))(OPTPROC_EMIT_SHELL, pOptDesc ); pzDefault = pOptDesc->optArg.argString; break; /* * Numeric and membership bit options are just printed as a number. */ case OPARG_TYPE_NUMERIC: snprintf( zVal, sizeof( zVal ), "%d", (int)pOptDesc->optArg.argInt ); pzDefault = zVal; break; case OPARG_TYPE_MEMBERSHIP: snprintf( zVal, sizeof( zVal ), "%lu", (unsigned long)pOptDesc->optArg.argIntptr ); pzDefault = zVal; break; case OPARG_TYPE_BOOLEAN: pzDefault = (pOptDesc->optArg.argBool) ? "true" : "false"; break; default: if (pOptDesc->optArg.argString == NULL) { if (pzFmt == zSingleDef) pzFmt = zSingleNoDef; pzDefault = NULL; } else pzDefault = pOptDesc->optArg.argString; } printf( pzFmt, pOpts->pzPROGNAME, pOptDesc->pz_NAME, pzDefault ); } }
/** * Load an option from a block of text. The text must start with the * configurable/option name and be followed by its associated value. * That value may be processed in any of several ways. See "tOptionLoadMode" * in autoopts.h. * * @param[in,out] opts program options descriptor * @param[in,out] opt_state option processing state * @param[in,out] line source line with long option name in it * @param[in] direction current processing direction (preset or not) * @param[in] load_mode option loading mode (OPTION_LOAD_*) */ LOCAL void loadOptionLine( tOptions * opts, tOptState * opt_state, char * line, tDirection direction, tOptionLoadMode load_mode ) { line = SPN_LOAD_LINE_SKIP_CHARS(line); { char * arg = assemble_arg_val(line, load_mode); if (! SUCCESSFUL(opt_find_long(opts, line, opt_state))) return; if (opt_state->flags & OPTST_NO_INIT) return; opt_state->pzOptArg = arg; } switch (opt_state->flags & (OPTST_IMM|OPTST_DISABLE_IMM)) { case 0: /* * The selected option has no immediate action. * THEREFORE, if the direction is PRESETTING * THEN we skip this option. */ if (PRESETTING(direction)) return; break; case OPTST_IMM: if (PRESETTING(direction)) { /* * We are in the presetting direction with an option we handle * immediately for enablement, but normally for disablement. * Therefore, skip if disabled. */ if ((opt_state->flags & OPTST_DISABLED) == 0) return; } else { /* * We are in the processing direction with an option we handle * immediately for enablement, but normally for disablement. * Therefore, skip if NOT disabled. */ if ((opt_state->flags & OPTST_DISABLED) != 0) return; } break; case OPTST_DISABLE_IMM: if (PRESETTING(direction)) { /* * We are in the presetting direction with an option we handle * immediately for disablement, but normally for disablement. * Therefore, skip if NOT disabled. */ if ((opt_state->flags & OPTST_DISABLED) != 0) return; } else { /* * We are in the processing direction with an option we handle * immediately for disablement, but normally for disablement. * Therefore, skip if disabled. */ if ((opt_state->flags & OPTST_DISABLED) == 0) return; } break; case OPTST_IMM|OPTST_DISABLE_IMM: /* * The selected option is always for immediate action. * THEREFORE, if the direction is PROCESSING * THEN we skip this option. */ if (PROCESSING(direction)) return; break; } /* * Fix up the args. */ if (OPTST_GET_ARGTYPE(opt_state->pOD->fOptState) == OPARG_TYPE_NONE) { if (*opt_state->pzOptArg != NUL) return; opt_state->pzOptArg = NULL; } else if (opt_state->pOD->fOptState & OPTST_ARG_OPTIONAL) { if (*opt_state->pzOptArg == NUL) opt_state->pzOptArg = NULL; else { AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg"); opt_state->flags |= OPTST_ALLOC_ARG; } } else { if (*opt_state->pzOptArg == NUL) opt_state->pzOptArg = zNil; else { AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg"); opt_state->flags |= OPTST_ALLOC_ARG; } } { tOptionLoadMode sv = option_load_mode; option_load_mode = load_mode; handle_opt(opts, opt_state); option_load_mode = sv; } }
/*=export_func optionPutShell * what: write a portable shell script to parse options * private: * arg: tOptions *, pOpts, the program options descriptor * doc: This routine will emit portable shell script text for parsing * the options described in the option definitions. =*/ void optionPutShell(tOptions * pOpts) { int optIx = 0; printf(zOptCtFmt, pOpts->curOptIdx-1); do { tOptDesc * pOD = pOpts->pOptDesc + optIx; if ((pOD->fOptState & OPTST_NO_OUTPUT_MASK) != 0) continue; /* * Equivalence classes are hard to deal with. Where the * option data wind up kind of squishes around. For the purposes * of emitting shell state, they are not recommended, but we'll * do something. I guess we'll emit the equivalenced-to option * at the point in time when the base option is found. */ if (pOD->optEquivIndex != NO_EQUIVALENT) continue; /* equivalence to a different option */ /* * Equivalenced to a different option. Process the current option * as the equivalenced-to option. Keep the persistent state bits, * but copy over the set-state bits. */ if (pOD->optActualIndex != optIx) { tOptDesc * p = pOpts->pOptDesc + pOD->optActualIndex; p->optArg = pOD->optArg; p->fOptState &= OPTST_PERSISTENT_MASK; p->fOptState |= pOD->fOptState & ~OPTST_PERSISTENT_MASK; printf(zEquivMode, pOpts->pzPROGNAME, pOD->pz_NAME, p->pz_NAME); pOD = p; } /* * If the argument type is a set membership bitmask, then we always * emit the thing. We do this because it will always have some sort * of bitmask value and we need to emit the bit values. */ if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) { print_membership(pOpts, pOD); continue; } /* * IF the option was either specified or it wakes up enabled, * then we will emit information. Otherwise, skip it. * The idea is that if someone defines an option to initialize * enabled, we should tell our shell script that it is enabled. */ if (UNUSED_OPT(pOD) && DISABLED_OPT(pOD)) continue; /* * Handle stacked arguments */ if ( (pOD->fOptState & OPTST_STACKED) && (pOD->optCookie != NULL) ) { print_stacked_arg(pOpts, pOD); continue; } /* * If the argument has been disabled, * Then set its value to the disablement string */ if ((pOD->fOptState & OPTST_DISABLED) != 0) { printf(zOptDisabl, pOpts->pzPROGNAME, pOD->pz_NAME, (pOD->pz_DisablePfx != NULL) ? pOD->pz_DisablePfx : "false"); continue; } /* * If the argument type is numeric, the last arg pointer * is really the VALUE of the string that was pointed to. */ if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NUMERIC) { printf(zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME, (int)pOD->optArg.argInt); continue; } /* * If the argument type is an enumeration, then it is much * like a text value, except we call the callback function * to emit the value corresponding to the "optArg" number. */ if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_ENUMERATION) { print_enumeration(pOpts, pOD); continue; } /* * If the argument type is numeric, the last arg pointer * is really the VALUE of the string that was pointed to. */ if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_BOOLEAN) { printf(zFullOptFmt, pOpts->pzPROGNAME, pOD->pz_NAME, (pOD->optArg.argBool == 0) ? "false" : "true"); continue; } /* * IF the option has an empty value, * THEN we set the argument to the occurrence count. */ if ( (pOD->optArg.argString == NULL) || (pOD->optArg.argString[0] == NUL) ) { printf(zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME, pOD->optOccCt); continue; } /* * This option has a text value */ printf(OPT_VAL_FMT, pOpts->pzPROGNAME, pOD->pz_NAME); print_quot_str(pOD->optArg.argString); printf(OPT_END_FMT, pOpts->pzPROGNAME, pOD->pz_NAME); } while (++optIx < pOpts->presetOptCt ); if ( ((pOpts->fOptSet & OPTPROC_REORDER) != 0) && (pOpts->curOptIdx < pOpts->origArgCt)) print_reordering(pOpts); fflush(stdout); }
/* * Load an option from a block of text. The text must start with the * configurable/option name and be followed by its associated value. * That value may be processed in any of several ways. See "tOptionLoadMode" * in autoopts.h. */ LOCAL void loadOptionLine( tOptions* pOpts, tOptState* pOS, char* pzLine, tDirection direction, tOptionLoadMode load_mode ) { while (isspace( (int)*pzLine )) pzLine++; { char* pzArg = assembleArgValue( pzLine, load_mode ); if (! SUCCESSFUL( longOptionFind( pOpts, pzLine, pOS ))) return; if (pOS->flags & OPTST_NO_INIT) return; pOS->pzOptArg = pzArg; } switch (pOS->flags & (OPTST_IMM|OPTST_DISABLE_IMM)) { case 0: /* * The selected option has no immediate action. * THEREFORE, if the direction is PRESETTING * THEN we skip this option. */ if (PRESETTING(direction)) return; break; case OPTST_IMM: if (PRESETTING(direction)) { /* * We are in the presetting direction with an option we handle * immediately for enablement, but normally for disablement. * Therefore, skip if disabled. */ if ((pOS->flags & OPTST_DISABLED) == 0) return; } else { /* * We are in the processing direction with an option we handle * immediately for enablement, but normally for disablement. * Therefore, skip if NOT disabled. */ if ((pOS->flags & OPTST_DISABLED) != 0) return; } break; case OPTST_DISABLE_IMM: if (PRESETTING(direction)) { /* * We are in the presetting direction with an option we handle * immediately for disablement, but normally for disablement. * Therefore, skip if NOT disabled. */ if ((pOS->flags & OPTST_DISABLED) != 0) return; } else { /* * We are in the processing direction with an option we handle * immediately for disablement, but normally for disablement. * Therefore, skip if disabled. */ if ((pOS->flags & OPTST_DISABLED) == 0) return; } break; case OPTST_IMM|OPTST_DISABLE_IMM: /* * The selected option is always for immediate action. * THEREFORE, if the direction is PROCESSING * THEN we skip this option. */ if (PROCESSING(direction)) return; break; } /* * Fix up the args. */ if (OPTST_GET_ARGTYPE(pOS->pOD->fOptState) == OPARG_TYPE_NONE) { if (*pOS->pzOptArg != NUL) return; pOS->pzOptArg = NULL; } else if (pOS->pOD->fOptState & OPTST_ARG_OPTIONAL) { if (*pOS->pzOptArg == NUL) pOS->pzOptArg = NULL; else { AGDUPSTR( pOS->pzOptArg, pOS->pzOptArg, "option argument" ); pOS->flags |= OPTST_ALLOC_ARG; } } else { if (*pOS->pzOptArg == NUL) pOS->pzOptArg = zNil; else { AGDUPSTR( pOS->pzOptArg, pOS->pzOptArg, "option argument" ); pOS->flags |= OPTST_ALLOC_ARG; } } { tOptionLoadMode sv = option_load_mode; option_load_mode = load_mode; handleOption( pOpts, pOS ); option_load_mode = sv; } }
/* * 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; }
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 zFmt[16]; /* format for all-but-last entries on a line */ sprintf(zFmt, ENUM_ERR_WIDTH, (int)max_len); 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, zFmt, *(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); } }
static void emit_setup(tOptions * opts) { tOptDesc * od = opts->pOptDesc; int opt_ct = opts->presetOptCt; char const * fmt; char const * def_val; for (;opt_ct > 0; od++, --opt_ct) { char int_val_buf[32]; /* * Options that are either usage documentation or are compiled out * are not to be processed. */ if (SKIP_OPT(od) || (od->pz_NAME == NULL)) continue; if (od->optMaxCt > 1) fmt = MULTI_DEF_FMT; else fmt = SGL_DEF_FMT; /* * IF this is an enumeration/bitmask option, then convert the value * to a string before printing the default value. */ switch (OPTST_GET_ARGTYPE(od->fOptState)) { case OPARG_TYPE_ENUMERATION: (*(od->pOptProc))(OPTPROC_EMIT_SHELL, od ); def_val = od->optArg.argString; break; /* * Numeric and membership bit options are just printed as a number. */ case OPARG_TYPE_NUMERIC: snprintf(int_val_buf, sizeof(int_val_buf), "%d", (int)od->optArg.argInt); def_val = int_val_buf; break; case OPARG_TYPE_MEMBERSHIP: snprintf(int_val_buf, sizeof(int_val_buf), "%lu", (unsigned long)od->optArg.argIntptr); def_val = int_val_buf; break; case OPARG_TYPE_BOOLEAN: def_val = (od->optArg.argBool) ? TRUE_STR : FALSE_STR; break; default: if (od->optArg.argString == NULL) { if (fmt == SGL_DEF_FMT) fmt = SGL_NO_DEF_FMT; def_val = NULL; } else def_val = od->optArg.argString; } printf(fmt, opts->pzPROGNAME, od->pz_NAME, def_val); } }
/* * Print the usage information for a single option. */ static void printOneUsage( tOptions* pOptions, tOptDesc* pOD, arg_types_t* pAT ) { /* * Flag prefix: IF no flags at all, then omit it. If not printable * (not allowed for this option), then blank, else print it. * Follow it with a comma if we are doing GNU usage and long * opts are to be printed too. */ if ((pOptions->fOptSet & OPTPROC_SHORTOPT) == 0) fputs( pAT->pzSpc, option_usage_fp ); else if (! isgraph( pOD->optValue)) { if ( (pOptions->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT)) == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT)) fputc( ' ', option_usage_fp ); fputs( pAT->pzNoF, option_usage_fp ); } else { fprintf( option_usage_fp, " -%c", pOD->optValue ); if ( (pOptions->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT)) == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT)) fputs( ", ", option_usage_fp ); } { char z[ 80 ]; tCC* pzArgType; /* * 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 (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NONE) { pzArgType = pAT->pzNo; } else if (pOD->fOptState & OPTST_ARG_OPTIONAL) { pzArgType = pAT->pzOpt; } else switch (OPTST_GET_ARGTYPE(pOD->fOptState)) { case OPARG_TYPE_ENUMERATION: pzArgType = pAT->pzKey; break; case OPARG_TYPE_MEMBERSHIP: pzArgType = pAT->pzKeyL; break; case OPARG_TYPE_BOOLEAN: pzArgType = pAT->pzBool; break; case OPARG_TYPE_NUMERIC: pzArgType = pAT->pzNum; break; case OPARG_TYPE_HIERARCHY: pzArgType = pAT->pzNest; break; case OPARG_TYPE_STRING: pzArgType = pAT->pzStr; break; default: goto bogus_desc; break; } snprintf( z, sizeof(z), pAT->pzOptFmt, pzArgType, pOD->pz_Name, (pOD->optMinCt != 0) ? pAT->pzReq : pAT->pzOpt ); fprintf( option_usage_fp, zOptFmtLine, z, pOD->pzText ); switch (OPTST_GET_ARGTYPE(pOD->fOptState)) { case OPARG_TYPE_ENUMERATION: case OPARG_TYPE_MEMBERSHIP: displayEnum = (pOD->pOptProc != NULL) ? AG_TRUE : displayEnum; } } return; bogus_desc: fprintf( stderr, zInvalOptDesc, pOD->pz_Name ); exit( EX_SOFTWARE ); }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * PER OPTION TYPE USAGE INFORMATION */ static void printExtendedUsage( tOptions* pOptions, tOptDesc* pOD, arg_types_t* pAT ) { /* * IF there are option conflicts or dependencies, * THEN print them here. */ if ( (pOD->pOptMust != NULL) || (pOD->pOptCant != NULL) ) { fputs( zTabHyp, option_usage_fp ); /* * DEPENDENCIES: */ if (pOD->pOptMust != NULL) { const int* pOptNo = pOD->pOptMust; fputs( zReqThese, option_usage_fp ); for (;;) { fprintf( option_usage_fp, zTabout, pOptions->pOptDesc[ *pOptNo ].pz_Name ); if (*++pOptNo == NO_EQUIVALENT) break; } if (pOD->pOptCant != NULL) fputs( zTabHypAnd, option_usage_fp ); } /* * CONFLICTS: */ if (pOD->pOptCant != NULL) { const int* pOptNo = pOD->pOptCant; fputs( zProhib, option_usage_fp ); for (;;) { fprintf( option_usage_fp, zTabout, pOptions->pOptDesc[ *pOptNo ].pz_Name ); if (*++pOptNo == NO_EQUIVALENT) break; } } } /* * IF there is a disablement string * THEN print the disablement info */ if (pOD->pz_DisableName != NULL ) fprintf( option_usage_fp, zDis, pOD->pz_DisableName ); /* * IF the numeric option has a special callback, * THEN call it, requesting the range or other special info */ if ( (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NUMERIC) && (pOD->pOptProc != NULL) && (pOD->pOptProc != optionNumericVal) ) { (*(pOD->pOptProc))( pOptions, NULL ); } /* * IF the option defaults to being enabled, * THEN print that out */ if (pOD->fOptState & OPTST_INITENABLED) fputs( zEnab, option_usage_fp ); /* * IF the option is in an equivalence class * AND not the designated lead * THEN print equivalence and leave it at that. */ if ( (pOD->optEquivIndex != NO_EQUIVALENT) && (pOD->optEquivIndex != pOD->optActualIndex ) ) { fprintf( option_usage_fp, zAlt, pOptions->pOptDesc[ pOD->optEquivIndex ].pz_Name ); return; } /* * IF this particular option can NOT be preset * AND some form of presetting IS allowed, * AND it is not an auto-managed option (e.g. --help, et al.) * THEN advise that this option may not be preset. */ if ( ((pOD->fOptState & OPTST_NO_INIT) != 0) && ( (pOptions->papzHomeList != NULL) || (pOptions->pzPROGNAME != NULL) ) && (pOD->optIndex < pOptions->presetOptCt) ) fputs( zNoPreset, option_usage_fp ); /* * Print the appearance requirements. */ if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) fputs( zMembers, option_usage_fp ); else switch (pOD->optMinCt) { case 1: case 0: switch (pOD->optMaxCt) { case 0: fputs( zPreset, option_usage_fp ); break; case NOLIMIT: fputs( zNoLim, option_usage_fp ); break; case 1: break; /* * IF the max is more than one but limited, print "UP TO" message */ default: fprintf( option_usage_fp, zUpTo, pOD->optMaxCt ); break; } break; default: /* * More than one is required. Print the range. */ fprintf( option_usage_fp, zMust, pOD->optMinCt, pOD->optMaxCt ); } if ( NAMED_OPTS( pOptions ) && (pOptions->specOptIdx.default_opt == pOD->optIndex)) fputs( zDefaultOpt, option_usage_fp ); }