summaryrefslogtreecommitdiffstats
path: root/sebhbsd/freebsd/contrib/ntp/sntp/libopts/usage.c
diff options
context:
space:
mode:
Diffstat (limited to 'sebhbsd/freebsd/contrib/ntp/sntp/libopts/usage.c')
-rw-r--r--sebhbsd/freebsd/contrib/ntp/sntp/libopts/usage.c1336
1 files changed, 1336 insertions, 0 deletions
diff --git a/sebhbsd/freebsd/contrib/ntp/sntp/libopts/usage.c b/sebhbsd/freebsd/contrib/ntp/sntp/libopts/usage.c
new file mode 100644
index 0000000..c652da7
--- /dev/null
+++ b/sebhbsd/freebsd/contrib/ntp/sntp/libopts/usage.c
@@ -0,0 +1,1336 @@
+
+/*
+ * \file usage.c
+ *
+ * This module implements the default usage procedure for
+ * Automated Options. It may be overridden, of course.
+ *
+ * @addtogroup autoopts
+ * @{
+ */
+/*
+ * Sort options:
+ --start=END-[S]TATIC-FORWARD --patt='^/\*($|[^:])' \
+ --out=xx.c key='^[a-zA-Z0-9_]+\(' --trail='^/\*:' \
+ --spac=2 --input=usage.c
+ */
+
+/*
+ * This file is part of AutoOpts, a companion to AutoGen.
+ * AutoOpts is free software.
+ * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved
+ *
+ * AutoOpts is available under any one of two licenses. The license
+ * in use must be one of these two and the choice is under the control
+ * of the user of the license.
+ *
+ * The GNU Lesser General Public License, version 3 or later
+ * See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ * The Modified Berkeley Software Distribution License
+ * See the file "COPYING.mbsd"
+ *
+ * These files have the following sha256 sums:
+ *
+ * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3
+ * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3
+ * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd
+ */
+
+/* = = = START-STATIC-FORWARD = = = */
+static unsigned int
+parse_usage_flags(ao_flag_names_t const * fnt, char const * txt);
+
+static inline bool
+do_gnu_usage(tOptions * pOpts);
+
+static inline bool
+skip_misuse_usage(tOptions * pOpts);
+
+static void
+print_offer_usage(tOptions * opts);
+
+static void
+print_usage_details(tOptions * opts, int exit_code);
+
+static void
+print_one_paragraph(char const * text, bool plain, FILE * fp);
+
+static void
+prt_conflicts(tOptions * opts, tOptDesc * od);
+
+static void
+prt_one_vendor(tOptions * opts, tOptDesc * od,
+ arg_types_t * argtp, char const * usefmt);
+
+static void
+prt_vendor_opts(tOptions * opts, char const * title);
+
+static void
+prt_extd_usage(tOptions * opts, tOptDesc * od, char const * title);
+
+static void
+prt_ini_list(char const * const * papz, char const * ini_file,
+ char const * path_nm);
+
+static void
+prt_preamble(tOptions * opts, tOptDesc * od, arg_types_t * at);
+
+static void
+prt_one_usage(tOptions * opts, tOptDesc * od, arg_types_t * at);
+
+static void
+prt_opt_usage(tOptions * opts, int ex_code, char const * title);
+
+static void
+prt_prog_detail(tOptions * opts);
+
+static int
+setGnuOptFmts(tOptions * opts, char const ** ptxt);
+
+static int
+setStdOptFmts(tOptions * opts, char const ** ptxt);
+/* = = = END-STATIC-FORWARD = = = */
+
+/**
+ * Parse the option usage flags string. Any parsing problems yield
+ * a zero (no flags set) result. This function is internal to
+ * set_usage_flags().
+ *
+ * @param[in] fnt Flag Name Table - maps a name to a mask
+ * @param[in] txt the text to process. If NULL, then
+ * getenv("AUTOOPTS_USAGE") is used.
+ * @returns a bit mask indicating which \a fnt entries were found.
+ */
+static unsigned int
+parse_usage_flags(ao_flag_names_t const * fnt, char const * txt)
+{
+ unsigned int res = 0;
+
+ /*
+ * The text may be passed in. If not, use the environment variable.
+ */
+ if (txt == NULL) {
+ txt = getenv("AUTOOPTS_USAGE");
+ if (txt == NULL)
+ return 0;
+ }
+
+ txt = SPN_WHITESPACE_CHARS(txt);
+ if (*txt == NUL)
+ return 0;
+
+ /*
+ * search the string for table entries. We must understand everything
+ * we see in the string, or we give up on it.
+ */
+ for (;;) {
+ int ix = 0;
+
+ for (;;) {
+ if (strneqvcmp(txt, fnt[ix].fnm_name, (int)fnt[ix].fnm_len) == 0)
+ break;
+ if (++ix >= AOUF_COUNT)
+ return 0;
+ }
+
+ /*
+ * Make sure we have a full match. Look for whitespace,
+ * a comma, or a NUL byte.
+ */
+ if (! IS_END_LIST_ENTRY_CHAR(txt[fnt[ix].fnm_len]))
+ return 0;
+
+ res |= 1U << ix;
+ txt = SPN_WHITESPACE_CHARS(txt + fnt[ix].fnm_len);
+
+ switch (*txt) {
+ case NUL:
+ return res;
+
+ case ',':
+ txt = SPN_WHITESPACE_CHARS(txt + 1);
+ /* Something must follow the comma */
+
+ default:
+ continue;
+ }
+ }
+}
+
+/**
+ * Set option usage flags. Any parsing problems yield no changes to options.
+ * Three different bits may be fiddled: \a OPTPROC_GNUUSAGE, \a OPTPROC_MISUSE
+ * and \a OPTPROC_COMPUTE.
+ *
+ * @param[in] flg_txt text to parse. If NULL, then the AUTOOPTS_USAGE
+ * environment variable is parsed.
+ * @param[in,out] opts the program option descriptor
+ */
+LOCAL void
+set_usage_flags(tOptions * opts, char const * flg_txt)
+{
+# define _aof_(_n, _f) { sizeof(#_n)-1, _f, #_n },
+ static ao_flag_names_t const fn_table[AOUF_COUNT] = {
+ AOFLAG_TABLE
+ };
+# undef _aof_
+
+ /*
+ * the flag word holds a bit for each selected table entry.
+ */
+ unsigned int flg = parse_usage_flags(fn_table, flg_txt);
+ if (flg == 0) return;
+
+ /*
+ * Ensure we do not have conflicting selections
+ */
+ {
+ static unsigned int const form_mask =
+ AOUF_gnu | AOUF_autoopts;
+ static unsigned int const misuse_mask =
+ AOUF_no_misuse_usage | AOUF_misuse_usage;
+ if ( ((flg & form_mask) == form_mask)
+ || ((flg & misuse_mask) == misuse_mask) )
+ return;
+ }
+
+ /*
+ * Now fiddle the fOptSet bits, based on settings.
+ * The OPTPROC_LONGOPT bit is immutable, thus if it is set,
+ * then fnm points to a mask off mask.
+ */
+ {
+ ao_flag_names_t const * fnm = fn_table;
+ for (;;) {
+ if ((flg & 1) != 0) {
+ if ((fnm->fnm_mask & OPTPROC_LONGOPT) != 0)
+ opts->fOptSet &= fnm->fnm_mask;
+ else opts->fOptSet |= fnm->fnm_mask;
+ }
+ flg >>= 1;
+ if (flg == 0)
+ break;
+ fnm++;
+ }
+ }
+}
+
+/*
+ * Figure out if we should try to format usage text sort-of like
+ * the way many GNU programs do.
+ */
+static inline bool
+do_gnu_usage(tOptions * pOpts)
+{
+ return (pOpts->fOptSet & OPTPROC_GNUUSAGE) ? true : false;
+}
+
+/*
+ * Figure out if we should try to format usage text sort-of like
+ * the way many GNU programs do.
+ */
+static inline bool
+skip_misuse_usage(tOptions * pOpts)
+{
+ return (pOpts->fOptSet & OPTPROC_MISUSE) ? true : false;
+}
+
+
+/*=export_func optionOnlyUsage
+ *
+ * what: Print usage text for just the options
+ * arg: + tOptions * + pOpts + program options descriptor +
+ * arg: + int + ex_code + exit code for calling exit(3) +
+ *
+ * doc:
+ * This routine will print only the usage for each option.
+ * This function may be used when the emitted usage must incorporate
+ * information not available to AutoOpts.
+=*/
+void
+optionOnlyUsage(tOptions * pOpts, int ex_code)
+{
+ char const * pOptTitle = NULL;
+
+ set_usage_flags(pOpts, NULL);
+ if ((ex_code != EXIT_SUCCESS) &&
+ skip_misuse_usage(pOpts))
+ return;
+
+ /*
+ * Determine which header and which option formatting strings to use
+ */
+ if (do_gnu_usage(pOpts))
+ (void)setGnuOptFmts(pOpts, &pOptTitle);
+ else
+ (void)setStdOptFmts(pOpts, &pOptTitle);
+
+ prt_opt_usage(pOpts, ex_code, pOptTitle);
+
+ fflush(option_usage_fp);
+ if (ferror(option_usage_fp) != 0)
+ fserr_exit(pOpts->pzProgName, zwriting, (option_usage_fp == stderr)
+ ? zstderr_name : zstdout_name);
+}
+
+/**
+ * Print a message suggesting how to get help.
+ *
+ * @param[in] opts the program options
+ */
+static void
+print_offer_usage(tOptions * opts)
+{
+ char help[24];
+
+ if (HAS_opt_usage_t(opts)) {
+ int ix = opts->presetOptCt;
+ tOptDesc * od = opts->pOptDesc + ix;
+ while (od->optUsage != AOUSE_HELP) {
+ if (++ix >= opts->optCt)
+ ao_bug(zmissing_help_msg);
+ od++;
+ }
+ switch (opts->fOptSet & (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)) {
+ case OPTPROC_SHORTOPT:
+ help[0] = '-';
+ help[1] = od->optValue;
+ help[2] = NUL;
+ break;
+
+ case OPTPROC_LONGOPT:
+ case (OPTPROC_LONGOPT | OPTPROC_SHORTOPT):
+ help[0] = help[1] = '-';
+ strncpy(help + 2, od->pz_Name, 20);
+ break;
+
+ case 0:
+ strncpy(help, od->pz_Name, 20);
+ break;
+ }
+
+ } else {
+ switch (opts->fOptSet & (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)) {
+ case OPTPROC_SHORTOPT:
+ strcpy(help, "-h");
+ break;
+
+ case OPTPROC_LONGOPT:
+ case (OPTPROC_LONGOPT | OPTPROC_SHORTOPT):
+ strcpy(help, "--help");
+ break;
+
+ case 0:
+ strcpy(help, "help");
+ break;
+ }
+ }
+
+ fprintf(option_usage_fp, zoffer_usage_fmt, opts->pzProgName, help);
+}
+
+/**
+ * Print information about each option.
+ *
+ * @param[in] opts the program options
+ * @param[in] exit_code whether or not there was a usage error reported.
+ * used to select full usage versus abbreviated.
+ */
+static void
+print_usage_details(tOptions * opts, int exit_code)
+{
+ {
+ char const * pOptTitle = NULL;
+ int flen;
+
+ /*
+ * Determine which header and which option formatting strings to use
+ */
+ if (do_gnu_usage(opts)) {
+ flen = setGnuOptFmts(opts, &pOptTitle);
+ sprintf(line_fmt_buf, zFmtFmt, flen);
+ fputc(NL, option_usage_fp);
+ }
+ else {
+ flen = setStdOptFmts(opts, &pOptTitle);
+ sprintf(line_fmt_buf, zFmtFmt, flen);
+
+ /*
+ * When we exit with EXIT_SUCCESS and the first option is a doc
+ * option, we do *NOT* want to emit the column headers.
+ * Otherwise, we do.
+ */
+ if ( (exit_code != EXIT_SUCCESS)
+ || ((opts->pOptDesc->fOptState & OPTST_DOCUMENT) == 0) )
+
+ fputs(pOptTitle, option_usage_fp);
+ }
+
+ flen = 4 - ((flen + 15) / 8);
+ if (flen > 0)
+ tab_skip_ct = flen;
+ prt_opt_usage(opts, exit_code, pOptTitle);
+ }
+
+ /*
+ * Describe the mechanics of denoting the options
+ */
+ switch (opts->fOptSet & OPTPROC_L_N_S) {
+ case OPTPROC_L_N_S: fputs(zFlagOkay, option_usage_fp); break;
+ case OPTPROC_SHORTOPT: break;
+ case OPTPROC_LONGOPT: fputs(zNoFlags, option_usage_fp); break;
+ case 0: fputs(zOptsOnly, option_usage_fp); break;
+ }
+
+ if ((opts->fOptSet & OPTPROC_NUM_OPT) != 0)
+ fputs(zNumberOpt, option_usage_fp);
+
+ if ((opts->fOptSet & OPTPROC_REORDER) != 0)
+ fputs(zReorder, option_usage_fp);
+
+ if (opts->pzExplain != NULL)
+ fputs(opts->pzExplain, option_usage_fp);
+
+ /*
+ * IF the user is asking for help (thus exiting with SUCCESS),
+ * THEN see what additional information we can provide.
+ */
+ if (exit_code == EXIT_SUCCESS)
+ prt_prog_detail(opts);
+
+ /*
+ * Give bug notification preference to the packager information
+ */
+ if (HAS_pzPkgDataDir(opts) && (opts->pzPackager != NULL))
+ fputs(opts->pzPackager, option_usage_fp);
+
+ else if (opts->pzBugAddr != NULL)
+ fprintf(option_usage_fp, zPlsSendBugs, opts->pzBugAddr);
+
+ fflush(option_usage_fp);
+
+ if (ferror(option_usage_fp) != 0)
+ fserr_exit(opts->pzProgName, zwriting, (option_usage_fp == stderr)
+ ? zstderr_name : zstdout_name);
+}
+
+static void
+print_one_paragraph(char const * text, bool plain, FILE * fp)
+{
+ if (plain) {
+#ifdef ENABLE_NLS
+#ifdef HAVE_LIBINTL_H
+#ifdef DEBUG_ENABLED
+#undef gettext
+#endif
+ char * buf = dgettext("libopts", text);
+ if (buf == text)
+ text = gettext(text);
+#endif /* HAVE_LIBINTL_H */
+#endif /* ENABLE_NLS */
+ fputs(text, fp);
+ }
+
+ else {
+ char const * t = optionQuoteString(text, LINE_SPLICE);
+ fprintf(fp, PUTS_FMT, t);
+ AGFREE(t);
+ }
+}
+
+/*=export_func optionPrintParagraphs
+ * private:
+ *
+ * what: Print a paragraph of usage text
+ * arg: + char const * + text + a block of text that has bee i18n-ed +
+ * arg: + bool + plain + false -> wrap text in fputs() +
+ * arg: + FILE * + fp + the stream file pointer for output +
+ *
+ * doc:
+ * This procedure is called in two contexts: when a full or short usage text
+ * has been provided for display, and when autogen is assembling a list of
+ * translatable texts in the optmain.tlib template. In the former case, \a
+ * plain is set to \a true, otherwise \a false.
+ *
+ * Anything less than 256 characters in size is printed as a single unit.
+ * Otherwise, paragraphs are detected. A paragraph break is defined as just
+ * before a non-empty line preceded by two newlines or a line that starts
+ * with at least one space character but fewer than 8 space characters.
+ * Lines indented with tabs or more than 7 spaces are considered continuation
+ * lines.
+ *
+ * If 'plain' is true, we are emitting text for a user to see. So, if it is
+ * true and NLS is not enabled, then just write the whole thing at once.
+=*/
+void
+optionPrintParagraphs(char const * text, bool plain, FILE * fp)
+{
+ size_t len = strlen(text);
+ char * buf;
+#ifndef ENABLE_NLS
+ if (plain || (len < 256))
+#else
+ if (len < 256)
+#endif
+ {
+ print_one_paragraph(text, plain, fp);
+ return;
+ }
+
+ AGDUPSTR(buf, text, "ppara");
+ text = buf;
+
+ for (;;) {
+ char * scan;
+
+ if (len < 256) {
+ done:
+ print_one_paragraph(buf, plain, fp);
+ break;
+ }
+ scan = buf;
+
+ try_longer:
+ scan = strchr(scan, NL);
+ if (scan == NULL)
+ goto done;
+
+ if ((scan - buf) < 40) {
+ scan++;
+ goto try_longer;
+ }
+
+ scan++;
+ if ((! isspace((int)*scan)) || (*scan == HT))
+ /*
+ * line starts with tab or non-whitespace --> continuation
+ */
+ goto try_longer;
+
+ if (*scan == NL) {
+ /*
+ * Double newline -> paragraph break
+ * Include all newlines in current paragraph.
+ */
+ while (*++scan == NL) /*continue*/;
+
+ } else {
+ char * p = scan;
+ int sp_ct = 0;
+
+ while (*p == ' ') {
+ if (++sp_ct >= 8) {
+ /*
+ * Too many spaces --> continuation line
+ */
+ scan = p;
+ goto try_longer;
+ }
+ p++;
+ }
+ }
+
+ /*
+ * "scan" points to the first character of a paragraph or the
+ * terminating NUL byte.
+ */
+ {
+ char svch = *scan;
+ *scan = NUL;
+ print_one_paragraph(buf, plain, fp);
+ len -= scan - buf;
+ if (len <= 0)
+ break;
+ *scan = svch;
+ buf = scan;
+ }
+ }
+ AGFREE(text);
+}
+
+/*=export_func optionUsage
+ * private:
+ *
+ * what: Print usage text
+ * arg: + tOptions * + opts + program options descriptor +
+ * arg: + int + exitCode + exit code for calling exit(3) +
+ *
+ * doc:
+ * This routine will print usage in both GNU-standard and AutoOpts-expanded
+ * formats. The descriptor specifies the default, but AUTOOPTS_USAGE will
+ * over-ride this, providing the value of it is set to either "gnu" or
+ * "autoopts". This routine will @strong{not} return.
+ *
+ * If "exitCode" is "AO_EXIT_REQ_USAGE" (normally 64), then output will to
+ * to stdout and the actual exit code will be "EXIT_SUCCESS".
+=*/
+void
+optionUsage(tOptions * opts, int usage_exit_code)
+{
+ int exit_code = (usage_exit_code == AO_EXIT_REQ_USAGE)
+ ? EXIT_SUCCESS : usage_exit_code;
+
+ displayEnum = false;
+ set_usage_flags(opts, NULL);
+
+ /*
+ * Paged usage will preset option_usage_fp to an output file.
+ * If it hasn't already been set, then set it to standard output
+ * on successful exit (help was requested), otherwise error out.
+ *
+ * Test the version before obtaining pzFullUsage or pzShortUsage.
+ * These fields do not exist before revision 30.
+ */
+ {
+ char const * pz;
+
+ if (exit_code == EXIT_SUCCESS) {
+ pz = (opts->structVersion >= 30 * 4096)
+ ? opts->pzFullUsage : NULL;
+
+ if (option_usage_fp == NULL)
+ option_usage_fp = print_exit ? stderr : stdout;
+
+ } else {
+ pz = (opts->structVersion >= 30 * 4096)
+ ? opts->pzShortUsage : NULL;
+
+ if (option_usage_fp == NULL)
+ option_usage_fp = stderr;
+ }
+
+ if (((opts->fOptSet & OPTPROC_COMPUTE) == 0) && (pz != NULL)) {
+ if ((opts->fOptSet & OPTPROC_TRANSLATE) != 0)
+ optionPrintParagraphs(pz, true, option_usage_fp);
+ else
+ fputs(pz, option_usage_fp);
+ goto flush_and_exit;
+ }
+ }
+
+ fprintf(option_usage_fp, opts->pzUsageTitle, opts->pzProgName);
+
+ if ((exit_code == EXIT_SUCCESS) ||
+ (! skip_misuse_usage(opts)))
+
+ print_usage_details(opts, usage_exit_code);
+ else
+ print_offer_usage(opts);
+
+ flush_and_exit:
+ fflush(option_usage_fp);
+ if (ferror(option_usage_fp) != 0)
+ fserr_exit(opts->pzProgName, zwriting, (option_usage_fp == stdout)
+ ? zstdout_name : zstderr_name);
+
+ option_exits(exit_code);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * PER OPTION TYPE USAGE INFORMATION
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/**
+ * print option conflicts.
+ *
+ * @param opts the program option descriptor
+ * @param od the option descriptor
+ */
+static void
+prt_conflicts(tOptions * opts, tOptDesc * od)
+{
+ const int * opt_no;
+ fputs(zTabHyp + tab_skip_ct, option_usage_fp);
+
+ /*
+ * REQUIRED:
+ */
+ if (od->pOptMust != NULL) {
+ opt_no = od->pOptMust;
+
+ if (opt_no[1] == NO_EQUIVALENT) {
+ fprintf(option_usage_fp, zReqOne,
+ opts->pOptDesc[*opt_no].pz_Name);
+ } else {
+ fputs(zReqThese, option_usage_fp);
+ for (;;) {
+ fprintf(option_usage_fp, zTabout + tab_skip_ct,
+ opts->pOptDesc[*opt_no].pz_Name);
+ if (*++opt_no == NO_EQUIVALENT)
+ break;
+ }
+ }
+
+ if (od->pOptCant != NULL)
+ fputs(zTabHypAnd + tab_skip_ct, option_usage_fp);
+ }
+
+ /*
+ * CONFLICTS:
+ */
+ if (od->pOptCant == NULL)
+ return;
+
+ opt_no = od->pOptCant;
+
+ if (opt_no[1] == NO_EQUIVALENT) {
+ fprintf(option_usage_fp, zProhibOne,
+ opts->pOptDesc[*opt_no].pz_Name);
+ return;
+ }
+
+ fputs(zProhib, option_usage_fp);
+ for (;;) {
+ fprintf(option_usage_fp, zTabout + tab_skip_ct,
+ opts->pOptDesc[*opt_no].pz_Name);
+ if (*++opt_no == NO_EQUIVALENT)
+ break;
+ }
+}
+
+/**
+ * Print the usage information for a single vendor option.
+ *
+ * @param[in] opts the program option descriptor
+ * @param[in] od the option descriptor
+ * @param[in] argtp names of the option argument types
+ * @param[in] usefmt format for primary usage line
+ */
+static void
+prt_one_vendor(tOptions * opts, tOptDesc * od,
+ arg_types_t * argtp, char const * usefmt)
+{
+ prt_preamble(opts, od, argtp);
+
+ {
+ char z[ 80 ];
+ char const * pzArgType;
+
+ /*
+ * Determine the argument type string first on its usage, then,
+ * when the option argument is required, base the type string on the
+ * argument type.
+ */
+ if (od->fOptState & OPTST_ARG_OPTIONAL) {
+ pzArgType = argtp->pzOpt;
+
+ } else switch (OPTST_GET_ARGTYPE(od->fOptState)) {
+ case OPARG_TYPE_NONE: pzArgType = argtp->pzNo; break;
+ case OPARG_TYPE_ENUMERATION: pzArgType = argtp->pzKey; break;
+ case OPARG_TYPE_FILE: pzArgType = argtp->pzFile; break;
+ case OPARG_TYPE_MEMBERSHIP: pzArgType = argtp->pzKeyL; break;
+ case OPARG_TYPE_BOOLEAN: pzArgType = argtp->pzBool; break;
+ case OPARG_TYPE_NUMERIC: pzArgType = argtp->pzNum; break;
+ case OPARG_TYPE_HIERARCHY: pzArgType = argtp->pzNest; break;
+ case OPARG_TYPE_STRING: pzArgType = argtp->pzStr; break;
+ case OPARG_TYPE_TIME: pzArgType = argtp->pzTime; break;
+ default: goto bogus_desc;
+ }
+
+ pzArgType = SPN_WHITESPACE_CHARS(pzArgType);
+ if (*pzArgType == NUL)
+ snprintf(z, sizeof(z), "%s", od->pz_Name);
+ else
+ snprintf(z, sizeof(z), "%s=%s", od->pz_Name, pzArgType);
+ fprintf(option_usage_fp, usefmt, z, od->pzText);
+
+ switch (OPTST_GET_ARGTYPE(od->fOptState)) {
+ case OPARG_TYPE_ENUMERATION:
+ case OPARG_TYPE_MEMBERSHIP:
+ displayEnum = (od->pOptProc != NULL) ? true : displayEnum;
+ }
+ }
+
+ return;
+
+ bogus_desc:
+ fprintf(stderr, zbad_od, opts->pzProgName, od->pz_Name);
+ ao_bug(zbad_arg_type_msg);
+}
+
+/**
+ * Print the long options processed with "-W". These options will be the
+ * ones that do *not* have flag characters.
+ *
+ * @param opts the program option descriptor
+ * @param title the title for the options
+ */
+static void
+prt_vendor_opts(tOptions * opts, char const * title)
+{
+ static unsigned int const not_vended_mask =
+ OPTST_NO_USAGE_MASK | OPTST_DOCUMENT;
+
+ static char const vfmtfmt[] = "%%-%us %%s\n";
+ char vfmt[sizeof(vfmtfmt)];
+
+ /*
+ * Only handle client specified options. The "vendor option" follows
+ * "presetOptCt", so we won't loop/recurse indefinitely.
+ */
+ int ct = opts->presetOptCt;
+ tOptDesc * od = opts->pOptDesc;
+ fprintf(option_usage_fp, zTabout + tab_skip_ct, zVendOptsAre);
+
+ {
+ size_t nmlen = 0;
+ do {
+ size_t l;
+ if ( ((od->fOptState & not_vended_mask) != 0)
+ || IS_GRAPHIC_CHAR(od->optValue))
+ continue;
+
+ l = strlen(od->pz_Name);
+ if (l > nmlen) nmlen = l;
+ } while (od++, (--ct > 0));
+
+ snprintf(vfmt, sizeof(vfmt), vfmtfmt, (unsigned int)nmlen + 4);
+ }
+
+ if (tab_skip_ct > 0)
+ tab_skip_ct--;
+
+ ct = opts->presetOptCt;
+ od = opts->pOptDesc;
+
+ do {
+ if ( ((od->fOptState & not_vended_mask) != 0)
+ || IS_GRAPHIC_CHAR(od->optValue))
+ continue;
+
+ prt_one_vendor(opts, od, &argTypes, vfmt);
+ prt_extd_usage(opts, od, title);
+
+ } while (od++, (--ct > 0));
+
+ /* no need to restore "tab_skip_ct" - options are done now */
+}
+
+/**
+ * Print extended usage. Usage/help was requested.
+ *
+ * @param opts the program option descriptor
+ * @param od the option descriptor
+ * @param title the title for the options
+ */
+static void
+prt_extd_usage(tOptions * opts, tOptDesc * od, char const * title)
+{
+ if ( ((opts->fOptSet & OPTPROC_VENDOR_OPT) != 0)
+ && (od->optActualValue == VENDOR_OPTION_VALUE)) {
+ prt_vendor_opts(opts, title);
+ return;
+ }
+
+ /*
+ * IF there are option conflicts or dependencies,
+ * THEN print them here.
+ */
+ if ((od->pOptMust != NULL) || (od->pOptCant != NULL))
+ prt_conflicts(opts, od);
+
+ /*
+ * IF there is a disablement string
+ * THEN print the disablement info
+ */
+ if (od->pz_DisableName != NULL )
+ fprintf(option_usage_fp, zDis + tab_skip_ct, od->pz_DisableName);
+
+ /*
+ * Check for argument types that have callbacks with magical properties
+ */
+ switch (OPTST_GET_ARGTYPE(od->fOptState)) {
+ case OPARG_TYPE_NUMERIC:
+ /*
+ * IF the numeric option has a special callback,
+ * THEN call it, requesting the range or other special info
+ */
+ if ( (od->pOptProc != NULL)
+ && (od->pOptProc != optionNumericVal) ) {
+ (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od);
+ }
+ break;
+
+ case OPARG_TYPE_FILE:
+ (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od);
+ break;
+ }
+
+ /*
+ * IF the option defaults to being enabled,
+ * THEN print that out
+ */
+ if (od->fOptState & OPTST_INITENABLED)
+ fputs(zEnab + tab_skip_ct, option_usage_fp);
+
+ /*
+ * IF the option is in an equivalence class
+ * AND not the designated lead
+ * THEN print equivalence and leave it at that.
+ */
+ if ( (od->optEquivIndex != NO_EQUIVALENT)
+ && (od->optEquivIndex != od->optActualIndex ) ) {
+ fprintf(option_usage_fp, zalt_opt + tab_skip_ct,
+ opts->pOptDesc[ od->optEquivIndex ].pz_Name);
+ return;
+ }
+
+ /*
+ * IF this particular option can NOT be preset
+ * AND some form of presetting IS allowed,
+ * AND it is not an auto-managed option (e.g. --help, et al.)
+ * THEN advise that this option may not be preset.
+ */
+ if ( ((od->fOptState & OPTST_NO_INIT) != 0)
+ && ( (opts->papzHomeList != NULL)
+ || (opts->pzPROGNAME != NULL)
+ )
+ && (od->optIndex < opts->presetOptCt)
+ )
+
+ fputs(zNoPreset + tab_skip_ct, option_usage_fp);
+
+ /*
+ * Print the appearance requirements.
+ */
+ if (OPTST_GET_ARGTYPE(od->fOptState) == OPARG_TYPE_MEMBERSHIP)
+ fputs(zMembers + tab_skip_ct, option_usage_fp);
+
+ else switch (od->optMinCt) {
+ case 1:
+ case 0:
+ switch (od->optMaxCt) {
+ case 0: fputs(zPreset + tab_skip_ct, option_usage_fp); break;
+ case NOLIMIT: fputs(zNoLim + tab_skip_ct, option_usage_fp); break;
+ case 1: break;
+ /*
+ * IF the max is more than one but limited, print "UP TO" message
+ */
+ default:
+ fprintf(option_usage_fp, zUpTo + tab_skip_ct, od->optMaxCt); break;
+ }
+ break;
+
+ default:
+ /*
+ * More than one is required. Print the range.
+ */
+ fprintf(option_usage_fp, zMust + tab_skip_ct,
+ od->optMinCt, od->optMaxCt);
+ }
+
+ if ( NAMED_OPTS(opts)
+ && (opts->specOptIdx.default_opt == od->optIndex))
+ fputs(zDefaultOpt + tab_skip_ct, option_usage_fp);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/**
+ * Figure out where all the initialization files might live. This requires
+ * translating some environment variables and testing to see if a name is a
+ * directory or a file. It's squishy, but important to tell users how to
+ * find these files.
+ *
+ * @param[in] papz search path
+ * @param[out] ini_file an output buffer of AG_PATH_MAX+1 bytes
+ * @param[in] path_nm the name of the file we're hunting for
+ */
+static void
+prt_ini_list(char const * const * papz, char const * ini_file,
+ char const * path_nm)
+{
+ char pth_buf[AG_PATH_MAX+1];
+
+ fputs(zPresetIntro, option_usage_fp);
+
+ for (;;) {
+ char const * path = *(papz++);
+ char const * nm_buf = pth_buf;
+
+ if (path == NULL)
+ break;
+
+ /*
+ * Ignore any invalid paths
+ */
+ if (! optionMakePath(pth_buf, (int)sizeof(pth_buf), path, path_nm))
+ nm_buf = path;
+
+ /*
+ * Expand paths that are relative to the executable or installation
+ * directories. Leave alone paths that use environment variables.
+ */
+ else if ((*path == '$')
+ && ((path[1] == '$') || (path[1] == '@')))
+ path = nm_buf;
+
+ /*
+ * Print the name of the "homerc" file. If the "rcfile" name is
+ * not empty, we may or may not print that, too...
+ */
+ fprintf(option_usage_fp, zPathFmt, path);
+ if (*ini_file != NUL) {
+ struct stat sb;
+
+ /*
+ * IF the "homerc" file is a directory,
+ * then append the "rcfile" name.
+ */
+ if ((stat(nm_buf, &sb) == 0) && S_ISDIR(sb.st_mode)) {
+ fputc(DIRCH, option_usage_fp);
+ fputs(ini_file, option_usage_fp);
+ }
+ }
+
+ fputc(NL, option_usage_fp);
+ }
+}
+
+/**
+ * Print the usage line preamble text
+ *
+ * @param opts the program option descriptor
+ * @param od the option descriptor
+ * @param at names of the option argument types
+ */
+static void
+prt_preamble(tOptions * opts, tOptDesc * od, arg_types_t * at)
+{
+ /*
+ * Flag prefix: IF no flags at all, then omit it. If not printable
+ * (not allowed for this option), then blank, else print it.
+ * Follow it with a comma if we are doing GNU usage and long
+ * opts are to be printed too.
+ */
+ if ((opts->fOptSet & OPTPROC_SHORTOPT) == 0)
+ fputs(at->pzSpc, option_usage_fp);
+
+ else if (! IS_GRAPHIC_CHAR(od->optValue)) {
+ if ( (opts->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
+ == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
+ fputc(' ', option_usage_fp);
+ fputs(at->pzNoF, option_usage_fp);
+
+ } else {
+ fprintf(option_usage_fp, " -%c", od->optValue);
+ if ( (opts->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
+ == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
+ fputs(", ", option_usage_fp);
+ }
+}
+
+/**
+ * Print the usage information for a single option.
+ *
+ * @param opts the program option descriptor
+ * @param od the option descriptor
+ * @param at names of the option argument types
+ */
+static void
+prt_one_usage(tOptions * opts, tOptDesc * od, arg_types_t * at)
+{
+ prt_preamble(opts, od, at);
+
+ {
+ char z[80];
+ char const * atyp;
+
+ /*
+ * Determine the argument type string first on its usage, then,
+ * when the option argument is required, base the type string on the
+ * argument type.
+ */
+ if (od->fOptState & OPTST_ARG_OPTIONAL) {
+ atyp = at->pzOpt;
+
+ } else switch (OPTST_GET_ARGTYPE(od->fOptState)) {
+ case OPARG_TYPE_NONE: atyp = at->pzNo; break;
+ case OPARG_TYPE_ENUMERATION: atyp = at->pzKey; break;
+ case OPARG_TYPE_FILE: atyp = at->pzFile; break;
+ case OPARG_TYPE_MEMBERSHIP: atyp = at->pzKeyL; break;
+ case OPARG_TYPE_BOOLEAN: atyp = at->pzBool; break;
+ case OPARG_TYPE_NUMERIC: atyp = at->pzNum; break;
+ case OPARG_TYPE_HIERARCHY: atyp = at->pzNest; break;
+ case OPARG_TYPE_STRING: atyp = at->pzStr; break;
+ case OPARG_TYPE_TIME: atyp = at->pzTime; break;
+ default: goto bogus_desc;
+ }
+
+#ifdef _WIN32
+ if (at->pzOptFmt == zGnuOptFmt)
+ snprintf(z, sizeof(z), "--%s%s", od->pz_Name, atyp);
+ else if (at->pzOptFmt == zGnuOptFmt + 2)
+ snprintf(z, sizeof(z), "%s%s", od->pz_Name, atyp);
+ else
+#endif
+ snprintf(z, sizeof(z), at->pzOptFmt, atyp, od->pz_Name,
+ (od->optMinCt != 0) ? at->pzReq : at->pzOpt);
+
+ fprintf(option_usage_fp, line_fmt_buf, z, od->pzText);
+
+ switch (OPTST_GET_ARGTYPE(od->fOptState)) {
+ case OPARG_TYPE_ENUMERATION:
+ case OPARG_TYPE_MEMBERSHIP:
+ displayEnum = (od->pOptProc != NULL) ? true : displayEnum;
+ }
+ }
+
+ return;
+
+ bogus_desc:
+ fprintf(stderr, zbad_od, opts->pzProgName, od->pz_Name);
+ option_exits(EX_SOFTWARE);
+}
+
+/**
+ * Print out the usage information for just the options.
+ */
+static void
+prt_opt_usage(tOptions * opts, int ex_code, char const * title)
+{
+ int ct = opts->optCt;
+ int optNo = 0;
+ tOptDesc * od = opts->pOptDesc;
+ int docCt = 0;
+
+ do {
+ /*
+ * no usage --> disallowed on command line (OPTST_NO_COMMAND), or
+ * deprecated -- strongly discouraged (OPTST_DEPRECATED), or
+ * compiled out of current object code (OPTST_OMITTED)
+ */
+ if ((od->fOptState & OPTST_NO_USAGE_MASK) != 0) {
+
+ /*
+ * IF this is a compiled-out option
+ * *AND* usage was requested with "omitted-usage"
+ * *AND* this is NOT abbreviated usage
+ * THEN display this option.
+ */
+ if ( (od->fOptState == (OPTST_OMITTED | OPTST_NO_INIT))
+ && (od->pz_Name != NULL)
+ && (ex_code == EXIT_SUCCESS)) {
+
+ char const * why_pz =
+ (od->pzText == NULL) ? zDisabledWhy : od->pzText;
+ prt_preamble(opts, od, &argTypes);
+ fprintf(option_usage_fp, zDisabledOpt, od->pz_Name, why_pz);
+ }
+
+ continue;
+ }
+
+ if ((od->fOptState & OPTST_DOCUMENT) != 0) {
+ if (ex_code == EXIT_SUCCESS) {
+ fprintf(option_usage_fp, argTypes.pzBrk, od->pzText,
+ title);
+ docCt++;
+ }
+
+ continue;
+ }
+
+ /* Skip name only options when we have a vendor option */
+ if ( ((opts->fOptSet & OPTPROC_VENDOR_OPT) != 0)
+ && (! IS_GRAPHIC_CHAR(od->optValue)))
+ continue;
+
+ /*
+ * IF this is the first auto-opt maintained option
+ * *AND* we are doing a full help
+ * *AND* there are documentation options
+ * *AND* the last one was not a doc option,
+ * THEN document that the remaining options are not user opts
+ */
+ if ((docCt > 0) && (ex_code == EXIT_SUCCESS)) {
+ if (opts->presetOptCt == optNo) {
+ if ((od[-1].fOptState & OPTST_DOCUMENT) == 0)
+ fprintf(option_usage_fp, argTypes.pzBrk, zAuto, title);
+
+ } else if ((ct == 1) &&
+ (opts->fOptSet & OPTPROC_VENDOR_OPT))
+ fprintf(option_usage_fp, argTypes.pzBrk, zVendIntro, title);
+ }
+
+ prt_one_usage(opts, od, &argTypes);
+
+ /*
+ * IF we were invoked because of the --help option,
+ * THEN print all the extra info
+ */
+ if (ex_code == EXIT_SUCCESS)
+ prt_extd_usage(opts, od, title);
+
+ } while (od++, optNo++, (--ct > 0));
+
+ fputc(NL, option_usage_fp);
+}
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/**
+ * Print program details.
+ * @param[in] opts the program option descriptor
+ */
+static void
+prt_prog_detail(tOptions * opts)
+{
+ bool need_intro = (opts->papzHomeList == NULL);
+
+ /*
+ * Display all the places we look for config files, if we have
+ * a list of directories to search.
+ */
+ if (! need_intro)
+ prt_ini_list(opts->papzHomeList, opts->pzRcName, opts->pzProgPath);
+
+ /*
+ * Let the user know about environment variable settings
+ */
+ if ((opts->fOptSet & OPTPROC_ENVIRON) != 0) {
+ if (need_intro)
+ fputs(zPresetIntro, option_usage_fp);
+
+ fprintf(option_usage_fp, zExamineFmt, opts->pzPROGNAME);
+ }
+
+ /*
+ * IF we found an enumeration,
+ * THEN hunt for it again. Call the handler proc with a NULL
+ * option struct pointer. That tells it to display the keywords.
+ */
+ if (displayEnum) {
+ int ct = opts->optCt;
+ int optNo = 0;
+ tOptDesc * od = opts->pOptDesc;
+
+ fputc(NL, option_usage_fp);
+ fflush(option_usage_fp);
+ do {
+ switch (OPTST_GET_ARGTYPE(od->fOptState)) {
+ case OPARG_TYPE_ENUMERATION:
+ case OPARG_TYPE_MEMBERSHIP:
+ (*(od->pOptProc))(OPTPROC_EMIT_USAGE, od);
+ }
+ } while (od++, optNo++, (--ct > 0));
+ }
+
+ /*
+ * If there is a detail string, now is the time for that.
+ */
+ if (opts->pzDetail != NULL)
+ fputs(opts->pzDetail, option_usage_fp);
+}
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * OPTION LINE FORMATTING SETUP
+ *
+ * The "OptFmt" formats receive three arguments:
+ * 1. the type of the option's argument
+ * 2. the long name of the option
+ * 3. "YES" or "no ", depending on whether or not the option must appear
+ * on the command line.
+ * These formats are used immediately after the option flag (if used) has
+ * been printed.
+ *
+ * Set up the formatting for GNU-style output
+ */
+static int
+setGnuOptFmts(tOptions * opts, char const ** ptxt)
+{
+ static char const zOneSpace[] = " ";
+ int flen = 22;
+ *ptxt = zNoRq_ShrtTtl;
+
+ argTypes.pzStr = zGnuStrArg;
+ argTypes.pzReq = zOneSpace;
+ argTypes.pzNum = zGnuNumArg;
+ argTypes.pzKey = zGnuKeyArg;
+ argTypes.pzKeyL = zGnuKeyLArg;
+ argTypes.pzTime = zGnuTimeArg;
+ argTypes.pzFile = zGnuFileArg;
+ argTypes.pzBool = zGnuBoolArg;
+ argTypes.pzNest = zGnuNestArg;
+ argTypes.pzOpt = zGnuOptArg;
+ argTypes.pzNo = zOneSpace;
+ argTypes.pzBrk = zGnuBreak;
+ argTypes.pzNoF = zSixSpaces;
+ argTypes.pzSpc = zThreeSpaces;
+
+ switch (opts->fOptSet & OPTPROC_L_N_S) {
+ case OPTPROC_L_N_S: argTypes.pzOptFmt = zGnuOptFmt; break;
+ case OPTPROC_LONGOPT: argTypes.pzOptFmt = zGnuOptFmt; break;
+ case 0: argTypes.pzOptFmt = zGnuOptFmt + 2; break;
+ case OPTPROC_SHORTOPT:
+ argTypes.pzOptFmt = zShrtGnuOptFmt;
+ zGnuStrArg[0] = zGnuNumArg[0] = zGnuKeyArg[0] = zGnuBoolArg[0] = ' ';
+ argTypes.pzOpt = " [arg]";
+ flen = 8;
+ break;
+ }
+
+ return flen;
+}
+
+
+/*
+ * Standard (AutoOpts normal) option line formatting
+ */
+static int
+setStdOptFmts(tOptions * opts, char const ** ptxt)
+{
+ int flen = 0;
+
+ argTypes.pzStr = zStdStrArg;
+ argTypes.pzReq = zStdReqArg;
+ argTypes.pzNum = zStdNumArg;
+ argTypes.pzKey = zStdKeyArg;
+ argTypes.pzKeyL = zStdKeyLArg;
+ argTypes.pzTime = zStdTimeArg;
+ argTypes.pzFile = zStdFileArg;
+ argTypes.pzBool = zStdBoolArg;
+ argTypes.pzNest = zStdNestArg;
+ argTypes.pzOpt = zStdOptArg;
+ argTypes.pzNo = zStdNoArg;
+ argTypes.pzBrk = zStdBreak;
+ argTypes.pzNoF = zFiveSpaces;
+ argTypes.pzSpc = zTwoSpaces;
+
+ switch (opts->fOptSet & (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT)) {
+ case (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT):
+ *ptxt = zNoRq_ShrtTtl;
+ argTypes.pzOptFmt = zNrmOptFmt;
+ flen = 19;
+ break;
+
+ case OPTPROC_NO_REQ_OPT:
+ *ptxt = zNoRq_NoShrtTtl;
+ argTypes.pzOptFmt = zNrmOptFmt;
+ flen = 19;
+ break;
+
+ case OPTPROC_SHORTOPT:
+ *ptxt = zReq_ShrtTtl;
+ argTypes.pzOptFmt = zReqOptFmt;
+ flen = 24;
+ break;
+
+ case 0:
+ *ptxt = zReq_NoShrtTtl;
+ argTypes.pzOptFmt = zReqOptFmt;
+ flen = 24;
+ }
+
+ return flen;
+}
+
+/** @}
+ *
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/usage.c */