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