1181834Sroberto
2285612Sdelphij/**
3285612Sdelphij * \file stack.c
4181834Sroberto *
5181834Sroberto *  This is a special option processing routine that will save the
6181834Sroberto *  argument to an option in a FIFO queue.
7285612Sdelphij *
8285612Sdelphij * @addtogroup autoopts
9285612Sdelphij * @{
10181834Sroberto */
11181834Sroberto/*
12285612Sdelphij *  This file is part of AutoOpts, a companion to AutoGen.
13285612Sdelphij *  AutoOpts is free software.
14285612Sdelphij *  AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved
15181834Sroberto *
16285612Sdelphij *  AutoOpts is available under any one of two licenses.  The license
17285612Sdelphij *  in use must be one of these two and the choice is under the control
18285612Sdelphij *  of the user of the license.
19181834Sroberto *
20285612Sdelphij *   The GNU Lesser General Public License, version 3 or later
21285612Sdelphij *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
22181834Sroberto *
23285612Sdelphij *   The Modified Berkeley Software Distribution License
24285612Sdelphij *      See the file "COPYING.mbsd"
25181834Sroberto *
26285612Sdelphij *  These files have the following sha256 sums:
27181834Sroberto *
28285612Sdelphij *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
29285612Sdelphij *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
30285612Sdelphij *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
31181834Sroberto */
32181834Sroberto
33181834Sroberto#ifdef WITH_LIBREGEX
34181834Sroberto#  include REGEX_HEADER
35181834Sroberto#endif
36181834Sroberto
37181834Sroberto/*=export_func  optionUnstackArg
38181834Sroberto * private:
39181834Sroberto *
40181834Sroberto * what:  Remove option args from a stack
41285612Sdelphij * arg:   + tOptions * + opts + program options descriptor +
42285612Sdelphij * arg:   + tOptDesc * + od   + the descriptor for this arg +
43181834Sroberto *
44181834Sroberto * doc:
45181834Sroberto *  Invoked for options that are equivalenced to stacked options.
46181834Sroberto=*/
47181834Srobertovoid
48285612SdelphijoptionUnstackArg(tOptions * opts, tOptDesc * od)
49181834Sroberto{
50285612Sdelphij    tArgList * arg_list;
51181834Sroberto
52285612Sdelphij    if (INQUERY_CALL(opts, od))
53285612Sdelphij        return;
54285612Sdelphij
55285612Sdelphij    arg_list = (tArgList *)od->optCookie;
56285612Sdelphij
57181834Sroberto    /*
58181834Sroberto     *  IF we don't have any stacked options,
59181834Sroberto     *  THEN indicate that we don't have any of these options
60181834Sroberto     */
61285612Sdelphij    if (arg_list == NULL) {
62285612Sdelphij        od->fOptState &= OPTST_PERSISTENT_MASK;
63285612Sdelphij        if ((od->fOptState & OPTST_INITENABLED) == 0)
64285612Sdelphij            od->fOptState |= OPTST_DISABLED;
65181834Sroberto        return;
66181834Sroberto    }
67181834Sroberto
68181834Sroberto#ifdef WITH_LIBREGEX
69181834Sroberto    {
70181834Sroberto        regex_t   re;
71181834Sroberto        int       i, ct, dIdx;
72181834Sroberto
73285612Sdelphij        if (regcomp(&re, od->optArg.argString, REG_NOSUB) != 0)
74181834Sroberto            return;
75181834Sroberto
76181834Sroberto        /*
77181834Sroberto         *  search the list for the entry(s) to remove.  Entries that
78181834Sroberto         *  are removed are *not* copied into the result.  The source
79181834Sroberto         *  index is incremented every time.  The destination only when
80181834Sroberto         *  we are keeping a define.
81181834Sroberto         */
82285612Sdelphij        for (i = 0, dIdx = 0, ct = arg_list->useCt; --ct >= 0; i++) {
83285612Sdelphij            char const * pzSrc = arg_list->apzArgs[ i ];
84285612Sdelphij            char *       pzEq  = strchr(pzSrc, '=');
85285612Sdelphij            int          res;
86181834Sroberto
87285612Sdelphij
88181834Sroberto            if (pzEq != NULL)
89181834Sroberto                *pzEq = NUL;
90181834Sroberto
91285612Sdelphij            res = regexec(&re, pzSrc, (size_t)0, NULL, 0);
92181834Sroberto            switch (res) {
93181834Sroberto            case 0:
94181834Sroberto                /*
95181834Sroberto                 *  Remove this entry by reducing the in-use count
96181834Sroberto                 *  and *not* putting the string pointer back into
97181834Sroberto                 *  the list.
98181834Sroberto                 */
99181834Sroberto                AGFREE(pzSrc);
100285612Sdelphij                arg_list->useCt--;
101181834Sroberto                break;
102181834Sroberto
103181834Sroberto            default:
104181834Sroberto            case REG_NOMATCH:
105181834Sroberto                if (pzEq != NULL)
106181834Sroberto                    *pzEq = '=';
107181834Sroberto
108181834Sroberto                /*
109181834Sroberto                 *  IF we have dropped an entry
110181834Sroberto                 *  THEN we have to move the current one.
111181834Sroberto                 */
112181834Sroberto                if (dIdx != i)
113285612Sdelphij                    arg_list->apzArgs[ dIdx ] = pzSrc;
114181834Sroberto                dIdx++;
115181834Sroberto            }
116181834Sroberto        }
117181834Sroberto
118285612Sdelphij        regfree(&re);
119181834Sroberto    }
120181834Sroberto#else  /* not WITH_LIBREGEX */
121181834Sroberto    {
122181834Sroberto        int i, ct, dIdx;
123181834Sroberto
124181834Sroberto        /*
125181834Sroberto         *  search the list for the entry(s) to remove.  Entries that
126181834Sroberto         *  are removed are *not* copied into the result.  The source
127181834Sroberto         *  index is incremented every time.  The destination only when
128181834Sroberto         *  we are keeping a define.
129181834Sroberto         */
130285612Sdelphij        for (i = 0, dIdx = 0, ct = arg_list->useCt; --ct >= 0; i++) {
131285612Sdelphij            const char * pzSrc = arg_list->apzArgs[ i ];
132285612Sdelphij            char *       pzEq  = strchr(pzSrc, '=');
133181834Sroberto
134181834Sroberto            if (pzEq != NULL)
135181834Sroberto                *pzEq = NUL;
136181834Sroberto
137285612Sdelphij            if (strcmp(pzSrc, od->optArg.argString) == 0) {
138181834Sroberto                /*
139181834Sroberto                 *  Remove this entry by reducing the in-use count
140181834Sroberto                 *  and *not* putting the string pointer back into
141181834Sroberto                 *  the list.
142181834Sroberto                 */
143181834Sroberto                AGFREE(pzSrc);
144285612Sdelphij                arg_list->useCt--;
145181834Sroberto            } else {
146181834Sroberto                if (pzEq != NULL)
147181834Sroberto                    *pzEq = '=';
148181834Sroberto
149181834Sroberto                /*
150181834Sroberto                 *  IF we have dropped an entry
151181834Sroberto                 *  THEN we have to move the current one.
152181834Sroberto                 */
153181834Sroberto                if (dIdx != i)
154285612Sdelphij                    arg_list->apzArgs[ dIdx ] = pzSrc;
155181834Sroberto                dIdx++;
156181834Sroberto            }
157181834Sroberto        }
158181834Sroberto    }
159181834Sroberto#endif /* WITH_LIBREGEX */
160181834Sroberto    /*
161181834Sroberto     *  IF we have unstacked everything,
162181834Sroberto     *  THEN indicate that we don't have any of these options
163181834Sroberto     */
164285612Sdelphij    if (arg_list->useCt == 0) {
165285612Sdelphij        od->fOptState &= OPTST_PERSISTENT_MASK;
166285612Sdelphij        if ((od->fOptState & OPTST_INITENABLED) == 0)
167285612Sdelphij            od->fOptState |= OPTST_DISABLED;
168285612Sdelphij        AGFREE(arg_list);
169285612Sdelphij        od->optCookie = NULL;
170181834Sroberto    }
171181834Sroberto}
172181834Sroberto
173181834Sroberto
174181834Sroberto/*
175181834Sroberto *  Put an entry into an argument list.  The first argument points to
176181834Sroberto *  a pointer to the argument list structure.  It gets passed around
177181834Sroberto *  as an opaque address.
178181834Sroberto */
179181834SrobertoLOCAL void
180285612SdelphijaddArgListEntry(void ** ppAL, void * entry)
181181834Sroberto{
182285612Sdelphij    tArgList * pAL = *(void **)ppAL;
183181834Sroberto
184181834Sroberto    /*
185181834Sroberto     *  IF we have never allocated one of these,
186181834Sroberto     *  THEN allocate one now
187181834Sroberto     */
188181834Sroberto    if (pAL == NULL) {
189285612Sdelphij        pAL = (tArgList *)AGALOC(sizeof(*pAL), "new option arg stack");
190181834Sroberto        if (pAL == NULL)
191181834Sroberto            return;
192181834Sroberto        pAL->useCt   = 0;
193181834Sroberto        pAL->allocCt = MIN_ARG_ALLOC_CT;
194285612Sdelphij        *ppAL = VOIDP(pAL);
195181834Sroberto    }
196181834Sroberto
197181834Sroberto    /*
198181834Sroberto     *  ELSE if we are out of room
199181834Sroberto     *  THEN make it bigger
200181834Sroberto     */
201181834Sroberto    else if (pAL->useCt >= pAL->allocCt) {
202285612Sdelphij        size_t sz = sizeof(*pAL);
203181834Sroberto        pAL->allocCt += INCR_ARG_ALLOC_CT;
204181834Sroberto
205181834Sroberto        /*
206181834Sroberto         *  The base structure contains space for MIN_ARG_ALLOC_CT
207181834Sroberto         *  pointers.  We subtract it off to find our augment size.
208181834Sroberto         */
209285612Sdelphij        sz += sizeof(char *) * ((size_t)pAL->allocCt - MIN_ARG_ALLOC_CT);
210285612Sdelphij        pAL = (tArgList *)AGREALOC(VOIDP(pAL), sz, "expanded opt arg stack");
211181834Sroberto        if (pAL == NULL)
212181834Sroberto            return;
213285612Sdelphij        *ppAL = VOIDP(pAL);
214181834Sroberto    }
215181834Sroberto
216181834Sroberto    /*
217181834Sroberto     *  Insert the new argument into the list
218181834Sroberto     */
219181834Sroberto    pAL->apzArgs[ (pAL->useCt)++ ] = entry;
220181834Sroberto}
221181834Sroberto
222181834Sroberto
223181834Sroberto/*=export_func  optionStackArg
224181834Sroberto * private:
225181834Sroberto *
226181834Sroberto * what:  put option args on a stack
227285612Sdelphij * arg:   + tOptions * + opts + program options descriptor +
228285612Sdelphij * arg:   + tOptDesc * + od   + the descriptor for this arg +
229181834Sroberto *
230181834Sroberto * doc:
231181834Sroberto *  Keep an entry-ordered list of option arguments.
232181834Sroberto=*/
233181834Srobertovoid
234285612SdelphijoptionStackArg(tOptions * opts, tOptDesc * od)
235181834Sroberto{
236181834Sroberto    char * pz;
237181834Sroberto
238285612Sdelphij    if (INQUERY_CALL(opts, od))
239181834Sroberto        return;
240181834Sroberto
241285612Sdelphij    if ((od->fOptState & OPTST_RESET) != 0) {
242285612Sdelphij        tArgList * arg_list = od->optCookie;
243285612Sdelphij        int ix;
244285612Sdelphij        if (arg_list == NULL)
245285612Sdelphij            return;
246285612Sdelphij
247285612Sdelphij        ix = arg_list->useCt;
248285612Sdelphij        while (--ix >= 0)
249285612Sdelphij            AGFREE(arg_list->apzArgs[ix]);
250285612Sdelphij        AGFREE(arg_list);
251285612Sdelphij
252285612Sdelphij    } else {
253285612Sdelphij        if (od->optArg.argString == NULL)
254285612Sdelphij            return;
255285612Sdelphij
256285612Sdelphij        AGDUPSTR(pz, od->optArg.argString, "stack arg");
257285612Sdelphij        addArgListEntry(&(od->optCookie), VOIDP(pz));
258285612Sdelphij    }
259181834Sroberto}
260285612Sdelphij/** @}
261285612Sdelphij *
262181834Sroberto * Local Variables:
263181834Sroberto * mode: C
264181834Sroberto * c-file-style: "stroustrup"
265181834Sroberto * indent-tabs-mode: nil
266181834Sroberto * End:
267181834Sroberto * end of autoopts/stack.c */
268