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