File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / sntp / libopts / enumeration.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 7 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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>