5 * usage.c Id: usage.c,v 4.15 2007/04/28 22:19:23 bkorb Exp
6 * Time-stamp: "2007-04-15 11:02:46 bkorb"
8 * This module implements the default usage procedure for
9 * Automated Options. It may be overridden, of course.
12 --start=END-[S]TATIC-FORWARD --patt='^/\*($|[^:])' \
13 --out=xx.c key='^[a-zA-Z0-9_]+\(' --trail='^/\*:' \
14 --spac=2 --input=usage.c
18 * Automated Options copyright 1992-2007 Bruce Korb
20 * Automated Options is free software.
21 * You may redistribute it and/or modify it under the terms of the
22 * GNU General Public License, as published by the Free Software
23 * Foundation; either version 2, or (at your option) any later version.
25 * Automated Options is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with Automated Options. See the file "COPYING". If not,
32 * write to: The Free Software Foundation, Inc.,
33 * 51 Franklin Street, Fifth Floor,
34 * Boston, MA 02110-1301, USA.
36 * As a special exception, Bruce Korb gives permission for additional
37 * uses of the text contained in his release of AutoOpts.
39 * The exception is that, if you link the AutoOpts library with other
40 * files to produce an executable, this does not by itself cause the
41 * resulting executable to be covered by the GNU General Public License.
42 * Your use of that executable is in no way restricted on account of
43 * linking the AutoOpts library code into it.
45 * This exception does not however invalidate any other reasons why
46 * the executable file might be covered by the GNU General Public License.
48 * This exception applies only to the code released by Bruce Korb under
49 * the name AutoOpts. If you copy code from other sources under the
50 * General Public License into a copy of AutoOpts, as the General Public
51 * License permits, the exception does not apply to the code that you add
52 * in this way. To avoid misleading anyone as to the status of such
53 * modified files, you must delete this exception notice from them.
55 * If you write modifications of your own for AutoOpts, it is your choice
56 * whether to permit this exception to apply to your modifications.
57 * If you do not wish that, delete this exception notice.
60 #define OPTPROC_L_N_S (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)
62 static arg_types_t argTypes
;
64 FILE* option_usage_fp
= NULL
;
65 static char zOptFmtLine
[ 16 ];
66 static ag_bool displayEnum
;
68 /* = = = START-STATIC-FORWARD = = = */
69 /* static forward declarations maintained by :mkfwd */
71 checkGNUUsage( tOptions
* pOpts
);
99 printProgramDetails( tOptions
* pOptions
);
102 setGnuOptFmts( tOptions
* pOpts
, tCC
** ppT
);
105 setStdOptFmts( tOptions
* pOpts
, tCC
** ppT
);
106 /* = = = END-STATIC-FORWARD = = = */
110 * Figure out if we should try to format usage text sort-of like
111 * the way many GNU programs do.
114 checkGNUUsage( tOptions
* pOpts
)
116 char* pz
= getenv( "AUTOOPTS_USAGE" );
120 else if (streqvcmp( pz
, "gnu" ) == 0)
121 pOpts
->fOptSet
|= OPTPROC_GNUUSAGE
;
123 else if (streqvcmp( pz
, "autoopts" ) == 0)
124 pOpts
->fOptSet
&= ~OPTPROC_GNUUSAGE
;
126 return (pOpts
->fOptSet
& OPTPROC_GNUUSAGE
) ? AG_TRUE
: AG_FALSE
;
130 /*=export_func optionOnlyUsage
132 * what: Print usage text for just the options
133 * arg: + tOptions* + pOpts + program options descriptor +
134 * arg: + int + ex_code + exit code for calling exit(3) +
137 * This routine will print only the usage for each option.
138 * This function may be used when the emitted usage must incorporate
139 * information not available to AutoOpts.
146 tCC
* pOptTitle
= NULL
;
149 * Determine which header and which option formatting strings to use
151 if (checkGNUUsage(pOpts
)) {
152 (void)setGnuOptFmts( pOpts
, &pOptTitle
);
155 (void)setStdOptFmts( pOpts
, &pOptTitle
);
158 printOptionUsage( pOpts
, ex_code
, pOptTitle
);
162 /*=export_func optionUsage
165 * what: Print usage text
166 * arg: + tOptions* + pOptions + program options descriptor +
167 * arg: + int + exitCode + exit code for calling exit(3) +
170 * This routine will print usage in both GNU-standard and AutoOpts-expanded
171 * formats. The descriptor specifies the default, but AUTOOPTS_USAGE will
172 * over-ride this, providing the value of it is set to either "gnu" or
173 * "autoopts". This routine will @strong{not} return.
175 * If "exitCode" is "EX_USAGE" (normally 64), then output will to to stdout
176 * and the actual exit code will be "EXIT_SUCCESS".
181 int usage_exit_code
)
183 int actual_exit_code
=
184 (usage_exit_code
== EX_USAGE
) ? EXIT_SUCCESS
: usage_exit_code
;
186 displayEnum
= AG_FALSE
;
189 * Paged usage will preset option_usage_fp to an output file.
190 * If it hasn't already been set, then set it to standard output
191 * on successful exit (help was requested), otherwise error out.
193 if (option_usage_fp
== NULL
)
194 option_usage_fp
= (actual_exit_code
!= EXIT_SUCCESS
) ? stderr
: stdout
;
196 fprintf( option_usage_fp
, pOptions
->pzUsageTitle
, pOptions
->pzProgName
);
199 tCC
* pOptTitle
= NULL
;
202 * Determine which header and which option formatting strings to use
204 if (checkGNUUsage(pOptions
)) {
205 int flen
= setGnuOptFmts( pOptions
, &pOptTitle
);
206 sprintf( zOptFmtLine
, zFmtFmt
, flen
);
207 fputc( '\n', option_usage_fp
);
210 int flen
= setStdOptFmts( pOptions
, &pOptTitle
);
211 sprintf( zOptFmtLine
, zFmtFmt
, flen
);
214 * When we exit with EXIT_SUCCESS and the first option is a doc
215 * option, we do *NOT* want to emit the column headers.
218 if ( (usage_exit_code
!= EXIT_SUCCESS
)
219 || ((pOptions
->pOptDesc
->fOptState
& OPTST_DOCUMENT
) == 0) )
221 fputs( pOptTitle
, option_usage_fp
);
224 printOptionUsage( pOptions
, usage_exit_code
, pOptTitle
);
228 * Describe the mechanics of denoting the options
230 switch (pOptions
->fOptSet
& OPTPROC_L_N_S
) {
231 case OPTPROC_L_N_S
: fputs( zFlagOkay
, option_usage_fp
); break;
232 case OPTPROC_SHORTOPT
: break;
233 case OPTPROC_LONGOPT
: fputs( zNoFlags
, option_usage_fp
); break;
234 case 0: fputs( zOptsOnly
, option_usage_fp
); break;
237 if ((pOptions
->fOptSet
& OPTPROC_NUM_OPT
) != 0) {
238 fputs( zNumberOpt
, option_usage_fp
);
241 if ((pOptions
->fOptSet
& OPTPROC_REORDER
) != 0) {
242 fputs( zReorder
, option_usage_fp
);
245 if (pOptions
->pzExplain
!= NULL
)
246 fputs( pOptions
->pzExplain
, option_usage_fp
);
249 * IF the user is asking for help (thus exiting with SUCCESS),
250 * THEN see what additional information we can provide.
252 if (usage_exit_code
== EXIT_SUCCESS
)
253 printProgramDetails( pOptions
);
255 if (pOptions
->pzBugAddr
!= NULL
)
256 fprintf( option_usage_fp
, zPlsSendBugs
, pOptions
->pzBugAddr
);
257 fflush( option_usage_fp
);
259 exit( actual_exit_code
);
263 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
265 * PER OPTION TYPE USAGE INFORMATION
274 * IF there are option conflicts or dependencies,
275 * THEN print them here.
277 if ( (pOD
->pOptMust
!= NULL
)
278 || (pOD
->pOptCant
!= NULL
) ) {
280 fputs( zTabHyp
, option_usage_fp
);
285 if (pOD
->pOptMust
!= NULL
) {
286 const int* pOptNo
= pOD
->pOptMust
;
288 fputs( zReqThese
, option_usage_fp
);
290 fprintf( option_usage_fp
, zTabout
, pOptions
->pOptDesc
[
292 if (*++pOptNo
== NO_EQUIVALENT
)
296 if (pOD
->pOptCant
!= NULL
)
297 fputs( zTabHypAnd
, option_usage_fp
);
303 if (pOD
->pOptCant
!= NULL
) {
304 const int* pOptNo
= pOD
->pOptCant
;
306 fputs( zProhib
, option_usage_fp
);
308 fprintf( option_usage_fp
, zTabout
, pOptions
->pOptDesc
[
310 if (*++pOptNo
== NO_EQUIVALENT
)
317 * IF there is a disablement string
318 * THEN print the disablement info
320 if (pOD
->pz_DisableName
!= NULL
)
321 fprintf( option_usage_fp
, zDis
, pOD
->pz_DisableName
);
324 * IF the numeric option has a special callback,
325 * THEN call it, requesting the range or other special info
327 if ( (OPTST_GET_ARGTYPE(pOD
->fOptState
) == OPARG_TYPE_NUMERIC
)
328 && (pOD
->pOptProc
!= NULL
)
329 && (pOD
->pOptProc
!= optionNumericVal
) ) {
330 (*(pOD
->pOptProc
))( pOptions
, NULL
);
334 * IF the option defaults to being enabled,
335 * THEN print that out
337 if (pOD
->fOptState
& OPTST_INITENABLED
)
338 fputs( zEnab
, option_usage_fp
);
341 * IF the option is in an equivalence class
342 * AND not the designated lead
343 * THEN print equivalence and leave it at that.
345 if ( (pOD
->optEquivIndex
!= NO_EQUIVALENT
)
346 && (pOD
->optEquivIndex
!= pOD
->optActualIndex
) ) {
347 fprintf( option_usage_fp
, zAlt
,
348 pOptions
->pOptDesc
[ pOD
->optEquivIndex
].pz_Name
);
353 * IF this particular option can NOT be preset
354 * AND some form of presetting IS allowed,
355 * AND it is not an auto-managed option (e.g. --help, et al.)
356 * THEN advise that this option may not be preset.
358 if ( ((pOD
->fOptState
& OPTST_NO_INIT
) != 0)
359 && ( (pOptions
->papzHomeList
!= NULL
)
360 || (pOptions
->pzPROGNAME
!= NULL
)
362 && (pOD
->optIndex
< pOptions
->presetOptCt
)
365 fputs( zNoPreset
, option_usage_fp
);
368 * Print the appearance requirements.
370 if (OPTST_GET_ARGTYPE(pOD
->fOptState
) == OPARG_TYPE_MEMBERSHIP
)
371 fputs( zMembers
, option_usage_fp
);
373 else switch (pOD
->optMinCt
) {
376 switch (pOD
->optMaxCt
) {
377 case 0: fputs( zPreset
, option_usage_fp
); break;
378 case NOLIMIT
: fputs( zNoLim
, option_usage_fp
); break;
381 * IF the max is more than one but limited, print "UP TO" message
383 default: fprintf( option_usage_fp
, zUpTo
, pOD
->optMaxCt
); break;
389 * More than one is required. Print the range.
391 fprintf( option_usage_fp
, zMust
, pOD
->optMinCt
, pOD
->optMaxCt
);
394 if ( NAMED_OPTS( pOptions
)
395 && (pOptions
->specOptIdx
.default_opt
== pOD
->optIndex
))
396 fputs( zDefaultOpt
, option_usage_fp
);
400 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
402 * Figure out where all the initialization files might live.
403 * This requires translating some environment variables and
404 * testing to see if a name is a directory or a file. It's
405 * squishy, but important to tell users how to find these files.
414 char zPath
[ AG_PATH_MAX
+1 ];
419 fputs( zPresetIntro
, option_usage_fp
);
420 *pInitIntro
= AG_FALSE
;
423 char const* pzPath
= *(papz
++);
428 if (optionMakePath(zPath
, (int)sizeof( zPath
), pzPath
, pzPN
))
432 * Print the name of the "homerc" file. If the "rcfile" name is
433 * not empty, we may or may not print that, too...
435 fprintf( option_usage_fp
, zPathFmt
, pzPath
);
440 * IF the "homerc" file is a directory,
441 * then append the "rcfile" name.
443 if ( (stat( pzPath
, &sb
) == 0)
444 && S_ISDIR( sb
.st_mode
) ) {
445 fputc( DIRCH
, option_usage_fp
);
446 fputs( pzRc
, option_usage_fp
);
450 fputc( '\n', option_usage_fp
);
456 * Print the usage information for a single option.
465 * Flag prefix: IF no flags at all, then omit it. If not printable
466 * (not allowed for this option), then blank, else print it.
467 * Follow it with a comma if we are doing GNU usage and long
468 * opts are to be printed too.
470 if ((pOptions
->fOptSet
& OPTPROC_SHORTOPT
) == 0)
471 fputs( pAT
->pzSpc
, option_usage_fp
);
472 else if (! isgraph( pOD
->optValue
)) {
473 if ( (pOptions
->fOptSet
& (OPTPROC_GNUUSAGE
|OPTPROC_LONGOPT
))
474 == (OPTPROC_GNUUSAGE
|OPTPROC_LONGOPT
))
475 fputc( ' ', option_usage_fp
);
476 fputs( pAT
->pzNoF
, option_usage_fp
);
478 fprintf( option_usage_fp
, " -%c", pOD
->optValue
);
479 if ( (pOptions
->fOptSet
& (OPTPROC_GNUUSAGE
|OPTPROC_LONGOPT
))
480 == (OPTPROC_GNUUSAGE
|OPTPROC_LONGOPT
))
481 fputs( ", ", option_usage_fp
);
488 * Determine the argument type string first on its usage, then,
489 * when the option argument is required, base the type string on the
492 if (OPTST_GET_ARGTYPE(pOD
->fOptState
) == OPARG_TYPE_NONE
) {
493 pzArgType
= pAT
->pzNo
;
495 } else if (pOD
->fOptState
& OPTST_ARG_OPTIONAL
) {
496 pzArgType
= pAT
->pzOpt
;
498 } else switch (OPTST_GET_ARGTYPE(pOD
->fOptState
)) {
499 case OPARG_TYPE_ENUMERATION
: pzArgType
= pAT
->pzKey
; break;
500 case OPARG_TYPE_MEMBERSHIP
: pzArgType
= pAT
->pzKeyL
; break;
501 case OPARG_TYPE_BOOLEAN
: pzArgType
= pAT
->pzBool
; break;
502 case OPARG_TYPE_NUMERIC
: pzArgType
= pAT
->pzNum
; break;
503 case OPARG_TYPE_HIERARCHY
: pzArgType
= pAT
->pzNest
; break;
504 case OPARG_TYPE_STRING
: pzArgType
= pAT
->pzStr
; break;
505 default: goto bogus_desc
; break;
508 snprintf( z
, sizeof(z
), pAT
->pzOptFmt
, pzArgType
, pOD
->pz_Name
,
509 (pOD
->optMinCt
!= 0) ? pAT
->pzReq
: pAT
->pzOpt
);
511 fprintf( option_usage_fp
, zOptFmtLine
, z
, pOD
->pzText
);
513 switch (OPTST_GET_ARGTYPE(pOD
->fOptState
)) {
514 case OPARG_TYPE_ENUMERATION
:
515 case OPARG_TYPE_MEMBERSHIP
:
516 displayEnum
= (pOD
->pOptProc
!= NULL
) ? AG_TRUE
: displayEnum
;
522 fprintf( stderr
, zInvalOptDesc
, pOD
->pz_Name
);
528 * Print out the usage information for just the options.
536 int ct
= pOpts
->optCt
;
538 tOptDesc
* pOD
= pOpts
->pOptDesc
;
542 if ((pOD
->fOptState
& OPTST_OMITTED
) != 0)
545 if ((pOD
->fOptState
& OPTST_DOCUMENT
) != 0) {
546 if (ex_code
== EXIT_SUCCESS
) {
547 fprintf(option_usage_fp
, argTypes
.pzBrk
, pOD
->pzText
,
556 * IF this is the first auto-opt maintained option
557 * *AND* we are doing a full help
558 * *AND* there are documentation options
559 * *AND* the last one was not a doc option,
560 * THEN document that the remaining options are not user opts
562 if ( (pOpts
->presetOptCt
== optNo
)
563 && (ex_code
== EXIT_SUCCESS
)
565 && ((pOD
[-1].fOptState
& OPTST_DOCUMENT
) == 0) )
566 fprintf( option_usage_fp
, argTypes
.pzBrk
, zAuto
, pOptTitle
);
568 printOneUsage( pOpts
, pOD
, &argTypes
);
571 * IF we were invoked because of the --help option,
572 * THEN print all the extra info
574 if (ex_code
== EXIT_SUCCESS
)
575 printExtendedUsage( pOpts
, pOD
, &argTypes
);
577 } while (pOD
++, optNo
++, (--ct
> 0));
579 fputc( '\n', option_usage_fp
);
583 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
588 printProgramDetails( tOptions
* pOptions
)
590 ag_bool initIntro
= AG_TRUE
;
593 * Display all the places we look for config files
595 printInitList( pOptions
->papzHomeList
, &initIntro
,
596 pOptions
->pzRcName
, pOptions
->pzProgPath
);
599 * Let the user know about environment variable settings
601 if ((pOptions
->fOptSet
& OPTPROC_ENVIRON
) != 0) {
603 fputs( zPresetIntro
, option_usage_fp
);
605 fprintf( option_usage_fp
, zExamineFmt
, pOptions
->pzPROGNAME
);
609 * IF we found an enumeration,
610 * THEN hunt for it again. Call the handler proc with a NULL
611 * option struct pointer. That tells it to display the keywords.
614 int ct
= pOptions
->optCt
;
616 tOptDesc
* pOD
= pOptions
->pOptDesc
;
618 fputc( '\n', option_usage_fp
);
619 fflush( option_usage_fp
);
621 switch (OPTST_GET_ARGTYPE(pOD
->fOptState
)) {
622 case OPARG_TYPE_ENUMERATION
:
623 case OPARG_TYPE_MEMBERSHIP
:
624 (*(pOD
->pOptProc
))( NULL
, pOD
);
626 } while (pOD
++, optNo
++, (--ct
> 0));
630 * If there is a detail string, now is the time for that.
632 if (pOptions
->pzDetail
!= NULL
)
633 fputs( pOptions
->pzDetail
, option_usage_fp
);
637 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
639 * OPTION LINE FORMATTING SETUP
641 * The "OptFmt" formats receive three arguments:
642 * 1. the type of the option's argument
643 * 2. the long name of the option
644 * 3. "YES" or "no ", depending on whether or not the option must appear
645 * on the command line.
646 * These formats are used immediately after the option flag (if used) has
649 * Set up the formatting for GNU-style output
652 setGnuOptFmts( tOptions
* pOpts
, tCC
** ppT
)
655 *ppT
= zNoRq_ShrtTtl
;
657 argTypes
.pzStr
= zGnuStrArg
;
658 argTypes
.pzReq
= zOneSpace
;
659 argTypes
.pzNum
= zGnuNumArg
;
660 argTypes
.pzKey
= zGnuKeyArg
;
661 argTypes
.pzKeyL
= zGnuKeyLArg
;
662 argTypes
.pzBool
= zGnuBoolArg
;
663 argTypes
.pzNest
= zGnuNestArg
;
664 argTypes
.pzOpt
= zGnuOptArg
;
665 argTypes
.pzNo
= zOneSpace
;
666 argTypes
.pzBrk
= zGnuBreak
;
667 argTypes
.pzNoF
= zSixSpaces
;
668 argTypes
.pzSpc
= zThreeSpaces
;
670 switch (pOpts
->fOptSet
& OPTPROC_L_N_S
) {
671 case OPTPROC_L_N_S
: argTypes
.pzOptFmt
= zGnuOptFmt
; break;
672 case OPTPROC_LONGOPT
: argTypes
.pzOptFmt
= zGnuOptFmt
; break;
673 case 0: argTypes
.pzOptFmt
= zGnuOptFmt
+ 2; break;
674 case OPTPROC_SHORTOPT
:
675 argTypes
.pzOptFmt
= zShrtGnuOptFmt
;
676 zGnuStrArg
[0] = zGnuNumArg
[0] = zGnuKeyArg
[0] = zGnuBoolArg
[0] = ' ';
677 argTypes
.pzOpt
= " [arg]";
687 * Standard (AutoOpts normal) option line formatting
690 setStdOptFmts( tOptions
* pOpts
, tCC
** ppT
)
694 argTypes
.pzStr
= zStdStrArg
;
695 argTypes
.pzReq
= zStdReqArg
;
696 argTypes
.pzNum
= zStdNumArg
;
697 argTypes
.pzKey
= zStdKeyArg
;
698 argTypes
.pzKeyL
= zStdKeyLArg
;
699 argTypes
.pzBool
= zStdBoolArg
;
700 argTypes
.pzNest
= zStdNestArg
;
701 argTypes
.pzOpt
= zStdOptArg
;
702 argTypes
.pzNo
= zStdNoArg
;
703 argTypes
.pzBrk
= zStdBreak
;
704 argTypes
.pzNoF
= zFiveSpaces
;
705 argTypes
.pzSpc
= zTwoSpaces
;
707 switch (pOpts
->fOptSet
& (OPTPROC_NO_REQ_OPT
| OPTPROC_SHORTOPT
)) {
708 case (OPTPROC_NO_REQ_OPT
| OPTPROC_SHORTOPT
):
709 *ppT
= zNoRq_ShrtTtl
;
710 argTypes
.pzOptFmt
= zNrmOptFmt
;
714 case OPTPROC_NO_REQ_OPT
:
715 *ppT
= zNoRq_NoShrtTtl
;
716 argTypes
.pzOptFmt
= zNrmOptFmt
;
720 case OPTPROC_SHORTOPT
:
722 argTypes
.pzOptFmt
= zReqOptFmt
;
727 *ppT
= zReq_NoShrtTtl
;
728 argTypes
.pzOptFmt
= zReqOptFmt
;
739 * c-file-style: "stroustrup"
740 * indent-tabs-mode: nil
742 * end of autoopts/usage.c */