/*=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; }
/** * 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); }
/** * Print a message suggesting how to get help. * * @param[in] opts the program options */ static void print_offer_usage(tOptions * opts) { char help[24]; if (HAS_opt_usage_t(opts)) { int ix = opts->presetOptCt; tOptDesc * od = opts->pOptDesc + ix; while (od->optUsage != AOUSE_HELP) { if (++ix >= opts->optCt) ao_bug(zmissing_help_msg); od++; } switch (opts->fOptSet & (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)) { case OPTPROC_SHORTOPT: help[0] = '-'; help[1] = od->optValue; help[2] = NUL; break; case OPTPROC_LONGOPT: case (OPTPROC_LONGOPT | OPTPROC_SHORTOPT): help[0] = help[1] = '-'; strncpy(help + 2, od->pz_Name, 20); break; case 0: strncpy(help, od->pz_Name, 20); break; } } else { switch (opts->fOptSet & (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)) { case OPTPROC_SHORTOPT: strcpy(help, "-h"); break; case OPTPROC_LONGOPT: case (OPTPROC_LONGOPT | OPTPROC_SHORTOPT): strcpy(help, "--help"); break; case 0: strcpy(help, "help"); break; } } fprintf(option_usage_fp, zoffer_usage_fmt, opts->pzProgName, help); }
/*=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; }
/** * Process an option with an optional argument. For short options, it looks * at the character after the option character, or it consumes the next full * argument. For long options, it looks for an '=' character attachment to * the long option name before deciding to take the next command line * argument. * * @param pOpts the option descriptor * @param o_st a structure for managing the current processing state * @returns SUCCESS or does not return */ static tSuccess get_opt_arg_may(tOptions * pOpts, tOptState * o_st) { /* * An option argument is optional. */ switch (o_st->optType) { case TOPT_SHORT: if (*++pOpts->pzCurOpt != NUL) o_st->pzOptArg = pOpts->pzCurOpt; else { char* pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; /* * BECAUSE it is optional, we must make sure * we did not find another flag and that there * is such an argument. */ if ((pzLA == NULL) || (*pzLA == '-')) o_st->pzOptArg = NULL; else { pOpts->curOptIdx++; /* argument found */ o_st->pzOptArg = pzLA; } } break; case TOPT_LONG: /* * Look for an argument if we don't already have one (glued on * with a `=' character) *AND* we are not in named argument mode */ if ( (o_st->pzOptArg == NULL) && (! NAMED_OPTS(pOpts))) { char* pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; /* * BECAUSE it is optional, we must make sure * we did not find another flag and that there * is such an argument. */ if ((pzLA == NULL) || (*pzLA == '-')) o_st->pzOptArg = NULL; else { pOpts->curOptIdx++; /* argument found */ o_st->pzOptArg = pzLA; } } break; default: case TOPT_DEFAULT: ao_bug(zbad_default_msg); } /* * After an option with an optional argument, we will * *always* start with the next option because if there * were any characters following the option name/flag, * they would be interpreted as the argument. */ pOpts->pzCurOpt = NULL; return SUCCESS; }