Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / sntp / libopts / usage.c
blobd43314a40f0bc5557562bceac12ebcab0a00eec9
1 /* $NetBSD$ */
4 /*
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.
11 * Sort options:
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 */
70 static ag_bool
71 checkGNUUsage( tOptions* pOpts );
73 static void
74 printExtendedUsage(
75 tOptions* pOptions,
76 tOptDesc* pOD,
77 arg_types_t* pAT );
79 static void
80 printInitList(
81 tCC* const* papz,
82 ag_bool* pInitIntro,
83 tCC* pzRc,
84 tCC* pzPN );
86 static void
87 printOneUsage(
88 tOptions* pOptions,
89 tOptDesc* pOD,
90 arg_types_t* pAT );
92 static void
93 printOptionUsage(
94 tOptions* pOpts,
95 int ex_code,
96 tCC* pOptTitle );
98 static void
99 printProgramDetails( tOptions* pOptions );
101 static int
102 setGnuOptFmts( tOptions* pOpts, tCC** ppT );
104 static int
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.
113 static ag_bool
114 checkGNUUsage( tOptions* pOpts )
116 char* pz = getenv( "AUTOOPTS_USAGE" );
117 if (pz == NULL)
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) +
136 * doc:
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.
141 void
142 optionOnlyUsage(
143 tOptions* pOpts,
144 int ex_code )
146 tCC* pOptTitle = NULL;
149 * Determine which header and which option formatting strings to use
151 if (checkGNUUsage(pOpts)) {
152 (void)setGnuOptFmts( pOpts, &pOptTitle );
154 else {
155 (void)setStdOptFmts( pOpts, &pOptTitle );
158 printOptionUsage( pOpts, ex_code, pOptTitle );
162 /*=export_func optionUsage
163 * private:
165 * what: Print usage text
166 * arg: + tOptions* + pOptions + program options descriptor +
167 * arg: + int + exitCode + exit code for calling exit(3) +
169 * doc:
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".
178 void
179 optionUsage(
180 tOptions* pOptions,
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 );
209 else {
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.
216 * Otherwise, we do.
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
267 static void
268 printExtendedUsage(
269 tOptions* pOptions,
270 tOptDesc* pOD,
271 arg_types_t* pAT )
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 );
283 * DEPENDENCIES:
285 if (pOD->pOptMust != NULL) {
286 const int* pOptNo = pOD->pOptMust;
288 fputs( zReqThese, option_usage_fp );
289 for (;;) {
290 fprintf( option_usage_fp, zTabout, pOptions->pOptDesc[
291 *pOptNo ].pz_Name );
292 if (*++pOptNo == NO_EQUIVALENT)
293 break;
296 if (pOD->pOptCant != NULL)
297 fputs( zTabHypAnd, option_usage_fp );
301 * CONFLICTS:
303 if (pOD->pOptCant != NULL) {
304 const int* pOptNo = pOD->pOptCant;
306 fputs( zProhib, option_usage_fp );
307 for (;;) {
308 fprintf( option_usage_fp, zTabout, pOptions->pOptDesc[
309 *pOptNo ].pz_Name );
310 if (*++pOptNo == NO_EQUIVALENT)
311 break;
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 );
349 return;
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) {
374 case 1:
375 case 0:
376 switch (pOD->optMaxCt) {
377 case 0: fputs( zPreset, option_usage_fp ); break;
378 case NOLIMIT: fputs( zNoLim, option_usage_fp ); break;
379 case 1: 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;
385 break;
387 default:
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.
407 static void
408 printInitList(
409 tCC* const* papz,
410 ag_bool* pInitIntro,
411 tCC* pzRc,
412 tCC* pzPN )
414 char zPath[ AG_PATH_MAX+1 ];
416 if (papz == NULL)
417 return;
419 fputs( zPresetIntro, option_usage_fp );
420 *pInitIntro = AG_FALSE;
422 for (;;) {
423 char const* pzPath = *(papz++);
425 if (pzPath == NULL)
426 break;
428 if (optionMakePath(zPath, (int)sizeof( zPath ), pzPath, pzPN))
429 pzPath = zPath;
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 );
436 if (*pzRc != NUL) {
437 struct stat sb;
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.
458 static void
459 printOneUsage(
460 tOptions* pOptions,
461 tOptDesc* pOD,
462 arg_types_t* pAT )
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 );
477 } else {
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 );
485 char z[ 80 ];
486 tCC* pzArgType;
488 * Determine the argument type string first on its usage, then,
489 * when the option argument is required, base the type string on the
490 * argument type.
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;
519 return;
521 bogus_desc:
522 fprintf( stderr, zInvalOptDesc, pOD->pz_Name );
523 exit( EX_SOFTWARE );
528 * Print out the usage information for just the options.
530 static void
531 printOptionUsage(
532 tOptions* pOpts,
533 int ex_code,
534 tCC* pOptTitle )
536 int ct = pOpts->optCt;
537 int optNo = 0;
538 tOptDesc* pOD = pOpts->pOptDesc;
539 int docCt = 0;
541 do {
542 if ((pOD->fOptState & OPTST_OMITTED) != 0)
543 continue;
545 if ((pOD->fOptState & OPTST_DOCUMENT) != 0) {
546 if (ex_code == EXIT_SUCCESS) {
547 fprintf(option_usage_fp, argTypes.pzBrk, pOD->pzText,
548 pOptTitle);
549 docCt++;
552 continue;
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)
564 && (docCt > 0)
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 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
585 * PROGRAM DETAILS
587 static void
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) {
602 if (initIntro)
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.
613 if (displayEnum) {
614 int ct = pOptions->optCt;
615 int optNo = 0;
616 tOptDesc* pOD = pOptions->pOptDesc;
618 fputc( '\n', option_usage_fp );
619 fflush( option_usage_fp );
620 do {
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
647 * been printed.
649 * Set up the formatting for GNU-style output
651 static int
652 setGnuOptFmts( tOptions* pOpts, tCC** ppT )
654 int flen = 22;
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]";
678 flen = 8;
679 break;
682 return flen;
687 * Standard (AutoOpts normal) option line formatting
689 static int
690 setStdOptFmts( tOptions* pOpts, tCC** ppT )
692 int flen = 0;
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;
711 flen = 19;
712 break;
714 case OPTPROC_NO_REQ_OPT:
715 *ppT = zNoRq_NoShrtTtl;
716 argTypes.pzOptFmt = zNrmOptFmt;
717 flen = 19;
718 break;
720 case OPTPROC_SHORTOPT:
721 *ppT = zReq_ShrtTtl;
722 argTypes.pzOptFmt = zReqOptFmt;
723 flen = 24;
724 break;
726 case 0:
727 *ppT = zReq_NoShrtTtl;
728 argTypes.pzOptFmt = zReqOptFmt;
729 flen = 24;
732 return flen;
737 * Local Variables:
738 * mode: C
739 * c-file-style: "stroustrup"
740 * indent-tabs-mode: nil
741 * End:
742 * end of autoopts/usage.c */