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