Return to enumeration.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / sntp / libopts |
1.1 ! misho 1: ! 2: /** ! 3: * \file enumeration.c ! 4: * ! 5: * Time-stamp: "2011-04-06 10:48:22 bkorb" ! 6: * ! 7: * Automated Options Paged Usage module. ! 8: * ! 9: * This routine will run run-on options through a pager so the ! 10: * user may examine, print or edit them at their leisure. ! 11: * ! 12: * This file is part of AutoOpts, a companion to AutoGen. ! 13: * AutoOpts is free software. ! 14: * AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved ! 15: * ! 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. ! 19: * ! 20: * The GNU Lesser General Public License, version 3 or later ! 21: * See the files "COPYING.lgplv3" and "COPYING.gplv3" ! 22: * ! 23: * The Modified Berkeley Software Distribution License ! 24: * See the file "COPYING.mbsd" ! 25: * ! 26: * These files have the following md5sums: ! 27: * ! 28: * 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3 ! 29: * 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3 ! 30: * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd ! 31: */ ! 32: ! 33: static char const * pz_enum_err_fmt; ! 34: ! 35: /* = = = START-STATIC-FORWARD = = = */ ! 36: static void ! 37: enum_err(tOptions * pOpts, tOptDesc * pOD, ! 38: char const * const * paz_names, int name_ct); ! 39: ! 40: static uintptr_t ! 41: find_name(char const * pzName, tOptions * pOpts, tOptDesc * pOD, ! 42: char const * const * paz_names, unsigned int name_ct); ! 43: ! 44: static void ! 45: set_memb_usage(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names, ! 46: unsigned int name_ct); ! 47: ! 48: static void ! 49: set_memb_shell(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names, ! 50: unsigned int name_ct); ! 51: ! 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 = = = */ ! 56: ! 57: static void ! 58: enum_err(tOptions * pOpts, tOptDesc * pOD, ! 59: char const * const * paz_names, int name_ct) ! 60: { ! 61: size_t max_len = 0; ! 62: size_t ttl_len = 0; ! 63: int ct_down = name_ct; ! 64: int hidden = 0; ! 65: ! 66: /* ! 67: * A real "pOpts" pointer means someone messed up. Give a real error. ! 68: */ ! 69: if (pOpts > OPTPROC_EMIT_LIMIT) ! 70: fprintf(option_usage_fp, pz_enum_err_fmt, pOpts->pzProgName, ! 71: pOD->optArg.argString, pOD->pz_Name); ! 72: ! 73: fprintf(option_usage_fp, zValidKeys, pOD->pz_Name); ! 74: ! 75: /* ! 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. ! 79: */ ! 80: if (**paz_names == 0x7F) { ! 81: paz_names++; ! 82: hidden = 1; ! 83: ct_down = --name_ct; ! 84: } ! 85: ! 86: /* ! 87: * Figure out the maximum length of any name, plus the total length ! 88: * of all the names. ! 89: */ ! 90: { ! 91: char const * const * paz = paz_names; ! 92: ! 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); ! 99: ! 100: ct_down = name_ct; ! 101: } ! 102: ! 103: /* ! 104: * IF any one entry is about 1/2 line or longer, print one per line ! 105: */ ! 106: if (max_len > 35) { ! 107: do { ! 108: fprintf(option_usage_fp, " %s\n", *(paz_names++)); ! 109: } while (--ct_down > 0); ! 110: } ! 111: ! 112: /* ! 113: * ELSE IF they all fit on one line, then do so. ! 114: */ ! 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('\n', option_usage_fp); ! 122: } ! 123: ! 124: /* ! 125: * Otherwise, columnize the output ! 126: */ ! 127: else { ! 128: int ent_no = 0; ! 129: char zFmt[16]; /* format for all-but-last entries on a line */ ! 130: ! 131: sprintf(zFmt, "%%-%ds", (int)max_len); ! 132: max_len = 78 / max_len; /* max_len is now max entries on a line */ ! 133: fputs(" ", option_usage_fp); ! 134: ! 135: /* ! 136: * Loop through all but the last entry ! 137: */ ! 138: ct_down = name_ct; ! 139: while (--ct_down > 0) { ! 140: if (++ent_no == max_len) { ! 141: /* ! 142: * Last entry on a line. Start next line, too. ! 143: */ ! 144: fprintf(option_usage_fp, "%s\n ", *(paz_names++)); ! 145: ent_no = 0; ! 146: } ! 147: ! 148: else ! 149: fprintf(option_usage_fp, zFmt, *(paz_names++) ); ! 150: } ! 151: fprintf(option_usage_fp, "%s\n", *paz_names); ! 152: } ! 153: ! 154: if (pOpts > OPTPROC_EMIT_LIMIT) { ! 155: fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden); ! 156: ! 157: (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE); ! 158: /* NOTREACHED */ ! 159: } ! 160: ! 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); ! 166: } ! 167: } ! 168: ! 169: ! 170: static uintptr_t ! 171: find_name(char const * pzName, tOptions * pOpts, tOptDesc * pOD, ! 172: char const * const * paz_names, unsigned int name_ct) ! 173: { ! 174: /* ! 175: * Return the matching index as a pointer sized integer. ! 176: * The result gets stashed in a char* pointer. ! 177: */ ! 178: uintptr_t res = name_ct; ! 179: size_t len = strlen((char*)pzName); ! 180: uintptr_t idx; ! 181: ! 182: if (IS_DEC_DIGIT_CHAR(*pzName)) { ! 183: char * pz = (char *)(void *)pzName; ! 184: unsigned long val = strtoul(pz, &pz, 0); ! 185: if ((*pz == NUL) && (val < name_ct)) ! 186: return (uintptr_t)val; ! 187: enum_err(pOpts, pOD, paz_names, (int)name_ct); ! 188: return name_ct; ! 189: } ! 190: ! 191: /* ! 192: * Look for an exact match, but remember any partial matches. ! 193: * Multiple partial matches means we have an ambiguous match. ! 194: */ ! 195: for (idx = 0; idx < name_ct; idx++) { ! 196: if (strncmp((char*)paz_names[idx], (char*)pzName, len) == 0) { ! 197: if (paz_names[idx][len] == NUL) ! 198: return idx; /* full match */ ! 199: ! 200: res = (res != name_ct) ? ~0 : idx; /* save partial match */ ! 201: } ! 202: } ! 203: ! 204: if (res < name_ct) ! 205: return res; /* partial match */ ! 206: ! 207: pz_enum_err_fmt = (res == name_ct) ? zNoKey : zAmbigKey; ! 208: option_usage_fp = stderr; ! 209: enum_err(pOpts, pOD, paz_names, (int)name_ct); ! 210: return name_ct; ! 211: } ! 212: ! 213: ! 214: /*=export_func optionKeywordName ! 215: * what: Convert between enumeration values and strings ! 216: * private: ! 217: * ! 218: * arg: tOptDesc*, pOD, enumeration option description ! 219: * arg: unsigned int, enum_val, the enumeration value to map ! 220: * ! 221: * ret_type: char const * ! 222: * ret_desc: the enumeration name from const memory ! 223: * ! 224: * doc: This converts an enumeration value into the matching string. ! 225: =*/ ! 226: char const * ! 227: optionKeywordName(tOptDesc * pOD, unsigned int enum_val) ! 228: { ! 229: tOptDesc od; ! 230: ! 231: od.optArg.argEnum = enum_val; ! 232: (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, &od ); ! 233: return od.optArg.argString; ! 234: } ! 235: ! 236: ! 237: /*=export_func optionEnumerationVal ! 238: * what: Convert from a string to an enumeration value ! 239: * private: ! 240: * ! 241: * arg: tOptions*, pOpts, the program options descriptor ! 242: * arg: tOptDesc*, pOD, enumeration option description ! 243: * arg: char const * const *, paz_names, list of enumeration names ! 244: * arg: unsigned int, name_ct, number of names in list ! 245: * ! 246: * ret_type: uintptr_t ! 247: * ret_desc: the enumeration value ! 248: * ! 249: * doc: This converts the optArg.argString string from the option description ! 250: * into the index corresponding to an entry in the name list. ! 251: * This will match the generated enumeration value. ! 252: * Full matches are always accepted. Partial matches are accepted ! 253: * if there is only one partial match. ! 254: =*/ ! 255: uintptr_t ! 256: optionEnumerationVal(tOptions * pOpts, tOptDesc * pOD, ! 257: char const * const * paz_names, unsigned int name_ct) ! 258: { ! 259: uintptr_t res = 0UL; ! 260: ! 261: /* ! 262: * IF the program option descriptor pointer is invalid, ! 263: * then it is some sort of special request. ! 264: */ ! 265: switch ((uintptr_t)pOpts) { ! 266: case (uintptr_t)OPTPROC_EMIT_USAGE: ! 267: /* ! 268: * print the list of enumeration names. ! 269: */ ! 270: enum_err(pOpts, pOD, paz_names, (int)name_ct); ! 271: break; ! 272: ! 273: case (uintptr_t)OPTPROC_EMIT_SHELL: ! 274: { ! 275: unsigned int ix = pOD->optArg.argEnum; ! 276: /* ! 277: * print the name string. ! 278: */ ! 279: if (ix >= name_ct) ! 280: printf("INVALID-%d", ix); ! 281: else ! 282: fputs(paz_names[ ix ], stdout); ! 283: ! 284: break; ! 285: } ! 286: ! 287: case (uintptr_t)OPTPROC_RETURN_VALNAME: ! 288: { ! 289: tSCC zInval[] = "*INVALID*"; ! 290: unsigned int ix = pOD->optArg.argEnum; ! 291: /* ! 292: * Replace the enumeration value with the name string. ! 293: */ ! 294: if (ix >= name_ct) ! 295: return (uintptr_t)zInval; ! 296: ! 297: pOD->optArg.argString = paz_names[ix]; ! 298: break; ! 299: } ! 300: ! 301: default: ! 302: res = find_name(pOD->optArg.argString, pOpts, pOD, paz_names, name_ct); ! 303: ! 304: if (pOD->fOptState & OPTST_ALLOC_ARG) { ! 305: AGFREE(pOD->optArg.argString); ! 306: pOD->fOptState &= ~OPTST_ALLOC_ARG; ! 307: pOD->optArg.argString = NULL; ! 308: } ! 309: } ! 310: ! 311: return res; ! 312: } ! 313: ! 314: static void ! 315: set_memb_usage(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names, ! 316: unsigned int name_ct) ! 317: { ! 318: /* ! 319: * print the list of enumeration names. ! 320: */ ! 321: enum_err(OPTPROC_EMIT_USAGE, pOD, paz_names, (int)name_ct ); ! 322: } ! 323: ! 324: static void ! 325: set_memb_shell(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names, ! 326: unsigned int name_ct) ! 327: { ! 328: /* ! 329: * print the name string. ! 330: */ ! 331: int ix = 0; ! 332: uintptr_t bits = (uintptr_t)pOD->optCookie; ! 333: size_t len = 0; ! 334: ! 335: bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1; ! 336: ! 337: while (bits != 0) { ! 338: if (bits & 1) { ! 339: if (len++ > 0) fputs(" | ", stdout); ! 340: fputs(paz_names[ix], stdout); ! 341: } ! 342: if (++ix >= name_ct) break; ! 343: bits >>= 1; ! 344: } ! 345: } ! 346: ! 347: static void ! 348: set_memb_names(tOptions * pOpts, tOptDesc * pOD, char const * const * paz_names, ! 349: unsigned int name_ct) ! 350: { ! 351: static char const none[] = "none"; ! 352: static char const plus[3] = " + "; ! 353: ! 354: char * pz; ! 355: uintptr_t bits = (uintptr_t)pOD->optCookie; ! 356: int ix = 0; ! 357: size_t len = sizeof(none); ! 358: ! 359: bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1; ! 360: ! 361: /* ! 362: * Replace the enumeration value with the name string. ! 363: * First, determine the needed length, then allocate and fill in. ! 364: */ ! 365: while (bits != 0) { ! 366: if (bits & 1) ! 367: len += strlen(paz_names[ix]) + sizeof(plus); ! 368: if (++ix >= name_ct) break; ! 369: bits >>= 1; ! 370: } ! 371: ! 372: pOD->optArg.argString = pz = AGALOC(len, "enum name"); ! 373: ! 374: /* ! 375: * Start by clearing all the bits. We want to turn off any defaults ! 376: * because we will be restoring to current state, not adding to ! 377: * the default set of bits. ! 378: */ ! 379: memcpy(pz, none, sizeof(none)-1); ! 380: pz += sizeof(none)-1; ! 381: bits = (uintptr_t)pOD->optCookie; ! 382: bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1; ! 383: ix = 0; ! 384: ! 385: while (bits != 0) { ! 386: if (bits & 1) { ! 387: size_t nln = strlen(paz_names[ix]); ! 388: memcpy(pz, plus, sizeof(plus)); ! 389: memcpy(pz+sizeof(plus), paz_names[ix], nln); ! 390: pz += strlen(paz_names[ix]) + 3; ! 391: } ! 392: if (++ix >= name_ct) break; ! 393: bits >>= 1; ! 394: } ! 395: *pz = NUL; ! 396: } ! 397: ! 398: /*=export_func optionSetMembers ! 399: * what: Convert between bit flag values and strings ! 400: * private: ! 401: * ! 402: * arg: tOptions*, pOpts, the program options descriptor ! 403: * arg: tOptDesc*, pOD, enumeration option description ! 404: * arg: char const * const *, ! 405: * paz_names, list of enumeration names ! 406: * arg: unsigned int, name_ct, number of names in list ! 407: * ! 408: * doc: This converts the optArg.argString string from the option description ! 409: * into the index corresponding to an entry in the name list. ! 410: * This will match the generated enumeration value. ! 411: * Full matches are always accepted. Partial matches are accepted ! 412: * if there is only one partial match. ! 413: =*/ ! 414: void ! 415: optionSetMembers(tOptions * pOpts, tOptDesc * pOD, ! 416: char const* const * paz_names, unsigned int name_ct) ! 417: { ! 418: /* ! 419: * IF the program option descriptor pointer is invalid, ! 420: * then it is some sort of special request. ! 421: */ ! 422: switch ((uintptr_t)pOpts) { ! 423: case (uintptr_t)OPTPROC_EMIT_USAGE: ! 424: set_memb_usage(pOpts, pOD, paz_names, name_ct); ! 425: return; ! 426: ! 427: case (uintptr_t)OPTPROC_EMIT_SHELL: ! 428: set_memb_shell(pOpts, pOD, paz_names, name_ct); ! 429: return; ! 430: ! 431: case (uintptr_t)OPTPROC_RETURN_VALNAME: ! 432: set_memb_names(pOpts, pOD, paz_names, name_ct); ! 433: return; ! 434: ! 435: default: ! 436: break; ! 437: } ! 438: ! 439: if ((pOD->fOptState & OPTST_RESET) != 0) ! 440: return; ! 441: ! 442: { ! 443: char const* pzArg = pOD->optArg.argString; ! 444: uintptr_t res; ! 445: if ((pzArg == NULL) || (*pzArg == NUL)) { ! 446: pOD->optCookie = (void*)0; ! 447: return; ! 448: } ! 449: ! 450: res = (uintptr_t)pOD->optCookie; ! 451: for (;;) { ! 452: tSCC zSpn[] = " ,|+\t\r\f\n"; ! 453: int iv, len; ! 454: ! 455: pzArg += strspn(pzArg, zSpn); ! 456: iv = (*pzArg == '!'); ! 457: if (iv) ! 458: pzArg += strspn(pzArg+1, zSpn) + 1; ! 459: ! 460: len = strcspn(pzArg, zSpn); ! 461: if (len == 0) ! 462: break; ! 463: ! 464: if ((len == 3) && (strncmp(pzArg, zAll, 3) == 0)) { ! 465: if (iv) ! 466: res = 0; ! 467: else res = ~0UL; ! 468: } ! 469: else if ((len == 4) && (strncmp(pzArg, zNone, 4) == 0)) { ! 470: if (! iv) ! 471: res = 0; ! 472: } ! 473: else do { ! 474: char* pz; ! 475: uintptr_t bit = strtoul(pzArg, &pz, 0); ! 476: ! 477: if (pz != pzArg + len) { ! 478: char z[ AO_NAME_SIZE ]; ! 479: char const* p; ! 480: int shift_ct; ! 481: ! 482: if (*pz != NUL) { ! 483: if (len >= AO_NAME_LIMIT) ! 484: break; ! 485: memcpy(z, pzArg, (size_t)len); ! 486: z[len] = NUL; ! 487: p = z; ! 488: } else { ! 489: p = pzArg; ! 490: } ! 491: ! 492: shift_ct = find_name(p, pOpts, pOD, paz_names, name_ct); ! 493: if (shift_ct >= name_ct) { ! 494: pOD->optCookie = (void*)0; ! 495: return; ! 496: } ! 497: bit = 1UL << shift_ct; ! 498: } ! 499: if (iv) ! 500: res &= ~bit; ! 501: else res |= bit; ! 502: } while (0); ! 503: ! 504: if (pzArg[len] == NUL) ! 505: break; ! 506: pzArg += len + 1; ! 507: } ! 508: if (name_ct < (8 * sizeof(uintptr_t))) { ! 509: res &= (1UL << name_ct) - 1UL; ! 510: } ! 511: ! 512: pOD->optCookie = (void*)res; ! 513: } ! 514: } ! 515: ! 516: /* ! 517: * Local Variables: ! 518: * mode: C ! 519: * c-file-style: "stroustrup" ! 520: * indent-tabs-mode: nil ! 521: * End: ! 522: * end of autoopts/enumeration.c */