1/* $NetBSD: autoopts.c,v 1.2 2010/12/04 23:08:34 christos Exp $ */ 2 3 4/* 5 * Id: 56abb301f50605ec5bae137ded730e330d8d7735 6 * Time-stamp: "2009-11-01 10:50:34 bkorb" 7 * 8 * This file contains all of the routines that must be linked into 9 * an executable to use the generated option processing. The optional 10 * routines are in separately compiled modules so that they will not 11 * necessarily be linked in. 12 * 13 * This file is part of AutoOpts, a companion to AutoGen. 14 * AutoOpts is free software. 15 * AutoOpts is copyright (c) 1992-2009 by Bruce Korb - all rights reserved 16 * 17 * AutoOpts is available under any one of two licenses. The license 18 * in use must be one of these two and the choice is under the control 19 * of the user of the license. 20 * 21 * The GNU Lesser General Public License, version 3 or later 22 * See the files "COPYING.lgplv3" and "COPYING.gplv3" 23 * 24 * The Modified Berkeley Software Distribution License 25 * See the file "COPYING.mbsd" 26 * 27 * These files have the following md5sums: 28 * 29 * 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3 30 * 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3 31 * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd 32 */ 33 34static char const zNil[] = ""; 35 36/* = = = START-STATIC-FORWARD = = = */ 37/* static forward declarations maintained by mk-fwd */ 38static tSuccess 39findOptDesc( tOptions* pOpts, tOptState* pOptState ); 40 41static tSuccess 42next_opt_arg_must(tOptions* pOpts, tOptState* pOptState); 43 44static tSuccess 45next_opt_arg_may(tOptions* pOpts, tOptState* pOptState); 46 47static tSuccess 48next_opt_arg_none(tOptions* pOpts, tOptState* pOptState); 49 50static tSuccess 51nextOption(tOptions* pOpts, tOptState* pOptState); 52 53static tSuccess 54doPresets( tOptions* pOpts ); 55 56static int 57checkConsistency( tOptions* pOpts ); 58/* = = = END-STATIC-FORWARD = = = */ 59 60LOCAL void * 61ao_malloc( size_t sz ) 62{ 63 void * res = malloc(sz); 64 if (res == NULL) { 65 fprintf( stderr, "malloc of %d bytes failed\n", (int)sz ); 66 exit( EXIT_FAILURE ); 67 } 68 return res; 69} 70#undef malloc 71#define malloc(_s) ao_malloc(_s) 72 73LOCAL void * 74ao_realloc( void *p, size_t sz ) 75{ 76 void * res = realloc(p, sz); 77 if (res == NULL) { 78 fprintf( stderr, "realloc of %d bytes at 0x%p failed\n", (int)sz, p ); 79 exit( EXIT_FAILURE ); 80 } 81 return res; 82} 83#undef realloc 84#define realloc(_p,_s) ao_realloc(_p,_s) 85 86 87LOCAL void 88ao_free( void *p ) 89{ 90 if (p != NULL) 91 free(p); 92} 93#undef free 94#define free(_p) ao_free(_p) 95 96 97LOCAL char * 98ao_strdup( char const *str ) 99{ 100 char * res = strdup(str); 101 if (res == NULL) { 102 fprintf(stderr, "strdup of %d byte string failed\n", (int)strlen(str)); 103 exit( EXIT_FAILURE ); 104 } 105 return res; 106} 107#undef strdup 108#define strdup(_p) ao_strdup(_p) 109 110#ifndef HAVE_PATHFIND 111# include "compat/pathfind.c" 112#endif 113 114#ifndef HAVE_SNPRINTF 115# include "compat/snprintf.c" 116#endif 117 118#ifndef HAVE_STRDUP 119# include "compat/strdup.c" 120#endif 121 122#ifndef HAVE_STRCHR 123# include "compat/strchr.c" 124#endif 125 126/* 127 * handleOption 128 * 129 * This routine handles equivalencing, sets the option state flags and 130 * invokes the handler procedure, if any. 131 */ 132LOCAL tSuccess 133handleOption( tOptions* pOpts, tOptState* pOptState ) 134{ 135 /* 136 * Save a copy of the option procedure pointer. 137 * If this is an equivalence class option, we still want this proc. 138 */ 139 tOptDesc* pOD = pOptState->pOD; 140 tOptProc* pOP = pOD->pOptProc; 141 if (pOD->fOptState & OPTST_ALLOC_ARG) 142 AGFREE(pOD->optArg.argString); 143 144 pOD->optArg.argString = pOptState->pzOptArg; 145 146 /* 147 * IF we are presetting options, then we will ignore any un-presettable 148 * options. They are the ones either marked as such. 149 */ 150 if ( ((pOpts->fOptSet & OPTPROC_PRESETTING) != 0) 151 && ((pOD->fOptState & OPTST_NO_INIT) != 0) 152 ) 153 return PROBLEM; 154 155 /* 156 * IF this is an equivalence class option, 157 * THEN 158 * Save the option value that got us to this option 159 * entry. (It may not be pOD->optChar[0], if this is an 160 * equivalence entry.) 161 * set the pointer to the equivalence class base 162 */ 163 if (pOD->optEquivIndex != NO_EQUIVALENT) { 164 tOptDesc* p = pOpts->pOptDesc + pOD->optEquivIndex; 165 166 /* 167 * IF the current option state has not been defined (set on the 168 * command line), THEN we will allow continued resetting of 169 * the value. Once "defined", then it must not change. 170 */ 171 if ((pOD->fOptState & OPTST_DEFINED) != 0) { 172 /* 173 * The equivalenced-to option has been found on the command 174 * line before. Make sure new occurrences are the same type. 175 * 176 * IF this option has been previously equivalenced and 177 * it was not the same equivalenced-to option, 178 * THEN we have a usage problem. 179 */ 180 if (p->optActualIndex != pOD->optIndex) { 181 fprintf( stderr, (const char*)zMultiEquiv, p->pz_Name, 182 pOD->pz_Name, 183 (pOpts->pOptDesc + p->optActualIndex)->pz_Name); 184 return FAILURE; 185 } 186 } else { 187 /* 188 * Set the equivalenced-to actual option index to no-equivalent 189 * so that we set all the entries below. This option may either 190 * never have been selected before, or else it was selected by 191 * some sort of "presetting" mechanism. 192 */ 193 p->optActualIndex = NO_EQUIVALENT; 194 } 195 196 if (p->optActualIndex != pOD->optIndex) { 197 /* 198 * First time through, copy over the state 199 * and add in the equivalence flag 200 */ 201 p->optActualValue = pOD->optValue; 202 p->optActualIndex = pOD->optIndex; 203 pOptState->flags |= OPTST_EQUIVALENCE; 204 } 205 206 /* 207 * Copy the most recent option argument. set membership state 208 * is kept in ``p->optCookie''. Do not overwrite. 209 */ 210 p->optArg.argString = pOD->optArg.argString; 211 pOD = p; 212 213 } else { 214 pOD->optActualValue = pOD->optValue; 215 pOD->optActualIndex = pOD->optIndex; 216 } 217 218 pOD->fOptState &= OPTST_PERSISTENT_MASK; 219 pOD->fOptState |= (pOptState->flags & ~OPTST_PERSISTENT_MASK); 220 221 /* 222 * Keep track of count only for DEFINED (command line) options. 223 * IF we have too many, build up an error message and bail. 224 */ 225 if ( (pOD->fOptState & OPTST_DEFINED) 226 && (++pOD->optOccCt > pOD->optMaxCt) ) { 227 228 if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { 229 char const * pzEqv = 230 (pOD->optEquivIndex != NO_EQUIVALENT) ? zEquiv : zNil; 231 232 fputs( zErrOnly, stderr ); 233 234 if (pOD->optMaxCt > 1) 235 fprintf(stderr, zAtMost, pOD->optMaxCt, pOD->pz_Name, pzEqv); 236 else 237 fprintf(stderr, zOnlyOne, pOD->pz_Name, pzEqv); 238 } 239 240 return FAILURE; 241 } 242 243 /* 244 * If provided a procedure to call, call it 245 */ 246 if (pOP != NULL) 247 (*pOP)( pOpts, pOD ); 248 249 return SUCCESS; 250} 251 252 253/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 254 * 255 * HUNT FOR OPTIONS IN THE ARGUMENT LIST 256 * 257 * The next four procedures are "private" to nextOption(). 258 * nextOption() uses findOptDesc() to find the next descriptor and it, in 259 * turn, uses longOptionFind() and shortOptionFind() to actually do the hunt. 260 * 261 * longOptionFind 262 * 263 * Find the long option descriptor for the current option 264 */ 265LOCAL tSuccess 266longOptionFind( tOptions* pOpts, char* pzOptName, tOptState* pOptState ) 267{ 268 ag_bool disable = AG_FALSE; 269 char* pzEq = strchr( pzOptName, '=' ); 270 tOptDesc* pOD = pOpts->pOptDesc; 271 int idx = 0; 272 int idxLim = pOpts->optCt; 273 int matchCt = 0; 274 int matchIdx = 0; 275 size_t nameLen; 276 char opt_name_buf[128]; 277 278 /* 279 * IF the value is attached to the name, 280 * copy it off so we can NUL terminate. 281 */ 282 if (pzEq != NULL) { 283 nameLen = (int)(pzEq - pzOptName); 284 if (nameLen >= sizeof(opt_name_buf)) 285 return FAILURE; 286 memcpy(opt_name_buf, pzOptName, nameLen); 287 opt_name_buf[nameLen] = NUL; 288 pzOptName = opt_name_buf; 289 pzEq++; 290 291 } else nameLen = strlen( pzOptName ); 292 293 do { 294 if (SKIP_OPT(pOD)) { 295 if ( (pOD->fOptState != (OPTST_OMITTED | OPTST_NO_INIT)) 296 || (pOD->pz_Name == NULL)) 297 continue; 298 } 299 else assert(pOD->pz_Name != NULL); 300 301 if (strneqvcmp( pzOptName, pOD->pz_Name, nameLen ) == 0) { 302 /* 303 * IF we have a complete match 304 * THEN it takes priority over any already located partial 305 */ 306 if (pOD->pz_Name[ nameLen ] == NUL) { 307 matchCt = 1; 308 matchIdx = idx; 309 break; 310 } 311 } 312 313 /* 314 * IF there is a disable name 315 * *AND* no argument value has been supplied 316 * (disabled options may have no argument) 317 * *AND* the option name matches the disable name 318 * THEN ... 319 */ 320 else if ( (pOD->pz_DisableName != NULL) 321 && (strneqvcmp(pzOptName, pOD->pz_DisableName, nameLen) == 0) 322 ) { 323 disable = AG_TRUE; 324 325 /* 326 * IF we have a complete match 327 * THEN it takes priority over any already located partial 328 */ 329 if (pOD->pz_DisableName[ nameLen ] == NUL) { 330 matchCt = 1; 331 matchIdx = idx; 332 break; 333 } 334 } 335 336 else 337 continue; 338 339 /* 340 * We found a partial match, either regular or disabling. 341 * Remember the index for later. 342 */ 343 matchIdx = idx; 344 345 if (++matchCt > 1) 346 break; 347 348 } while (pOD++, (++idx < idxLim)); 349 350 /* 351 * Make sure we either found an exact match or found only one partial 352 */ 353 if (matchCt == 1) { 354 pOD = pOpts->pOptDesc + matchIdx; 355 356 if (SKIP_OPT(pOD)) { 357 fprintf(stderr, zDisabledErr, pOpts->pzProgName, pOD->pz_Name); 358 if (pOD->pzText != NULL) 359 fprintf(stderr, " -- %s", pOD->pzText); 360 fputc('\n', stderr); 361 (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); 362 /* NOTREACHED */ 363 } 364 365 /* 366 * IF we found a disablement name, 367 * THEN set the bit in the callers' flag word 368 */ 369 if (disable) 370 pOptState->flags |= OPTST_DISABLED; 371 372 pOptState->pOD = pOD; 373 pOptState->pzOptArg = pzEq; 374 pOptState->optType = TOPT_LONG; 375 return SUCCESS; 376 } 377 378 /* 379 * IF there is no equal sign 380 * *AND* we are using named arguments 381 * *AND* there is a default named option, 382 * THEN return that option. 383 */ 384 if ( (pzEq == NULL) 385 && NAMED_OPTS(pOpts) 386 && (pOpts->specOptIdx.default_opt != NO_EQUIVALENT)) { 387 pOptState->pOD = pOpts->pOptDesc + pOpts->specOptIdx.default_opt; 388 389 pOptState->pzOptArg = pzOptName; 390 pOptState->optType = TOPT_DEFAULT; 391 return SUCCESS; 392 } 393 394 /* 395 * IF we are to stop on errors (the default, actually) 396 * THEN call the usage procedure. 397 */ 398 if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { 399 fprintf(stderr, (matchCt == 0) ? zIllOptStr : zAmbigOptStr, 400 pOpts->pzProgPath, pzOptName); 401 (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); 402 } 403 404 return FAILURE; 405} 406 407 408/* 409 * shortOptionFind 410 * 411 * Find the short option descriptor for the current option 412 */ 413LOCAL tSuccess 414shortOptionFind( tOptions* pOpts, uint_t optValue, tOptState* pOptState ) 415{ 416 tOptDesc* pRes = pOpts->pOptDesc; 417 int ct = pOpts->optCt; 418 419 /* 420 * Search the option list 421 */ 422 do { 423 if (optValue != pRes->optValue) 424 continue; 425 426 if (SKIP_OPT(pRes)) { 427 if ( (pRes->fOptState == (OPTST_OMITTED | OPTST_NO_INIT)) 428 && (pRes->pz_Name != NULL)) { 429 fprintf(stderr, zDisabledErr, pOpts->pzProgPath, pRes->pz_Name); 430 if (pRes->pzText != NULL) 431 fprintf(stderr, " -- %s", pRes->pzText); 432 fputc('\n', stderr); 433 (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); 434 /* NOTREACHED */ 435 } 436 goto short_opt_error; 437 } 438 439 pOptState->pOD = pRes; 440 pOptState->optType = TOPT_SHORT; 441 return SUCCESS; 442 443 } while (pRes++, --ct > 0); 444 445 /* 446 * IF the character value is a digit 447 * AND there is a special number option ("-n") 448 * THEN the result is the "option" itself and the 449 * option is the specially marked "number" option. 450 */ 451 if ( IS_DEC_DIGIT_CHAR(optValue) 452 && (pOpts->specOptIdx.number_option != NO_EQUIVALENT) ) { 453 pOptState->pOD = \ 454 pRes = pOpts->pOptDesc + pOpts->specOptIdx.number_option; 455 (pOpts->pzCurOpt)--; 456 pOptState->optType = TOPT_SHORT; 457 return SUCCESS; 458 } 459 460 short_opt_error: 461 462 /* 463 * IF we are to stop on errors (the default, actually) 464 * THEN call the usage procedure. 465 */ 466 if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { 467 fprintf( stderr, zIllOptChr, pOpts->pzProgPath, optValue ); 468 (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE ); 469 } 470 471 return FAILURE; 472} 473 474 475/* 476 * findOptDesc 477 * 478 * Find the option descriptor for the current option 479 */ 480static tSuccess 481findOptDesc( tOptions* pOpts, tOptState* pOptState ) 482{ 483 /* 484 * IF we are continuing a short option list (e.g. -xyz...) 485 * THEN continue a single flag option. 486 * OTHERWISE see if there is room to advance and then do so. 487 */ 488 if ((pOpts->pzCurOpt != NULL) && (*pOpts->pzCurOpt != NUL)) 489 return shortOptionFind( pOpts, (tAoUC)*(pOpts->pzCurOpt), pOptState ); 490 491 if (pOpts->curOptIdx >= pOpts->origArgCt) 492 return PROBLEM; /* NORMAL COMPLETION */ 493 494 pOpts->pzCurOpt = pOpts->origArgVect[ pOpts->curOptIdx ]; 495 496 /* 497 * IF all arguments must be named options, ... 498 */ 499 if (NAMED_OPTS(pOpts)) { 500 char * pz = pOpts->pzCurOpt; 501 int def; 502 tSuccess res; 503 tAoUS * def_opt; 504 505 pOpts->curOptIdx++; 506 507 if (*pz != '-') 508 return longOptionFind(pOpts, pz, pOptState); 509 510 /* 511 * The name is prefixed with one or more hyphens. Strip them off 512 * and disable the "default_opt" setting. Use heavy recasting to 513 * strip off the "const" quality of the "default_opt" field. 514 */ 515 while (*(++pz) == '-') ; 516 def_opt = (void *)(intptr_t)&(pOpts->specOptIdx.default_opt); 517 def = *def_opt; 518 *def_opt = NO_EQUIVALENT; 519 res = longOptionFind(pOpts, pz, pOptState); 520 *def_opt = def; 521 return res; 522 } 523 524 /* 525 * Note the kind of flag/option marker 526 */ 527 if (*((pOpts->pzCurOpt)++) != '-') 528 return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */ 529 530 /* 531 * Special hack for a hyphen by itself 532 */ 533 if (*(pOpts->pzCurOpt) == NUL) 534 return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */ 535 536 /* 537 * The current argument is to be processed as an option argument 538 */ 539 pOpts->curOptIdx++; 540 541 /* 542 * We have an option marker. 543 * Test the next character for long option indication 544 */ 545 if (pOpts->pzCurOpt[0] == '-') { 546 if (*++(pOpts->pzCurOpt) == NUL) 547 /* 548 * NORMAL COMPLETION - NOT this arg, but rest are operands 549 */ 550 return PROBLEM; 551 552 /* 553 * We do not allow the hyphen to be used as a flag value. 554 * Therefore, if long options are not to be accepted, we punt. 555 */ 556 if ((pOpts->fOptSet & OPTPROC_LONGOPT) == 0) { 557 fprintf( stderr, zIllOptStr, pOpts->pzProgPath, 558 zIllegal, pOpts->pzCurOpt-2 ); 559 return FAILURE; 560 } 561 562 return longOptionFind( pOpts, pOpts->pzCurOpt, pOptState ); 563 } 564 565 /* 566 * If short options are not allowed, then do long 567 * option processing. Otherwise the character must be a 568 * short (i.e. single character) option. 569 */ 570 if ((pOpts->fOptSet & OPTPROC_SHORTOPT) != 0) 571 return shortOptionFind( pOpts, (tAoUC)*(pOpts->pzCurOpt), pOptState ); 572 573 return longOptionFind( pOpts, pOpts->pzCurOpt, pOptState ); 574} 575 576 577static tSuccess 578next_opt_arg_must(tOptions* pOpts, tOptState* pOptState) 579{ 580 /* 581 * An option argument is required. Long options can either have 582 * a separate command line argument, or an argument attached by 583 * the '=' character. Figure out which. 584 */ 585 switch (pOptState->optType) { 586 case TOPT_SHORT: 587 /* 588 * See if an arg string follows the flag character 589 */ 590 if (*++(pOpts->pzCurOpt) == NUL) 591 pOpts->pzCurOpt = pOpts->origArgVect[ pOpts->curOptIdx++ ]; 592 pOptState->pzOptArg = pOpts->pzCurOpt; 593 break; 594 595 case TOPT_LONG: 596 /* 597 * See if an arg string has already been assigned (glued on 598 * with an `=' character) 599 */ 600 if (pOptState->pzOptArg == NULL) 601 pOptState->pzOptArg = pOpts->origArgVect[ pOpts->curOptIdx++ ]; 602 break; 603 604 default: 605#ifdef DEBUG 606 fputs( "AutoOpts lib error: option type not selected\n", 607 stderr ); 608 exit( EXIT_FAILURE ); 609#endif 610 611 case TOPT_DEFAULT: 612 /* 613 * The option was selected by default. The current token is 614 * the option argument. 615 */ 616 break; 617 } 618 619 /* 620 * Make sure we did not overflow the argument list. 621 */ 622 if (pOpts->curOptIdx > pOpts->origArgCt) { 623 fprintf( stderr, zMisArg, pOpts->pzProgPath, 624 pOptState->pOD->pz_Name ); 625 return FAILURE; 626 } 627 628 pOpts->pzCurOpt = NULL; /* next time advance to next arg */ 629 return SUCCESS; 630} 631 632 633static tSuccess 634next_opt_arg_may(tOptions* pOpts, tOptState* pOptState) 635{ 636 /* 637 * An option argument is optional. 638 */ 639 switch (pOptState->optType) { 640 case TOPT_SHORT: 641 if (*++pOpts->pzCurOpt != NUL) 642 pOptState->pzOptArg = pOpts->pzCurOpt; 643 else { 644 char* pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; 645 646 /* 647 * BECAUSE it is optional, we must make sure 648 * we did not find another flag and that there 649 * is such an argument. 650 */ 651 if ((pzLA == NULL) || (*pzLA == '-')) 652 pOptState->pzOptArg = NULL; 653 else { 654 pOpts->curOptIdx++; /* argument found */ 655 pOptState->pzOptArg = pzLA; 656 } 657 } 658 break; 659 660 case TOPT_LONG: 661 /* 662 * Look for an argument if we don't already have one (glued on 663 * with a `=' character) *AND* we are not in named argument mode 664 */ 665 if ( (pOptState->pzOptArg == NULL) 666 && (! NAMED_OPTS(pOpts))) { 667 char* pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; 668 669 /* 670 * BECAUSE it is optional, we must make sure 671 * we did not find another flag and that there 672 * is such an argument. 673 */ 674 if ((pzLA == NULL) || (*pzLA == '-')) 675 pOptState->pzOptArg = NULL; 676 else { 677 pOpts->curOptIdx++; /* argument found */ 678 pOptState->pzOptArg = pzLA; 679 } 680 } 681 break; 682 683 default: 684 case TOPT_DEFAULT: 685 fputs(zAO_Woops, stderr ); 686 exit( EX_SOFTWARE ); 687 } 688 689 /* 690 * After an option with an optional argument, we will 691 * *always* start with the next option because if there 692 * were any characters following the option name/flag, 693 * they would be interpreted as the argument. 694 */ 695 pOpts->pzCurOpt = NULL; 696 return SUCCESS; 697} 698 699 700static tSuccess 701next_opt_arg_none(tOptions* pOpts, tOptState* pOptState) 702{ 703 /* 704 * No option argument. Make sure next time around we find 705 * the correct option flag character for short options 706 */ 707 if (pOptState->optType == TOPT_SHORT) 708 (pOpts->pzCurOpt)++; 709 710 /* 711 * It is a long option. Make sure there was no ``=xxx'' argument 712 */ 713 else if (pOptState->pzOptArg != NULL) { 714 fprintf(stderr, zNoArg, pOpts->pzProgPath, pOptState->pOD->pz_Name); 715 return FAILURE; 716 } 717 718 /* 719 * It is a long option. Advance to next command line argument. 720 */ 721 else 722 pOpts->pzCurOpt = NULL; 723 return SUCCESS; 724} 725 726/* 727 * nextOption 728 * 729 * Find the option descriptor and option argument (if any) for the 730 * next command line argument. DO NOT modify the descriptor. Put 731 * all the state in the state argument so that the option can be skipped 732 * without consequence (side effect). 733 */ 734static tSuccess 735nextOption(tOptions* pOpts, tOptState* pOptState) 736{ 737 { 738 tSuccess res; 739 res = findOptDesc( pOpts, pOptState ); 740 if (! SUCCESSFUL( res )) 741 return res; 742 } 743 744 if ( ((pOptState->flags & OPTST_DEFINED) != 0) 745 && ((pOptState->pOD->fOptState & OPTST_NO_COMMAND) != 0)) { 746 fprintf(stderr, zNotCmdOpt, pOptState->pOD->pz_Name); 747 return FAILURE; 748 } 749 750 pOptState->flags |= (pOptState->pOD->fOptState & OPTST_PERSISTENT_MASK); 751 752 /* 753 * Figure out what to do about option arguments. An argument may be 754 * required, not associated with the option, or be optional. We detect the 755 * latter by examining for an option marker on the next possible argument. 756 * Disabled mode option selection also disables option arguments. 757 */ 758 { 759 enum { ARG_NONE, ARG_MAY, ARG_MUST } arg_type = ARG_NONE; 760 tSuccess res; 761 762 if ((pOptState->flags & OPTST_DISABLED) != 0) 763 arg_type = ARG_NONE; 764 765 else if (OPTST_GET_ARGTYPE(pOptState->flags) == OPARG_TYPE_NONE) 766 arg_type = ARG_NONE; 767 768 else if (pOptState->flags & OPTST_ARG_OPTIONAL) 769 arg_type = ARG_MAY; 770 771 else 772 arg_type = ARG_MUST; 773 774 switch (arg_type) { 775 case ARG_MUST: res = next_opt_arg_must(pOpts, pOptState); break; 776 case ARG_MAY: res = next_opt_arg_may( pOpts, pOptState); break; 777 case ARG_NONE: res = next_opt_arg_none(pOpts, pOptState); break; 778 } 779 780 return res; 781 } 782} 783 784 785/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 786 * 787 * DO PRESETS 788 * 789 * The next several routines do the immediate action pass on the command 790 * line options, then the environment variables, then the config files in 791 * reverse order. Once done with that, the order is reversed and all 792 * the config files and environment variables are processed again, this 793 * time only processing the non-immediate action options. doPresets() 794 * will then return for optionProcess() to do the final pass on the command 795 * line arguments. 796 */ 797 798/* 799 * doImmediateOpts - scan the command line for immediate action options 800 */ 801LOCAL tSuccess 802doImmediateOpts( tOptions* pOpts ) 803{ 804 pOpts->curOptIdx = 1; /* start by skipping program name */ 805 pOpts->pzCurOpt = NULL; 806 807 /* 808 * Examine all the options from the start. We process any options that 809 * are marked for immediate processing. 810 */ 811 for (;;) { 812 tOptState optState = OPTSTATE_INITIALIZER(PRESET); 813 814 switch (nextOption( pOpts, &optState )) { 815 case FAILURE: goto optionsDone; 816 case PROBLEM: return SUCCESS; /* no more args */ 817 case SUCCESS: break; 818 } 819 820 /* 821 * IF this *is* an immediate-attribute option, then do it. 822 */ 823 if (! DO_IMMEDIATELY(optState.flags)) 824 continue; 825 826 if (! SUCCESSFUL( handleOption( pOpts, &optState ))) 827 break; 828 } optionsDone:; 829 830 if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) 831 (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE ); 832 return FAILURE; 833} 834 835 836LOCAL tSuccess 837doRegularOpts( tOptions* pOpts ) 838{ 839 /* 840 * Now, process all the options from our current position onward. 841 * (This allows interspersed options and arguments for the few 842 * non-standard programs that require it.) 843 */ 844 for (;;) { 845 tOptState optState = OPTSTATE_INITIALIZER(DEFINED); 846 847 switch (nextOption( pOpts, &optState )) { 848 case FAILURE: goto optionsDone; 849 case PROBLEM: return SUCCESS; /* no more args */ 850 case SUCCESS: break; 851 } 852 853 /* 854 * IF this is not being processed normally (i.e. is immediate action) 855 * THEN skip it (unless we are supposed to do it a second time). 856 */ 857 if (! DO_NORMALLY(optState.flags)) { 858 if (! DO_SECOND_TIME(optState.flags)) 859 continue; 860 optState.pOD->optOccCt--; /* don't count last time */ 861 } 862 863 if (! SUCCESSFUL( handleOption( pOpts, &optState ))) 864 break; 865 } optionsDone:; 866 if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) 867 (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE ); 868 return FAILURE; 869} 870 871 872/* 873 * doPresets - check for preset values from a config file or the envrionment 874 */ 875static tSuccess 876doPresets( tOptions* pOpts ) 877{ 878 tOptDesc * pOD = NULL; 879 880 if (! SUCCESSFUL( doImmediateOpts( pOpts ))) 881 return FAILURE; 882 883 /* 884 * IF this option set has a --save-opts option, then it also 885 * has a --load-opts option. See if a command line option has disabled 886 * option presetting. 887 */ 888 if ( (pOpts->specOptIdx.save_opts != NO_EQUIVALENT) 889 && (pOpts->specOptIdx.save_opts != 0)) { 890 pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts + 1; 891 if (DISABLED_OPT(pOD)) 892 return SUCCESS; 893 } 894 895 /* 896 * Until we return from this procedure, disable non-presettable opts 897 */ 898 pOpts->fOptSet |= OPTPROC_PRESETTING; 899 /* 900 * IF there are no config files, 901 * THEN do any environment presets and leave. 902 */ 903 if (pOpts->papzHomeList == NULL) { 904 doEnvPresets( pOpts, ENV_ALL ); 905 } 906 else { 907 doEnvPresets( pOpts, ENV_IMM ); 908 909 /* 910 * Check to see if environment variables have disabled presetting. 911 */ 912 if ((pOD != NULL) && ! DISABLED_OPT(pOD)) 913 internalFileLoad( pOpts ); 914 915 /* 916 * ${PROGRAM_LOAD_OPTS} value of "no" cannot disable other environment 917 * variable options. Only the loading of .rc files. 918 */ 919 doEnvPresets( pOpts, ENV_NON_IMM ); 920 } 921 pOpts->fOptSet &= ~OPTPROC_PRESETTING; 922 923 return SUCCESS; 924} 925 926 927/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 928 * 929 * VERIFY OPTION CONSISTENCY 930 * 931 * Make sure that the argument list passes our consistency tests. 932 */ 933static int 934checkConsistency( tOptions* pOpts ) 935{ 936 int errCt = 0; 937 tOptDesc* pOD = pOpts->pOptDesc; 938 int oCt = pOpts->presetOptCt; 939 940 /* 941 * FOR each of "oCt" options, ... 942 */ 943 for (;;) { 944 const int* pMust = pOD->pOptMust; 945 const int* pCant = pOD->pOptCant; 946 947 /* 948 * IF the current option was provided on the command line 949 * THEN ensure that any "MUST" requirements are not 950 * "DEFAULT" (unspecified) *AND* ensure that any 951 * "CANT" options have not been SET or DEFINED. 952 */ 953 if (SELECTED_OPT(pOD)) { 954 if (pMust != NULL) for (;;) { 955 tOptDesc* p = pOpts->pOptDesc + *(pMust++); 956 if (UNUSED_OPT(p)) { 957 const tOptDesc* pN = pOpts->pOptDesc + pMust[-1]; 958 errCt++; 959 fprintf( stderr, zReqFmt, pOD->pz_Name, pN->pz_Name ); 960 } 961 962 if (*pMust == NO_EQUIVALENT) 963 break; 964 } 965 966 if (pCant != NULL) for (;;) { 967 tOptDesc* p = pOpts->pOptDesc + *(pCant++); 968 if (SELECTED_OPT(p)) { 969 const tOptDesc* pN = pOpts->pOptDesc + pCant[-1]; 970 errCt++; 971 fprintf( stderr, zCantFmt, pOD->pz_Name, pN->pz_Name ); 972 } 973 974 if (*pCant == NO_EQUIVALENT) 975 break; 976 } 977 } 978 979 /* 980 * IF this option is not equivalenced to another, 981 * OR it is equivalenced to itself (is the equiv. root) 982 * THEN we need to make sure it occurs often enough. 983 */ 984 if ( (pOD->optEquivIndex == NO_EQUIVALENT) 985 || (pOD->optEquivIndex == pOD->optIndex) ) do { 986 /* 987 * IF the occurrence counts have been satisfied, 988 * THEN there is no problem. 989 */ 990 if (pOD->optOccCt >= pOD->optMinCt) 991 break; 992 993 /* 994 * IF MUST_SET means SET and PRESET are okay, 995 * so min occurrence count doesn't count 996 */ 997 if ( (pOD->fOptState & OPTST_MUST_SET) 998 && (pOD->fOptState & (OPTST_PRESET | OPTST_SET)) ) 999 break; 1000 1001 errCt++; 1002 if (pOD->optMinCt > 1) 1003 fprintf( stderr, zNotEnough, pOD->pz_Name, pOD->optMinCt ); 1004 else fprintf( stderr, zNeedOne, pOD->pz_Name ); 1005 } while (0); 1006 1007 if (--oCt <= 0) 1008 break; 1009 pOD++; 1010 } 1011 1012 /* 1013 * IF we are stopping on errors, check to see if any remaining 1014 * arguments are required to be there or prohibited from being there. 1015 */ 1016 if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { 1017 1018 /* 1019 * Check for prohibition 1020 */ 1021 if ((pOpts->fOptSet & OPTPROC_NO_ARGS) != 0) { 1022 if (pOpts->origArgCt > pOpts->curOptIdx) { 1023 fprintf( stderr, zNoArgs, pOpts->pzProgName ); 1024 ++errCt; 1025 } 1026 } 1027 1028 /* 1029 * ELSE not prohibited, check for being required 1030 */ 1031 else if ((pOpts->fOptSet & OPTPROC_ARGS_REQ) != 0) { 1032 if (pOpts->origArgCt <= pOpts->curOptIdx) { 1033 fprintf( stderr, zArgsMust, pOpts->pzProgName ); 1034 ++errCt; 1035 } 1036 } 1037 } 1038 1039 return errCt; 1040} 1041 1042 1043/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1044 * 1045 * THESE ROUTINES ARE CALLABLE FROM THE GENERATED OPTION PROCESSING CODE 1046 */ 1047/*=--subblock=arg=arg_type,arg_name,arg_desc =*/ 1048/*=* 1049 * library: opts 1050 * header: your-opts.h 1051 * 1052 * lib_description: 1053 * 1054 * These are the routines that libopts users may call directly from their 1055 * code. There are several other routines that can be called by code 1056 * generated by the libopts option templates, but they are not to be 1057 * called from any other user code. The @file{options.h} header is 1058 * fairly clear about this, too. 1059=*/ 1060 1061/*=export_func optionProcess 1062 * 1063 * what: this is the main option processing routine 1064 * 1065 * arg: + tOptions* + pOpts + program options descriptor + 1066 * arg: + int + argc + program arg count + 1067 * arg: + char** + argv + program arg vector + 1068 * 1069 * ret_type: int 1070 * ret_desc: the count of the arguments processed 1071 * 1072 * doc: 1073 * 1074 * This is the main entry point for processing options. It is intended 1075 * that this procedure be called once at the beginning of the execution of 1076 * a program. Depending on options selected earlier, it is sometimes 1077 * necessary to stop and restart option processing, or to select completely 1078 * different sets of options. This can be done easily, but you generally 1079 * do not want to do this. 1080 * 1081 * The number of arguments processed always includes the program name. 1082 * If one of the arguments is "--", then it is counted and the processing 1083 * stops. If an error was encountered and errors are to be tolerated, then 1084 * the returned value is the index of the argument causing the error. 1085 * A hyphen by itself ("-") will also cause processing to stop and will 1086 * @emph{not} be counted among the processed arguments. A hyphen by itself 1087 * is treated as an operand. Encountering an operand stops option 1088 * processing. 1089 * 1090 * err: Errors will cause diagnostics to be printed. @code{exit(3)} may 1091 * or may not be called. It depends upon whether or not the options 1092 * were generated with the "allow-errors" attribute, or if the 1093 * ERRSKIP_OPTERR or ERRSTOP_OPTERR macros were invoked. 1094=*/ 1095int 1096optionProcess( 1097 tOptions* pOpts, 1098 int argCt, 1099 char** argVect ) 1100{ 1101 if (! SUCCESSFUL( validateOptionsStruct( pOpts, argVect[0] ))) 1102 exit( EX_SOFTWARE ); 1103 1104 /* 1105 * Establish the real program name, the program full path, 1106 * and do all the presetting the first time thru only. 1107 */ 1108 if ((pOpts->fOptSet & OPTPROC_INITDONE) == 0) { 1109 pOpts->origArgCt = argCt; 1110 pOpts->origArgVect = argVect; 1111 pOpts->fOptSet |= OPTPROC_INITDONE; 1112 1113 if (! SUCCESSFUL( doPresets( pOpts ))) 1114 return 0; 1115 1116 /* 1117 * IF option name conversion was suppressed but it is not suppressed 1118 * for the command line, then it's time to translate option names. 1119 * Usage text will not get retranslated. 1120 */ 1121 if ( ((pOpts->fOptSet & OPTPROC_TRANSLATE) != 0) 1122 && (pOpts->pTransProc != NULL) 1123 && ((pOpts->fOptSet & OPTPROC_NO_XLAT_MASK) 1124 == OPTPROC_NXLAT_OPT_CFG) ) { 1125 1126 pOpts->fOptSet &= ~OPTPROC_NXLAT_OPT_CFG; 1127 (*pOpts->pTransProc)(); 1128 } 1129 1130 if ((pOpts->fOptSet & OPTPROC_REORDER) != 0) 1131 optionSort( pOpts ); 1132 1133 pOpts->curOptIdx = 1; 1134 pOpts->pzCurOpt = NULL; 1135 } 1136 1137 /* 1138 * IF we are (re)starting, 1139 * THEN reset option location 1140 */ 1141 else if (pOpts->curOptIdx <= 0) { 1142 pOpts->curOptIdx = 1; 1143 pOpts->pzCurOpt = NULL; 1144 } 1145 1146 if (! SUCCESSFUL( doRegularOpts( pOpts ))) 1147 return pOpts->origArgCt; 1148 1149 /* 1150 * IF there were no errors 1151 * AND we have RC/INI files 1152 * AND there is a request to save the files 1153 * THEN do that now before testing for conflicts. 1154 * (conflicts are ignored in preset options) 1155 */ 1156 if ( (pOpts->specOptIdx.save_opts != NO_EQUIVALENT) 1157 && (pOpts->specOptIdx.save_opts != 0)) { 1158 tOptDesc* pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts; 1159 1160 if (SELECTED_OPT( pOD )) { 1161 optionSaveFile( pOpts ); 1162 exit( EXIT_SUCCESS ); 1163 } 1164 } 1165 1166 /* 1167 * IF we are checking for errors, 1168 * THEN look for too few occurrences of required options 1169 */ 1170 if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { 1171 if (checkConsistency( pOpts ) != 0) 1172 (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE ); 1173 } 1174 1175 return pOpts->curOptIdx; 1176} 1177 1178/* 1179 * Local Variables: 1180 * mode: C 1181 * c-file-style: "stroustrup" 1182 * indent-tabs-mode: nil 1183 * End: 1184 * end of autoopts/autoopts.c */ 1185