turns printfs back on
[freebsd-src/fkvm-freebsd.git] / contrib / ntp / libopts / enumeration.c
blob67dd4f47e429e4c7df2149dcf35e8c90a5d19ff2
2 /*
3 * $Id: enumeration.c,v 4.17 2007/02/04 17:44:12 bkorb Exp $
4 * Time-stamp: "2007-01-13 10:22:35 bkorb"
6 * Automated Options Paged Usage module.
8 * This routine will run run-on options through a pager so the
9 * user may examine, print or edit them at their leisure.
13 * Automated Options copyright 1992-2007 Bruce Korb
15 * Automated Options is free software.
16 * You may redistribute it and/or modify it under the terms of the
17 * GNU General Public License, as published by the Free Software
18 * Foundation; either version 2, or (at your option) any later version.
20 * Automated Options is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with Automated Options. See the file "COPYING". If not,
27 * write to: The Free Software Foundation, Inc.,
28 * 51 Franklin Street, Fifth Floor,
29 * Boston, MA 02110-1301, USA.
31 * As a special exception, Bruce Korb gives permission for additional
32 * uses of the text contained in his release of AutoOpts.
34 * The exception is that, if you link the AutoOpts library with other
35 * files to produce an executable, this does not by itself cause the
36 * resulting executable to be covered by the GNU General Public License.
37 * Your use of that executable is in no way restricted on account of
38 * linking the AutoOpts library code into it.
40 * This exception does not however invalidate any other reasons why
41 * the executable file might be covered by the GNU General Public License.
43 * This exception applies only to the code released by Bruce Korb under
44 * the name AutoOpts. If you copy code from other sources under the
45 * General Public License into a copy of AutoOpts, as the General Public
46 * License permits, the exception does not apply to the code that you add
47 * in this way. To avoid misleading anyone as to the status of such
48 * modified files, you must delete this exception notice from them.
50 * If you write modifications of your own for AutoOpts, it is your choice
51 * whether to permit this exception to apply to your modifications.
52 * If you do not wish that, delete this exception notice.
55 tSCC* pz_enum_err_fmt;
57 /* = = = START-STATIC-FORWARD = = = */
58 /* static forward declarations maintained by :mkfwd */
59 static void
60 enumError(
61 tOptions* pOpts,
62 tOptDesc* pOD,
63 tCC* const * paz_names,
64 int name_ct );
66 static uintptr_t
67 findName(
68 tCC* pzName,
69 tOptions* pOpts,
70 tOptDesc* pOD,
71 tCC* const * paz_names,
72 unsigned int name_ct );
73 /* = = = END-STATIC-FORWARD = = = */
75 static void
76 enumError(
77 tOptions* pOpts,
78 tOptDesc* pOD,
79 tCC* const * paz_names,
80 int name_ct )
82 size_t max_len = 0;
83 size_t ttl_len = 0;
85 if (pOpts != NULL)
86 fprintf( option_usage_fp, pz_enum_err_fmt, pOpts->pzProgName,
87 pOD->optArg.argString, pOD->pz_Name );
89 fprintf( option_usage_fp, zValidKeys, pOD->pz_Name );
91 if (**paz_names == 0x7F) {
92 paz_names++;
93 name_ct--;
97 * Figure out the maximum length of any name, plus the total length
98 * of all the names.
101 tCC * const * paz = paz_names;
102 int ct = name_ct;
104 do {
105 size_t len = strlen( *(paz++) ) + 1;
106 if (len > max_len)
107 max_len = len;
108 ttl_len += len;
109 } while (--ct > 0);
113 * IF any one entry is about 1/2 line or longer, print one per line
115 if (max_len > 35) {
116 do {
117 fprintf( option_usage_fp, " %s\n", *(paz_names++) );
118 } while (--name_ct > 0);
122 * ELSE IF they all fit on one line, then do so.
124 else if (ttl_len < 76) {
125 fputc( ' ', option_usage_fp );
126 do {
127 fputc( ' ', option_usage_fp );
128 fputs( *(paz_names++), option_usage_fp );
129 } while (--name_ct > 0);
130 fputc( '\n', option_usage_fp );
134 * Otherwise, columnize the output
136 else {
137 int ent_no = 0;
138 char zFmt[16]; /* format for all-but-last entries on a line */
140 sprintf( zFmt, "%%-%ds", (int)max_len );
141 max_len = 78 / max_len; /* max_len is now max entries on a line */
142 fputs( " ", option_usage_fp );
145 * Loop through all but the last entry
147 while (--name_ct > 0) {
148 if (++ent_no == max_len) {
150 * Last entry on a line. Start next line, too.
152 fprintf( option_usage_fp, "%s\n ", *(paz_names++) );
153 ent_no = 0;
156 else
157 fprintf( option_usage_fp, zFmt, *(paz_names++) );
159 fprintf( option_usage_fp, "%s\n", *paz_names );
163 * IF we do not have a pOpts pointer, then this output is being requested
164 * by the usage procedure. Let's not re-invoke it recursively.
166 if (pOpts != NULL)
167 (*(pOpts->pUsageProc))( pOpts, EXIT_FAILURE );
168 if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP)
169 fputs( zSetMemberSettings, option_usage_fp );
173 static uintptr_t
174 findName(
175 tCC* pzName,
176 tOptions* pOpts,
177 tOptDesc* pOD,
178 tCC* const * paz_names,
179 unsigned int name_ct )
181 uintptr_t res = name_ct;
182 size_t len = strlen( (char*)pzName );
183 uintptr_t idx;
185 * Look for an exact match, but remember any partial matches.
186 * Multiple partial matches means we have an ambiguous match.
188 for (idx = 0; idx < name_ct; idx++) {
189 if (strncmp( (char*)paz_names[idx], (char*)pzName, len) == 0) {
190 if (paz_names[idx][len] == NUL)
191 return idx; /* full match */
193 if (res != name_ct) {
194 pz_enum_err_fmt = zAmbigKey;
195 option_usage_fp = stderr;
196 enumError( pOpts, pOD, paz_names, (int)name_ct );
198 res = idx; /* save partial match */
203 * no partial match -> error
205 if (res == name_ct) {
206 pz_enum_err_fmt = zNoKey;
207 option_usage_fp = stderr;
208 enumError( pOpts, pOD, paz_names, (int)name_ct );
212 * Return the matching index as a char* pointer.
213 * The result gets stashed in a char* pointer, so it will have to fit.
215 return res;
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))( (void*)(2UL), &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 0UL:
278 * print the list of enumeration names.
280 enumError( pOpts, pOD, paz_names, (int)name_ct );
281 break;
283 case 1UL:
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 2UL:
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 res = (uintptr_t)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 0UL:
355 * print the list of enumeration names.
357 enumError( pOpts, pOD, paz_names, (int)name_ct );
358 return;
360 case 1UL:
363 * print the name string.
365 uintptr_t bits = (uintptr_t)pOD->optCookie;
366 uintptr_t res = 0;
367 size_t len = 0;
369 while (bits != 0) {
370 if (bits & 1) {
371 if (len++ > 0) fputs( " | ", stdout );
372 fputs( paz_names[ res ], stdout );
374 if (++res >= name_ct) break;
375 bits >>= 1;
377 return;
380 case 2UL:
382 char* pz;
383 uintptr_t bits = (uintptr_t)pOD->optCookie;
384 uintptr_t res = 0;
385 size_t len = 0;
388 * Replace the enumeration value with the name string.
389 * First, determine the needed length, then allocate and fill in.
391 while (bits != 0) {
392 if (bits & 1)
393 len += strlen( paz_names[ res ]) + 8;
394 if (++res >= name_ct) break;
395 bits >>= 1;
398 pOD->optArg.argString = pz = AGALOC( len, "enum name" );
401 * Start by clearing all the bits. We want to turn off any defaults
402 * because we will be restoring to current state, not adding to
403 * the default set of bits.
405 strcpy( pz, "none" );
406 pz += 4;
407 bits = (uintptr_t)pOD->optCookie;
408 res = 0;
409 while (bits != 0) {
410 if (bits & 1) {
411 strcpy( pz, " + " );
412 strcpy( pz+3, paz_names[ res ]);
413 pz += strlen( paz_names[ res ]) + 3;
415 if (++res >= name_ct) break;
416 bits >>= 1;
418 return;
421 default:
422 break;
426 tCC* pzArg = pOD->optArg.argString;
427 uintptr_t res;
428 if ((pzArg == NULL) || (*pzArg == NUL)) {
429 pOD->optCookie = (void*)0;
430 return;
433 res = (uintptr_t)pOD->optCookie;
434 for (;;) {
435 tSCC zSpn[] = " ,|+\t\r\f\n";
436 int iv, len;
438 pzArg += strspn( pzArg, zSpn );
439 iv = (*pzArg == '!');
440 if (iv)
441 pzArg += strspn( pzArg+1, zSpn ) + 1;
443 len = strcspn( pzArg, zSpn );
444 if (len == 0)
445 break;
447 if ((len == 3) && (strncmp(pzArg, zAll, (size_t)3) == 0)) {
448 if (iv)
449 res = 0;
450 else res = ~0UL;
452 else if ((len == 4) && (strncmp(pzArg, zNone, (size_t)4) == 0)) {
453 if (! iv)
454 res = 0;
456 else do {
457 char* pz;
458 uintptr_t bit = strtoul( pzArg, &pz, 0 );
460 if (pz != pzArg + len) {
461 char z[ AO_NAME_SIZE ];
462 tCC* p;
463 if (*pz != NUL) {
464 if (len >= AO_NAME_LIMIT)
465 break;
466 strncpy( z, pzArg, (size_t)len );
467 z[len] = NUL;
468 p = z;
469 } else {
470 p = pzArg;
473 bit = 1UL << findName(p, pOpts, pOD, paz_names, name_ct);
475 if (iv)
476 res &= ~bit;
477 else res |= bit;
478 } while (0);
480 if (pzArg[len] == NUL)
481 break;
482 pzArg += len + 1;
484 if (name_ct < (8 * sizeof( uintptr_t ))) {
485 res &= (1UL << name_ct) - 1UL;
488 pOD->optCookie = (void*)res;
493 * Local Variables:
494 * mode: C
495 * c-file-style: "stroustrup"
496 * indent-tabs-mode: nil
497 * End:
498 * end of autoopts/enumeration.c */