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