/src/ntp-dev/sntp/libopts/autoopts.c
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | /** |
3 | | * \file autoopts.c |
4 | | * |
5 | | * This file contains all of the routines that must be linked into |
6 | | * an executable to use the generated option processing. The optional |
7 | | * routines are in separately compiled modules so that they will not |
8 | | * necessarily be linked in. |
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 | | /** |
36 | | * The number of tab characters to skip when printing continuation lines. |
37 | | */ |
38 | | static unsigned int tab_skip_ct = 0; |
39 | | |
40 | | #ifndef HAVE_PATHFIND |
41 | 0 | # define pathfind(_p, _n, _m) option_pathfind(_p, _n, _m) |
42 | | # include "compat/pathfind.c" |
43 | | #endif |
44 | | |
45 | | #ifndef HAVE_SNPRINTF |
46 | | # define vsnprintf option_vsnprintf |
47 | | # define snprintf option_snprintf |
48 | | # include "compat/snprintf.c" |
49 | | #endif |
50 | | |
51 | | #ifndef HAVE_STRDUP |
52 | | # define strdup(_s) option_strdup(_s) |
53 | | # include "compat/strdup.c" |
54 | | #endif |
55 | | |
56 | | #ifndef HAVE_STRCHR |
57 | | # define strrchr(_s, _c) option_strrchr(_s, _c) |
58 | | # define strchr(_s, _c) option_strchr(_s, _c) |
59 | | # include "compat/strchr.c" |
60 | | #endif |
61 | | |
62 | | LOCAL void * |
63 | | ao_malloc(size_t sz) |
64 | 0 | { |
65 | 0 | void * res = malloc(sz); |
66 | 0 | if (res == NULL) { |
67 | 0 | fprintf(stderr, zalloc_fail, (int)sz); |
68 | 0 | option_exits(EXIT_FAILURE); |
69 | 0 | } |
70 | 0 | return res; |
71 | 0 | } |
72 | | #undef malloc |
73 | 0 | #define malloc(_s) ao_malloc(_s) |
74 | | |
75 | | LOCAL void * |
76 | | ao_realloc(void *p, size_t sz) |
77 | 0 | { |
78 | 0 | void * res = (p == NULL) ? malloc(sz) : realloc(p, sz); |
79 | 0 | if (res == NULL) { |
80 | 0 | fprintf(stderr, zrealloc_fail, (int)sz, p); |
81 | 0 | option_exits(EXIT_FAILURE); |
82 | 0 | } |
83 | 0 | return res; |
84 | 0 | } |
85 | | #undef realloc |
86 | | #define realloc(_p,_s) ao_realloc(_p,_s) |
87 | | |
88 | | LOCAL char * |
89 | | ao_strdup(char const *str) |
90 | 0 | { |
91 | 0 | char * res = strdup(str); |
92 | 0 | if (res == NULL) { |
93 | 0 | fprintf(stderr, zalloc_fail, (int)strlen(str)); |
94 | 0 | option_exits(EXIT_FAILURE); |
95 | 0 | } |
96 | 0 | return res; |
97 | 0 | } |
98 | | #undef strdup |
99 | | #define strdup(_p) ao_strdup(_p) |
100 | | |
101 | | /** |
102 | | * handle an option. |
103 | | * |
104 | | * This routine handles equivalencing, sets the option state flags and |
105 | | * invokes the handler procedure, if any. |
106 | | */ |
107 | | LOCAL tSuccess |
108 | | handle_opt(tOptions * opts, tOptState * o_st) |
109 | 0 | { |
110 | | /* |
111 | | * Save a copy of the option procedure pointer. |
112 | | * If this is an equivalence class option, we still want this proc. |
113 | | */ |
114 | 0 | tOptDesc * od = o_st->pOD; |
115 | 0 | tOptProc * opt_proc = od->pOptProc; |
116 | 0 | if (od->fOptState & OPTST_ALLOC_ARG) |
117 | 0 | AGFREE(od->optArg.argString); |
118 | |
|
119 | 0 | od->optArg.argString = o_st->pzOptArg; |
120 | | |
121 | | /* |
122 | | * IF we are presetting options, then we will ignore any un-presettable |
123 | | * options. They are the ones either marked as such. |
124 | | */ |
125 | 0 | if ( ((opts->fOptSet & OPTPROC_PRESETTING) != 0) |
126 | 0 | && ((od->fOptState & OPTST_NO_INIT) != 0) |
127 | 0 | ) |
128 | 0 | return PROBLEM; |
129 | | |
130 | | /* |
131 | | * IF this is an equivalence class option, |
132 | | * THEN |
133 | | * Save the option value that got us to this option |
134 | | * entry. (It may not be od->optChar[0], if this is an |
135 | | * equivalence entry.) |
136 | | * set the pointer to the equivalence class base |
137 | | */ |
138 | 0 | if (od->optEquivIndex != NO_EQUIVALENT) { |
139 | 0 | tOptDesc * eqv_od = opts->pOptDesc + od->optEquivIndex; |
140 | | |
141 | | /* |
142 | | * IF the current option state has not been defined (set on the |
143 | | * command line), THEN we will allow continued resetting of |
144 | | * the value. Once "defined", then it must not change. |
145 | | */ |
146 | 0 | if ((od->fOptState & OPTST_DEFINED) != 0) { |
147 | | /* |
148 | | * The equivalenced-to option has been found on the command |
149 | | * line before. Make sure new occurrences are the same type. |
150 | | * |
151 | | * IF this option has been previously equivalenced and |
152 | | * it was not the same equivalenced-to option, |
153 | | * THEN we have a usage problem. |
154 | | */ |
155 | 0 | if (eqv_od->optActualIndex != od->optIndex) { |
156 | 0 | fprintf(stderr, zmultiway_bug, eqv_od->pz_Name, od->pz_Name, |
157 | 0 | (opts->pOptDesc + eqv_od->optActualIndex)->pz_Name); |
158 | 0 | return FAILURE; |
159 | 0 | } |
160 | 0 | } else { |
161 | | /* |
162 | | * Set the equivalenced-to actual option index to no-equivalent |
163 | | * so that we set all the entries below. This option may either |
164 | | * never have been selected before, or else it was selected by |
165 | | * some sort of "presetting" mechanism. |
166 | | */ |
167 | 0 | eqv_od->optActualIndex = NO_EQUIVALENT; |
168 | 0 | } |
169 | | |
170 | 0 | if (eqv_od->optActualIndex != od->optIndex) { |
171 | | /* |
172 | | * First time through, copy over the state |
173 | | * and add in the equivalence flag |
174 | | */ |
175 | 0 | eqv_od->optActualValue = od->optValue; |
176 | 0 | eqv_od->optActualIndex = od->optIndex; |
177 | 0 | o_st->flags |= OPTST_EQUIVALENCE; |
178 | 0 | } |
179 | | |
180 | | /* |
181 | | * Copy the most recent option argument. set membership state |
182 | | * is kept in 'eqv_od->optCookie'. Do not overwrite. |
183 | | */ |
184 | 0 | eqv_od->optArg.argString = od->optArg.argString; |
185 | 0 | od = eqv_od; |
186 | |
|
187 | 0 | } else { |
188 | 0 | od->optActualValue = od->optValue; |
189 | 0 | od->optActualIndex = od->optIndex; |
190 | 0 | } |
191 | | |
192 | 0 | od->fOptState &= OPTST_PERSISTENT_MASK; |
193 | 0 | od->fOptState |= (o_st->flags & ~OPTST_PERSISTENT_MASK); |
194 | | |
195 | | /* |
196 | | * Keep track of count only for DEFINED (command line) options. |
197 | | * IF we have too many, build up an error message and bail. |
198 | | */ |
199 | 0 | if ( (od->fOptState & OPTST_DEFINED) |
200 | 0 | && (++od->optOccCt > od->optMaxCt) ) |
201 | 0 | return too_many_occurrences(opts, od); |
202 | | /* |
203 | | * If provided a procedure to call, call it |
204 | | */ |
205 | 0 | if (opt_proc != NULL) |
206 | 0 | (*opt_proc)(opts, od); |
207 | |
|
208 | 0 | return SUCCESS; |
209 | 0 | } |
210 | | |
211 | | /** |
212 | | * Find the option descriptor and option argument (if any) for the |
213 | | * next command line argument. DO NOT modify the descriptor. Put |
214 | | * all the state in the state argument so that the option can be skipped |
215 | | * without consequence (side effect). |
216 | | * |
217 | | * @param opts the program option descriptor |
218 | | * @param o_st the state of the next found option |
219 | | */ |
220 | | LOCAL tSuccess |
221 | | next_opt(tOptions * opts, tOptState * o_st) |
222 | 0 | { |
223 | 0 | { |
224 | 0 | tSuccess res = find_opt(opts, o_st); |
225 | 0 | if (! SUCCESSFUL(res)) |
226 | 0 | return res; |
227 | 0 | } |
228 | | |
229 | 0 | if ( ((o_st->flags & OPTST_DEFINED) != 0) |
230 | 0 | && ((o_st->pOD->fOptState & OPTST_NO_COMMAND) != 0)) { |
231 | 0 | fprintf(stderr, zNotCmdOpt, o_st->pOD->pz_Name); |
232 | 0 | return FAILURE; |
233 | 0 | } |
234 | | |
235 | 0 | return get_opt_arg(opts, o_st); |
236 | 0 | } |
237 | | |
238 | | /** |
239 | | * Process all the options from our current position onward. (This allows |
240 | | * interspersed options and arguments for the few non-standard programs that |
241 | | * require it.) Thus, do not rewind option indexes because some programs |
242 | | * choose to re-invoke after a non-option. |
243 | | * |
244 | | * @param[in,out] opts program options descriptor |
245 | | * @returns SUCCESS or FAILURE |
246 | | */ |
247 | | LOCAL tSuccess |
248 | | regular_opts(tOptions * opts) |
249 | 0 | { |
250 | | /* assert: opts->fOptSet & OPTPROC_IMMEDIATE == 0 */ |
251 | 0 | for (;;) { |
252 | 0 | tOptState opt_st = OPTSTATE_INITIALIZER(DEFINED); |
253 | |
|
254 | 0 | switch (next_opt(opts, &opt_st)) { |
255 | 0 | case FAILURE: goto failed_option; |
256 | 0 | case PROBLEM: return SUCCESS; /* no more args */ |
257 | 0 | case SUCCESS: break; |
258 | 0 | } |
259 | | |
260 | | /* |
261 | | * IF this is an immediate action option, |
262 | | * THEN skip it (unless we are supposed to do it a second time). |
263 | | */ |
264 | 0 | if (! DO_NORMALLY(opt_st.flags)) { |
265 | 0 | if (! DO_SECOND_TIME(opt_st.flags)) |
266 | 0 | continue; |
267 | 0 | opt_st.pOD->optOccCt--; /* don't count this repetition */ |
268 | 0 | } |
269 | | |
270 | 0 | if (! SUCCESSFUL(handle_opt(opts, &opt_st))) |
271 | 0 | break; |
272 | 0 | } failed_option:; |
273 | |
|
274 | 0 | if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) |
275 | 0 | (*opts->pUsageProc)(opts, EXIT_FAILURE); |
276 | |
|
277 | 0 | return FAILURE; |
278 | 0 | } |
279 | | |
280 | | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
281 | | * |
282 | | * THESE ROUTINES ARE CALLABLE FROM THE GENERATED OPTION PROCESSING CODE |
283 | | */ |
284 | | /*=--subblock=arg=arg_type,arg_name,arg_desc =*/ |
285 | | /*=* |
286 | | * library: opts |
287 | | * header: your-opts.h |
288 | | * |
289 | | * lib_description: |
290 | | * |
291 | | * These are the routines that libopts users may call directly from their |
292 | | * code. There are several other routines that can be called by code |
293 | | * generated by the libopts option templates, but they are not to be |
294 | | * called from any other user code. The @file{options.h} header is |
295 | | * fairly clear about this, too. |
296 | | =*/ |
297 | | |
298 | | /*=export_func optionProcess |
299 | | * |
300 | | * what: this is the main option processing routine |
301 | | * |
302 | | * arg: + tOptions * + opts + program options descriptor + |
303 | | * arg: + int + a_ct + program arg count + |
304 | | * arg: + char ** + a_v + program arg vector + |
305 | | * |
306 | | * ret_type: int |
307 | | * ret_desc: the count of the arguments processed |
308 | | * |
309 | | * doc: |
310 | | * |
311 | | * This is the main entry point for processing options. It is intended |
312 | | * that this procedure be called once at the beginning of the execution of |
313 | | * a program. Depending on options selected earlier, it is sometimes |
314 | | * necessary to stop and restart option processing, or to select completely |
315 | | * different sets of options. This can be done easily, but you generally |
316 | | * do not want to do this. |
317 | | * |
318 | | * The number of arguments processed always includes the program name. |
319 | | * If one of the arguments is "--", then it is counted and the processing |
320 | | * stops. If an error was encountered and errors are to be tolerated, then |
321 | | * the returned value is the index of the argument causing the error. |
322 | | * A hyphen by itself ("-") will also cause processing to stop and will |
323 | | * @emph{not} be counted among the processed arguments. A hyphen by itself |
324 | | * is treated as an operand. Encountering an operand stops option |
325 | | * processing. |
326 | | * |
327 | | * err: Errors will cause diagnostics to be printed. @code{exit(3)} may |
328 | | * or may not be called. It depends upon whether or not the options |
329 | | * were generated with the "allow-errors" attribute, or if the |
330 | | * ERRSKIP_OPTERR or ERRSTOP_OPTERR macros were invoked. |
331 | | =*/ |
332 | | int |
333 | | optionProcess(tOptions * opts, int a_ct, char ** a_v) |
334 | 0 | { |
335 | 0 | if (! SUCCESSFUL(validate_struct(opts, a_v[0]))) |
336 | 0 | ao_bug(zbad_data_msg); |
337 | | |
338 | | /* |
339 | | * Establish the real program name, the program full path, |
340 | | * and do all the presetting the first time thru only. |
341 | | */ |
342 | 0 | if (! ao_initialize(opts, a_ct, a_v)) |
343 | 0 | return 0; |
344 | | |
345 | | /* |
346 | | * IF we are (re)starting, |
347 | | * THEN reset option location |
348 | | */ |
349 | 0 | if (opts->curOptIdx <= 0) { |
350 | 0 | opts->curOptIdx = 1; |
351 | 0 | opts->pzCurOpt = NULL; |
352 | 0 | } |
353 | |
|
354 | 0 | if (! SUCCESSFUL(regular_opts(opts))) |
355 | 0 | return (int)opts->origArgCt; |
356 | | |
357 | | /* |
358 | | * IF there were no errors |
359 | | * AND we have RC/INI files |
360 | | * AND there is a request to save the files |
361 | | * THEN do that now before testing for conflicts. |
362 | | * (conflicts are ignored in preset options) |
363 | | */ |
364 | 0 | switch (opts->specOptIdx.save_opts) { |
365 | 0 | case 0: |
366 | 0 | case NO_EQUIVALENT: |
367 | 0 | break; |
368 | 0 | default: |
369 | 0 | { |
370 | 0 | tOptDesc * od = opts->pOptDesc + opts->specOptIdx.save_opts; |
371 | |
|
372 | 0 | if (SELECTED_OPT(od)) { |
373 | 0 | optionSaveFile(opts); |
374 | 0 | option_exits(EXIT_SUCCESS); |
375 | 0 | } |
376 | 0 | } |
377 | 0 | } |
378 | | |
379 | | /* |
380 | | * IF we are checking for errors, |
381 | | * THEN look for too few occurrences of required options |
382 | | */ |
383 | 0 | if (((opts->fOptSet & OPTPROC_ERRSTOP) != 0) |
384 | 0 | && (! is_consistent(opts))) |
385 | 0 | (*opts->pUsageProc)(opts, EXIT_FAILURE); |
386 | |
|
387 | 0 | return (int)opts->curOptIdx; |
388 | 0 | } |
389 | | |
390 | | /** @} |
391 | | * |
392 | | * Local Variables: |
393 | | * mode: C |
394 | | * c-file-style: "stroustrup" |
395 | | * indent-tabs-mode: nil |
396 | | * End: |
397 | | * end of autoopts/autoopts.c */ |