diff options
author | roberto <roberto@FreeBSD.org> | 2008-08-22 15:58:00 +0000 |
---|---|---|
committer | roberto <roberto@FreeBSD.org> | 2008-08-22 15:58:00 +0000 |
commit | b85c7169a740b2edf0106ad59fdaa1b0160f823c (patch) | |
tree | 2b9fb7f64eacb322e95695e412c923e97ba33e88 /contrib/ntp/libopts/enumeration.c | |
parent | 1d197cfe9feac6bc29537d8e53c30b6435937b95 (diff) | |
parent | 7a6072eb585696f8856cd498c3fd194cf49f14c6 (diff) | |
download | FreeBSD-src-b85c7169a740b2edf0106ad59fdaa1b0160f823c.zip FreeBSD-src-b85c7169a740b2edf0106ad59fdaa1b0160f823c.tar.gz |
Merge ntpd & friends 4.2.4p5 from vendor/ntp/dist into head. Next commit
will update usr.sbin/ntp to match this.
MFC after: 2 weeks
Diffstat (limited to 'contrib/ntp/libopts/enumeration.c')
-rw-r--r-- | contrib/ntp/libopts/enumeration.c | 498 |
1 files changed, 498 insertions, 0 deletions
diff --git a/contrib/ntp/libopts/enumeration.c b/contrib/ntp/libopts/enumeration.c new file mode 100644 index 0000000..67dd4f4 --- /dev/null +++ b/contrib/ntp/libopts/enumeration.c @@ -0,0 +1,498 @@ + +/* + * $Id: enumeration.c,v 4.17 2007/02/04 17:44:12 bkorb Exp $ + * Time-stamp: "2007-01-13 10:22:35 bkorb" + * + * Automated Options Paged Usage module. + * + * This routine will run run-on options through a pager so the + * user may examine, print or edit them at their leisure. + */ + +/* + * Automated Options copyright 1992-2007 Bruce Korb + * + * Automated Options is free software. + * You may redistribute it and/or modify it under the terms of the + * GNU General Public License, as published by the Free Software + * Foundation; either version 2, or (at your option) any later version. + * + * Automated Options is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Automated Options. See the file "COPYING". If not, + * write to: The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * As a special exception, Bruce Korb gives permission for additional + * uses of the text contained in his release of AutoOpts. + * + * The exception is that, if you link the AutoOpts library with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the AutoOpts library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by Bruce Korb under + * the name AutoOpts. If you copy code from other sources under the + * General Public License into a copy of AutoOpts, as the General Public + * License permits, the exception does not apply to the code that you add + * in this way. To avoid misleading anyone as to the status of such + * modified files, you must delete this exception notice from them. + * + * If you write modifications of your own for AutoOpts, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +tSCC* pz_enum_err_fmt; + +/* = = = START-STATIC-FORWARD = = = */ +/* static forward declarations maintained by :mkfwd */ +static void +enumError( + tOptions* pOpts, + tOptDesc* pOD, + tCC* const * paz_names, + int name_ct ); + +static uintptr_t +findName( + tCC* pzName, + tOptions* pOpts, + tOptDesc* pOD, + tCC* const * paz_names, + unsigned int name_ct ); +/* = = = END-STATIC-FORWARD = = = */ + +static void +enumError( + tOptions* pOpts, + tOptDesc* pOD, + tCC* const * paz_names, + int name_ct ) +{ + size_t max_len = 0; + size_t ttl_len = 0; + + if (pOpts != NULL) + fprintf( option_usage_fp, pz_enum_err_fmt, pOpts->pzProgName, + pOD->optArg.argString, pOD->pz_Name ); + + fprintf( option_usage_fp, zValidKeys, pOD->pz_Name ); + + if (**paz_names == 0x7F) { + paz_names++; + name_ct--; + } + + /* + * Figure out the maximum length of any name, plus the total length + * of all the names. + */ + { + tCC * const * paz = paz_names; + int ct = name_ct; + + do { + size_t len = strlen( *(paz++) ) + 1; + if (len > max_len) + max_len = len; + ttl_len += len; + } while (--ct > 0); + } + + /* + * IF any one entry is about 1/2 line or longer, print one per line + */ + if (max_len > 35) { + do { + fprintf( option_usage_fp, " %s\n", *(paz_names++) ); + } while (--name_ct > 0); + } + + /* + * ELSE IF they all fit on one line, then do so. + */ + else if (ttl_len < 76) { + fputc( ' ', option_usage_fp ); + do { + fputc( ' ', option_usage_fp ); + fputs( *(paz_names++), option_usage_fp ); + } while (--name_ct > 0); + fputc( '\n', option_usage_fp ); + } + + /* + * Otherwise, columnize the output + */ + else { + int ent_no = 0; + char zFmt[16]; /* format for all-but-last entries on a line */ + + sprintf( zFmt, "%%-%ds", (int)max_len ); + max_len = 78 / max_len; /* max_len is now max entries on a line */ + fputs( " ", option_usage_fp ); + + /* + * Loop through all but the last entry + */ + while (--name_ct > 0) { + if (++ent_no == max_len) { + /* + * Last entry on a line. Start next line, too. + */ + fprintf( option_usage_fp, "%s\n ", *(paz_names++) ); + ent_no = 0; + } + + else + fprintf( option_usage_fp, zFmt, *(paz_names++) ); + } + fprintf( option_usage_fp, "%s\n", *paz_names ); + } + + /* + * IF we do not have a pOpts pointer, then this output is being requested + * by the usage procedure. Let's not re-invoke it recursively. + */ + if (pOpts != NULL) + (*(pOpts->pUsageProc))( pOpts, EXIT_FAILURE ); + if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) + fputs( zSetMemberSettings, option_usage_fp ); +} + + +static uintptr_t +findName( + tCC* pzName, + tOptions* pOpts, + tOptDesc* pOD, + tCC* const * paz_names, + unsigned int name_ct ) +{ + uintptr_t res = name_ct; + size_t len = strlen( (char*)pzName ); + uintptr_t idx; + /* + * Look for an exact match, but remember any partial matches. + * Multiple partial matches means we have an ambiguous match. + */ + for (idx = 0; idx < name_ct; idx++) { + if (strncmp( (char*)paz_names[idx], (char*)pzName, len) == 0) { + if (paz_names[idx][len] == NUL) + return idx; /* full match */ + + if (res != name_ct) { + pz_enum_err_fmt = zAmbigKey; + option_usage_fp = stderr; + enumError( pOpts, pOD, paz_names, (int)name_ct ); + } + res = idx; /* save partial match */ + } + } + + /* + * no partial match -> error + */ + if (res == name_ct) { + pz_enum_err_fmt = zNoKey; + option_usage_fp = stderr; + enumError( pOpts, pOD, paz_names, (int)name_ct ); + } + + /* + * Return the matching index as a char* pointer. + * The result gets stashed in a char* pointer, so it will have to fit. + */ + return res; +} + + +/*=export_func optionKeywordName + * what: Convert between enumeration values and strings + * private: + * + * arg: tOptDesc*, pOD, enumeration option description + * arg: unsigned int, enum_val, the enumeration value to map + * + * ret_type: char const* + * ret_desc: the enumeration name from const memory + * + * doc: This converts an enumeration value into the matching string. +=*/ +char const* +optionKeywordName( + tOptDesc* pOD, + unsigned int enum_val ) +{ + tOptDesc od; + + od.optArg.argEnum = enum_val; + (*(pOD->pOptProc))( (void*)(2UL), &od ); + return od.optArg.argString; +} + + +/*=export_func optionEnumerationVal + * what: Convert from a string to an enumeration value + * private: + * + * arg: tOptions*, pOpts, the program options descriptor + * arg: tOptDesc*, pOD, enumeration option description + * arg: char const * const *, paz_names, list of enumeration names + * arg: unsigned int, name_ct, number of names in list + * + * ret_type: uintptr_t + * ret_desc: the enumeration value + * + * doc: This converts the optArg.argString string from the option description + * into the index corresponding to an entry in the name list. + * This will match the generated enumeration value. + * Full matches are always accepted. Partial matches are accepted + * if there is only one partial match. +=*/ +uintptr_t +optionEnumerationVal( + tOptions* pOpts, + tOptDesc* pOD, + tCC * const * paz_names, + unsigned int name_ct ) +{ + uintptr_t res = 0UL; + + /* + * IF the program option descriptor pointer is invalid, + * then it is some sort of special request. + */ + switch ((uintptr_t)pOpts) { + case 0UL: + /* + * print the list of enumeration names. + */ + enumError( pOpts, pOD, paz_names, (int)name_ct ); + break; + + case 1UL: + { + unsigned int ix = pOD->optArg.argEnum; + /* + * print the name string. + */ + if (ix >= name_ct) + printf( "INVALID-%d", ix ); + else + fputs( paz_names[ ix ], stdout ); + + break; + } + + case 2UL: + { + tSCC zInval[] = "*INVALID*"; + unsigned int ix = pOD->optArg.argEnum; + /* + * Replace the enumeration value with the name string. + */ + if (ix >= name_ct) + return (uintptr_t)zInval; + + res = (uintptr_t)paz_names[ ix ]; + break; + } + + default: + res = findName( pOD->optArg.argString, pOpts, pOD, paz_names, name_ct ); + + if (pOD->fOptState & OPTST_ALLOC_ARG) { + AGFREE(pOD->optArg.argString); + pOD->fOptState &= ~OPTST_ALLOC_ARG; + pOD->optArg.argString = NULL; + } + } + + return res; +} + + +/*=export_func optionSetMembers + * what: Convert between bit flag values and strings + * private: + * + * arg: tOptions*, pOpts, the program options descriptor + * arg: tOptDesc*, pOD, enumeration option description + * arg: char const * const *, + * paz_names, list of enumeration names + * arg: unsigned int, name_ct, number of names in list + * + * doc: This converts the optArg.argString string from the option description + * into the index corresponding to an entry in the name list. + * This will match the generated enumeration value. + * Full matches are always accepted. Partial matches are accepted + * if there is only one partial match. +=*/ +void +optionSetMembers( + tOptions* pOpts, + tOptDesc* pOD, + tCC* const * paz_names, + unsigned int name_ct ) +{ + /* + * IF the program option descriptor pointer is invalid, + * then it is some sort of special request. + */ + switch ((uintptr_t)pOpts) { + case 0UL: + /* + * print the list of enumeration names. + */ + enumError( pOpts, pOD, paz_names, (int)name_ct ); + return; + + case 1UL: + { + /* + * print the name string. + */ + uintptr_t bits = (uintptr_t)pOD->optCookie; + uintptr_t res = 0; + size_t len = 0; + + while (bits != 0) { + if (bits & 1) { + if (len++ > 0) fputs( " | ", stdout ); + fputs( paz_names[ res ], stdout ); + } + if (++res >= name_ct) break; + bits >>= 1; + } + return; + } + + case 2UL: + { + char* pz; + uintptr_t bits = (uintptr_t)pOD->optCookie; + uintptr_t res = 0; + size_t len = 0; + + /* + * Replace the enumeration value with the name string. + * First, determine the needed length, then allocate and fill in. + */ + while (bits != 0) { + if (bits & 1) + len += strlen( paz_names[ res ]) + 8; + if (++res >= name_ct) break; + bits >>= 1; + } + + pOD->optArg.argString = pz = AGALOC( len, "enum name" ); + + /* + * Start by clearing all the bits. We want to turn off any defaults + * because we will be restoring to current state, not adding to + * the default set of bits. + */ + strcpy( pz, "none" ); + pz += 4; + bits = (uintptr_t)pOD->optCookie; + res = 0; + while (bits != 0) { + if (bits & 1) { + strcpy( pz, " + " ); + strcpy( pz+3, paz_names[ res ]); + pz += strlen( paz_names[ res ]) + 3; + } + if (++res >= name_ct) break; + bits >>= 1; + } + return; + } + + default: + break; + } + + { + tCC* pzArg = pOD->optArg.argString; + uintptr_t res; + if ((pzArg == NULL) || (*pzArg == NUL)) { + pOD->optCookie = (void*)0; + return; + } + + res = (uintptr_t)pOD->optCookie; + for (;;) { + tSCC zSpn[] = " ,|+\t\r\f\n"; + int iv, len; + + pzArg += strspn( pzArg, zSpn ); + iv = (*pzArg == '!'); + if (iv) + pzArg += strspn( pzArg+1, zSpn ) + 1; + + len = strcspn( pzArg, zSpn ); + if (len == 0) + break; + + if ((len == 3) && (strncmp(pzArg, zAll, (size_t)3) == 0)) { + if (iv) + res = 0; + else res = ~0UL; + } + else if ((len == 4) && (strncmp(pzArg, zNone, (size_t)4) == 0)) { + if (! iv) + res = 0; + } + else do { + char* pz; + uintptr_t bit = strtoul( pzArg, &pz, 0 ); + + if (pz != pzArg + len) { + char z[ AO_NAME_SIZE ]; + tCC* p; + if (*pz != NUL) { + if (len >= AO_NAME_LIMIT) + break; + strncpy( z, pzArg, (size_t)len ); + z[len] = NUL; + p = z; + } else { + p = pzArg; + } + + bit = 1UL << findName(p, pOpts, pOD, paz_names, name_ct); + } + if (iv) + res &= ~bit; + else res |= bit; + } while (0); + + if (pzArg[len] == NUL) + break; + pzArg += len + 1; + } + if (name_ct < (8 * sizeof( uintptr_t ))) { + res &= (1UL << name_ct) - 1UL; + } + + pOD->optCookie = (void*)res; + } +} + +/* + * Local Variables: + * mode: C + * c-file-style: "stroustrup" + * indent-tabs-mode: nil + * End: + * end of autoopts/enumeration.c */ |