autoopts.c revision 181834
1181834Sroberto
2181834Sroberto/*
3181834Sroberto *  $Id: autoopts.c,v 4.25 2007/04/15 19:01:18 bkorb Exp $
4181834Sroberto *  Time-stamp:      "2007-04-15 11:10:40 bkorb"
5181834Sroberto *
6181834Sroberto *  This file contains all of the routines that must be linked into
7181834Sroberto *  an executable to use the generated option processing.  The optional
8181834Sroberto *  routines are in separately compiled modules so that they will not
9181834Sroberto *  necessarily be linked in.
10181834Sroberto */
11181834Sroberto
12181834Sroberto/*
13181834Sroberto *  Automated Options copyright 1992-2007 Bruce Korb
14181834Sroberto *
15181834Sroberto *  Automated Options is free software.
16181834Sroberto *  You may redistribute it and/or modify it under the terms of the
17181834Sroberto *  GNU General Public License, as published by the Free Software
18181834Sroberto *  Foundation; either version 2, or (at your option) any later version.
19181834Sroberto *
20181834Sroberto *  Automated Options is distributed in the hope that it will be useful,
21181834Sroberto *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22181834Sroberto *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23181834Sroberto *  GNU General Public License for more details.
24181834Sroberto *
25181834Sroberto *  You should have received a copy of the GNU General Public License
26181834Sroberto *  along with Automated Options.  See the file "COPYING".  If not,
27181834Sroberto *  write to:  The Free Software Foundation, Inc.,
28181834Sroberto *             51 Franklin Street, Fifth Floor,
29181834Sroberto *             Boston, MA  02110-1301, USA.
30181834Sroberto *
31181834Sroberto * As a special exception, Bruce Korb gives permission for additional
32181834Sroberto * uses of the text contained in his release of AutoOpts.
33181834Sroberto *
34181834Sroberto * The exception is that, if you link the AutoOpts library with other
35181834Sroberto * files to produce an executable, this does not by itself cause the
36181834Sroberto * resulting executable to be covered by the GNU General Public License.
37181834Sroberto * Your use of that executable is in no way restricted on account of
38181834Sroberto * linking the AutoOpts library code into it.
39181834Sroberto *
40181834Sroberto * This exception does not however invalidate any other reasons why
41181834Sroberto * the executable file might be covered by the GNU General Public License.
42181834Sroberto *
43181834Sroberto * This exception applies only to the code released by Bruce Korb under
44181834Sroberto * the name AutoOpts.  If you copy code from other sources under the
45181834Sroberto * General Public License into a copy of AutoOpts, as the General Public
46181834Sroberto * License permits, the exception does not apply to the code that you add
47181834Sroberto * in this way.  To avoid misleading anyone as to the status of such
48181834Sroberto * modified files, you must delete this exception notice from them.
49181834Sroberto *
50181834Sroberto * If you write modifications of your own for AutoOpts, it is your choice
51181834Sroberto * whether to permit this exception to apply to your modifications.
52181834Sroberto * If you do not wish that, delete this exception notice.
53181834Sroberto */
54181834Sroberto
55181834Srobertostatic char const zNil[] = "";
56181834Sroberto
57181834Sroberto/* = = = START-STATIC-FORWARD = = = */
58181834Sroberto/* static forward declarations maintained by :mkfwd */
59181834Srobertostatic tSuccess
60181834SrobertofindOptDesc( tOptions* pOpts, tOptState* pOptState );
61181834Sroberto
62181834Srobertostatic tSuccess
63181834SrobertonextOption( tOptions* pOpts, tOptState* pOptState );
64181834Sroberto
65181834Srobertostatic tSuccess
66181834SrobertodoPresets( tOptions* pOpts );
67181834Sroberto
68181834Srobertostatic int
69181834SrobertocheckConsistency( tOptions* pOpts );
70181834Sroberto/* = = = END-STATIC-FORWARD = = = */
71181834Sroberto
72181834SrobertoLOCAL void *
73181834Srobertoao_malloc( size_t sz )
74181834Sroberto{
75181834Sroberto    void * res = malloc(sz);
76181834Sroberto    if (res == NULL) {
77181834Sroberto        fprintf( stderr, "malloc of %d bytes failed\n", (int)sz );
78181834Sroberto        exit( EXIT_FAILURE );
79181834Sroberto    }
80181834Sroberto    return res;
81181834Sroberto}
82181834Sroberto#undef  malloc
83181834Sroberto#define malloc(_s) ao_malloc(_s)
84181834Sroberto
85181834SrobertoLOCAL void *
86181834Srobertoao_realloc( void *p, size_t sz )
87181834Sroberto{
88181834Sroberto    void * res = realloc(p, sz);
89181834Sroberto    if (res == NULL) {
90181834Sroberto        fprintf( stderr, "realloc of %d bytes at 0x%p failed\n", (int)sz, p );
91181834Sroberto        exit( EXIT_FAILURE );
92181834Sroberto    }
93181834Sroberto    return res;
94181834Sroberto}
95181834Sroberto#undef  realloc
96181834Sroberto#define realloc(_p,_s) ao_realloc(_p,_s)
97181834Sroberto
98181834Sroberto
99181834SrobertoLOCAL void
100181834Srobertoao_free( void *p )
101181834Sroberto{
102181834Sroberto    if (p != NULL)
103181834Sroberto        free(p);
104181834Sroberto}
105181834Sroberto#undef  free
106181834Sroberto#define free(_p) ao_free(_p)
107181834Sroberto
108181834Sroberto
109181834SrobertoLOCAL char *
110181834Srobertoao_strdup( char const *str )
111181834Sroberto{
112181834Sroberto    char * res = strdup(str);
113181834Sroberto    if (res == NULL) {
114181834Sroberto        fprintf( stderr, "strdup of %d byte string failed\n", (int)strlen(str) );
115181834Sroberto        exit( EXIT_FAILURE );
116181834Sroberto    }
117181834Sroberto    return res;
118181834Sroberto}
119181834Sroberto#undef  strdup
120181834Sroberto#define strdup(_p) ao_strdup(_p)
121181834Sroberto
122181834Sroberto#ifndef HAVE_PATHFIND
123181834Sroberto#  include "compat/pathfind.c"
124181834Sroberto#endif
125181834Sroberto
126181834Sroberto#ifndef HAVE_SNPRINTF
127181834Sroberto#  include "compat/snprintf.c"
128181834Sroberto#endif
129181834Sroberto
130181834Sroberto#ifndef HAVE_STRDUP
131181834Sroberto#  include "compat/strdup.c"
132181834Sroberto#endif
133181834Sroberto
134181834Sroberto#ifndef HAVE_STRCHR
135181834Sroberto#  include "compat/strchr.c"
136181834Sroberto#endif
137181834Sroberto
138181834Sroberto/*
139181834Sroberto *  handleOption
140181834Sroberto *
141181834Sroberto *  This routine handles equivalencing, sets the option state flags and
142181834Sroberto *  invokes the handler procedure, if any.
143181834Sroberto */
144181834SrobertoLOCAL tSuccess
145181834SrobertohandleOption( tOptions* pOpts, tOptState* pOptState )
146181834Sroberto{
147181834Sroberto    /*
148181834Sroberto     *  Save a copy of the option procedure pointer.
149181834Sroberto     *  If this is an equivalence class option, we still want this proc.
150181834Sroberto     */
151181834Sroberto    tOptDesc* pOD = pOptState->pOD;
152181834Sroberto    tOptProc* pOP = pOD->pOptProc;
153181834Sroberto    if (pOD->fOptState & OPTST_ALLOC_ARG)
154181834Sroberto        AGFREE(pOD->optArg.argString);
155181834Sroberto
156181834Sroberto    pOD->optArg.argString = pOptState->pzOptArg;
157181834Sroberto
158181834Sroberto    /*
159181834Sroberto     *  IF we are presetting options, then we will ignore any un-presettable
160181834Sroberto     *  options.  They are the ones either marked as such.
161181834Sroberto     */
162181834Sroberto    if (  ((pOpts->fOptSet & OPTPROC_PRESETTING) != 0)
163181834Sroberto       && ((pOD->fOptState & OPTST_NO_INIT) != 0)
164181834Sroberto       )
165181834Sroberto        return PROBLEM;
166181834Sroberto
167181834Sroberto    /*
168181834Sroberto     *  IF this is an equivalence class option,
169181834Sroberto     *  THEN
170181834Sroberto     *      Save the option value that got us to this option
171181834Sroberto     *      entry.  (It may not be pOD->optChar[0], if this is an
172181834Sroberto     *      equivalence entry.)
173181834Sroberto     *      set the pointer to the equivalence class base
174181834Sroberto     */
175181834Sroberto    if (pOD->optEquivIndex != NO_EQUIVALENT) {
176181834Sroberto        tOptDesc* p = pOpts->pOptDesc + pOD->optEquivIndex;
177181834Sroberto
178181834Sroberto        /*
179181834Sroberto         * IF the current option state has not been defined (set on the
180181834Sroberto         *    command line), THEN we will allow continued resetting of
181181834Sroberto         *    the value.  Once "defined", then it must not change.
182181834Sroberto         */
183181834Sroberto        if ((pOD->fOptState & OPTST_DEFINED) != 0) {
184181834Sroberto            /*
185181834Sroberto             *  The equivalenced-to option has been found on the command
186181834Sroberto             *  line before.  Make sure new occurrences are the same type.
187181834Sroberto             *
188181834Sroberto             *  IF this option has been previously equivalenced and
189181834Sroberto             *     it was not the same equivalenced-to option,
190181834Sroberto             *  THEN we have a usage problem.
191181834Sroberto             */
192181834Sroberto            if (p->optActualIndex != pOD->optIndex) {
193181834Sroberto                fprintf( stderr, (char*)zMultiEquiv, p->pz_Name, pOD->pz_Name,
194181834Sroberto                         (pOpts->pOptDesc + p->optActualIndex)->pz_Name);
195181834Sroberto                return FAILURE;
196181834Sroberto            }
197181834Sroberto        } else {
198181834Sroberto            /*
199181834Sroberto             *  Set the equivalenced-to actual option index to no-equivalent
200181834Sroberto             *  so that we set all the entries below.  This option may either
201181834Sroberto             *  never have been selected before, or else it was selected by
202181834Sroberto             *  some sort of "presetting" mechanism.
203181834Sroberto             */
204181834Sroberto            p->optActualIndex = NO_EQUIVALENT;
205181834Sroberto        }
206181834Sroberto
207181834Sroberto        if (p->optActualIndex != pOD->optIndex) {
208181834Sroberto            /*
209181834Sroberto             *  First time through, copy over the state
210181834Sroberto             *  and add in the equivalence flag
211181834Sroberto             */
212181834Sroberto            p->optActualValue = pOD->optValue;
213181834Sroberto            p->optActualIndex = pOD->optIndex;
214181834Sroberto            pOptState->flags |= OPTST_EQUIVALENCE;
215181834Sroberto        }
216181834Sroberto
217181834Sroberto        /*
218181834Sroberto         *  Copy the most recent option argument.  set membership state
219181834Sroberto         *  is kept in ``p->optCookie''.  Do not overwrite.
220181834Sroberto         */
221181834Sroberto        p->optArg.argString = pOD->optArg.argString;
222181834Sroberto        pOD = p;
223181834Sroberto
224181834Sroberto    } else {
225181834Sroberto        pOD->optActualValue = pOD->optValue;
226181834Sroberto        pOD->optActualIndex = pOD->optIndex;
227181834Sroberto    }
228181834Sroberto
229181834Sroberto    pOD->fOptState &= OPTST_PERSISTENT_MASK;
230181834Sroberto    pOD->fOptState |= (pOptState->flags & ~OPTST_PERSISTENT_MASK);
231181834Sroberto
232181834Sroberto    /*
233181834Sroberto     *  Keep track of count only for DEFINED (command line) options.
234181834Sroberto     *  IF we have too many, build up an error message and bail.
235181834Sroberto     */
236181834Sroberto    if (  (pOD->fOptState & OPTST_DEFINED)
237181834Sroberto       && (++pOD->optOccCt > pOD->optMaxCt)  )  {
238181834Sroberto
239181834Sroberto        if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
240181834Sroberto            char const * pzEqv =
241181834Sroberto                (pOD->optEquivIndex != NO_EQUIVALENT) ? zEquiv : zNil;
242181834Sroberto
243181834Sroberto            fputs( zErrOnly, stderr );
244181834Sroberto
245181834Sroberto            if (pOD->optMaxCt > 1)
246181834Sroberto                fprintf(stderr, zAtMost, pOD->optMaxCt, pOD->pz_Name, pzEqv);
247181834Sroberto            else
248181834Sroberto                fprintf(stderr, zOnlyOne, pOD->pz_Name, pzEqv);
249181834Sroberto        }
250181834Sroberto
251181834Sroberto        return FAILURE;
252181834Sroberto    }
253181834Sroberto
254181834Sroberto    /*
255181834Sroberto     *  If provided a procedure to call, call it
256181834Sroberto     */
257181834Sroberto    if (pOP != (tpOptProc)NULL)
258181834Sroberto        (*pOP)( pOpts, pOD );
259181834Sroberto
260181834Sroberto    return SUCCESS;
261181834Sroberto}
262181834Sroberto
263181834Sroberto
264181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
265181834Sroberto *
266181834Sroberto *  HUNT FOR OPTIONS IN THE ARGUMENT LIST
267181834Sroberto *
268181834Sroberto *  The next four procedures are "private" to nextOption().
269181834Sroberto *  nextOption() uses findOptDesc() to find the next descriptor and it, in
270181834Sroberto *  turn, uses longOptionFind() and shortOptionFind() to actually do the hunt.
271181834Sroberto *
272181834Sroberto *  longOptionFind
273181834Sroberto *
274181834Sroberto *  Find the long option descriptor for the current option
275181834Sroberto */
276181834SrobertoLOCAL tSuccess
277181834SrobertolongOptionFind( tOptions* pOpts, char* pzOptName, tOptState* pOptState )
278181834Sroberto{
279181834Sroberto    ag_bool    disable  = AG_FALSE;
280181834Sroberto    char*      pzEq     = strchr( pzOptName, '=' );
281181834Sroberto    tOptDesc*  pOD      = pOpts->pOptDesc;
282181834Sroberto    int        idx      = 0;
283181834Sroberto    int        idxLim   = pOpts->optCt;
284181834Sroberto    int        matchCt  = 0;
285181834Sroberto    int        matchIdx = 0;
286181834Sroberto    int        nameLen;
287181834Sroberto
288181834Sroberto    /*
289181834Sroberto     *  IF the value is attached to the name,
290181834Sroberto     *  THEN clip it off.
291181834Sroberto     *  Either way, figure out how long our name is
292181834Sroberto     */
293181834Sroberto    if (pzEq != NULL) {
294181834Sroberto        nameLen = (int)(pzEq - pzOptName);
295181834Sroberto        *pzEq = NUL;
296181834Sroberto    } else nameLen = strlen( pzOptName );
297181834Sroberto
298181834Sroberto    do  {
299181834Sroberto        if (SKIP_OPT(pOD))
300181834Sroberto            continue;
301181834Sroberto
302181834Sroberto        if (strneqvcmp( pzOptName, pOD->pz_Name, nameLen ) == 0) {
303181834Sroberto            /*
304181834Sroberto             *  IF we have a complete match
305181834Sroberto             *  THEN it takes priority over any already located partial
306181834Sroberto             */
307181834Sroberto            if (pOD->pz_Name[ nameLen ] == NUL) {
308181834Sroberto                matchCt  = 1;
309181834Sroberto                matchIdx = idx;
310181834Sroberto                break;
311181834Sroberto            }
312181834Sroberto        }
313181834Sroberto
314181834Sroberto        /*
315181834Sroberto         *  IF       there is a disable name
316181834Sroberto         *     *AND* no argument value has been supplied
317181834Sroberto         *              (disabled options may have no argument)
318181834Sroberto         *     *AND* the option name matches the disable name
319181834Sroberto         *  THEN ...
320181834Sroberto         */
321181834Sroberto        else if (  (pOD->pz_DisableName != NULL)
322181834Sroberto                && (strneqvcmp(pzOptName, pOD->pz_DisableName, nameLen) == 0)
323181834Sroberto                )  {
324181834Sroberto            disable  = AG_TRUE;
325181834Sroberto
326181834Sroberto            /*
327181834Sroberto             *  IF we have a complete match
328181834Sroberto             *  THEN it takes priority over any already located partial
329181834Sroberto             */
330181834Sroberto            if (pOD->pz_DisableName[ nameLen ] == NUL) {
331181834Sroberto                matchCt  = 1;
332181834Sroberto                matchIdx = idx;
333181834Sroberto                break;
334181834Sroberto            }
335181834Sroberto        }
336181834Sroberto
337181834Sroberto        else
338181834Sroberto            continue;
339181834Sroberto
340181834Sroberto        /*
341181834Sroberto         *  We found a partial match, either regular or disabling.
342181834Sroberto         *  Remember the index for later.
343181834Sroberto         */
344181834Sroberto        matchIdx = idx;
345181834Sroberto
346181834Sroberto        if (++matchCt > 1)
347181834Sroberto            break;
348181834Sroberto
349181834Sroberto    } while (pOD++, (++idx < idxLim));
350181834Sroberto
351181834Sroberto    if (pzEq != NULL)
352181834Sroberto        *(pzEq++) = '=';
353181834Sroberto
354181834Sroberto    /*
355181834Sroberto     *  Make sure we either found an exact match or found only one partial
356181834Sroberto     */
357181834Sroberto    if (matchCt == 1) {
358181834Sroberto        /*
359181834Sroberto         *  IF we found a disablement name,
360181834Sroberto         *  THEN set the bit in the callers' flag word
361181834Sroberto         */
362181834Sroberto        if (disable)
363181834Sroberto            pOptState->flags |= OPTST_DISABLED;
364181834Sroberto
365181834Sroberto        pOptState->pOD      = pOpts->pOptDesc + matchIdx;
366181834Sroberto        pOptState->pzOptArg = pzEq;
367181834Sroberto        pOptState->optType  = TOPT_LONG;
368181834Sroberto        return SUCCESS;
369181834Sroberto    }
370181834Sroberto
371181834Sroberto    /*
372181834Sroberto     *  IF there is no equal sign
373181834Sroberto     *     *AND* we are using named arguments
374181834Sroberto     *     *AND* there is a default named option,
375181834Sroberto     *  THEN return that option.
376181834Sroberto     */
377181834Sroberto    if (  (pzEq == NULL)
378181834Sroberto       && NAMED_OPTS(pOpts)
379181834Sroberto       && (pOpts->specOptIdx.default_opt != NO_EQUIVALENT)) {
380181834Sroberto        pOptState->pOD = pOpts->pOptDesc + pOpts->specOptIdx.default_opt;
381181834Sroberto
382181834Sroberto        pOptState->pzOptArg = pzOptName;
383181834Sroberto        pOptState->optType  = TOPT_DEFAULT;
384181834Sroberto        return SUCCESS;
385181834Sroberto    }
386181834Sroberto
387181834Sroberto    /*
388181834Sroberto     *  IF we are to stop on errors (the default, actually)
389181834Sroberto     *  THEN call the usage procedure.
390181834Sroberto     */
391181834Sroberto    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
392181834Sroberto        fprintf( stderr, zIllOptStr, pOpts->pzProgPath,
393181834Sroberto                 (matchCt == 0) ? zIllegal : zAmbiguous, pzOptName );
394181834Sroberto        (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE );
395181834Sroberto    }
396181834Sroberto
397181834Sroberto    return FAILURE;
398181834Sroberto}
399181834Sroberto
400181834Sroberto
401181834Sroberto/*
402181834Sroberto *  shortOptionFind
403181834Sroberto *
404181834Sroberto *  Find the short option descriptor for the current option
405181834Sroberto */
406181834SrobertoLOCAL tSuccess
407181834SrobertoshortOptionFind( tOptions* pOpts, uint_t optValue, tOptState* pOptState )
408181834Sroberto{
409181834Sroberto    tOptDesc*  pRes = pOpts->pOptDesc;
410181834Sroberto    int        ct   = pOpts->optCt;
411181834Sroberto
412181834Sroberto    /*
413181834Sroberto     *  Search the option list
414181834Sroberto     */
415181834Sroberto    for (;;) {
416181834Sroberto        /*
417181834Sroberto         *  IF the values match,
418181834Sroberto         *  THEN we stop here
419181834Sroberto         */
420181834Sroberto        if ((! SKIP_OPT(pRes)) && (optValue == pRes->optValue)) {
421181834Sroberto            pOptState->pOD     = pRes;
422181834Sroberto            pOptState->optType = TOPT_SHORT;
423181834Sroberto            return SUCCESS;
424181834Sroberto        }
425181834Sroberto
426181834Sroberto        /*
427181834Sroberto         *  Advance to next option description
428181834Sroberto         */
429181834Sroberto        pRes++;
430181834Sroberto
431181834Sroberto        /*
432181834Sroberto         *  IF we have searched everything, ...
433181834Sroberto         */
434181834Sroberto        if (--ct <= 0)
435181834Sroberto            break;
436181834Sroberto    }
437181834Sroberto
438181834Sroberto    /*
439181834Sroberto     *  IF    the character value is a digit
440181834Sroberto     *    AND there is a special number option ("-n")
441181834Sroberto     *  THEN the result is the "option" itself and the
442181834Sroberto     *       option is the specially marked "number" option.
443181834Sroberto     */
444181834Sroberto    if (  isdigit( optValue )
445181834Sroberto       && (pOpts->specOptIdx.number_option != NO_EQUIVALENT) ) {
446181834Sroberto        pOptState->pOD = \
447181834Sroberto        pRes           = pOpts->pOptDesc + pOpts->specOptIdx.number_option;
448181834Sroberto        (pOpts->pzCurOpt)--;
449181834Sroberto        pOptState->optType = TOPT_SHORT;
450181834Sroberto        return SUCCESS;
451181834Sroberto    }
452181834Sroberto
453181834Sroberto    /*
454181834Sroberto     *  IF we are to stop on errors (the default, actually)
455181834Sroberto     *  THEN call the usage procedure.
456181834Sroberto     */
457181834Sroberto    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
458181834Sroberto        fprintf( stderr, zIllOptChr, pOpts->pzProgPath, optValue );
459181834Sroberto        (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE );
460181834Sroberto    }
461181834Sroberto
462181834Sroberto    return FAILURE;
463181834Sroberto}
464181834Sroberto
465181834Sroberto
466181834Sroberto/*
467181834Sroberto *  findOptDesc
468181834Sroberto *
469181834Sroberto *  Find the option descriptor for the current option
470181834Sroberto */
471181834Srobertostatic tSuccess
472181834SrobertofindOptDesc( tOptions* pOpts, tOptState* pOptState )
473181834Sroberto{
474181834Sroberto    /*
475181834Sroberto     *  IF we are continuing a short option list (e.g. -xyz...)
476181834Sroberto     *  THEN continue a single flag option.
477181834Sroberto     *  OTHERWISE see if there is room to advance and then do so.
478181834Sroberto     */
479181834Sroberto    if ((pOpts->pzCurOpt != NULL) && (*pOpts->pzCurOpt != NUL))
480181834Sroberto        return shortOptionFind( pOpts, (tAoUC)*(pOpts->pzCurOpt), pOptState );
481181834Sroberto
482181834Sroberto    if (pOpts->curOptIdx >= pOpts->origArgCt)
483181834Sroberto        return PROBLEM; /* NORMAL COMPLETION */
484181834Sroberto
485181834Sroberto    pOpts->pzCurOpt = pOpts->origArgVect[ pOpts->curOptIdx ];
486181834Sroberto
487181834Sroberto    /*
488181834Sroberto     *  IF all arguments must be named options, ...
489181834Sroberto     */
490181834Sroberto    if (NAMED_OPTS(pOpts)) {
491181834Sroberto        char* pz = pOpts->pzCurOpt;
492181834Sroberto        pOpts->curOptIdx++;
493181834Sroberto
494181834Sroberto        /*
495181834Sroberto         *  Skip over any flag/option markers.
496181834Sroberto         *  In this mode, they are not required.
497181834Sroberto         */
498181834Sroberto        while (*pz == '-') pz++;
499181834Sroberto
500181834Sroberto        return longOptionFind( pOpts, pz, pOptState );
501181834Sroberto    }
502181834Sroberto
503181834Sroberto    /*
504181834Sroberto     *  Note the kind of flag/option marker
505181834Sroberto     */
506181834Sroberto    if (*((pOpts->pzCurOpt)++) != '-')
507181834Sroberto        return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */
508181834Sroberto
509181834Sroberto    /*
510181834Sroberto     *  Special hack for a hyphen by itself
511181834Sroberto     */
512181834Sroberto    if (*(pOpts->pzCurOpt) == NUL)
513181834Sroberto        return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */
514181834Sroberto
515181834Sroberto    /*
516181834Sroberto     *  The current argument is to be processed as an option argument
517181834Sroberto     */
518181834Sroberto    pOpts->curOptIdx++;
519181834Sroberto
520181834Sroberto    /*
521181834Sroberto     *  We have an option marker.
522181834Sroberto     *  Test the next character for long option indication
523181834Sroberto     */
524181834Sroberto    if (pOpts->pzCurOpt[0] == '-') {
525181834Sroberto        if (*++(pOpts->pzCurOpt) == NUL)
526181834Sroberto            /*
527181834Sroberto             *  NORMAL COMPLETION - NOT this arg, but rest are operands
528181834Sroberto             */
529181834Sroberto            return PROBLEM;
530181834Sroberto
531181834Sroberto        /*
532181834Sroberto         *  We do not allow the hyphen to be used as a flag value.
533181834Sroberto         *  Therefore, if long options are not to be accepted, we punt.
534181834Sroberto         */
535181834Sroberto        if ((pOpts->fOptSet & OPTPROC_LONGOPT) == 0) {
536181834Sroberto            fprintf( stderr, zIllOptStr, pOpts->pzProgPath,
537181834Sroberto                     zIllegal, pOpts->pzCurOpt-2 );
538181834Sroberto            return FAILURE;
539181834Sroberto        }
540181834Sroberto
541181834Sroberto        return longOptionFind( pOpts, pOpts->pzCurOpt, pOptState );
542181834Sroberto    }
543181834Sroberto
544181834Sroberto    /*
545181834Sroberto     *  If short options are not allowed, then do long
546181834Sroberto     *  option processing.  Otherwise the character must be a
547181834Sroberto     *  short (i.e. single character) option.
548181834Sroberto     */
549181834Sroberto    if ((pOpts->fOptSet & OPTPROC_SHORTOPT) != 0)
550181834Sroberto        return shortOptionFind( pOpts, (tAoUC)*(pOpts->pzCurOpt), pOptState );
551181834Sroberto
552181834Sroberto    return longOptionFind( pOpts, pOpts->pzCurOpt, pOptState );
553181834Sroberto}
554181834Sroberto
555181834Sroberto
556181834Sroberto/*
557181834Sroberto *  nextOption
558181834Sroberto *
559181834Sroberto *  Find the option descriptor and option argument (if any) for the
560181834Sroberto *  next command line argument.  DO NOT modify the descriptor.  Put
561181834Sroberto *  all the state in the state argument so that the option can be skipped
562181834Sroberto *  without consequence (side effect).
563181834Sroberto */
564181834Srobertostatic tSuccess
565181834SrobertonextOption( tOptions* pOpts, tOptState* pOptState )
566181834Sroberto{
567181834Sroberto    tSuccess res;
568181834Sroberto    enum { ARG_NONE, ARG_MAY, ARG_MUST } arg_type = ARG_NONE;
569181834Sroberto    teOptArgType at;
570181834Sroberto
571181834Sroberto    res = findOptDesc( pOpts, pOptState );
572181834Sroberto    if (! SUCCESSFUL( res ))
573181834Sroberto        return res;
574181834Sroberto    pOptState->flags |= (pOptState->pOD->fOptState & OPTST_PERSISTENT_MASK);
575181834Sroberto    at = OPTST_GET_ARGTYPE(pOptState->flags);
576181834Sroberto
577181834Sroberto    /*
578181834Sroberto     *  Figure out what to do about option arguments.  An argument may be
579181834Sroberto     *  required, not associated with the option, or be optional.  We detect the
580181834Sroberto     *  latter by examining for an option marker on the next possible argument.
581181834Sroberto     *  Disabled mode option selection also disables option arguments.
582181834Sroberto     */
583181834Sroberto    if ((pOptState->flags & OPTST_DISABLED) != 0)
584181834Sroberto        arg_type = ARG_NONE;
585181834Sroberto    else if (at == OPARG_TYPE_NONE)
586181834Sroberto        arg_type = ARG_NONE;
587181834Sroberto    else if (pOptState->flags & OPTST_ARG_OPTIONAL)
588181834Sroberto        arg_type = ARG_MAY;
589181834Sroberto    else
590181834Sroberto        arg_type = ARG_MUST;
591181834Sroberto
592181834Sroberto    switch (arg_type) {
593181834Sroberto    case ARG_MUST:
594181834Sroberto        /*
595181834Sroberto         *  An option argument is required.  Long options can either have
596181834Sroberto         *  a separate command line argument, or an argument attached by
597181834Sroberto         *  the '=' character.  Figure out which.
598181834Sroberto         */
599181834Sroberto        switch (pOptState->optType) {
600181834Sroberto        case TOPT_SHORT:
601181834Sroberto            /*
602181834Sroberto             *  See if an arg string follows the flag character
603181834Sroberto             */
604181834Sroberto            if (*++(pOpts->pzCurOpt) == NUL)
605181834Sroberto                pOpts->pzCurOpt = pOpts->origArgVect[ pOpts->curOptIdx++ ];
606181834Sroberto            pOptState->pzOptArg = pOpts->pzCurOpt;
607181834Sroberto            break;
608181834Sroberto
609181834Sroberto        case TOPT_LONG:
610181834Sroberto            /*
611181834Sroberto             *  See if an arg string has already been assigned (glued on
612181834Sroberto             *  with an `=' character)
613181834Sroberto             */
614181834Sroberto            if (pOptState->pzOptArg == NULL)
615181834Sroberto                pOptState->pzOptArg = pOpts->origArgVect[ pOpts->curOptIdx++ ];
616181834Sroberto            break;
617181834Sroberto
618181834Sroberto        default:
619181834Sroberto#ifdef DEBUG
620181834Sroberto            fputs( "AutoOpts lib error: option type not selected\n",
621181834Sroberto                   stderr );
622181834Sroberto            exit( EXIT_FAILURE );
623181834Sroberto#endif
624181834Sroberto
625181834Sroberto        case TOPT_DEFAULT:
626181834Sroberto            /*
627181834Sroberto             *  The option was selected by default.  The current token is
628181834Sroberto             *  the option argument.
629181834Sroberto             */
630181834Sroberto            break;
631181834Sroberto        }
632181834Sroberto
633181834Sroberto        /*
634181834Sroberto         *  Make sure we did not overflow the argument list.
635181834Sroberto         */
636181834Sroberto        if (pOpts->curOptIdx > pOpts->origArgCt) {
637181834Sroberto            fprintf( stderr, zMisArg, pOpts->pzProgPath,
638181834Sroberto                     pOptState->pOD->pz_Name );
639181834Sroberto            return FAILURE;
640181834Sroberto        }
641181834Sroberto
642181834Sroberto        pOpts->pzCurOpt = NULL;  /* next time advance to next arg */
643181834Sroberto        break;
644181834Sroberto
645181834Sroberto    case ARG_MAY:
646181834Sroberto        /*
647181834Sroberto         *  An option argument is optional.
648181834Sroberto         */
649181834Sroberto        switch (pOptState->optType) {
650181834Sroberto        case TOPT_SHORT:
651181834Sroberto            if (*++pOpts->pzCurOpt != NUL)
652181834Sroberto                pOptState->pzOptArg = pOpts->pzCurOpt;
653181834Sroberto            else {
654181834Sroberto                char* pzLA = pOpts->origArgVect[ pOpts->curOptIdx ];
655181834Sroberto
656181834Sroberto                /*
657181834Sroberto                 *  BECAUSE it is optional, we must make sure
658181834Sroberto                 *  we did not find another flag and that there
659181834Sroberto                 *  is such an argument.
660181834Sroberto                 */
661181834Sroberto                if ((pzLA == NULL) || (*pzLA == '-'))
662181834Sroberto                    pOptState->pzOptArg = NULL;
663181834Sroberto                else {
664181834Sroberto                    pOpts->curOptIdx++; /* argument found */
665181834Sroberto                    pOptState->pzOptArg = pzLA;
666181834Sroberto                }
667181834Sroberto            }
668181834Sroberto            break;
669181834Sroberto
670181834Sroberto        case TOPT_LONG:
671181834Sroberto            /*
672181834Sroberto             *  Look for an argument if we don't already have one (glued on
673181834Sroberto             *  with a `=' character) *AND* we are not in named argument mode
674181834Sroberto             */
675181834Sroberto            if (  (pOptState->pzOptArg == NULL)
676181834Sroberto               && (! NAMED_OPTS(pOpts))) {
677181834Sroberto                char* pzLA = pOpts->origArgVect[ pOpts->curOptIdx ];
678181834Sroberto
679181834Sroberto                /*
680181834Sroberto                 *  BECAUSE it is optional, we must make sure
681181834Sroberto                 *  we did not find another flag and that there
682181834Sroberto                 *  is such an argument.
683181834Sroberto                 */
684181834Sroberto                if ((pzLA == NULL) || (*pzLA == '-'))
685181834Sroberto                    pOptState->pzOptArg = NULL;
686181834Sroberto                else {
687181834Sroberto                    pOpts->curOptIdx++; /* argument found */
688181834Sroberto                    pOptState->pzOptArg = pzLA;
689181834Sroberto                }
690181834Sroberto            }
691181834Sroberto            break;
692181834Sroberto
693181834Sroberto        default:
694181834Sroberto        case TOPT_DEFAULT:
695181834Sroberto            fputs( "AutoOpts lib error: defaulted to option with optional arg\n",
696181834Sroberto                   stderr );
697181834Sroberto            exit( EX_SOFTWARE );
698181834Sroberto        }
699181834Sroberto
700181834Sroberto        /*
701181834Sroberto         *  After an option with an optional argument, we will
702181834Sroberto         *  *always* start with the next option because if there
703181834Sroberto         *  were any characters following the option name/flag,
704181834Sroberto         *  they would be interpreted as the argument.
705181834Sroberto         */
706181834Sroberto        pOpts->pzCurOpt = NULL;
707181834Sroberto        break;
708181834Sroberto
709181834Sroberto    default: /* CANNOT */
710181834Sroberto        /*
711181834Sroberto         *  No option argument.  Make sure next time around we find
712181834Sroberto         *  the correct option flag character for short options
713181834Sroberto         */
714181834Sroberto        if (pOptState->optType == TOPT_SHORT)
715181834Sroberto            (pOpts->pzCurOpt)++;
716181834Sroberto
717181834Sroberto        /*
718181834Sroberto         *  It is a long option.  Make sure there was no ``=xxx'' argument
719181834Sroberto         */
720181834Sroberto        else if (pOptState->pzOptArg != NULL) {
721181834Sroberto            fprintf( stderr, zNoArg, pOpts->pzProgPath,
722181834Sroberto                     pOptState->pOD->pz_Name );
723181834Sroberto            return FAILURE;
724181834Sroberto        }
725181834Sroberto
726181834Sroberto        /*
727181834Sroberto         *  It is a long option.  Advance to next command line argument.
728181834Sroberto         */
729181834Sroberto        else
730181834Sroberto            pOpts->pzCurOpt = NULL;
731181834Sroberto    }
732181834Sroberto
733181834Sroberto    return SUCCESS;
734181834Sroberto}
735181834Sroberto
736181834Sroberto
737181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
738181834Sroberto *
739181834Sroberto *  DO PRESETS
740181834Sroberto *
741181834Sroberto *  The next several routines do the immediate action pass on the command
742181834Sroberto *  line options, then the environment variables, then the config files in
743181834Sroberto *  reverse order.  Once done with that, the order is reversed and all
744181834Sroberto *  the config files and environment variables are processed again, this
745181834Sroberto *  time only processing the non-immediate action options.  doPresets()
746181834Sroberto *  will then return for optionProcess() to do the final pass on the command
747181834Sroberto *  line arguments.
748181834Sroberto */
749181834Sroberto
750181834Sroberto/*
751181834Sroberto *  doImmediateOpts - scan the command line for immediate action options
752181834Sroberto */
753181834SrobertoLOCAL tSuccess
754181834SrobertodoImmediateOpts( tOptions* pOpts )
755181834Sroberto{
756181834Sroberto    pOpts->curOptIdx = 1;     /* start by skipping program name */
757181834Sroberto    pOpts->pzCurOpt  = NULL;
758181834Sroberto
759181834Sroberto    /*
760181834Sroberto     *  Examine all the options from the start.  We process any options that
761181834Sroberto     *  are marked for immediate processing.
762181834Sroberto     */
763181834Sroberto    for (;;) {
764181834Sroberto        tOptState optState = OPTSTATE_INITIALIZER(PRESET);
765181834Sroberto
766181834Sroberto        switch (nextOption( pOpts, &optState )) {
767181834Sroberto        case FAILURE: goto optionsDone;
768181834Sroberto        case PROBLEM: return SUCCESS; /* no more args */
769181834Sroberto        case SUCCESS: break;
770181834Sroberto        }
771181834Sroberto
772181834Sroberto        /*
773181834Sroberto         *  IF this *is* an immediate-attribute option, then do it.
774181834Sroberto         */
775181834Sroberto        if (! DO_IMMEDIATELY(optState.flags))
776181834Sroberto            continue;
777181834Sroberto
778181834Sroberto        if (! SUCCESSFUL( handleOption( pOpts, &optState )))
779181834Sroberto            break;
780181834Sroberto    } optionsDone:;
781181834Sroberto
782181834Sroberto    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0)
783181834Sroberto        (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE );
784181834Sroberto    return FAILURE;
785181834Sroberto}
786181834Sroberto
787181834Sroberto
788181834SrobertoLOCAL tSuccess
789181834SrobertodoRegularOpts( tOptions* pOpts )
790181834Sroberto{
791181834Sroberto    /*
792181834Sroberto     *  Now, process all the options from our current position onward.
793181834Sroberto     *  (This allows interspersed options and arguments for the few
794181834Sroberto     *  non-standard programs that require it.)
795181834Sroberto     */
796181834Sroberto    for (;;) {
797181834Sroberto        tOptState optState = OPTSTATE_INITIALIZER(DEFINED);
798181834Sroberto
799181834Sroberto        switch (nextOption( pOpts, &optState )) {
800181834Sroberto        case FAILURE: goto optionsDone;
801181834Sroberto        case PROBLEM: return SUCCESS; /* no more args */
802181834Sroberto        case SUCCESS: break;
803181834Sroberto        }
804181834Sroberto
805181834Sroberto        /*
806181834Sroberto         *  IF this is not being processed normally (i.e. is immediate action)
807181834Sroberto         *  THEN skip it (unless we are supposed to do it a second time).
808181834Sroberto         */
809181834Sroberto        if (! DO_NORMALLY(optState.flags)) {
810181834Sroberto            if (! DO_SECOND_TIME(optState.flags))
811181834Sroberto                continue;
812181834Sroberto            optState.pOD->optOccCt--; /* don't count last time */
813181834Sroberto        }
814181834Sroberto
815181834Sroberto        if (! SUCCESSFUL( handleOption( pOpts, &optState )))
816181834Sroberto            break;
817181834Sroberto    } optionsDone:;
818181834Sroberto    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0)
819181834Sroberto        (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE );
820181834Sroberto    return FAILURE;
821181834Sroberto}
822181834Sroberto
823181834Sroberto
824181834Sroberto/*
825181834Sroberto *  doPresets - check for preset values from a config file or the envrionment
826181834Sroberto */
827181834Srobertostatic tSuccess
828181834SrobertodoPresets( tOptions* pOpts )
829181834Sroberto{
830181834Sroberto    tOptDesc * pOD = NULL;
831181834Sroberto
832181834Sroberto    if (! SUCCESSFUL( doImmediateOpts( pOpts )))
833181834Sroberto        return FAILURE;
834181834Sroberto
835181834Sroberto    /*
836181834Sroberto     *  IF this option set has a --save-opts option, then it also
837181834Sroberto     *  has a --load-opts option.  See if a command line option has disabled
838181834Sroberto     *  option presetting.
839181834Sroberto     */
840181834Sroberto    if (pOpts->specOptIdx.save_opts != 0) {
841181834Sroberto        pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts + 1;
842181834Sroberto        if (DISABLED_OPT(pOD))
843181834Sroberto            return SUCCESS;
844181834Sroberto    }
845181834Sroberto
846181834Sroberto    /*
847181834Sroberto     *  Until we return from this procedure, disable non-presettable opts
848181834Sroberto     */
849181834Sroberto    pOpts->fOptSet |= OPTPROC_PRESETTING;
850181834Sroberto    /*
851181834Sroberto     *  IF there are no config files,
852181834Sroberto     *  THEN do any environment presets and leave.
853181834Sroberto     */
854181834Sroberto    if (pOpts->papzHomeList == NULL) {
855181834Sroberto        doEnvPresets( pOpts, ENV_ALL );
856181834Sroberto    }
857181834Sroberto    else {
858181834Sroberto        doEnvPresets( pOpts, ENV_IMM );
859181834Sroberto
860181834Sroberto        /*
861181834Sroberto         *  Check to see if environment variables have disabled presetting.
862181834Sroberto         */
863181834Sroberto        if ((pOD != NULL) && ! DISABLED_OPT(pOD))
864181834Sroberto            internalFileLoad( pOpts );
865181834Sroberto
866181834Sroberto        /*
867181834Sroberto         *  ${PROGRAM_LOAD_OPTS} value of "no" cannot disable other environment
868181834Sroberto         *  variable options.  Only the loading of .rc files.
869181834Sroberto         */
870181834Sroberto        doEnvPresets( pOpts, ENV_NON_IMM );
871181834Sroberto    }
872181834Sroberto    pOpts->fOptSet &= ~OPTPROC_PRESETTING;
873181834Sroberto
874181834Sroberto    return SUCCESS;
875181834Sroberto}
876181834Sroberto
877181834Sroberto
878181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
879181834Sroberto *
880181834Sroberto *  VERIFY OPTION CONSISTENCY
881181834Sroberto *
882181834Sroberto *  Make sure that the argument list passes our consistency tests.
883181834Sroberto */
884181834Srobertostatic int
885181834SrobertocheckConsistency( tOptions* pOpts )
886181834Sroberto{
887181834Sroberto    int        errCt = 0;
888181834Sroberto    tOptDesc*  pOD   = pOpts->pOptDesc;
889181834Sroberto    int        oCt   = pOpts->presetOptCt;
890181834Sroberto
891181834Sroberto    /*
892181834Sroberto     *  FOR each of "oCt" options, ...
893181834Sroberto     */
894181834Sroberto    for (;;) {
895181834Sroberto        const int*  pMust = pOD->pOptMust;
896181834Sroberto        const int*  pCant = pOD->pOptCant;
897181834Sroberto
898181834Sroberto        /*
899181834Sroberto         *  IF the current option was provided on the command line
900181834Sroberto         *  THEN ensure that any "MUST" requirements are not
901181834Sroberto         *       "DEFAULT" (unspecified) *AND* ensure that any
902181834Sroberto         *       "CANT" options have not been SET or DEFINED.
903181834Sroberto         */
904181834Sroberto        if (SELECTED_OPT(pOD)) {
905181834Sroberto            if (pMust != NULL) for (;;) {
906181834Sroberto                tOptDesc*  p = pOpts->pOptDesc + *(pMust++);
907181834Sroberto                if (UNUSED_OPT(p)) {
908181834Sroberto                    const tOptDesc* pN = pOpts->pOptDesc + pMust[-1];
909181834Sroberto                    errCt++;
910181834Sroberto                    fprintf( stderr, zReqFmt, pOD->pz_Name, pN->pz_Name );
911181834Sroberto                }
912181834Sroberto
913181834Sroberto                if (*pMust == NO_EQUIVALENT)
914181834Sroberto                    break;
915181834Sroberto            }
916181834Sroberto
917181834Sroberto            if (pCant != NULL) for (;;) {
918181834Sroberto                tOptDesc*  p = pOpts->pOptDesc + *(pCant++);
919181834Sroberto                if (SELECTED_OPT(p)) {
920181834Sroberto                    const tOptDesc* pN = pOpts->pOptDesc + pCant[-1];
921181834Sroberto                    errCt++;
922181834Sroberto                    fprintf( stderr, zCantFmt, pOD->pz_Name, pN->pz_Name );
923181834Sroberto                }
924181834Sroberto
925181834Sroberto                if (*pCant == NO_EQUIVALENT)
926181834Sroberto                    break;
927181834Sroberto            }
928181834Sroberto        }
929181834Sroberto
930181834Sroberto        /*
931181834Sroberto         *  IF       this option is not equivalenced to another,
932181834Sroberto         *        OR it is equivalenced to itself (is the equiv. root)
933181834Sroberto         *  THEN we need to make sure it occurs often enough.
934181834Sroberto         */
935181834Sroberto        if (  (pOD->optEquivIndex == NO_EQUIVALENT)
936181834Sroberto           || (pOD->optEquivIndex == pOD->optIndex) )   do {
937181834Sroberto            /*
938181834Sroberto             *  IF the occurrence counts have been satisfied,
939181834Sroberto             *  THEN there is no problem.
940181834Sroberto             */
941181834Sroberto            if (pOD->optOccCt >= pOD->optMinCt)
942181834Sroberto                break;
943181834Sroberto
944181834Sroberto            /*
945181834Sroberto             *  IF MUST_SET means SET and PRESET are okay,
946181834Sroberto             *  so min occurrence count doesn't count
947181834Sroberto             */
948181834Sroberto            if (  (pOD->fOptState & OPTST_MUST_SET)
949181834Sroberto               && (pOD->fOptState & (OPTST_PRESET | OPTST_SET)) )
950181834Sroberto                break;
951181834Sroberto
952181834Sroberto            errCt++;
953181834Sroberto            if (pOD->optMinCt > 1)
954181834Sroberto                 fprintf( stderr, zNotEnough, pOD->pz_Name, pOD->optMinCt );
955181834Sroberto            else fprintf( stderr, zNeedOne, pOD->pz_Name );
956181834Sroberto        } while (0);
957181834Sroberto
958181834Sroberto        if (--oCt <= 0)
959181834Sroberto            break;
960181834Sroberto        pOD++;
961181834Sroberto    }
962181834Sroberto
963181834Sroberto    /*
964181834Sroberto     *  IF we are stopping on errors, check to see if any remaining
965181834Sroberto     *  arguments are required to be there or prohibited from being there.
966181834Sroberto     */
967181834Sroberto    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
968181834Sroberto
969181834Sroberto        /*
970181834Sroberto         *  Check for prohibition
971181834Sroberto         */
972181834Sroberto        if ((pOpts->fOptSet & OPTPROC_NO_ARGS) != 0) {
973181834Sroberto            if (pOpts->origArgCt > pOpts->curOptIdx) {
974181834Sroberto                fprintf( stderr, zNoArgs, pOpts->pzProgName );
975181834Sroberto                ++errCt;
976181834Sroberto            }
977181834Sroberto        }
978181834Sroberto
979181834Sroberto        /*
980181834Sroberto         *  ELSE not prohibited, check for being required
981181834Sroberto         */
982181834Sroberto        else if ((pOpts->fOptSet & OPTPROC_ARGS_REQ) != 0) {
983181834Sroberto            if (pOpts->origArgCt <= pOpts->curOptIdx) {
984181834Sroberto                fprintf( stderr, zArgsMust, pOpts->pzProgName );
985181834Sroberto                ++errCt;
986181834Sroberto            }
987181834Sroberto        }
988181834Sroberto    }
989181834Sroberto
990181834Sroberto    return errCt;
991181834Sroberto}
992181834Sroberto
993181834Sroberto
994181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
995181834Sroberto *
996181834Sroberto *  THESE ROUTINES ARE CALLABLE FROM THE GENERATED OPTION PROCESSING CODE
997181834Sroberto */
998181834Sroberto/*=--subblock=arg=arg_type,arg_name,arg_desc =*/
999181834Sroberto/*=*
1000181834Sroberto * library:  opts
1001181834Sroberto * header:   your-opts.h
1002181834Sroberto *
1003181834Sroberto * lib_description:
1004181834Sroberto *
1005181834Sroberto *  These are the routines that libopts users may call directly from their
1006181834Sroberto *  code.  There are several other routines that can be called by code
1007181834Sroberto *  generated by the libopts option templates, but they are not to be
1008181834Sroberto *  called from any other user code.  The @file{options.h} header is
1009181834Sroberto *  fairly clear about this, too.
1010181834Sroberto=*/
1011181834Sroberto
1012181834Sroberto/*=export_func optionProcess
1013181834Sroberto *
1014181834Sroberto * what: this is the main option processing routine
1015181834Sroberto *
1016181834Sroberto * arg:  + tOptions* + pOpts + program options descriptor +
1017181834Sroberto * arg:  + int       + argc  + program arg count  +
1018181834Sroberto * arg:  + char**    + argv  + program arg vector +
1019181834Sroberto *
1020181834Sroberto * ret_type:  int
1021181834Sroberto * ret_desc:  the count of the arguments processed
1022181834Sroberto *
1023181834Sroberto * doc:
1024181834Sroberto *
1025181834Sroberto * This is the main entry point for processing options.  It is intended
1026181834Sroberto * that this procedure be called once at the beginning of the execution of
1027181834Sroberto * a program.  Depending on options selected earlier, it is sometimes
1028181834Sroberto * necessary to stop and restart option processing, or to select completely
1029181834Sroberto * different sets of options.  This can be done easily, but you generally
1030181834Sroberto * do not want to do this.
1031181834Sroberto *
1032181834Sroberto * The number of arguments processed always includes the program name.
1033181834Sroberto * If one of the arguments is "--", then it is counted and the processing
1034181834Sroberto * stops.  If an error was encountered and errors are to be tolerated, then
1035181834Sroberto * the returned value is the index of the argument causing the error.
1036181834Sroberto * A hyphen by itself ("-") will also cause processing to stop and will
1037181834Sroberto * @emph{not} be counted among the processed arguments.  A hyphen by itself
1038181834Sroberto * is treated as an operand.  Encountering an operand stops option
1039181834Sroberto * processing.
1040181834Sroberto *
1041181834Sroberto * err:  Errors will cause diagnostics to be printed.  @code{exit(3)} may
1042181834Sroberto *       or may not be called.  It depends upon whether or not the options
1043181834Sroberto *       were generated with the "allow-errors" attribute, or if the
1044181834Sroberto *       ERRSKIP_OPTERR or ERRSTOP_OPTERR macros were invoked.
1045181834Sroberto=*/
1046181834Srobertoint
1047181834SrobertooptionProcess(
1048181834Sroberto    tOptions*  pOpts,
1049181834Sroberto    int        argCt,
1050181834Sroberto    char**     argVect )
1051181834Sroberto{
1052181834Sroberto    if (! SUCCESSFUL( validateOptionsStruct( pOpts, argVect[0] )))
1053181834Sroberto        exit( EX_SOFTWARE );
1054181834Sroberto
1055181834Sroberto    /*
1056181834Sroberto     *  Establish the real program name, the program full path,
1057181834Sroberto     *  and do all the presetting the first time thru only.
1058181834Sroberto     */
1059181834Sroberto    if ((pOpts->fOptSet & OPTPROC_INITDONE) == 0) {
1060181834Sroberto        pOpts->origArgCt   = argCt;
1061181834Sroberto        pOpts->origArgVect = argVect;
1062181834Sroberto        pOpts->fOptSet    |= OPTPROC_INITDONE;
1063181834Sroberto
1064181834Sroberto        if (! SUCCESSFUL( doPresets( pOpts )))
1065181834Sroberto            return 0;
1066181834Sroberto
1067181834Sroberto        if ((pOpts->fOptSet & OPTPROC_REORDER) != 0)
1068181834Sroberto            optionSort( pOpts );
1069181834Sroberto
1070181834Sroberto        pOpts->curOptIdx   = 1;
1071181834Sroberto        pOpts->pzCurOpt    = NULL;
1072181834Sroberto    }
1073181834Sroberto
1074181834Sroberto    /*
1075181834Sroberto     *  IF we are (re)starting,
1076181834Sroberto     *  THEN reset option location
1077181834Sroberto     */
1078181834Sroberto    else if (pOpts->curOptIdx <= 0) {
1079181834Sroberto        pOpts->curOptIdx = 1;
1080181834Sroberto        pOpts->pzCurOpt  = NULL;
1081181834Sroberto    }
1082181834Sroberto
1083181834Sroberto    if (! SUCCESSFUL( doRegularOpts( pOpts )))
1084181834Sroberto        return pOpts->origArgCt;
1085181834Sroberto
1086181834Sroberto    /*
1087181834Sroberto     *  IF    there were no errors
1088181834Sroberto     *    AND we have RC/INI files
1089181834Sroberto     *    AND there is a request to save the files
1090181834Sroberto     *  THEN do that now before testing for conflicts.
1091181834Sroberto     *       (conflicts are ignored in preset options)
1092181834Sroberto     */
1093181834Sroberto    if (pOpts->specOptIdx.save_opts != 0) {
1094181834Sroberto        tOptDesc*  pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts;
1095181834Sroberto
1096181834Sroberto        if (SELECTED_OPT( pOD )) {
1097181834Sroberto            optionSaveFile( pOpts );
1098181834Sroberto            exit( EXIT_SUCCESS );
1099181834Sroberto        }
1100181834Sroberto    }
1101181834Sroberto
1102181834Sroberto    /*
1103181834Sroberto     *  IF we are checking for errors,
1104181834Sroberto     *  THEN look for too few occurrences of required options
1105181834Sroberto     */
1106181834Sroberto    if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
1107181834Sroberto        if (checkConsistency( pOpts ) != 0)
1108181834Sroberto            (*pOpts->pUsageProc)( pOpts, EXIT_FAILURE );
1109181834Sroberto    }
1110181834Sroberto
1111181834Sroberto    return pOpts->curOptIdx;
1112181834Sroberto}
1113181834Sroberto
1114181834Sroberto/*
1115181834Sroberto * Local Variables:
1116181834Sroberto * mode: C
1117181834Sroberto * c-file-style: "stroustrup"
1118181834Sroberto * indent-tabs-mode: nil
1119181834Sroberto * End:
1120181834Sroberto * end of autoopts/autoopts.c */
1121