PageRenderTime 95ms CodeModel.GetById 20ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/ntp/libopts/autoopts.c

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