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