1
2/*
3 *  stack.c
4 *  $Id: 9d4a7c1c6ae364a6134dc5ff01f58f08b52f1a16 $
5 *  Time-stamp:      "2008-07-30 16:56:32 bkorb"
6 *
7 *  This is a special option processing routine that will save the
8 *  argument to an option in a FIFO queue.
9 *
10 *  This file is part of AutoOpts, a companion to AutoGen.
11 *  AutoOpts is free software.
12 *  AutoOpts is copyright (c) 1992-2009 by Bruce Korb - all rights reserved
13 *
14 *  AutoOpts is available under any one of two licenses.  The license
15 *  in use must be one of these two and the choice is under the control
16 *  of the user of the license.
17 *
18 *   The GNU Lesser General Public License, version 3 or later
19 *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
20 *
21 *   The Modified Berkeley Software Distribution License
22 *      See the file "COPYING.mbsd"
23 *
24 *  These files have the following md5sums:
25 *
26 *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
27 *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
28 *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
29 */
30
31#ifdef WITH_LIBREGEX
32#  include REGEX_HEADER
33#endif
34
35/*=export_func  optionUnstackArg
36 * private:
37 *
38 * what:  Remove option args from a stack
39 * arg:   + tOptions* + pOpts    + program options descriptor +
40 * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
41 *
42 * doc:
43 *  Invoked for options that are equivalenced to stacked options.
44=*/
45void
46optionUnstackArg(
47    tOptions*  pOpts,
48    tOptDesc*  pOptDesc )
49{
50    int       res;
51
52    tArgList* pAL;
53
54    if ((pOptDesc->fOptState & OPTST_RESET) != 0)
55        return;
56    pAL = (tArgList*)pOptDesc->optCookie;
57
58    /*
59     *  IF we don't have any stacked options,
60     *  THEN indicate that we don't have any of these options
61     */
62    if (pAL == NULL) {
63        pOptDesc->fOptState &= OPTST_PERSISTENT_MASK;
64        if ( (pOptDesc->fOptState & OPTST_INITENABLED) == 0)
65            pOptDesc->fOptState |= OPTST_DISABLED;
66        return;
67    }
68
69#ifdef WITH_LIBREGEX
70    {
71        regex_t   re;
72        int       i, ct, dIdx;
73
74        if (regcomp( &re, pOptDesc->optArg.argString, REG_NOSUB ) != 0)
75            return;
76
77        /*
78         *  search the list for the entry(s) to remove.  Entries that
79         *  are removed are *not* copied into the result.  The source
80         *  index is incremented every time.  The destination only when
81         *  we are keeping a define.
82         */
83        for (i = 0, dIdx = 0, ct = pAL->useCt; --ct >= 0; i++) {
84            tCC*      pzSrc = pAL->apzArgs[ i ];
85            char*     pzEq  = strchr( pzSrc, '=' );
86
87            if (pzEq != NULL)
88                *pzEq = NUL;
89
90            res = regexec( &re, pzSrc, (size_t)0, NULL, 0 );
91            switch (res) {
92            case 0:
93                /*
94                 *  Remove this entry by reducing the in-use count
95                 *  and *not* putting the string pointer back into
96                 *  the list.
97                 */
98                AGFREE(pzSrc);
99                pAL->useCt--;
100                break;
101
102            default:
103            case REG_NOMATCH:
104                if (pzEq != NULL)
105                    *pzEq = '=';
106
107                /*
108                 *  IF we have dropped an entry
109                 *  THEN we have to move the current one.
110                 */
111                if (dIdx != i)
112                    pAL->apzArgs[ dIdx ] = pzSrc;
113                dIdx++;
114            }
115        }
116
117        regfree( &re );
118    }
119#else  /* not WITH_LIBREGEX */
120    {
121        int i, ct, dIdx;
122
123        /*
124         *  search the list for the entry(s) to remove.  Entries that
125         *  are removed are *not* copied into the result.  The source
126         *  index is incremented every time.  The destination only when
127         *  we are keeping a define.
128         */
129        for (i = 0, dIdx = 0, ct = pAL->useCt; --ct >= 0; i++) {
130            tCC*      pzSrc = pAL->apzArgs[ i ];
131            char*     pzEq  = strchr( pzSrc, '=' );
132
133            if (pzEq != NULL)
134                *pzEq = NUL;
135
136            if (strcmp( pzSrc, pOptDesc->optArg.argString ) == 0) {
137                /*
138                 *  Remove this entry by reducing the in-use count
139                 *  and *not* putting the string pointer back into
140                 *  the list.
141                 */
142                AGFREE(pzSrc);
143                pAL->useCt--;
144            } else {
145                if (pzEq != NULL)
146                    *pzEq = '=';
147
148                /*
149                 *  IF we have dropped an entry
150                 *  THEN we have to move the current one.
151                 */
152                if (dIdx != i)
153                    pAL->apzArgs[ dIdx ] = pzSrc;
154                dIdx++;
155            }
156        }
157    }
158#endif /* WITH_LIBREGEX */
159    /*
160     *  IF we have unstacked everything,
161     *  THEN indicate that we don't have any of these options
162     */
163    if (pAL->useCt == 0) {
164        pOptDesc->fOptState &= OPTST_PERSISTENT_MASK;
165        if ( (pOptDesc->fOptState & OPTST_INITENABLED) == 0)
166            pOptDesc->fOptState |= OPTST_DISABLED;
167        AGFREE( (void*)pAL );
168        pOptDesc->optCookie = NULL;
169    }
170}
171
172
173/*
174 *  Put an entry into an argument list.  The first argument points to
175 *  a pointer to the argument list structure.  It gets passed around
176 *  as an opaque address.
177 */
178LOCAL void
179addArgListEntry( void** ppAL, void* entry )
180{
181    tArgList* pAL = *(void**)ppAL;
182
183    /*
184     *  IF we have never allocated one of these,
185     *  THEN allocate one now
186     */
187    if (pAL == NULL) {
188        pAL = (tArgList*)AGALOC( sizeof( *pAL ), "new option arg stack" );
189        if (pAL == NULL)
190            return;
191        pAL->useCt   = 0;
192        pAL->allocCt = MIN_ARG_ALLOC_CT;
193        *ppAL = (void*)pAL;
194    }
195
196    /*
197     *  ELSE if we are out of room
198     *  THEN make it bigger
199     */
200    else if (pAL->useCt >= pAL->allocCt) {
201        size_t sz = sizeof( *pAL );
202        pAL->allocCt += INCR_ARG_ALLOC_CT;
203
204        /*
205         *  The base structure contains space for MIN_ARG_ALLOC_CT
206         *  pointers.  We subtract it off to find our augment size.
207         */
208        sz += sizeof(char*) * (pAL->allocCt - MIN_ARG_ALLOC_CT);
209        pAL = (tArgList*)AGREALOC( (void*)pAL, sz, "expanded opt arg stack" );
210        if (pAL == NULL)
211            return;
212        *ppAL = (void*)pAL;
213    }
214
215    /*
216     *  Insert the new argument into the list
217     */
218    pAL->apzArgs[ (pAL->useCt)++ ] = entry;
219}
220
221
222/*=export_func  optionStackArg
223 * private:
224 *
225 * what:  put option args on a stack
226 * arg:   + tOptions* + pOpts    + program options descriptor +
227 * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
228 *
229 * doc:
230 *  Keep an entry-ordered list of option arguments.
231=*/
232void
233optionStackArg(
234    tOptions*  pOpts,
235    tOptDesc*  pOD )
236{
237    char * pz;
238
239    if ((pOD->fOptState & OPTST_RESET) != 0) {
240        tArgList* pAL = (void*)pOD->optCookie;
241        int ix;
242        if (pAL == NULL)
243            return;
244
245        ix = pAL->useCt;
246        while (--ix >= 0)
247            AGFREE(pAL->apzArgs[ix]);
248        AGFREE(pAL);
249
250    } else {
251        if (pOD->optArg.argString == NULL)
252            return;
253
254        AGDUPSTR(pz, pOD->optArg.argString, "stack arg");
255        addArgListEntry( &(pOD->optCookie), (void*)pz );
256    }
257}
258/*
259 * Local Variables:
260 * mode: C
261 * c-file-style: "stroustrup"
262 * indent-tabs-mode: nil
263 * End:
264 * end of autoopts/stack.c */
265