1181834Sroberto
2280849Scy/**
3280849Scy * \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.
7280849Scy *
8280849Scy * @addtogroup autoopts
9280849Scy * @{
10181834Sroberto */
11181834Sroberto/*
12280849Scy *  This file is part of AutoOpts, a companion to AutoGen.
13280849Scy *  AutoOpts is free software.
14285169Scy *  AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved
15181834Sroberto *
16280849Scy *  AutoOpts is available under any one of two licenses.  The license
17280849Scy *  in use must be one of these two and the choice is under the control
18280849Scy *  of the user of the license.
19181834Sroberto *
20280849Scy *   The GNU Lesser General Public License, version 3 or later
21280849Scy *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
22181834Sroberto *
23280849Scy *   The Modified Berkeley Software Distribution License
24280849Scy *      See the file "COPYING.mbsd"
25181834Sroberto *
26280849Scy *  These files have the following sha256 sums:
27181834Sroberto *
28280849Scy *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
29280849Scy *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
30280849Scy *  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
41285169Scy * arg:   + tOptions * + opts + program options descriptor +
42285169Scy * arg:   + tOptDesc * + od   + the descriptor for this arg +
43181834Sroberto *
44181834Sroberto * doc:
45181834Sroberto *  Invoked for options that are equivalenced to stacked options.
46181834Sroberto=*/
47181834Srobertovoid
48280849ScyoptionUnstackArg(tOptions * opts, tOptDesc * od)
49181834Sroberto{
50280849Scy    tArgList * arg_list;
51181834Sroberto
52280849Scy    if (INQUERY_CALL(opts, od))
53280849Scy        return;
54280849Scy
55285169Scy    arg_list = (tArgList *)od->optCookie;
56280849Scy
57181834Sroberto    /*
58181834Sroberto     *  IF we don't have any stacked options,
59181834Sroberto     *  THEN indicate that we don't have any of these options
60181834Sroberto     */
61280849Scy    if (arg_list == NULL) {
62280849Scy        od->fOptState &= OPTST_PERSISTENT_MASK;
63280849Scy        if ((od->fOptState & OPTST_INITENABLED) == 0)
64280849Scy            od->fOptState |= OPTST_DISABLED;
65181834Sroberto        return;
66181834Sroberto    }
67181834Sroberto
68181834Sroberto#ifdef WITH_LIBREGEX
69181834Sroberto    {
70181834Sroberto        regex_t   re;
71181834Sroberto        int       i, ct, dIdx;
72181834Sroberto
73280849Scy        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         */
82280849Scy        for (i = 0, dIdx = 0, ct = arg_list->useCt; --ct >= 0; i++) {
83280849Scy            char const * pzSrc = arg_list->apzArgs[ i ];
84280849Scy            char *       pzEq  = strchr(pzSrc, '=');
85280849Scy            int          res;
86181834Sroberto
87280849Scy
88181834Sroberto            if (pzEq != NULL)
89181834Sroberto                *pzEq = NUL;
90181834Sroberto
91280849Scy            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);
100280849Scy                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)
113280849Scy                    arg_list->apzArgs[ dIdx ] = pzSrc;
114181834Sroberto                dIdx++;
115181834Sroberto            }
116181834Sroberto        }
117181834Sroberto
118280849Scy        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         */
130280849Scy        for (i = 0, dIdx = 0, ct = arg_list->useCt; --ct >= 0; i++) {
131280849Scy            const char * pzSrc = arg_list->apzArgs[ i ];
132280849Scy            char *       pzEq  = strchr(pzSrc, '=');
133181834Sroberto
134181834Sroberto            if (pzEq != NULL)
135181834Sroberto                *pzEq = NUL;
136181834Sroberto
137280849Scy            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);
144280849Scy                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)
154280849Scy                    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     */
164280849Scy    if (arg_list->useCt == 0) {
165280849Scy        od->fOptState &= OPTST_PERSISTENT_MASK;
166280849Scy        if ((od->fOptState & OPTST_INITENABLED) == 0)
167280849Scy            od->fOptState |= OPTST_DISABLED;
168285169Scy        AGFREE(arg_list);
169280849Scy        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
180280849ScyaddArgListEntry(void ** ppAL, void * entry)
181181834Sroberto{
182285169Scy    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) {
189285169Scy        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;
194285169Scy        *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) {
202280849Scy        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         */
209285169Scy        sz += sizeof(char *) * ((size_t)pAL->allocCt - MIN_ARG_ALLOC_CT);
210285169Scy        pAL = (tArgList *)AGREALOC(VOIDP(pAL), sz, "expanded opt arg stack");
211181834Sroberto        if (pAL == NULL)
212181834Sroberto            return;
213285169Scy        *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
227285169Scy * arg:   + tOptions * + opts + program options descriptor +
228285169Scy * arg:   + tOptDesc * + od   + the descriptor for this arg +
229181834Sroberto *
230181834Sroberto * doc:
231181834Sroberto *  Keep an entry-ordered list of option arguments.
232181834Sroberto=*/
233181834Srobertovoid
234280849ScyoptionStackArg(tOptions * opts, tOptDesc * od)
235181834Sroberto{
236181834Sroberto    char * pz;
237181834Sroberto
238280849Scy    if (INQUERY_CALL(opts, od))
239181834Sroberto        return;
240181834Sroberto
241280849Scy    if ((od->fOptState & OPTST_RESET) != 0) {
242285169Scy        tArgList * arg_list = od->optCookie;
243280849Scy        int ix;
244280849Scy        if (arg_list == NULL)
245280849Scy            return;
246280849Scy
247280849Scy        ix = arg_list->useCt;
248280849Scy        while (--ix >= 0)
249280849Scy            AGFREE(arg_list->apzArgs[ix]);
250280849Scy        AGFREE(arg_list);
251280849Scy
252280849Scy    } else {
253280849Scy        if (od->optArg.argString == NULL)
254280849Scy            return;
255280849Scy
256280849Scy        AGDUPSTR(pz, od->optArg.argString, "stack arg");
257285169Scy        addArgListEntry(&(od->optCookie), VOIDP(pz));
258280849Scy    }
259181834Sroberto}
260280849Scy/** @}
261280849Scy *
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