xref: /freebsd-src/contrib/ntp/sntp/libopts/usage.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
1ea906c41SOllivier Robert 
2ea906c41SOllivier Robert /*
32b15cb3dSCy Schubert  * \file usage.c
4ea906c41SOllivier Robert  *
5ea906c41SOllivier Robert  *  This module implements the default usage procedure for
6ea906c41SOllivier Robert  *  Automated Options.  It may be overridden, of course.
7ea906c41SOllivier Robert  *
82b15cb3dSCy Schubert  * @addtogroup autoopts
92b15cb3dSCy Schubert  * @{
102b15cb3dSCy Schubert  */
112b15cb3dSCy Schubert /*
12ea906c41SOllivier Robert  *  Sort options:
13ea906c41SOllivier Robert     --start=END-[S]TATIC-FORWARD --patt='^/\*($|[^:])' \
14ea906c41SOllivier Robert     --out=xx.c key='^[a-zA-Z0-9_]+\(' --trail='^/\*:' \
15ea906c41SOllivier Robert     --spac=2 --input=usage.c
16ea906c41SOllivier Robert  */
17ea906c41SOllivier Robert 
18ea906c41SOllivier Robert /*
192b15cb3dSCy Schubert  *  This file is part of AutoOpts, a companion to AutoGen.
202b15cb3dSCy Schubert  *  AutoOpts is free software.
21*a466cc55SCy Schubert  *  AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
22ea906c41SOllivier Robert  *
232b15cb3dSCy Schubert  *  AutoOpts is available under any one of two licenses.  The license
242b15cb3dSCy Schubert  *  in use must be one of these two and the choice is under the control
252b15cb3dSCy Schubert  *  of the user of the license.
26ea906c41SOllivier Robert  *
272b15cb3dSCy Schubert  *   The GNU Lesser General Public License, version 3 or later
282b15cb3dSCy Schubert  *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
29ea906c41SOllivier Robert  *
302b15cb3dSCy Schubert  *   The Modified Berkeley Software Distribution License
312b15cb3dSCy Schubert  *      See the file "COPYING.mbsd"
32ea906c41SOllivier Robert  *
332b15cb3dSCy Schubert  *  These files have the following sha256 sums:
34ea906c41SOllivier Robert  *
352b15cb3dSCy Schubert  *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
362b15cb3dSCy Schubert  *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
372b15cb3dSCy Schubert  *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
38ea906c41SOllivier Robert  */
39ea906c41SOllivier Robert 
40*a466cc55SCy Schubert #define GRAPH_CH(_ch) \
41*a466cc55SCy Schubert     ((((unsigned)_ch) <= 0x7E) && (((unsigned)_ch) > ' '))
42ea906c41SOllivier Robert 
432b15cb3dSCy Schubert /**
442b15cb3dSCy Schubert  * Parse the option usage flags string.  Any parsing problems yield
452b15cb3dSCy Schubert  * a zero (no flags set) result.  This function is internal to
462b15cb3dSCy Schubert  * set_usage_flags().
472b15cb3dSCy Schubert  *
482b15cb3dSCy Schubert  * @param[in] fnt   Flag Name Table - maps a name to a mask
492b15cb3dSCy Schubert  * @param[in] txt   the text to process.  If NULL, then
502b15cb3dSCy Schubert  *                  getenv("AUTOOPTS_USAGE") is used.
512b15cb3dSCy Schubert  * @returns a bit mask indicating which \a fnt entries were found.
522b15cb3dSCy Schubert  */
532b15cb3dSCy Schubert static unsigned int
parse_usage_flags(ao_flag_names_t const * fnt,char const * txt)542b15cb3dSCy Schubert parse_usage_flags(ao_flag_names_t const * fnt, char const * txt)
552b15cb3dSCy Schubert {
562b15cb3dSCy Schubert     unsigned int res = 0;
572b15cb3dSCy Schubert 
582b15cb3dSCy Schubert     /*
592b15cb3dSCy Schubert      * The text may be passed in.  If not, use the environment variable.
602b15cb3dSCy Schubert      */
612b15cb3dSCy Schubert     if (txt == NULL) {
622b15cb3dSCy Schubert         txt = getenv("AUTOOPTS_USAGE");
632b15cb3dSCy Schubert         if (txt == NULL)
642b15cb3dSCy Schubert             return 0;
652b15cb3dSCy Schubert     }
662b15cb3dSCy Schubert 
672b15cb3dSCy Schubert     txt = SPN_WHITESPACE_CHARS(txt);
682b15cb3dSCy Schubert     if (*txt == NUL)
692b15cb3dSCy Schubert         return 0;
702b15cb3dSCy Schubert 
712b15cb3dSCy Schubert     /*
722b15cb3dSCy Schubert      * search the string for table entries.  We must understand everything
732b15cb3dSCy Schubert      * we see in the string, or we give up on it.
742b15cb3dSCy Schubert      */
752b15cb3dSCy Schubert     for (;;) {
762b15cb3dSCy Schubert         int ix = 0;
772b15cb3dSCy Schubert 
782b15cb3dSCy Schubert         for (;;) {
792b15cb3dSCy Schubert             if (strneqvcmp(txt, fnt[ix].fnm_name, (int)fnt[ix].fnm_len) == 0)
802b15cb3dSCy Schubert                 break;
812b15cb3dSCy Schubert             if (++ix >= AOUF_COUNT)
822b15cb3dSCy Schubert                 return 0;
832b15cb3dSCy Schubert         }
842b15cb3dSCy Schubert 
852b15cb3dSCy Schubert         /*
862b15cb3dSCy Schubert          *  Make sure we have a full match.  Look for whitespace,
872b15cb3dSCy Schubert          *  a comma, or a NUL byte.
882b15cb3dSCy Schubert          */
892b15cb3dSCy Schubert         if (! IS_END_LIST_ENTRY_CHAR(txt[fnt[ix].fnm_len]))
902b15cb3dSCy Schubert             return 0;
912b15cb3dSCy Schubert 
922b15cb3dSCy Schubert         res |= 1U << ix;
932b15cb3dSCy Schubert         txt = SPN_WHITESPACE_CHARS(txt + fnt[ix].fnm_len);
942b15cb3dSCy Schubert 
952b15cb3dSCy Schubert         switch (*txt) {
962b15cb3dSCy Schubert         case NUL:
972b15cb3dSCy Schubert             return res;
982b15cb3dSCy Schubert 
992b15cb3dSCy Schubert         case ',':
1002b15cb3dSCy Schubert             txt = SPN_WHITESPACE_CHARS(txt + 1);
1012b15cb3dSCy Schubert             /* Something must follow the comma */
102*a466cc55SCy Schubert             /* FALLTHROUGH */
1032b15cb3dSCy Schubert 
1042b15cb3dSCy Schubert         default:
1052b15cb3dSCy Schubert             continue;
1062b15cb3dSCy Schubert         }
1072b15cb3dSCy Schubert     }
1082b15cb3dSCy Schubert }
1092b15cb3dSCy Schubert 
1102b15cb3dSCy Schubert /**
1112b15cb3dSCy Schubert  * Set option usage flags.  Any parsing problems yield no changes to options.
1122b15cb3dSCy Schubert  * Three different bits may be fiddled: \a OPTPROC_GNUUSAGE, \a OPTPROC_MISUSE
1132b15cb3dSCy Schubert  * and \a OPTPROC_COMPUTE.
1142b15cb3dSCy Schubert  *
1152b15cb3dSCy Schubert  * @param[in] flg_txt   text to parse.  If NULL, then the AUTOOPTS_USAGE
1162b15cb3dSCy Schubert  *                      environment variable is parsed.
1172b15cb3dSCy Schubert  * @param[in,out] opts  the program option descriptor
1182b15cb3dSCy Schubert  */
119*a466cc55SCy Schubert static void
set_usage_flags(tOptions * opts,char const * flg_txt)1202b15cb3dSCy Schubert set_usage_flags(tOptions * opts, char const * flg_txt)
1212b15cb3dSCy Schubert {
1222b15cb3dSCy Schubert #   define _aof_(_n, _f)   { sizeof(#_n)-1, _f, #_n },
1232b15cb3dSCy Schubert     static ao_flag_names_t const fn_table[AOUF_COUNT] = {
1242b15cb3dSCy Schubert         AOFLAG_TABLE
1252b15cb3dSCy Schubert     };
1262b15cb3dSCy Schubert #   undef  _aof_
1272b15cb3dSCy Schubert 
1282b15cb3dSCy Schubert     /*
1292b15cb3dSCy Schubert      * the flag word holds a bit for each selected table entry.
1302b15cb3dSCy Schubert      */
1312b15cb3dSCy Schubert     unsigned int flg = parse_usage_flags(fn_table, flg_txt);
1322b15cb3dSCy Schubert     if (flg == 0) return;
1332b15cb3dSCy Schubert 
1342b15cb3dSCy Schubert     /*
1352b15cb3dSCy Schubert      * Ensure we do not have conflicting selections
1362b15cb3dSCy Schubert      */
1372b15cb3dSCy Schubert     {
1382b15cb3dSCy Schubert         static unsigned int const form_mask =
1392b15cb3dSCy Schubert             AOUF_gnu | AOUF_autoopts;
1402b15cb3dSCy Schubert         static unsigned int const misuse_mask =
1412b15cb3dSCy Schubert             AOUF_no_misuse_usage | AOUF_misuse_usage;
1422b15cb3dSCy Schubert         if (  ((flg & form_mask)   == form_mask)
1432b15cb3dSCy Schubert            || ((flg & misuse_mask) == misuse_mask) )
1442b15cb3dSCy Schubert             return;
1452b15cb3dSCy Schubert     }
1462b15cb3dSCy Schubert 
1472b15cb3dSCy Schubert     /*
1482b15cb3dSCy Schubert      * Now fiddle the fOptSet bits, based on settings.
1492b15cb3dSCy Schubert      * The OPTPROC_LONGOPT bit is immutable, thus if it is set,
1502b15cb3dSCy Schubert      * then fnm points to a mask off mask.
1512b15cb3dSCy Schubert      */
1522b15cb3dSCy Schubert     {
1532b15cb3dSCy Schubert         ao_flag_names_t const * fnm = fn_table;
1542b15cb3dSCy Schubert         for (;;) {
1552b15cb3dSCy Schubert             if ((flg & 1) != 0) {
1562b15cb3dSCy Schubert                 if ((fnm->fnm_mask & OPTPROC_LONGOPT) != 0)
1572b15cb3dSCy Schubert                      opts->fOptSet &= fnm->fnm_mask;
1582b15cb3dSCy Schubert                 else opts->fOptSet |= fnm->fnm_mask;
1592b15cb3dSCy Schubert             }
1602b15cb3dSCy Schubert             flg >>= 1;
1612b15cb3dSCy Schubert             if (flg == 0)
1622b15cb3dSCy Schubert                 break;
1632b15cb3dSCy Schubert             fnm++;
1642b15cb3dSCy Schubert         }
1652b15cb3dSCy Schubert     }
1662b15cb3dSCy Schubert }
167ea906c41SOllivier Robert 
168ea906c41SOllivier Robert /*
169ea906c41SOllivier Robert  *  Figure out if we should try to format usage text sort-of like
170ea906c41SOllivier Robert  *  the way many GNU programs do.
171ea906c41SOllivier Robert  */
1722b15cb3dSCy Schubert static inline bool
do_gnu_usage(tOptions * pOpts)1732b15cb3dSCy Schubert do_gnu_usage(tOptions * pOpts)
174ea906c41SOllivier Robert {
1752b15cb3dSCy Schubert     return (pOpts->fOptSet & OPTPROC_GNUUSAGE) ? true : false;
1762b15cb3dSCy Schubert }
177ea906c41SOllivier Robert 
1782b15cb3dSCy Schubert /*
1792b15cb3dSCy Schubert  *  Figure out if we should try to format usage text sort-of like
1802b15cb3dSCy Schubert  *  the way many GNU programs do.
1812b15cb3dSCy Schubert  */
1822b15cb3dSCy Schubert static inline bool
skip_misuse_usage(tOptions * pOpts)1832b15cb3dSCy Schubert skip_misuse_usage(tOptions * pOpts)
1842b15cb3dSCy Schubert {
1852b15cb3dSCy Schubert     return (pOpts->fOptSet & OPTPROC_MISUSE) ? true : false;
186ea906c41SOllivier Robert }
187ea906c41SOllivier Robert 
188ea906c41SOllivier Robert 
189ea906c41SOllivier Robert /*=export_func  optionOnlyUsage
190ea906c41SOllivier Robert  *
191ea906c41SOllivier Robert  * what:  Print usage text for just the options
192ea906c41SOllivier Robert  * arg:   + tOptions *  + pOpts    + program options descriptor +
193ea906c41SOllivier Robert  * arg:   + int         + ex_code  + exit code for calling exit(3) +
194ea906c41SOllivier Robert  *
195ea906c41SOllivier Robert  * doc:
196ea906c41SOllivier Robert  *  This routine will print only the usage for each option.
197ea906c41SOllivier Robert  *  This function may be used when the emitted usage must incorporate
198ea906c41SOllivier Robert  *  information not available to AutoOpts.
199ea906c41SOllivier Robert =*/
200ea906c41SOllivier Robert void
optionOnlyUsage(tOptions * pOpts,int ex_code)2012b15cb3dSCy Schubert optionOnlyUsage(tOptions * pOpts, int ex_code)
202ea906c41SOllivier Robert {
2032b15cb3dSCy Schubert     char const * pOptTitle = NULL;
2042b15cb3dSCy Schubert 
2052b15cb3dSCy Schubert     set_usage_flags(pOpts, NULL);
2062b15cb3dSCy Schubert     if ((ex_code != EXIT_SUCCESS) &&
2072b15cb3dSCy Schubert         skip_misuse_usage(pOpts))
2082b15cb3dSCy Schubert         return;
209ea906c41SOllivier Robert 
210ea906c41SOllivier Robert     /*
211ea906c41SOllivier Robert      *  Determine which header and which option formatting strings to use
212ea906c41SOllivier Robert      */
2132b15cb3dSCy Schubert     if (do_gnu_usage(pOpts))
214ea906c41SOllivier Robert         (void)setGnuOptFmts(pOpts, &pOptTitle);
2152b15cb3dSCy Schubert     else
2162b15cb3dSCy Schubert         (void)setStdOptFmts(pOpts, &pOptTitle);
2172b15cb3dSCy Schubert 
2182b15cb3dSCy Schubert     prt_opt_usage(pOpts, ex_code, pOptTitle);
2192b15cb3dSCy Schubert 
2202b15cb3dSCy Schubert     fflush(option_usage_fp);
2212b15cb3dSCy Schubert     if (ferror(option_usage_fp) != 0)
2222b15cb3dSCy Schubert         fserr_exit(pOpts->pzProgName, zwriting, (option_usage_fp == stderr)
2232b15cb3dSCy Schubert                    ? zstderr_name : zstdout_name);
2242b15cb3dSCy Schubert }
2252b15cb3dSCy Schubert 
2262b15cb3dSCy Schubert /**
2272b15cb3dSCy Schubert  * Print a message suggesting how to get help.
2282b15cb3dSCy Schubert  *
2292b15cb3dSCy Schubert  * @param[in] opts      the program options
2302b15cb3dSCy Schubert  */
2312b15cb3dSCy Schubert static void
print_offer_usage(tOptions * opts)2322b15cb3dSCy Schubert print_offer_usage(tOptions * opts)
2332b15cb3dSCy Schubert {
2342b15cb3dSCy Schubert     char help[24];
2352b15cb3dSCy Schubert 
2362b15cb3dSCy Schubert     if (HAS_opt_usage_t(opts)) {
2372b15cb3dSCy Schubert         int ix = opts->presetOptCt;
2382b15cb3dSCy Schubert         tOptDesc * od = opts->pOptDesc + ix;
2392b15cb3dSCy Schubert         while (od->optUsage != AOUSE_HELP) {
2402b15cb3dSCy Schubert             if (++ix >= opts->optCt)
2412b15cb3dSCy Schubert                 ao_bug(zmissing_help_msg);
2422b15cb3dSCy Schubert             od++;
2432b15cb3dSCy Schubert         }
2442b15cb3dSCy Schubert         switch (opts->fOptSet & (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)) {
2452b15cb3dSCy Schubert         case OPTPROC_SHORTOPT:
2462b15cb3dSCy Schubert             help[0] = '-';
2472b15cb3dSCy Schubert             help[1] = od->optValue;
2482b15cb3dSCy Schubert             help[2] = NUL;
2492b15cb3dSCy Schubert             break;
2502b15cb3dSCy Schubert 
2512b15cb3dSCy Schubert         case OPTPROC_LONGOPT:
2522b15cb3dSCy Schubert         case (OPTPROC_LONGOPT | OPTPROC_SHORTOPT):
2532b15cb3dSCy Schubert             help[0] = help[1] = '-';
2542b15cb3dSCy Schubert             strncpy(help + 2, od->pz_Name, 20);
2552b15cb3dSCy Schubert             break;
2562b15cb3dSCy Schubert 
2572b15cb3dSCy Schubert         case 0:
2582b15cb3dSCy Schubert             strncpy(help, od->pz_Name, 20);
2592b15cb3dSCy Schubert             break;
2602b15cb3dSCy Schubert         }
2612b15cb3dSCy Schubert 
2622b15cb3dSCy Schubert     } else {
2632b15cb3dSCy Schubert         switch (opts->fOptSet & (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)) {
2642b15cb3dSCy Schubert         case OPTPROC_SHORTOPT:
2652b15cb3dSCy Schubert             strcpy(help, "-h");
2662b15cb3dSCy Schubert             break;
2672b15cb3dSCy Schubert 
2682b15cb3dSCy Schubert         case OPTPROC_LONGOPT:
2692b15cb3dSCy Schubert         case (OPTPROC_LONGOPT | OPTPROC_SHORTOPT):
2702b15cb3dSCy Schubert             strcpy(help, "--help");
2712b15cb3dSCy Schubert             break;
2722b15cb3dSCy Schubert 
2732b15cb3dSCy Schubert         case 0:
2742b15cb3dSCy Schubert             strcpy(help, "help");
2752b15cb3dSCy Schubert             break;
2762b15cb3dSCy Schubert         }
2772b15cb3dSCy Schubert     }
2782b15cb3dSCy Schubert 
2792b15cb3dSCy Schubert     fprintf(option_usage_fp, zoffer_usage_fmt, opts->pzProgName, help);
2802b15cb3dSCy Schubert }
2812b15cb3dSCy Schubert 
2822b15cb3dSCy Schubert /**
2832b15cb3dSCy Schubert  * Print information about each option.
2842b15cb3dSCy Schubert  *
2852b15cb3dSCy Schubert  * @param[in] opts      the program options
2862b15cb3dSCy Schubert  * @param[in] exit_code whether or not there was a usage error reported.
2872b15cb3dSCy Schubert  *                      used to select full usage versus abbreviated.
2882b15cb3dSCy Schubert  */
2892b15cb3dSCy Schubert static void
print_usage_details(tOptions * opts,int exit_code)2902b15cb3dSCy Schubert print_usage_details(tOptions * opts, int exit_code)
2912b15cb3dSCy Schubert {
2922b15cb3dSCy Schubert     {
2932b15cb3dSCy Schubert         char const * pOptTitle = NULL;
2942b15cb3dSCy Schubert         int flen;
2952b15cb3dSCy Schubert 
2962b15cb3dSCy Schubert         /*
2972b15cb3dSCy Schubert          *  Determine which header and which option formatting strings to use
2982b15cb3dSCy Schubert          */
2992b15cb3dSCy Schubert         if (do_gnu_usage(opts)) {
3002b15cb3dSCy Schubert             flen = setGnuOptFmts(opts, &pOptTitle);
3012b15cb3dSCy Schubert             sprintf(line_fmt_buf, zFmtFmt, flen);
3022b15cb3dSCy Schubert             fputc(NL, option_usage_fp);
303*a466cc55SCy Schubert 
304*a466cc55SCy Schubert         } else {
3052b15cb3dSCy Schubert             flen = setStdOptFmts(opts, &pOptTitle);
3062b15cb3dSCy Schubert             sprintf(line_fmt_buf, zFmtFmt, flen);
3072b15cb3dSCy Schubert 
3082b15cb3dSCy Schubert             /*
3092b15cb3dSCy Schubert              *  When we exit with EXIT_SUCCESS and the first option is a doc
3102b15cb3dSCy Schubert              *  option, we do *NOT* want to emit the column headers.
3112b15cb3dSCy Schubert              *  Otherwise, we do.
3122b15cb3dSCy Schubert              */
3132b15cb3dSCy Schubert             if (  (exit_code != EXIT_SUCCESS)
3142b15cb3dSCy Schubert                || ((opts->pOptDesc->fOptState & OPTST_DOCUMENT) == 0) )
3152b15cb3dSCy Schubert 
3162b15cb3dSCy Schubert                 fputs(pOptTitle, option_usage_fp);
317ea906c41SOllivier Robert         }
318ea906c41SOllivier Robert 
3192b15cb3dSCy Schubert         flen = 4 - ((flen + 15) / 8);
3202b15cb3dSCy Schubert         if (flen > 0)
3212b15cb3dSCy Schubert             tab_skip_ct = flen;
3222b15cb3dSCy Schubert         prt_opt_usage(opts, exit_code, pOptTitle);
323ea906c41SOllivier Robert     }
324ea906c41SOllivier Robert 
3252b15cb3dSCy Schubert     /*
3262b15cb3dSCy Schubert      *  Describe the mechanics of denoting the options
3272b15cb3dSCy Schubert      */
3282b15cb3dSCy Schubert     switch (opts->fOptSet & OPTPROC_L_N_S) {
3292b15cb3dSCy Schubert     case OPTPROC_L_N_S:     fputs(zFlagOkay, option_usage_fp); break;
3302b15cb3dSCy Schubert     case OPTPROC_SHORTOPT:  break;
3312b15cb3dSCy Schubert     case OPTPROC_LONGOPT:   fputs(zNoFlags,  option_usage_fp); break;
3322b15cb3dSCy Schubert     case 0:                 fputs(zOptsOnly, option_usage_fp); break;
3332b15cb3dSCy Schubert     }
3342b15cb3dSCy Schubert 
3352b15cb3dSCy Schubert     if ((opts->fOptSet & OPTPROC_NUM_OPT) != 0)
3362b15cb3dSCy Schubert         fputs(zNumberOpt, option_usage_fp);
3372b15cb3dSCy Schubert 
3382b15cb3dSCy Schubert     if ((opts->fOptSet & OPTPROC_REORDER) != 0)
3392b15cb3dSCy Schubert         fputs(zReorder, option_usage_fp);
3402b15cb3dSCy Schubert 
3412b15cb3dSCy Schubert     if (opts->pzExplain != NULL)
3422b15cb3dSCy Schubert         fputs(opts->pzExplain, option_usage_fp);
3432b15cb3dSCy Schubert 
3442b15cb3dSCy Schubert     /*
3452b15cb3dSCy Schubert      *  IF the user is asking for help (thus exiting with SUCCESS),
3462b15cb3dSCy Schubert      *  THEN see what additional information we can provide.
3472b15cb3dSCy Schubert      */
3482b15cb3dSCy Schubert     if (exit_code == EXIT_SUCCESS)
3492b15cb3dSCy Schubert         prt_prog_detail(opts);
3502b15cb3dSCy Schubert 
3512b15cb3dSCy Schubert     /*
3522b15cb3dSCy Schubert      * Give bug notification preference to the packager information
3532b15cb3dSCy Schubert      */
3542b15cb3dSCy Schubert     if (HAS_pzPkgDataDir(opts) && (opts->pzPackager != NULL))
3552b15cb3dSCy Schubert         fputs(opts->pzPackager, option_usage_fp);
3562b15cb3dSCy Schubert 
3572b15cb3dSCy Schubert     else if (opts->pzBugAddr != NULL)
3582b15cb3dSCy Schubert         fprintf(option_usage_fp, zPlsSendBugs, opts->pzBugAddr);
3592b15cb3dSCy Schubert 
3602b15cb3dSCy Schubert     fflush(option_usage_fp);
3612b15cb3dSCy Schubert 
3622b15cb3dSCy Schubert     if (ferror(option_usage_fp) != 0)
3632b15cb3dSCy Schubert         fserr_exit(opts->pzProgName, zwriting, (option_usage_fp == stderr)
3642b15cb3dSCy Schubert                    ? zstderr_name : zstdout_name);
3652b15cb3dSCy Schubert }
3662b15cb3dSCy Schubert 
3672b15cb3dSCy Schubert static void
print_one_paragraph(char const * text,bool plain,FILE * fp)3682b15cb3dSCy Schubert print_one_paragraph(char const * text, bool plain, FILE * fp)
3692b15cb3dSCy Schubert {
3702b15cb3dSCy Schubert     if (plain) {
3712b15cb3dSCy Schubert #ifdef ENABLE_NLS
3722b15cb3dSCy Schubert #ifdef HAVE_LIBINTL_H
3732b15cb3dSCy Schubert #ifdef DEBUG_ENABLED
3742b15cb3dSCy Schubert #undef gettext
3752b15cb3dSCy Schubert #endif
3762b15cb3dSCy Schubert         char * buf = dgettext("libopts", text);
3772b15cb3dSCy Schubert         if (buf == text)
3782b15cb3dSCy Schubert             text = gettext(text);
3792b15cb3dSCy Schubert #endif /* HAVE_LIBINTL_H */
3802b15cb3dSCy Schubert #endif /* ENABLE_NLS */
3812b15cb3dSCy Schubert         fputs(text, fp);
3822b15cb3dSCy Schubert     }
3832b15cb3dSCy Schubert 
3842b15cb3dSCy Schubert     else {
3852b15cb3dSCy Schubert         char const * t = optionQuoteString(text, LINE_SPLICE);
3862b15cb3dSCy Schubert         fprintf(fp, PUTS_FMT, t);
3872b15cb3dSCy Schubert         AGFREE(t);
3882b15cb3dSCy Schubert     }
3892b15cb3dSCy Schubert }
3902b15cb3dSCy Schubert 
3912b15cb3dSCy Schubert /*=export_func  optionPrintParagraphs
3922b15cb3dSCy Schubert  * private:
3932b15cb3dSCy Schubert  *
3942b15cb3dSCy Schubert  * what:  Print a paragraph of usage text
3952b15cb3dSCy Schubert  * arg:   + char const * + text  + a block of text that has bee i18n-ed +
3962b15cb3dSCy Schubert  * arg:   + bool         + plain + false -> wrap text in fputs()        +
3972b15cb3dSCy Schubert  * arg:   + FILE *       + fp    + the stream file pointer for output   +
3982b15cb3dSCy Schubert  *
3992b15cb3dSCy Schubert  * doc:
4002b15cb3dSCy Schubert  *  This procedure is called in two contexts: when a full or short usage text
4012b15cb3dSCy Schubert  *  has been provided for display, and when autogen is assembling a list of
4022b15cb3dSCy Schubert  *  translatable texts in the optmain.tlib template.  In the former case, \a
4032b15cb3dSCy Schubert  *  plain is set to \a true, otherwise \a false.
4042b15cb3dSCy Schubert  *
4052b15cb3dSCy Schubert  *  Anything less than 256 characters in size is printed as a single unit.
4062b15cb3dSCy Schubert  *  Otherwise, paragraphs are detected.  A paragraph break is defined as just
4072b15cb3dSCy Schubert  *  before a non-empty line preceded by two newlines or a line that starts
4082b15cb3dSCy Schubert  *  with at least one space character but fewer than 8 space characters.
4092b15cb3dSCy Schubert  *  Lines indented with tabs or more than 7 spaces are considered continuation
4102b15cb3dSCy Schubert  *  lines.
4112b15cb3dSCy Schubert  *
4122b15cb3dSCy Schubert  *  If 'plain' is true, we are emitting text for a user to see.  So, if it is
4132b15cb3dSCy Schubert  *  true and NLS is not enabled, then just write the whole thing at once.
4142b15cb3dSCy Schubert =*/
4152b15cb3dSCy Schubert void
optionPrintParagraphs(char const * text,bool plain,FILE * fp)4162b15cb3dSCy Schubert optionPrintParagraphs(char const * text, bool plain, FILE * fp)
4172b15cb3dSCy Schubert {
4182b15cb3dSCy Schubert     size_t len = strlen(text);
4192b15cb3dSCy Schubert     char * buf;
4202b15cb3dSCy Schubert #ifndef ENABLE_NLS
4212b15cb3dSCy Schubert     if (plain || (len < 256))
4222b15cb3dSCy Schubert #else
4232b15cb3dSCy Schubert     if (len < 256)
4242b15cb3dSCy Schubert #endif
4252b15cb3dSCy Schubert     {
4262b15cb3dSCy Schubert         print_one_paragraph(text, plain, fp);
4272b15cb3dSCy Schubert         return;
4282b15cb3dSCy Schubert     }
4292b15cb3dSCy Schubert 
4302b15cb3dSCy Schubert     AGDUPSTR(buf, text, "ppara");
4312b15cb3dSCy Schubert     text = buf;
4322b15cb3dSCy Schubert 
4332b15cb3dSCy Schubert     for (;;) {
4342b15cb3dSCy Schubert         char * scan;
4352b15cb3dSCy Schubert 
4362b15cb3dSCy Schubert         if (len < 256) {
4372b15cb3dSCy Schubert         done:
4382b15cb3dSCy Schubert             print_one_paragraph(buf, plain, fp);
4392b15cb3dSCy Schubert             break;
4402b15cb3dSCy Schubert         }
4412b15cb3dSCy Schubert         scan = buf;
4422b15cb3dSCy Schubert 
4432b15cb3dSCy Schubert     try_longer:
4442b15cb3dSCy Schubert         scan = strchr(scan, NL);
4452b15cb3dSCy Schubert         if (scan == NULL)
4462b15cb3dSCy Schubert             goto done;
4472b15cb3dSCy Schubert 
4482b15cb3dSCy Schubert         if ((scan - buf) < 40) {
4492b15cb3dSCy Schubert             scan++;
4502b15cb3dSCy Schubert             goto try_longer;
4512b15cb3dSCy Schubert         }
4522b15cb3dSCy Schubert 
4532b15cb3dSCy Schubert         scan++;
4542b15cb3dSCy Schubert         if ((! isspace((int)*scan)) || (*scan == HT))
4552b15cb3dSCy Schubert             /*
4562b15cb3dSCy Schubert              * line starts with tab or non-whitespace --> continuation
4572b15cb3dSCy Schubert              */
4582b15cb3dSCy Schubert             goto try_longer;
4592b15cb3dSCy Schubert 
4602b15cb3dSCy Schubert         if (*scan == NL) {
4612b15cb3dSCy Schubert             /*
4622b15cb3dSCy Schubert              * Double newline -> paragraph break
4632b15cb3dSCy Schubert              * Include all newlines in current paragraph.
4642b15cb3dSCy Schubert              */
4652b15cb3dSCy Schubert             while (*++scan == NL)  /*continue*/;
4662b15cb3dSCy Schubert 
4672b15cb3dSCy Schubert         } else {
4682b15cb3dSCy Schubert             char * p = scan;
4692b15cb3dSCy Schubert             int   sp_ct = 0;
4702b15cb3dSCy Schubert 
4712b15cb3dSCy Schubert             while (*p == ' ') {
4722b15cb3dSCy Schubert                 if (++sp_ct >= 8) {
4732b15cb3dSCy Schubert                     /*
4742b15cb3dSCy Schubert                      * Too many spaces --> continuation line
4752b15cb3dSCy Schubert                      */
4762b15cb3dSCy Schubert                     scan = p;
4772b15cb3dSCy Schubert                     goto try_longer;
4782b15cb3dSCy Schubert                 }
4792b15cb3dSCy Schubert                 p++;
4802b15cb3dSCy Schubert             }
4812b15cb3dSCy Schubert         }
4822b15cb3dSCy Schubert 
4832b15cb3dSCy Schubert         /*
4842b15cb3dSCy Schubert          * "scan" points to the first character of a paragraph or the
4852b15cb3dSCy Schubert          * terminating NUL byte.
4862b15cb3dSCy Schubert          */
4872b15cb3dSCy Schubert         {
4882b15cb3dSCy Schubert             char svch = *scan;
4892b15cb3dSCy Schubert             *scan = NUL;
4902b15cb3dSCy Schubert             print_one_paragraph(buf, plain, fp);
4912b15cb3dSCy Schubert             len -= scan - buf;
4922b15cb3dSCy Schubert             if (len <= 0)
4932b15cb3dSCy Schubert                 break;
4942b15cb3dSCy Schubert             *scan = svch;
4952b15cb3dSCy Schubert             buf = scan;
4962b15cb3dSCy Schubert         }
4972b15cb3dSCy Schubert     }
4982b15cb3dSCy Schubert     AGFREE(text);
4992b15cb3dSCy Schubert }
500ea906c41SOllivier Robert 
501ea906c41SOllivier Robert /*=export_func  optionUsage
502ea906c41SOllivier Robert  * private:
503ea906c41SOllivier Robert  *
504ea906c41SOllivier Robert  * what:  Print usage text
5052b15cb3dSCy Schubert  * arg:   + tOptions * + opts + program options descriptor +
506ea906c41SOllivier Robert  * arg:   + int        + exitCode + exit code for calling exit(3) +
507ea906c41SOllivier Robert  *
508ea906c41SOllivier Robert  * doc:
509ea906c41SOllivier Robert  *  This routine will print usage in both GNU-standard and AutoOpts-expanded
510ea906c41SOllivier Robert  *  formats.  The descriptor specifies the default, but AUTOOPTS_USAGE will
511ea906c41SOllivier Robert  *  over-ride this, providing the value of it is set to either "gnu" or
512ea906c41SOllivier Robert  *  "autoopts".  This routine will @strong{not} return.
513ea906c41SOllivier Robert  *
5142b15cb3dSCy Schubert  *  If "exitCode" is "AO_EXIT_REQ_USAGE" (normally 64), then output will to
5152b15cb3dSCy Schubert  *  to stdout and the actual exit code will be "EXIT_SUCCESS".
516ea906c41SOllivier Robert =*/
517*a466cc55SCy Schubert lo_noreturn void
optionUsage(tOptions * opts,int usage_exit_code)5182b15cb3dSCy Schubert optionUsage(tOptions * opts, int usage_exit_code)
519ea906c41SOllivier Robert {
5202b15cb3dSCy Schubert     int exit_code = (usage_exit_code == AO_EXIT_REQ_USAGE)
5212b15cb3dSCy Schubert         ? EXIT_SUCCESS : usage_exit_code;
522ea906c41SOllivier Robert 
5232b15cb3dSCy Schubert     displayEnum = false;
5242b15cb3dSCy Schubert     set_usage_flags(opts, NULL);
525ea906c41SOllivier Robert 
526ea906c41SOllivier Robert     /*
527ea906c41SOllivier Robert      *  Paged usage will preset option_usage_fp to an output file.
528ea906c41SOllivier Robert      *  If it hasn't already been set, then set it to standard output
529ea906c41SOllivier Robert      *  on successful exit (help was requested), otherwise error out.
5302b15cb3dSCy Schubert      *
5312b15cb3dSCy Schubert      *  Test the version before obtaining pzFullUsage or pzShortUsage.
5322b15cb3dSCy Schubert      *  These fields do not exist before revision 30.
533ea906c41SOllivier Robert      */
534ea906c41SOllivier Robert     {
5352b15cb3dSCy Schubert         char const * pz;
536ea906c41SOllivier Robert 
5372b15cb3dSCy Schubert         if (exit_code == EXIT_SUCCESS) {
5382b15cb3dSCy Schubert             pz = (opts->structVersion >= 30 * 4096)
5392b15cb3dSCy Schubert                 ? opts->pzFullUsage : NULL;
540ea906c41SOllivier Robert 
5412b15cb3dSCy Schubert             if (option_usage_fp == NULL)
5422b15cb3dSCy Schubert                 option_usage_fp = print_exit ? stderr : stdout;
543ea906c41SOllivier Robert 
5442b15cb3dSCy Schubert         } else {
5452b15cb3dSCy Schubert             pz = (opts->structVersion >= 30 * 4096)
5462b15cb3dSCy Schubert                 ? opts->pzShortUsage : NULL;
5472b15cb3dSCy Schubert 
5482b15cb3dSCy Schubert             if (option_usage_fp == NULL)
5492b15cb3dSCy Schubert                 option_usage_fp = stderr;
550ea906c41SOllivier Robert         }
551ea906c41SOllivier Robert 
5522b15cb3dSCy Schubert         if (((opts->fOptSet & OPTPROC_COMPUTE) == 0) && (pz != NULL)) {
5532b15cb3dSCy Schubert             if ((opts->fOptSet & OPTPROC_TRANSLATE) != 0)
5542b15cb3dSCy Schubert                 optionPrintParagraphs(pz, true, option_usage_fp);
5552b15cb3dSCy Schubert             else
5562b15cb3dSCy Schubert                 fputs(pz, option_usage_fp);
5572b15cb3dSCy Schubert             goto flush_and_exit;
5582b15cb3dSCy Schubert         }
559ea906c41SOllivier Robert     }
560ea906c41SOllivier Robert 
5612b15cb3dSCy Schubert     fprintf(option_usage_fp, opts->pzUsageTitle, opts->pzProgName);
562ea906c41SOllivier Robert 
5632b15cb3dSCy Schubert     if ((exit_code == EXIT_SUCCESS) ||
5642b15cb3dSCy Schubert         (! skip_misuse_usage(opts)))
565ea906c41SOllivier Robert 
5662b15cb3dSCy Schubert         print_usage_details(opts, usage_exit_code);
5672b15cb3dSCy Schubert     else
5682b15cb3dSCy Schubert         print_offer_usage(opts);
569ea906c41SOllivier Robert 
5702b15cb3dSCy Schubert  flush_and_exit:
571ea906c41SOllivier Robert     fflush(option_usage_fp);
5722b15cb3dSCy Schubert     if (ferror(option_usage_fp) != 0)
5732b15cb3dSCy Schubert         fserr_exit(opts->pzProgName, zwriting, (option_usage_fp == stdout)
5742b15cb3dSCy Schubert                    ? zstdout_name : zstderr_name);
575ea906c41SOllivier Robert 
5762b15cb3dSCy Schubert     option_exits(exit_code);
577ea906c41SOllivier Robert }
578ea906c41SOllivier Robert 
579ea906c41SOllivier Robert /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
580ea906c41SOllivier Robert  *   PER OPTION TYPE USAGE INFORMATION
5812b15cb3dSCy Schubert  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5822b15cb3dSCy Schubert /**
5832b15cb3dSCy Schubert  * print option conflicts.
5842b15cb3dSCy Schubert  *
5852b15cb3dSCy Schubert  * @param opts the program option descriptor
5862b15cb3dSCy Schubert  * @param od   the option descriptor
587ea906c41SOllivier Robert  */
588ea906c41SOllivier Robert static void
prt_conflicts(tOptions * opts,tOptDesc * od)5892b15cb3dSCy Schubert prt_conflicts(tOptions * opts, tOptDesc * od)
590ea906c41SOllivier Robert {
5912b15cb3dSCy Schubert     const int * opt_no;
5922b15cb3dSCy Schubert     fputs(zTabHyp + tab_skip_ct, option_usage_fp);
593ea906c41SOllivier Robert 
594ea906c41SOllivier Robert     /*
5952b15cb3dSCy Schubert      *  REQUIRED:
596ea906c41SOllivier Robert      */
5972b15cb3dSCy Schubert     if (od->pOptMust != NULL) {
5982b15cb3dSCy Schubert         opt_no = od->pOptMust;
599ea906c41SOllivier Robert 
6002b15cb3dSCy Schubert         if (opt_no[1] == NO_EQUIVALENT) {
6012b15cb3dSCy Schubert             fprintf(option_usage_fp, zReqOne,
6022b15cb3dSCy Schubert                     opts->pOptDesc[*opt_no].pz_Name);
6032b15cb3dSCy Schubert         } else {
604ea906c41SOllivier Robert             fputs(zReqThese, option_usage_fp);
605ea906c41SOllivier Robert             for (;;) {
6062b15cb3dSCy Schubert                 fprintf(option_usage_fp, zTabout + tab_skip_ct,
6072b15cb3dSCy Schubert                         opts->pOptDesc[*opt_no].pz_Name);
6082b15cb3dSCy Schubert                 if (*++opt_no == NO_EQUIVALENT)
609ea906c41SOllivier Robert                     break;
610ea906c41SOllivier Robert             }
6112b15cb3dSCy Schubert         }
612ea906c41SOllivier Robert 
6132b15cb3dSCy Schubert         if (od->pOptCant != NULL)
6142b15cb3dSCy Schubert             fputs(zTabHypAnd + tab_skip_ct, option_usage_fp);
615ea906c41SOllivier Robert     }
616ea906c41SOllivier Robert 
617ea906c41SOllivier Robert     /*
618ea906c41SOllivier Robert      *  CONFLICTS:
619ea906c41SOllivier Robert      */
6202b15cb3dSCy Schubert     if (od->pOptCant == NULL)
6212b15cb3dSCy Schubert         return;
6222b15cb3dSCy Schubert 
6232b15cb3dSCy Schubert     opt_no = od->pOptCant;
6242b15cb3dSCy Schubert 
6252b15cb3dSCy Schubert     if (opt_no[1] == NO_EQUIVALENT) {
6262b15cb3dSCy Schubert         fprintf(option_usage_fp, zProhibOne,
6272b15cb3dSCy Schubert                 opts->pOptDesc[*opt_no].pz_Name);
6282b15cb3dSCy Schubert         return;
6292b15cb3dSCy Schubert     }
630ea906c41SOllivier Robert 
631ea906c41SOllivier Robert     fputs(zProhib, option_usage_fp);
632ea906c41SOllivier Robert     for (;;) {
6332b15cb3dSCy Schubert         fprintf(option_usage_fp, zTabout + tab_skip_ct,
6342b15cb3dSCy Schubert                 opts->pOptDesc[*opt_no].pz_Name);
6352b15cb3dSCy Schubert         if (*++opt_no == NO_EQUIVALENT)
636ea906c41SOllivier Robert             break;
637ea906c41SOllivier Robert     }
638ea906c41SOllivier Robert }
6392b15cb3dSCy Schubert 
6402b15cb3dSCy Schubert /**
6412b15cb3dSCy Schubert  *  Print the usage information for a single vendor option.
6422b15cb3dSCy Schubert  *
6432b15cb3dSCy Schubert  * @param[in] opts    the program option descriptor
6442b15cb3dSCy Schubert  * @param[in] od      the option descriptor
6452b15cb3dSCy Schubert  * @param[in] argtp   names of the option argument types
6462b15cb3dSCy Schubert  * @param[in] usefmt  format for primary usage line
6472b15cb3dSCy Schubert  */
6482b15cb3dSCy Schubert static void
prt_one_vendor(tOptions * opts,tOptDesc * od,arg_types_t * argtp,char const * usefmt)6492b15cb3dSCy Schubert prt_one_vendor(tOptions *    opts,  tOptDesc *   od,
6502b15cb3dSCy Schubert                arg_types_t * argtp, char const * usefmt)
6512b15cb3dSCy Schubert {
6522b15cb3dSCy Schubert     prt_preamble(opts, od, argtp);
6532b15cb3dSCy Schubert 
6542b15cb3dSCy Schubert     {
6552b15cb3dSCy Schubert         char z[ 80 ];
6562b15cb3dSCy Schubert         char const *  pzArgType;
6572b15cb3dSCy Schubert 
6582b15cb3dSCy Schubert         /*
6592b15cb3dSCy Schubert          *  Determine the argument type string first on its usage, then,
6602b15cb3dSCy Schubert          *  when the option argument is required, base the type string on the
6612b15cb3dSCy Schubert          *  argument type.
6622b15cb3dSCy Schubert          */
6632b15cb3dSCy Schubert         if (od->fOptState & OPTST_ARG_OPTIONAL) {
6642b15cb3dSCy Schubert             pzArgType = argtp->pzOpt;
6652b15cb3dSCy Schubert 
6662b15cb3dSCy Schubert         } else switch (OPTST_GET_ARGTYPE(od->fOptState)) {
6672b15cb3dSCy Schubert         case OPARG_TYPE_NONE:        pzArgType = argtp->pzNo;   break;
6682b15cb3dSCy Schubert         case OPARG_TYPE_ENUMERATION: pzArgType = argtp->pzKey;  break;
6692b15cb3dSCy Schubert         case OPARG_TYPE_FILE:        pzArgType = argtp->pzFile; break;
6702b15cb3dSCy Schubert         case OPARG_TYPE_MEMBERSHIP:  pzArgType = argtp->pzKeyL; break;
6712b15cb3dSCy Schubert         case OPARG_TYPE_BOOLEAN:     pzArgType = argtp->pzBool; break;
6722b15cb3dSCy Schubert         case OPARG_TYPE_NUMERIC:     pzArgType = argtp->pzNum;  break;
6732b15cb3dSCy Schubert         case OPARG_TYPE_HIERARCHY:   pzArgType = argtp->pzNest; break;
6742b15cb3dSCy Schubert         case OPARG_TYPE_STRING:      pzArgType = argtp->pzStr;  break;
6752b15cb3dSCy Schubert         case OPARG_TYPE_TIME:        pzArgType = argtp->pzTime; break;
6762b15cb3dSCy Schubert         default:                     goto bogus_desc;
677ea906c41SOllivier Robert         }
678ea906c41SOllivier Robert 
6792b15cb3dSCy Schubert         pzArgType = SPN_WHITESPACE_CHARS(pzArgType);
6802b15cb3dSCy Schubert         if (*pzArgType == NUL)
6812b15cb3dSCy Schubert             snprintf(z, sizeof(z), "%s", od->pz_Name);
6822b15cb3dSCy Schubert         else
6832b15cb3dSCy Schubert             snprintf(z, sizeof(z), "%s=%s", od->pz_Name, pzArgType);
6842b15cb3dSCy Schubert         fprintf(option_usage_fp, usefmt, z, od->pzText);
6852b15cb3dSCy Schubert 
6862b15cb3dSCy Schubert         switch (OPTST_GET_ARGTYPE(od->fOptState)) {
6872b15cb3dSCy Schubert         case OPARG_TYPE_ENUMERATION:
6882b15cb3dSCy Schubert         case OPARG_TYPE_MEMBERSHIP:
6892b15cb3dSCy Schubert             displayEnum = (od->pOptProc != NULL) ? true : displayEnum;
6902b15cb3dSCy Schubert         }
6912b15cb3dSCy Schubert     }
6922b15cb3dSCy Schubert 
6932b15cb3dSCy Schubert     return;
6942b15cb3dSCy Schubert 
6952b15cb3dSCy Schubert  bogus_desc:
6962b15cb3dSCy Schubert     fprintf(stderr, zbad_od, opts->pzProgName, od->pz_Name);
6972b15cb3dSCy Schubert     ao_bug(zbad_arg_type_msg);
6982b15cb3dSCy Schubert }
6992b15cb3dSCy Schubert 
7002b15cb3dSCy Schubert /**
7012b15cb3dSCy Schubert  * Print the long options processed with "-W".  These options will be the
7022b15cb3dSCy Schubert  * ones that do *not* have flag characters.
7032b15cb3dSCy Schubert  *
7042b15cb3dSCy Schubert  * @param opts  the program option descriptor
7052b15cb3dSCy Schubert  * @param title the title for the options
7062b15cb3dSCy Schubert  */
7072b15cb3dSCy Schubert static void
prt_vendor_opts(tOptions * opts,char const * title)7082b15cb3dSCy Schubert prt_vendor_opts(tOptions * opts, char const * title)
7092b15cb3dSCy Schubert {
7102b15cb3dSCy Schubert     static unsigned int const not_vended_mask =
7112b15cb3dSCy Schubert         OPTST_NO_USAGE_MASK | OPTST_DOCUMENT;
7122b15cb3dSCy Schubert 
7132b15cb3dSCy Schubert     static char const vfmtfmt[] = "%%-%us %%s\n";
7142b15cb3dSCy Schubert     char vfmt[sizeof(vfmtfmt)];
7152b15cb3dSCy Schubert 
7162b15cb3dSCy Schubert     /*
7172b15cb3dSCy Schubert      *  Only handle client specified options.  The "vendor option" follows
7182b15cb3dSCy Schubert      *  "presetOptCt", so we won't loop/recurse indefinitely.
7192b15cb3dSCy Schubert      */
7202b15cb3dSCy Schubert     int          ct     = opts->presetOptCt;
7212b15cb3dSCy Schubert     tOptDesc *   od     = opts->pOptDesc;
7222b15cb3dSCy Schubert     fprintf(option_usage_fp, zTabout + tab_skip_ct, zVendOptsAre);
7232b15cb3dSCy Schubert 
7242b15cb3dSCy Schubert     {
7252b15cb3dSCy Schubert         size_t   nmlen  = 0;
7262b15cb3dSCy Schubert         do  {
7272b15cb3dSCy Schubert             size_t l;
7282b15cb3dSCy Schubert             if (  ((od->fOptState & not_vended_mask) != 0)
729*a466cc55SCy Schubert                || GRAPH_CH(od->optValue))
7302b15cb3dSCy Schubert                 continue;
7312b15cb3dSCy Schubert 
7322b15cb3dSCy Schubert             l = strlen(od->pz_Name);
7332b15cb3dSCy Schubert             if (l > nmlen)  nmlen = l;
7342b15cb3dSCy Schubert         } while (od++, (--ct > 0));
7352b15cb3dSCy Schubert 
7362b15cb3dSCy Schubert         snprintf(vfmt, sizeof(vfmt), vfmtfmt, (unsigned int)nmlen + 4);
7372b15cb3dSCy Schubert     }
7382b15cb3dSCy Schubert 
7392b15cb3dSCy Schubert     if (tab_skip_ct > 0)
7402b15cb3dSCy Schubert         tab_skip_ct--;
7412b15cb3dSCy Schubert 
7422b15cb3dSCy Schubert     ct    = opts->presetOptCt;
7432b15cb3dSCy Schubert     od    = opts->pOptDesc;
7442b15cb3dSCy Schubert 
7452b15cb3dSCy Schubert     do  {
7462b15cb3dSCy Schubert         if (  ((od->fOptState & not_vended_mask) != 0)
747*a466cc55SCy Schubert            || GRAPH_CH(od->optValue))
7482b15cb3dSCy Schubert             continue;
7492b15cb3dSCy Schubert 
7502b15cb3dSCy Schubert         prt_one_vendor(opts, od, &argTypes, vfmt);
7512b15cb3dSCy Schubert         prt_extd_usage(opts, od, title);
7522b15cb3dSCy Schubert 
7532b15cb3dSCy Schubert     } while (od++, (--ct > 0));
7542b15cb3dSCy Schubert 
7552b15cb3dSCy Schubert     /* no need to restore "tab_skip_ct" - options are done now */
7562b15cb3dSCy Schubert }
7572b15cb3dSCy Schubert 
7582b15cb3dSCy Schubert /**
7592b15cb3dSCy Schubert  * Print extended usage.  Usage/help was requested.
7602b15cb3dSCy Schubert  *
7612b15cb3dSCy Schubert  * @param opts  the program option descriptor
7622b15cb3dSCy Schubert  * @param od   the option descriptor
7632b15cb3dSCy Schubert  * @param title the title for the options
7642b15cb3dSCy Schubert  */
7652b15cb3dSCy Schubert static void
prt_extd_usage(tOptions * opts,tOptDesc * od,char const * title)7662b15cb3dSCy Schubert prt_extd_usage(tOptions * opts, tOptDesc * od, char const * title)
7672b15cb3dSCy Schubert {
7682b15cb3dSCy Schubert     if (  ((opts->fOptSet & OPTPROC_VENDOR_OPT) != 0)
7692b15cb3dSCy Schubert        && (od->optActualValue == VENDOR_OPTION_VALUE)) {
7702b15cb3dSCy Schubert         prt_vendor_opts(opts, title);
7712b15cb3dSCy Schubert         return;
7722b15cb3dSCy Schubert     }
7732b15cb3dSCy Schubert 
7742b15cb3dSCy Schubert     /*
7752b15cb3dSCy Schubert      *  IF there are option conflicts or dependencies,
7762b15cb3dSCy Schubert      *  THEN print them here.
7772b15cb3dSCy Schubert      */
7782b15cb3dSCy Schubert     if ((od->pOptMust != NULL) || (od->pOptCant != NULL))
7792b15cb3dSCy Schubert         prt_conflicts(opts, od);
7802b15cb3dSCy Schubert 
781ea906c41SOllivier Robert     /*
782ea906c41SOllivier Robert      *  IF there is a disablement string
783ea906c41SOllivier Robert      *  THEN print the disablement info
784ea906c41SOllivier Robert      */
7852b15cb3dSCy Schubert     if (od->pz_DisableName != NULL )
7862b15cb3dSCy Schubert         fprintf(option_usage_fp, zDis + tab_skip_ct, od->pz_DisableName);
787ea906c41SOllivier Robert 
788ea906c41SOllivier Robert     /*
7892b15cb3dSCy Schubert      *  Check for argument types that have callbacks with magical properties
7902b15cb3dSCy Schubert      */
7912b15cb3dSCy Schubert     switch (OPTST_GET_ARGTYPE(od->fOptState)) {
7922b15cb3dSCy Schubert     case OPARG_TYPE_NUMERIC:
7932b15cb3dSCy Schubert         /*
794ea906c41SOllivier Robert          *  IF the numeric option has a special callback,
795ea906c41SOllivier Robert          *  THEN call it, requesting the range or other special info
796ea906c41SOllivier Robert          */
7972b15cb3dSCy Schubert         if (  (od->pOptProc != NULL)
7982b15cb3dSCy Schubert            && (od->pOptProc != optionNumericVal) ) {
7992b15cb3dSCy Schubert             (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od);
8002b15cb3dSCy Schubert         }
8012b15cb3dSCy Schubert         break;
8022b15cb3dSCy Schubert 
8032b15cb3dSCy Schubert     case OPARG_TYPE_FILE:
8042b15cb3dSCy Schubert         (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od);
8052b15cb3dSCy Schubert         break;
806ea906c41SOllivier Robert     }
807ea906c41SOllivier Robert 
808ea906c41SOllivier Robert     /*
809ea906c41SOllivier Robert      *  IF the option defaults to being enabled,
810ea906c41SOllivier Robert      *  THEN print that out
811ea906c41SOllivier Robert      */
8122b15cb3dSCy Schubert     if (od->fOptState & OPTST_INITENABLED)
8132b15cb3dSCy Schubert         fputs(zEnab + tab_skip_ct, option_usage_fp);
814ea906c41SOllivier Robert 
815ea906c41SOllivier Robert     /*
816ea906c41SOllivier Robert      *  IF  the option is in an equivalence class
817ea906c41SOllivier Robert      *        AND not the designated lead
818ea906c41SOllivier Robert      *  THEN print equivalence and leave it at that.
819ea906c41SOllivier Robert      */
8202b15cb3dSCy Schubert     if (  (od->optEquivIndex != NO_EQUIVALENT)
8212b15cb3dSCy Schubert        && (od->optEquivIndex != od->optActualIndex )  )  {
8222b15cb3dSCy Schubert         fprintf(option_usage_fp, zalt_opt + tab_skip_ct,
8232b15cb3dSCy Schubert                  opts->pOptDesc[ od->optEquivIndex ].pz_Name);
824ea906c41SOllivier Robert         return;
825ea906c41SOllivier Robert     }
826ea906c41SOllivier Robert 
827ea906c41SOllivier Robert     /*
828ea906c41SOllivier Robert      *  IF this particular option can NOT be preset
829ea906c41SOllivier Robert      *    AND some form of presetting IS allowed,
830ea906c41SOllivier Robert      *    AND it is not an auto-managed option (e.g. --help, et al.)
831ea906c41SOllivier Robert      *  THEN advise that this option may not be preset.
832ea906c41SOllivier Robert      */
8332b15cb3dSCy Schubert     if (  ((od->fOptState & OPTST_NO_INIT) != 0)
8342b15cb3dSCy Schubert        && (  (opts->papzHomeList != NULL)
8352b15cb3dSCy Schubert           || (opts->pzPROGNAME != NULL)
836ea906c41SOllivier Robert           )
8372b15cb3dSCy Schubert        && (od->optIndex < opts->presetOptCt)
838ea906c41SOllivier Robert        )
839ea906c41SOllivier Robert 
8402b15cb3dSCy Schubert         fputs(zNoPreset + tab_skip_ct, option_usage_fp);
841ea906c41SOllivier Robert 
842ea906c41SOllivier Robert     /*
843ea906c41SOllivier Robert      *  Print the appearance requirements.
844ea906c41SOllivier Robert      */
8452b15cb3dSCy Schubert     if (OPTST_GET_ARGTYPE(od->fOptState) == OPARG_TYPE_MEMBERSHIP)
8462b15cb3dSCy Schubert         fputs(zMembers + tab_skip_ct, option_usage_fp);
847ea906c41SOllivier Robert 
8482b15cb3dSCy Schubert     else switch (od->optMinCt) {
849ea906c41SOllivier Robert     case 1:
850ea906c41SOllivier Robert     case 0:
8512b15cb3dSCy Schubert         switch (od->optMaxCt) {
8522b15cb3dSCy Schubert         case 0:       fputs(zPreset + tab_skip_ct, option_usage_fp); break;
8532b15cb3dSCy Schubert         case NOLIMIT: fputs(zNoLim  + tab_skip_ct, option_usage_fp); break;
854ea906c41SOllivier Robert         case 1:       break;
855ea906c41SOllivier Robert             /*
856ea906c41SOllivier Robert              * IF the max is more than one but limited, print "UP TO" message
857ea906c41SOllivier Robert              */
8582b15cb3dSCy Schubert         default:
8592b15cb3dSCy Schubert             fprintf(option_usage_fp, zUpTo + tab_skip_ct, od->optMaxCt); break;
860ea906c41SOllivier Robert         }
861ea906c41SOllivier Robert         break;
862ea906c41SOllivier Robert 
863ea906c41SOllivier Robert     default:
864ea906c41SOllivier Robert         /*
865ea906c41SOllivier Robert          *  More than one is required.  Print the range.
866ea906c41SOllivier Robert          */
8672b15cb3dSCy Schubert         fprintf(option_usage_fp, zMust + tab_skip_ct,
8682b15cb3dSCy Schubert                 od->optMinCt, od->optMaxCt);
869ea906c41SOllivier Robert     }
870ea906c41SOllivier Robert 
8712b15cb3dSCy Schubert     if (  NAMED_OPTS(opts)
8722b15cb3dSCy Schubert        && (opts->specOptIdx.default_opt == od->optIndex))
8732b15cb3dSCy Schubert         fputs(zDefaultOpt + tab_skip_ct, option_usage_fp);
874ea906c41SOllivier Robert }
875ea906c41SOllivier Robert 
8762b15cb3dSCy Schubert /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8772b15cb3dSCy Schubert /**
8782b15cb3dSCy Schubert  * Figure out where all the initialization files might live.  This requires
8792b15cb3dSCy Schubert  * translating some environment variables and testing to see if a name is a
8802b15cb3dSCy Schubert  * directory or a file.  It's squishy, but important to tell users how to
8812b15cb3dSCy Schubert  * find these files.
882ea906c41SOllivier Robert  *
8832b15cb3dSCy Schubert  * @param[in]  papz        search path
8842b15cb3dSCy Schubert  * @param[out] ini_file    an output buffer of AG_PATH_MAX+1 bytes
8852b15cb3dSCy Schubert  * @param[in]  path_nm     the name of the file we're hunting for
886ea906c41SOllivier Robert  */
887ea906c41SOllivier Robert static void
prt_ini_list(char const * const * papz,char const * ini_file,char const * path_nm)8882b15cb3dSCy Schubert prt_ini_list(char const * const * papz, char const * ini_file,
8892b15cb3dSCy Schubert              char const * path_nm)
890ea906c41SOllivier Robert {
8912b15cb3dSCy Schubert     char pth_buf[AG_PATH_MAX+1];
892ea906c41SOllivier Robert 
893ea906c41SOllivier Robert     fputs(zPresetIntro, option_usage_fp);
894ea906c41SOllivier Robert 
895ea906c41SOllivier Robert     for (;;) {
8962b15cb3dSCy Schubert         char const * path   = *(papz++);
8972b15cb3dSCy Schubert         char const * nm_buf = pth_buf;
898ea906c41SOllivier Robert 
8992b15cb3dSCy Schubert         if (path == NULL)
900ea906c41SOllivier Robert             break;
901ea906c41SOllivier Robert 
9022b15cb3dSCy Schubert         /*
9032b15cb3dSCy Schubert          * Ignore any invalid paths
9042b15cb3dSCy Schubert          */
9052b15cb3dSCy Schubert         if (! optionMakePath(pth_buf, (int)sizeof(pth_buf), path, path_nm))
9062b15cb3dSCy Schubert             nm_buf = path;
9072b15cb3dSCy Schubert 
9082b15cb3dSCy Schubert         /*
9092b15cb3dSCy Schubert          * Expand paths that are relative to the executable or installation
9102b15cb3dSCy Schubert          * directories.  Leave alone paths that use environment variables.
9112b15cb3dSCy Schubert          */
9122b15cb3dSCy Schubert         else if ((*path == '$')
9132b15cb3dSCy Schubert                  && ((path[1] == '$') || (path[1] == '@')))
9142b15cb3dSCy Schubert             path = nm_buf;
915ea906c41SOllivier Robert 
916ea906c41SOllivier Robert         /*
917ea906c41SOllivier Robert          *  Print the name of the "homerc" file.  If the "rcfile" name is
918ea906c41SOllivier Robert          *  not empty, we may or may not print that, too...
919ea906c41SOllivier Robert          */
9202b15cb3dSCy Schubert         fprintf(option_usage_fp, zPathFmt, path);
9212b15cb3dSCy Schubert         if (*ini_file != NUL) {
922ea906c41SOllivier Robert             struct stat sb;
923ea906c41SOllivier Robert 
924ea906c41SOllivier Robert             /*
925ea906c41SOllivier Robert              *  IF the "homerc" file is a directory,
926ea906c41SOllivier Robert              *  then append the "rcfile" name.
927ea906c41SOllivier Robert              */
9282b15cb3dSCy Schubert             if ((stat(nm_buf, &sb) == 0) && S_ISDIR(sb.st_mode)) {
929ea906c41SOllivier Robert                 fputc(DIRCH,    option_usage_fp);
9302b15cb3dSCy Schubert                 fputs(ini_file, option_usage_fp);
931ea906c41SOllivier Robert             }
932ea906c41SOllivier Robert         }
933ea906c41SOllivier Robert 
9342b15cb3dSCy Schubert         fputc(NL, option_usage_fp);
935ea906c41SOllivier Robert     }
936ea906c41SOllivier Robert }
937ea906c41SOllivier Robert 
9382b15cb3dSCy Schubert /**
9392b15cb3dSCy Schubert  *  Print the usage line preamble text
9402b15cb3dSCy Schubert  *
9412b15cb3dSCy Schubert  * @param opts  the program option descriptor
9422b15cb3dSCy Schubert  * @param od    the option descriptor
9432b15cb3dSCy Schubert  * @param at    names of the option argument types
944ea906c41SOllivier Robert  */
945ea906c41SOllivier Robert static void
prt_preamble(tOptions * opts,tOptDesc * od,arg_types_t * at)9462b15cb3dSCy Schubert prt_preamble(tOptions * opts, tOptDesc * od, arg_types_t * at)
947ea906c41SOllivier Robert {
948ea906c41SOllivier Robert     /*
949ea906c41SOllivier Robert      *  Flag prefix: IF no flags at all, then omit it.  If not printable
950ea906c41SOllivier Robert      *  (not allowed for this option), then blank, else print it.
951ea906c41SOllivier Robert      *  Follow it with a comma if we are doing GNU usage and long
952ea906c41SOllivier Robert      *  opts are to be printed too.
953ea906c41SOllivier Robert      */
9542b15cb3dSCy Schubert     if ((opts->fOptSet & OPTPROC_SHORTOPT) == 0)
9552b15cb3dSCy Schubert         fputs(at->pzSpc, option_usage_fp);
9562b15cb3dSCy Schubert 
957*a466cc55SCy Schubert     else if (! GRAPH_CH(od->optValue)) {
9582b15cb3dSCy Schubert         if (  (opts->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
959ea906c41SOllivier Robert            == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
960ea906c41SOllivier Robert             fputc(' ', option_usage_fp);
9612b15cb3dSCy Schubert         fputs(at->pzNoF, option_usage_fp);
9622b15cb3dSCy Schubert 
963ea906c41SOllivier Robert     } else {
9642b15cb3dSCy Schubert         fprintf(option_usage_fp, "   -%c", od->optValue);
9652b15cb3dSCy Schubert         if (  (opts->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
966ea906c41SOllivier Robert            == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
967ea906c41SOllivier Robert             fputs(", ", option_usage_fp);
968ea906c41SOllivier Robert     }
9692b15cb3dSCy Schubert }
9702b15cb3dSCy Schubert 
9712b15cb3dSCy Schubert /**
9722b15cb3dSCy Schubert  *  Print the usage information for a single option.
9732b15cb3dSCy Schubert  *
9742b15cb3dSCy Schubert  * @param opts  the program option descriptor
9752b15cb3dSCy Schubert  * @param od    the option descriptor
9762b15cb3dSCy Schubert  * @param at    names of the option argument types
9772b15cb3dSCy Schubert  */
9782b15cb3dSCy Schubert static void
prt_one_usage(tOptions * opts,tOptDesc * od,arg_types_t * at)9792b15cb3dSCy Schubert prt_one_usage(tOptions * opts, tOptDesc * od, arg_types_t * at)
9802b15cb3dSCy Schubert {
9812b15cb3dSCy Schubert     prt_preamble(opts, od, at);
982ea906c41SOllivier Robert 
983ea906c41SOllivier Robert     {
984ea906c41SOllivier Robert         char z[80];
9852b15cb3dSCy Schubert         char const * atyp;
9862b15cb3dSCy Schubert 
987ea906c41SOllivier Robert         /*
988ea906c41SOllivier Robert          *  Determine the argument type string first on its usage, then,
989ea906c41SOllivier Robert          *  when the option argument is required, base the type string on the
990ea906c41SOllivier Robert          *  argument type.
991ea906c41SOllivier Robert          */
9922b15cb3dSCy Schubert         if (od->fOptState & OPTST_ARG_OPTIONAL) {
9932b15cb3dSCy Schubert             atyp = at->pzOpt;
994ea906c41SOllivier Robert 
9952b15cb3dSCy Schubert         } else switch (OPTST_GET_ARGTYPE(od->fOptState)) {
9962b15cb3dSCy Schubert         case OPARG_TYPE_NONE:        atyp = at->pzNo;   break;
9972b15cb3dSCy Schubert         case OPARG_TYPE_ENUMERATION: atyp = at->pzKey;  break;
9982b15cb3dSCy Schubert         case OPARG_TYPE_FILE:        atyp = at->pzFile; break;
9992b15cb3dSCy Schubert         case OPARG_TYPE_MEMBERSHIP:  atyp = at->pzKeyL; break;
10002b15cb3dSCy Schubert         case OPARG_TYPE_BOOLEAN:     atyp = at->pzBool; break;
10012b15cb3dSCy Schubert         case OPARG_TYPE_NUMERIC:     atyp = at->pzNum;  break;
10022b15cb3dSCy Schubert         case OPARG_TYPE_HIERARCHY:   atyp = at->pzNest; break;
10032b15cb3dSCy Schubert         case OPARG_TYPE_STRING:      atyp = at->pzStr;  break;
10042b15cb3dSCy Schubert         case OPARG_TYPE_TIME:        atyp = at->pzTime; break;
10052b15cb3dSCy Schubert         default:                     goto bogus_desc;
1006ea906c41SOllivier Robert         }
1007ea906c41SOllivier Robert 
10082b15cb3dSCy Schubert #ifdef _WIN32
10092b15cb3dSCy Schubert         if (at->pzOptFmt == zGnuOptFmt)
10102b15cb3dSCy Schubert             snprintf(z, sizeof(z), "--%s%s", od->pz_Name, atyp);
10112b15cb3dSCy Schubert         else if (at->pzOptFmt == zGnuOptFmt + 2)
10122b15cb3dSCy Schubert             snprintf(z, sizeof(z), "%s%s", od->pz_Name, atyp);
10132b15cb3dSCy Schubert         else
10142b15cb3dSCy Schubert #endif
10152b15cb3dSCy Schubert         snprintf(z, sizeof(z), at->pzOptFmt, atyp, od->pz_Name,
10162b15cb3dSCy Schubert                  (od->optMinCt != 0) ? at->pzReq : at->pzOpt);
1017ea906c41SOllivier Robert 
10182b15cb3dSCy Schubert         fprintf(option_usage_fp, line_fmt_buf, z, od->pzText);
1019ea906c41SOllivier Robert 
10202b15cb3dSCy Schubert         switch (OPTST_GET_ARGTYPE(od->fOptState)) {
1021ea906c41SOllivier Robert         case OPARG_TYPE_ENUMERATION:
1022ea906c41SOllivier Robert         case OPARG_TYPE_MEMBERSHIP:
10232b15cb3dSCy Schubert             displayEnum = (od->pOptProc != NULL) ? true : displayEnum;
1024ea906c41SOllivier Robert         }
1025ea906c41SOllivier Robert     }
10262b15cb3dSCy Schubert 
1027ea906c41SOllivier Robert     return;
1028ea906c41SOllivier Robert 
1029ea906c41SOllivier Robert  bogus_desc:
10302b15cb3dSCy Schubert     fprintf(stderr, zbad_od, opts->pzProgName, od->pz_Name);
10312b15cb3dSCy Schubert     option_exits(EX_SOFTWARE);
1032ea906c41SOllivier Robert }
1033ea906c41SOllivier Robert 
10342b15cb3dSCy Schubert /**
1035ea906c41SOllivier Robert  *  Print out the usage information for just the options.
1036ea906c41SOllivier Robert  */
1037ea906c41SOllivier Robert static void
prt_opt_usage(tOptions * opts,int ex_code,char const * title)10382b15cb3dSCy Schubert prt_opt_usage(tOptions * opts, int ex_code, char const * title)
1039ea906c41SOllivier Robert {
10402b15cb3dSCy Schubert     int         ct     = opts->optCt;
1041ea906c41SOllivier Robert     int         optNo  = 0;
10422b15cb3dSCy Schubert     tOptDesc *  od     = opts->pOptDesc;
1043ea906c41SOllivier Robert     int         docCt  = 0;
1044ea906c41SOllivier Robert 
1045ea906c41SOllivier Robert     do  {
10462b15cb3dSCy Schubert         /*
10472b15cb3dSCy Schubert          * no usage --> disallowed on command line (OPTST_NO_COMMAND), or
10482b15cb3dSCy Schubert          * deprecated -- strongly discouraged (OPTST_DEPRECATED), or
10492b15cb3dSCy Schubert          * compiled out of current object code (OPTST_OMITTED)
10502b15cb3dSCy Schubert          */
10512b15cb3dSCy Schubert         if ((od->fOptState & OPTST_NO_USAGE_MASK) != 0) {
1052ea906c41SOllivier Robert 
10532b15cb3dSCy Schubert             /*
10542b15cb3dSCy Schubert              * IF      this is a compiled-out option
10552b15cb3dSCy Schubert              *   *AND* usage was requested with "omitted-usage"
10562b15cb3dSCy Schubert              *   *AND* this is NOT abbreviated usage
10572b15cb3dSCy Schubert              * THEN display this option.
10582b15cb3dSCy Schubert              */
10592b15cb3dSCy Schubert             if (  (od->fOptState == (OPTST_OMITTED | OPTST_NO_INIT))
10602b15cb3dSCy Schubert                && (od->pz_Name != NULL)
10612b15cb3dSCy Schubert                && (ex_code == EXIT_SUCCESS))  {
10622b15cb3dSCy Schubert 
10632b15cb3dSCy Schubert                 char const * why_pz =
10642b15cb3dSCy Schubert                     (od->pzText == NULL) ? zDisabledWhy : od->pzText;
10652b15cb3dSCy Schubert                 prt_preamble(opts, od, &argTypes);
10662b15cb3dSCy Schubert                 fprintf(option_usage_fp, zDisabledOpt, od->pz_Name, why_pz);
10672b15cb3dSCy Schubert             }
10682b15cb3dSCy Schubert 
10692b15cb3dSCy Schubert             continue;
10702b15cb3dSCy Schubert         }
10712b15cb3dSCy Schubert 
10722b15cb3dSCy Schubert         if ((od->fOptState & OPTST_DOCUMENT) != 0) {
1073ea906c41SOllivier Robert             if (ex_code == EXIT_SUCCESS) {
10742b15cb3dSCy Schubert                 fprintf(option_usage_fp, argTypes.pzBrk, od->pzText,
10752b15cb3dSCy Schubert                         title);
1076ea906c41SOllivier Robert                 docCt++;
1077ea906c41SOllivier Robert             }
1078ea906c41SOllivier Robert 
1079ea906c41SOllivier Robert             continue;
1080ea906c41SOllivier Robert         }
1081ea906c41SOllivier Robert 
10822b15cb3dSCy Schubert         /* Skip name only options when we have a vendor option */
10832b15cb3dSCy Schubert         if (  ((opts->fOptSet & OPTPROC_VENDOR_OPT) != 0)
1084*a466cc55SCy Schubert            && (! GRAPH_CH(od->optValue)))
10852b15cb3dSCy Schubert             continue;
10862b15cb3dSCy Schubert 
1087ea906c41SOllivier Robert         /*
1088ea906c41SOllivier Robert          *  IF       this is the first auto-opt maintained option
1089ea906c41SOllivier Robert          *    *AND*  we are doing a full help
1090ea906c41SOllivier Robert          *    *AND*  there are documentation options
1091ea906c41SOllivier Robert          *    *AND*  the last one was not a doc option,
1092ea906c41SOllivier Robert          *  THEN document that the remaining options are not user opts
1093ea906c41SOllivier Robert          */
10942b15cb3dSCy Schubert         if ((docCt > 0) && (ex_code == EXIT_SUCCESS)) {
10952b15cb3dSCy Schubert             if (opts->presetOptCt == optNo) {
10962b15cb3dSCy Schubert                 if ((od[-1].fOptState & OPTST_DOCUMENT) == 0)
10972b15cb3dSCy Schubert                     fprintf(option_usage_fp, argTypes.pzBrk, zAuto, title);
1098ea906c41SOllivier Robert 
10992b15cb3dSCy Schubert             } else if ((ct == 1) &&
11002b15cb3dSCy Schubert                        (opts->fOptSet & OPTPROC_VENDOR_OPT))
11012b15cb3dSCy Schubert                 fprintf(option_usage_fp, argTypes.pzBrk, zVendIntro, title);
11022b15cb3dSCy Schubert         }
11032b15cb3dSCy Schubert 
11042b15cb3dSCy Schubert         prt_one_usage(opts, od, &argTypes);
1105ea906c41SOllivier Robert 
1106ea906c41SOllivier Robert         /*
1107ea906c41SOllivier Robert          *  IF we were invoked because of the --help option,
1108ea906c41SOllivier Robert          *  THEN print all the extra info
1109ea906c41SOllivier Robert          */
1110ea906c41SOllivier Robert         if (ex_code == EXIT_SUCCESS)
11112b15cb3dSCy Schubert             prt_extd_usage(opts, od, title);
1112ea906c41SOllivier Robert 
11132b15cb3dSCy Schubert     } while (od++, optNo++, (--ct > 0));
1114ea906c41SOllivier Robert 
11152b15cb3dSCy Schubert     fputc(NL, option_usage_fp);
1116ea906c41SOllivier Robert }
1117ea906c41SOllivier Robert 
1118ea906c41SOllivier Robert 
11192b15cb3dSCy Schubert /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11202b15cb3dSCy Schubert /**
11212b15cb3dSCy Schubert  *  Print program details.
11222b15cb3dSCy Schubert  * @param[in] opts  the program option descriptor
1123ea906c41SOllivier Robert  */
1124ea906c41SOllivier Robert static void
prt_prog_detail(tOptions * opts)11252b15cb3dSCy Schubert prt_prog_detail(tOptions * opts)
1126ea906c41SOllivier Robert {
11272b15cb3dSCy Schubert     bool need_intro = (opts->papzHomeList == NULL);
1128ea906c41SOllivier Robert 
1129ea906c41SOllivier Robert     /*
11302b15cb3dSCy Schubert      *  Display all the places we look for config files, if we have
11312b15cb3dSCy Schubert      *  a list of directories to search.
1132ea906c41SOllivier Robert      */
11332b15cb3dSCy Schubert     if (! need_intro)
11342b15cb3dSCy Schubert         prt_ini_list(opts->papzHomeList, opts->pzRcName, opts->pzProgPath);
1135ea906c41SOllivier Robert 
1136ea906c41SOllivier Robert     /*
1137ea906c41SOllivier Robert      *  Let the user know about environment variable settings
1138ea906c41SOllivier Robert      */
11392b15cb3dSCy Schubert     if ((opts->fOptSet & OPTPROC_ENVIRON) != 0) {
11402b15cb3dSCy Schubert         if (need_intro)
1141ea906c41SOllivier Robert             fputs(zPresetIntro, option_usage_fp);
1142ea906c41SOllivier Robert 
11432b15cb3dSCy Schubert         fprintf(option_usage_fp, zExamineFmt, opts->pzPROGNAME);
1144ea906c41SOllivier Robert     }
1145ea906c41SOllivier Robert 
1146ea906c41SOllivier Robert     /*
1147ea906c41SOllivier Robert      *  IF we found an enumeration,
1148ea906c41SOllivier Robert      *  THEN hunt for it again.  Call the handler proc with a NULL
1149ea906c41SOllivier Robert      *       option struct pointer.  That tells it to display the keywords.
1150ea906c41SOllivier Robert      */
1151ea906c41SOllivier Robert     if (displayEnum) {
11522b15cb3dSCy Schubert         int        ct     = opts->optCt;
1153ea906c41SOllivier Robert         int        optNo  = 0;
11542b15cb3dSCy Schubert         tOptDesc * od     = opts->pOptDesc;
1155ea906c41SOllivier Robert 
11562b15cb3dSCy Schubert         fputc(NL, option_usage_fp);
1157ea906c41SOllivier Robert         fflush(option_usage_fp);
1158ea906c41SOllivier Robert         do  {
11592b15cb3dSCy Schubert             switch (OPTST_GET_ARGTYPE(od->fOptState)) {
1160ea906c41SOllivier Robert             case OPARG_TYPE_ENUMERATION:
1161ea906c41SOllivier Robert             case OPARG_TYPE_MEMBERSHIP:
11622b15cb3dSCy Schubert                 (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od);
1163ea906c41SOllivier Robert             }
11642b15cb3dSCy Schubert         } while (od++, optNo++, (--ct > 0));
1165ea906c41SOllivier Robert     }
1166ea906c41SOllivier Robert 
1167ea906c41SOllivier Robert     /*
1168ea906c41SOllivier Robert      *  If there is a detail string, now is the time for that.
1169ea906c41SOllivier Robert      */
11702b15cb3dSCy Schubert     if (opts->pzDetail != NULL)
11712b15cb3dSCy Schubert         fputs(opts->pzDetail, option_usage_fp);
1172ea906c41SOllivier Robert }
1173ea906c41SOllivier Robert 
1174ea906c41SOllivier Robert 
1175ea906c41SOllivier Robert /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1176ea906c41SOllivier Robert  *
1177ea906c41SOllivier Robert  *   OPTION LINE FORMATTING SETUP
1178ea906c41SOllivier Robert  *
1179ea906c41SOllivier Robert  *  The "OptFmt" formats receive three arguments:
1180ea906c41SOllivier Robert  *  1.  the type of the option's argument
1181ea906c41SOllivier Robert  *  2.  the long name of the option
1182ea906c41SOllivier Robert  *  3.  "YES" or "no ", depending on whether or not the option must appear
1183ea906c41SOllivier Robert  *      on the command line.
1184ea906c41SOllivier Robert  *  These formats are used immediately after the option flag (if used) has
1185ea906c41SOllivier Robert  *  been printed.
1186ea906c41SOllivier Robert  *
1187ea906c41SOllivier Robert  *  Set up the formatting for GNU-style output
1188ea906c41SOllivier Robert  */
1189ea906c41SOllivier Robert static int
setGnuOptFmts(tOptions * opts,char const ** ptxt)11902b15cb3dSCy Schubert setGnuOptFmts(tOptions * opts, char const ** ptxt)
1191ea906c41SOllivier Robert {
11922b15cb3dSCy Schubert     static char const zOneSpace[] = " ";
1193ea906c41SOllivier Robert     int  flen = 22;
11942b15cb3dSCy Schubert     *ptxt = zNoRq_ShrtTtl;
1195ea906c41SOllivier Robert 
1196ea906c41SOllivier Robert     argTypes.pzStr  = zGnuStrArg;
1197ea906c41SOllivier Robert     argTypes.pzReq  = zOneSpace;
1198ea906c41SOllivier Robert     argTypes.pzNum  = zGnuNumArg;
1199ea906c41SOllivier Robert     argTypes.pzKey  = zGnuKeyArg;
1200ea906c41SOllivier Robert     argTypes.pzKeyL = zGnuKeyLArg;
12012b15cb3dSCy Schubert     argTypes.pzTime = zGnuTimeArg;
12022b15cb3dSCy Schubert     argTypes.pzFile = zGnuFileArg;
1203ea906c41SOllivier Robert     argTypes.pzBool = zGnuBoolArg;
1204ea906c41SOllivier Robert     argTypes.pzNest = zGnuNestArg;
1205ea906c41SOllivier Robert     argTypes.pzOpt  = zGnuOptArg;
1206ea906c41SOllivier Robert     argTypes.pzNo   = zOneSpace;
1207ea906c41SOllivier Robert     argTypes.pzBrk  = zGnuBreak;
1208ea906c41SOllivier Robert     argTypes.pzNoF  = zSixSpaces;
1209ea906c41SOllivier Robert     argTypes.pzSpc  = zThreeSpaces;
1210ea906c41SOllivier Robert 
12112b15cb3dSCy Schubert     switch (opts->fOptSet & OPTPROC_L_N_S) {
1212ea906c41SOllivier Robert     case OPTPROC_L_N_S:    argTypes.pzOptFmt = zGnuOptFmt;     break;
1213ea906c41SOllivier Robert     case OPTPROC_LONGOPT:  argTypes.pzOptFmt = zGnuOptFmt;     break;
1214ea906c41SOllivier Robert     case 0:                argTypes.pzOptFmt = zGnuOptFmt + 2; break;
1215ea906c41SOllivier Robert     case OPTPROC_SHORTOPT:
1216ea906c41SOllivier Robert         argTypes.pzOptFmt = zShrtGnuOptFmt;
1217ea906c41SOllivier Robert         zGnuStrArg[0] = zGnuNumArg[0] = zGnuKeyArg[0] = zGnuBoolArg[0] = ' ';
1218ea906c41SOllivier Robert         argTypes.pzOpt = " [arg]";
1219ea906c41SOllivier Robert         flen = 8;
1220ea906c41SOllivier Robert         break;
1221ea906c41SOllivier Robert     }
1222ea906c41SOllivier Robert 
1223ea906c41SOllivier Robert     return flen;
1224ea906c41SOllivier Robert }
1225ea906c41SOllivier Robert 
1226ea906c41SOllivier Robert 
1227ea906c41SOllivier Robert /*
1228ea906c41SOllivier Robert  *  Standard (AutoOpts normal) option line formatting
1229ea906c41SOllivier Robert  */
1230ea906c41SOllivier Robert static int
setStdOptFmts(tOptions * opts,char const ** ptxt)12312b15cb3dSCy Schubert setStdOptFmts(tOptions * opts, char const ** ptxt)
1232ea906c41SOllivier Robert {
1233ea906c41SOllivier Robert     int  flen = 0;
1234ea906c41SOllivier Robert 
1235ea906c41SOllivier Robert     argTypes.pzStr  = zStdStrArg;
1236ea906c41SOllivier Robert     argTypes.pzReq  = zStdReqArg;
1237ea906c41SOllivier Robert     argTypes.pzNum  = zStdNumArg;
1238ea906c41SOllivier Robert     argTypes.pzKey  = zStdKeyArg;
1239ea906c41SOllivier Robert     argTypes.pzKeyL = zStdKeyLArg;
12402b15cb3dSCy Schubert     argTypes.pzTime = zStdTimeArg;
12412b15cb3dSCy Schubert     argTypes.pzFile = zStdFileArg;
1242ea906c41SOllivier Robert     argTypes.pzBool = zStdBoolArg;
1243ea906c41SOllivier Robert     argTypes.pzNest = zStdNestArg;
1244ea906c41SOllivier Robert     argTypes.pzOpt  = zStdOptArg;
1245ea906c41SOllivier Robert     argTypes.pzNo   = zStdNoArg;
1246ea906c41SOllivier Robert     argTypes.pzBrk  = zStdBreak;
1247ea906c41SOllivier Robert     argTypes.pzNoF  = zFiveSpaces;
1248ea906c41SOllivier Robert     argTypes.pzSpc  = zTwoSpaces;
1249ea906c41SOllivier Robert 
12502b15cb3dSCy Schubert     switch (opts->fOptSet & (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT)) {
1251ea906c41SOllivier Robert     case (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT):
12522b15cb3dSCy Schubert         *ptxt = zNoRq_ShrtTtl;
1253ea906c41SOllivier Robert         argTypes.pzOptFmt = zNrmOptFmt;
1254ea906c41SOllivier Robert         flen = 19;
1255ea906c41SOllivier Robert         break;
1256ea906c41SOllivier Robert 
1257ea906c41SOllivier Robert     case OPTPROC_NO_REQ_OPT:
12582b15cb3dSCy Schubert         *ptxt = zNoRq_NoShrtTtl;
1259ea906c41SOllivier Robert         argTypes.pzOptFmt = zNrmOptFmt;
1260ea906c41SOllivier Robert         flen = 19;
1261ea906c41SOllivier Robert         break;
1262ea906c41SOllivier Robert 
1263ea906c41SOllivier Robert     case OPTPROC_SHORTOPT:
12642b15cb3dSCy Schubert         *ptxt = zReq_ShrtTtl;
1265ea906c41SOllivier Robert         argTypes.pzOptFmt = zReqOptFmt;
1266ea906c41SOllivier Robert         flen = 24;
1267ea906c41SOllivier Robert         break;
1268ea906c41SOllivier Robert 
1269ea906c41SOllivier Robert     case 0:
12702b15cb3dSCy Schubert         *ptxt = zReq_NoShrtTtl;
1271ea906c41SOllivier Robert         argTypes.pzOptFmt = zReqOptFmt;
1272ea906c41SOllivier Robert         flen = 24;
1273ea906c41SOllivier Robert     }
1274ea906c41SOllivier Robert 
1275ea906c41SOllivier Robert     return flen;
1276ea906c41SOllivier Robert }
1277ea906c41SOllivier Robert 
12782b15cb3dSCy Schubert /** @}
12792b15cb3dSCy Schubert  *
1280ea906c41SOllivier Robert  * Local Variables:
1281ea906c41SOllivier Robert  * mode: C
1282ea906c41SOllivier Robert  * c-file-style: "stroustrup"
1283ea906c41SOllivier Robert  * indent-tabs-mode: nil
1284ea906c41SOllivier Robert  * End:
1285ea906c41SOllivier Robert  * end of autoopts/usage.c */
1286