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