12b15cb3dSCy Schubert
22b15cb3dSCy Schubert /**
32b15cb3dSCy Schubert * \file enumeration.c
42b15cb3dSCy Schubert *
52b15cb3dSCy Schubert * Handle options with enumeration names and bit mask bit names
62b15cb3dSCy Schubert * for their arguments.
72b15cb3dSCy Schubert *
82b15cb3dSCy Schubert * @addtogroup autoopts
92b15cb3dSCy Schubert * @{
102b15cb3dSCy Schubert */
112b15cb3dSCy Schubert /*
122b15cb3dSCy Schubert * This routine will run run-on options through a pager so the
132b15cb3dSCy Schubert * user may examine, print or edit them at their leisure.
142b15cb3dSCy Schubert *
152b15cb3dSCy Schubert * This file is part of AutoOpts, a companion to AutoGen.
162b15cb3dSCy Schubert * AutoOpts is free software.
17*a466cc55SCy Schubert * AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
182b15cb3dSCy Schubert *
192b15cb3dSCy Schubert * AutoOpts is available under any one of two licenses. The license
202b15cb3dSCy Schubert * in use must be one of these two and the choice is under the control
212b15cb3dSCy Schubert * of the user of the license.
222b15cb3dSCy Schubert *
232b15cb3dSCy Schubert * The GNU Lesser General Public License, version 3 or later
242b15cb3dSCy Schubert * See the files "COPYING.lgplv3" and "COPYING.gplv3"
252b15cb3dSCy Schubert *
262b15cb3dSCy Schubert * The Modified Berkeley Software Distribution License
272b15cb3dSCy Schubert * See the file "COPYING.mbsd"
282b15cb3dSCy Schubert *
292b15cb3dSCy Schubert * These files have the following sha256 sums:
302b15cb3dSCy Schubert *
312b15cb3dSCy Schubert * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3
322b15cb3dSCy Schubert * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3
332b15cb3dSCy Schubert * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd
342b15cb3dSCy Schubert */
352b15cb3dSCy Schubert
362b15cb3dSCy Schubert static void
enum_err(tOptions * pOpts,tOptDesc * pOD,char const * const * paz_names,int name_ct)372b15cb3dSCy Schubert enum_err(tOptions * pOpts, tOptDesc * pOD,
382b15cb3dSCy Schubert char const * const * paz_names, int name_ct)
392b15cb3dSCy Schubert {
402b15cb3dSCy Schubert size_t max_len = 0;
412b15cb3dSCy Schubert size_t ttl_len = 0;
422b15cb3dSCy Schubert int ct_down = name_ct;
432b15cb3dSCy Schubert int hidden = 0;
442b15cb3dSCy Schubert
452b15cb3dSCy Schubert /*
462b15cb3dSCy Schubert * A real "pOpts" pointer means someone messed up. Give a real error.
472b15cb3dSCy Schubert */
482b15cb3dSCy Schubert if (pOpts > OPTPROC_EMIT_LIMIT)
492b15cb3dSCy Schubert fprintf(option_usage_fp, pz_enum_err_fmt, pOpts->pzProgName,
502b15cb3dSCy Schubert pOD->optArg.argString, pOD->pz_Name);
512b15cb3dSCy Schubert
522b15cb3dSCy Schubert fprintf(option_usage_fp, zValidKeys, pOD->pz_Name);
532b15cb3dSCy Schubert
542b15cb3dSCy Schubert /*
552b15cb3dSCy Schubert * If the first name starts with this funny character, then we have
562b15cb3dSCy Schubert * a first value with an unspellable name. You cannot specify it.
572b15cb3dSCy Schubert * So, we don't list it either.
582b15cb3dSCy Schubert */
592b15cb3dSCy Schubert if (**paz_names == 0x7F) {
602b15cb3dSCy Schubert paz_names++;
612b15cb3dSCy Schubert hidden = 1;
622b15cb3dSCy Schubert ct_down = --name_ct;
632b15cb3dSCy Schubert }
642b15cb3dSCy Schubert
652b15cb3dSCy Schubert /*
662b15cb3dSCy Schubert * Figure out the maximum length of any name, plus the total length
672b15cb3dSCy Schubert * of all the names.
682b15cb3dSCy Schubert */
692b15cb3dSCy Schubert {
702b15cb3dSCy Schubert char const * const * paz = paz_names;
712b15cb3dSCy Schubert
722b15cb3dSCy Schubert do {
732b15cb3dSCy Schubert size_t len = strlen(*(paz++)) + 1;
742b15cb3dSCy Schubert if (len > max_len)
752b15cb3dSCy Schubert max_len = len;
762b15cb3dSCy Schubert ttl_len += len;
772b15cb3dSCy Schubert } while (--ct_down > 0);
782b15cb3dSCy Schubert
792b15cb3dSCy Schubert ct_down = name_ct;
802b15cb3dSCy Schubert }
812b15cb3dSCy Schubert
822b15cb3dSCy Schubert /*
832b15cb3dSCy Schubert * IF any one entry is about 1/2 line or longer, print one per line
842b15cb3dSCy Schubert */
852b15cb3dSCy Schubert if (max_len > 35) {
862b15cb3dSCy Schubert do {
872b15cb3dSCy Schubert fprintf(option_usage_fp, ENUM_ERR_LINE, *(paz_names++));
882b15cb3dSCy Schubert } while (--ct_down > 0);
892b15cb3dSCy Schubert }
902b15cb3dSCy Schubert
912b15cb3dSCy Schubert /*
922b15cb3dSCy Schubert * ELSE IF they all fit on one line, then do so.
932b15cb3dSCy Schubert */
942b15cb3dSCy Schubert else if (ttl_len < 76) {
952b15cb3dSCy Schubert fputc(' ', option_usage_fp);
962b15cb3dSCy Schubert do {
972b15cb3dSCy Schubert fputc(' ', option_usage_fp);
982b15cb3dSCy Schubert fputs(*(paz_names++), option_usage_fp);
992b15cb3dSCy Schubert } while (--ct_down > 0);
1002b15cb3dSCy Schubert fputc(NL, option_usage_fp);
1012b15cb3dSCy Schubert }
1022b15cb3dSCy Schubert
1032b15cb3dSCy Schubert /*
1042b15cb3dSCy Schubert * Otherwise, columnize the output
1052b15cb3dSCy Schubert */
1062b15cb3dSCy Schubert else {
1072b15cb3dSCy Schubert unsigned int ent_no = 0;
108*a466cc55SCy Schubert char fmt[16]; /* format for all-but-last entries on a line */
1092b15cb3dSCy Schubert
110*a466cc55SCy Schubert if (snprintf(fmt, 16, ENUM_ERR_WIDTH, (int)max_len) >= 16)
111*a466cc55SCy Schubert option_exits(EXIT_FAILURE);
1122b15cb3dSCy Schubert max_len = 78 / max_len; /* max_len is now max entries on a line */
1132b15cb3dSCy Schubert fputs(TWO_SPACES_STR, option_usage_fp);
1142b15cb3dSCy Schubert
1152b15cb3dSCy Schubert /*
1162b15cb3dSCy Schubert * Loop through all but the last entry
1172b15cb3dSCy Schubert */
1182b15cb3dSCy Schubert ct_down = name_ct;
1192b15cb3dSCy Schubert while (--ct_down > 0) {
1202b15cb3dSCy Schubert if (++ent_no == max_len) {
1212b15cb3dSCy Schubert /*
1222b15cb3dSCy Schubert * Last entry on a line. Start next line, too.
1232b15cb3dSCy Schubert */
1242b15cb3dSCy Schubert fprintf(option_usage_fp, NLSTR_SPACE_FMT, *(paz_names++));
1252b15cb3dSCy Schubert ent_no = 0;
1262b15cb3dSCy Schubert }
1272b15cb3dSCy Schubert
1282b15cb3dSCy Schubert else
129*a466cc55SCy Schubert fprintf(option_usage_fp, fmt, *(paz_names++) );
1302b15cb3dSCy Schubert }
1312b15cb3dSCy Schubert fprintf(option_usage_fp, NLSTR_FMT, *paz_names);
1322b15cb3dSCy Schubert }
1332b15cb3dSCy Schubert
1342b15cb3dSCy Schubert if (pOpts > OPTPROC_EMIT_LIMIT) {
1352b15cb3dSCy Schubert fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden);
1362b15cb3dSCy Schubert
1372b15cb3dSCy Schubert (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE);
1382b15cb3dSCy Schubert /* NOTREACHED */
1392b15cb3dSCy Schubert }
1402b15cb3dSCy Schubert
1412b15cb3dSCy Schubert if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) {
1422b15cb3dSCy Schubert fprintf(option_usage_fp, zLowerBits, name_ct);
1432b15cb3dSCy Schubert fputs(zSetMemberSettings, option_usage_fp);
1442b15cb3dSCy Schubert } else {
1452b15cb3dSCy Schubert fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden);
1462b15cb3dSCy Schubert }
1472b15cb3dSCy Schubert }
1482b15cb3dSCy Schubert
1492b15cb3dSCy Schubert /**
1502b15cb3dSCy Schubert * Convert a name or number into a binary number.
1512b15cb3dSCy Schubert * "~0" and "-1" will be converted to the largest value in the enumeration.
1522b15cb3dSCy Schubert *
1532b15cb3dSCy Schubert * @param name the keyword name (number) to convert
1542b15cb3dSCy Schubert * @param pOpts the program's option descriptor
1552b15cb3dSCy Schubert * @param pOD the option descriptor for this option
1562b15cb3dSCy Schubert * @param paz_names the list of keywords for this option
1572b15cb3dSCy Schubert * @param name_ct the count of keywords
1582b15cb3dSCy Schubert */
1592b15cb3dSCy Schubert static uintptr_t
find_name(char const * name,tOptions * pOpts,tOptDesc * pOD,char const * const * paz_names,unsigned int name_ct)1602b15cb3dSCy Schubert find_name(char const * name, tOptions * pOpts, tOptDesc * pOD,
1612b15cb3dSCy Schubert char const * const * paz_names, unsigned int name_ct)
1622b15cb3dSCy Schubert {
1632b15cb3dSCy Schubert /*
1642b15cb3dSCy Schubert * Return the matching index as a pointer sized integer.
1652b15cb3dSCy Schubert * The result gets stashed in a char * pointer.
1662b15cb3dSCy Schubert */
1672b15cb3dSCy Schubert uintptr_t res = name_ct;
168*a466cc55SCy Schubert size_t len = strlen((char *)name);
1692b15cb3dSCy Schubert uintptr_t idx;
1702b15cb3dSCy Schubert
1712b15cb3dSCy Schubert if (IS_DEC_DIGIT_CHAR(*name)) {
172*a466cc55SCy Schubert char * pz = VOIDP(name);
173*a466cc55SCy Schubert unsigned long val = strtoul(pz, &pz, 0);
1742b15cb3dSCy Schubert if ((*pz == NUL) && (val < name_ct))
1752b15cb3dSCy Schubert return (uintptr_t)val;
1762b15cb3dSCy Schubert pz_enum_err_fmt = znum_too_large;
1772b15cb3dSCy Schubert option_usage_fp = stderr;
1782b15cb3dSCy Schubert enum_err(pOpts, pOD, paz_names, (int)name_ct);
1792b15cb3dSCy Schubert return name_ct;
1802b15cb3dSCy Schubert }
1812b15cb3dSCy Schubert
1822b15cb3dSCy Schubert if (IS_INVERSION_CHAR(*name) && (name[2] == NUL)) {
1832b15cb3dSCy Schubert if ( ((name[0] == '~') && (name[1] == '0'))
1842b15cb3dSCy Schubert || ((name[0] == '-') && (name[1] == '1')))
1852b15cb3dSCy Schubert return (uintptr_t)(name_ct - 1);
1862b15cb3dSCy Schubert goto oops;
1872b15cb3dSCy Schubert }
1882b15cb3dSCy Schubert
1892b15cb3dSCy Schubert /*
1902b15cb3dSCy Schubert * Look for an exact match, but remember any partial matches.
1912b15cb3dSCy Schubert * Multiple partial matches means we have an ambiguous match.
1922b15cb3dSCy Schubert */
1932b15cb3dSCy Schubert for (idx = 0; idx < name_ct; idx++) {
194*a466cc55SCy Schubert if (strncmp((char *)paz_names[idx], (char *)name, len) == 0) {
1952b15cb3dSCy Schubert if (paz_names[idx][len] == NUL)
1962b15cb3dSCy Schubert return idx; /* full match */
1972b15cb3dSCy Schubert
1982b15cb3dSCy Schubert if (res == name_ct)
1992b15cb3dSCy Schubert res = idx; /* save partial match */
2002b15cb3dSCy Schubert else
2012b15cb3dSCy Schubert res = (uintptr_t)~0; /* may yet find full match */
2022b15cb3dSCy Schubert }
2032b15cb3dSCy Schubert }
2042b15cb3dSCy Schubert
2052b15cb3dSCy Schubert if (res < name_ct)
2062b15cb3dSCy Schubert return res; /* partial match */
2072b15cb3dSCy Schubert
2082b15cb3dSCy Schubert oops:
2092b15cb3dSCy Schubert
2102b15cb3dSCy Schubert pz_enum_err_fmt = (res == name_ct) ? zNoKey : zambiguous_key;
2112b15cb3dSCy Schubert option_usage_fp = stderr;
2122b15cb3dSCy Schubert enum_err(pOpts, pOD, paz_names, (int)name_ct);
2132b15cb3dSCy Schubert return name_ct;
2142b15cb3dSCy Schubert }
2152b15cb3dSCy Schubert
2162b15cb3dSCy Schubert
2172b15cb3dSCy Schubert /*=export_func optionKeywordName
2182b15cb3dSCy Schubert * what: Convert between enumeration values and strings
2192b15cb3dSCy Schubert * private:
2202b15cb3dSCy Schubert *
2212b15cb3dSCy Schubert * arg: tOptDesc *, pOD, enumeration option description
2222b15cb3dSCy Schubert * arg: unsigned int, enum_val, the enumeration value to map
2232b15cb3dSCy Schubert *
2242b15cb3dSCy Schubert * ret_type: char const *
2252b15cb3dSCy Schubert * ret_desc: the enumeration name from const memory
2262b15cb3dSCy Schubert *
2272b15cb3dSCy Schubert * doc: This converts an enumeration value into the matching string.
2282b15cb3dSCy Schubert =*/
2292b15cb3dSCy Schubert char const *
optionKeywordName(tOptDesc * pOD,unsigned int enum_val)2302b15cb3dSCy Schubert optionKeywordName(tOptDesc * pOD, unsigned int enum_val)
2312b15cb3dSCy Schubert {
2322b15cb3dSCy Schubert tOptDesc od = { 0 };
2332b15cb3dSCy Schubert od.optArg.argEnum = enum_val;
2342b15cb3dSCy Schubert
2352b15cb3dSCy Schubert (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, &od );
2362b15cb3dSCy Schubert return od.optArg.argString;
2372b15cb3dSCy Schubert }
2382b15cb3dSCy Schubert
2392b15cb3dSCy Schubert
2402b15cb3dSCy Schubert /*=export_func optionEnumerationVal
2412b15cb3dSCy Schubert * what: Convert from a string to an enumeration value
2422b15cb3dSCy Schubert * private:
2432b15cb3dSCy Schubert *
2442b15cb3dSCy Schubert * arg: tOptions *, pOpts, the program options descriptor
2452b15cb3dSCy Schubert * arg: tOptDesc *, pOD, enumeration option description
2462b15cb3dSCy Schubert * arg: char const * const *, paz_names, list of enumeration names
2472b15cb3dSCy Schubert * arg: unsigned int, name_ct, number of names in list
2482b15cb3dSCy Schubert *
2492b15cb3dSCy Schubert * ret_type: uintptr_t
2502b15cb3dSCy Schubert * ret_desc: the enumeration value
2512b15cb3dSCy Schubert *
2522b15cb3dSCy Schubert * doc: This converts the optArg.argString string from the option description
2532b15cb3dSCy Schubert * into the index corresponding to an entry in the name list.
2542b15cb3dSCy Schubert * This will match the generated enumeration value.
2552b15cb3dSCy Schubert * Full matches are always accepted. Partial matches are accepted
2562b15cb3dSCy Schubert * if there is only one partial match.
2572b15cb3dSCy Schubert =*/
2582b15cb3dSCy Schubert uintptr_t
optionEnumerationVal(tOptions * pOpts,tOptDesc * pOD,char const * const * paz_names,unsigned int name_ct)2592b15cb3dSCy Schubert optionEnumerationVal(tOptions * pOpts, tOptDesc * pOD,
2602b15cb3dSCy Schubert char const * const * paz_names, unsigned int name_ct)
2612b15cb3dSCy Schubert {
2622b15cb3dSCy Schubert uintptr_t res = 0UL;
2632b15cb3dSCy Schubert
2642b15cb3dSCy Schubert /*
2652b15cb3dSCy Schubert * IF the program option descriptor pointer is invalid,
2662b15cb3dSCy Schubert * then it is some sort of special request.
2672b15cb3dSCy Schubert */
2682b15cb3dSCy Schubert switch ((uintptr_t)pOpts) {
2692b15cb3dSCy Schubert case (uintptr_t)OPTPROC_EMIT_USAGE:
2702b15cb3dSCy Schubert /*
2712b15cb3dSCy Schubert * print the list of enumeration names.
2722b15cb3dSCy Schubert */
2732b15cb3dSCy Schubert enum_err(pOpts, pOD, paz_names, (int)name_ct);
2742b15cb3dSCy Schubert break;
2752b15cb3dSCy Schubert
2762b15cb3dSCy Schubert case (uintptr_t)OPTPROC_EMIT_SHELL:
2772b15cb3dSCy Schubert {
2782b15cb3dSCy Schubert unsigned int ix = (unsigned int)pOD->optArg.argEnum;
2792b15cb3dSCy Schubert /*
2802b15cb3dSCy Schubert * print the name string.
2812b15cb3dSCy Schubert */
2822b15cb3dSCy Schubert if (ix >= name_ct)
2832b15cb3dSCy Schubert printf(INVALID_FMT, ix);
2842b15cb3dSCy Schubert else
2852b15cb3dSCy Schubert fputs(paz_names[ ix ], stdout);
2862b15cb3dSCy Schubert
2872b15cb3dSCy Schubert break;
2882b15cb3dSCy Schubert }
2892b15cb3dSCy Schubert
2902b15cb3dSCy Schubert case (uintptr_t)OPTPROC_RETURN_VALNAME:
2912b15cb3dSCy Schubert {
2922b15cb3dSCy Schubert unsigned int ix = (unsigned int)pOD->optArg.argEnum;
2932b15cb3dSCy Schubert /*
2942b15cb3dSCy Schubert * Replace the enumeration value with the name string.
2952b15cb3dSCy Schubert */
2962b15cb3dSCy Schubert if (ix >= name_ct)
2972b15cb3dSCy Schubert return (uintptr_t)INVALID_STR;
2982b15cb3dSCy Schubert
2992b15cb3dSCy Schubert pOD->optArg.argString = paz_names[ix];
3002b15cb3dSCy Schubert break;
3012b15cb3dSCy Schubert }
3022b15cb3dSCy Schubert
3032b15cb3dSCy Schubert default:
3042b15cb3dSCy Schubert if ((pOD->fOptState & OPTST_RESET) != 0)
3052b15cb3dSCy Schubert break;
3062b15cb3dSCy Schubert
3072b15cb3dSCy Schubert res = find_name(pOD->optArg.argString, pOpts, pOD, paz_names, name_ct);
3082b15cb3dSCy Schubert
3092b15cb3dSCy Schubert if (pOD->fOptState & OPTST_ALLOC_ARG) {
3102b15cb3dSCy Schubert AGFREE(pOD->optArg.argString);
3112b15cb3dSCy Schubert pOD->fOptState &= ~OPTST_ALLOC_ARG;
3122b15cb3dSCy Schubert pOD->optArg.argString = NULL;
3132b15cb3dSCy Schubert }
3142b15cb3dSCy Schubert }
3152b15cb3dSCy Schubert
3162b15cb3dSCy Schubert return res;
3172b15cb3dSCy Schubert }
3182b15cb3dSCy Schubert
3192b15cb3dSCy Schubert static void
set_memb_shell(tOptions * pOpts,tOptDesc * pOD,char const * const * paz_names,unsigned int name_ct)3202b15cb3dSCy Schubert set_memb_shell(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names,
3212b15cb3dSCy Schubert unsigned int name_ct)
3222b15cb3dSCy Schubert {
3232b15cb3dSCy Schubert /*
3242b15cb3dSCy Schubert * print the name string.
3252b15cb3dSCy Schubert */
3262b15cb3dSCy Schubert unsigned int ix = 0;
3272b15cb3dSCy Schubert uintptr_t bits = (uintptr_t)pOD->optCookie;
3282b15cb3dSCy Schubert size_t len = 0;
3292b15cb3dSCy Schubert
3302b15cb3dSCy Schubert (void)pOpts;
3312b15cb3dSCy Schubert bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1;
3322b15cb3dSCy Schubert
3332b15cb3dSCy Schubert while (bits != 0) {
3342b15cb3dSCy Schubert if (bits & 1) {
3352b15cb3dSCy Schubert if (len++ > 0) fputs(OR_STR, stdout);
3362b15cb3dSCy Schubert fputs(paz_names[ix], stdout);
3372b15cb3dSCy Schubert }
3382b15cb3dSCy Schubert if (++ix >= name_ct) break;
3392b15cb3dSCy Schubert bits >>= 1;
3402b15cb3dSCy Schubert }
3412b15cb3dSCy Schubert }
3422b15cb3dSCy Schubert
3432b15cb3dSCy Schubert static void
set_memb_names(tOptions * opts,tOptDesc * od,char const * const * nm_list,unsigned int nm_ct)3442b15cb3dSCy Schubert set_memb_names(tOptions * opts, tOptDesc * od, char const * const * nm_list,
3452b15cb3dSCy Schubert unsigned int nm_ct)
3462b15cb3dSCy Schubert {
3472b15cb3dSCy Schubert char * pz;
3482b15cb3dSCy Schubert uintptr_t mask = (1UL << (uintptr_t)nm_ct) - 1UL;
3492b15cb3dSCy Schubert uintptr_t bits = (uintptr_t)od->optCookie & mask;
3502b15cb3dSCy Schubert unsigned int ix = 0;
3512b15cb3dSCy Schubert size_t len = 1;
3522b15cb3dSCy Schubert
3532b15cb3dSCy Schubert /*
3542b15cb3dSCy Schubert * Replace the enumeration value with the name string.
3552b15cb3dSCy Schubert * First, determine the needed length, then allocate and fill in.
3562b15cb3dSCy Schubert */
3572b15cb3dSCy Schubert while (bits != 0) {
3582b15cb3dSCy Schubert if (bits & 1)
3592b15cb3dSCy Schubert len += strlen(nm_list[ix]) + PLUS_STR_LEN + 1;
3602b15cb3dSCy Schubert if (++ix >= nm_ct) break;
3612b15cb3dSCy Schubert bits >>= 1;
3622b15cb3dSCy Schubert }
3632b15cb3dSCy Schubert
3642b15cb3dSCy Schubert od->optArg.argString = pz = AGALOC(len, "enum");
3652b15cb3dSCy Schubert bits = (uintptr_t)od->optCookie & mask;
3662b15cb3dSCy Schubert if (bits == 0) {
3672b15cb3dSCy Schubert *pz = NUL;
3682b15cb3dSCy Schubert return;
3692b15cb3dSCy Schubert }
3702b15cb3dSCy Schubert
3712b15cb3dSCy Schubert for (ix = 0; ; ix++) {
3722b15cb3dSCy Schubert size_t nln;
3732b15cb3dSCy Schubert int doit = bits & 1;
3742b15cb3dSCy Schubert
3752b15cb3dSCy Schubert bits >>= 1;
3762b15cb3dSCy Schubert if (doit == 0)
3772b15cb3dSCy Schubert continue;
3782b15cb3dSCy Schubert
3792b15cb3dSCy Schubert nln = strlen(nm_list[ix]);
3802b15cb3dSCy Schubert memcpy(pz, nm_list[ix], nln);
3812b15cb3dSCy Schubert pz += nln;
3822b15cb3dSCy Schubert if (bits == 0)
3832b15cb3dSCy Schubert break;
3842b15cb3dSCy Schubert memcpy(pz, PLUS_STR, PLUS_STR_LEN);
3852b15cb3dSCy Schubert pz += PLUS_STR_LEN;
3862b15cb3dSCy Schubert }
3872b15cb3dSCy Schubert *pz = NUL;
3882b15cb3dSCy Schubert (void)opts;
3892b15cb3dSCy Schubert }
3902b15cb3dSCy Schubert
3912b15cb3dSCy Schubert /**
3922b15cb3dSCy Schubert * Check membership start conditions. An equal character (@samp{=}) says to
3932b15cb3dSCy Schubert * clear the result and not carry over any residual value. A carat
3942b15cb3dSCy Schubert * (@samp{^}), which may follow the equal character, says to invert the
3952b15cb3dSCy Schubert * result. The scanning pointer is advanced past these characters and any
3962b15cb3dSCy Schubert * leading white space. Invalid sequences are indicated by setting the
3972b15cb3dSCy Schubert * scanning pointer to NULL.
3982b15cb3dSCy Schubert *
3992b15cb3dSCy Schubert * @param od the set membership option description
4002b15cb3dSCy Schubert * @param argp a pointer to the string scanning pointer
4012b15cb3dSCy Schubert * @param invert a pointer to the boolean inversion indicator
4022b15cb3dSCy Schubert *
4032b15cb3dSCy Schubert * @returns either zero or the original value for the optCookie.
4042b15cb3dSCy Schubert */
4052b15cb3dSCy Schubert static uintptr_t
check_membership_start(tOptDesc * od,char const ** argp,bool * invert)4062b15cb3dSCy Schubert check_membership_start(tOptDesc * od, char const ** argp, bool * invert)
4072b15cb3dSCy Schubert {
4082b15cb3dSCy Schubert uintptr_t res = (uintptr_t)od->optCookie;
4092b15cb3dSCy Schubert char const * arg = SPN_WHITESPACE_CHARS(od->optArg.argString);
4102b15cb3dSCy Schubert if ((arg == NULL) || (*arg == NUL))
4112b15cb3dSCy Schubert goto member_start_fail;
4122b15cb3dSCy Schubert
4132b15cb3dSCy Schubert *invert = false;
4142b15cb3dSCy Schubert
4152b15cb3dSCy Schubert switch (*arg) {
4162b15cb3dSCy Schubert case '=':
4172b15cb3dSCy Schubert res = 0UL;
4182b15cb3dSCy Schubert arg = SPN_WHITESPACE_CHARS(arg + 1);
4192b15cb3dSCy Schubert switch (*arg) {
4202b15cb3dSCy Schubert case '=': case ',':
4212b15cb3dSCy Schubert goto member_start_fail;
4222b15cb3dSCy Schubert case '^':
4232b15cb3dSCy Schubert goto inversion;
4242b15cb3dSCy Schubert default:
4252b15cb3dSCy Schubert break;
4262b15cb3dSCy Schubert }
4272b15cb3dSCy Schubert break;
4282b15cb3dSCy Schubert
4292b15cb3dSCy Schubert case '^':
4302b15cb3dSCy Schubert inversion:
4312b15cb3dSCy Schubert *invert = true;
4322b15cb3dSCy Schubert arg = SPN_WHITESPACE_CHARS(arg + 1);
4332b15cb3dSCy Schubert if (*arg != ',')
4342b15cb3dSCy Schubert break;
4352b15cb3dSCy Schubert /* FALLTHROUGH */
4362b15cb3dSCy Schubert
4372b15cb3dSCy Schubert case ',':
4382b15cb3dSCy Schubert goto member_start_fail;
4392b15cb3dSCy Schubert
4402b15cb3dSCy Schubert default:
4412b15cb3dSCy Schubert break;
4422b15cb3dSCy Schubert }
4432b15cb3dSCy Schubert
4442b15cb3dSCy Schubert *argp = arg;
4452b15cb3dSCy Schubert return res;
4462b15cb3dSCy Schubert
4472b15cb3dSCy Schubert member_start_fail:
4482b15cb3dSCy Schubert *argp = NULL;
4492b15cb3dSCy Schubert return 0UL;
4502b15cb3dSCy Schubert }
4512b15cb3dSCy Schubert
4522b15cb3dSCy Schubert /**
4532b15cb3dSCy Schubert * convert a name to a bit. Look up a name string to get a bit number
4542b15cb3dSCy Schubert * and shift the value "1" left that number of bits.
4552b15cb3dSCy Schubert *
4562b15cb3dSCy Schubert * @param opts program options descriptor
4572b15cb3dSCy Schubert * @param od the set membership option description
4582b15cb3dSCy Schubert * @param pz address of the start of the bit name
4592b15cb3dSCy Schubert * @param nm_list the list of names for this option
4602b15cb3dSCy Schubert * @param nm_ct the number of entries in this list
4612b15cb3dSCy Schubert *
4622b15cb3dSCy Schubert * @returns 0UL on error, other an unsigned long with the correct bit set.
4632b15cb3dSCy Schubert */
4642b15cb3dSCy Schubert static uintptr_t
find_member_bit(tOptions * opts,tOptDesc * od,char const * pz,int len,char const * const * nm_list,unsigned int nm_ct)4652b15cb3dSCy Schubert find_member_bit(tOptions * opts, tOptDesc * od, char const * pz, int len,
4662b15cb3dSCy Schubert char const * const * nm_list, unsigned int nm_ct)
4672b15cb3dSCy Schubert {
4682b15cb3dSCy Schubert char nm_buf[ AO_NAME_SIZE ];
4692b15cb3dSCy Schubert
4702b15cb3dSCy Schubert memcpy(nm_buf, pz, len);
4712b15cb3dSCy Schubert nm_buf[len] = NUL;
4722b15cb3dSCy Schubert
4732b15cb3dSCy Schubert {
4742b15cb3dSCy Schubert unsigned int shift_ct = (unsigned int)
4752b15cb3dSCy Schubert find_name(nm_buf, opts, od, nm_list, nm_ct);
4762b15cb3dSCy Schubert if (shift_ct >= nm_ct)
4772b15cb3dSCy Schubert return 0UL;
4782b15cb3dSCy Schubert
479*a466cc55SCy Schubert return 1UL << shift_ct;
4802b15cb3dSCy Schubert }
4812b15cb3dSCy Schubert }
4822b15cb3dSCy Schubert
4832b15cb3dSCy Schubert /*=export_func optionMemberList
4842b15cb3dSCy Schubert * what: Get the list of members of a bit mask set
4852b15cb3dSCy Schubert *
4862b15cb3dSCy Schubert * arg: tOptDesc *, od, the set membership option description
4872b15cb3dSCy Schubert *
4882b15cb3dSCy Schubert * ret_type: char *
4892b15cb3dSCy Schubert * ret_desc: the names of the set bits
4902b15cb3dSCy Schubert *
4912b15cb3dSCy Schubert * doc: This converts the OPT_VALUE_name mask value to a allocated string.
4922b15cb3dSCy Schubert * It is the caller's responsibility to free the string.
4932b15cb3dSCy Schubert =*/
4942b15cb3dSCy Schubert char *
optionMemberList(tOptDesc * od)4952b15cb3dSCy Schubert optionMemberList(tOptDesc * od)
4962b15cb3dSCy Schubert {
4972b15cb3dSCy Schubert uintptr_t sv = od->optArg.argIntptr;
4982b15cb3dSCy Schubert char * res;
4992b15cb3dSCy Schubert (*(od->pOptProc))(OPTPROC_RETURN_VALNAME, od);
500276da39aSCy Schubert res = VOIDP(od->optArg.argString);
5012b15cb3dSCy Schubert od->optArg.argIntptr = sv;
5022b15cb3dSCy Schubert return res;
5032b15cb3dSCy Schubert }
5042b15cb3dSCy Schubert
5052b15cb3dSCy Schubert /*=export_func optionSetMembers
5062b15cb3dSCy Schubert * what: Convert between bit flag values and strings
5072b15cb3dSCy Schubert * private:
5082b15cb3dSCy Schubert *
5092b15cb3dSCy Schubert * arg: tOptions *, opts, the program options descriptor
5102b15cb3dSCy Schubert * arg: tOptDesc *, od, the set membership option description
5112b15cb3dSCy Schubert * arg: char const * const *,
5122b15cb3dSCy Schubert * nm_list, list of enumeration names
5132b15cb3dSCy Schubert * arg: unsigned int, nm_ct, number of names in list
5142b15cb3dSCy Schubert *
5152b15cb3dSCy Schubert * doc: This converts the optArg.argString string from the option description
5162b15cb3dSCy Schubert * into the index corresponding to an entry in the name list.
5172b15cb3dSCy Schubert * This will match the generated enumeration value.
5182b15cb3dSCy Schubert * Full matches are always accepted. Partial matches are accepted
5192b15cb3dSCy Schubert * if there is only one partial match.
5202b15cb3dSCy Schubert =*/
5212b15cb3dSCy Schubert void
optionSetMembers(tOptions * opts,tOptDesc * od,char const * const * nm_list,unsigned int nm_ct)5222b15cb3dSCy Schubert optionSetMembers(tOptions * opts, tOptDesc * od,
5232b15cb3dSCy Schubert char const * const * nm_list, unsigned int nm_ct)
5242b15cb3dSCy Schubert {
5252b15cb3dSCy Schubert /*
5262b15cb3dSCy Schubert * IF the program option descriptor pointer is invalid,
5272b15cb3dSCy Schubert * then it is some sort of special request.
5282b15cb3dSCy Schubert */
5292b15cb3dSCy Schubert switch ((uintptr_t)opts) {
5302b15cb3dSCy Schubert case (uintptr_t)OPTPROC_EMIT_USAGE:
5312b15cb3dSCy Schubert enum_err(OPTPROC_EMIT_USAGE, od, nm_list, nm_ct);
5322b15cb3dSCy Schubert return;
5332b15cb3dSCy Schubert
5342b15cb3dSCy Schubert case (uintptr_t)OPTPROC_EMIT_SHELL:
5352b15cb3dSCy Schubert set_memb_shell(opts, od, nm_list, nm_ct);
5362b15cb3dSCy Schubert return;
5372b15cb3dSCy Schubert
5382b15cb3dSCy Schubert case (uintptr_t)OPTPROC_RETURN_VALNAME:
5392b15cb3dSCy Schubert set_memb_names(opts, od, nm_list, nm_ct);
5402b15cb3dSCy Schubert return;
5412b15cb3dSCy Schubert
5422b15cb3dSCy Schubert default:
5432b15cb3dSCy Schubert break;
5442b15cb3dSCy Schubert }
5452b15cb3dSCy Schubert
5462b15cb3dSCy Schubert if ((od->fOptState & OPTST_RESET) != 0)
5472b15cb3dSCy Schubert return;
5482b15cb3dSCy Schubert
5492b15cb3dSCy Schubert {
5502b15cb3dSCy Schubert char const * arg;
5512b15cb3dSCy Schubert bool invert;
5522b15cb3dSCy Schubert uintptr_t res = check_membership_start(od, &arg, &invert);
5532b15cb3dSCy Schubert if (arg == NULL)
5542b15cb3dSCy Schubert goto fail_return;
5552b15cb3dSCy Schubert
5562b15cb3dSCy Schubert while (*arg != NUL) {
5572b15cb3dSCy Schubert bool inv_val = false;
5582b15cb3dSCy Schubert int len;
5592b15cb3dSCy Schubert
5602b15cb3dSCy Schubert switch (*arg) {
5612b15cb3dSCy Schubert case ',':
5622b15cb3dSCy Schubert arg = SPN_WHITESPACE_CHARS(arg+1);
5632b15cb3dSCy Schubert if ((*arg == ',') || (*arg == '|'))
5642b15cb3dSCy Schubert goto fail_return;
5652b15cb3dSCy Schubert continue;
5662b15cb3dSCy Schubert
5672b15cb3dSCy Schubert case '-':
5682b15cb3dSCy Schubert case '!':
5692b15cb3dSCy Schubert inv_val = true;
5702b15cb3dSCy Schubert /* FALLTHROUGH */
5712b15cb3dSCy Schubert
5722b15cb3dSCy Schubert case '+':
5732b15cb3dSCy Schubert case '|':
5742b15cb3dSCy Schubert arg = SPN_WHITESPACE_CHARS(arg+1);
5752b15cb3dSCy Schubert }
5762b15cb3dSCy Schubert
5772b15cb3dSCy Schubert len = (int)(BRK_SET_SEPARATOR_CHARS(arg) - arg);
5782b15cb3dSCy Schubert if (len == 0)
5792b15cb3dSCy Schubert break;
5802b15cb3dSCy Schubert
5812b15cb3dSCy Schubert if ((len == 3) && (strncmp(arg, zAll, 3) == 0)) {
5822b15cb3dSCy Schubert if (inv_val)
5832b15cb3dSCy Schubert res = 0;
5842b15cb3dSCy Schubert else res = ~0UL;
5852b15cb3dSCy Schubert }
5862b15cb3dSCy Schubert else if ((len == 4) && (strncmp(arg, zNone, 4) == 0)) {
5872b15cb3dSCy Schubert if (! inv_val)
5882b15cb3dSCy Schubert res = 0;
5892b15cb3dSCy Schubert }
5902b15cb3dSCy Schubert else do {
5912b15cb3dSCy Schubert char * pz;
5922b15cb3dSCy Schubert uintptr_t bit = strtoul(arg, &pz, 0);
5932b15cb3dSCy Schubert
5942b15cb3dSCy Schubert if (pz != arg + len) {
5952b15cb3dSCy Schubert bit = find_member_bit(opts, od, pz, len, nm_list, nm_ct);
5962b15cb3dSCy Schubert if (bit == 0UL)
5972b15cb3dSCy Schubert goto fail_return;
5982b15cb3dSCy Schubert }
5992b15cb3dSCy Schubert if (inv_val)
6002b15cb3dSCy Schubert res &= ~bit;
6012b15cb3dSCy Schubert else res |= bit;
6022b15cb3dSCy Schubert } while (false);
6032b15cb3dSCy Schubert
6042b15cb3dSCy Schubert arg = SPN_WHITESPACE_CHARS(arg + len);
6052b15cb3dSCy Schubert }
6062b15cb3dSCy Schubert
6072b15cb3dSCy Schubert if (invert)
6082b15cb3dSCy Schubert res ^= ~0UL;
6092b15cb3dSCy Schubert
6102b15cb3dSCy Schubert if (nm_ct < (8 * sizeof(uintptr_t)))
6112b15cb3dSCy Schubert res &= (1UL << nm_ct) - 1UL;
6122b15cb3dSCy Schubert
613276da39aSCy Schubert od->optCookie = VOIDP(res);
6142b15cb3dSCy Schubert }
6152b15cb3dSCy Schubert return;
6162b15cb3dSCy Schubert
6172b15cb3dSCy Schubert fail_return:
618276da39aSCy Schubert od->optCookie = VOIDP(0);
6192b15cb3dSCy Schubert }
6202b15cb3dSCy Schubert
6212b15cb3dSCy Schubert /** @}
6222b15cb3dSCy Schubert *
6232b15cb3dSCy Schubert * Local Variables:
6242b15cb3dSCy Schubert * mode: C
6252b15cb3dSCy Schubert * c-file-style: "stroustrup"
6262b15cb3dSCy Schubert * indent-tabs-mode: nil
6272b15cb3dSCy Schubert * End:
6282b15cb3dSCy Schubert * end of autoopts/enum.c */
629