3 * usage.c $Id: usage.c,v 4.15 2007/04/28 22:19:23 bkorb Exp $
4 * Time-stamp: "2007-04-15 11:02:46 bkorb"
6 * This module implements the default usage procedure for
7 * Automated Options. It may be overridden, of course.
10 --start=END-[S]TATIC-FORWARD --patt='^/\*($|[^:])' \
11 --out=xx.c key='^[a-zA-Z0-9_]+\(' --trail='^/\*:' \
12 --spac=2 --input=usage.c
16 * Automated Options copyright 1992-2007 Bruce Korb
18 * Automated Options is free software.
19 * You may redistribute it and/or modify it under the terms of the
20 * GNU General Public License, as published by the Free Software
21 * Foundation; either version 2, or (at your option) any later version.
23 * Automated Options is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with Automated Options. See the file "COPYING". If not,
30 * write to: The Free Software Foundation, Inc.,
31 * 51 Franklin Street, Fifth Floor,
32 * Boston, MA 02110-1301, USA.
34 * As a special exception, Bruce Korb gives permission for additional
35 * uses of the text contained in his release of AutoOpts.
37 * The exception is that, if you link the AutoOpts library with other
38 * files to produce an executable, this does not by itself cause the
39 * resulting executable to be covered by the GNU General Public License.
40 * Your use of that executable is in no way restricted on account of
41 * linking the AutoOpts library code into it.
43 * This exception does not however invalidate any other reasons why
44 * the executable file might be covered by the GNU General Public License.
46 * This exception applies only to the code released by Bruce Korb under
47 * the name AutoOpts. If you copy code from other sources under the
48 * General Public License into a copy of AutoOpts, as the General Public
49 * License permits, the exception does not apply to the code that you add
50 * in this way. To avoid misleading anyone as to the status of such
51 * modified files, you must delete this exception notice from them.
53 * If you write modifications of your own for AutoOpts, it is your choice
54 * whether to permit this exception to apply to your modifications.
55 * If you do not wish that, delete this exception notice.
58 #define OPTPROC_L_N_S (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)
60 static arg_types_t argTypes;
62 FILE* option_usage_fp = NULL;
63 static char zOptFmtLine[ 16 ];
64 static ag_bool displayEnum;
66 /* = = = START-STATIC-FORWARD = = = */
67 /* static forward declarations maintained by :mkfwd */
69 checkGNUUsage( tOptions* pOpts );
97 printProgramDetails( tOptions* pOptions );
100 setGnuOptFmts( tOptions* pOpts, tCC** ppT );
103 setStdOptFmts( tOptions* pOpts, tCC** ppT );
104 /* = = = END-STATIC-FORWARD = = = */
108 * Figure out if we should try to format usage text sort-of like
109 * the way many GNU programs do.
112 checkGNUUsage( tOptions* pOpts )
114 char* pz = getenv( "AUTOOPTS_USAGE" );
118 else if (streqvcmp( pz, "gnu" ) == 0)
119 pOpts->fOptSet |= OPTPROC_GNUUSAGE;
121 else if (streqvcmp( pz, "autoopts" ) == 0)
122 pOpts->fOptSet &= ~OPTPROC_GNUUSAGE;
124 return (pOpts->fOptSet & OPTPROC_GNUUSAGE) ? AG_TRUE : AG_FALSE;
128 /*=export_func optionOnlyUsage
130 * what: Print usage text for just the options
131 * arg: + tOptions* + pOpts + program options descriptor +
132 * arg: + int + ex_code + exit code for calling exit(3) +
135 * This routine will print only the usage for each option.
136 * This function may be used when the emitted usage must incorporate
137 * information not available to AutoOpts.
144 tCC* pOptTitle = NULL;
147 * Determine which header and which option formatting strings to use
149 if (checkGNUUsage(pOpts)) {
150 (void)setGnuOptFmts( pOpts, &pOptTitle );
153 (void)setStdOptFmts( pOpts, &pOptTitle );
156 printOptionUsage( pOpts, ex_code, pOptTitle );
160 /*=export_func optionUsage
163 * what: Print usage text
164 * arg: + tOptions* + pOptions + program options descriptor +
165 * arg: + int + exitCode + exit code for calling exit(3) +
168 * This routine will print usage in both GNU-standard and AutoOpts-expanded
169 * formats. The descriptor specifies the default, but AUTOOPTS_USAGE will
170 * over-ride this, providing the value of it is set to either "gnu" or
171 * "autoopts". This routine will @strong{not} return.
173 * If "exitCode" is "EX_USAGE" (normally 64), then output will to to stdout
174 * and the actual exit code will be "EXIT_SUCCESS".
179 int usage_exit_code )
181 int actual_exit_code =
182 (usage_exit_code == EX_USAGE) ? EXIT_SUCCESS : usage_exit_code;
184 displayEnum = AG_FALSE;
187 * Paged usage will preset option_usage_fp to an output file.
188 * If it hasn't already been set, then set it to standard output
189 * on successful exit (help was requested), otherwise error out.
191 if (option_usage_fp == NULL)
192 option_usage_fp = (actual_exit_code != EXIT_SUCCESS) ? stderr : stdout;
194 fprintf( option_usage_fp, pOptions->pzUsageTitle, pOptions->pzProgName );
197 tCC* pOptTitle = NULL;
200 * Determine which header and which option formatting strings to use
202 if (checkGNUUsage(pOptions)) {
203 int flen = setGnuOptFmts( pOptions, &pOptTitle );
204 sprintf( zOptFmtLine, zFmtFmt, flen );
205 fputc( '\n', option_usage_fp );
208 int flen = setStdOptFmts( pOptions, &pOptTitle );
209 sprintf( zOptFmtLine, zFmtFmt, flen );
212 * When we exit with EXIT_SUCCESS and the first option is a doc
213 * option, we do *NOT* want to emit the column headers.
216 if ( (usage_exit_code != EXIT_SUCCESS)
217 || ((pOptions->pOptDesc->fOptState & OPTST_DOCUMENT) == 0) )
219 fputs( pOptTitle, option_usage_fp );
222 printOptionUsage( pOptions, usage_exit_code, pOptTitle );
226 * Describe the mechanics of denoting the options
228 switch (pOptions->fOptSet & OPTPROC_L_N_S) {
229 case OPTPROC_L_N_S: fputs( zFlagOkay, option_usage_fp ); break;
230 case OPTPROC_SHORTOPT: break;
231 case OPTPROC_LONGOPT: fputs( zNoFlags, option_usage_fp ); break;
232 case 0: fputs( zOptsOnly, option_usage_fp ); break;
235 if ((pOptions->fOptSet & OPTPROC_NUM_OPT) != 0) {
236 fputs( zNumberOpt, option_usage_fp );
239 if ((pOptions->fOptSet & OPTPROC_REORDER) != 0) {
240 fputs( zReorder, option_usage_fp );
243 if (pOptions->pzExplain != NULL)
244 fputs( pOptions->pzExplain, option_usage_fp );
247 * IF the user is asking for help (thus exiting with SUCCESS),
248 * THEN see what additional information we can provide.
250 if (usage_exit_code == EXIT_SUCCESS)
251 printProgramDetails( pOptions );
253 if (pOptions->pzBugAddr != NULL)
254 fprintf( option_usage_fp, zPlsSendBugs, pOptions->pzBugAddr );
255 fflush( option_usage_fp );
257 exit( actual_exit_code );
261 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
263 * PER OPTION TYPE USAGE INFORMATION
272 * IF there are option conflicts or dependencies,
273 * THEN print them here.
275 if ( (pOD->pOptMust != NULL)
276 || (pOD->pOptCant != NULL) ) {
278 fputs( zTabHyp, option_usage_fp );
283 if (pOD->pOptMust != NULL) {
284 const int* pOptNo = pOD->pOptMust;
286 fputs( zReqThese, option_usage_fp );
288 fprintf( option_usage_fp, zTabout, pOptions->pOptDesc[
290 if (*++pOptNo == NO_EQUIVALENT)
294 if (pOD->pOptCant != NULL)
295 fputs( zTabHypAnd, option_usage_fp );
301 if (pOD->pOptCant != NULL) {
302 const int* pOptNo = pOD->pOptCant;
304 fputs( zProhib, option_usage_fp );
306 fprintf( option_usage_fp, zTabout, pOptions->pOptDesc[
308 if (*++pOptNo == NO_EQUIVALENT)
315 * IF there is a disablement string
316 * THEN print the disablement info
318 if (pOD->pz_DisableName != NULL )
319 fprintf( option_usage_fp, zDis, pOD->pz_DisableName );
322 * IF the numeric option has a special callback,
323 * THEN call it, requesting the range or other special info
325 if ( (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NUMERIC)
326 && (pOD->pOptProc != NULL)
327 && (pOD->pOptProc != optionNumericVal) ) {
328 (*(pOD->pOptProc))( pOptions, NULL );
332 * IF the option defaults to being enabled,
333 * THEN print that out
335 if (pOD->fOptState & OPTST_INITENABLED)
336 fputs( zEnab, option_usage_fp );
339 * IF the option is in an equivalence class
340 * AND not the designated lead
341 * THEN print equivalence and leave it at that.
343 if ( (pOD->optEquivIndex != NO_EQUIVALENT)
344 && (pOD->optEquivIndex != pOD->optActualIndex ) ) {
345 fprintf( option_usage_fp, zAlt,
346 pOptions->pOptDesc[ pOD->optEquivIndex ].pz_Name );
351 * IF this particular option can NOT be preset
352 * AND some form of presetting IS allowed,
353 * AND it is not an auto-managed option (e.g. --help, et al.)
354 * THEN advise that this option may not be preset.
356 if ( ((pOD->fOptState & OPTST_NO_INIT) != 0)
357 && ( (pOptions->papzHomeList != NULL)
358 || (pOptions->pzPROGNAME != NULL)
360 && (pOD->optIndex < pOptions->presetOptCt)
363 fputs( zNoPreset, option_usage_fp );
366 * Print the appearance requirements.
368 if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP)
369 fputs( zMembers, option_usage_fp );
371 else switch (pOD->optMinCt) {
374 switch (pOD->optMaxCt) {
375 case 0: fputs( zPreset, option_usage_fp ); break;
376 case NOLIMIT: fputs( zNoLim, option_usage_fp ); break;
379 * IF the max is more than one but limited, print "UP TO" message
381 default: fprintf( option_usage_fp, zUpTo, pOD->optMaxCt ); break;
387 * More than one is required. Print the range.
389 fprintf( option_usage_fp, zMust, pOD->optMinCt, pOD->optMaxCt );
392 if ( NAMED_OPTS( pOptions )
393 && (pOptions->specOptIdx.default_opt == pOD->optIndex))
394 fputs( zDefaultOpt, option_usage_fp );
398 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
400 * Figure out where all the initialization files might live.
401 * This requires translating some environment variables and
402 * testing to see if a name is a directory or a file. It's
403 * squishy, but important to tell users how to find these files.
412 char zPath[ AG_PATH_MAX+1 ];
417 fputs( zPresetIntro, option_usage_fp );
418 *pInitIntro = AG_FALSE;
421 char const* pzPath = *(papz++);
426 if (optionMakePath(zPath, (int)sizeof( zPath ), pzPath, pzPN))
430 * Print the name of the "homerc" file. If the "rcfile" name is
431 * not empty, we may or may not print that, too...
433 fprintf( option_usage_fp, zPathFmt, pzPath );
438 * IF the "homerc" file is a directory,
439 * then append the "rcfile" name.
441 if ( (stat( pzPath, &sb ) == 0)
442 && S_ISDIR( sb.st_mode ) ) {
443 fputc( DIRCH, option_usage_fp );
444 fputs( pzRc, option_usage_fp );
448 fputc( '\n', option_usage_fp );
454 * Print the usage information for a single option.
463 * Flag prefix: IF no flags at all, then omit it. If not printable
464 * (not allowed for this option), then blank, else print it.
465 * Follow it with a comma if we are doing GNU usage and long
466 * opts are to be printed too.
468 if ((pOptions->fOptSet & OPTPROC_SHORTOPT) == 0)
469 fputs( pAT->pzSpc, option_usage_fp );
470 else if (! isgraph( pOD->optValue)) {
471 if ( (pOptions->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
472 == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
473 fputc( ' ', option_usage_fp );
474 fputs( pAT->pzNoF, option_usage_fp );
476 fprintf( option_usage_fp, " -%c", pOD->optValue );
477 if ( (pOptions->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
478 == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
479 fputs( ", ", option_usage_fp );
486 * Determine the argument type string first on its usage, then,
487 * when the option argument is required, base the type string on the
490 if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NONE) {
491 pzArgType = pAT->pzNo;
493 } else if (pOD->fOptState & OPTST_ARG_OPTIONAL) {
494 pzArgType = pAT->pzOpt;
496 } else switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
497 case OPARG_TYPE_ENUMERATION: pzArgType = pAT->pzKey; break;
498 case OPARG_TYPE_MEMBERSHIP: pzArgType = pAT->pzKeyL; break;
499 case OPARG_TYPE_BOOLEAN: pzArgType = pAT->pzBool; break;
500 case OPARG_TYPE_NUMERIC: pzArgType = pAT->pzNum; break;
501 case OPARG_TYPE_HIERARCHY: pzArgType = pAT->pzNest; break;
502 case OPARG_TYPE_STRING: pzArgType = pAT->pzStr; break;
503 default: goto bogus_desc; break;
506 snprintf( z, sizeof(z), pAT->pzOptFmt, pzArgType, pOD->pz_Name,
507 (pOD->optMinCt != 0) ? pAT->pzReq : pAT->pzOpt );
509 fprintf( option_usage_fp, zOptFmtLine, z, pOD->pzText );
511 switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
512 case OPARG_TYPE_ENUMERATION:
513 case OPARG_TYPE_MEMBERSHIP:
514 displayEnum = (pOD->pOptProc != NULL) ? AG_TRUE : displayEnum;
520 fprintf( stderr, zInvalOptDesc, pOD->pz_Name );
526 * Print out the usage information for just the options.
534 int ct = pOpts->optCt;
536 tOptDesc* pOD = pOpts->pOptDesc;
540 if ((pOD->fOptState & OPTST_OMITTED) != 0)
543 if ((pOD->fOptState & OPTST_DOCUMENT) != 0) {
544 if (ex_code == EXIT_SUCCESS) {
545 fprintf(option_usage_fp, argTypes.pzBrk, pOD->pzText,
554 * IF this is the first auto-opt maintained option
555 * *AND* we are doing a full help
556 * *AND* there are documentation options
557 * *AND* the last one was not a doc option,
558 * THEN document that the remaining options are not user opts
560 if ( (pOpts->presetOptCt == optNo)
561 && (ex_code == EXIT_SUCCESS)
563 && ((pOD[-1].fOptState & OPTST_DOCUMENT) == 0) )
564 fprintf( option_usage_fp, argTypes.pzBrk, zAuto, pOptTitle );
566 printOneUsage( pOpts, pOD, &argTypes );
569 * IF we were invoked because of the --help option,
570 * THEN print all the extra info
572 if (ex_code == EXIT_SUCCESS)
573 printExtendedUsage( pOpts, pOD, &argTypes );
575 } while (pOD++, optNo++, (--ct > 0));
577 fputc( '\n', option_usage_fp );
581 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
586 printProgramDetails( tOptions* pOptions )
588 ag_bool initIntro = AG_TRUE;
591 * Display all the places we look for config files
593 printInitList( pOptions->papzHomeList, &initIntro,
594 pOptions->pzRcName, pOptions->pzProgPath );
597 * Let the user know about environment variable settings
599 if ((pOptions->fOptSet & OPTPROC_ENVIRON) != 0) {
601 fputs( zPresetIntro, option_usage_fp );
603 fprintf( option_usage_fp, zExamineFmt, pOptions->pzPROGNAME );
607 * IF we found an enumeration,
608 * THEN hunt for it again. Call the handler proc with a NULL
609 * option struct pointer. That tells it to display the keywords.
612 int ct = pOptions->optCt;
614 tOptDesc* pOD = pOptions->pOptDesc;
616 fputc( '\n', option_usage_fp );
617 fflush( option_usage_fp );
619 switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
620 case OPARG_TYPE_ENUMERATION:
621 case OPARG_TYPE_MEMBERSHIP:
622 (*(pOD->pOptProc))( NULL, pOD );
624 } while (pOD++, optNo++, (--ct > 0));
628 * If there is a detail string, now is the time for that.
630 if (pOptions->pzDetail != NULL)
631 fputs( pOptions->pzDetail, option_usage_fp );
635 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
637 * OPTION LINE FORMATTING SETUP
639 * The "OptFmt" formats receive three arguments:
640 * 1. the type of the option's argument
641 * 2. the long name of the option
642 * 3. "YES" or "no ", depending on whether or not the option must appear
643 * on the command line.
644 * These formats are used immediately after the option flag (if used) has
647 * Set up the formatting for GNU-style output
650 setGnuOptFmts( tOptions* pOpts, tCC** ppT )
653 *ppT = zNoRq_ShrtTtl;
655 argTypes.pzStr = zGnuStrArg;
656 argTypes.pzReq = zOneSpace;
657 argTypes.pzNum = zGnuNumArg;
658 argTypes.pzKey = zGnuKeyArg;
659 argTypes.pzKeyL = zGnuKeyLArg;
660 argTypes.pzBool = zGnuBoolArg;
661 argTypes.pzNest = zGnuNestArg;
662 argTypes.pzOpt = zGnuOptArg;
663 argTypes.pzNo = zOneSpace;
664 argTypes.pzBrk = zGnuBreak;
665 argTypes.pzNoF = zSixSpaces;
666 argTypes.pzSpc = zThreeSpaces;
668 switch (pOpts->fOptSet & OPTPROC_L_N_S) {
669 case OPTPROC_L_N_S: argTypes.pzOptFmt = zGnuOptFmt; break;
670 case OPTPROC_LONGOPT: argTypes.pzOptFmt = zGnuOptFmt; break;
671 case 0: argTypes.pzOptFmt = zGnuOptFmt + 2; break;
672 case OPTPROC_SHORTOPT:
673 argTypes.pzOptFmt = zShrtGnuOptFmt;
674 zGnuStrArg[0] = zGnuNumArg[0] = zGnuKeyArg[0] = zGnuBoolArg[0] = ' ';
675 argTypes.pzOpt = " [arg]";
685 * Standard (AutoOpts normal) option line formatting
688 setStdOptFmts( tOptions* pOpts, tCC** ppT )
692 argTypes.pzStr = zStdStrArg;
693 argTypes.pzReq = zStdReqArg;
694 argTypes.pzNum = zStdNumArg;
695 argTypes.pzKey = zStdKeyArg;
696 argTypes.pzKeyL = zStdKeyLArg;
697 argTypes.pzBool = zStdBoolArg;
698 argTypes.pzNest = zStdNestArg;
699 argTypes.pzOpt = zStdOptArg;
700 argTypes.pzNo = zStdNoArg;
701 argTypes.pzBrk = zStdBreak;
702 argTypes.pzNoF = zFiveSpaces;
703 argTypes.pzSpc = zTwoSpaces;
705 switch (pOpts->fOptSet & (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT)) {
706 case (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT):
707 *ppT = zNoRq_ShrtTtl;
708 argTypes.pzOptFmt = zNrmOptFmt;
712 case OPTPROC_NO_REQ_OPT:
713 *ppT = zNoRq_NoShrtTtl;
714 argTypes.pzOptFmt = zNrmOptFmt;
718 case OPTPROC_SHORTOPT:
720 argTypes.pzOptFmt = zReqOptFmt;
725 *ppT = zReq_NoShrtTtl;
726 argTypes.pzOptFmt = zReqOptFmt;
737 * c-file-style: "stroustrup"
738 * indent-tabs-mode: nil
740 * end of autoopts/usage.c */