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 */
65 tCC
* const * paz_names
,
73 tCC
* const * paz_names
,
74 unsigned int name_ct
);
75 /* = = = END-STATIC-FORWARD = = = */
81 tCC
* const * paz_names
,
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) {
99 * Figure out the maximum length of any name, plus the total length
103 tCC
* const * paz
= paz_names
;
107 size_t len
= strlen( *(paz
++) ) + 1;
115 * IF any one entry is about 1/2 line or longer, print one per line
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
);
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
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
++) );
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.
169 (*(pOpts
->pUsageProc
))( pOpts
, EXIT_FAILURE
);
170 if (OPTST_GET_ARGTYPE(pOD
->fOptState
) == OPARG_TYPE_MEMBERSHIP
)
171 fputs( zSetMemberSettings
, option_usage_fp
);
180 tCC
* const * paz_names
,
181 unsigned int name_ct
)
183 uintptr_t res
= name_ct
;
184 size_t len
= strlen( (char*)pzName
);
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.
221 /*=export_func optionKeywordName
222 * what: Convert between enumeration values and strings
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.
236 unsigned int enum_val
)
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
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.
265 optionEnumerationVal(
268 tCC
* const * paz_names
,
269 unsigned int name_ct
)
274 * IF the program option descriptor pointer is invalid,
275 * then it is some sort of special request.
277 switch ((uintptr_t)pOpts
) {
280 * print the list of enumeration names.
282 enumError( pOpts
, pOD
, paz_names
, (int)name_ct
);
287 unsigned int ix
= pOD
->optArg
.argEnum
;
289 * print the name string.
292 printf( "INVALID-%d", ix
);
294 fputs( paz_names
[ ix
], stdout
);
301 tSCC zInval
[] = "*INVALID*";
302 unsigned int ix
= pOD
->optArg
.argEnum
;
304 * Replace the enumeration value with the name string.
307 return (uintptr_t)zInval
;
309 res
= (uintptr_t)paz_names
[ ix
];
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
;
327 /*=export_func optionSetMembers
328 * what: Convert between bit flag values and strings
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.
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
) {
357 * print the list of enumeration names.
359 enumError( pOpts
, pOD
, paz_names
, (int)name_ct
);
365 * print the name string.
367 uintptr_t bits
= (uintptr_t)pOD
->optCookie
;
373 if (len
++ > 0) fputs( " | ", stdout
);
374 fputs( paz_names
[ res
], stdout
);
376 if (++res
>= name_ct
) break;
385 uintptr_t bits
= (uintptr_t)pOD
->optCookie
;
390 * Replace the enumeration value with the name string.
391 * First, determine the needed length, then allocate and fill in.
395 len
+= strlen( paz_names
[ res
]) + 8;
396 if (++res
>= name_ct
) break;
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" );
409 bits
= (uintptr_t)pOD
->optCookie
;
414 strcpy( pz
+3, paz_names
[ res
]);
415 pz
+= strlen( paz_names
[ res
]) + 3;
417 if (++res
>= name_ct
) break;
428 tCC
* pzArg
= pOD
->optArg
.argString
;
430 if ((pzArg
== NULL
) || (*pzArg
== NUL
)) {
431 pOD
->optCookie
= (void*)0;
435 res
= (uintptr_t)pOD
->optCookie
;
437 tSCC zSpn
[] = " ,|+\t\r\f\n";
440 pzArg
+= strspn( pzArg
, zSpn
);
441 iv
= (*pzArg
== '!');
443 pzArg
+= strspn( pzArg
+1, zSpn
) + 1;
445 len
= strcspn( pzArg
, zSpn
);
449 if ((len
== 3) && (strncmp(pzArg
, zAll
, (size_t)3) == 0)) {
454 else if ((len
== 4) && (strncmp(pzArg
, zNone
, (size_t)4) == 0)) {
460 uintptr_t bit
= strtoul( pzArg
, &pz
, 0 );
462 if (pz
!= pzArg
+ len
) {
463 char z
[ AO_NAME_SIZE
];
466 if (len
>= AO_NAME_LIMIT
)
468 strncpy( z
, pzArg
, (size_t)len
);
475 bit
= 1UL << findName(p
, pOpts
, pOD
, paz_names
, name_ct
);
482 if (pzArg
[len
] == NUL
)
486 if (name_ct
< (8 * sizeof( uintptr_t ))) {
487 res
&= (1UL << name_ct
) - 1UL;
490 pOD
->optCookie
= (void*)res
;
497 * c-file-style: "stroustrup"
498 * indent-tabs-mode: nil
500 * end of autoopts/enumeration.c */