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 */
42 tCC
* const * paz_names
,
50 tCC
* const * paz_names
,
51 unsigned int name_ct
);
52 /* = = = END-STATIC-FORWARD = = = */
58 tCC
* const * paz_names
,
63 int ct_down
= name_ct
;
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) {
87 * Figure out the maximum length of any name, plus the total length
91 tCC
* const * paz
= paz_names
;
94 size_t len
= strlen( *(paz
++) ) + 1;
98 } while (--ct_down
> 0);
104 * IF any one entry is about 1/2 line or longer, print one per line
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
);
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
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
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
++) );
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
);
162 if (OPTST_GET_ARGTYPE(pOD
->fOptState
) == OPARG_TYPE_MEMBERSHIP
) {
163 fprintf(option_usage_fp
, zLowerBits
, name_ct
);
164 fputs(zSetMemberSettings
, option_usage_fp
);
166 fprintf(option_usage_fp
, zIntRange
, hidden
, name_ct
- 1 + hidden
);
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
);
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
);
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 */
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
);
219 /*=export_func optionKeywordName
220 * what: Convert between enumeration values and strings
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.
234 unsigned int enum_val
)
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
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.
263 optionEnumerationVal(
266 tCC
* const * paz_names
,
267 unsigned int name_ct
)
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
);
283 case (uintptr_t)OPTPROC_EMIT_SHELL
:
285 unsigned int ix
= pOD
->optArg
.argEnum
;
287 * print the name string.
290 printf( "INVALID-%d", ix
);
292 fputs( paz_names
[ ix
], stdout
);
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.
305 return (uintptr_t)zInval
;
307 pOD
->optArg
.argString
= paz_names
[ix
];
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
;
325 /*=export_func optionSetMembers
326 * what: Convert between bit flag values and strings
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.
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
);
360 case (uintptr_t)OPTPROC_EMIT_SHELL
:
363 * print the name string.
366 uintptr_t bits
= (uintptr_t)pOD
->optCookie
;
369 bits
&= ((uintptr_t)1 << (uintptr_t)name_ct
) - (uintptr_t)1;
373 if (len
++ > 0) fputs( " | ", stdout
);
374 fputs(paz_names
[ix
], stdout
);
376 if (++ix
>= name_ct
) break;
382 case (uintptr_t)OPTPROC_RETURN_VALNAME
:
385 uintptr_t bits
= (uintptr_t)pOD
->optCookie
;
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.
397 len
+= strlen( paz_names
[ix
]) + 8;
398 if (++ix
>= name_ct
) break;
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" );
411 bits
= (uintptr_t)pOD
->optCookie
;
412 bits
&= ((uintptr_t)1 << (uintptr_t)name_ct
) - (uintptr_t)1;
418 strcpy( pz
+3, paz_names
[ix
]);
419 pz
+= strlen( paz_names
[ix
]) + 3;
421 if (++ix
>= name_ct
) break;
431 if ((pOD
->fOptState
& OPTST_RESET
) != 0)
435 tCC
* pzArg
= pOD
->optArg
.argString
;
437 if ((pzArg
== NULL
) || (*pzArg
== NUL
)) {
438 pOD
->optCookie
= (void*)0;
442 res
= (uintptr_t)pOD
->optCookie
;
444 tSCC zSpn
[] = " ,|+\t\r\f\n";
447 pzArg
+= strspn( pzArg
, zSpn
);
448 iv
= (*pzArg
== '!');
450 pzArg
+= strspn( pzArg
+1, zSpn
) + 1;
452 len
= strcspn( pzArg
, zSpn
);
456 if ((len
== 3) && (strncmp(pzArg
, zAll
, (size_t)3) == 0)) {
461 else if ((len
== 4) && (strncmp(pzArg
, zNone
, (size_t)4) == 0)) {
467 uintptr_t bit
= strtoul( pzArg
, &pz
, 0 );
469 if (pz
!= pzArg
+ len
) {
470 char z
[ AO_NAME_SIZE
];
475 if (len
>= AO_NAME_LIMIT
)
477 strncpy( z
, pzArg
, (size_t)len
);
484 shift_ct
= findName(p
, pOpts
, pOD
, paz_names
, name_ct
);
485 if (shift_ct
>= name_ct
) {
486 pOD
->optCookie
= (void*)0;
489 bit
= 1UL << shift_ct
;
496 if (pzArg
[len
] == NUL
)
500 if (name_ct
< (8 * sizeof( uintptr_t ))) {
501 res
&= (1UL << name_ct
) - 1UL;
504 pOD
->optCookie
= (void*)res
;
511 * c-file-style: "stroustrup"
512 * indent-tabs-mode: nil
514 * end of autoopts/enumeration.c */