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