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