Annotation of embedaddon/ntp/sntp/libopts/enumeration.c, revision 1.1.1.1

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 */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>