1275970Scy/** 2275970Scy * @file check.c 3275970Scy * 4275970Scy * @brief Hunt for options in the option descriptor list 5275970Scy * 6275970Scy * This file contains the routines that deal with processing quoted strings 7275970Scy * into an internal format. 8275970Scy * 9275970Scy * @addtogroup autoopts 10275970Scy * @{ 11275970Scy */ 12275970Scy/* 13275970Scy * This file is part of AutoOpts, a companion to AutoGen. 14275970Scy * AutoOpts is free software. 15285169Scy * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 16275970Scy * 17275970Scy * AutoOpts is available under any one of two licenses. The license 18275970Scy * in use must be one of these two and the choice is under the control 19275970Scy * of the user of the license. 20275970Scy * 21275970Scy * The GNU Lesser General Public License, version 3 or later 22275970Scy * See the files "COPYING.lgplv3" and "COPYING.gplv3" 23275970Scy * 24275970Scy * The Modified Berkeley Software Distribution License 25275970Scy * See the file "COPYING.mbsd" 26275970Scy * 27275970Scy * These files have the following sha256 sums: 28275970Scy * 29275970Scy * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 30275970Scy * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 31275970Scy * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 32275970Scy */ 33275970Scy 34275970Scy/* = = = START-STATIC-FORWARD = = = */ 35275970Scystatic int 36275970Scyparse_opt(char const ** nm_pp, char ** arg_pp, char * buf, size_t bufsz); 37275970Scy 38275970Scystatic void 39275970Scyopt_ambiguities(tOptions * opts, char const * name, int nm_len); 40275970Scy 41275970Scystatic int 42275970Scyopt_match_ct(tOptions * opts, char const * name, int nm_len, 43275970Scy int * ixp, bool * disable); 44275970Scy 45275970Scystatic tSuccess 46275970Scyopt_set(tOptions * opts, char * arg, int idx, bool disable, tOptState * st); 47275970Scy 48275970Scystatic tSuccess 49275970Scyopt_unknown(tOptions * opts, char const * name, char * arg, tOptState * st); 50275970Scy 51275970Scystatic tSuccess 52275970Scyopt_ambiguous(tOptions * opts, char const * name, int match_ct); 53275970Scy 54275970Scystatic tSuccess 55275970Scyget_opt_arg_must(tOptions * opts, tOptState * o_st); 56275970Scy 57275970Scystatic tSuccess 58275970Scyget_opt_arg_may(tOptions * pOpts, tOptState * o_st); 59275970Scy 60275970Scystatic tSuccess 61285169Scyget_opt_arg_none(tOptions * pOpts, tOptState * o_st); 62275970Scy/* = = = END-STATIC-FORWARD = = = */ 63275970Scy 64275970Scy/** 65275970Scy * find the name and name length we are looking for 66275970Scy */ 67275970Scystatic int 68275970Scyparse_opt(char const ** nm_pp, char ** arg_pp, char * buf, size_t bufsz) 69275970Scy{ 70275970Scy int res = 0; 71275970Scy char const * p = *nm_pp; 72275970Scy *arg_pp = NULL; 73275970Scy 74275970Scy for (;;) { 75275970Scy switch (*(p++)) { 76275970Scy case NUL: return res; 77275970Scy 78275970Scy case '=': 79275970Scy memcpy(buf, *nm_pp, (size_t)res); 80275970Scy 81275970Scy buf[res] = NUL; 82275970Scy *nm_pp = buf; 83294554Sdelphij *arg_pp = VOIDP(p); 84275970Scy return res; 85275970Scy 86275970Scy default: 87275970Scy if (++res >= (int)bufsz) 88275970Scy return -1; 89275970Scy } 90275970Scy } 91275970Scy} 92275970Scy 93275970Scy/** 94275970Scy * print out the options that match the given name. 95275970Scy * 96275970Scy * @param pOpts option data 97275970Scy * @param opt_name name of option to look for 98275970Scy */ 99275970Scystatic void 100275970Scyopt_ambiguities(tOptions * opts, char const * name, int nm_len) 101275970Scy{ 102275970Scy char const * const hyph = 103275970Scy NAMED_OPTS(opts) ? "" : LONG_OPT_MARKER; 104275970Scy 105275970Scy tOptDesc * pOD = opts->pOptDesc; 106275970Scy int idx = 0; 107275970Scy 108275970Scy fputs(zambig_list_msg, stderr); 109275970Scy do { 110275970Scy if (pOD->pz_Name == NULL) 111275970Scy continue; /* doc option */ 112275970Scy 113275970Scy if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0) 114275970Scy fprintf(stderr, zambig_file, hyph, pOD->pz_Name); 115275970Scy 116275970Scy else if ( (pOD->pz_DisableName != NULL) 117275970Scy && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0) 118275970Scy ) 119275970Scy fprintf(stderr, zambig_file, hyph, pOD->pz_DisableName); 120275970Scy } while (pOD++, (++idx < opts->optCt)); 121275970Scy} 122275970Scy 123275970Scy/** 124275970Scy * Determine the number of options that match the name 125275970Scy * 126275970Scy * @param pOpts option data 127275970Scy * @param opt_name name of option to look for 128275970Scy * @param nm_len length of provided name 129275970Scy * @param index pointer to int for option index 130275970Scy * @param disable pointer to bool to mark disabled option 131275970Scy * @return count of options that match 132275970Scy */ 133275970Scystatic int 134275970Scyopt_match_ct(tOptions * opts, char const * name, int nm_len, 135275970Scy int * ixp, bool * disable) 136275970Scy{ 137275970Scy int matchCt = 0; 138275970Scy int idx = 0; 139275970Scy int idxLim = opts->optCt; 140275970Scy tOptDesc * pOD = opts->pOptDesc; 141275970Scy 142275970Scy do { 143275970Scy /* 144275970Scy * If option disabled or a doc option, skip to next 145275970Scy */ 146275970Scy if (pOD->pz_Name == NULL) 147275970Scy continue; 148275970Scy 149275970Scy if ( SKIP_OPT(pOD) 150275970Scy && (pOD->fOptState != (OPTST_OMITTED | OPTST_NO_INIT))) 151275970Scy continue; 152275970Scy 153275970Scy if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0) { 154275970Scy /* 155275970Scy * IF we have a complete match 156275970Scy * THEN it takes priority over any already located partial 157275970Scy */ 158275970Scy if (pOD->pz_Name[ nm_len ] == NUL) { 159275970Scy *ixp = idx; 160275970Scy return 1; 161275970Scy } 162275970Scy } 163275970Scy 164275970Scy /* 165275970Scy * IF there is a disable name 166275970Scy * *AND* the option name matches the disable name 167275970Scy * THEN ... 168275970Scy */ 169275970Scy else if ( (pOD->pz_DisableName != NULL) 170275970Scy && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0) 171275970Scy ) { 172275970Scy *disable = true; 173275970Scy 174275970Scy /* 175275970Scy * IF we have a complete match 176275970Scy * THEN it takes priority over any already located partial 177275970Scy */ 178275970Scy if (pOD->pz_DisableName[ nm_len ] == NUL) { 179275970Scy *ixp = idx; 180275970Scy return 1; 181275970Scy } 182275970Scy } 183275970Scy 184275970Scy else 185275970Scy continue; /* does not match any option */ 186275970Scy 187275970Scy /* 188275970Scy * We found a full or partial match, either regular or disabling. 189275970Scy * Remember the index for later. 190275970Scy */ 191275970Scy *ixp = idx; 192275970Scy ++matchCt; 193275970Scy 194275970Scy } while (pOD++, (++idx < idxLim)); 195275970Scy 196275970Scy return matchCt; 197275970Scy} 198275970Scy 199275970Scy/** 200275970Scy * Set the option to the indicated option number. 201275970Scy * 202275970Scy * @param opts option data 203275970Scy * @param arg option argument (if glued to name) 204275970Scy * @param idx option index 205275970Scy * @param disable mark disabled option 206275970Scy * @param st state about current option 207275970Scy */ 208275970Scystatic tSuccess 209275970Scyopt_set(tOptions * opts, char * arg, int idx, bool disable, tOptState * st) 210275970Scy{ 211275970Scy tOptDesc * pOD = opts->pOptDesc + idx; 212275970Scy 213275970Scy if (SKIP_OPT(pOD)) { 214275970Scy if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0) 215275970Scy return FAILURE; 216275970Scy 217275970Scy fprintf(stderr, zDisabledErr, opts->pzProgName, pOD->pz_Name); 218275970Scy if (pOD->pzText != NULL) 219275970Scy fprintf(stderr, SET_OFF_FMT, pOD->pzText); 220275970Scy fputc(NL, stderr); 221275970Scy (*opts->pUsageProc)(opts, EXIT_FAILURE); 222275970Scy /* NOTREACHED */ 223275970Scy _exit(EXIT_FAILURE); /* to be certain */ 224275970Scy } 225275970Scy 226275970Scy /* 227275970Scy * IF we found a disablement name, 228275970Scy * THEN set the bit in the callers' flag word 229275970Scy */ 230275970Scy if (disable) 231275970Scy st->flags |= OPTST_DISABLED; 232275970Scy 233275970Scy st->pOD = pOD; 234275970Scy st->pzOptArg = arg; 235275970Scy st->optType = TOPT_LONG; 236275970Scy 237275970Scy return SUCCESS; 238275970Scy} 239275970Scy 240275970Scy/** 241275970Scy * An option was not found. Check for default option and set it 242275970Scy * if there is one. Otherwise, handle the error. 243275970Scy * 244275970Scy * @param opts option data 245275970Scy * @param name name of option to look for 246275970Scy * @param arg option argument 247275970Scy * @param st state about current option 248275970Scy * 249275970Scy * @return success status 250275970Scy */ 251275970Scystatic tSuccess 252275970Scyopt_unknown(tOptions * opts, char const * name, char * arg, tOptState * st) 253275970Scy{ 254275970Scy /* 255275970Scy * IF there is no equal sign 256275970Scy * *AND* we are using named arguments 257275970Scy * *AND* there is a default named option, 258275970Scy * THEN return that option. 259275970Scy */ 260275970Scy if ( (arg == NULL) 261275970Scy && NAMED_OPTS(opts) 262275970Scy && (opts->specOptIdx.default_opt != NO_EQUIVALENT)) { 263275970Scy 264275970Scy st->pOD = opts->pOptDesc + opts->specOptIdx.default_opt; 265275970Scy st->pzOptArg = name; 266275970Scy st->optType = TOPT_DEFAULT; 267275970Scy return SUCCESS; 268275970Scy } 269275970Scy 270275970Scy if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) { 271275970Scy fprintf(stderr, zIllOptStr, opts->pzProgPath, name); 272275970Scy (*opts->pUsageProc)(opts, EXIT_FAILURE); 273275970Scy /* NOTREACHED */ 274275970Scy _exit(EXIT_FAILURE); /* to be certain */ 275275970Scy } 276275970Scy 277275970Scy return FAILURE; 278275970Scy} 279275970Scy 280275970Scy/** 281275970Scy * Several options match the provided name. 282275970Scy * 283275970Scy * @param opts option data 284275970Scy * @param name name of option to look for 285275970Scy * @param match_ct number of matching options 286275970Scy * 287275970Scy * @return success status (always FAILURE, if it returns) 288275970Scy */ 289275970Scystatic tSuccess 290275970Scyopt_ambiguous(tOptions * opts, char const * name, int match_ct) 291275970Scy{ 292275970Scy if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) { 293275970Scy fprintf(stderr, zambig_opt_fmt, opts->pzProgPath, name, match_ct); 294275970Scy if (match_ct <= 4) 295275970Scy opt_ambiguities(opts, name, (int)strlen(name)); 296275970Scy (*opts->pUsageProc)(opts, EXIT_FAILURE); 297275970Scy /* NOTREACHED */ 298275970Scy _exit(EXIT_FAILURE); /* to be certain */ 299275970Scy } 300275970Scy return FAILURE; 301275970Scy} 302275970Scy 303275970Scy/*=export_func optionVendorOption 304275970Scy * private: 305275970Scy * 306275970Scy * what: Process a vendor option 307275970Scy * arg: + tOptions * + pOpts + program options descriptor + 308275970Scy * arg: + tOptDesc * + pOptDesc + the descriptor for this arg + 309275970Scy * 310275970Scy * doc: 311275970Scy * For POSIX specified utilities, the options are constrained to the options, 312275970Scy * @xref{config attributes, Program Configuration}. AutoOpts clients should 313275970Scy * never specify this directly. It gets referenced when the option 314275970Scy * definitions contain a "vendor-opt" attribute. 315275970Scy=*/ 316275970Scyvoid 317275970ScyoptionVendorOption(tOptions * pOpts, tOptDesc * pOD) 318275970Scy{ 319275970Scy tOptState opt_st = OPTSTATE_INITIALIZER(PRESET); 320275970Scy char const * vopt_str = pOD->optArg.argString; 321275970Scy 322275970Scy if (pOpts <= OPTPROC_EMIT_LIMIT) 323275970Scy return; 324275970Scy 325275970Scy if ((pOD->fOptState & OPTST_RESET) != 0) 326275970Scy return; 327275970Scy 328275970Scy if ((pOD->fOptState & OPTPROC_IMMEDIATE) == 0) 329275970Scy opt_st.flags = OPTST_DEFINED; 330275970Scy 331275970Scy if ( ((pOpts->fOptSet & OPTPROC_VENDOR_OPT) == 0) 332275970Scy || ! SUCCESSFUL(opt_find_long(pOpts, vopt_str, &opt_st)) 333275970Scy || ! SUCCESSFUL(get_opt_arg(pOpts, &opt_st)) ) 334275970Scy { 335275970Scy fprintf(stderr, zIllVendOptStr, pOpts->pzProgName, vopt_str); 336275970Scy (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); 337275970Scy /* NOTREACHED */ 338275970Scy _exit(EXIT_FAILURE); /* to be certain */ 339275970Scy } 340275970Scy 341275970Scy /* 342275970Scy * See if we are in immediate handling state. 343275970Scy */ 344275970Scy if (pOpts->fOptSet & OPTPROC_IMMEDIATE) { 345275970Scy /* 346275970Scy * See if the enclosed option is okay with that state. 347275970Scy */ 348275970Scy if (DO_IMMEDIATELY(opt_st.flags)) 349275970Scy (void)handle_opt(pOpts, &opt_st); 350275970Scy 351275970Scy } else { 352275970Scy /* 353275970Scy * non-immediate direction. 354275970Scy * See if the enclosed option is okay with that state. 355275970Scy */ 356275970Scy if (DO_NORMALLY(opt_st.flags) || DO_SECOND_TIME(opt_st.flags)) 357275970Scy (void)handle_opt(pOpts, &opt_st); 358275970Scy } 359275970Scy} 360275970Scy 361275970Scy/** 362275970Scy * Find the option descriptor by full name. 363275970Scy * 364275970Scy * @param opts option data 365275970Scy * @param opt_name name of option to look for 366275970Scy * @param state state about current option 367275970Scy * 368275970Scy * @return success status 369275970Scy */ 370275970ScyLOCAL tSuccess 371275970Scyopt_find_long(tOptions * opts, char const * opt_name, tOptState * state) 372275970Scy{ 373275970Scy char name_buf[128]; 374275970Scy char * opt_arg; 375275970Scy int nm_len = parse_opt(&opt_name, &opt_arg, name_buf, sizeof(name_buf)); 376275970Scy 377275970Scy int idx = 0; 378275970Scy bool disable = false; 379275970Scy int ct; 380275970Scy 381275970Scy if (nm_len <= 1) { 382275970Scy if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0) 383275970Scy return FAILURE; 384275970Scy 385275970Scy fprintf(stderr, zInvalOptName, opts->pzProgName, opt_name); 386275970Scy (*opts->pUsageProc)(opts, EXIT_FAILURE); 387275970Scy /* NOTREACHED */ 388275970Scy _exit(EXIT_FAILURE); /* to be certain */ 389275970Scy } 390275970Scy 391275970Scy ct = opt_match_ct(opts, opt_name, nm_len, &idx, &disable); 392275970Scy 393275970Scy /* 394275970Scy * See if we found one match, no matches or multiple matches. 395275970Scy */ 396275970Scy switch (ct) { 397275970Scy case 1: return opt_set(opts, opt_arg, idx, disable, state); 398275970Scy case 0: return opt_unknown(opts, opt_name, opt_arg, state); 399275970Scy default: return opt_ambiguous(opts, opt_name, ct); 400275970Scy } 401275970Scy} 402275970Scy 403275970Scy 404275970Scy/** 405275970Scy * Find the short option descriptor for the current option 406275970Scy * 407275970Scy * @param pOpts option data 408275970Scy * @param optValue option flag character 409275970Scy * @param pOptState state about current option 410275970Scy */ 411275970ScyLOCAL tSuccess 412285169Scyopt_find_short(tOptions * pOpts, uint_t optValue, tOptState * pOptState) 413275970Scy{ 414285169Scy tOptDesc * pRes = pOpts->pOptDesc; 415275970Scy int ct = pOpts->optCt; 416275970Scy 417275970Scy /* 418275970Scy * Search the option list 419275970Scy */ 420275970Scy do { 421275970Scy if (optValue != pRes->optValue) 422275970Scy continue; 423275970Scy 424275970Scy if (SKIP_OPT(pRes)) { 425275970Scy if ( (pRes->fOptState == (OPTST_OMITTED | OPTST_NO_INIT)) 426275970Scy && (pRes->pz_Name != NULL)) { 427275970Scy if ((pOpts->fOptSet & OPTPROC_ERRSTOP) == 0) 428275970Scy return FAILURE; 429275970Scy 430275970Scy fprintf(stderr, zDisabledErr, pOpts->pzProgPath, pRes->pz_Name); 431275970Scy if (pRes->pzText != NULL) 432275970Scy fprintf(stderr, SET_OFF_FMT, pRes->pzText); 433275970Scy fputc(NL, stderr); 434275970Scy (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); 435275970Scy /* NOTREACHED */ 436275970Scy _exit(EXIT_FAILURE); /* to be certain */ 437275970Scy } 438275970Scy goto short_opt_error; 439275970Scy } 440275970Scy 441275970Scy pOptState->pOD = pRes; 442275970Scy pOptState->optType = TOPT_SHORT; 443275970Scy return SUCCESS; 444275970Scy 445275970Scy } while (pRes++, --ct > 0); 446275970Scy 447275970Scy /* 448275970Scy * IF the character value is a digit 449275970Scy * AND there is a special number option ("-n") 450275970Scy * THEN the result is the "option" itself and the 451275970Scy * option is the specially marked "number" option. 452275970Scy */ 453275970Scy if ( IS_DEC_DIGIT_CHAR(optValue) 454275970Scy && (pOpts->specOptIdx.number_option != NO_EQUIVALENT) ) { 455275970Scy pOptState->pOD = \ 456275970Scy pRes = pOpts->pOptDesc + pOpts->specOptIdx.number_option; 457275970Scy (pOpts->pzCurOpt)--; 458275970Scy pOptState->optType = TOPT_SHORT; 459275970Scy return SUCCESS; 460275970Scy } 461275970Scy 462275970Scy short_opt_error: 463275970Scy 464275970Scy /* 465275970Scy * IF we are to stop on errors (the default, actually) 466275970Scy * THEN call the usage procedure. 467275970Scy */ 468275970Scy if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { 469275970Scy fprintf(stderr, zIllOptChr, pOpts->pzProgPath, optValue); 470275970Scy (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); 471275970Scy /* NOTREACHED */ 472275970Scy _exit(EXIT_FAILURE); /* to be certain */ 473275970Scy } 474275970Scy 475275970Scy return FAILURE; 476275970Scy} 477275970Scy 478275970Scy/** 479275970Scy * Process option with a required argument. Long options can either have a 480275970Scy * separate command line argument, or an argument attached by the '=' 481275970Scy * character. Figure out which. 482275970Scy * 483275970Scy * @param[in,out] opts the program option descriptor 484275970Scy * @param[in,out] o_st the option processing state 485275970Scy * @returns SUCCESS or FAILURE 486275970Scy */ 487275970Scystatic tSuccess 488275970Scyget_opt_arg_must(tOptions * opts, tOptState * o_st) 489275970Scy{ 490275970Scy switch (o_st->optType) { 491275970Scy case TOPT_SHORT: 492275970Scy /* 493275970Scy * See if an arg string follows the flag character 494275970Scy */ 495275970Scy if (*++(opts->pzCurOpt) == NUL) 496275970Scy opts->pzCurOpt = opts->origArgVect[ opts->curOptIdx++ ]; 497275970Scy o_st->pzOptArg = opts->pzCurOpt; 498275970Scy break; 499275970Scy 500275970Scy case TOPT_LONG: 501275970Scy /* 502275970Scy * See if an arg string has already been assigned (glued on 503275970Scy * with an `=' character) 504275970Scy */ 505275970Scy if (o_st->pzOptArg == NULL) 506275970Scy o_st->pzOptArg = opts->origArgVect[ opts->curOptIdx++ ]; 507275970Scy break; 508275970Scy 509275970Scy default: 510275970Scy#ifdef DEBUG 511275970Scy fputs("AutoOpts lib error: option type not selected\n", stderr); 512275970Scy option_exits(EXIT_FAILURE); 513275970Scy#endif 514275970Scy 515275970Scy case TOPT_DEFAULT: 516275970Scy /* 517275970Scy * The option was selected by default. The current token is 518275970Scy * the option argument. 519275970Scy */ 520275970Scy break; 521275970Scy } 522275970Scy 523275970Scy /* 524275970Scy * Make sure we did not overflow the argument list. 525275970Scy */ 526275970Scy if (opts->curOptIdx > opts->origArgCt) { 527275970Scy fprintf(stderr, zMisArg, opts->pzProgPath, o_st->pOD->pz_Name); 528275970Scy return FAILURE; 529275970Scy } 530275970Scy 531275970Scy opts->pzCurOpt = NULL; /* next time advance to next arg */ 532275970Scy return SUCCESS; 533275970Scy} 534275970Scy 535275970Scy/** 536275970Scy * Process an option with an optional argument. For short options, it looks 537275970Scy * at the character after the option character, or it consumes the next full 538275970Scy * argument. For long options, it looks for an '=' character attachment to 539275970Scy * the long option name before deciding to take the next command line 540275970Scy * argument. 541275970Scy * 542275970Scy * @param pOpts the option descriptor 543275970Scy * @param o_st a structure for managing the current processing state 544275970Scy * @returns SUCCESS or does not return 545275970Scy */ 546275970Scystatic tSuccess 547275970Scyget_opt_arg_may(tOptions * pOpts, tOptState * o_st) 548275970Scy{ 549275970Scy /* 550275970Scy * An option argument is optional. 551275970Scy */ 552275970Scy switch (o_st->optType) { 553275970Scy case TOPT_SHORT: 554275970Scy if (*++pOpts->pzCurOpt != NUL) 555275970Scy o_st->pzOptArg = pOpts->pzCurOpt; 556275970Scy else { 557285169Scy char * pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; 558275970Scy 559275970Scy /* 560275970Scy * BECAUSE it is optional, we must make sure 561275970Scy * we did not find another flag and that there 562275970Scy * is such an argument. 563275970Scy */ 564275970Scy if ((pzLA == NULL) || (*pzLA == '-')) 565275970Scy o_st->pzOptArg = NULL; 566275970Scy else { 567275970Scy pOpts->curOptIdx++; /* argument found */ 568275970Scy o_st->pzOptArg = pzLA; 569275970Scy } 570275970Scy } 571275970Scy break; 572275970Scy 573275970Scy case TOPT_LONG: 574275970Scy /* 575275970Scy * Look for an argument if we don't already have one (glued on 576275970Scy * with a `=' character) *AND* we are not in named argument mode 577275970Scy */ 578275970Scy if ( (o_st->pzOptArg == NULL) 579275970Scy && (! NAMED_OPTS(pOpts))) { 580285169Scy char * pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; 581275970Scy 582275970Scy /* 583275970Scy * BECAUSE it is optional, we must make sure 584275970Scy * we did not find another flag and that there 585275970Scy * is such an argument. 586275970Scy */ 587275970Scy if ((pzLA == NULL) || (*pzLA == '-')) 588275970Scy o_st->pzOptArg = NULL; 589275970Scy else { 590275970Scy pOpts->curOptIdx++; /* argument found */ 591275970Scy o_st->pzOptArg = pzLA; 592275970Scy } 593275970Scy } 594275970Scy break; 595275970Scy 596275970Scy default: 597275970Scy case TOPT_DEFAULT: 598275970Scy ao_bug(zbad_default_msg); 599275970Scy } 600275970Scy 601275970Scy /* 602275970Scy * After an option with an optional argument, we will 603275970Scy * *always* start with the next option because if there 604275970Scy * were any characters following the option name/flag, 605275970Scy * they would be interpreted as the argument. 606275970Scy */ 607275970Scy pOpts->pzCurOpt = NULL; 608275970Scy return SUCCESS; 609275970Scy} 610275970Scy 611275970Scy/** 612275970Scy * Process option that does not have an argument. 613275970Scy * 614275970Scy * @param[in,out] opts the program option descriptor 615275970Scy * @param[in,out] o_st the option processing state 616275970Scy * @returns SUCCESS or FAILURE 617275970Scy */ 618275970Scystatic tSuccess 619285169Scyget_opt_arg_none(tOptions * pOpts, tOptState * o_st) 620275970Scy{ 621275970Scy /* 622275970Scy * No option argument. Make sure next time around we find 623275970Scy * the correct option flag character for short options 624275970Scy */ 625275970Scy if (o_st->optType == TOPT_SHORT) 626275970Scy (pOpts->pzCurOpt)++; 627275970Scy 628275970Scy /* 629275970Scy * It is a long option. Make sure there was no ``=xxx'' argument 630275970Scy */ 631275970Scy else if (o_st->pzOptArg != NULL) { 632275970Scy fprintf(stderr, zNoArg, pOpts->pzProgPath, o_st->pOD->pz_Name); 633275970Scy return FAILURE; 634275970Scy } 635275970Scy 636275970Scy /* 637275970Scy * It is a long option. Advance to next command line argument. 638275970Scy */ 639275970Scy else 640275970Scy pOpts->pzCurOpt = NULL; 641275970Scy return SUCCESS; 642275970Scy} 643275970Scy 644275970Scy/** 645275970Scy * Process option. Figure out whether or not to look for an option argument. 646275970Scy * 647275970Scy * @param[in,out] opts the program option descriptor 648275970Scy * @param[in,out] o_st the option processing state 649275970Scy * @returns SUCCESS or FAILURE 650275970Scy */ 651275970ScyLOCAL tSuccess 652275970Scyget_opt_arg(tOptions * opts, tOptState * o_st) 653275970Scy{ 654275970Scy o_st->flags |= (o_st->pOD->fOptState & OPTST_PERSISTENT_MASK); 655275970Scy 656275970Scy /* 657275970Scy * Disabled options and options specified to not have arguments 658275970Scy * are handled with the "none" procedure. Otherwise, check the 659275970Scy * optional flag and call either the "may" or "must" function. 660275970Scy */ 661275970Scy if ( ((o_st->flags & OPTST_DISABLED) != 0) 662275970Scy || (OPTST_GET_ARGTYPE(o_st->flags) == OPARG_TYPE_NONE)) 663275970Scy return get_opt_arg_none(opts, o_st); 664275970Scy 665275970Scy if (o_st->flags & OPTST_ARG_OPTIONAL) 666275970Scy return get_opt_arg_may( opts, o_st); 667275970Scy 668275970Scy return get_opt_arg_must(opts, o_st); 669275970Scy} 670275970Scy 671275970Scy/** 672275970Scy * Find the option descriptor for the current option. 673275970Scy * 674275970Scy * @param[in,out] opts the program option descriptor 675275970Scy * @param[in,out] o_st the option processing state 676275970Scy * @returns SUCCESS or FAILURE 677275970Scy */ 678275970ScyLOCAL tSuccess 679275970Scyfind_opt(tOptions * opts, tOptState * o_st) 680275970Scy{ 681275970Scy /* 682275970Scy * IF we are continuing a short option list (e.g. -xyz...) 683275970Scy * THEN continue a single flag option. 684275970Scy * OTHERWISE see if there is room to advance and then do so. 685275970Scy */ 686275970Scy if ((opts->pzCurOpt != NULL) && (*opts->pzCurOpt != NUL)) 687275970Scy return opt_find_short(opts, (uint8_t)*(opts->pzCurOpt), o_st); 688275970Scy 689275970Scy if (opts->curOptIdx >= opts->origArgCt) 690275970Scy return PROBLEM; /* NORMAL COMPLETION */ 691275970Scy 692275970Scy opts->pzCurOpt = opts->origArgVect[ opts->curOptIdx ]; 693275970Scy 694275970Scy /* 695275970Scy * IF all arguments must be named options, ... 696275970Scy */ 697275970Scy if (NAMED_OPTS(opts)) { 698275970Scy char * pz = opts->pzCurOpt; 699275970Scy int def; 700275970Scy tSuccess res; 701275970Scy uint16_t * def_opt; 702275970Scy 703275970Scy opts->curOptIdx++; 704275970Scy 705275970Scy if (*pz != '-') 706275970Scy return opt_find_long(opts, pz, o_st); 707275970Scy 708275970Scy /* 709275970Scy * The name is prefixed with one or more hyphens. Strip them off 710275970Scy * and disable the "default_opt" setting. Use heavy recasting to 711275970Scy * strip off the "const" quality of the "default_opt" field. 712275970Scy */ 713275970Scy while (*(++pz) == '-') ; 714285169Scy def_opt = VOIDP(&(opts->specOptIdx.default_opt)); 715275970Scy def = *def_opt; 716275970Scy *def_opt = NO_EQUIVALENT; 717275970Scy res = opt_find_long(opts, pz, o_st); 718275970Scy *def_opt = (uint16_t)def; 719275970Scy return res; 720275970Scy } 721275970Scy 722275970Scy /* 723275970Scy * Note the kind of flag/option marker 724275970Scy */ 725275970Scy if (*((opts->pzCurOpt)++) != '-') 726275970Scy return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */ 727275970Scy 728275970Scy /* 729275970Scy * Special hack for a hyphen by itself 730275970Scy */ 731275970Scy if (*(opts->pzCurOpt) == NUL) 732275970Scy return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */ 733275970Scy 734275970Scy /* 735275970Scy * The current argument is to be processed as an option argument 736275970Scy */ 737275970Scy opts->curOptIdx++; 738275970Scy 739275970Scy /* 740275970Scy * We have an option marker. 741275970Scy * Test the next character for long option indication 742275970Scy */ 743275970Scy if (opts->pzCurOpt[0] == '-') { 744275970Scy if (*++(opts->pzCurOpt) == NUL) 745275970Scy /* 746275970Scy * NORMAL COMPLETION - NOT this arg, but rest are operands 747275970Scy */ 748275970Scy return PROBLEM; 749275970Scy 750275970Scy /* 751275970Scy * We do not allow the hyphen to be used as a flag value. 752275970Scy * Therefore, if long options are not to be accepted, we punt. 753275970Scy */ 754275970Scy if ((opts->fOptSet & OPTPROC_LONGOPT) == 0) { 755275970Scy fprintf(stderr, zIllOptStr, opts->pzProgPath, opts->pzCurOpt-2); 756275970Scy return FAILURE; 757275970Scy } 758275970Scy 759275970Scy return opt_find_long(opts, opts->pzCurOpt, o_st); 760275970Scy } 761275970Scy 762275970Scy /* 763275970Scy * If short options are not allowed, then do long 764275970Scy * option processing. Otherwise the character must be a 765275970Scy * short (i.e. single character) option. 766275970Scy */ 767275970Scy if ((opts->fOptSet & OPTPROC_SHORTOPT) != 0) 768275970Scy return opt_find_short(opts, (uint8_t)*(opts->pzCurOpt), o_st); 769275970Scy 770275970Scy return opt_find_long(opts, opts->pzCurOpt, o_st); 771275970Scy} 772275970Scy 773275970Scy/** @} 774275970Scy * 775275970Scy * Local Variables: 776275970Scy * mode: C 777275970Scy * c-file-style: "stroustrup" 778275970Scy * indent-tabs-mode: nil 779275970Scy * End: 780275970Scy * end of autoopts/find.c */ 781