1
2 /*
3 * stack.c
4 * $Id: stack.c,v 4.13 2007/02/04 17:44:12 bkorb Exp $
5 * Time-stamp: "2007-01-13 10:43:21 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
11 /*
12 * Automated Options copyright 1992-2007 Bruce Korb
13 *
14 * Automated Options is free software.
15 * You may redistribute it and/or modify it under the terms of the
16 * GNU General Public License, as published by the Free Software
17 * Foundation; either version 2, or (at your option) any later version.
18 *
19 * Automated Options is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Automated Options. See the file "COPYING". If not,
26 * write to: The Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor,
28 * Boston, MA 02110-1301, USA.
29 *
30 * As a special exception, Bruce Korb gives permission for additional
31 * uses of the text contained in his release of AutoOpts.
32 *
33 * The exception is that, if you link the AutoOpts library with other
34 * files to produce an executable, this does not by itself cause the
35 * resulting executable to be covered by the GNU General Public License.
36 * Your use of that executable is in no way restricted on account of
37 * linking the AutoOpts library code into it.
38 *
39 * This exception does not however invalidate any other reasons why
40 * the executable file might be covered by the GNU General Public License.
41 *
42 * This exception applies only to the code released by Bruce Korb under
43 * the name AutoOpts. If you copy code from other sources under the
44 * General Public License into a copy of AutoOpts, as the General Public
45 * License permits, the exception does not apply to the code that you add
46 * in this way. To avoid misleading anyone as to the status of such
47 * modified files, you must delete this exception notice from them.
48 *
49 * If you write modifications of your own for AutoOpts, it is your choice
50 * whether to permit this exception to apply to your modifications.
51 * If you do not wish that, delete this exception notice.
52 */
53
54 #ifdef WITH_LIBREGEX
55 # include REGEX_HEADER
56 #endif
57
58 /*=export_func optionUnstackArg
59 * private:
60 *
61 * what: Remove option args from a stack
62 * arg: + tOptions* + pOpts + program options descriptor +
63 * arg: + tOptDesc* + pOptDesc + the descriptor for this arg +
64 *
65 * doc:
66 * Invoked for options that are equivalenced to stacked options.
67 =*/
68 void
optionUnstackArg(tOptions * pOpts,tOptDesc * pOptDesc)69 optionUnstackArg(
70 tOptions* pOpts,
71 tOptDesc* pOptDesc )
72 {
73 int res;
74
75 tArgList* pAL = (tArgList*)pOptDesc->optCookie;
76 /*
77 * IF we don't have any stacked options,
78 * THEN indicate that we don't have any of these options
79 */
80 if (pAL == NULL) {
81 pOptDesc->fOptState &= OPTST_PERSISTENT_MASK;
82 if ( (pOptDesc->fOptState & OPTST_INITENABLED) == 0)
83 pOptDesc->fOptState |= OPTST_DISABLED;
84 return;
85 }
86
87 #ifdef WITH_LIBREGEX
88 {
89 regex_t re;
90 int i, ct, dIdx;
91
92 if (regcomp( &re, pOptDesc->optArg.argString, REG_NOSUB ) != 0)
93 return;
94
95 /*
96 * search the list for the entry(s) to remove. Entries that
97 * are removed are *not* copied into the result. The source
98 * index is incremented every time. The destination only when
99 * we are keeping a define.
100 */
101 for (i = 0, dIdx = 0, ct = pAL->useCt; --ct >= 0; i++) {
102 tCC* pzSrc = pAL->apzArgs[ i ];
103 char* pzEq = strchr( pzSrc, '=' );
104
105 if (pzEq != NULL)
106 *pzEq = NUL;
107
108 res = regexec( &re, pzSrc, (size_t)0, NULL, 0 );
109 switch (res) {
110 case 0:
111 /*
112 * Remove this entry by reducing the in-use count
113 * and *not* putting the string pointer back into
114 * the list.
115 */
116 AGFREE(pzSrc);
117 pAL->useCt--;
118 break;
119
120 default:
121 case REG_NOMATCH:
122 if (pzEq != NULL)
123 *pzEq = '=';
124
125 /*
126 * IF we have dropped an entry
127 * THEN we have to move the current one.
128 */
129 if (dIdx != i)
130 pAL->apzArgs[ dIdx ] = pzSrc;
131 dIdx++;
132 }
133 }
134
135 regfree( &re );
136 }
137 #else /* not WITH_LIBREGEX */
138 {
139 int i, ct, dIdx;
140
141 /*
142 * search the list for the entry(s) to remove. Entries that
143 * are removed are *not* copied into the result. The source
144 * index is incremented every time. The destination only when
145 * we are keeping a define.
146 */
147 for (i = 0, dIdx = 0, ct = pAL->useCt; --ct >= 0; i++) {
148 tCC* pzSrc = pAL->apzArgs[ i ];
149 char* pzEq = strchr( pzSrc, '=' );
150
151 if (pzEq != NULL)
152 *pzEq = NUL;
153
154 if (strcmp( pzSrc, pOptDesc->optArg.argString ) == 0) {
155 /*
156 * Remove this entry by reducing the in-use count
157 * and *not* putting the string pointer back into
158 * the list.
159 */
160 AGFREE(pzSrc);
161 pAL->useCt--;
162 } else {
163 if (pzEq != NULL)
164 *pzEq = '=';
165
166 /*
167 * IF we have dropped an entry
168 * THEN we have to move the current one.
169 */
170 if (dIdx != i)
171 pAL->apzArgs[ dIdx ] = pzSrc;
172 dIdx++;
173 }
174 }
175 }
176 #endif /* WITH_LIBREGEX */
177 /*
178 * IF we have unstacked everything,
179 * THEN indicate that we don't have any of these options
180 */
181 if (pAL->useCt == 0) {
182 pOptDesc->fOptState &= OPTST_PERSISTENT_MASK;
183 if ( (pOptDesc->fOptState & OPTST_INITENABLED) == 0)
184 pOptDesc->fOptState |= OPTST_DISABLED;
185 AGFREE( (void*)pAL );
186 pOptDesc->optCookie = NULL;
187 }
188 }
189
190
191 /*
192 * Put an entry into an argument list. The first argument points to
193 * a pointer to the argument list structure. It gets passed around
194 * as an opaque address.
195 */
196 LOCAL void
addArgListEntry(void ** ppAL,void * entry)197 addArgListEntry( void** ppAL, void* entry )
198 {
199 tArgList* pAL = *(void**)ppAL;
200
201 /*
202 * IF we have never allocated one of these,
203 * THEN allocate one now
204 */
205 if (pAL == NULL) {
206 pAL = (tArgList*)AGALOC( sizeof( *pAL ), "new option arg stack" );
207 if (pAL == NULL)
208 return;
209 pAL->useCt = 0;
210 pAL->allocCt = MIN_ARG_ALLOC_CT;
211 *ppAL = (void*)pAL;
212 }
213
214 /*
215 * ELSE if we are out of room
216 * THEN make it bigger
217 */
218 else if (pAL->useCt >= pAL->allocCt) {
219 size_t sz = sizeof( *pAL );
220 pAL->allocCt += INCR_ARG_ALLOC_CT;
221
222 /*
223 * The base structure contains space for MIN_ARG_ALLOC_CT
224 * pointers. We subtract it off to find our augment size.
225 */
226 sz += sizeof(char*) * (pAL->allocCt - MIN_ARG_ALLOC_CT);
227 pAL = (tArgList*)AGREALOC( (void*)pAL, sz, "expanded opt arg stack" );
228 if (pAL == NULL)
229 return;
230 *ppAL = (void*)pAL;
231 }
232
233 /*
234 * Insert the new argument into the list
235 */
236 pAL->apzArgs[ (pAL->useCt)++ ] = entry;
237 }
238
239
240 /*=export_func optionStackArg
241 * private:
242 *
243 * what: put option args on a stack
244 * arg: + tOptions* + pOpts + program options descriptor +
245 * arg: + tOptDesc* + pOptDesc + the descriptor for this arg +
246 *
247 * doc:
248 * Keep an entry-ordered list of option arguments.
249 =*/
250 void
optionStackArg(tOptions * pOpts,tOptDesc * pOD)251 optionStackArg(
252 tOptions* pOpts,
253 tOptDesc* pOD )
254 {
255 char * pz;
256
257 if (pOD->optArg.argString == NULL)
258 return;
259
260 AGDUPSTR(pz, pOD->optArg.argString, "stack arg");
261 addArgListEntry( &(pOD->optCookie), (void*)pz );
262 }
263 /*
264 * Local Variables:
265 * mode: C
266 * c-file-style: "stroustrup"
267 * indent-tabs-mode: nil
268 * End:
269 * end of autoopts/stack.c */
270