📄 argp-help.c
字号:
static voidindent_to (argp_fmtstream_t stream, unsigned col){ int needed = col - __argp_fmtstream_point (stream); while (needed-- > 0) __argp_fmtstream_putc (stream, ' ');}/* Output to STREAM either a space, or a newline if there isn't room for at least ENSURE characters before the right margin. */static voidspace (argp_fmtstream_t stream, size_t ensure){ if (__argp_fmtstream_point (stream) + ensure >= __argp_fmtstream_rmargin (stream)) __argp_fmtstream_putc (stream, '\n'); else __argp_fmtstream_putc (stream, ' ');}/* If the option REAL has an argument, we print it in using the printf format REQ_FMT or OPT_FMT depending on whether it's a required or optional argument. */static voidarg (const struct argp_option *real, const char *req_fmt, const char *opt_fmt, argp_fmtstream_t stream){ if (real->arg) if (real->flags & OPTION_ARG_OPTIONAL) __argp_fmtstream_printf (stream, opt_fmt, gettext (real->arg)); else __argp_fmtstream_printf (stream, req_fmt, gettext (real->arg));}/* Helper functions for hol_entry_help. *//* State used during the execution of hol_help. */struct hol_help_state { /* PREV_ENTRY should contain the last entry printed before this, or null if it's the first, and if an ENTRY is in a different group, and SEP_GROUPS is true, then a blank line will be printed before any output. SEP_GROUPS is also set to true if a user-specified group header is printed. */ struct hol_entry *prev_entry; int sep_groups; /* True if a duplicate option argument was suppressed (only ever set if UPARAMS.dup_args is false). */ int suppressed_dup_arg;};/* Some state used while printing a help entry (used to communicate with helper functions). See the doc for hol_entry_help for more info, as most of the fields are copied from its arguments. */struct pentry_state{ const struct hol_entry *entry; argp_fmtstream_t stream; struct hol_help_state *hhstate; /* True if nothing's been printed so far. */ int first; /* If non-zero, the state that was used to print this help. */ const struct argp_state *state;};/* If a user doc filter should be applied to DOC, do so. */static const char *filter_doc (const char *doc, int key, const struct argp *argp, const struct argp_state *state){ if (argp->help_filter) /* We must apply a user filter to this output. */ { void *input = __argp_input (argp, state); return (*argp->help_filter) (key, doc, input); } else /* No filter. */ return (char *)doc; }/* Prints STR as a header line, with the margin lines set appropiately, and notes the fact that groups should be separated with a blank line. ARGP is the argp that should dictate any user doc filtering to take place. Note that the previous wrap margin isn't restored, but the left margin is reset to 0. */static voidprint_header (const char *str, const struct argp *argp, struct pentry_state *pest){ const char *tstr = gettext (str); const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_HEADER, argp, pest->state); if (fstr) { if (*fstr) { if (pest->hhstate->prev_entry) /* Precede with a blank line. */ __argp_fmtstream_putc (pest->stream, '\n'); indent_to (pest->stream, uparams.header_col); __argp_fmtstream_set_lmargin (pest->stream, uparams.header_col); __argp_fmtstream_set_wmargin (pest->stream, uparams.header_col); __argp_fmtstream_puts (pest->stream, fstr); __argp_fmtstream_set_lmargin (pest->stream, 0); __argp_fmtstream_putc (pest->stream, '\n'); } pest->hhstate->sep_groups = 1; /* Separate subsequent groups. */ } if (fstr != tstr) free ((char *) fstr);}/* Inserts a comma if this isn't the first item on the line, and then makes sure we're at least to column COL. If this *is* the first item on a line, prints any pending whitespace/headers that should precede this line. Also clears FIRST. */static voidcomma (unsigned col, struct pentry_state *pest){ if (pest->first) { const struct hol_entry *pe = pest->hhstate->prev_entry; const struct hol_cluster *cl = pest->entry->cluster; if (pest->hhstate->sep_groups && pe && pest->entry->group != pe->group) __argp_fmtstream_putc (pest->stream, '\n'); if (pe && cl && pe->cluster != cl && cl->header && *cl->header && !hol_cluster_is_child (pe->cluster, cl)) /* If we're changing clusters, then this must be the start of the ENTRY's cluster unless that is an ancestor of the previous one (in which case we had just popped into a sub-cluster for a bit). If so, then print the cluster's header line. */ { int old_wm = __argp_fmtstream_wmargin (pest->stream); print_header (cl->header, cl->argp, pest); __argp_fmtstream_set_wmargin (pest->stream, old_wm); } pest->first = 0; } else __argp_fmtstream_puts (pest->stream, ", "); indent_to (pest->stream, col);}/* Print help for ENTRY to STREAM. */static voidhol_entry_help (struct hol_entry *entry, const struct argp_state *state, argp_fmtstream_t stream, struct hol_help_state *hhstate){ unsigned num; const struct argp_option *real = entry->opt, *opt; char *so = entry->short_options; int have_long_opt = 0; /* We have any long options. */ /* Saved margins. */ int old_lm = __argp_fmtstream_set_lmargin (stream, 0); int old_wm = __argp_fmtstream_wmargin (stream); /* PEST is a state block holding some of our variables that we'd like to share with helper functions. */ struct pentry_state pest = { entry, stream, hhstate, 1, state }; if (! odoc (real)) for (opt = real, num = entry->num; num > 0; opt++, num--) if (opt->name && ovisible (opt)) { have_long_opt = 1; break; } /* First emit short options. */ __argp_fmtstream_set_wmargin (stream, uparams.short_opt_col); /* For truly bizarre cases. */ for (opt = real, num = entry->num; num > 0; opt++, num--) if (oshort (opt) && opt->key == *so) /* OPT has a valid (non shadowed) short option. */ { if (ovisible (opt)) { comma (uparams.short_opt_col, &pest); __argp_fmtstream_putc (stream, '-'); __argp_fmtstream_putc (stream, *so); if (!have_long_opt || uparams.dup_args) arg (real, " %s", "[%s]", stream); else if (real->arg) hhstate->suppressed_dup_arg = 1; } so++; } /* Now, long options. */ if (odoc (real)) /* A `documentation' option. */ { __argp_fmtstream_set_wmargin (stream, uparams.doc_opt_col); for (opt = real, num = entry->num; num > 0; opt++, num--) if (opt->name && ovisible (opt)) { comma (uparams.doc_opt_col, &pest); /* Calling gettext here isn't quite right, since sorting will have been done on the original; but documentation options should be pretty rare anyway... */ __argp_fmtstream_puts (stream, gettext (opt->name)); } } else /* A real long option. */ { int first_long_opt = 1; __argp_fmtstream_set_wmargin (stream, uparams.long_opt_col); for (opt = real, num = entry->num; num > 0; opt++, num--) if (opt->name && ovisible (opt)) { comma (uparams.long_opt_col, &pest); __argp_fmtstream_printf (stream, "--%s", opt->name); if (first_long_opt || uparams.dup_args) arg (real, "=%s", "[=%s]", stream); else if (real->arg) hhstate->suppressed_dup_arg = 1; } } /* Next, documentation strings. */ __argp_fmtstream_set_lmargin (stream, 0); if (pest.first) /* Didn't print any switches, what's up? */ if (!oshort (real) && !real->name) /* This is a group header, print it nicely. */ print_header (real->doc, entry->argp, &pest); else /* Just a totally shadowed option or null header; print nothing. */ goto cleanup; /* Just return, after cleaning up. */ else { const char *tstr = real->doc ? gettext (real->doc) : 0; const char *fstr = filter_doc (tstr, real->key, entry->argp, state); if (fstr && *fstr) { unsigned col = __argp_fmtstream_point (stream); __argp_fmtstream_set_lmargin (stream, uparams.opt_doc_col); __argp_fmtstream_set_wmargin (stream, uparams.opt_doc_col); if (col > uparams.opt_doc_col + 3) __argp_fmtstream_putc (stream, '\n'); else if (col >= uparams.opt_doc_col) __argp_fmtstream_puts (stream, " "); else indent_to (stream, uparams.opt_doc_col); __argp_fmtstream_puts (stream, fstr); } if (fstr && fstr != tstr) free ((char *) fstr); /* Reset the left margin. */ __argp_fmtstream_set_lmargin (stream, 0); __argp_fmtstream_putc (stream, '\n'); } hhstate->prev_entry = entry;cleanup: __argp_fmtstream_set_lmargin (stream, old_lm); __argp_fmtstream_set_wmargin (stream, old_wm);}/* Output a long help message about the options in HOL to STREAM. */static voidhol_help (struct hol *hol, const struct argp_state *state, argp_fmtstream_t stream){ unsigned num; struct hol_entry *entry; struct hol_help_state hhstate = { 0, 0, 0 }; for (entry = hol->entries, num = hol->num_entries; num > 0; entry++, num--) hol_entry_help (entry, state, stream, &hhstate); if (hhstate.suppressed_dup_arg && uparams.dup_args_note) { const char *tstr = _("\Mandatory or optional arguments to long options are also mandatory or \optional for any corresponding short options."); const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_DUP_ARGS_NOTE, state ? state->argp : 0, state); if (fstr && *fstr) { __argp_fmtstream_putc (stream, '\n'); __argp_fmtstream_puts (stream, fstr); __argp_fmtstream_putc (stream, '\n'); } if (fstr && fstr != tstr) free ((char *) fstr); }}/* Helper functions for hol_usage. *//* If OPT is a short option without an arg, append its key to the string pointer pointer to by COOKIE, and advance the pointer. */static intadd_argless_short_opt (const struct argp_option *opt, const struct argp_option *real, void *cookie){ char **snao_end = cookie; if (! (opt->arg || real->arg)) *(*snao_end)++ = opt->key; return 0;}/* If OPT is a short option with an arg, output a usage entry for it to the stream pointed at by COOKIE. */static intusage_argful_short_opt (const struct argp_option *opt, const struct argp_option *real, void *cookie){ argp_fmtstream_t stream = cookie; const char *arg = opt->arg; if (! arg) arg = real->arg; if (arg) { arg = gettext (arg); if ((opt->flags | real->flags) & OPTION_ARG_OPTIONAL) __argp_fmtstream_printf (stream, " [-%c[%s]]", opt->key, arg); else { /* Manually do line wrapping so that it (probably) won't get wrapped at the embedded space. */ space (stream, 6 + strlen (arg)); __argp_fmtstream_printf (stream, "[-%c %s]", opt->key, arg); } } return 0;}/* Output a usage entry for the long option opt to the stream pointed at by COOKIE. */static intusage_long_opt (const struct argp_option *opt, const struct argp_option *real, void *cookie){ argp_fmtstream_t stream = cookie; const char *arg = opt->arg; if (! arg) arg = real->arg; if (arg) { arg = gettext (arg); if ((opt->flags | real->flags) & OPTION_ARG_OPTIONAL) __argp_fmtstream_printf (stream, " [--%s[=%s]]", opt->name, arg); else __argp_fmtstream_printf (stream, " [--%s=%s]", opt->name, arg); } else __argp_fmtstream_printf (stream, " [--%s]", opt->name); return 0;}/* Print a short usage description for the arguments in HOL to STREAM. */static voidhol_usage (struct hol *hol, argp_fmtstream_t stream){ if (hol->num_entries > 0) { unsigned nentries; struct hol_entry *entry; char *short_no_arg_opts = alloca (strlen (hol->short_options) + 1); char *snao_end = short_no_arg_opts; /* First we put a list of short options without arguments. */ for (entry = hol->entries, nentries = hol->num_entries ; nentries > 0 ; entry++, nentries--) hol_entry_short_iterate (entry, add_argless_short_opt, &snao_end); if (snao_end > short_no_arg_opts) { *snao_end++ = 0; __argp_fmtstream_printf (stream, " [-%s]", short_no_arg_opts); } /* Now a list of short options *with* arguments. */ for (entry = hol->entries, nentries = hol->num_entries ; nentries > 0 ; entry++, nentries--) hol_entry_short_iterate (entry, usage_argful_short_opt, stream); /* Finally, a list of long options (whew!). */ for (entry = hol->entries, nentries = hol->num_entries ; nentries > 0 ; entry++, nentries--) hol_entry_long_iterate (entry, usage_long_opt, stream); }}/* Make a HOL containing all levels of options in ARGP. CLUSTER is the cluster in which ARGP's entries should be clustered, or 0. */static struct hol *argp_hol (const struct argp *argp, struct hol_cluster *cluster){ const struct argp_child *child = argp->children; struct hol *hol = make_hol (argp, cluster); if (child) while (child->argp) { struct hol_cluster *child_cluster = ((child->group || child->header)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -