/src/ntp-dev/sntp/libopts/enum.c
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | /** |
3 | | * \file enumeration.c |
4 | | * |
5 | | * Handle options with enumeration names and bit mask bit names |
6 | | * for their arguments. |
7 | | * |
8 | | * @addtogroup autoopts |
9 | | * @{ |
10 | | */ |
11 | | /* |
12 | | * This routine will run run-on options through a pager so the |
13 | | * user may examine, print or edit them at their leisure. |
14 | | * |
15 | | * This file is part of AutoOpts, a companion to AutoGen. |
16 | | * AutoOpts is free software. |
17 | | * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved |
18 | | * |
19 | | * AutoOpts is available under any one of two licenses. The license |
20 | | * in use must be one of these two and the choice is under the control |
21 | | * of the user of the license. |
22 | | * |
23 | | * The GNU Lesser General Public License, version 3 or later |
24 | | * See the files "COPYING.lgplv3" and "COPYING.gplv3" |
25 | | * |
26 | | * The Modified Berkeley Software Distribution License |
27 | | * See the file "COPYING.mbsd" |
28 | | * |
29 | | * These files have the following sha256 sums: |
30 | | * |
31 | | * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 |
32 | | * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 |
33 | | * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd |
34 | | */ |
35 | | |
36 | | /* = = = START-STATIC-FORWARD = = = */ |
37 | | static void |
38 | | enum_err(tOptions * pOpts, tOptDesc * pOD, |
39 | | char const * const * paz_names, int name_ct); |
40 | | |
41 | | static uintptr_t |
42 | | find_name(char const * name, tOptions * pOpts, tOptDesc * pOD, |
43 | | char const * const * paz_names, unsigned int name_ct); |
44 | | |
45 | | static void |
46 | | set_memb_shell(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names, |
47 | | unsigned int name_ct); |
48 | | |
49 | | static void |
50 | | set_memb_names(tOptions * opts, tOptDesc * od, char const * const * nm_list, |
51 | | unsigned int nm_ct); |
52 | | |
53 | | static uintptr_t |
54 | | check_membership_start(tOptDesc * od, char const ** argp, bool * invert); |
55 | | |
56 | | static uintptr_t |
57 | | find_member_bit(tOptions * opts, tOptDesc * od, char const * pz, int len, |
58 | | char const * const * nm_list, unsigned int nm_ct); |
59 | | /* = = = END-STATIC-FORWARD = = = */ |
60 | | |
61 | | static void |
62 | | enum_err(tOptions * pOpts, tOptDesc * pOD, |
63 | | char const * const * paz_names, int name_ct) |
64 | 0 | { |
65 | 0 | size_t max_len = 0; |
66 | 0 | size_t ttl_len = 0; |
67 | 0 | int ct_down = name_ct; |
68 | 0 | int hidden = 0; |
69 | | |
70 | | /* |
71 | | * A real "pOpts" pointer means someone messed up. Give a real error. |
72 | | */ |
73 | 0 | if (pOpts > OPTPROC_EMIT_LIMIT) |
74 | 0 | fprintf(option_usage_fp, pz_enum_err_fmt, pOpts->pzProgName, |
75 | 0 | pOD->optArg.argString, pOD->pz_Name); |
76 | |
|
77 | 0 | fprintf(option_usage_fp, zValidKeys, pOD->pz_Name); |
78 | | |
79 | | /* |
80 | | * If the first name starts with this funny character, then we have |
81 | | * a first value with an unspellable name. You cannot specify it. |
82 | | * So, we don't list it either. |
83 | | */ |
84 | 0 | if (**paz_names == 0x7F) { |
85 | 0 | paz_names++; |
86 | 0 | hidden = 1; |
87 | 0 | ct_down = --name_ct; |
88 | 0 | } |
89 | | |
90 | | /* |
91 | | * Figure out the maximum length of any name, plus the total length |
92 | | * of all the names. |
93 | | */ |
94 | 0 | { |
95 | 0 | char const * const * paz = paz_names; |
96 | |
|
97 | 0 | do { |
98 | 0 | size_t len = strlen(*(paz++)) + 1; |
99 | 0 | if (len > max_len) |
100 | 0 | max_len = len; |
101 | 0 | ttl_len += len; |
102 | 0 | } while (--ct_down > 0); |
103 | |
|
104 | 0 | ct_down = name_ct; |
105 | 0 | } |
106 | | |
107 | | /* |
108 | | * IF any one entry is about 1/2 line or longer, print one per line |
109 | | */ |
110 | 0 | if (max_len > 35) { |
111 | 0 | do { |
112 | 0 | fprintf(option_usage_fp, ENUM_ERR_LINE, *(paz_names++)); |
113 | 0 | } while (--ct_down > 0); |
114 | 0 | } |
115 | | |
116 | | /* |
117 | | * ELSE IF they all fit on one line, then do so. |
118 | | */ |
119 | 0 | else if (ttl_len < 76) { |
120 | 0 | fputc(' ', option_usage_fp); |
121 | 0 | do { |
122 | 0 | fputc(' ', option_usage_fp); |
123 | 0 | fputs(*(paz_names++), option_usage_fp); |
124 | 0 | } while (--ct_down > 0); |
125 | 0 | fputc(NL, option_usage_fp); |
126 | 0 | } |
127 | | |
128 | | /* |
129 | | * Otherwise, columnize the output |
130 | | */ |
131 | 0 | else { |
132 | 0 | unsigned int ent_no = 0; |
133 | 0 | char zFmt[16]; /* format for all-but-last entries on a line */ |
134 | |
|
135 | 0 | sprintf(zFmt, ENUM_ERR_WIDTH, (int)max_len); |
136 | 0 | max_len = 78 / max_len; /* max_len is now max entries on a line */ |
137 | 0 | fputs(TWO_SPACES_STR, option_usage_fp); |
138 | | |
139 | | /* |
140 | | * Loop through all but the last entry |
141 | | */ |
142 | 0 | ct_down = name_ct; |
143 | 0 | while (--ct_down > 0) { |
144 | 0 | if (++ent_no == max_len) { |
145 | | /* |
146 | | * Last entry on a line. Start next line, too. |
147 | | */ |
148 | 0 | fprintf(option_usage_fp, NLSTR_SPACE_FMT, *(paz_names++)); |
149 | 0 | ent_no = 0; |
150 | 0 | } |
151 | | |
152 | 0 | else |
153 | 0 | fprintf(option_usage_fp, zFmt, *(paz_names++) ); |
154 | 0 | } |
155 | 0 | fprintf(option_usage_fp, NLSTR_FMT, *paz_names); |
156 | 0 | } |
157 | |
|
158 | 0 | if (pOpts > OPTPROC_EMIT_LIMIT) { |
159 | 0 | fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden); |
160 | |
|
161 | 0 | (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE); |
162 | | /* NOTREACHED */ |
163 | 0 | } |
164 | |
|
165 | 0 | if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) { |
166 | 0 | fprintf(option_usage_fp, zLowerBits, name_ct); |
167 | 0 | fputs(zSetMemberSettings, option_usage_fp); |
168 | 0 | } else { |
169 | 0 | fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden); |
170 | 0 | } |
171 | 0 | } |
172 | | |
173 | | /** |
174 | | * Convert a name or number into a binary number. |
175 | | * "~0" and "-1" will be converted to the largest value in the enumeration. |
176 | | * |
177 | | * @param name the keyword name (number) to convert |
178 | | * @param pOpts the program's option descriptor |
179 | | * @param pOD the option descriptor for this option |
180 | | * @param paz_names the list of keywords for this option |
181 | | * @param name_ct the count of keywords |
182 | | */ |
183 | | static uintptr_t |
184 | | find_name(char const * name, tOptions * pOpts, tOptDesc * pOD, |
185 | | char const * const * paz_names, unsigned int name_ct) |
186 | 0 | { |
187 | | /* |
188 | | * Return the matching index as a pointer sized integer. |
189 | | * The result gets stashed in a char * pointer. |
190 | | */ |
191 | 0 | uintptr_t res = name_ct; |
192 | 0 | size_t len = strlen((char *)name); |
193 | 0 | uintptr_t idx; |
194 | |
|
195 | 0 | if (IS_DEC_DIGIT_CHAR(*name)) { |
196 | 0 | char * pz = VOIDP(name); |
197 | 0 | unsigned long val = strtoul(pz, &pz, 0); |
198 | 0 | if ((*pz == NUL) && (val < name_ct)) |
199 | 0 | return (uintptr_t)val; |
200 | 0 | pz_enum_err_fmt = znum_too_large; |
201 | 0 | option_usage_fp = stderr; |
202 | 0 | enum_err(pOpts, pOD, paz_names, (int)name_ct); |
203 | 0 | return name_ct; |
204 | 0 | } |
205 | | |
206 | 0 | if (IS_INVERSION_CHAR(*name) && (name[2] == NUL)) { |
207 | 0 | if ( ((name[0] == '~') && (name[1] == '0')) |
208 | 0 | || ((name[0] == '-') && (name[1] == '1'))) |
209 | 0 | return (uintptr_t)(name_ct - 1); |
210 | 0 | goto oops; |
211 | 0 | } |
212 | | |
213 | | /* |
214 | | * Look for an exact match, but remember any partial matches. |
215 | | * Multiple partial matches means we have an ambiguous match. |
216 | | */ |
217 | 0 | for (idx = 0; idx < name_ct; idx++) { |
218 | 0 | if (strncmp((char *)paz_names[idx], (char *)name, len) == 0) { |
219 | 0 | if (paz_names[idx][len] == NUL) |
220 | 0 | return idx; /* full match */ |
221 | | |
222 | 0 | if (res == name_ct) |
223 | 0 | res = idx; /* save partial match */ |
224 | 0 | else |
225 | 0 | res = (uintptr_t)~0; /* may yet find full match */ |
226 | 0 | } |
227 | 0 | } |
228 | | |
229 | 0 | if (res < name_ct) |
230 | 0 | return res; /* partial match */ |
231 | | |
232 | 0 | oops: |
233 | |
|
234 | 0 | pz_enum_err_fmt = (res == name_ct) ? zNoKey : zambiguous_key; |
235 | 0 | option_usage_fp = stderr; |
236 | 0 | enum_err(pOpts, pOD, paz_names, (int)name_ct); |
237 | 0 | return name_ct; |
238 | 0 | } |
239 | | |
240 | | |
241 | | /*=export_func optionKeywordName |
242 | | * what: Convert between enumeration values and strings |
243 | | * private: |
244 | | * |
245 | | * arg: tOptDesc *, pOD, enumeration option description |
246 | | * arg: unsigned int, enum_val, the enumeration value to map |
247 | | * |
248 | | * ret_type: char const * |
249 | | * ret_desc: the enumeration name from const memory |
250 | | * |
251 | | * doc: This converts an enumeration value into the matching string. |
252 | | =*/ |
253 | | char const * |
254 | | optionKeywordName(tOptDesc * pOD, unsigned int enum_val) |
255 | 0 | { |
256 | 0 | tOptDesc od = { 0 }; |
257 | 0 | od.optArg.argEnum = enum_val; |
258 | |
|
259 | 0 | (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, &od ); |
260 | 0 | return od.optArg.argString; |
261 | 0 | } |
262 | | |
263 | | |
264 | | /*=export_func optionEnumerationVal |
265 | | * what: Convert from a string to an enumeration value |
266 | | * private: |
267 | | * |
268 | | * arg: tOptions *, pOpts, the program options descriptor |
269 | | * arg: tOptDesc *, pOD, enumeration option description |
270 | | * arg: char const * const *, paz_names, list of enumeration names |
271 | | * arg: unsigned int, name_ct, number of names in list |
272 | | * |
273 | | * ret_type: uintptr_t |
274 | | * ret_desc: the enumeration value |
275 | | * |
276 | | * doc: This converts the optArg.argString string from the option description |
277 | | * into the index corresponding to an entry in the name list. |
278 | | * This will match the generated enumeration value. |
279 | | * Full matches are always accepted. Partial matches are accepted |
280 | | * if there is only one partial match. |
281 | | =*/ |
282 | | uintptr_t |
283 | | optionEnumerationVal(tOptions * pOpts, tOptDesc * pOD, |
284 | | char const * const * paz_names, unsigned int name_ct) |
285 | 0 | { |
286 | 0 | uintptr_t res = 0UL; |
287 | | |
288 | | /* |
289 | | * IF the program option descriptor pointer is invalid, |
290 | | * then it is some sort of special request. |
291 | | */ |
292 | 0 | switch ((uintptr_t)pOpts) { |
293 | 0 | case (uintptr_t)OPTPROC_EMIT_USAGE: |
294 | | /* |
295 | | * print the list of enumeration names. |
296 | | */ |
297 | 0 | enum_err(pOpts, pOD, paz_names, (int)name_ct); |
298 | 0 | break; |
299 | | |
300 | 0 | case (uintptr_t)OPTPROC_EMIT_SHELL: |
301 | 0 | { |
302 | 0 | unsigned int ix = (unsigned int)pOD->optArg.argEnum; |
303 | | /* |
304 | | * print the name string. |
305 | | */ |
306 | 0 | if (ix >= name_ct) |
307 | 0 | printf(INVALID_FMT, ix); |
308 | 0 | else |
309 | 0 | fputs(paz_names[ ix ], stdout); |
310 | |
|
311 | 0 | break; |
312 | 0 | } |
313 | | |
314 | 0 | case (uintptr_t)OPTPROC_RETURN_VALNAME: |
315 | 0 | { |
316 | 0 | unsigned int ix = (unsigned int)pOD->optArg.argEnum; |
317 | | /* |
318 | | * Replace the enumeration value with the name string. |
319 | | */ |
320 | 0 | if (ix >= name_ct) |
321 | 0 | return (uintptr_t)INVALID_STR; |
322 | | |
323 | 0 | pOD->optArg.argString = paz_names[ix]; |
324 | 0 | break; |
325 | 0 | } |
326 | | |
327 | 0 | default: |
328 | 0 | if ((pOD->fOptState & OPTST_RESET) != 0) |
329 | 0 | break; |
330 | | |
331 | 0 | res = find_name(pOD->optArg.argString, pOpts, pOD, paz_names, name_ct); |
332 | |
|
333 | 0 | if (pOD->fOptState & OPTST_ALLOC_ARG) { |
334 | 0 | AGFREE(pOD->optArg.argString); |
335 | 0 | pOD->fOptState &= ~OPTST_ALLOC_ARG; |
336 | 0 | pOD->optArg.argString = NULL; |
337 | 0 | } |
338 | 0 | } |
339 | | |
340 | 0 | return res; |
341 | 0 | } |
342 | | |
343 | | static void |
344 | | set_memb_shell(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names, |
345 | | unsigned int name_ct) |
346 | 0 | { |
347 | | /* |
348 | | * print the name string. |
349 | | */ |
350 | 0 | unsigned int ix = 0; |
351 | 0 | uintptr_t bits = (uintptr_t)pOD->optCookie; |
352 | 0 | size_t len = 0; |
353 | |
|
354 | 0 | (void)pOpts; |
355 | 0 | bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1; |
356 | |
|
357 | 0 | while (bits != 0) { |
358 | 0 | if (bits & 1) { |
359 | 0 | if (len++ > 0) fputs(OR_STR, stdout); |
360 | 0 | fputs(paz_names[ix], stdout); |
361 | 0 | } |
362 | 0 | if (++ix >= name_ct) break; |
363 | 0 | bits >>= 1; |
364 | 0 | } |
365 | 0 | } |
366 | | |
367 | | static void |
368 | | set_memb_names(tOptions * opts, tOptDesc * od, char const * const * nm_list, |
369 | | unsigned int nm_ct) |
370 | 0 | { |
371 | 0 | char * pz; |
372 | 0 | uintptr_t mask = (1UL << (uintptr_t)nm_ct) - 1UL; |
373 | 0 | uintptr_t bits = (uintptr_t)od->optCookie & mask; |
374 | 0 | unsigned int ix = 0; |
375 | 0 | size_t len = 1; |
376 | | |
377 | | /* |
378 | | * Replace the enumeration value with the name string. |
379 | | * First, determine the needed length, then allocate and fill in. |
380 | | */ |
381 | 0 | while (bits != 0) { |
382 | 0 | if (bits & 1) |
383 | 0 | len += strlen(nm_list[ix]) + PLUS_STR_LEN + 1; |
384 | 0 | if (++ix >= nm_ct) break; |
385 | 0 | bits >>= 1; |
386 | 0 | } |
387 | |
|
388 | 0 | od->optArg.argString = pz = AGALOC(len, "enum"); |
389 | 0 | bits = (uintptr_t)od->optCookie & mask; |
390 | 0 | if (bits == 0) { |
391 | 0 | *pz = NUL; |
392 | 0 | return; |
393 | 0 | } |
394 | | |
395 | 0 | for (ix = 0; ; ix++) { |
396 | 0 | size_t nln; |
397 | 0 | int doit = bits & 1; |
398 | |
|
399 | 0 | bits >>= 1; |
400 | 0 | if (doit == 0) |
401 | 0 | continue; |
402 | | |
403 | 0 | nln = strlen(nm_list[ix]); |
404 | 0 | memcpy(pz, nm_list[ix], nln); |
405 | 0 | pz += nln; |
406 | 0 | if (bits == 0) |
407 | 0 | break; |
408 | 0 | memcpy(pz, PLUS_STR, PLUS_STR_LEN); |
409 | 0 | pz += PLUS_STR_LEN; |
410 | 0 | } |
411 | 0 | *pz = NUL; |
412 | 0 | (void)opts; |
413 | 0 | } |
414 | | |
415 | | /** |
416 | | * Check membership start conditions. An equal character (@samp{=}) says to |
417 | | * clear the result and not carry over any residual value. A carat |
418 | | * (@samp{^}), which may follow the equal character, says to invert the |
419 | | * result. The scanning pointer is advanced past these characters and any |
420 | | * leading white space. Invalid sequences are indicated by setting the |
421 | | * scanning pointer to NULL. |
422 | | * |
423 | | * @param od the set membership option description |
424 | | * @param argp a pointer to the string scanning pointer |
425 | | * @param invert a pointer to the boolean inversion indicator |
426 | | * |
427 | | * @returns either zero or the original value for the optCookie. |
428 | | */ |
429 | | static uintptr_t |
430 | | check_membership_start(tOptDesc * od, char const ** argp, bool * invert) |
431 | 0 | { |
432 | 0 | uintptr_t res = (uintptr_t)od->optCookie; |
433 | 0 | char const * arg = SPN_WHITESPACE_CHARS(od->optArg.argString); |
434 | 0 | if ((arg == NULL) || (*arg == NUL)) |
435 | 0 | goto member_start_fail; |
436 | | |
437 | 0 | *invert = false; |
438 | |
|
439 | 0 | switch (*arg) { |
440 | 0 | case '=': |
441 | 0 | res = 0UL; |
442 | 0 | arg = SPN_WHITESPACE_CHARS(arg + 1); |
443 | 0 | switch (*arg) { |
444 | 0 | case '=': case ',': |
445 | 0 | goto member_start_fail; |
446 | 0 | case '^': |
447 | 0 | goto inversion; |
448 | 0 | default: |
449 | 0 | break; |
450 | 0 | } |
451 | 0 | break; |
452 | | |
453 | 0 | case '^': |
454 | 0 | inversion: |
455 | 0 | *invert = true; |
456 | 0 | arg = SPN_WHITESPACE_CHARS(arg + 1); |
457 | 0 | if (*arg != ',') |
458 | 0 | break; |
459 | | /* FALLTHROUGH */ |
460 | | |
461 | 0 | case ',': |
462 | 0 | goto member_start_fail; |
463 | | |
464 | 0 | default: |
465 | 0 | break; |
466 | 0 | } |
467 | | |
468 | 0 | *argp = arg; |
469 | 0 | return res; |
470 | | |
471 | 0 | member_start_fail: |
472 | 0 | *argp = NULL; |
473 | 0 | return 0UL; |
474 | 0 | } |
475 | | |
476 | | /** |
477 | | * convert a name to a bit. Look up a name string to get a bit number |
478 | | * and shift the value "1" left that number of bits. |
479 | | * |
480 | | * @param opts program options descriptor |
481 | | * @param od the set membership option description |
482 | | * @param pz address of the start of the bit name |
483 | | * @param nm_list the list of names for this option |
484 | | * @param nm_ct the number of entries in this list |
485 | | * |
486 | | * @returns 0UL on error, other an unsigned long with the correct bit set. |
487 | | */ |
488 | | static uintptr_t |
489 | | find_member_bit(tOptions * opts, tOptDesc * od, char const * pz, int len, |
490 | | char const * const * nm_list, unsigned int nm_ct) |
491 | 0 | { |
492 | 0 | char nm_buf[ AO_NAME_SIZE ]; |
493 | |
|
494 | 0 | memcpy(nm_buf, pz, len); |
495 | 0 | nm_buf[len] = NUL; |
496 | |
|
497 | 0 | { |
498 | 0 | unsigned int shift_ct = (unsigned int) |
499 | 0 | find_name(nm_buf, opts, od, nm_list, nm_ct); |
500 | 0 | if (shift_ct >= nm_ct) |
501 | 0 | return 0UL; |
502 | | |
503 | 0 | return 1UL << shift_ct; |
504 | 0 | } |
505 | 0 | } |
506 | | |
507 | | /*=export_func optionMemberList |
508 | | * what: Get the list of members of a bit mask set |
509 | | * |
510 | | * arg: tOptDesc *, od, the set membership option description |
511 | | * |
512 | | * ret_type: char * |
513 | | * ret_desc: the names of the set bits |
514 | | * |
515 | | * doc: This converts the OPT_VALUE_name mask value to a allocated string. |
516 | | * It is the caller's responsibility to free the string. |
517 | | =*/ |
518 | | char * |
519 | | optionMemberList(tOptDesc * od) |
520 | 0 | { |
521 | 0 | uintptr_t sv = od->optArg.argIntptr; |
522 | 0 | char * res; |
523 | 0 | (*(od->pOptProc))(OPTPROC_RETURN_VALNAME, od); |
524 | 0 | res = VOIDP(od->optArg.argString); |
525 | 0 | od->optArg.argIntptr = sv; |
526 | 0 | return res; |
527 | 0 | } |
528 | | |
529 | | /*=export_func optionSetMembers |
530 | | * what: Convert between bit flag values and strings |
531 | | * private: |
532 | | * |
533 | | * arg: tOptions *, opts, the program options descriptor |
534 | | * arg: tOptDesc *, od, the set membership option description |
535 | | * arg: char const * const *, |
536 | | * nm_list, list of enumeration names |
537 | | * arg: unsigned int, nm_ct, number of names in list |
538 | | * |
539 | | * doc: This converts the optArg.argString string from the option description |
540 | | * into the index corresponding to an entry in the name list. |
541 | | * This will match the generated enumeration value. |
542 | | * Full matches are always accepted. Partial matches are accepted |
543 | | * if there is only one partial match. |
544 | | =*/ |
545 | | void |
546 | | optionSetMembers(tOptions * opts, tOptDesc * od, |
547 | | char const * const * nm_list, unsigned int nm_ct) |
548 | 0 | { |
549 | | /* |
550 | | * IF the program option descriptor pointer is invalid, |
551 | | * then it is some sort of special request. |
552 | | */ |
553 | 0 | switch ((uintptr_t)opts) { |
554 | 0 | case (uintptr_t)OPTPROC_EMIT_USAGE: |
555 | 0 | enum_err(OPTPROC_EMIT_USAGE, od, nm_list, nm_ct); |
556 | 0 | return; |
557 | | |
558 | 0 | case (uintptr_t)OPTPROC_EMIT_SHELL: |
559 | 0 | set_memb_shell(opts, od, nm_list, nm_ct); |
560 | 0 | return; |
561 | | |
562 | 0 | case (uintptr_t)OPTPROC_RETURN_VALNAME: |
563 | 0 | set_memb_names(opts, od, nm_list, nm_ct); |
564 | 0 | return; |
565 | | |
566 | 0 | default: |
567 | 0 | break; |
568 | 0 | } |
569 | | |
570 | 0 | if ((od->fOptState & OPTST_RESET) != 0) |
571 | 0 | return; |
572 | | |
573 | 0 | { |
574 | 0 | char const * arg; |
575 | 0 | bool invert; |
576 | 0 | uintptr_t res = check_membership_start(od, &arg, &invert); |
577 | 0 | if (arg == NULL) |
578 | 0 | goto fail_return; |
579 | | |
580 | 0 | while (*arg != NUL) { |
581 | 0 | bool inv_val = false; |
582 | 0 | int len; |
583 | |
|
584 | 0 | switch (*arg) { |
585 | 0 | case ',': |
586 | 0 | arg = SPN_WHITESPACE_CHARS(arg+1); |
587 | 0 | if ((*arg == ',') || (*arg == '|')) |
588 | 0 | goto fail_return; |
589 | 0 | continue; |
590 | | |
591 | 0 | case '-': |
592 | 0 | case '!': |
593 | 0 | inv_val = true; |
594 | | /* FALLTHROUGH */ |
595 | |
|
596 | 0 | case '+': |
597 | 0 | case '|': |
598 | 0 | arg = SPN_WHITESPACE_CHARS(arg+1); |
599 | 0 | } |
600 | | |
601 | 0 | len = (int)(BRK_SET_SEPARATOR_CHARS(arg) - arg); |
602 | 0 | if (len == 0) |
603 | 0 | break; |
604 | | |
605 | 0 | if ((len == 3) && (strncmp(arg, zAll, 3) == 0)) { |
606 | 0 | if (inv_val) |
607 | 0 | res = 0; |
608 | 0 | else res = ~0UL; |
609 | 0 | } |
610 | 0 | else if ((len == 4) && (strncmp(arg, zNone, 4) == 0)) { |
611 | 0 | if (! inv_val) |
612 | 0 | res = 0; |
613 | 0 | } |
614 | 0 | else do { |
615 | 0 | char * pz; |
616 | 0 | uintptr_t bit = strtoul(arg, &pz, 0); |
617 | |
|
618 | 0 | if (pz != arg + len) { |
619 | 0 | bit = find_member_bit(opts, od, pz, len, nm_list, nm_ct); |
620 | 0 | if (bit == 0UL) |
621 | 0 | goto fail_return; |
622 | 0 | } |
623 | 0 | if (inv_val) |
624 | 0 | res &= ~bit; |
625 | 0 | else res |= bit; |
626 | 0 | } while (false); |
627 | | |
628 | 0 | arg = SPN_WHITESPACE_CHARS(arg + len); |
629 | 0 | } |
630 | | |
631 | 0 | if (invert) |
632 | 0 | res ^= ~0UL; |
633 | |
|
634 | 0 | if (nm_ct < (8 * sizeof(uintptr_t))) |
635 | 0 | res &= (1UL << nm_ct) - 1UL; |
636 | |
|
637 | 0 | od->optCookie = VOIDP(res); |
638 | 0 | } |
639 | 0 | return; |
640 | | |
641 | 0 | fail_return: |
642 | 0 | od->optCookie = VOIDP(0); |
643 | 0 | } |
644 | | |
645 | | /** @} |
646 | | * |
647 | | * Local Variables: |
648 | | * mode: C |
649 | | * c-file-style: "stroustrup" |
650 | | * indent-tabs-mode: nil |
651 | | * End: |
652 | | * end of autoopts/enum.c */ |