bumped version
[gnutls.git] / src / libopts / enum.c
blob2a9f9bc2b5e3a8b5f3f97076c2a8e3694b125c19
2 /**
3 * \file enumeration.c
5 * Time-stamp: "2012-03-31 13:22:33 bkorb"
7 * Automated Options Paged Usage module.
9 * This routine will run run-on options through a pager so the
10 * user may examine, print or edit them at their leisure.
12 * This file is part of AutoOpts, a companion to AutoGen.
13 * AutoOpts is free software.
14 * AutoOpts is Copyright (c) 1992-2012 by Bruce Korb - all rights reserved
16 * AutoOpts is available under any one of two licenses. The license
17 * in use must be one of these two and the choice is under the control
18 * of the user of the license.
20 * The GNU Lesser General Public License, version 3 or later
21 * See the files "COPYING.lgplv3" and "COPYING.gplv3"
23 * The Modified Berkeley Software Distribution License
24 * See the file "COPYING.mbsd"
26 * These files have the following md5sums:
28 * 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
29 * 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
30 * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
33 static char const * pz_enum_err_fmt;
35 /* = = = START-STATIC-FORWARD = = = */
36 static void
37 enum_err(tOptions * pOpts, tOptDesc * pOD,
38 char const * const * paz_names, int name_ct);
40 static uintptr_t
41 find_name(char const * pzName, tOptions * pOpts, tOptDesc * pOD,
42 char const * const * paz_names, unsigned int name_ct);
44 static void
45 set_memb_usage(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names,
46 unsigned int name_ct);
48 static void
49 set_memb_shell(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names,
50 unsigned int name_ct);
52 static void
53 set_memb_names(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names,
54 unsigned int name_ct);
55 /* = = = END-STATIC-FORWARD = = = */
57 static void
58 enum_err(tOptions * pOpts, tOptDesc * pOD,
59 char const * const * paz_names, int name_ct)
61 size_t max_len = 0;
62 size_t ttl_len = 0;
63 int ct_down = name_ct;
64 int hidden = 0;
67 * A real "pOpts" pointer means someone messed up. Give a real error.
69 if (pOpts > OPTPROC_EMIT_LIMIT)
70 fprintf(option_usage_fp, pz_enum_err_fmt, pOpts->pzProgName,
71 pOD->optArg.argString, pOD->pz_Name);
73 fprintf(option_usage_fp, zValidKeys, pOD->pz_Name);
76 * If the first name starts with this funny character, then we have
77 * a first value with an unspellable name. You cannot specify it.
78 * So, we don't list it either.
80 if (**paz_names == 0x7F) {
81 paz_names++;
82 hidden = 1;
83 ct_down = --name_ct;
87 * Figure out the maximum length of any name, plus the total length
88 * of all the names.
91 char const * const * paz = paz_names;
93 do {
94 size_t len = strlen(*(paz++)) + 1;
95 if (len > max_len)
96 max_len = len;
97 ttl_len += len;
98 } while (--ct_down > 0);
100 ct_down = name_ct;
104 * IF any one entry is about 1/2 line or longer, print one per line
106 if (max_len > 35) {
107 do {
108 fprintf(option_usage_fp, ENUM_ERR_SEP_LINE_FMT, *(paz_names++));
109 } while (--ct_down > 0);
113 * ELSE IF they all fit on one line, then do so.
115 else if (ttl_len < 76) {
116 fputc(' ', option_usage_fp);
117 do {
118 fputc(' ', option_usage_fp);
119 fputs(*(paz_names++), option_usage_fp);
120 } while (--ct_down > 0);
121 fputc(NL, option_usage_fp);
125 * Otherwise, columnize the output
127 else {
128 unsigned int ent_no = 0;
129 char zFmt[16]; /* format for all-but-last entries on a line */
131 sprintf(zFmt, ENUM_ERR_STR_WIDTH_FMT, (int)max_len);
132 max_len = 78 / max_len; /* max_len is now max entries on a line */
133 fputs(TWO_SPACES_STR, option_usage_fp);
136 * Loop through all but the last entry
138 ct_down = name_ct;
139 while (--ct_down > 0) {
140 if (++ent_no == max_len) {
142 * Last entry on a line. Start next line, too.
144 fprintf(option_usage_fp, NLSTR_SPACE_FMT, *(paz_names++));
145 ent_no = 0;
148 else
149 fprintf(option_usage_fp, zFmt, *(paz_names++) );
151 fprintf(option_usage_fp, NLSTR_FMT, *paz_names);
154 if (pOpts > OPTPROC_EMIT_LIMIT) {
155 fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden);
157 (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE);
158 /* NOTREACHED */
161 if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) {
162 fprintf(option_usage_fp, zLowerBits, name_ct);
163 fputs(zSetMemberSettings, option_usage_fp);
164 } else {
165 fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden);
170 * Convert a name or number into a binary number.
171 * "~0" and "-1" will be converted to the largest value in the enumeration.
173 * @param pzName the keyword name (number) to convert
174 * @param pOpts the program's option descriptor
175 * @param pOD the option descriptor for this option
176 * @param paz_names the list of keywords for this option
177 * @param name_ct the count of keywords
179 static uintptr_t
180 find_name(char const * pzName, tOptions * pOpts, tOptDesc * pOD,
181 char const * const * paz_names, unsigned int name_ct)
184 * Return the matching index as a pointer sized integer.
185 * The result gets stashed in a char* pointer.
187 uintptr_t res = name_ct;
188 size_t len = strlen((char*)pzName);
189 uintptr_t idx;
191 if (IS_DEC_DIGIT_CHAR(*pzName)) {
192 char * pz = (char *)(void *)pzName;
193 unsigned long val = strtoul(pz, &pz, 0);
194 if ((*pz == NUL) && (val < name_ct))
195 return (uintptr_t)val;
196 pz_enum_err_fmt = zTooLarge;
197 option_usage_fp = stderr;
198 enum_err(pOpts, pOD, paz_names, (int)name_ct);
199 return name_ct;
202 if (IS_INVERSION_CHAR(*pzName) && (pzName[2] == NUL)) {
203 if ( ((pzName[0] == '~') && (pzName[1] == '0'))
204 || ((pzName[0] == '-') && (pzName[1] == '1')))
205 return (uintptr_t)(name_ct - 1);
206 goto oops;
210 * Look for an exact match, but remember any partial matches.
211 * Multiple partial matches means we have an ambiguous match.
213 for (idx = 0; idx < name_ct; idx++) {
214 if (strncmp((char*)paz_names[idx], (char*)pzName, len) == 0) {
215 if (paz_names[idx][len] == NUL)
216 return idx; /* full match */
218 if (res == name_ct)
219 res = idx; /* save partial match */
220 else
221 res = ~0; /* may yet find full match */
225 if (res < name_ct)
226 return res; /* partial match */
228 oops:
230 pz_enum_err_fmt = (res == name_ct) ? zNoKey : zAmbigKey;
231 option_usage_fp = stderr;
232 enum_err(pOpts, pOD, paz_names, (int)name_ct);
233 return name_ct;
237 /*=export_func optionKeywordName
238 * what: Convert between enumeration values and strings
239 * private:
241 * arg: tOptDesc*, pOD, enumeration option description
242 * arg: unsigned int, enum_val, the enumeration value to map
244 * ret_type: char const *
245 * ret_desc: the enumeration name from const memory
247 * doc: This converts an enumeration value into the matching string.
249 char const *
250 optionKeywordName(tOptDesc * pOD, unsigned int enum_val)
252 tOptDesc od = {
253 .optArg.argEnum = enum_val };
255 (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, &od );
256 return od.optArg.argString;
260 /*=export_func optionEnumerationVal
261 * what: Convert from a string to an enumeration value
262 * private:
264 * arg: tOptions*, pOpts, the program options descriptor
265 * arg: tOptDesc*, pOD, enumeration option description
266 * arg: char const * const *, paz_names, list of enumeration names
267 * arg: unsigned int, name_ct, number of names in list
269 * ret_type: uintptr_t
270 * ret_desc: the enumeration value
272 * doc: This converts the optArg.argString string from the option description
273 * into the index corresponding to an entry in the name list.
274 * This will match the generated enumeration value.
275 * Full matches are always accepted. Partial matches are accepted
276 * if there is only one partial match.
278 uintptr_t
279 optionEnumerationVal(tOptions * pOpts, tOptDesc * pOD,
280 char const * const * paz_names, unsigned int name_ct)
282 uintptr_t res = 0UL;
285 * IF the program option descriptor pointer is invalid,
286 * then it is some sort of special request.
288 switch ((uintptr_t)pOpts) {
289 case (uintptr_t)OPTPROC_EMIT_USAGE:
291 * print the list of enumeration names.
293 enum_err(pOpts, pOD, paz_names, (int)name_ct);
294 break;
296 case (uintptr_t)OPTPROC_EMIT_SHELL:
298 unsigned int ix = pOD->optArg.argEnum;
300 * print the name string.
302 if (ix >= name_ct)
303 printf(INVALID_FMT, ix);
304 else
305 fputs(paz_names[ ix ], stdout);
307 break;
310 case (uintptr_t)OPTPROC_RETURN_VALNAME:
312 unsigned int ix = pOD->optArg.argEnum;
314 * Replace the enumeration value with the name string.
316 if (ix >= name_ct)
317 return (uintptr_t)INVALID_STR;
319 pOD->optArg.argString = paz_names[ix];
320 break;
323 default:
324 res = find_name(pOD->optArg.argString, pOpts, pOD, paz_names, name_ct);
326 if (pOD->fOptState & OPTST_ALLOC_ARG) {
327 AGFREE(pOD->optArg.argString);
328 pOD->fOptState &= ~OPTST_ALLOC_ARG;
329 pOD->optArg.argString = NULL;
333 return res;
336 static void
337 set_memb_usage(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names,
338 unsigned int name_ct)
341 * print the list of enumeration names.
343 (void)pOpts;
344 enum_err(OPTPROC_EMIT_USAGE, pOD, paz_names, (int)name_ct );
347 static void
348 set_memb_shell(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names,
349 unsigned int name_ct)
352 * print the name string.
354 unsigned int ix = 0;
355 uintptr_t bits = (uintptr_t)pOD->optCookie;
356 size_t len = 0;
358 (void)pOpts;
359 bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1;
361 while (bits != 0) {
362 if (bits & 1) {
363 if (len++ > 0) fputs(OR_STR, stdout);
364 fputs(paz_names[ix], stdout);
366 if (++ix >= name_ct) break;
367 bits >>= 1;
371 static void
372 set_memb_names(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names,
373 unsigned int name_ct)
375 char * pz;
376 uintptr_t bits = (uintptr_t)pOD->optCookie;
377 unsigned int ix = 0;
378 size_t len = NONE_STR_LEN + 1;
380 (void)pOpts;
381 bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1;
384 * Replace the enumeration value with the name string.
385 * First, determine the needed length, then allocate and fill in.
387 while (bits != 0) {
388 if (bits & 1)
389 len += strlen(paz_names[ix]) + PLUS_STR_LEN + 1;
390 if (++ix >= name_ct) break;
391 bits >>= 1;
394 pOD->optArg.argString = pz = AGALOC(len, "enum");
397 * Start by clearing all the bits. We want to turn off any defaults
398 * because we will be restoring to current state, not adding to
399 * the default set of bits.
401 memcpy(pz, NONE_STR, NONE_STR_LEN);
402 pz += NONE_STR_LEN;
403 bits = (uintptr_t)pOD->optCookie;
404 bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1;
405 ix = 0;
407 while (bits != 0) {
408 if (bits & 1) {
409 size_t nln = strlen(paz_names[ix]);
410 memcpy(pz, PLUS_STR, PLUS_STR_LEN);
411 memcpy(pz+PLUS_STR_LEN, paz_names[ix], nln);
412 pz += nln + PLUS_STR_LEN;
414 if (++ix >= name_ct) break;
415 bits >>= 1;
417 *pz = NUL;
420 /*=export_func optionSetMembers
421 * what: Convert between bit flag values and strings
422 * private:
424 * arg: tOptions*, pOpts, the program options descriptor
425 * arg: tOptDesc*, pOD, enumeration option description
426 * arg: char const * const *,
427 * paz_names, list of enumeration names
428 * arg: unsigned int, name_ct, number of names in list
430 * doc: This converts the optArg.argString string from the option description
431 * into the index corresponding to an entry in the name list.
432 * This will match the generated enumeration value.
433 * Full matches are always accepted. Partial matches are accepted
434 * if there is only one partial match.
436 void
437 optionSetMembers(tOptions * pOpts, tOptDesc * pOD,
438 char const* const * paz_names, unsigned int name_ct)
441 * IF the program option descriptor pointer is invalid,
442 * then it is some sort of special request.
444 switch ((uintptr_t)pOpts) {
445 case (uintptr_t)OPTPROC_EMIT_USAGE:
446 set_memb_usage(pOpts, pOD, paz_names, name_ct);
447 return;
449 case (uintptr_t)OPTPROC_EMIT_SHELL:
450 set_memb_shell(pOpts, pOD, paz_names, name_ct);
451 return;
453 case (uintptr_t)OPTPROC_RETURN_VALNAME:
454 set_memb_names(pOpts, pOD, paz_names, name_ct);
455 return;
457 default:
458 break;
461 if ((pOD->fOptState & OPTST_RESET) != 0)
462 return;
465 char const * pzArg = pOD->optArg.argString;
466 uintptr_t res;
467 if ((pzArg == NULL) || (*pzArg == NUL)) {
468 pOD->optCookie = (void*)0;
469 return;
472 res = (uintptr_t)pOD->optCookie;
473 for (;;) {
474 int iv, len;
476 pzArg = SPN_SET_SEPARATOR_CHARS(pzArg);
477 iv = (*pzArg == '!');
478 if (iv)
479 pzArg = SPN_WHITESPACE_CHARS(pzArg+1);
481 len = BRK_SET_SEPARATOR_CHARS(pzArg) - pzArg;
482 if (len == 0)
483 break;
485 if ((len == 3) && (strncmp(pzArg, zAll, 3) == 0)) {
486 if (iv)
487 res = 0;
488 else res = ~0UL;
490 else if ((len == 4) && (strncmp(pzArg, zNone, 4) == 0)) {
491 if (! iv)
492 res = 0;
494 else do {
495 char* pz;
496 uintptr_t bit = strtoul(pzArg, &pz, 0);
498 if (pz != pzArg + len) {
499 char z[ AO_NAME_SIZE ];
500 char const* p;
501 unsigned int shift_ct;
503 if (*pz != NUL) {
504 if (len >= AO_NAME_LIMIT)
505 break;
506 memcpy(z, pzArg, (size_t)len);
507 z[len] = NUL;
508 p = z;
509 } else {
510 p = pzArg;
513 shift_ct = find_name(p, pOpts, pOD, paz_names, name_ct);
514 if (shift_ct >= name_ct) {
515 pOD->optCookie = (void*)0;
516 return;
518 bit = 1UL << shift_ct;
520 if (iv)
521 res &= ~bit;
522 else res |= bit;
523 } while (false);
525 if (pzArg[len] == NUL)
526 break;
527 pzArg += len + 1;
529 if (name_ct < (8 * sizeof(uintptr_t))) {
530 res &= (1UL << name_ct) - 1UL;
533 pOD->optCookie = (void*)res;
538 * Local Variables:
539 * mode: C
540 * c-file-style: "stroustrup"
541 * indent-tabs-mode: nil
542 * End:
543 * end of autoopts/enumeration.c */