1181834Sroberto
2290000Sglebius/**
3290000Sglebius * \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.
7290000Sglebius *
8290000Sglebius * @addtogroup autoopts
9290000Sglebius * @{
10181834Sroberto */
11181834Sroberto/*
12290000Sglebius *  This file is part of AutoOpts, a companion to AutoGen.
13290000Sglebius *  AutoOpts is free software.
14290000Sglebius *  AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved
15181834Sroberto *
16290000Sglebius *  AutoOpts is available under any one of two licenses.  The license
17290000Sglebius *  in use must be one of these two and the choice is under the control
18290000Sglebius *  of the user of the license.
19181834Sroberto *
20290000Sglebius *   The GNU Lesser General Public License, version 3 or later
21290000Sglebius *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
22181834Sroberto *
23290000Sglebius *   The Modified Berkeley Software Distribution License
24290000Sglebius *      See the file "COPYING.mbsd"
25181834Sroberto *
26290000Sglebius *  These files have the following sha256 sums:
27181834Sroberto *
28290000Sglebius *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
29290000Sglebius *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
30290000Sglebius *  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
41290000Sglebius * arg:   + tOptions * + opts + program options descriptor +
42290000Sglebius * arg:   + tOptDesc * + od   + the descriptor for this arg +
43181834Sroberto *
44181834Sroberto * doc:
45181834Sroberto *  Invoked for options that are equivalenced to stacked options.
46181834Sroberto=*/
47181834Srobertovoid
48290000SglebiusoptionUnstackArg(tOptions * opts, tOptDesc * od)
49181834Sroberto{
50290000Sglebius    tArgList * arg_list;
51181834Sroberto
52290000Sglebius    if (INQUERY_CALL(opts, od))
53290000Sglebius        return;
54290000Sglebius
55290000Sglebius    arg_list = (tArgList *)od->optCookie;
56290000Sglebius
57181834Sroberto    /*
58181834Sroberto     *  IF we don't have any stacked options,
59181834Sroberto     *  THEN indicate that we don't have any of these options
60181834Sroberto     */
61290000Sglebius    if (arg_list == NULL) {
62290000Sglebius        od->fOptState &= OPTST_PERSISTENT_MASK;
63290000Sglebius        if ((od->fOptState & OPTST_INITENABLED) == 0)
64290000Sglebius            od->fOptState |= OPTST_DISABLED;
65181834Sroberto        return;
66181834Sroberto    }
67181834Sroberto
68181834Sroberto#ifdef WITH_LIBREGEX
69181834Sroberto    {
70181834Sroberto        regex_t   re;
71181834Sroberto        int       i, ct, dIdx;
72181834Sroberto
73290000Sglebius        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         */
82290000Sglebius        for (i = 0, dIdx = 0, ct = arg_list->useCt; --ct >= 0; i++) {
83290000Sglebius            char const * pzSrc = arg_list->apzArgs[ i ];
84290000Sglebius            char *       pzEq  = strchr(pzSrc, '=');
85290000Sglebius            int          res;
86181834Sroberto
87290000Sglebius
88181834Sroberto            if (pzEq != NULL)
89181834Sroberto                *pzEq = NUL;
90181834Sroberto
91290000Sglebius            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);
100290000Sglebius                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)
113290000Sglebius                    arg_list->apzArgs[ dIdx ] = pzSrc;
114181834Sroberto                dIdx++;
115181834Sroberto            }
116181834Sroberto        }
117181834Sroberto
118290000Sglebius        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         */
130290000Sglebius        for (i = 0, dIdx = 0, ct = arg_list->useCt; --ct >= 0; i++) {
131290000Sglebius            const char * pzSrc = arg_list->apzArgs[ i ];
132290000Sglebius            char *       pzEq  = strchr(pzSrc, '=');
133181834Sroberto
134181834Sroberto            if (pzEq != NULL)
135181834Sroberto                *pzEq = NUL;
136181834Sroberto
137290000Sglebius            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);
144290000Sglebius                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)
154290000Sglebius                    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     */
164290000Sglebius    if (arg_list->useCt == 0) {
165290000Sglebius        od->fOptState &= OPTST_PERSISTENT_MASK;
166290000Sglebius        if ((od->fOptState & OPTST_INITENABLED) == 0)
167290000Sglebius            od->fOptState |= OPTST_DISABLED;
168290000Sglebius        AGFREE(arg_list);
169290000Sglebius        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
180290000SglebiusaddArgListEntry(void ** ppAL, void * entry)
181181834Sroberto{
182290000Sglebius    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) {
189290000Sglebius        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;
194290000Sglebius        *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) {
202290000Sglebius        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         */
209290000Sglebius        sz += sizeof(char *) * ((size_t)pAL->allocCt - MIN_ARG_ALLOC_CT);
210290000Sglebius        pAL = (tArgList *)AGREALOC(VOIDP(pAL), sz, "expanded opt arg stack");
211181834Sroberto        if (pAL == NULL)
212181834Sroberto            return;
213290000Sglebius        *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
227290000Sglebius * arg:   + tOptions * + opts + program options descriptor +
228290000Sglebius * arg:   + tOptDesc * + od   + the descriptor for this arg +
229181834Sroberto *
230181834Sroberto * doc:
231181834Sroberto *  Keep an entry-ordered list of option arguments.
232181834Sroberto=*/
233181834Srobertovoid
234290000SglebiusoptionStackArg(tOptions * opts, tOptDesc * od)
235181834Sroberto{
236181834Sroberto    char * pz;
237181834Sroberto
238290000Sglebius    if (INQUERY_CALL(opts, od))
239181834Sroberto        return;
240181834Sroberto
241290000Sglebius    if ((od->fOptState & OPTST_RESET) != 0) {
242290000Sglebius        tArgList * arg_list = od->optCookie;
243290000Sglebius        int ix;
244290000Sglebius        if (arg_list == NULL)
245290000Sglebius            return;
246290000Sglebius
247290000Sglebius        ix = arg_list->useCt;
248290000Sglebius        while (--ix >= 0)
249290000Sglebius            AGFREE(arg_list->apzArgs[ix]);
250290000Sglebius        AGFREE(arg_list);
251290000Sglebius
252290000Sglebius    } else {
253290000Sglebius        if (od->optArg.argString == NULL)
254290000Sglebius            return;
255290000Sglebius
256290000Sglebius        AGDUPSTR(pz, od->optArg.argString, "stack arg");
257290000Sglebius        addArgListEntry(&(od->optCookie), VOIDP(pz));
258290000Sglebius    }
259181834Sroberto}
260290000Sglebius/** @}
261290000Sglebius *
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