Annotation of embedaddon/ntp/sntp/libopts/autoopts.c, revision 1.1
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 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>