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