1ea906c41SOllivier Robert
22b15cb3dSCy Schubert /**
32b15cb3dSCy Schubert * \file stack.c
4ea906c41SOllivier Robert *
5ea906c41SOllivier Robert * This is a special option processing routine that will save the
6ea906c41SOllivier Robert * argument to an option in a FIFO queue.
72b15cb3dSCy Schubert *
82b15cb3dSCy Schubert * @addtogroup autoopts
92b15cb3dSCy Schubert * @{
10ea906c41SOllivier Robert */
11ea906c41SOllivier Robert /*
122b15cb3dSCy Schubert * This file is part of AutoOpts, a companion to AutoGen.
132b15cb3dSCy Schubert * AutoOpts is free software.
14*a466cc55SCy Schubert * AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
15ea906c41SOllivier Robert *
162b15cb3dSCy Schubert * AutoOpts is available under any one of two licenses. The license
172b15cb3dSCy Schubert * in use must be one of these two and the choice is under the control
182b15cb3dSCy Schubert * of the user of the license.
19ea906c41SOllivier Robert *
202b15cb3dSCy Schubert * The GNU Lesser General Public License, version 3 or later
212b15cb3dSCy Schubert * See the files "COPYING.lgplv3" and "COPYING.gplv3"
22ea906c41SOllivier Robert *
232b15cb3dSCy Schubert * The Modified Berkeley Software Distribution License
242b15cb3dSCy Schubert * See the file "COPYING.mbsd"
25ea906c41SOllivier Robert *
262b15cb3dSCy Schubert * These files have the following sha256 sums:
27ea906c41SOllivier Robert *
282b15cb3dSCy Schubert * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3
292b15cb3dSCy Schubert * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3
302b15cb3dSCy Schubert * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd
31ea906c41SOllivier Robert */
32ea906c41SOllivier Robert
33ea906c41SOllivier Robert #ifdef WITH_LIBREGEX
34ea906c41SOllivier Robert # include REGEX_HEADER
35ea906c41SOllivier Robert #endif
36ea906c41SOllivier Robert
37ea906c41SOllivier Robert /*=export_func optionUnstackArg
38ea906c41SOllivier Robert * private:
39ea906c41SOllivier Robert *
40ea906c41SOllivier Robert * what: Remove option args from a stack
412b15cb3dSCy Schubert * arg: + tOptions * + opts + program options descriptor +
422b15cb3dSCy Schubert * arg: + tOptDesc * + od + the descriptor for this arg +
43ea906c41SOllivier Robert *
44ea906c41SOllivier Robert * doc:
45ea906c41SOllivier Robert * Invoked for options that are equivalenced to stacked options.
46ea906c41SOllivier Robert =*/
47ea906c41SOllivier Robert void
optionUnstackArg(tOptions * opts,tOptDesc * od)482b15cb3dSCy Schubert optionUnstackArg(tOptions * opts, tOptDesc * od)
49ea906c41SOllivier Robert {
502b15cb3dSCy Schubert tArgList * arg_list;
51ea906c41SOllivier Robert
522b15cb3dSCy Schubert if (INQUERY_CALL(opts, od))
532b15cb3dSCy Schubert return;
542b15cb3dSCy Schubert
552b15cb3dSCy Schubert arg_list = (tArgList *)od->optCookie;
562b15cb3dSCy Schubert
57ea906c41SOllivier Robert /*
58ea906c41SOllivier Robert * IF we don't have any stacked options,
59ea906c41SOllivier Robert * THEN indicate that we don't have any of these options
60ea906c41SOllivier Robert */
612b15cb3dSCy Schubert if (arg_list == NULL) {
622b15cb3dSCy Schubert od->fOptState &= OPTST_PERSISTENT_MASK;
632b15cb3dSCy Schubert if ((od->fOptState & OPTST_INITENABLED) == 0)
642b15cb3dSCy Schubert od->fOptState |= OPTST_DISABLED;
65ea906c41SOllivier Robert return;
66ea906c41SOllivier Robert }
67ea906c41SOllivier Robert
68ea906c41SOllivier Robert #ifdef WITH_LIBREGEX
69ea906c41SOllivier Robert {
70ea906c41SOllivier Robert regex_t re;
71ea906c41SOllivier Robert int i, ct, dIdx;
72ea906c41SOllivier Robert
732b15cb3dSCy Schubert if (regcomp(&re, od->optArg.argString, REG_NOSUB) != 0)
74ea906c41SOllivier Robert return;
75ea906c41SOllivier Robert
76ea906c41SOllivier Robert /*
77ea906c41SOllivier Robert * search the list for the entry(s) to remove. Entries that
78ea906c41SOllivier Robert * are removed are *not* copied into the result. The source
79ea906c41SOllivier Robert * index is incremented every time. The destination only when
80ea906c41SOllivier Robert * we are keeping a define.
81ea906c41SOllivier Robert */
822b15cb3dSCy Schubert for (i = 0, dIdx = 0, ct = arg_list->useCt; --ct >= 0; i++) {
832b15cb3dSCy Schubert char const * pzSrc = arg_list->apzArgs[ i ];
84ea906c41SOllivier Robert char * pzEq = strchr(pzSrc, '=');
852b15cb3dSCy Schubert int res;
862b15cb3dSCy Schubert
87ea906c41SOllivier Robert
88ea906c41SOllivier Robert if (pzEq != NULL)
89ea906c41SOllivier Robert *pzEq = NUL;
90ea906c41SOllivier Robert
91ea906c41SOllivier Robert res = regexec(&re, pzSrc, (size_t)0, NULL, 0);
92ea906c41SOllivier Robert switch (res) {
93ea906c41SOllivier Robert case 0:
94ea906c41SOllivier Robert /*
95ea906c41SOllivier Robert * Remove this entry by reducing the in-use count
96ea906c41SOllivier Robert * and *not* putting the string pointer back into
97ea906c41SOllivier Robert * the list.
98ea906c41SOllivier Robert */
99ea906c41SOllivier Robert AGFREE(pzSrc);
1002b15cb3dSCy Schubert arg_list->useCt--;
101ea906c41SOllivier Robert break;
102ea906c41SOllivier Robert
103ea906c41SOllivier Robert default:
104ea906c41SOllivier Robert case REG_NOMATCH:
105ea906c41SOllivier Robert if (pzEq != NULL)
106ea906c41SOllivier Robert *pzEq = '=';
107ea906c41SOllivier Robert
108ea906c41SOllivier Robert /*
109ea906c41SOllivier Robert * IF we have dropped an entry
110ea906c41SOllivier Robert * THEN we have to move the current one.
111ea906c41SOllivier Robert */
112ea906c41SOllivier Robert if (dIdx != i)
1132b15cb3dSCy Schubert arg_list->apzArgs[ dIdx ] = pzSrc;
114ea906c41SOllivier Robert dIdx++;
115ea906c41SOllivier Robert }
116ea906c41SOllivier Robert }
117ea906c41SOllivier Robert
118ea906c41SOllivier Robert regfree(&re);
119ea906c41SOllivier Robert }
120ea906c41SOllivier Robert #else /* not WITH_LIBREGEX */
121ea906c41SOllivier Robert {
122ea906c41SOllivier Robert int i, ct, dIdx;
123ea906c41SOllivier Robert
124ea906c41SOllivier Robert /*
125ea906c41SOllivier Robert * search the list for the entry(s) to remove. Entries that
126ea906c41SOllivier Robert * are removed are *not* copied into the result. The source
127ea906c41SOllivier Robert * index is incremented every time. The destination only when
128ea906c41SOllivier Robert * we are keeping a define.
129ea906c41SOllivier Robert */
1302b15cb3dSCy Schubert for (i = 0, dIdx = 0, ct = arg_list->useCt; --ct >= 0; i++) {
1312b15cb3dSCy Schubert const char * pzSrc = arg_list->apzArgs[ i ];
132ea906c41SOllivier Robert char * pzEq = strchr(pzSrc, '=');
133ea906c41SOllivier Robert
134ea906c41SOllivier Robert if (pzEq != NULL)
135ea906c41SOllivier Robert *pzEq = NUL;
136ea906c41SOllivier Robert
1372b15cb3dSCy Schubert if (strcmp(pzSrc, od->optArg.argString) == 0) {
138ea906c41SOllivier Robert /*
139ea906c41SOllivier Robert * Remove this entry by reducing the in-use count
140ea906c41SOllivier Robert * and *not* putting the string pointer back into
141ea906c41SOllivier Robert * the list.
142ea906c41SOllivier Robert */
143ea906c41SOllivier Robert AGFREE(pzSrc);
1442b15cb3dSCy Schubert arg_list->useCt--;
145ea906c41SOllivier Robert } else {
146ea906c41SOllivier Robert if (pzEq != NULL)
147ea906c41SOllivier Robert *pzEq = '=';
148ea906c41SOllivier Robert
149ea906c41SOllivier Robert /*
150ea906c41SOllivier Robert * IF we have dropped an entry
151ea906c41SOllivier Robert * THEN we have to move the current one.
152ea906c41SOllivier Robert */
153ea906c41SOllivier Robert if (dIdx != i)
1542b15cb3dSCy Schubert arg_list->apzArgs[ dIdx ] = pzSrc;
155ea906c41SOllivier Robert dIdx++;
156ea906c41SOllivier Robert }
157ea906c41SOllivier Robert }
158ea906c41SOllivier Robert }
159ea906c41SOllivier Robert #endif /* WITH_LIBREGEX */
160ea906c41SOllivier Robert /*
161ea906c41SOllivier Robert * IF we have unstacked everything,
162ea906c41SOllivier Robert * THEN indicate that we don't have any of these options
163ea906c41SOllivier Robert */
1642b15cb3dSCy Schubert if (arg_list->useCt == 0) {
1652b15cb3dSCy Schubert od->fOptState &= OPTST_PERSISTENT_MASK;
1662b15cb3dSCy Schubert if ((od->fOptState & OPTST_INITENABLED) == 0)
1672b15cb3dSCy Schubert od->fOptState |= OPTST_DISABLED;
168276da39aSCy Schubert AGFREE(arg_list);
1692b15cb3dSCy Schubert od->optCookie = NULL;
170ea906c41SOllivier Robert }
171ea906c41SOllivier Robert }
172ea906c41SOllivier Robert
173ea906c41SOllivier Robert
174ea906c41SOllivier Robert /*
175ea906c41SOllivier Robert * Put an entry into an argument list. The first argument points to
176ea906c41SOllivier Robert * a pointer to the argument list structure. It gets passed around
177ea906c41SOllivier Robert * as an opaque address.
178ea906c41SOllivier Robert */
179*a466cc55SCy Schubert static void
addArgListEntry(void ** ppAL,void * entry)180ea906c41SOllivier Robert addArgListEntry(void ** ppAL, void * entry)
181ea906c41SOllivier Robert {
182ea906c41SOllivier Robert tArgList * pAL = *(void **)ppAL;
183ea906c41SOllivier Robert
184ea906c41SOllivier Robert /*
185ea906c41SOllivier Robert * IF we have never allocated one of these,
186ea906c41SOllivier Robert * THEN allocate one now
187ea906c41SOllivier Robert */
188ea906c41SOllivier Robert if (pAL == NULL) {
189ea906c41SOllivier Robert pAL = (tArgList *)AGALOC(sizeof(*pAL), "new option arg stack");
190ea906c41SOllivier Robert if (pAL == NULL)
191ea906c41SOllivier Robert return;
192ea906c41SOllivier Robert pAL->useCt = 0;
193ea906c41SOllivier Robert pAL->allocCt = MIN_ARG_ALLOC_CT;
194276da39aSCy Schubert *ppAL = VOIDP(pAL);
195ea906c41SOllivier Robert }
196ea906c41SOllivier Robert
197ea906c41SOllivier Robert /*
198ea906c41SOllivier Robert * ELSE if we are out of room
199ea906c41SOllivier Robert * THEN make it bigger
200ea906c41SOllivier Robert */
201ea906c41SOllivier Robert else if (pAL->useCt >= pAL->allocCt) {
202ea906c41SOllivier Robert size_t sz = sizeof(*pAL);
203ea906c41SOllivier Robert pAL->allocCt += INCR_ARG_ALLOC_CT;
204ea906c41SOllivier Robert
205ea906c41SOllivier Robert /*
206ea906c41SOllivier Robert * The base structure contains space for MIN_ARG_ALLOC_CT
207ea906c41SOllivier Robert * pointers. We subtract it off to find our augment size.
208ea906c41SOllivier Robert */
2092b15cb3dSCy Schubert sz += sizeof(char *) * ((size_t)pAL->allocCt - MIN_ARG_ALLOC_CT);
210276da39aSCy Schubert pAL = (tArgList *)AGREALOC(VOIDP(pAL), sz, "expanded opt arg stack");
211ea906c41SOllivier Robert if (pAL == NULL)
212ea906c41SOllivier Robert return;
213276da39aSCy Schubert *ppAL = VOIDP(pAL);
214ea906c41SOllivier Robert }
215ea906c41SOllivier Robert
216ea906c41SOllivier Robert /*
217ea906c41SOllivier Robert * Insert the new argument into the list
218ea906c41SOllivier Robert */
219ea906c41SOllivier Robert pAL->apzArgs[ (pAL->useCt)++ ] = entry;
220ea906c41SOllivier Robert }
221ea906c41SOllivier Robert
222ea906c41SOllivier Robert
223ea906c41SOllivier Robert /*=export_func optionStackArg
224ea906c41SOllivier Robert * private:
225ea906c41SOllivier Robert *
226ea906c41SOllivier Robert * what: put option args on a stack
2272b15cb3dSCy Schubert * arg: + tOptions * + opts + program options descriptor +
2282b15cb3dSCy Schubert * arg: + tOptDesc * + od + the descriptor for this arg +
229ea906c41SOllivier Robert *
230ea906c41SOllivier Robert * doc:
231ea906c41SOllivier Robert * Keep an entry-ordered list of option arguments.
232ea906c41SOllivier Robert =*/
233ea906c41SOllivier Robert void
optionStackArg(tOptions * opts,tOptDesc * od)2342b15cb3dSCy Schubert optionStackArg(tOptions * opts, tOptDesc * od)
235ea906c41SOllivier Robert {
236ea906c41SOllivier Robert char * pz;
237ea906c41SOllivier Robert
2382b15cb3dSCy Schubert if (INQUERY_CALL(opts, od))
239ea906c41SOllivier Robert return;
240ea906c41SOllivier Robert
2412b15cb3dSCy Schubert if ((od->fOptState & OPTST_RESET) != 0) {
242276da39aSCy Schubert tArgList * arg_list = od->optCookie;
2432b15cb3dSCy Schubert int ix;
2442b15cb3dSCy Schubert if (arg_list == NULL)
2452b15cb3dSCy Schubert return;
2462b15cb3dSCy Schubert
2472b15cb3dSCy Schubert ix = arg_list->useCt;
2482b15cb3dSCy Schubert while (--ix >= 0)
2492b15cb3dSCy Schubert AGFREE(arg_list->apzArgs[ix]);
2502b15cb3dSCy Schubert AGFREE(arg_list);
2512b15cb3dSCy Schubert
2522b15cb3dSCy Schubert } else {
2532b15cb3dSCy Schubert if (od->optArg.argString == NULL)
2542b15cb3dSCy Schubert return;
2552b15cb3dSCy Schubert
2562b15cb3dSCy Schubert AGDUPSTR(pz, od->optArg.argString, "stack arg");
257276da39aSCy Schubert addArgListEntry(&(od->optCookie), VOIDP(pz));
258ea906c41SOllivier Robert }
2592b15cb3dSCy Schubert }
2602b15cb3dSCy Schubert /** @}
2612b15cb3dSCy Schubert *
262ea906c41SOllivier Robert * Local Variables:
263ea906c41SOllivier Robert * mode: C
264ea906c41SOllivier Robert * c-file-style: "stroustrup"
265ea906c41SOllivier Robert * indent-tabs-mode: nil
266ea906c41SOllivier Robert * End:
267ea906c41SOllivier Robert * end of autoopts/stack.c */
268