Annotation of embedaddon/ntp/sntp/libopts/enumeration.c, revision 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>