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