/src/ntp-dev/sntp/libopts/find.c
Line | Count | Source |
1 | | /** |
2 | | * @file check.c |
3 | | * |
4 | | * @brief Hunt for options in the option descriptor list |
5 | | * |
6 | | * This file contains the routines that deal with processing quoted strings |
7 | | * into an internal format. |
8 | | * |
9 | | * @addtogroup autoopts |
10 | | * @{ |
11 | | */ |
12 | | /* |
13 | | * This file is part of AutoOpts, a companion to AutoGen. |
14 | | * AutoOpts is free software. |
15 | | * AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved |
16 | | * |
17 | | * AutoOpts is available under any one of two licenses. The license |
18 | | * in use must be one of these two and the choice is under the control |
19 | | * of the user of the license. |
20 | | * |
21 | | * The GNU Lesser General Public License, version 3 or later |
22 | | * See the files "COPYING.lgplv3" and "COPYING.gplv3" |
23 | | * |
24 | | * The Modified Berkeley Software Distribution License |
25 | | * See the file "COPYING.mbsd" |
26 | | * |
27 | | * These files have the following sha256 sums: |
28 | | * |
29 | | * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 |
30 | | * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 |
31 | | * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd |
32 | | */ |
33 | | |
34 | | /** |
35 | | * find the name and name length we are looking for |
36 | | */ |
37 | | static int |
38 | | parse_opt(char const ** nm_pp, char ** arg_pp, char * buf, size_t bufsz) |
39 | 0 | { |
40 | 0 | int res = 0; |
41 | 0 | char const * p = *nm_pp; |
42 | 0 | *arg_pp = NULL; |
43 | |
|
44 | 0 | for (;;) { |
45 | 0 | switch (*(p++)) { |
46 | 0 | case NUL: return res; |
47 | | |
48 | 0 | case '=': |
49 | 0 | memcpy(buf, *nm_pp, (size_t)res); |
50 | |
|
51 | 0 | buf[res] = NUL; |
52 | 0 | *nm_pp = buf; |
53 | 0 | *arg_pp = (char *)p; |
54 | 0 | return res; |
55 | | |
56 | 0 | default: |
57 | 0 | if (++res >= (int)bufsz) |
58 | 0 | return -1; |
59 | 0 | } |
60 | 0 | } |
61 | 0 | } |
62 | | |
63 | | /** |
64 | | * print out the options that match the given name. |
65 | | * |
66 | | * @param pOpts option data |
67 | | * @param opt_name name of option to look for |
68 | | */ |
69 | | static void |
70 | | opt_ambiguities(tOptions * opts, char const * name, int nm_len) |
71 | 0 | { |
72 | 0 | char const * const hyph = |
73 | 0 | NAMED_OPTS(opts) ? "" : LONG_OPT_MARKER; |
74 | |
|
75 | 0 | tOptDesc * pOD = opts->pOptDesc; |
76 | 0 | int idx = 0; |
77 | |
|
78 | 0 | fputs(zambig_list_msg, stderr); |
79 | 0 | do { |
80 | 0 | if (pOD->pz_Name == NULL) |
81 | 0 | continue; /* doc option */ |
82 | | |
83 | 0 | if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0) |
84 | 0 | fprintf(stderr, zambig_file, hyph, pOD->pz_Name); |
85 | | |
86 | 0 | else if ( (pOD->pz_DisableName != NULL) |
87 | 0 | && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0) |
88 | 0 | ) |
89 | 0 | fprintf(stderr, zambig_file, hyph, pOD->pz_DisableName); |
90 | 0 | } while (pOD++, (++idx < opts->optCt)); |
91 | 0 | } |
92 | | |
93 | | /** |
94 | | * Determine the number of options that match the name |
95 | | * |
96 | | * @param pOpts option data |
97 | | * @param opt_name name of option to look for |
98 | | * @param nm_len length of provided name |
99 | | * @param index pointer to int for option index |
100 | | * @param disable pointer to bool to mark disabled option |
101 | | * @return count of options that match |
102 | | */ |
103 | | static int |
104 | | opt_match_ct(tOptions * opts, char const * name, int nm_len, |
105 | | int * ixp, bool * disable) |
106 | 0 | { |
107 | 0 | int matchCt = 0; |
108 | 0 | int idx = 0; |
109 | 0 | int idxLim = opts->optCt; |
110 | 0 | tOptDesc * pOD = opts->pOptDesc; |
111 | |
|
112 | 0 | do { |
113 | | /* |
114 | | * If option disabled or a doc option, skip to next |
115 | | */ |
116 | 0 | if (pOD->pz_Name == NULL) |
117 | 0 | continue; |
118 | | |
119 | 0 | if ( SKIP_OPT(pOD) |
120 | 0 | && (pOD->fOptState != (OPTST_OMITTED | OPTST_NO_INIT))) |
121 | 0 | continue; |
122 | | |
123 | 0 | if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0) { |
124 | | /* |
125 | | * IF we have a complete match |
126 | | * THEN it takes priority over any already located partial |
127 | | */ |
128 | 0 | if (pOD->pz_Name[ nm_len ] == NUL) { |
129 | 0 | *ixp = idx; |
130 | 0 | return 1; |
131 | 0 | } |
132 | 0 | } |
133 | | |
134 | | /* |
135 | | * IF there is a disable name |
136 | | * *AND* the option name matches the disable name |
137 | | * THEN ... |
138 | | */ |
139 | 0 | else if ( (pOD->pz_DisableName != NULL) |
140 | 0 | && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0) |
141 | 0 | ) { |
142 | 0 | *disable = true; |
143 | | |
144 | | /* |
145 | | * IF we have a complete match |
146 | | * THEN it takes priority over any already located partial |
147 | | */ |
148 | 0 | if (pOD->pz_DisableName[ nm_len ] == NUL) { |
149 | 0 | *ixp = idx; |
150 | 0 | return 1; |
151 | 0 | } |
152 | 0 | } |
153 | | |
154 | 0 | else |
155 | 0 | continue; /* does not match any option */ |
156 | | |
157 | | /* |
158 | | * We found a full or partial match, either regular or disabling. |
159 | | * Remember the index for later. |
160 | | */ |
161 | 0 | *ixp = idx; |
162 | 0 | ++matchCt; |
163 | |
|
164 | 0 | } while (pOD++, (++idx < idxLim)); |
165 | | |
166 | 0 | return matchCt; |
167 | 0 | } |
168 | | |
169 | | /** |
170 | | * Set the option to the indicated option number. |
171 | | * |
172 | | * @param opts option data |
173 | | * @param arg option argument (if glued to name) |
174 | | * @param idx option index |
175 | | * @param disable mark disabled option |
176 | | * @param st state about current option |
177 | | */ |
178 | | static tSuccess |
179 | | opt_set(tOptions * opts, char * arg, int idx, bool disable, tOptState * st) |
180 | 0 | { |
181 | 0 | tOptDesc * pOD = opts->pOptDesc + idx; |
182 | |
|
183 | 0 | if (SKIP_OPT(pOD)) { |
184 | 0 | if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0) |
185 | 0 | return FAILURE; |
186 | | |
187 | 0 | fprintf(stderr, zDisabledErr, opts->pzProgName, pOD->pz_Name); |
188 | 0 | if (pOD->pzText != NULL) |
189 | 0 | fprintf(stderr, SET_OFF_FMT, pOD->pzText); |
190 | 0 | fputc(NL, stderr); |
191 | 0 | (*opts->pUsageProc)(opts, EXIT_FAILURE); |
192 | | /* NOTREACHED */ |
193 | 0 | _exit(EXIT_FAILURE); /* to be certain */ |
194 | 0 | } |
195 | | |
196 | | /* |
197 | | * IF we found a disablement name, |
198 | | * THEN set the bit in the callers' flag word |
199 | | */ |
200 | 0 | if (disable) |
201 | 0 | st->flags |= OPTST_DISABLED; |
202 | |
|
203 | 0 | st->pOD = pOD; |
204 | 0 | st->pzOptArg = arg; |
205 | 0 | st->optType = TOPT_LONG; |
206 | |
|
207 | 0 | return SUCCESS; |
208 | 0 | } |
209 | | |
210 | | /** |
211 | | * An option was not found. Check for default option and set it |
212 | | * if there is one. Otherwise, handle the error. |
213 | | * |
214 | | * @param opts option data |
215 | | * @param name name of option to look for |
216 | | * @param arg option argument |
217 | | * @param st state about current option |
218 | | * |
219 | | * @return success status |
220 | | */ |
221 | | static tSuccess |
222 | | opt_unknown(tOptions * opts, char const * name, char * arg, tOptState * st) |
223 | 0 | { |
224 | | /* |
225 | | * IF there is no equal sign |
226 | | * *AND* we are using named arguments |
227 | | * *AND* there is a default named option, |
228 | | * THEN return that option. |
229 | | */ |
230 | 0 | if ( (arg == NULL) |
231 | 0 | && NAMED_OPTS(opts) |
232 | 0 | && (opts->specOptIdx.default_opt != NO_EQUIVALENT)) { |
233 | |
|
234 | 0 | st->pOD = opts->pOptDesc + opts->specOptIdx.default_opt; |
235 | 0 | st->pzOptArg = name; |
236 | 0 | st->optType = TOPT_DEFAULT; |
237 | 0 | return SUCCESS; |
238 | 0 | } |
239 | | |
240 | 0 | if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) { |
241 | 0 | fprintf(stderr, zIllOptStr, opts->pzProgPath, name); |
242 | 0 | (*opts->pUsageProc)(opts, EXIT_FAILURE); |
243 | | /* NOTREACHED */ |
244 | 0 | _exit(EXIT_FAILURE); /* to be certain */ |
245 | 0 | } |
246 | | |
247 | 0 | return FAILURE; |
248 | 0 | } |
249 | | |
250 | | /** |
251 | | * Several options match the provided name. |
252 | | * |
253 | | * @param opts option data |
254 | | * @param name name of option to look for |
255 | | * @param match_ct number of matching options |
256 | | * |
257 | | * @return success status (always FAILURE, if it returns) |
258 | | */ |
259 | | static tSuccess |
260 | | opt_ambiguous(tOptions * opts, char const * name, int match_ct) |
261 | 0 | { |
262 | 0 | if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) { |
263 | 0 | fprintf(stderr, zambig_opt_fmt, opts->pzProgPath, name, match_ct); |
264 | 0 | if (match_ct <= 4) |
265 | 0 | opt_ambiguities(opts, name, (int)strlen(name)); |
266 | 0 | (*opts->pUsageProc)(opts, EXIT_FAILURE); |
267 | | /* NOTREACHED */ |
268 | 0 | _exit(EXIT_FAILURE); /* to be certain */ |
269 | 0 | } |
270 | 0 | return FAILURE; |
271 | 0 | } |
272 | | |
273 | | /*=export_func optionVendorOption |
274 | | * private: |
275 | | * |
276 | | * what: Process a vendor option |
277 | | * arg: + tOptions * + pOpts + program options descriptor + |
278 | | * arg: + tOptDesc * + pOptDesc + the descriptor for this arg + |
279 | | * |
280 | | * doc: |
281 | | * For POSIX specified utilities, the options are constrained to the options, |
282 | | * @xref{config attributes, Program Configuration}. AutoOpts clients should |
283 | | * never specify this directly. It gets referenced when the option |
284 | | * definitions contain a "vendor-opt" attribute. |
285 | | =*/ |
286 | | void |
287 | | optionVendorOption(tOptions * pOpts, tOptDesc * pOD) |
288 | 0 | { |
289 | 0 | tOptState opt_st = OPTSTATE_INITIALIZER(PRESET); |
290 | 0 | char const * vopt_str = pOD->optArg.argString; |
291 | |
|
292 | 0 | if (pOpts <= OPTPROC_EMIT_LIMIT) |
293 | 0 | return; |
294 | | |
295 | 0 | if ((pOD->fOptState & OPTST_RESET) != 0) |
296 | 0 | return; |
297 | | |
298 | 0 | if ((pOD->fOptState & OPTPROC_IMMEDIATE) == 0) |
299 | 0 | opt_st.flags = OPTST_DEFINED; |
300 | |
|
301 | 0 | if ( ((pOpts->fOptSet & OPTPROC_VENDOR_OPT) == 0) |
302 | 0 | || ! SUCCESSFUL(opt_find_long(pOpts, vopt_str, &opt_st)) |
303 | 0 | || ! SUCCESSFUL(get_opt_arg(pOpts, &opt_st)) ) |
304 | 0 | { |
305 | 0 | fprintf(stderr, zIllVendOptStr, pOpts->pzProgName, vopt_str); |
306 | 0 | (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); |
307 | | /* NOTREACHED */ |
308 | 0 | _exit(EXIT_FAILURE); /* to be certain */ |
309 | 0 | } |
310 | | |
311 | | /* |
312 | | * See if we are in immediate handling state. |
313 | | */ |
314 | 0 | if (pOpts->fOptSet & OPTPROC_IMMEDIATE) { |
315 | | /* |
316 | | * See if the enclosed option is okay with that state. |
317 | | */ |
318 | 0 | if (DO_IMMEDIATELY(opt_st.flags)) |
319 | 0 | (void)handle_opt(pOpts, &opt_st); |
320 | |
|
321 | 0 | } else { |
322 | | /* |
323 | | * non-immediate direction. |
324 | | * See if the enclosed option is okay with that state. |
325 | | */ |
326 | 0 | if (DO_NORMALLY(opt_st.flags) || DO_SECOND_TIME(opt_st.flags)) |
327 | 0 | (void)handle_opt(pOpts, &opt_st); |
328 | 0 | } |
329 | 0 | } |
330 | | |
331 | | /** |
332 | | * Find the option descriptor by full name. |
333 | | * |
334 | | * @param opts option data |
335 | | * @param opt_name name of option to look for |
336 | | * @param state state about current option |
337 | | * |
338 | | * @return success status |
339 | | */ |
340 | | static tSuccess |
341 | | opt_find_long(tOptions * opts, char const * opt_name, tOptState * state) |
342 | 0 | { |
343 | 0 | char name_buf[128]; |
344 | 0 | char * opt_arg; |
345 | 0 | int nm_len = parse_opt(&opt_name, &opt_arg, name_buf, sizeof(name_buf)); |
346 | |
|
347 | 0 | int idx = 0; |
348 | 0 | bool disable = false; |
349 | 0 | int ct; |
350 | |
|
351 | 0 | if (nm_len <= 1) { |
352 | 0 | if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0) |
353 | 0 | return FAILURE; |
354 | | |
355 | 0 | fprintf(stderr, zInvalOptName, opts->pzProgName, opt_name); |
356 | 0 | (*opts->pUsageProc)(opts, EXIT_FAILURE); |
357 | | /* NOTREACHED */ |
358 | 0 | _exit(EXIT_FAILURE); /* to be certain */ |
359 | 0 | } |
360 | | |
361 | 0 | ct = opt_match_ct(opts, opt_name, nm_len, &idx, &disable); |
362 | | |
363 | | /* |
364 | | * See if we found one match, no matches or multiple matches. |
365 | | */ |
366 | 0 | switch (ct) { |
367 | 0 | case 1: return opt_set(opts, opt_arg, idx, disable, state); |
368 | 0 | case 0: return opt_unknown(opts, opt_name, opt_arg, state); |
369 | 0 | default: return opt_ambiguous(opts, opt_name, ct); |
370 | 0 | } |
371 | 0 | } |
372 | | |
373 | | |
374 | | /** |
375 | | * Find the short option descriptor for the current option |
376 | | * |
377 | | * @param pOpts option data |
378 | | * @param optValue option flag character |
379 | | * @param pOptState state about current option |
380 | | */ |
381 | | static tSuccess |
382 | | opt_find_short(tOptions * pOpts, uint_t optValue, tOptState * pOptState) |
383 | 0 | { |
384 | 0 | tOptDesc * pRes = pOpts->pOptDesc; |
385 | 0 | int ct = pOpts->optCt; |
386 | | |
387 | | /* |
388 | | * Search the option list |
389 | | */ |
390 | 0 | do { |
391 | 0 | if (optValue != pRes->optValue) |
392 | 0 | continue; |
393 | | |
394 | 0 | if (SKIP_OPT(pRes)) { |
395 | 0 | if ( (pRes->fOptState == (OPTST_OMITTED | OPTST_NO_INIT)) |
396 | 0 | && (pRes->pz_Name != NULL)) { |
397 | 0 | if ((pOpts->fOptSet & OPTPROC_ERRSTOP) == 0) |
398 | 0 | return FAILURE; |
399 | | |
400 | 0 | fprintf(stderr, zDisabledErr, pOpts->pzProgPath, pRes->pz_Name); |
401 | 0 | if (pRes->pzText != NULL) |
402 | 0 | fprintf(stderr, SET_OFF_FMT, pRes->pzText); |
403 | 0 | fputc(NL, stderr); |
404 | 0 | (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); |
405 | | /* NOTREACHED */ |
406 | 0 | _exit(EXIT_FAILURE); /* to be certain */ |
407 | 0 | } |
408 | 0 | goto short_opt_error; |
409 | 0 | } |
410 | | |
411 | 0 | pOptState->pOD = pRes; |
412 | 0 | pOptState->optType = TOPT_SHORT; |
413 | 0 | return SUCCESS; |
414 | |
|
415 | 0 | } while (pRes++, --ct > 0); |
416 | | |
417 | | /* |
418 | | * IF the character value is a digit |
419 | | * AND there is a special number option ("-n") |
420 | | * THEN the result is the "option" itself and the |
421 | | * option is the specially marked "number" option. |
422 | | */ |
423 | 0 | if ( IS_DEC_DIGIT_CHAR(optValue) |
424 | 0 | && (pOpts->specOptIdx.number_option != NO_EQUIVALENT) ) { |
425 | 0 | pOptState->pOD = \ |
426 | 0 | pRes = pOpts->pOptDesc + pOpts->specOptIdx.number_option; |
427 | 0 | (pOpts->pzCurOpt)--; |
428 | 0 | pOptState->optType = TOPT_SHORT; |
429 | 0 | return SUCCESS; |
430 | 0 | } |
431 | | |
432 | 0 | short_opt_error: |
433 | | |
434 | | /* |
435 | | * IF we are to stop on errors (the default, actually) |
436 | | * THEN call the usage procedure. |
437 | | */ |
438 | 0 | if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) { |
439 | 0 | fprintf(stderr, zIllOptChr, pOpts->pzProgPath, optValue); |
440 | 0 | (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); |
441 | | /* NOTREACHED */ |
442 | 0 | _exit(EXIT_FAILURE); /* to be certain */ |
443 | 0 | } |
444 | | |
445 | 0 | return FAILURE; |
446 | 0 | } |
447 | | |
448 | | /** |
449 | | * Process option with a required argument. Long options can either have a |
450 | | * separate command line argument, or an argument attached by the '=' |
451 | | * character. Figure out which. |
452 | | * |
453 | | * @param[in,out] opts the program option descriptor |
454 | | * @param[in,out] o_st the option processing state |
455 | | * @returns SUCCESS or FAILURE |
456 | | */ |
457 | | static tSuccess |
458 | | get_opt_arg_must(tOptions * opts, tOptState * o_st) |
459 | 0 | { |
460 | 0 | switch (o_st->optType) { |
461 | 0 | case TOPT_SHORT: |
462 | | /* |
463 | | * See if an arg string follows the flag character |
464 | | */ |
465 | 0 | if (*++(opts->pzCurOpt) == NUL) |
466 | 0 | opts->pzCurOpt = opts->origArgVect[ opts->curOptIdx++ ]; |
467 | 0 | o_st->pzOptArg = opts->pzCurOpt; |
468 | 0 | break; |
469 | | |
470 | 0 | case TOPT_LONG: |
471 | | /* |
472 | | * See if an arg string has already been assigned (glued on |
473 | | * with an `=' character) |
474 | | */ |
475 | 0 | if (o_st->pzOptArg == NULL) |
476 | 0 | o_st->pzOptArg = opts->origArgVect[ opts->curOptIdx++ ]; |
477 | 0 | break; |
478 | | |
479 | 0 | default: |
480 | 0 | #ifdef DEBUG |
481 | 0 | fputs("AutoOpts lib error: option type not selected\n", stderr); |
482 | 0 | option_exits(EXIT_FAILURE); |
483 | 0 | #endif |
484 | |
|
485 | 0 | case TOPT_DEFAULT: |
486 | | /* |
487 | | * The option was selected by default. The current token is |
488 | | * the option argument. |
489 | | */ |
490 | 0 | break; |
491 | 0 | } |
492 | | |
493 | | /* |
494 | | * Make sure we did not overflow the argument list. |
495 | | */ |
496 | 0 | if (opts->curOptIdx > opts->origArgCt) { |
497 | 0 | fprintf(stderr, zMisArg, opts->pzProgPath, o_st->pOD->pz_Name); |
498 | 0 | return FAILURE; |
499 | 0 | } |
500 | | |
501 | 0 | opts->pzCurOpt = NULL; /* next time advance to next arg */ |
502 | 0 | return SUCCESS; |
503 | 0 | } |
504 | | |
505 | | /** |
506 | | * Process an option with an optional argument. For short options, it looks |
507 | | * at the character after the option character, or it consumes the next full |
508 | | * argument. For long options, it looks for an '=' character attachment to |
509 | | * the long option name before deciding to take the next command line |
510 | | * argument. |
511 | | * |
512 | | * @param pOpts the option descriptor |
513 | | * @param o_st a structure for managing the current processing state |
514 | | * @returns SUCCESS or does not return |
515 | | */ |
516 | | static tSuccess |
517 | | get_opt_arg_may(tOptions * pOpts, tOptState * o_st) |
518 | 0 | { |
519 | | /* |
520 | | * An option argument is optional. |
521 | | */ |
522 | 0 | switch (o_st->optType) { |
523 | 0 | case TOPT_SHORT: |
524 | 0 | if (*++pOpts->pzCurOpt != NUL) |
525 | 0 | o_st->pzOptArg = pOpts->pzCurOpt; |
526 | 0 | else { |
527 | 0 | char * pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; |
528 | | |
529 | | /* |
530 | | * BECAUSE it is optional, we must make sure |
531 | | * we did not find another flag and that there |
532 | | * is such an argument. |
533 | | */ |
534 | 0 | if ((pzLA == NULL) || (*pzLA == '-')) |
535 | 0 | o_st->pzOptArg = NULL; |
536 | 0 | else { |
537 | 0 | pOpts->curOptIdx++; /* argument found */ |
538 | 0 | o_st->pzOptArg = pzLA; |
539 | 0 | } |
540 | 0 | } |
541 | 0 | break; |
542 | | |
543 | 0 | case TOPT_LONG: |
544 | | /* |
545 | | * Look for an argument if we don't already have one (glued on |
546 | | * with a `=' character) *AND* we are not in named argument mode |
547 | | */ |
548 | 0 | if ( (o_st->pzOptArg == NULL) |
549 | 0 | && (! NAMED_OPTS(pOpts))) { |
550 | 0 | char * pzLA = pOpts->origArgVect[ pOpts->curOptIdx ]; |
551 | | |
552 | | /* |
553 | | * BECAUSE it is optional, we must make sure |
554 | | * we did not find another flag and that there |
555 | | * is such an argument. |
556 | | */ |
557 | 0 | if ((pzLA == NULL) || (*pzLA == '-')) |
558 | 0 | o_st->pzOptArg = NULL; |
559 | 0 | else { |
560 | 0 | pOpts->curOptIdx++; /* argument found */ |
561 | 0 | o_st->pzOptArg = pzLA; |
562 | 0 | } |
563 | 0 | } |
564 | 0 | break; |
565 | | |
566 | 0 | default: |
567 | 0 | case TOPT_DEFAULT: |
568 | 0 | ao_bug(zbad_default_msg); |
569 | 0 | } |
570 | | |
571 | | /* |
572 | | * After an option with an optional argument, we will |
573 | | * *always* start with the next option because if there |
574 | | * were any characters following the option name/flag, |
575 | | * they would be interpreted as the argument. |
576 | | */ |
577 | 0 | pOpts->pzCurOpt = NULL; |
578 | 0 | return SUCCESS; |
579 | 0 | } |
580 | | |
581 | | /** |
582 | | * Process option that does not have an argument. |
583 | | * |
584 | | * @param[in,out] opts the program option descriptor |
585 | | * @param[in,out] o_st the option processing state |
586 | | * @returns SUCCESS or FAILURE |
587 | | */ |
588 | | static tSuccess |
589 | | get_opt_arg_none(tOptions * pOpts, tOptState * o_st) |
590 | 0 | { |
591 | | /* |
592 | | * No option argument. Make sure next time around we find |
593 | | * the correct option flag character for short options |
594 | | */ |
595 | 0 | if (o_st->optType == TOPT_SHORT) |
596 | 0 | (pOpts->pzCurOpt)++; |
597 | | |
598 | | /* |
599 | | * It is a long option. Make sure there was no ``=xxx'' argument |
600 | | */ |
601 | 0 | else if (o_st->pzOptArg != NULL) { |
602 | 0 | fprintf(stderr, zNoArg, pOpts->pzProgPath, o_st->pOD->pz_Name); |
603 | 0 | return FAILURE; |
604 | 0 | } |
605 | | |
606 | | /* |
607 | | * It is a long option. Advance to next command line argument. |
608 | | */ |
609 | 0 | else |
610 | 0 | pOpts->pzCurOpt = NULL; |
611 | | |
612 | 0 | return SUCCESS; |
613 | 0 | } |
614 | | |
615 | | /** |
616 | | * Process option. Figure out whether or not to look for an option argument. |
617 | | * |
618 | | * @param[in,out] opts the program option descriptor |
619 | | * @param[in,out] o_st the option processing state |
620 | | * @returns SUCCESS or FAILURE |
621 | | */ |
622 | | static tSuccess |
623 | | get_opt_arg(tOptions * opts, tOptState * o_st) |
624 | 0 | { |
625 | 0 | o_st->flags |= (o_st->pOD->fOptState & OPTST_PERSISTENT_MASK); |
626 | | |
627 | | /* |
628 | | * Disabled options and options specified to not have arguments |
629 | | * are handled with the "none" procedure. Otherwise, check the |
630 | | * optional flag and call either the "may" or "must" function. |
631 | | */ |
632 | 0 | if ((o_st->flags & OPTST_DISABLED) != 0) |
633 | 0 | return get_opt_arg_none(opts, o_st); |
634 | | |
635 | 0 | switch (OPTST_GET_ARGTYPE(o_st->flags)) { |
636 | 0 | case OPARG_TYPE_STATIC: |
637 | 0 | { |
638 | | /* |
639 | | * Propagate the static arg |
640 | | */ |
641 | 0 | tSuccess res = get_opt_arg_none(opts, o_st); |
642 | 0 | o_st->pzOptArg = o_st->pOD->optArg.argString; |
643 | 0 | return res; |
644 | 0 | } |
645 | | |
646 | 0 | case OPARG_TYPE_NONE: |
647 | 0 | return get_opt_arg_none(opts, o_st); |
648 | 0 | } |
649 | | |
650 | 0 | if (o_st->flags & OPTST_ARG_OPTIONAL) |
651 | 0 | return get_opt_arg_may( opts, o_st); |
652 | | |
653 | 0 | return get_opt_arg_must(opts, o_st); |
654 | 0 | } |
655 | | |
656 | | /** |
657 | | * Find the option descriptor for the current option. |
658 | | * |
659 | | * @param[in,out] opts the program option descriptor |
660 | | * @param[in,out] o_st the option processing state |
661 | | * @returns SUCCESS or FAILURE |
662 | | */ |
663 | | static tSuccess |
664 | | find_opt(tOptions * opts, tOptState * o_st) |
665 | 0 | { |
666 | | /* |
667 | | * IF we are continuing a short option list (e.g. -xyz...) |
668 | | * THEN continue a single flag option. |
669 | | * OTHERWISE see if there is room to advance and then do so. |
670 | | */ |
671 | 0 | if ((opts->pzCurOpt != NULL) && (*opts->pzCurOpt != NUL)) |
672 | 0 | return opt_find_short(opts, (uint8_t)*(opts->pzCurOpt), o_st); |
673 | | |
674 | 0 | if (opts->curOptIdx >= opts->origArgCt) |
675 | 0 | return PROBLEM; /* NORMAL COMPLETION */ |
676 | | |
677 | 0 | opts->pzCurOpt = opts->origArgVect[ opts->curOptIdx ]; |
678 | | |
679 | | /* |
680 | | * IF all arguments must be named options, ... |
681 | | */ |
682 | 0 | if (NAMED_OPTS(opts)) { |
683 | 0 | char * pz = opts->pzCurOpt; |
684 | 0 | int def; |
685 | 0 | tSuccess res; |
686 | 0 | uint16_t * def_opt; |
687 | |
|
688 | 0 | opts->curOptIdx++; |
689 | |
|
690 | 0 | if (*pz != '-') |
691 | 0 | return opt_find_long(opts, pz, o_st); |
692 | | |
693 | | /* |
694 | | * The name is prefixed with one or more hyphens. Strip them off |
695 | | * and disable the "default_opt" setting. Use heavy recasting to |
696 | | * strip off the "const" quality of the "default_opt" field. |
697 | | */ |
698 | 0 | while (*(++pz) == '-') ; |
699 | 0 | def_opt = VOIDP(&(opts->specOptIdx.default_opt)); |
700 | 0 | def = *def_opt; |
701 | 0 | *def_opt = NO_EQUIVALENT; |
702 | 0 | res = opt_find_long(opts, pz, o_st); |
703 | 0 | *def_opt = (uint16_t)def; |
704 | 0 | return res; |
705 | 0 | } |
706 | | |
707 | | /* |
708 | | * Note the kind of flag/option marker |
709 | | */ |
710 | 0 | if (*((opts->pzCurOpt)++) != '-') |
711 | 0 | return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */ |
712 | | |
713 | | /* |
714 | | * Special hack for a hyphen by itself |
715 | | */ |
716 | 0 | if (*(opts->pzCurOpt) == NUL) |
717 | 0 | return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */ |
718 | | |
719 | | /* |
720 | | * The current argument is to be processed as an option argument |
721 | | */ |
722 | 0 | opts->curOptIdx++; |
723 | | |
724 | | /* |
725 | | * We have an option marker. |
726 | | * Test the next character for long option indication |
727 | | */ |
728 | 0 | if (opts->pzCurOpt[0] == '-') { |
729 | 0 | if (*++(opts->pzCurOpt) == NUL) |
730 | | /* |
731 | | * NORMAL COMPLETION - NOT this arg, but rest are operands |
732 | | */ |
733 | 0 | return PROBLEM; |
734 | | |
735 | | /* |
736 | | * We do not allow the hyphen to be used as a flag value. |
737 | | * Therefore, if long options are not to be accepted, we punt. |
738 | | */ |
739 | 0 | if ((opts->fOptSet & OPTPROC_LONGOPT) == 0) { |
740 | 0 | fprintf(stderr, zIllOptStr, opts->pzProgPath, opts->pzCurOpt-2); |
741 | 0 | return FAILURE; |
742 | 0 | } |
743 | | |
744 | 0 | return opt_find_long(opts, opts->pzCurOpt, o_st); |
745 | 0 | } |
746 | | |
747 | | /* |
748 | | * If short options are not allowed, then do long |
749 | | * option processing. Otherwise the character must be a |
750 | | * short (i.e. single character) option. |
751 | | */ |
752 | 0 | if ((opts->fOptSet & OPTPROC_SHORTOPT) != 0) |
753 | 0 | return opt_find_short(opts, (uint8_t)*(opts->pzCurOpt), o_st); |
754 | | |
755 | 0 | return opt_find_long(opts, opts->pzCurOpt, o_st); |
756 | 0 | } |
757 | | |
758 | | /** @} |
759 | | * |
760 | | * Local Variables: |
761 | | * mode: C |
762 | | * c-file-style: "stroustrup" |
763 | | * indent-tabs-mode: nil |
764 | | * End: |
765 | | * end of autoopts/find.c */ |