Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / ntp / dist / sntp / libopts / enumeration.c
bloba4ebb97a7e09dc4455405f3540f0c8354a2030ba
1 /* $NetBSD$ */
4 /*
5 * Id: 27595043d23170eb4bb8b9831fc54016944e00e8
6 * Time-stamp: "2008-07-27 12:28:01 bkorb"
8 * Automated Options Paged Usage module.
10 * This routine will run run-on options through a pager so the
11 * user may examine, print or edit them at their leisure.
13 * This file is part of AutoOpts, a companion to AutoGen.
14 * AutoOpts is free software.
15 * AutoOpts is copyright (c) 1992-2009 by Bruce Korb - all rights reserved
17 * AutoOpts is available under any one of two licenses. The license
18 * in use must be one of these two and the choice is under the control
19 * of the user of the license.
21 * The GNU Lesser General Public License, version 3 or later
22 * See the files "COPYING.lgplv3" and "COPYING.gplv3"
24 * The Modified Berkeley Software Distribution License
25 * See the file "COPYING.mbsd"
27 * These files have the following md5sums:
29 * 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
30 * 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
31 * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
34 tSCC* pz_enum_err_fmt;
36 /* = = = START-STATIC-FORWARD = = = */
37 /* static forward declarations maintained by mk-fwd */
38 static void
39 enumError(
40 tOptions* pOpts,
41 tOptDesc* pOD,
42 tCC* const * paz_names,
43 int name_ct );
45 static uintptr_t
46 findName(
47 tCC* pzName,
48 tOptions* pOpts,
49 tOptDesc* pOD,
50 tCC* const * paz_names,
51 unsigned int name_ct );
52 /* = = = END-STATIC-FORWARD = = = */
54 static void
55 enumError(
56 tOptions* pOpts,
57 tOptDesc* pOD,
58 tCC* const * paz_names,
59 int name_ct )
61 size_t max_len = 0;
62 size_t ttl_len = 0;
63 int ct_down = name_ct;
64 int hidden = 0;
67 * A real "pOpts" pointer means someone messed up. Give a real error.
69 if (pOpts > OPTPROC_EMIT_LIMIT)
70 fprintf(option_usage_fp, pz_enum_err_fmt, pOpts->pzProgName,
71 pOD->optArg.argString, pOD->pz_Name);
73 fprintf(option_usage_fp, zValidKeys, pOD->pz_Name);
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.
80 if (**paz_names == 0x7F) {
81 paz_names++;
82 hidden = 1;
83 ct_down = --name_ct;
87 * Figure out the maximum length of any name, plus the total length
88 * of all the names.
91 tCC * const * paz = paz_names;
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);
100 ct_down = name_ct;
104 * IF any one entry is about 1/2 line or longer, print one per line
106 if (max_len > 35) {
107 do {
108 fprintf( option_usage_fp, " %s\n", *(paz_names++) );
109 } while (--ct_down > 0);
113 * ELSE IF they all fit on one line, then do so.
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 );
125 * Otherwise, columnize the output
127 else {
128 int ent_no = 0;
129 char zFmt[16]; /* format for all-but-last entries on a line */
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 );
136 * Loop through all but the last entry
138 ct_down = name_ct;
139 while (--ct_down > 0) {
140 if (++ent_no == max_len) {
142 * Last entry on a line. Start next line, too.
144 fprintf( option_usage_fp, "%s\n ", *(paz_names++) );
145 ent_no = 0;
148 else
149 fprintf(option_usage_fp, zFmt, *(paz_names++) );
151 fprintf(option_usage_fp, "%s\n", *paz_names);
154 if (pOpts > OPTPROC_EMIT_LIMIT) {
155 fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden);
157 (*(pOpts->pUsageProc))( pOpts, EXIT_FAILURE );
158 /* NOTREACHED */
162 if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) {
163 fprintf(option_usage_fp, zLowerBits, name_ct);
164 fputs(zSetMemberSettings, option_usage_fp);
165 } else {
166 fprintf(option_usage_fp, zIntRange, hidden, name_ct - 1 + hidden);
171 static uintptr_t
172 findName(
173 tCC* pzName,
174 tOptions* pOpts,
175 tOptDesc* pOD,
176 tCC* const * paz_names,
177 unsigned int name_ct )
180 * Return the matching index as a pointer sized integer.
181 * The result gets stashed in a char* pointer.
183 uintptr_t res = name_ct;
184 size_t len = strlen( (char*)pzName );
185 uintptr_t idx;
187 if (IS_DEC_DIGIT_CHAR(*pzName)) {
188 char * pz = (char *)(void *)pzName;
189 unsigned long val = strtoul(pz, &pz, 0);
190 if ((*pz == NUL) && (val < name_ct))
191 return (uintptr_t)val;
192 enumError(pOpts, pOD, paz_names, (int)name_ct);
193 return name_ct;
197 * Look for an exact match, but remember any partial matches.
198 * Multiple partial matches means we have an ambiguous match.
200 for (idx = 0; idx < name_ct; idx++) {
201 if (strncmp( (char*)paz_names[idx], (char*)pzName, len) == 0) {
202 if (paz_names[idx][len] == NUL)
203 return idx; /* full match */
205 res = (res != name_ct) ? ~0 : idx; /* save partial match */
209 if (res < name_ct)
210 return res; /* partial match */
212 pz_enum_err_fmt = (res == name_ct) ? zNoKey : zAmbigKey;
213 option_usage_fp = stderr;
214 enumError(pOpts, pOD, paz_names, (int)name_ct);
215 return name_ct;
219 /*=export_func optionKeywordName
220 * what: Convert between enumeration values and strings
221 * private:
223 * arg: tOptDesc*, pOD, enumeration option description
224 * arg: unsigned int, enum_val, the enumeration value to map
226 * ret_type: char const*
227 * ret_desc: the enumeration name from const memory
229 * doc: This converts an enumeration value into the matching string.
231 char const*
232 optionKeywordName(
233 tOptDesc* pOD,
234 unsigned int enum_val )
236 tOptDesc od;
238 od.optArg.argEnum = enum_val;
239 (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, &od );
240 return od.optArg.argString;
244 /*=export_func optionEnumerationVal
245 * what: Convert from a string to an enumeration value
246 * private:
248 * arg: tOptions*, pOpts, the program options descriptor
249 * arg: tOptDesc*, pOD, enumeration option description
250 * arg: char const * const *, paz_names, list of enumeration names
251 * arg: unsigned int, name_ct, number of names in list
253 * ret_type: uintptr_t
254 * ret_desc: the enumeration value
256 * doc: This converts the optArg.argString string from the option description
257 * into the index corresponding to an entry in the name list.
258 * This will match the generated enumeration value.
259 * Full matches are always accepted. Partial matches are accepted
260 * if there is only one partial match.
262 uintptr_t
263 optionEnumerationVal(
264 tOptions* pOpts,
265 tOptDesc* pOD,
266 tCC * const * paz_names,
267 unsigned int name_ct )
269 uintptr_t res = 0UL;
272 * IF the program option descriptor pointer is invalid,
273 * then it is some sort of special request.
275 switch ((uintptr_t)pOpts) {
276 case (uintptr_t)OPTPROC_EMIT_USAGE:
278 * print the list of enumeration names.
280 enumError(pOpts, pOD, paz_names, (int)name_ct);
281 break;
283 case (uintptr_t)OPTPROC_EMIT_SHELL:
285 unsigned int ix = pOD->optArg.argEnum;
287 * print the name string.
289 if (ix >= name_ct)
290 printf( "INVALID-%d", ix );
291 else
292 fputs( paz_names[ ix ], stdout );
294 break;
297 case (uintptr_t)OPTPROC_RETURN_VALNAME:
299 tSCC zInval[] = "*INVALID*";
300 unsigned int ix = pOD->optArg.argEnum;
302 * Replace the enumeration value with the name string.
304 if (ix >= name_ct)
305 return (uintptr_t)zInval;
307 pOD->optArg.argString = paz_names[ix];
308 break;
311 default:
312 res = findName(pOD->optArg.argString, pOpts, pOD, paz_names, name_ct);
314 if (pOD->fOptState & OPTST_ALLOC_ARG) {
315 AGFREE(pOD->optArg.argString);
316 pOD->fOptState &= ~OPTST_ALLOC_ARG;
317 pOD->optArg.argString = NULL;
321 return res;
325 /*=export_func optionSetMembers
326 * what: Convert between bit flag values and strings
327 * private:
329 * arg: tOptions*, pOpts, the program options descriptor
330 * arg: tOptDesc*, pOD, enumeration option description
331 * arg: char const * const *,
332 * paz_names, list of enumeration names
333 * arg: unsigned int, name_ct, number of names in list
335 * doc: This converts the optArg.argString string from the option description
336 * into the index corresponding to an entry in the name list.
337 * This will match the generated enumeration value.
338 * Full matches are always accepted. Partial matches are accepted
339 * if there is only one partial match.
341 void
342 optionSetMembers(
343 tOptions* pOpts,
344 tOptDesc* pOD,
345 tCC* const * paz_names,
346 unsigned int name_ct )
349 * IF the program option descriptor pointer is invalid,
350 * then it is some sort of special request.
352 switch ((uintptr_t)pOpts) {
353 case (uintptr_t)OPTPROC_EMIT_USAGE:
355 * print the list of enumeration names.
357 enumError(OPTPROC_EMIT_USAGE, pOD, paz_names, (int)name_ct );
358 return;
360 case (uintptr_t)OPTPROC_EMIT_SHELL:
363 * print the name string.
365 int ix = 0;
366 uintptr_t bits = (uintptr_t)pOD->optCookie;
367 size_t len = 0;
369 bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1;
371 while (bits != 0) {
372 if (bits & 1) {
373 if (len++ > 0) fputs( " | ", stdout );
374 fputs(paz_names[ix], stdout);
376 if (++ix >= name_ct) break;
377 bits >>= 1;
379 return;
382 case (uintptr_t)OPTPROC_RETURN_VALNAME:
384 char* pz;
385 uintptr_t bits = (uintptr_t)pOD->optCookie;
386 int ix = 0;
387 size_t len = 5;
389 bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1;
392 * Replace the enumeration value with the name string.
393 * First, determine the needed length, then allocate and fill in.
395 while (bits != 0) {
396 if (bits & 1)
397 len += strlen( paz_names[ix]) + 8;
398 if (++ix >= name_ct) break;
399 bits >>= 1;
402 pOD->optArg.argString = pz = AGALOC(len, "enum name");
405 * Start by clearing all the bits. We want to turn off any defaults
406 * because we will be restoring to current state, not adding to
407 * the default set of bits.
409 strcpy( pz, "none" );
410 pz += 4;
411 bits = (uintptr_t)pOD->optCookie;
412 bits &= ((uintptr_t)1 << (uintptr_t)name_ct) - (uintptr_t)1;
413 ix = 0;
415 while (bits != 0) {
416 if (bits & 1) {
417 strcpy( pz, " + " );
418 strcpy( pz+3, paz_names[ix]);
419 pz += strlen( paz_names[ix]) + 3;
421 if (++ix >= name_ct) break;
422 bits >>= 1;
424 return;
427 default:
428 break;
431 if ((pOD->fOptState & OPTST_RESET) != 0)
432 return;
435 tCC* pzArg = pOD->optArg.argString;
436 uintptr_t res;
437 if ((pzArg == NULL) || (*pzArg == NUL)) {
438 pOD->optCookie = (void*)0;
439 return;
442 res = (uintptr_t)pOD->optCookie;
443 for (;;) {
444 tSCC zSpn[] = " ,|+\t\r\f\n";
445 int iv, len;
447 pzArg += strspn( pzArg, zSpn );
448 iv = (*pzArg == '!');
449 if (iv)
450 pzArg += strspn( pzArg+1, zSpn ) + 1;
452 len = strcspn( pzArg, zSpn );
453 if (len == 0)
454 break;
456 if ((len == 3) && (strncmp(pzArg, zAll, (size_t)3) == 0)) {
457 if (iv)
458 res = 0;
459 else res = ~0UL;
461 else if ((len == 4) && (strncmp(pzArg, zNone, (size_t)4) == 0)) {
462 if (! iv)
463 res = 0;
465 else do {
466 char* pz;
467 uintptr_t bit = strtoul( pzArg, &pz, 0 );
469 if (pz != pzArg + len) {
470 char z[ AO_NAME_SIZE ];
471 tCC* p;
472 int shift_ct;
474 if (*pz != NUL) {
475 if (len >= AO_NAME_LIMIT)
476 break;
477 strncpy( z, pzArg, (size_t)len );
478 z[len] = NUL;
479 p = z;
480 } else {
481 p = pzArg;
484 shift_ct = findName(p, pOpts, pOD, paz_names, name_ct);
485 if (shift_ct >= name_ct) {
486 pOD->optCookie = (void*)0;
487 return;
489 bit = 1UL << shift_ct;
491 if (iv)
492 res &= ~bit;
493 else res |= bit;
494 } while (0);
496 if (pzArg[len] == NUL)
497 break;
498 pzArg += len + 1;
500 if (name_ct < (8 * sizeof( uintptr_t ))) {
501 res &= (1UL << name_ct) - 1UL;
504 pOD->optCookie = (void*)res;
509 * Local Variables:
510 * mode: C
511 * c-file-style: "stroustrup"
512 * indent-tabs-mode: nil
513 * End:
514 * end of autoopts/enumeration.c */