Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / sntp / libopts / enumeration.c
blob913d723b9a4d44b1ee9008f030b85f1fe0c7b194
1 /* $NetBSD$ */
4 /*
5 * Id: enumeration.c,v 4.17 2007/02/04 17:44:12 bkorb Exp
6 * Time-stamp: "2007-01-13 10:22:35 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.
15 * Automated Options copyright 1992-2007 Bruce Korb
17 * Automated Options is free software.
18 * You may redistribute it and/or modify it under the terms of the
19 * GNU General Public License, as published by the Free Software
20 * Foundation; either version 2, or (at your option) any later version.
22 * Automated Options is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with Automated Options. See the file "COPYING". If not,
29 * write to: The Free Software Foundation, Inc.,
30 * 51 Franklin Street, Fifth Floor,
31 * Boston, MA 02110-1301, USA.
33 * As a special exception, Bruce Korb gives permission for additional
34 * uses of the text contained in his release of AutoOpts.
36 * The exception is that, if you link the AutoOpts library with other
37 * files to produce an executable, this does not by itself cause the
38 * resulting executable to be covered by the GNU General Public License.
39 * Your use of that executable is in no way restricted on account of
40 * linking the AutoOpts library code into it.
42 * This exception does not however invalidate any other reasons why
43 * the executable file might be covered by the GNU General Public License.
45 * This exception applies only to the code released by Bruce Korb under
46 * the name AutoOpts. If you copy code from other sources under the
47 * General Public License into a copy of AutoOpts, as the General Public
48 * License permits, the exception does not apply to the code that you add
49 * in this way. To avoid misleading anyone as to the status of such
50 * modified files, you must delete this exception notice from them.
52 * If you write modifications of your own for AutoOpts, it is your choice
53 * whether to permit this exception to apply to your modifications.
54 * If you do not wish that, delete this exception notice.
57 tSCC* pz_enum_err_fmt;
59 /* = = = START-STATIC-FORWARD = = = */
60 /* static forward declarations maintained by :mkfwd */
61 static void
62 enumError(
63 tOptions* pOpts,
64 tOptDesc* pOD,
65 tCC* const * paz_names,
66 int name_ct );
68 static uintptr_t
69 findName(
70 tCC* pzName,
71 tOptions* pOpts,
72 tOptDesc* pOD,
73 tCC* const * paz_names,
74 unsigned int name_ct );
75 /* = = = END-STATIC-FORWARD = = = */
77 static void
78 enumError(
79 tOptions* pOpts,
80 tOptDesc* pOD,
81 tCC* const * paz_names,
82 int name_ct )
84 size_t max_len = 0;
85 size_t ttl_len = 0;
87 if (pOpts != NULL)
88 fprintf( option_usage_fp, pz_enum_err_fmt, pOpts->pzProgName,
89 pOD->optArg.argString, pOD->pz_Name );
91 fprintf( option_usage_fp, zValidKeys, pOD->pz_Name );
93 if (**paz_names == 0x7F) {
94 paz_names++;
95 name_ct--;
99 * Figure out the maximum length of any name, plus the total length
100 * of all the names.
103 tCC * const * paz = paz_names;
104 int ct = name_ct;
106 do {
107 size_t len = strlen( *(paz++) ) + 1;
108 if (len > max_len)
109 max_len = len;
110 ttl_len += len;
111 } while (--ct > 0);
115 * IF any one entry is about 1/2 line or longer, print one per line
117 if (max_len > 35) {
118 do {
119 fprintf( option_usage_fp, " %s\n", *(paz_names++) );
120 } while (--name_ct > 0);
124 * ELSE IF they all fit on one line, then do so.
126 else if (ttl_len < 76) {
127 fputc( ' ', option_usage_fp );
128 do {
129 fputc( ' ', option_usage_fp );
130 fputs( *(paz_names++), option_usage_fp );
131 } while (--name_ct > 0);
132 fputc( '\n', option_usage_fp );
136 * Otherwise, columnize the output
138 else {
139 int ent_no = 0;
140 char zFmt[16]; /* format for all-but-last entries on a line */
142 sprintf( zFmt, "%%-%ds", (int)max_len );
143 max_len = 78 / max_len; /* max_len is now max entries on a line */
144 fputs( " ", option_usage_fp );
147 * Loop through all but the last entry
149 while (--name_ct > 0) {
150 if (++ent_no == max_len) {
152 * Last entry on a line. Start next line, too.
154 fprintf( option_usage_fp, "%s\n ", *(paz_names++) );
155 ent_no = 0;
158 else
159 fprintf( option_usage_fp, zFmt, *(paz_names++) );
161 fprintf( option_usage_fp, "%s\n", *paz_names );
165 * IF we do not have a pOpts pointer, then this output is being requested
166 * by the usage procedure. Let's not re-invoke it recursively.
168 if (pOpts != NULL)
169 (*(pOpts->pUsageProc))( pOpts, EXIT_FAILURE );
170 if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP)
171 fputs( zSetMemberSettings, option_usage_fp );
175 static uintptr_t
176 findName(
177 tCC* pzName,
178 tOptions* pOpts,
179 tOptDesc* pOD,
180 tCC* const * paz_names,
181 unsigned int name_ct )
183 uintptr_t res = name_ct;
184 size_t len = strlen( (char*)pzName );
185 uintptr_t idx;
187 * Look for an exact match, but remember any partial matches.
188 * Multiple partial matches means we have an ambiguous match.
190 for (idx = 0; idx < name_ct; idx++) {
191 if (strncmp( (char*)paz_names[idx], (char*)pzName, len) == 0) {
192 if (paz_names[idx][len] == NUL)
193 return idx; /* full match */
195 if (res != name_ct) {
196 pz_enum_err_fmt = zAmbigKey;
197 option_usage_fp = stderr;
198 enumError( pOpts, pOD, paz_names, (int)name_ct );
200 res = idx; /* save partial match */
205 * no partial match -> error
207 if (res == name_ct) {
208 pz_enum_err_fmt = zNoKey;
209 option_usage_fp = stderr;
210 enumError( pOpts, pOD, paz_names, (int)name_ct );
214 * Return the matching index as a char* pointer.
215 * The result gets stashed in a char* pointer, so it will have to fit.
217 return res;
221 /*=export_func optionKeywordName
222 * what: Convert between enumeration values and strings
223 * private:
225 * arg: tOptDesc*, pOD, enumeration option description
226 * arg: unsigned int, enum_val, the enumeration value to map
228 * ret_type: char const*
229 * ret_desc: the enumeration name from const memory
231 * doc: This converts an enumeration value into the matching string.
233 char const*
234 optionKeywordName(
235 tOptDesc* pOD,
236 unsigned int enum_val )
238 tOptDesc od;
240 od.optArg.argEnum = enum_val;
241 (*(pOD->pOptProc))( (void*)(2UL), &od );
242 return od.optArg.argString;
246 /*=export_func optionEnumerationVal
247 * what: Convert from a string to an enumeration value
248 * private:
250 * arg: tOptions*, pOpts, the program options descriptor
251 * arg: tOptDesc*, pOD, enumeration option description
252 * arg: char const * const *, paz_names, list of enumeration names
253 * arg: unsigned int, name_ct, number of names in list
255 * ret_type: uintptr_t
256 * ret_desc: the enumeration value
258 * doc: This converts the optArg.argString string from the option description
259 * into the index corresponding to an entry in the name list.
260 * This will match the generated enumeration value.
261 * Full matches are always accepted. Partial matches are accepted
262 * if there is only one partial match.
264 uintptr_t
265 optionEnumerationVal(
266 tOptions* pOpts,
267 tOptDesc* pOD,
268 tCC * const * paz_names,
269 unsigned int name_ct )
271 uintptr_t res = 0UL;
274 * IF the program option descriptor pointer is invalid,
275 * then it is some sort of special request.
277 switch ((uintptr_t)pOpts) {
278 case 0UL:
280 * print the list of enumeration names.
282 enumError( pOpts, pOD, paz_names, (int)name_ct );
283 break;
285 case 1UL:
287 unsigned int ix = pOD->optArg.argEnum;
289 * print the name string.
291 if (ix >= name_ct)
292 printf( "INVALID-%d", ix );
293 else
294 fputs( paz_names[ ix ], stdout );
296 break;
299 case 2UL:
301 tSCC zInval[] = "*INVALID*";
302 unsigned int ix = pOD->optArg.argEnum;
304 * Replace the enumeration value with the name string.
306 if (ix >= name_ct)
307 return (uintptr_t)zInval;
309 res = (uintptr_t)paz_names[ ix ];
310 break;
313 default:
314 res = findName( pOD->optArg.argString, pOpts, pOD, paz_names, name_ct );
316 if (pOD->fOptState & OPTST_ALLOC_ARG) {
317 AGFREE(pOD->optArg.argString);
318 pOD->fOptState &= ~OPTST_ALLOC_ARG;
319 pOD->optArg.argString = NULL;
323 return res;
327 /*=export_func optionSetMembers
328 * what: Convert between bit flag values and strings
329 * private:
331 * arg: tOptions*, pOpts, the program options descriptor
332 * arg: tOptDesc*, pOD, enumeration option description
333 * arg: char const * const *,
334 * paz_names, list of enumeration names
335 * arg: unsigned int, name_ct, number of names in list
337 * doc: This converts the optArg.argString string from the option description
338 * into the index corresponding to an entry in the name list.
339 * This will match the generated enumeration value.
340 * Full matches are always accepted. Partial matches are accepted
341 * if there is only one partial match.
343 void
344 optionSetMembers(
345 tOptions* pOpts,
346 tOptDesc* pOD,
347 tCC* const * paz_names,
348 unsigned int name_ct )
351 * IF the program option descriptor pointer is invalid,
352 * then it is some sort of special request.
354 switch ((uintptr_t)pOpts) {
355 case 0UL:
357 * print the list of enumeration names.
359 enumError( pOpts, pOD, paz_names, (int)name_ct );
360 return;
362 case 1UL:
365 * print the name string.
367 uintptr_t bits = (uintptr_t)pOD->optCookie;
368 uintptr_t res = 0;
369 size_t len = 0;
371 while (bits != 0) {
372 if (bits & 1) {
373 if (len++ > 0) fputs( " | ", stdout );
374 fputs( paz_names[ res ], stdout );
376 if (++res >= name_ct) break;
377 bits >>= 1;
379 return;
382 case 2UL:
384 char* pz;
385 uintptr_t bits = (uintptr_t)pOD->optCookie;
386 uintptr_t res = 0;
387 size_t len = 0;
390 * Replace the enumeration value with the name string.
391 * First, determine the needed length, then allocate and fill in.
393 while (bits != 0) {
394 if (bits & 1)
395 len += strlen( paz_names[ res ]) + 8;
396 if (++res >= name_ct) break;
397 bits >>= 1;
400 pOD->optArg.argString = pz = AGALOC( len, "enum name" );
403 * Start by clearing all the bits. We want to turn off any defaults
404 * because we will be restoring to current state, not adding to
405 * the default set of bits.
407 strcpy( pz, "none" );
408 pz += 4;
409 bits = (uintptr_t)pOD->optCookie;
410 res = 0;
411 while (bits != 0) {
412 if (bits & 1) {
413 strcpy( pz, " + " );
414 strcpy( pz+3, paz_names[ res ]);
415 pz += strlen( paz_names[ res ]) + 3;
417 if (++res >= name_ct) break;
418 bits >>= 1;
420 return;
423 default:
424 break;
428 tCC* pzArg = pOD->optArg.argString;
429 uintptr_t res;
430 if ((pzArg == NULL) || (*pzArg == NUL)) {
431 pOD->optCookie = (void*)0;
432 return;
435 res = (uintptr_t)pOD->optCookie;
436 for (;;) {
437 tSCC zSpn[] = " ,|+\t\r\f\n";
438 int iv, len;
440 pzArg += strspn( pzArg, zSpn );
441 iv = (*pzArg == '!');
442 if (iv)
443 pzArg += strspn( pzArg+1, zSpn ) + 1;
445 len = strcspn( pzArg, zSpn );
446 if (len == 0)
447 break;
449 if ((len == 3) && (strncmp(pzArg, zAll, (size_t)3) == 0)) {
450 if (iv)
451 res = 0;
452 else res = ~0UL;
454 else if ((len == 4) && (strncmp(pzArg, zNone, (size_t)4) == 0)) {
455 if (! iv)
456 res = 0;
458 else do {
459 char* pz;
460 uintptr_t bit = strtoul( pzArg, &pz, 0 );
462 if (pz != pzArg + len) {
463 char z[ AO_NAME_SIZE ];
464 tCC* p;
465 if (*pz != NUL) {
466 if (len >= AO_NAME_LIMIT)
467 break;
468 strncpy( z, pzArg, (size_t)len );
469 z[len] = NUL;
470 p = z;
471 } else {
472 p = pzArg;
475 bit = 1UL << findName(p, pOpts, pOD, paz_names, name_ct);
477 if (iv)
478 res &= ~bit;
479 else res |= bit;
480 } while (0);
482 if (pzArg[len] == NUL)
483 break;
484 pzArg += len + 1;
486 if (name_ct < (8 * sizeof( uintptr_t ))) {
487 res &= (1UL << name_ct) - 1UL;
490 pOD->optCookie = (void*)res;
495 * Local Variables:
496 * mode: C
497 * c-file-style: "stroustrup"
498 * indent-tabs-mode: nil
499 * End:
500 * end of autoopts/enumeration.c */