xref: /netbsd/external/bsd/ntp/dist/sntp/libopts/stack.c (revision 9034ec65)
1 /*	$NetBSD: stack.c,v 1.8 2020/05/25 20:47:35 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-2015 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 * + opts + program options descriptor +
44  * arg:   + tOptDesc * + od   + the descriptor for this arg +
45  *
46  * doc:
47  *  Invoked for options that are equivalenced to stacked options.
48 =*/
49 void
optionUnstackArg(tOptions * opts,tOptDesc * od)50 optionUnstackArg(tOptions * opts, tOptDesc * od)
51 {
52     tArgList * arg_list;
53 
54     if (INQUERY_CALL(opts, od))
55         return;
56 
57     arg_list = (tArgList *)od->optCookie;
58 
59     /*
60      *  IF we don't have any stacked options,
61      *  THEN indicate that we don't have any of these options
62      */
63     if (arg_list == NULL) {
64         od->fOptState &= OPTST_PERSISTENT_MASK;
65         if ((od->fOptState & OPTST_INITENABLED) == 0)
66             od->fOptState |= OPTST_DISABLED;
67         return;
68     }
69 
70 #ifdef WITH_LIBREGEX
71     {
72         regex_t   re;
73         int       i, ct, dIdx;
74 
75         if (regcomp(&re, od->optArg.argString, REG_NOSUB) != 0)
76             return;
77 
78         /*
79          *  search the list for the entry(s) to remove.  Entries that
80          *  are removed are *not* copied into the result.  The source
81          *  index is incremented every time.  The destination only when
82          *  we are keeping a define.
83          */
84         for (i = 0, dIdx = 0, ct = arg_list->useCt; --ct >= 0; i++) {
85             char const * pzSrc = arg_list->apzArgs[ i ];
86             char *       pzEq  = strchr(pzSrc, '=');
87             int          res;
88 
89 
90             if (pzEq != NULL)
91                 *pzEq = NUL;
92 
93             res = regexec(&re, pzSrc, (size_t)0, NULL, 0);
94             switch (res) {
95             case 0:
96                 /*
97                  *  Remove this entry by reducing the in-use count
98                  *  and *not* putting the string pointer back into
99                  *  the list.
100                  */
101                 AGFREE(pzSrc);
102                 arg_list->useCt--;
103                 break;
104 
105             default:
106             case REG_NOMATCH:
107                 if (pzEq != NULL)
108                     *pzEq = '=';
109 
110                 /*
111                  *  IF we have dropped an entry
112                  *  THEN we have to move the current one.
113                  */
114                 if (dIdx != i)
115                     arg_list->apzArgs[ dIdx ] = pzSrc;
116                 dIdx++;
117             }
118         }
119 
120         regfree(&re);
121     }
122 #else  /* not WITH_LIBREGEX */
123     {
124         int i, ct, dIdx;
125 
126         /*
127          *  search the list for the entry(s) to remove.  Entries that
128          *  are removed are *not* copied into the result.  The source
129          *  index is incremented every time.  The destination only when
130          *  we are keeping a define.
131          */
132         for (i = 0, dIdx = 0, ct = arg_list->useCt; --ct >= 0; i++) {
133             const char * pzSrc = arg_list->apzArgs[ i ];
134             char *       pzEq  = strchr(pzSrc, '=');
135 
136             if (pzEq != NULL)
137                 *pzEq = NUL;
138 
139             if (strcmp(pzSrc, od->optArg.argString) == 0) {
140                 /*
141                  *  Remove this entry by reducing the in-use count
142                  *  and *not* putting the string pointer back into
143                  *  the list.
144                  */
145                 AGFREE(pzSrc);
146                 arg_list->useCt--;
147             } else {
148                 if (pzEq != NULL)
149                     *pzEq = '=';
150 
151                 /*
152                  *  IF we have dropped an entry
153                  *  THEN we have to move the current one.
154                  */
155                 if (dIdx != i)
156                     arg_list->apzArgs[ dIdx ] = pzSrc;
157                 dIdx++;
158             }
159         }
160     }
161 #endif /* WITH_LIBREGEX */
162     /*
163      *  IF we have unstacked everything,
164      *  THEN indicate that we don't have any of these options
165      */
166     if (arg_list->useCt == 0) {
167         od->fOptState &= OPTST_PERSISTENT_MASK;
168         if ((od->fOptState & OPTST_INITENABLED) == 0)
169             od->fOptState |= OPTST_DISABLED;
170         AGFREE(arg_list);
171         od->optCookie = NULL;
172     }
173 }
174 
175 
176 /*
177  *  Put an entry into an argument list.  The first argument points to
178  *  a pointer to the argument list structure.  It gets passed around
179  *  as an opaque address.
180  */
181 LOCAL void
addArgListEntry(void ** ppAL,void * entry)182 addArgListEntry(void ** ppAL, void * entry)
183 {
184     tArgList * pAL = *(void **)ppAL;
185 
186     /*
187      *  IF we have never allocated one of these,
188      *  THEN allocate one now
189      */
190     if (pAL == NULL) {
191         pAL = (tArgList *)AGALOC(sizeof(*pAL), "new option arg stack");
192         if (pAL == NULL)
193             return;
194         pAL->useCt   = 0;
195         pAL->allocCt = MIN_ARG_ALLOC_CT;
196         *ppAL = VOIDP(pAL);
197     }
198 
199     /*
200      *  ELSE if we are out of room
201      *  THEN make it bigger
202      */
203     else if (pAL->useCt >= pAL->allocCt) {
204         size_t sz = sizeof(*pAL);
205         pAL->allocCt += INCR_ARG_ALLOC_CT;
206 
207         /*
208          *  The base structure contains space for MIN_ARG_ALLOC_CT
209          *  pointers.  We subtract it off to find our augment size.
210          */
211         sz += sizeof(char *) * ((size_t)pAL->allocCt - MIN_ARG_ALLOC_CT);
212         pAL = (tArgList *)AGREALOC(VOIDP(pAL), sz, "expanded opt arg stack");
213         if (pAL == NULL)
214             return;
215         *ppAL = VOIDP(pAL);
216     }
217 
218     /*
219      *  Insert the new argument into the list
220      */
221     pAL->apzArgs[ (pAL->useCt)++ ] = entry;
222 }
223 
224 
225 /*=export_func  optionStackArg
226  * private:
227  *
228  * what:  put option args on a stack
229  * arg:   + tOptions * + opts + program options descriptor +
230  * arg:   + tOptDesc * + od   + the descriptor for this arg +
231  *
232  * doc:
233  *  Keep an entry-ordered list of option arguments.
234 =*/
235 void
optionStackArg(tOptions * opts,tOptDesc * od)236 optionStackArg(tOptions * opts, tOptDesc * od)
237 {
238     char * pz;
239 
240     if (INQUERY_CALL(opts, od))
241         return;
242 
243     if ((od->fOptState & OPTST_RESET) != 0) {
244         tArgList * arg_list = od->optCookie;
245         int ix;
246         if (arg_list == NULL)
247             return;
248 
249         ix = arg_list->useCt;
250         while (--ix >= 0)
251             AGFREE(arg_list->apzArgs[ix]);
252         AGFREE(arg_list);
253 
254     } else {
255         if (od->optArg.argString == NULL)
256             return;
257 
258         AGDUPSTR(pz, od->optArg.argString, "stack arg");
259         addArgListEntry(&(od->optCookie), VOIDP(pz));
260     }
261 }
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