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