1290001Sglebius 2290001Sglebius/** 3290001Sglebius * \file enumeration.c 4290001Sglebius * 5290001Sglebius * Handle options with enumeration names and bit mask bit names 6290001Sglebius * for their arguments. 7290001Sglebius * 8290001Sglebius * @addtogroup autoopts 9290001Sglebius * @{ 10290001Sglebius */ 11290001Sglebius/* 12290001Sglebius * This routine will run run-on options through a pager so the 13290001Sglebius * user may examine, print or edit them at their leisure. 14290001Sglebius * 15290001Sglebius * This file is part of AutoOpts, a companion to AutoGen. 16290001Sglebius * AutoOpts is free software. 17290001Sglebius * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 18290001Sglebius * 19290001Sglebius * AutoOpts is available under any one of two licenses. The license 20290001Sglebius * in use must be one of these two and the choice is under the control 21290001Sglebius * of the user of the license. 22290001Sglebius * 23290001Sglebius * The GNU Lesser General Public License, version 3 or later 24290001Sglebius * See the files "COPYING.lgplv3" and "COPYING.gplv3" 25290001Sglebius * 26290001Sglebius * The Modified Berkeley Software Distribution License 27290001Sglebius * See the file "COPYING.mbsd" 28290001Sglebius * 29290001Sglebius * These files have the following sha256 sums: 30290001Sglebius * 31290001Sglebius * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 32290001Sglebius * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 33290001Sglebius * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 34290001Sglebius */ 35290001Sglebius 36290001Sglebius/* = = = START-STATIC-FORWARD = = = */ 37290001Sglebiusstatic void 38290001Sglebiusenum_err(tOptions * pOpts, tOptDesc * pOD, 39290001Sglebius char const * const * paz_names, int name_ct); 40290001Sglebius 41290001Sglebiusstatic uintptr_t 42290001Sglebiusfind_name(char const * name, tOptions * pOpts, tOptDesc * pOD, 43290001Sglebius char const * const * paz_names, unsigned int name_ct); 44290001Sglebius 45290001Sglebiusstatic void 46290001Sglebiusset_memb_shell(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names, 47290001Sglebius unsigned int name_ct); 48290001Sglebius 49290001Sglebiusstatic void 50290001Sglebiusset_memb_names(tOptions * opts, tOptDesc * od, char const * const * nm_list, 51290001Sglebius unsigned int nm_ct); 52290001Sglebius 53290001Sglebiusstatic uintptr_t 54290001Sglebiuscheck_membership_start(tOptDesc * od, char const ** argp, bool * invert); 55290001Sglebius 56290001Sglebiusstatic uintptr_t 57290001Sglebiusfind_member_bit(tOptions * opts, tOptDesc * od, char const * pz, int len, 58290001Sglebius char const * const * nm_list, unsigned int nm_ct); 59290001Sglebius/* = = = END-STATIC-FORWARD = = = */ 60290001Sglebius 61290001Sglebiusstatic void 62290001Sglebiusenum_err(tOptions * pOpts, tOptDesc * pOD, 63290001Sglebius char const * const * paz_names, int name_ct) 64290001Sglebius{ 65290001Sglebius size_t max_len = 0; 66290001Sglebius size_t ttl_len = 0; 67290001Sglebius int ct_down = name_ct; 68290001Sglebius int hidden = 0; 69290001Sglebius 70290001Sglebius /* 71290001Sglebius * A real "pOpts" pointer means someone messed up. Give a real error. 72290001Sglebius */ 73290001Sglebius if (pOpts > OPTPROC_EMIT_LIMIT) 74290001Sglebius fprintf(option_usage_fp, pz_enum_err_fmt, pOpts->pzProgName, 75290001Sglebius pOD->optArg.argString, pOD->pz_Name); 76290001Sglebius 77290001Sglebius fprintf(option_usage_fp, zValidKeys, pOD->pz_Name); 78290001Sglebius 79290001Sglebius /* 80290001Sglebius * If the first name starts with this funny character, then we have 81290001Sglebius * a first value with an unspellable name. You cannot specify it. 82290001Sglebius * So, we don't list it either. 83290001Sglebius */ 84290001Sglebius if (**paz_names == 0x7F) { 85290001Sglebius paz_names++; 86290001Sglebius hidden = 1; 87290001Sglebius ct_down = --name_ct; 88290001Sglebius } 89290001Sglebius 90290001Sglebius /* 91290001Sglebius * Figure out the maximum length of any name, plus the total length 92290001Sglebius * of all the names. 93290001Sglebius */ 94290001Sglebius { 95290001Sglebius char const * const * paz = paz_names; 96290001Sglebius 97290001Sglebius do { 98290001Sglebius size_t len = strlen(*(paz++)) + 1; 99290001Sglebius if (len > max_len) 100290001Sglebius max_len = len; 101290001Sglebius ttl_len += len; 102290001Sglebius } while (--ct_down > 0); 103290001Sglebius 104290001Sglebius ct_down = name_ct; 105290001Sglebius } 106290001Sglebius 107290001Sglebius /* 108290001Sglebius * IF any one entry is about 1/2 line or longer, print one per line 109290001Sglebius */ 110290001Sglebius if (max_len > 35) { 111290001Sglebius do { 112290001Sglebius fprintf(option_usage_fp, ENUM_ERR_LINE, *(paz_names++)); 113290001Sglebius } while (--ct_down > 0); 114290001Sglebius } 115290001Sglebius 116290001Sglebius /* 117290001Sglebius * ELSE IF they all fit on one line, then do so. 118290001Sglebius */ 119290001Sglebius else if (ttl_len < 76) { 120290001Sglebius fputc(' ', option_usage_fp); 121290001Sglebius do { 122290001Sglebius fputc(' ', option_usage_fp); 123290001Sglebius fputs(*(paz_names++), option_usage_fp); 124290001Sglebius } while (--ct_down > 0); 125290001Sglebius fputc(NL, option_usage_fp); 126290001Sglebius } 127290001Sglebius 128290001Sglebius /* 129290001Sglebius * Otherwise, columnize the output 130290001Sglebius */ 131290001Sglebius else { 132290001Sglebius unsigned int ent_no = 0; 133290001Sglebius char zFmt[16]; /* format for all-but-last entries on a line */ 134290001Sglebius 135290001Sglebius sprintf(zFmt, ENUM_ERR_WIDTH, (int)max_len); 136290001Sglebius max_len = 78 / max_len; /* max_len is now max entries on a line */ 137290001Sglebius fputs(TWO_SPACES_STR, option_usage_fp); 138290001Sglebius 139290001Sglebius /* 140290001Sglebius * Loop through all but the last entry 141290001Sglebius */ 142290001Sglebius ct_down = name_ct; 143290001Sglebius while (--ct_down > 0) { 144290001Sglebius if (++ent_no == max_len) { 145290001Sglebius /* 146290001Sglebius * Last entry on a line. Start next line, too. 147290001Sglebius */ 148290001Sglebius fprintf(option_usage_fp, NLSTR_SPACE_FMT, *(paz_names++)); 149290001Sglebius ent_no = 0; 150290001Sglebius } 151290001Sglebius 152290001Sglebius else 153290001Sglebius fprintf(option_usage_fp, zFmt, *(paz_names++) ); 154290001Sglebius } 155290001Sglebius fprintf(option_usage_fp, NLSTR_FMT, *paz_names); 156290001Sglebius } 157290001Sglebius 158290001Sglebius if (pOpts > OPTPROC_EMIT_LIMIT) { 159290001Sglebius fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden); 160290001Sglebius 161290001Sglebius (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE); 162290001Sglebius /* NOTREACHED */ 163290001Sglebius } 164290001Sglebius 165290001Sglebius if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) { 166290001Sglebius fprintf(option_usage_fp, zLowerBits, name_ct); 167290001Sglebius fputs(zSetMemberSettings, option_usage_fp); 168290001Sglebius } else { 169290001Sglebius fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden); 170290001Sglebius } 171290001Sglebius} 172290001Sglebius 173290001Sglebius/** 174290001Sglebius * Convert a name or number into a binary number. 175290001Sglebius * "~0" and "-1" will be converted to the largest value in the enumeration. 176290001Sglebius * 177290001Sglebius * @param name the keyword name (number) to convert 178290001Sglebius * @param pOpts the program's option descriptor 179290001Sglebius * @param pOD the option descriptor for this option 180290001Sglebius * @param paz_names the list of keywords for this option 181290001Sglebius * @param name_ct the count of keywords 182290001Sglebius */ 183290001Sglebiusstatic uintptr_t 184290001Sglebiusfind_name(char const * name, tOptions * pOpts, tOptDesc * pOD, 185290001Sglebius char const * const * paz_names, unsigned int name_ct) 186290001Sglebius{ 187290001Sglebius /* 188290001Sglebius * Return the matching index as a pointer sized integer. 189290001Sglebius * The result gets stashed in a char * pointer. 190290001Sglebius */ 191290001Sglebius uintptr_t res = name_ct; 192294905Sdelphij size_t len = strlen(name); 193290001Sglebius uintptr_t idx; 194290001Sglebius 195290001Sglebius if (IS_DEC_DIGIT_CHAR(*name)) { 196294905Sdelphij char * pz; 197294905Sdelphij unsigned long val = strtoul(name, &pz, 0); 198290001Sglebius if ((*pz == NUL) && (val < name_ct)) 199290001Sglebius return (uintptr_t)val; 200290001Sglebius pz_enum_err_fmt = znum_too_large; 201290001Sglebius option_usage_fp = stderr; 202290001Sglebius enum_err(pOpts, pOD, paz_names, (int)name_ct); 203290001Sglebius return name_ct; 204290001Sglebius } 205290001Sglebius 206290001Sglebius if (IS_INVERSION_CHAR(*name) && (name[2] == NUL)) { 207290001Sglebius if ( ((name[0] == '~') && (name[1] == '0')) 208290001Sglebius || ((name[0] == '-') && (name[1] == '1'))) 209290001Sglebius return (uintptr_t)(name_ct - 1); 210290001Sglebius goto oops; 211290001Sglebius } 212290001Sglebius 213290001Sglebius /* 214290001Sglebius * Look for an exact match, but remember any partial matches. 215290001Sglebius * Multiple partial matches means we have an ambiguous match. 216290001Sglebius */ 217290001Sglebius for (idx = 0; idx < name_ct; idx++) { 218294905Sdelphij if (strncmp(paz_names[idx], name, len) == 0) { 219290001Sglebius if (paz_names[idx][len] == NUL) 220290001Sglebius return idx; /* full match */ 221290001Sglebius 222290001Sglebius if (res == name_ct) 223290001Sglebius res = idx; /* save partial match */ 224290001Sglebius else 225290001Sglebius res = (uintptr_t)~0; /* may yet find full match */ 226290001Sglebius } 227290001Sglebius } 228290001Sglebius 229290001Sglebius if (res < name_ct) 230290001Sglebius return res; /* partial match */ 231290001Sglebius 232290001Sglebius oops: 233290001Sglebius 234290001Sglebius pz_enum_err_fmt = (res == name_ct) ? zNoKey : zambiguous_key; 235290001Sglebius option_usage_fp = stderr; 236290001Sglebius enum_err(pOpts, pOD, paz_names, (int)name_ct); 237290001Sglebius return name_ct; 238290001Sglebius} 239290001Sglebius 240290001Sglebius 241290001Sglebius/*=export_func optionKeywordName 242290001Sglebius * what: Convert between enumeration values and strings 243290001Sglebius * private: 244290001Sglebius * 245290001Sglebius * arg: tOptDesc *, pOD, enumeration option description 246290001Sglebius * arg: unsigned int, enum_val, the enumeration value to map 247290001Sglebius * 248290001Sglebius * ret_type: char const * 249290001Sglebius * ret_desc: the enumeration name from const memory 250290001Sglebius * 251290001Sglebius * doc: This converts an enumeration value into the matching string. 252290001Sglebius=*/ 253290001Sglebiuschar const * 254290001SglebiusoptionKeywordName(tOptDesc * pOD, unsigned int enum_val) 255290001Sglebius{ 256290001Sglebius tOptDesc od = { 0 }; 257290001Sglebius od.optArg.argEnum = enum_val; 258290001Sglebius 259290001Sglebius (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, &od ); 260290001Sglebius return od.optArg.argString; 261290001Sglebius} 262290001Sglebius 263290001Sglebius 264290001Sglebius/*=export_func optionEnumerationVal 265290001Sglebius * what: Convert from a string to an enumeration value 266290001Sglebius * private: 267290001Sglebius * 268290001Sglebius * arg: tOptions *, pOpts, the program options descriptor 269290001Sglebius * arg: tOptDesc *, pOD, enumeration option description 270290001Sglebius * arg: char const * const *, paz_names, list of enumeration names 271290001Sglebius * arg: unsigned int, name_ct, number of names in list 272290001Sglebius * 273290001Sglebius * ret_type: uintptr_t 274290001Sglebius * ret_desc: the enumeration value 275290001Sglebius * 276290001Sglebius * doc: This converts the optArg.argString string from the option description 277290001Sglebius * into the index corresponding to an entry in the name list. 278290001Sglebius * This will match the generated enumeration value. 279290001Sglebius * Full matches are always accepted. Partial matches are accepted 280290001Sglebius * if there is only one partial match. 281290001Sglebius=*/ 282290001Sglebiusuintptr_t 283290001SglebiusoptionEnumerationVal(tOptions * pOpts, tOptDesc * pOD, 284290001Sglebius char const * const * paz_names, unsigned int name_ct) 285290001Sglebius{ 286290001Sglebius uintptr_t res = 0UL; 287290001Sglebius 288290001Sglebius /* 289290001Sglebius * IF the program option descriptor pointer is invalid, 290290001Sglebius * then it is some sort of special request. 291290001Sglebius */ 292290001Sglebius switch ((uintptr_t)pOpts) { 293290001Sglebius case (uintptr_t)OPTPROC_EMIT_USAGE: 294290001Sglebius /* 295290001Sglebius * print the list of enumeration names. 296290001Sglebius */ 297290001Sglebius enum_err(pOpts, pOD, paz_names, (int)name_ct); 298290001Sglebius break; 299290001Sglebius 300290001Sglebius case (uintptr_t)OPTPROC_EMIT_SHELL: 301290001Sglebius { 302290001Sglebius unsigned int ix = (unsigned int)pOD->optArg.argEnum; 303290001Sglebius /* 304290001Sglebius * print the name string. 305290001Sglebius */ 306290001Sglebius if (ix >= name_ct) 307290001Sglebius printf(INVALID_FMT, ix); 308290001Sglebius else 309290001Sglebius fputs(paz_names[ ix ], stdout); 310290001Sglebius 311290001Sglebius break; 312290001Sglebius } 313290001Sglebius 314290001Sglebius case (uintptr_t)OPTPROC_RETURN_VALNAME: 315290001Sglebius { 316290001Sglebius unsigned int ix = (unsigned int)pOD->optArg.argEnum; 317290001Sglebius /* 318290001Sglebius * Replace the enumeration value with the name string. 319290001Sglebius */ 320290001Sglebius if (ix >= name_ct) 321290001Sglebius return (uintptr_t)INVALID_STR; 322290001Sglebius 323290001Sglebius pOD->optArg.argString = paz_names[ix]; 324290001Sglebius break; 325290001Sglebius } 326290001Sglebius 327290001Sglebius default: 328290001Sglebius if ((pOD->fOptState & OPTST_RESET) != 0) 329290001Sglebius break; 330290001Sglebius 331290001Sglebius res = find_name(pOD->optArg.argString, pOpts, pOD, paz_names, name_ct); 332290001Sglebius 333290001Sglebius if (pOD->fOptState & OPTST_ALLOC_ARG) { 334290001Sglebius AGFREE(pOD->optArg.argString); 335290001Sglebius pOD->fOptState &= ~OPTST_ALLOC_ARG; 336290001Sglebius pOD->optArg.argString = NULL; 337290001Sglebius } 338290001Sglebius } 339290001Sglebius 340290001Sglebius return res; 341290001Sglebius} 342290001Sglebius 343290001Sglebiusstatic void 344290001Sglebiusset_memb_shell(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names, 345290001Sglebius unsigned int name_ct) 346290001Sglebius{ 347290001Sglebius /* 348290001Sglebius * print the name string. 349290001Sglebius */ 350290001Sglebius unsigned int ix = 0; 351290001Sglebius uintptr_t bits = (uintptr_t)pOD->optCookie; 352290001Sglebius size_t len = 0; 353290001Sglebius 354290001Sglebius (void)pOpts; 355290001Sglebius bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1; 356290001Sglebius 357290001Sglebius while (bits != 0) { 358290001Sglebius if (bits & 1) { 359290001Sglebius if (len++ > 0) fputs(OR_STR, stdout); 360290001Sglebius fputs(paz_names[ix], stdout); 361290001Sglebius } 362290001Sglebius if (++ix >= name_ct) break; 363290001Sglebius bits >>= 1; 364290001Sglebius } 365290001Sglebius} 366290001Sglebius 367290001Sglebiusstatic void 368290001Sglebiusset_memb_names(tOptions * opts, tOptDesc * od, char const * const * nm_list, 369290001Sglebius unsigned int nm_ct) 370290001Sglebius{ 371290001Sglebius char * pz; 372290001Sglebius uintptr_t mask = (1UL << (uintptr_t)nm_ct) - 1UL; 373290001Sglebius uintptr_t bits = (uintptr_t)od->optCookie & mask; 374290001Sglebius unsigned int ix = 0; 375290001Sglebius size_t len = 1; 376290001Sglebius 377290001Sglebius /* 378290001Sglebius * Replace the enumeration value with the name string. 379290001Sglebius * First, determine the needed length, then allocate and fill in. 380290001Sglebius */ 381290001Sglebius while (bits != 0) { 382290001Sglebius if (bits & 1) 383290001Sglebius len += strlen(nm_list[ix]) + PLUS_STR_LEN + 1; 384290001Sglebius if (++ix >= nm_ct) break; 385290001Sglebius bits >>= 1; 386290001Sglebius } 387290001Sglebius 388290001Sglebius od->optArg.argString = pz = AGALOC(len, "enum"); 389290001Sglebius bits = (uintptr_t)od->optCookie & mask; 390290001Sglebius if (bits == 0) { 391290001Sglebius *pz = NUL; 392290001Sglebius return; 393290001Sglebius } 394290001Sglebius 395290001Sglebius for (ix = 0; ; ix++) { 396290001Sglebius size_t nln; 397290001Sglebius int doit = bits & 1; 398290001Sglebius 399290001Sglebius bits >>= 1; 400290001Sglebius if (doit == 0) 401290001Sglebius continue; 402290001Sglebius 403290001Sglebius nln = strlen(nm_list[ix]); 404290001Sglebius memcpy(pz, nm_list[ix], nln); 405290001Sglebius pz += nln; 406290001Sglebius if (bits == 0) 407290001Sglebius break; 408290001Sglebius memcpy(pz, PLUS_STR, PLUS_STR_LEN); 409290001Sglebius pz += PLUS_STR_LEN; 410290001Sglebius } 411290001Sglebius *pz = NUL; 412290001Sglebius (void)opts; 413290001Sglebius} 414290001Sglebius 415290001Sglebius/** 416290001Sglebius * Check membership start conditions. An equal character (@samp{=}) says to 417290001Sglebius * clear the result and not carry over any residual value. A carat 418290001Sglebius * (@samp{^}), which may follow the equal character, says to invert the 419290001Sglebius * result. The scanning pointer is advanced past these characters and any 420290001Sglebius * leading white space. Invalid sequences are indicated by setting the 421290001Sglebius * scanning pointer to NULL. 422290001Sglebius * 423290001Sglebius * @param od the set membership option description 424290001Sglebius * @param argp a pointer to the string scanning pointer 425290001Sglebius * @param invert a pointer to the boolean inversion indicator 426290001Sglebius * 427290001Sglebius * @returns either zero or the original value for the optCookie. 428290001Sglebius */ 429290001Sglebiusstatic uintptr_t 430290001Sglebiuscheck_membership_start(tOptDesc * od, char const ** argp, bool * invert) 431290001Sglebius{ 432290001Sglebius uintptr_t res = (uintptr_t)od->optCookie; 433290001Sglebius char const * arg = SPN_WHITESPACE_CHARS(od->optArg.argString); 434290001Sglebius if ((arg == NULL) || (*arg == NUL)) 435290001Sglebius goto member_start_fail; 436290001Sglebius 437290001Sglebius *invert = false; 438290001Sglebius 439290001Sglebius switch (*arg) { 440290001Sglebius case '=': 441290001Sglebius res = 0UL; 442290001Sglebius arg = SPN_WHITESPACE_CHARS(arg + 1); 443290001Sglebius switch (*arg) { 444290001Sglebius case '=': case ',': 445290001Sglebius goto member_start_fail; 446290001Sglebius case '^': 447290001Sglebius goto inversion; 448290001Sglebius default: 449290001Sglebius break; 450290001Sglebius } 451290001Sglebius break; 452290001Sglebius 453290001Sglebius case '^': 454290001Sglebius inversion: 455290001Sglebius *invert = true; 456290001Sglebius arg = SPN_WHITESPACE_CHARS(arg + 1); 457290001Sglebius if (*arg != ',') 458290001Sglebius break; 459290001Sglebius /* FALLTHROUGH */ 460290001Sglebius 461290001Sglebius case ',': 462290001Sglebius goto member_start_fail; 463290001Sglebius 464290001Sglebius default: 465290001Sglebius break; 466290001Sglebius } 467290001Sglebius 468290001Sglebius *argp = arg; 469290001Sglebius return res; 470290001Sglebius 471290001Sglebiusmember_start_fail: 472290001Sglebius *argp = NULL; 473290001Sglebius return 0UL; 474290001Sglebius} 475290001Sglebius 476290001Sglebius/** 477290001Sglebius * convert a name to a bit. Look up a name string to get a bit number 478290001Sglebius * and shift the value "1" left that number of bits. 479290001Sglebius * 480290001Sglebius * @param opts program options descriptor 481290001Sglebius * @param od the set membership option description 482290001Sglebius * @param pz address of the start of the bit name 483290001Sglebius * @param nm_list the list of names for this option 484290001Sglebius * @param nm_ct the number of entries in this list 485290001Sglebius * 486290001Sglebius * @returns 0UL on error, other an unsigned long with the correct bit set. 487290001Sglebius */ 488290001Sglebiusstatic uintptr_t 489290001Sglebiusfind_member_bit(tOptions * opts, tOptDesc * od, char const * pz, int len, 490290001Sglebius char const * const * nm_list, unsigned int nm_ct) 491290001Sglebius{ 492290001Sglebius char nm_buf[ AO_NAME_SIZE ]; 493290001Sglebius 494290001Sglebius memcpy(nm_buf, pz, len); 495290001Sglebius nm_buf[len] = NUL; 496290001Sglebius 497290001Sglebius { 498290001Sglebius unsigned int shift_ct = (unsigned int) 499290001Sglebius find_name(nm_buf, opts, od, nm_list, nm_ct); 500290001Sglebius if (shift_ct >= nm_ct) 501290001Sglebius return 0UL; 502290001Sglebius 503294905Sdelphij return (uintptr_t)1U << shift_ct; 504290001Sglebius } 505290001Sglebius} 506290001Sglebius 507290001Sglebius/*=export_func optionMemberList 508290001Sglebius * what: Get the list of members of a bit mask set 509290001Sglebius * 510290001Sglebius * arg: tOptDesc *, od, the set membership option description 511290001Sglebius * 512290001Sglebius * ret_type: char * 513290001Sglebius * ret_desc: the names of the set bits 514290001Sglebius * 515290001Sglebius * doc: This converts the OPT_VALUE_name mask value to a allocated string. 516290001Sglebius * It is the caller's responsibility to free the string. 517290001Sglebius=*/ 518290001Sglebiuschar * 519290001SglebiusoptionMemberList(tOptDesc * od) 520290001Sglebius{ 521290001Sglebius uintptr_t sv = od->optArg.argIntptr; 522290001Sglebius char * res; 523290001Sglebius (*(od->pOptProc))(OPTPROC_RETURN_VALNAME, od); 524290001Sglebius res = VOIDP(od->optArg.argString); 525290001Sglebius od->optArg.argIntptr = sv; 526290001Sglebius return res; 527290001Sglebius} 528290001Sglebius 529290001Sglebius/*=export_func optionSetMembers 530290001Sglebius * what: Convert between bit flag values and strings 531290001Sglebius * private: 532290001Sglebius * 533290001Sglebius * arg: tOptions *, opts, the program options descriptor 534290001Sglebius * arg: tOptDesc *, od, the set membership option description 535290001Sglebius * arg: char const * const *, 536290001Sglebius * nm_list, list of enumeration names 537290001Sglebius * arg: unsigned int, nm_ct, number of names in list 538290001Sglebius * 539290001Sglebius * doc: This converts the optArg.argString string from the option description 540290001Sglebius * into the index corresponding to an entry in the name list. 541290001Sglebius * This will match the generated enumeration value. 542290001Sglebius * Full matches are always accepted. Partial matches are accepted 543290001Sglebius * if there is only one partial match. 544290001Sglebius=*/ 545290001Sglebiusvoid 546290001SglebiusoptionSetMembers(tOptions * opts, tOptDesc * od, 547290001Sglebius char const * const * nm_list, unsigned int nm_ct) 548290001Sglebius{ 549290001Sglebius /* 550290001Sglebius * IF the program option descriptor pointer is invalid, 551290001Sglebius * then it is some sort of special request. 552290001Sglebius */ 553290001Sglebius switch ((uintptr_t)opts) { 554290001Sglebius case (uintptr_t)OPTPROC_EMIT_USAGE: 555290001Sglebius enum_err(OPTPROC_EMIT_USAGE, od, nm_list, nm_ct); 556290001Sglebius return; 557290001Sglebius 558290001Sglebius case (uintptr_t)OPTPROC_EMIT_SHELL: 559290001Sglebius set_memb_shell(opts, od, nm_list, nm_ct); 560290001Sglebius return; 561290001Sglebius 562290001Sglebius case (uintptr_t)OPTPROC_RETURN_VALNAME: 563290001Sglebius set_memb_names(opts, od, nm_list, nm_ct); 564290001Sglebius return; 565290001Sglebius 566290001Sglebius default: 567290001Sglebius break; 568290001Sglebius } 569290001Sglebius 570290001Sglebius if ((od->fOptState & OPTST_RESET) != 0) 571290001Sglebius return; 572290001Sglebius 573290001Sglebius { 574290001Sglebius char const * arg; 575290001Sglebius bool invert; 576290001Sglebius uintptr_t res = check_membership_start(od, &arg, &invert); 577290001Sglebius if (arg == NULL) 578290001Sglebius goto fail_return; 579290001Sglebius 580290001Sglebius while (*arg != NUL) { 581290001Sglebius bool inv_val = false; 582290001Sglebius int len; 583290001Sglebius 584290001Sglebius switch (*arg) { 585290001Sglebius case ',': 586290001Sglebius arg = SPN_WHITESPACE_CHARS(arg+1); 587290001Sglebius if ((*arg == ',') || (*arg == '|')) 588290001Sglebius goto fail_return; 589290001Sglebius continue; 590290001Sglebius 591290001Sglebius case '-': 592290001Sglebius case '!': 593290001Sglebius inv_val = true; 594290001Sglebius /* FALLTHROUGH */ 595290001Sglebius 596290001Sglebius case '+': 597290001Sglebius case '|': 598290001Sglebius arg = SPN_WHITESPACE_CHARS(arg+1); 599290001Sglebius } 600290001Sglebius 601290001Sglebius len = (int)(BRK_SET_SEPARATOR_CHARS(arg) - arg); 602290001Sglebius if (len == 0) 603290001Sglebius break; 604290001Sglebius 605290001Sglebius if ((len == 3) && (strncmp(arg, zAll, 3) == 0)) { 606290001Sglebius if (inv_val) 607290001Sglebius res = 0; 608290001Sglebius else res = ~0UL; 609290001Sglebius } 610290001Sglebius else if ((len == 4) && (strncmp(arg, zNone, 4) == 0)) { 611290001Sglebius if (! inv_val) 612290001Sglebius res = 0; 613290001Sglebius } 614290001Sglebius else do { 615290001Sglebius char * pz; 616290001Sglebius uintptr_t bit = strtoul(arg, &pz, 0); 617290001Sglebius 618290001Sglebius if (pz != arg + len) { 619290001Sglebius bit = find_member_bit(opts, od, pz, len, nm_list, nm_ct); 620290001Sglebius if (bit == 0UL) 621290001Sglebius goto fail_return; 622290001Sglebius } 623290001Sglebius if (inv_val) 624290001Sglebius res &= ~bit; 625290001Sglebius else res |= bit; 626290001Sglebius } while (false); 627290001Sglebius 628290001Sglebius arg = SPN_WHITESPACE_CHARS(arg + len); 629290001Sglebius } 630290001Sglebius 631290001Sglebius if (invert) 632290001Sglebius res ^= ~0UL; 633290001Sglebius 634290001Sglebius if (nm_ct < (8 * sizeof(uintptr_t))) 635290001Sglebius res &= (1UL << nm_ct) - 1UL; 636290001Sglebius 637290001Sglebius od->optCookie = VOIDP(res); 638290001Sglebius } 639290001Sglebius return; 640290001Sglebius 641290001Sglebiusfail_return: 642290001Sglebius od->optCookie = VOIDP(0); 643290001Sglebius} 644290001Sglebius 645290001Sglebius/** @} 646290001Sglebius * 647290001Sglebius * Local Variables: 648290001Sglebius * mode: C 649290001Sglebius * c-file-style: "stroustrup" 650290001Sglebius * indent-tabs-mode: nil 651290001Sglebius * End: 652290001Sglebius * end of autoopts/enum.c */ 653