1290001Sglebius/** 2290001Sglebius * @file check.c 3290001Sglebius * 4290001Sglebius * @brief Hunt for options in the option descriptor list 5290001Sglebius * 6290001Sglebius * This file contains the routines that deal with processing quoted strings 7290001Sglebius * into an internal format. 8290001Sglebius * 9290001Sglebius * @addtogroup autoopts 10290001Sglebius * @{ 11290001Sglebius */ 12290001Sglebius/* 13290001Sglebius * This file is part of AutoOpts, a companion to AutoGen. 14290001Sglebius * AutoOpts is free software. 15290001Sglebius * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 16290001Sglebius * 17290001Sglebius * AutoOpts is available under any one of two licenses. The license 18290001Sglebius * in use must be one of these two and the choice is under the control 19290001Sglebius * of the user of the license. 20290001Sglebius * 21290001Sglebius * The GNU Lesser General Public License, version 3 or later 22290001Sglebius * See the files "COPYING.lgplv3" and "COPYING.gplv3" 23290001Sglebius * 24290001Sglebius * The Modified Berkeley Software Distribution License 25290001Sglebius * See the file "COPYING.mbsd" 26290001Sglebius * 27290001Sglebius * These files have the following sha256 sums: 28290001Sglebius * 29290001Sglebius * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 30290001Sglebius * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 31290001Sglebius * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 32290001Sglebius */ 33290001Sglebius 34290001Sglebius/* = = = START-STATIC-FORWARD = = = */ 35290001Sglebiusstatic int 36290001Sglebiusparse_opt(char const ** nm_pp, char ** arg_pp, char * buf, size_t bufsz); 37290001Sglebius 38290001Sglebiusstatic void 39290001Sglebiusopt_ambiguities(tOptions * opts, char const * name, int nm_len); 40290001Sglebius 41290001Sglebiusstatic int 42290001Sglebiusopt_match_ct(tOptions * opts, char const * name, int nm_len, 43290001Sglebius int * ixp, bool * disable); 44290001Sglebius 45290001Sglebiusstatic tSuccess 46290001Sglebiusopt_set(tOptions * opts, char * arg, int idx, bool disable, tOptState * st); 47290001Sglebius 48290001Sglebiusstatic tSuccess 49290001Sglebiusopt_unknown(tOptions * opts, char const * name, char * arg, tOptState * st); 50290001Sglebius 51290001Sglebiusstatic tSuccess 52290001Sglebiusopt_ambiguous(tOptions * opts, char const * name, int match_ct); 53290001Sglebius 54290001Sglebiusstatic tSuccess 55290001Sglebiusget_opt_arg_must(tOptions * opts, tOptState * o_st); 56290001Sglebius 57290001Sglebiusstatic tSuccess 58290001Sglebiusget_opt_arg_may(tOptions * pOpts, tOptState * o_st); 59290001Sglebius 60290001Sglebiusstatic tSuccess 61290001Sglebiusget_opt_arg_none(tOptions * pOpts, tOptState * o_st); 62290001Sglebius/* = = = END-STATIC-FORWARD = = = */ 63290001Sglebius 64290001Sglebius/** 65290001Sglebius * find the name and name length we are looking for 66290001Sglebius */ 67290001Sglebiusstatic int 68290001Sglebiusparse_opt(char const ** nm_pp, char ** arg_pp, char * buf, size_t bufsz) 69290001Sglebius{ 70290001Sglebius int res = 0; 71290001Sglebius char const * p = *nm_pp; 72290001Sglebius *arg_pp = NULL; 73290001Sglebius 74290001Sglebius for (;;) { 75290001Sglebius switch (*(p++)) { 76290001Sglebius case NUL: return res; 77290001Sglebius 78290001Sglebius case '=': 79290001Sglebius memcpy(buf, *nm_pp, (size_t)res); 80290001Sglebius 81290001Sglebius buf[res] = NUL; 82290001Sglebius *nm_pp = buf; 83294905Sdelphij *arg_pp = VOIDP(p); 84290001Sglebius return res; 85290001Sglebius 86290001Sglebius default: 87290001Sglebius if (++res >= (int)bufsz) 88290001Sglebius return -1; 89290001Sglebius } 90290001Sglebius } 91290001Sglebius} 92290001Sglebius 93290001Sglebius/** 94290001Sglebius * print out the options that match the given name. 95290001Sglebius * 96290001Sglebius * @param pOpts option data 97290001Sglebius * @param opt_name name of option to look for 98290001Sglebius */ 99290001Sglebiusstatic void 100290001Sglebiusopt_ambiguities(tOptions * opts, char const * name, int nm_len) 101290001Sglebius{ 102290001Sglebius char const * const hyph = 103290001Sglebius NAMED_OPTS(opts) ? "" : LONG_OPT_MARKER; 104290001Sglebius 105290001Sglebius tOptDesc * pOD = opts->pOptDesc; 106290001Sglebius int idx = 0; 107290001Sglebius 108290001Sglebius fputs(zambig_list_msg, stderr); 109290001Sglebius do { 110290001Sglebius if (pOD->pz_Name == NULL) 111290001Sglebius continue; /* doc option */ 112290001Sglebius 113290001Sglebius if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0) 114290001Sglebius fprintf(stderr, zambig_file, hyph, pOD->pz_Name); 115290001Sglebius 116290001Sglebius else if ( (pOD->pz_DisableName != NULL) 117290001Sglebius && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0) 118290001Sglebius ) 119290001Sglebius fprintf(stderr, zambig_file, hyph, pOD->pz_DisableName); 120290001Sglebius } while (pOD++, (++idx < opts->optCt)); 121290001Sglebius} 122290001Sglebius 123290001Sglebius/** 124290001Sglebius * Determine the number of options that match the name 125290001Sglebius * 126290001Sglebius * @param pOpts option data 127290001Sglebius * @param opt_name name of option to look for 128290001Sglebius * @param nm_len length of provided name 129290001Sglebius * @param index pointer to int for option index 130290001Sglebius * @param disable pointer to bool to mark disabled option 131290001Sglebius * @return count of options that match 132290001Sglebius */ 133290001Sglebiusstatic int 134290001Sglebiusopt_match_ct(tOptions * opts, char const * name, int nm_len, 135290001Sglebius int * ixp, bool * disable) 136290001Sglebius{ 137290001Sglebius int matchCt = 0; 138290001Sglebius int idx = 0; 139290001Sglebius int idxLim = opts->optCt; 140290001Sglebius tOptDesc * pOD = opts->pOptDesc; 141290001Sglebius 142290001Sglebius do { 143290001Sglebius /* 144290001Sglebius * If option disabled or a doc option, skip to next 145290001Sglebius */ 146290001Sglebius if (pOD->pz_Name == NULL) 147290001Sglebius continue; 148290001Sglebius 149290001Sglebius if ( SKIP_OPT(pOD) 150290001Sglebius && (pOD->fOptState != (OPTST_OMITTED | OPTST_NO_INIT))) 151290001Sglebius continue; 152290001Sglebius 153290001Sglebius if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0) { 154290001Sglebius /* 155290001Sglebius * IF we have a complete match 156290001Sglebius * THEN it takes priority over any already located partial 157290001Sglebius */ 158290001Sglebius if (pOD->pz_Name[ nm_len ] == NUL) { 159290001Sglebius *ixp = idx; 160290001Sglebius return 1; 161290001Sglebius } 162290001Sglebius } 163290001Sglebius 164290001Sglebius /* 165290001Sglebius * IF there is a disable name 166290001Sglebius * *AND* the option name matches the disable name 167290001Sglebius * THEN ... 168290001Sglebius */ 169290001Sglebius else if ( (pOD->pz_DisableName != NULL) 170290001Sglebius && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0) 171290001Sglebius ) { 172290001Sglebius *disable = true; 173290001Sglebius 174290001Sglebius /* 175290001Sglebius * IF we have a complete match 176290001Sglebius * THEN it takes priority over any already located partial 177290001Sglebius */ 178290001Sglebius if (pOD->pz_DisableName[ nm_len ] == NUL) { 179290001Sglebius *ixp = idx; 180290001Sglebius return 1; 181290001Sglebius } 182290001Sglebius } 183290001Sglebius 184290001Sglebius else 185290001Sglebius continue; /* does not match any option */ 186290001Sglebius 187290001Sglebius /* 188290001Sglebius * We found a full or partial match, either regular or disabling. 189290001Sglebius * Remember the index for later. 190290001Sglebius */ 191290001Sglebius *ixp = idx; 192290001Sglebius ++matchCt; 193290001Sglebius 194290001Sglebius } while (pOD++, (++idx < idxLim)); 195290001Sglebius 196290001Sglebius return matchCt; 197290001Sglebius} 198290001Sglebius 199290001Sglebius/** 200290001Sglebius * Set the option to the indicated option number. 201290001Sglebius * 202290001Sglebius * @param opts option data 203290001Sglebius * @param arg option argument (if glued to name) 204290001Sglebius * @param idx option index 205290001Sglebius * @param disable mark disabled option 206290001Sglebius * @param st state about current option 207290001Sglebius */ 208290001Sglebiusstatic tSuccess 209290001Sglebiusopt_set(tOptions * opts, char * arg, int idx, bool disable, tOptState * st) 210290001Sglebius{ 211290001Sglebius tOptDesc * pOD = opts->pOptDesc + idx; 212290001Sglebius 213290001Sglebius if (SKIP_OPT(pOD)) { 214290001Sglebius if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0) 215290001Sglebius return FAILURE; 216290001Sglebius 217290001Sglebius fprintf(stderr, zDisabledErr, opts->pzProgName, pOD->pz_Name); 218290001Sglebius if (pOD->pzText != NULL) 219290001Sglebius fprintf(stderr, SET_OFF_FMT, pOD->pzText); 220290001Sglebius fputc(NL, stderr); 221290001Sglebius (*opts->pUsageProc)(opts, EXIT_FAILURE); 222290001Sglebius /* NOTREACHED */ 223290001Sglebius _exit(EXIT_FAILURE); /* to be certain */ 224290001Sglebius } 225290001Sglebius 226290001Sglebius /* 227290001Sglebius * IF we found a disablement name, 228290001Sglebius * THEN set the bit in the callers' flag word 229290001Sglebius */ 230290001Sglebius if (disable) 231290001Sglebius st->flags |= OPTST_DISABLED; 232290001Sglebius 233290001Sglebius st->pOD = pOD; 234290001Sglebius st->pzOptArg = arg; 235290001Sglebius st->optType = TOPT_LONG; 236290001Sglebius 237290001Sglebius return SUCCESS; 238290001Sglebius} 239290001Sglebius 240290001Sglebius/** 241290001Sglebius * An option was not found. Check for default option and set it 242290001Sglebius * if there is one. Otherwise, handle the error. 243290001Sglebius * 244290001Sglebius * @param opts option data 245290001Sglebius * @param name name of option to look for 246290001Sglebius * @param arg option argument 247290001Sglebius * @param st state about current option 248290001Sglebius * 249290001Sglebius * @return success status 250290001Sglebius */ 251290001Sglebiusstatic tSuccess 252290001Sglebiusopt_unknown(tOptions * opts, char const * name, char * arg, tOptState * st) 253290001Sglebius{ 254290001Sglebius /* 255290001Sglebius * IF there is no equal sign 256290001Sglebius * *AND* we are using named arguments 257290001Sglebius * *AND* there is a default named option, 258290001Sglebius * THEN return that option. 259290001Sglebius */ 260290001Sglebius if ( (arg == NULL) 261290001Sglebius && NAMED_OPTS(opts) 262290001Sglebius && (opts->specOptIdx.default_opt != NO_EQUIVALENT)) { 263290001Sglebius 264290001Sglebius st->pOD = opts->pOptDesc + opts->specOptIdx.default_opt; 265290001Sglebius st->pzOptArg = name; 266290001Sglebius st->optType = TOPT_DEFAULT; 267290001Sglebius return SUCCESS; 268290001Sglebius } 269290001Sglebius 270290001Sglebius if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) { 271290001Sglebius fprintf(stderr, zIllOptStr, opts->pzProgPath, name); 272290001Sglebius (*opts->pUsageProc)(opts, EXIT_FAILURE); 273290001Sglebius /* NOTREACHED */ 274290001Sglebius _exit(EXIT_FAILURE); /* to be certain */ 275290001Sglebius } 276290001Sglebius 277290001Sglebius return FAILURE; 278290001Sglebius} 279290001Sglebius 280290001Sglebius/** 281290001Sglebius * Several options match the provided name. 282290001Sglebius * 283290001Sglebius * @param opts option data 284290001Sglebius * @param name name of option to look for 285290001Sglebius * @param match_ct number of matching options 286290001Sglebius * 287290001Sglebius * @return success status (always FAILURE, if it returns) 288290001Sglebius */ 289290001Sglebiusstatic tSuccess 290290001Sglebiusopt_ambiguous(tOptions * opts, char const * name, int match_ct) 291290001Sglebius{ 292290001Sglebius if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) { 293290001Sglebius fprintf(stderr, zambig_opt_fmt, opts->pzProgPath, name, match_ct); 294290001Sglebius if (match_ct <= 4) 295290001Sglebius opt_ambiguities(opts, name, (int)strlen(name)); 296290001Sglebius (*opts->pUsageProc)(opts, EXIT_FAILURE); 297290001Sglebius /* NOTREACHED */ 298290001Sglebius _exit(EXIT_FAILURE); /* to be certain */ 299290001Sglebius } 300290001Sglebius return FAILURE; 301290001Sglebius} 302290001Sglebius 303290001Sglebius/*=export_func optionVendorOption 304290001Sglebius * private: 305290001Sglebius * 306290001Sglebius * what: Process a vendor option 307290001Sglebius * arg: + tOptions * + pOpts + program options descriptor + 308290001Sglebius * arg: + tOptDesc * + pOptDesc + the descriptor for this arg + 309290001Sglebius * 310290001Sglebius * doc: 311290001Sglebius * For POSIX specified utilities, the options are constrained to the options, 312290001Sglebius * @xref{config attributes, Program Configuration}. AutoOpts clients should 313290001Sglebius * never specify this directly. It gets referenced when the option 314290001Sglebius * definitions contain a "vendor-opt" attribute. 315290001Sglebius=*/ 316290001Sglebiusvoid 317290001SglebiusoptionVendorOption(tOptions * pOpts, tOptDesc * pOD) 318290001Sglebius{ 319290001Sglebius tOptState opt_st = OPTSTATE_INITIALIZER(PRESET); 320290001Sglebius char const * vopt_str = pOD->optArg.argString; 321290001Sglebius 322290001Sglebius if (pOpts <= OPTPROC_EMIT_LIMIT) 323290001Sglebius return; 324290001Sglebius 325290001Sglebius if ((pOD->fOptState & OPTST_RESET) != 0) 326290001Sglebius return; 327290001Sglebius 328290001Sglebius if ((pOD->fOptState & OPTPROC_IMMEDIATE) == 0) 329290001Sglebius opt_st.flags = OPTST_DEFINED; 330290001Sglebius 331290001Sglebius if ( ((pOpts->fOptSet & OPTPROC_VENDOR_OPT) == 0) 332290001Sglebius || ! SUCCESSFUL(opt_find_long(pOpts, vopt_str, &opt_st)) 333290001Sglebius || ! SUCCESSFUL(get_opt_arg(pOpts, &opt_st)) ) 334290001Sglebius { 335290001Sglebius fprintf(stderr, zIllVendOptStr, pOpts->pzProgName, vopt_str); 336290001Sglebius (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); 337290001Sglebius /* NOTREACHED */ 338290001Sglebius _exit(EXIT_FAILURE); /* to be certain */ 339290001Sglebius } 340290001Sglebius 341290001Sglebius /* 342290001Sglebius * See if we are in immediate handling state. 343290001Sglebius */ 344290001Sglebius if (pOpts->fOptSet & OPTPROC_IMMEDIATE) { 345290001Sglebius /* 346290001Sglebius * See if the enclosed option is okay with that state. 347290001Sglebius */ 348290001Sglebius if (DO_IMMEDIATELY(opt_st.flags)) 349290001Sglebius (void)handle_opt(pOpts, &opt_st); 350290001Sglebius 351290001Sglebius } else { 352290001Sglebius /* 353290001Sglebius * non-immediate direction. 354290001Sglebius * See if the enclosed option is okay with that state. 355290001Sglebius */ 356290001Sglebius if (DO_NORMALLY(opt_st.flags) || DO_SECOND_TIME(opt_st.flags)) 357290001Sglebius (void)handle_opt(pOpts, &opt_st); 358290001Sglebius } 359290001Sglebius} 360290001Sglebius 361290001Sglebius/** 362290001Sglebius * Find the option descriptor by full name. 363290001Sglebius * 364290001Sglebius * @param opts option data 365290001Sglebius * @param opt_name name of option to look for 366290001Sglebius * @param state state about current option 367290001Sglebius * 368290001Sglebius * @return success status 369290001Sglebius */ 370290001SglebiusLOCAL tSuccess 371290001Sglebiusopt_find_long(tOptions * opts, char const * opt_name, tOptState * state) 372290001Sglebius{ 373290001Sglebius char name_buf[128]; 374290001Sglebius char * opt_arg; 375290001Sglebius int nm_len = parse_opt(&opt_name, &opt_arg, name_buf, sizeof(name_buf)); 376290001Sglebius 377290001Sglebius int idx = 0; 378290001Sglebius bool disable = false; 379290001Sglebius int ct; 380290001Sglebius 381290001Sglebius if (nm_len <= 1) { 382290001Sglebius if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0) 383290001Sglebius return FAILURE; 384290001Sglebius 385290001Sglebius fprintf(stderr, zInvalOptName, opts->pzProgName, opt_name); 386290001Sglebius (*opts->pUsageProc)(opts, EXIT_FAILURE); 387290001Sglebius /* NOTREACHED */ 388290001Sglebius _exit(EXIT_FAILURE); /* to be certain */ 389290001Sglebius } 390290001Sglebius 391290001Sglebius ct = opt_match_ct(opts, opt_name, nm_len, &idx, &disable); 392290001Sglebius 393290001Sglebius /* 394290001Sglebius * See if we found one match, no matches or multiple matches. 395290001Sglebius */ 396290001Sglebius switch (ct) { 397290001Sglebius case 1: return opt_set(opts, opt_arg, idx, disable, state); 398290001Sglebius case 0: return opt_unknown(opts, opt_name, opt_arg, state); 399290001Sglebius default: return opt_ambiguous(opts, opt_name, ct); 400290001Sglebius } 401290001Sglebius} 402290001Sglebius 403290001Sglebius 404290001Sglebius/** 405290001Sglebius * Find the short option descriptor for the current option 406290001Sglebius * 407290001Sglebius * @param pOpts option data 408290001Sglebius * @param optValue option flag character 409290001Sglebius * @param pOptState state about current option 410290001Sglebius */ 411290001SglebiusLOCAL tSuccess 412290001Sglebiusopt_find_short(tOptions * pOpts, uint_t optValue, tOptState * pOptState) 413290001Sglebius{ 414290001Sglebius tOptDesc * pRes = pOpts->pOptDesc; 415290001Sglebius int ct = pOpts->optCt; 416290001Sglebius 417290001Sglebius /* 418290001Sglebius * Search the option list 419290001Sglebius */ 420290001Sglebius do { 421290001Sglebius if (optValue != pRes->optValue) 422290001Sglebius continue; 423290001Sglebius 424290001Sglebius if (SKIP_OPT(pRes)) { 425290001Sglebius if ( (pRes->fOptState == (OPTST_OMITTED | OPTST_NO_INIT)) 426290001Sglebius && (pRes->pz_Name != NULL)) { 427290001Sglebius if ((pOpts->fOptSet & OPTPROC_ERRSTOP) == 0) 428290001Sglebius return FAILURE; 429290001Sglebius 430290001Sglebius fprintf(stderr, zDisabledErr, pOpts->pzProgPath, pRes->pz_Name); 431290001Sglebius if (pRes->pzText != NULL) 432290001Sglebius fprintf(stderr, SET_OFF_FMT, pRes->pzText); 433290001Sglebius fputc(NL, stderr); 434290001Sglebius (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); 435290001Sglebius /* NOTREACHED */ 436290001Sglebius _exit(EXIT_FAILURE); /* to be certain */ 437290001Sglebius } 438290001Sglebius goto short_opt_error; 439290001Sglebius } 440290001Sglebius 441290001Sglebius pOptState->pOD = pRes; 442290001Sglebius pOptState->optType = TOPT_SHORT; 443290001Sglebius return SUCCESS; 444290001Sglebius 445290001Sglebius } while (pRes++, --ct > 0); 446290001Sglebius 447290001Sglebius /* 448290001Sglebius * IF the character value is a digit 449290001Sglebius * AND there is a special number option ("-n") 450290001Sglebius * THEN the result is the "option" itself and the 451290001Sglebius * option is the specially marked "number" option. 452290001Sglebius */ 453290001Sglebius if ( IS_DEC_DIGIT_CHAR(optValue) 454290001Sglebius && (pOpts->specOptIdx.number_option != NO_EQUIVALENT) ) { 455290001Sglebius pOptState->pOD = \ 456290001Sglebius pRes = pOpts->pOptDesc + pOpts->specOptIdx.number_option; 457290001Sglebius (pOpts->pzCurOpt)--; 458290001Sglebius pOptState->optType = TOPT_SHORT; 459290001Sglebius return SUCCESS; 460290001Sglebius } 461290001Sglebius 462290001Sglebius short_opt_error: 463290001Sglebius 464290001Sglebius /* 465290001Sglebius * IF we are to stop on errors (the default, actually) 466290001Sglebius * THEN call the usage procedure. 467290001Sglebius */ 468290001Sglebius if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { 469290001Sglebius fprintf(stderr, zIllOptChr, pOpts->pzProgPath, optValue); 470290001Sglebius (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); 471290001Sglebius /* NOTREACHED */ 472290001Sglebius _exit(EXIT_FAILURE); /* to be certain */ 473290001Sglebius } 474290001Sglebius 475290001Sglebius return FAILURE; 476290001Sglebius} 477290001Sglebius 478290001Sglebius/** 479290001Sglebius * Process option with a required argument. Long options can either have a 480290001Sglebius * separate command line argument, or an argument attached by the '=' 481290001Sglebius * character. Figure out which. 482290001Sglebius * 483290001Sglebius * @param[in,out] opts the program option descriptor 484290001Sglebius * @param[in,out] o_st the option processing state 485290001Sglebius * @returns SUCCESS or FAILURE 486290001Sglebius */ 487290001Sglebiusstatic tSuccess 488290001Sglebiusget_opt_arg_must(tOptions * opts, tOptState * o_st) 489290001Sglebius{ 490290001Sglebius switch (o_st->optType) { 491290001Sglebius case TOPT_SHORT: 492290001Sglebius /* 493290001Sglebius * See if an arg string follows the flag character 494290001Sglebius */ 495290001Sglebius if (*++(opts->pzCurOpt) == NUL) 496290001Sglebius opts->pzCurOpt = opts->origArgVect[ opts->curOptIdx++ ]; 497290001Sglebius o_st->pzOptArg = opts->pzCurOpt; 498290001Sglebius break; 499290001Sglebius 500290001Sglebius case TOPT_LONG: 501290001Sglebius /* 502290001Sglebius * See if an arg string has already been assigned (glued on 503290001Sglebius * with an `=' character) 504290001Sglebius */ 505290001Sglebius if (o_st->pzOptArg == NULL) 506290001Sglebius o_st->pzOptArg = opts->origArgVect[ opts->curOptIdx++ ]; 507290001Sglebius break; 508290001Sglebius 509290001Sglebius default: 510290001Sglebius#ifdef DEBUG 511290001Sglebius fputs("AutoOpts lib error: option type not selected\n", stderr); 512290001Sglebius option_exits(EXIT_FAILURE); 513290001Sglebius#endif 514290001Sglebius 515290001Sglebius case TOPT_DEFAULT: 516290001Sglebius /* 517290001Sglebius * The option was selected by default. The current token is 518290001Sglebius * the option argument. 519290001Sglebius */ 520290001Sglebius break; 521290001Sglebius } 522290001Sglebius 523290001Sglebius /* 524290001Sglebius * Make sure we did not overflow the argument list. 525290001Sglebius */ 526290001Sglebius if (opts->curOptIdx > opts->origArgCt) { 527290001Sglebius fprintf(stderr, zMisArg, opts->pzProgPath, o_st->pOD->pz_Name); 528290001Sglebius return FAILURE; 529290001Sglebius } 530290001Sglebius 531290001Sglebius opts->pzCurOpt = NULL; /* next time advance to next arg */ 532290001Sglebius return SUCCESS; 533290001Sglebius} 534290001Sglebius 535290001Sglebius/** 536290001Sglebius * Process an option with an optional argument. For short options, it looks 537290001Sglebius * at the character after the option character, or it consumes the next full 538290001Sglebius * argument. For long options, it looks for an '=' character attachment to 539290001Sglebius * the long option name before deciding to take the next command line 540290001Sglebius * argument. 541290001Sglebius * 542290001Sglebius * @param pOpts the option descriptor 543290001Sglebius * @param o_st a structure for managing the current processing state 544290001Sglebius * @returns SUCCESS or does not return 545290001Sglebius */ 546290001Sglebiusstatic tSuccess 547290001Sglebiusget_opt_arg_may(tOptions * pOpts, tOptState * o_st) 548290001Sglebius{ 549290001Sglebius /* 550290001Sglebius * An option argument is optional. 551290001Sglebius */ 552290001Sglebius switch (o_st->optType) { 553290001Sglebius case TOPT_SHORT: 554290001Sglebius if (*++pOpts->pzCurOpt != NUL) 555290001Sglebius o_st->pzOptArg = pOpts->pzCurOpt; 556290001Sglebius else { 557290001Sglebius char * pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; 558290001Sglebius 559290001Sglebius /* 560290001Sglebius * BECAUSE it is optional, we must make sure 561290001Sglebius * we did not find another flag and that there 562290001Sglebius * is such an argument. 563290001Sglebius */ 564290001Sglebius if ((pzLA == NULL) || (*pzLA == '-')) 565290001Sglebius o_st->pzOptArg = NULL; 566290001Sglebius else { 567290001Sglebius pOpts->curOptIdx++; /* argument found */ 568290001Sglebius o_st->pzOptArg = pzLA; 569290001Sglebius } 570290001Sglebius } 571290001Sglebius break; 572290001Sglebius 573290001Sglebius case TOPT_LONG: 574290001Sglebius /* 575290001Sglebius * Look for an argument if we don't already have one (glued on 576290001Sglebius * with a `=' character) *AND* we are not in named argument mode 577290001Sglebius */ 578290001Sglebius if ( (o_st->pzOptArg == NULL) 579290001Sglebius && (! NAMED_OPTS(pOpts))) { 580290001Sglebius char * pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; 581290001Sglebius 582290001Sglebius /* 583290001Sglebius * BECAUSE it is optional, we must make sure 584290001Sglebius * we did not find another flag and that there 585290001Sglebius * is such an argument. 586290001Sglebius */ 587290001Sglebius if ((pzLA == NULL) || (*pzLA == '-')) 588290001Sglebius o_st->pzOptArg = NULL; 589290001Sglebius else { 590290001Sglebius pOpts->curOptIdx++; /* argument found */ 591290001Sglebius o_st->pzOptArg = pzLA; 592290001Sglebius } 593290001Sglebius } 594290001Sglebius break; 595290001Sglebius 596290001Sglebius default: 597290001Sglebius case TOPT_DEFAULT: 598290001Sglebius ao_bug(zbad_default_msg); 599290001Sglebius } 600290001Sglebius 601290001Sglebius /* 602290001Sglebius * After an option with an optional argument, we will 603290001Sglebius * *always* start with the next option because if there 604290001Sglebius * were any characters following the option name/flag, 605290001Sglebius * they would be interpreted as the argument. 606290001Sglebius */ 607290001Sglebius pOpts->pzCurOpt = NULL; 608290001Sglebius return SUCCESS; 609290001Sglebius} 610290001Sglebius 611290001Sglebius/** 612290001Sglebius * Process option that does not have an argument. 613290001Sglebius * 614290001Sglebius * @param[in,out] opts the program option descriptor 615290001Sglebius * @param[in,out] o_st the option processing state 616290001Sglebius * @returns SUCCESS or FAILURE 617290001Sglebius */ 618290001Sglebiusstatic tSuccess 619290001Sglebiusget_opt_arg_none(tOptions * pOpts, tOptState * o_st) 620290001Sglebius{ 621290001Sglebius /* 622290001Sglebius * No option argument. Make sure next time around we find 623290001Sglebius * the correct option flag character for short options 624290001Sglebius */ 625290001Sglebius if (o_st->optType == TOPT_SHORT) 626290001Sglebius (pOpts->pzCurOpt)++; 627290001Sglebius 628290001Sglebius /* 629290001Sglebius * It is a long option. Make sure there was no ``=xxx'' argument 630290001Sglebius */ 631290001Sglebius else if (o_st->pzOptArg != NULL) { 632290001Sglebius fprintf(stderr, zNoArg, pOpts->pzProgPath, o_st->pOD->pz_Name); 633290001Sglebius return FAILURE; 634290001Sglebius } 635290001Sglebius 636290001Sglebius /* 637290001Sglebius * It is a long option. Advance to next command line argument. 638290001Sglebius */ 639290001Sglebius else 640290001Sglebius pOpts->pzCurOpt = NULL; 641290001Sglebius return SUCCESS; 642290001Sglebius} 643290001Sglebius 644290001Sglebius/** 645290001Sglebius * Process option. Figure out whether or not to look for an option argument. 646290001Sglebius * 647290001Sglebius * @param[in,out] opts the program option descriptor 648290001Sglebius * @param[in,out] o_st the option processing state 649290001Sglebius * @returns SUCCESS or FAILURE 650290001Sglebius */ 651290001SglebiusLOCAL tSuccess 652290001Sglebiusget_opt_arg(tOptions * opts, tOptState * o_st) 653290001Sglebius{ 654290001Sglebius o_st->flags |= (o_st->pOD->fOptState & OPTST_PERSISTENT_MASK); 655290001Sglebius 656290001Sglebius /* 657290001Sglebius * Disabled options and options specified to not have arguments 658290001Sglebius * are handled with the "none" procedure. Otherwise, check the 659290001Sglebius * optional flag and call either the "may" or "must" function. 660290001Sglebius */ 661290001Sglebius if ( ((o_st->flags & OPTST_DISABLED) != 0) 662290001Sglebius || (OPTST_GET_ARGTYPE(o_st->flags) == OPARG_TYPE_NONE)) 663290001Sglebius return get_opt_arg_none(opts, o_st); 664290001Sglebius 665290001Sglebius if (o_st->flags & OPTST_ARG_OPTIONAL) 666290001Sglebius return get_opt_arg_may( opts, o_st); 667290001Sglebius 668290001Sglebius return get_opt_arg_must(opts, o_st); 669290001Sglebius} 670290001Sglebius 671290001Sglebius/** 672290001Sglebius * Find the option descriptor for the current option. 673290001Sglebius * 674290001Sglebius * @param[in,out] opts the program option descriptor 675290001Sglebius * @param[in,out] o_st the option processing state 676290001Sglebius * @returns SUCCESS or FAILURE 677290001Sglebius */ 678290001SglebiusLOCAL tSuccess 679290001Sglebiusfind_opt(tOptions * opts, tOptState * o_st) 680290001Sglebius{ 681290001Sglebius /* 682290001Sglebius * IF we are continuing a short option list (e.g. -xyz...) 683290001Sglebius * THEN continue a single flag option. 684290001Sglebius * OTHERWISE see if there is room to advance and then do so. 685290001Sglebius */ 686290001Sglebius if ((opts->pzCurOpt != NULL) && (*opts->pzCurOpt != NUL)) 687290001Sglebius return opt_find_short(opts, (uint8_t)*(opts->pzCurOpt), o_st); 688290001Sglebius 689290001Sglebius if (opts->curOptIdx >= opts->origArgCt) 690290001Sglebius return PROBLEM; /* NORMAL COMPLETION */ 691290001Sglebius 692290001Sglebius opts->pzCurOpt = opts->origArgVect[ opts->curOptIdx ]; 693290001Sglebius 694290001Sglebius /* 695290001Sglebius * IF all arguments must be named options, ... 696290001Sglebius */ 697290001Sglebius if (NAMED_OPTS(opts)) { 698290001Sglebius char * pz = opts->pzCurOpt; 699290001Sglebius int def; 700290001Sglebius tSuccess res; 701290001Sglebius uint16_t * def_opt; 702290001Sglebius 703290001Sglebius opts->curOptIdx++; 704290001Sglebius 705290001Sglebius if (*pz != '-') 706290001Sglebius return opt_find_long(opts, pz, o_st); 707290001Sglebius 708290001Sglebius /* 709290001Sglebius * The name is prefixed with one or more hyphens. Strip them off 710290001Sglebius * and disable the "default_opt" setting. Use heavy recasting to 711290001Sglebius * strip off the "const" quality of the "default_opt" field. 712290001Sglebius */ 713290001Sglebius while (*(++pz) == '-') ; 714290001Sglebius def_opt = VOIDP(&(opts->specOptIdx.default_opt)); 715290001Sglebius def = *def_opt; 716290001Sglebius *def_opt = NO_EQUIVALENT; 717290001Sglebius res = opt_find_long(opts, pz, o_st); 718290001Sglebius *def_opt = (uint16_t)def; 719290001Sglebius return res; 720290001Sglebius } 721290001Sglebius 722290001Sglebius /* 723290001Sglebius * Note the kind of flag/option marker 724290001Sglebius */ 725290001Sglebius if (*((opts->pzCurOpt)++) != '-') 726290001Sglebius return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */ 727290001Sglebius 728290001Sglebius /* 729290001Sglebius * Special hack for a hyphen by itself 730290001Sglebius */ 731290001Sglebius if (*(opts->pzCurOpt) == NUL) 732290001Sglebius return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */ 733290001Sglebius 734290001Sglebius /* 735290001Sglebius * The current argument is to be processed as an option argument 736290001Sglebius */ 737290001Sglebius opts->curOptIdx++; 738290001Sglebius 739290001Sglebius /* 740290001Sglebius * We have an option marker. 741290001Sglebius * Test the next character for long option indication 742290001Sglebius */ 743290001Sglebius if (opts->pzCurOpt[0] == '-') { 744290001Sglebius if (*++(opts->pzCurOpt) == NUL) 745290001Sglebius /* 746290001Sglebius * NORMAL COMPLETION - NOT this arg, but rest are operands 747290001Sglebius */ 748290001Sglebius return PROBLEM; 749290001Sglebius 750290001Sglebius /* 751290001Sglebius * We do not allow the hyphen to be used as a flag value. 752290001Sglebius * Therefore, if long options are not to be accepted, we punt. 753290001Sglebius */ 754290001Sglebius if ((opts->fOptSet & OPTPROC_LONGOPT) == 0) { 755290001Sglebius fprintf(stderr, zIllOptStr, opts->pzProgPath, opts->pzCurOpt-2); 756290001Sglebius return FAILURE; 757290001Sglebius } 758290001Sglebius 759290001Sglebius return opt_find_long(opts, opts->pzCurOpt, o_st); 760290001Sglebius } 761290001Sglebius 762290001Sglebius /* 763290001Sglebius * If short options are not allowed, then do long 764290001Sglebius * option processing. Otherwise the character must be a 765290001Sglebius * short (i.e. single character) option. 766290001Sglebius */ 767290001Sglebius if ((opts->fOptSet & OPTPROC_SHORTOPT) != 0) 768290001Sglebius return opt_find_short(opts, (uint8_t)*(opts->pzCurOpt), o_st); 769290001Sglebius 770290001Sglebius return opt_find_long(opts, opts->pzCurOpt, o_st); 771290001Sglebius} 772290001Sglebius 773290001Sglebius/** @} 774290001Sglebius * 775290001Sglebius * Local Variables: 776290001Sglebius * mode: C 777290001Sglebius * c-file-style: "stroustrup" 778290001Sglebius * indent-tabs-mode: nil 779290001Sglebius * End: 780290001Sglebius * end of autoopts/find.c */ 781