From 5a97622d5e053e935af0a9715ddd941fdaafcaf9 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sat, 22 Feb 1997 01:20:46 +0000 Subject: update from main archive 970221 1997-02-22 00:17 Ulrich Drepper * catgets/gencat.c: Change to use argp. * db/makedb: Likewise. * locale/programs/localedef.c: Likewise. * locale/programs/locale.c: Little adjustment for better usage of argp. 1997-02-20 20:07 Greg McGary * Makeconfig: Add rules for libc with bounded pointers. * Makerules: Likewise. * config.make.in: Likewise. * configure.in: Likewise. 1997-02-21 10:41 Miles Bader * argp.h (OPTION_NO_USAGE): New macro. * argp-help.c (usage_long_opt, usage_argful_short_opt, add_argless_short_opt): Implement OPTION_NO_USAGE. 1997-02-20 16:41 Andreas Schwab * malloc/obstack.h: Fix typo. 1997-02-20 15:56 Miles Bader * argp-fmtstream.c (__argp_fmtstream_update): Account for case where NEXTLINE points one past the end of the active buffer. * argp-help.c : New include. (__argp_failure): Only exit if STATE says it's ok. (print_header, hol_entry_help): Use UPARAMS fields rather than constants. (_help): Call fill_in_uparams if necessary. (struct hol_help_state): New type. (struct pentry_state): Add hhstate field. Remove prev_entry & sep_groups fields. (hol_entry_help): Add HHSTATE parameter. Remove prev_entry & sep_groups parameters. Suppress duplicate arguments if requested, and note the fact. (print_header, comma): Use PEST->hhstate fields. (hol_help): Add HHSTATE variable & pass to hol_entry_help. Remove LAST_ENTRY & SEP_GROUPS variables. If any suplicate arguments were suppressed, print explanatory note. (filter_doc): Replace PEST parameter with STATE. (struct uparams): New type. (uparams): New variable. (struct uparam_name): New type. (uparam_names): New variable. (fill_in_uparams): New function. (__argp_failure, __argp_error, __argp_state_help): Make STATE parameter const. * argp.h (argp_state_help, __argp_state_help, argp_usage, __argp_usage, argp_error, __argp_error, argp_failure, __argp_failure): Make STATE parameter const. (ARGP_KEY_HELP_DUP_ARGS_NOTE): New macro. * argp.h (argp_program_bug_address): Make const. 1997-02-20 19:20 Ulrich Drepper * sysdeps/unix/mman/syscalls.list: Explain msync interface. 1997-02-19 01:37 Erik Troan * shadow/sgetspent_r.c: Accept empty third, fourth and fifth fields. 1997-02-20 14:44 Andreas Jaeger * stdio-common/test-fseek.c: Remove temporary file, add copyright. 1997-02-20 17:51 Ulrich Drepper * sysdeps/generic/netinet/in.h: Protect contents using __BEGIN/END_DECLS. Reported by a sun . * inet/net/ethernet.h: Move to sysdeps/unix/sysv/linux/net. * inet/Makefile (headers): Remove net/ethernet.h. * sysdeps/unix/sysv/linux/Makefile: Install net/ethernet.h. * sysdeps/unix/sysv/linux/Dist: Distribute net/ethernet.h. 1997-02-20 15:23 Thorsten Kukuk * nss/nsswitch.c (__nss_configure_lookup): Use correct test when searching in sorted array. 1997-02-20 01:24 Philip Blundell * inet/getnameinfo.c: Change to use reentrant getXXbyYY functions and protect modification of global data. 1997-02-19 18:48 Miles Bader * argp-parse.c (argp_default_parser): Set STATE->name for OPT_PROGNAME. (parser_init): Use the basename for PARSER->state.name. * argp-help.c (__argp_error, __argp_failure, __argp_state_help): Use PROGRAM_INVOCATION_SHORT_NAME instead of PROGRAM_INVOCATION_NAME. * argp-parse.c (parser_init): Set PARSER->state.flags. Make check whether PARSER has the prog name in argv[0] at the proper place. 1997-02-19 23:34 Ulrich Drepper * locale/programs/ld-time.c (time_finish): t_fmt_ampm is optional. Use default value instead of printing a warning. * nss/XXX-lookup.c: Add misssing explanation. 1997-02-19 19:14 Andreas Jaeger * inet/in6_addr.c: Add missing braces. * inet/getnameinfo.c: Include . * sysdeps/posix/getaddrinfo.c: Include . 1997-02-19 11:46 Ulrich Drepper * string/strxfrm.c (STRCOLL): Correct handling of `position' levels with no non-IGNOREd element and handling of NUL byte. * string/strcoll.c (STRXFRM): Likewise. * locale/weight.h: Likewise. * shadow/sgetspent_r.c (LINE_PARSER): Add missing ')'. --- argp/argp-fmtstream.c | 14 ++- argp/argp-help.c | 329 ++++++++++++++++++++++++++++++++++++++++---------- argp/argp-parse.c | 27 +++-- argp/argp-test.c | 2 +- argp/argp.h | 75 ++++++++---- 5 files changed, 341 insertions(+), 106 deletions(-) (limited to 'argp') diff --git a/argp/argp-fmtstream.c b/argp/argp-fmtstream.c index c7203deac6..ab2e870af8 100644 --- a/argp/argp-fmtstream.c +++ b/argp/argp-fmtstream.c @@ -240,7 +240,14 @@ __argp_fmtstream_update (argp_fmtstream_t fs) nextline = p; } - if (nextline - (nl + 1) < fs->wmargin) + /* Note: There are a bunch of tests below for + NEXTLINE == BUF + LEN + 1; this case is where NL happens to fall + at the end of the buffer, and NEXTLINE is in fact empty (and so + we need not be careful to maintain its contents). */ + + if (nextline == buf + len + 1 + ? fs->end - nl < fs->wmargin + 1 + : nextline - (nl + 1) < fs->wmargin) /* The margin needs more blanks than we removed. */ if (fs->end - fs->p > fs->wmargin + 1) /* Make some space for them. */ @@ -265,7 +272,8 @@ __argp_fmtstream_update (argp_fmtstream_t fs) the next word. */ *nl++ = '\n'; - if (nextline - nl >= fs->wmargin) + if (nextline - nl >= fs->wmargin + || (nextline == buf + len + 1 && fs->end - nextline >= fs->wmargin)) /* Add blanks up to the wrap margin column. */ for (i = 0; i < fs->wmargin; ++i) *nl++ = ' '; @@ -275,7 +283,7 @@ __argp_fmtstream_update (argp_fmtstream_t fs) /* Copy the tail of the original buffer into the current buffer position. */ - if (nl != nextline) + if (nl < nextline) memmove (nl, nextline, buf + len - nextline); len -= nextline - buf; diff --git a/argp/argp-help.c b/argp/argp-help.c index 84f9ca51c9..e954beb5a9 100644 --- a/argp/argp-help.c +++ b/argp/argp-help.c @@ -22,6 +22,7 @@ #include #endif +#include #include #include #include @@ -44,7 +45,17 @@ #include "argp.h" #include "argp-fmtstream.h" #include "argp-namefrob.h" + +/* User-selectable (using an environment variable) formatting parameters. + + These may be specified in an environment variable called `ARGP_HELP_FMT', + with a contents like: VAR1=VAL1,VAR2=VAL2,BOOLVAR2,no-BOOLVAR2 + Where VALn must be a positive integer. The list of variables is in the + UPARAM_NAMES vector, below. */ +/* Default parameters. */ +#define DUP_ARGS 0 /* True if option argument can be duplicated. */ +#define DUP_ARGS_NOTE 1 /* True to print a note about duplicate args. */ #define SHORT_OPT_COL 2 /* column in which short options start */ #define LONG_OPT_COL 6 /* column in which long options start */ #define DOC_OPT_COL 2 /* column in which doc options start */ @@ -53,6 +64,146 @@ #define USAGE_INDENT 12 /* indentation of wrapped usage lines */ #define RMARGIN 79 /* right margin used for wrapping */ +/* User-selectable (using an environment variable) formatting parameters. + They must all be of type `int' for the parsing code to work. */ +struct uparams +{ + /* If true, arguments for an option are shown with both short and long + options, even when a given option has both, e.g. `-x ARG, --longx=ARG'. + If false, then if an option has both, the argument is only shown with + the long one, e.g., `-x, --longx=ARG', and a message indicating that + this really means both is printed below the options. */ + int dup_args; + + /* This is true if when DUP_ARGS is false, and some duplicate arguments have + been suppressed, an explanatory message should be printed. */ + int dup_args_note; + + /* Various output columns. */ + int short_opt_col; + int long_opt_col; + int doc_opt_col; + int opt_doc_col; + int header_col; + int usage_indent; + int rmargin; + + int valid; /* True when the values in here are valid. */ +}; + +/* This is a global variable, as user options are only ever read once. */ +static struct uparams uparams = { + DUP_ARGS, DUP_ARGS_NOTE, + SHORT_OPT_COL, LONG_OPT_COL, DOC_OPT_COL, OPT_DOC_COL, HEADER_COL, + USAGE_INDENT, RMARGIN, + 0 +}; + +/* A particular uparam, and what the user name is. */ +struct uparam_name +{ + const char *name; /* User name. */ + int is_bool; /* Whether it's `boolean'. */ + size_t uparams_offs; /* Location of the (int) field in UPARAMS. */ +}; + +/* The name-field mappings we know about. */ +static const struct uparam_name uparam_names[] = +{ + { "dup-args", 1, offsetof (struct uparams, dup_args) }, + { "dup-args-note", 1, offsetof (struct uparams, dup_args_note) }, + { "short-opt-col", 0, offsetof (struct uparams, short_opt_col) }, + { "long-opt-col", 0, offsetof (struct uparams, long_opt_col) }, + { "doc-opt-col", 0, offsetof (struct uparams, doc_opt_col) }, + { "opt-doc-col", 0, offsetof (struct uparams, opt_doc_col) }, + { "header-col", 0, offsetof (struct uparams, header_col) }, + { "usage-indent", 0, offsetof (struct uparams, usage_indent) }, + { "rmargin", 0, offsetof (struct uparams, rmargin) }, + { 0 } +}; + +/* Read user options from the environment, and fill in UPARAMS appropiately. */ +static void +fill_in_uparams (const struct argp_state *state) +{ + const char *var = getenv ("ARGP_HELP_FMT"); + +#define SKIPWS(p) do { while (isspace (*p)) p++; } while (0); + + if (var) + /* Parse var. */ + while (*var) + { + SKIPWS (var); + + if (isalpha (*var)) + { + size_t var_len; + const struct uparam_name *un; + int unspec = 0, val = 0; + const char *arg = var; + + while (isalnum (*arg) || *arg == '-' || *arg == '_') + arg++; + var_len = arg - var; + + SKIPWS (arg); + + if (*arg == '\0' || *arg == ',') + unspec = 1; + else if (*arg == '=') + { + arg++; + SKIPWS (arg); + } + + if (unspec) + if (var[0] == 'n' && var[1] == 'o' && var[2] == '-') + { + val = 0; + var += 3; + var_len -= 3; + } + else + val = 1; + else if (isdigit (*arg)) + { + val = atoi (arg); + while (isdigit (*arg)) + arg++; + SKIPWS (arg); + } + + for (un = uparam_names; un->name; un++) + if (strlen (un->name) == var_len + && strncmp (var, un->name, var_len) == 0) + { + if (unspec && !un->is_bool) + __argp_failure (state, 0, 0, + _("%.*s: ARGP_HELP_FMT parameter requires a value"), + (int)var_len, var); + else + *(int *)((char *)&uparams + un->uparams_offs) = val; + break; + } + if (! un->name) + __argp_failure (state, 0, 0, + _("%.*s: Unknown ARGP_HELP_FMT parameter"), + (int)var_len, var); + + var = arg; + if (*var == ',') + var++; + } + else if (*var) + { + __argp_failure (state, 0, 0, + _("Garbage in ARGP_HELP_FMT: %s"), var); + break; + } + } +} + /* Returns true if OPT hasn't been marked invisible. Visibility only affects whether OPT is displayed or used in sorting, not option shadowing. */ #define ovisible(opt) (! ((opt)->flags & OPTION_HIDDEN)) @@ -719,13 +870,28 @@ arg (const struct argp_option *real, const char *req_fmt, const char *opt_fmt, { if (real->arg) if (real->flags & OPTION_ARG_OPTIONAL) - __argp_fmtstream_printf (stream, opt_fmt, _(real->arg)); + __argp_fmtstream_printf (stream, opt_fmt, gettext (real->arg)); else - __argp_fmtstream_printf (stream, req_fmt, _(real->arg)); + __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 previous entry printed, or 0. */ + struct hol_entry *prev_entry; + + /* If an entry is in a different group from the previous one, and SEP_GROUPS + is true, then a blank line will be printed before any output. */ + 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. */ @@ -733,8 +899,7 @@ struct pentry_state { const struct hol_entry *entry; argp_fmtstream_t stream; - struct hol_entry **prev_entry; - int *sep_groups; + struct hol_help_state *hhstate; /* True if nothing's been printed so far. */ int first; @@ -746,12 +911,12 @@ struct pentry_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, - struct pentry_state *pest) + const struct argp_state *state) { if (argp->help_filter) /* We must apply a user filter to this output. */ { - void *input = __argp_input (argp, pest->state); + void *input = __argp_input (argp, state); return (*argp->help_filter) (key, doc, input); } else @@ -769,25 +934,24 @@ print_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); + const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_HEADER, argp, pest->state); if (fstr) { if (*fstr) { - if (pest->prev_entry && *pest->prev_entry) + if (pest->hhstate->prev_entry) /* Precede with a blank line. */ __argp_fmtstream_putc (pest->stream, '\n'); - indent_to (pest->stream, HEADER_COL); - __argp_fmtstream_set_lmargin (pest->stream, HEADER_COL); - __argp_fmtstream_set_wmargin (pest->stream, HEADER_COL); + 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'); } - if (pest->sep_groups) - *pest->sep_groups = 1; /* Separate subsequent groups. */ + pest->hhstate->sep_groups = 1; /* Separate subsequent groups. */ } if (fstr != tstr) @@ -803,11 +967,10 @@ comma (unsigned col, struct pentry_state *pest) { if (pest->first) { - const struct hol_entry *pe = pest->prev_entry ? *pest->prev_entry : 0; + const struct hol_entry *pe = pest->hhstate->prev_entry; const struct hol_cluster *cl = pest->entry->cluster; - if (pest->sep_groups && *pest->sep_groups - && pe && pest->entry->group != pe->group) + 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 @@ -830,38 +993,45 @@ comma (unsigned col, struct pentry_state *pest) indent_to (pest->stream, col); } -/* Print help for ENTRY to STREAM. *PREV_ENTRY should contain the last entry - printed before this, or null if it's the first, and if 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. */ +/* Print help for ENTRY to STREAM. */ static void hol_entry_help (struct hol_entry *entry, const struct argp_state *state, - argp_fmtstream_t stream, - struct hol_entry **prev_entry, int *sep_groups) + 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, prev_entry, sep_groups, 1, state }; + 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, SHORT_OPT_COL); /* For truly bizarre cases. */ + __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 (SHORT_OPT_COL, &pest); + comma (uparams.short_opt_col, &pest); __argp_fmtstream_putc (stream, '-'); __argp_fmtstream_putc (stream, *so); - arg (real, " %s", "[%s]", stream); + if (!have_long_opt || uparams.dup_args) + arg (real, " %s", "[%s]", stream); + else if (real->arg) + hhstate->suppressed_dup_arg = 1; } so++; } @@ -870,27 +1040,32 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state, if (odoc (real)) /* A `documentation' option. */ { - __argp_fmtstream_set_wmargin (stream, DOC_OPT_COL); + __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 (DOC_OPT_COL, &pest); + 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, _(opt->name)); + __argp_fmtstream_puts (stream, gettext (opt->name)); } } else /* A real long option. */ { - __argp_fmtstream_set_wmargin (stream, LONG_OPT_COL); + 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 (LONG_OPT_COL, &pest); + comma (uparams.long_opt_col, &pest); __argp_fmtstream_printf (stream, "--%s", opt->name); - arg (real, "=%s", "[=%s]", stream); + if (first_long_opt || uparams.dup_args) + arg (real, "=%s", "[=%s]", stream); + else if (real->arg) + hhstate->suppressed_dup_arg = 1; } } @@ -908,20 +1083,20 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state, else { const char *tstr = real->doc ? gettext (real->doc) : 0; - const char *fstr = filter_doc (tstr, real->key, entry->argp, &pest); + 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, OPT_DOC_COL); - __argp_fmtstream_set_wmargin (stream, OPT_DOC_COL); + __argp_fmtstream_set_lmargin (stream, uparams.opt_doc_col); + __argp_fmtstream_set_wmargin (stream, uparams.opt_doc_col); - if (col > OPT_DOC_COL + 3) + if (col > uparams.opt_doc_col + 3) __argp_fmtstream_putc (stream, '\n'); - else if (col >= OPT_DOC_COL) + else if (col >= uparams.opt_doc_col) __argp_fmtstream_puts (stream, " "); else - indent_to (stream, OPT_DOC_COL); + indent_to (stream, uparams.opt_doc_col); __argp_fmtstream_puts (stream, fstr); } @@ -933,8 +1108,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state, __argp_fmtstream_putc (stream, '\n'); } - if (prev_entry) - *prev_entry = entry; + hhstate->prev_entry = entry; cleanup: __argp_fmtstream_set_lmargin (stream, old_lm); @@ -948,11 +1122,27 @@ hol_help (struct hol *hol, const struct argp_state *state, { unsigned num; struct hol_entry *entry; - struct hol_entry *last_entry = 0; - int sep_groups = 0; /* True if we should separate different - sections with blank lines. */ + 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, &last_entry, &sep_groups); + 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. */ @@ -965,7 +1155,8 @@ add_argless_short_opt (const struct argp_option *opt, void *cookie) { char **snao_end = cookie; - if (! (opt->arg || real->arg)) + if (!(opt->arg || real->arg) + && !((opt->flags | real->flags) & OPTION_NO_USAGE)) *(*snao_end)++ = opt->key; return 0; } @@ -979,15 +1170,16 @@ usage_argful_short_opt (const struct argp_option *opt, { argp_fmtstream_t stream = cookie; const char *arg = opt->arg; + int flags = opt->flags | real->flags; if (! arg) arg = real->arg; - if (arg) + if (arg && !(flags & OPTION_NO_USAGE)) { - arg = _(arg); + arg = gettext (arg); - if ((opt->flags | real->flags) & OPTION_ARG_OPTIONAL) + if (flags & OPTION_ARG_OPTIONAL) __argp_fmtstream_printf (stream, " [-%c[%s]]", opt->key, arg); else { @@ -1010,20 +1202,22 @@ usage_long_opt (const struct argp_option *opt, { argp_fmtstream_t stream = cookie; const char *arg = opt->arg; + int flags = opt->flags | real->flags; 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); + if (! (flags & OPTION_NO_USAGE)) + if (arg) + { + arg = gettext (arg); + if (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; } @@ -1117,7 +1311,7 @@ argp_args_usage (const struct argp *argp, char **levels, int advance, char *our_level = *levels; int multiple = 0; const struct argp_child *child = argp->children; - const char *doc = _(argp->args_doc), *nl = 0; + const char *doc = gettext (argp->args_doc), *nl = 0; if (doc) { @@ -1269,7 +1463,10 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream, if (! stream) return; - fs = __argp_make_fmtstream (stream, 0, RMARGIN, 0); + if (! uparams.valid) + fill_in_uparams (state); + + fs = __argp_make_fmtstream (stream, 0, uparams.rmargin, 0); if (! fs) return; @@ -1390,7 +1587,7 @@ weak_alias (__argp_help, argp_help) /* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are from the set ARGP_HELP_*. */ void -__argp_state_help (struct argp_state *state, FILE *stream, unsigned flags) +__argp_state_help (const struct argp_state *state, FILE *stream, unsigned flags) { if ((!state || ! (state->flags & ARGP_NO_ERRS)) && stream) { @@ -1417,7 +1614,7 @@ weak_alias (__argp_state_help, argp_state_help) by the program name and `:', to stderr, and followed by a `Try ... --help' message, then exit (1). */ void -__argp_error (struct argp_state *state, const char *fmt, ...) +__argp_error (const struct argp_state *state, const char *fmt, ...) { if (!state || !(state->flags & ARGP_NO_ERRS)) { @@ -1454,8 +1651,8 @@ weak_alias (__argp_error, argp_error) *parsing errors*, and the former is for other problems that occur during parsing but don't reflect a (syntactic) problem with the input. */ void -__argp_failure (struct argp_state *state, int status, int errnum, - const char *fmt, ...) +__argp_failure (const struct argp_state *state, int status, int errnum, + const char *fmt, ...) { if (!state || !(state->flags & ARGP_NO_ERRS)) { @@ -1486,7 +1683,7 @@ __argp_failure (struct argp_state *state, int status, int errnum, putc ('\n', stream); - if (status) + if (status && (!state || !(state->flags & ARGP_NO_EXIT))) exit (status); } } diff --git a/argp/argp-parse.c b/argp/argp-parse.c index af27757273..11c36be705 100644 --- a/argp/argp-parse.c +++ b/argp/argp-parse.c @@ -106,7 +106,7 @@ argp_default_parser (int key, char *arg, struct argp_state *state) break; case OPT_PROGNAME: /* Set the program name. */ - program_invocation_short_name = arg; + program_invocation_name = arg; /* [Note that some systems only have PROGRAM_INVOCATION_SHORT_NAME (aka __PROGNAME), in which case, PROGRAM_INVOCATION_NAME is just defined @@ -117,10 +117,13 @@ argp_default_parser (int key, char *arg, struct argp_state *state) else program_invocation_short_name = program_invocation_name; + /* Update what we use for messages. */ + state->name = program_invocation_short_name; + if ((state->flags & (ARGP_PARSE_ARGV0 | ARGP_NO_ERRS)) == ARGP_PARSE_ARGV0) /* Update what getopt uses too. */ - state->argv[0] = program_invocation_short_name; + state->argv[0] = program_invocation_name; break; @@ -522,17 +525,18 @@ parser_init (struct parser *parser, const struct argp *argp, memset (parser->child_inputs, 0, szs.num_child_inputs * sizeof (void *)); parser_convert (parser, argp, flags); - parser->try_getopt = 1; - memset (&parser->state, 0, sizeof (struct argp_state)); parser->state.argp = parser->argp; parser->state.argc = argc; parser->state.argv = argv; + parser->state.flags = flags; parser->state.err_stream = stderr; parser->state.out_stream = stdout; parser->state.next = 0; /* Tell getopt to initialize. */ parser->state.pstate = parser; + parser->try_getopt = 1; + /* Call each parser for the first time, giving it a chance to propagate values to child parsers. */ if (parser->groups < parser->egroup) @@ -552,12 +556,6 @@ parser_init (struct parser *parser, const struct argp *argp, if (err) return err; - if (parser->state.argv == argv && argv[0]) - /* There's an argv[0]; use it for messages. */ - parser->state.name = argv[0]; - else - parser->state.name = program_invocation_name; - /* Getopt is (currently) non-reentrant. */ LOCK_GETOPT; @@ -572,6 +570,15 @@ parser_init (struct parser *parser, const struct argp *argp, else opterr = 1; /* Print error messages. */ + if (parser->state.argv == argv && argv[0]) + /* There's an argv[0]; use it for messages. */ + { + char *short_name = strrchr (argv[0], '/'); + parser->state.name = short_name ? short_name + 1 : argv[0]; + } + else + parser->state.name = program_invocation_short_name; + return 0; } diff --git a/argp/argp-test.c b/argp/argp-test.c index 1ce48c3e3f..702ae9aa85 100644 --- a/argp/argp-test.c +++ b/argp/argp-test.c @@ -187,7 +187,7 @@ help_filter (int key, const char *text, void *input) asprintf (&new_text, "%s (ZOT defaults to %x)", text, params->foonly_default); else - new_text = (char *) text; + new_text = (char *)text; return new_text; } diff --git a/argp/argp.h b/argp/argp.h index 2e20ea67f3..cdb32b799a 100644 --- a/argp/argp.h +++ b/argp/argp.h @@ -108,6 +108,15 @@ struct argp_option is displayed after all options (and OPTION_DOC entries with a leading `-') in the same group. */ #define OPTION_DOC 0x8 + +/* This option shouldn't be included in `long' usage messages (but is still + included in help messages). This is mainly intended for options that are + completely documented in an argp's ARGS_DOC field, in which case including + the option in the generic usage list would be redundant. For instance, + if ARGS_DOC is "FOO BAR\n-x BLAH", and the `-x' option's purpose is to + distinguish these two cases, -x should probably be marked + OPTION_NO_USAGE. */ +#define OPTION_NO_USAGE 0x10 struct argp; /* fwd declare this type */ struct argp_state; /* " */ @@ -126,12 +135,21 @@ typedef error_t (*argp_parser_t)(int key, char *arg, struct argp_state *state); /* Special values for the KEY argument to an argument parsing function. ARGP_ERR_UNKNOWN should be returned if they aren't understood. - The sequence of keys to parser calls is either (where opt is a user key): - ARGP_KEY_INIT (opt | ARGP_KEY_ARG)... ARGP_KEY_END - or ARGP_KEY_INIT opt... ARGP_KEY_NO_ARGS ARGP_KEY_END + The sequence of keys to a parsing function is either (where each + uppercased word should be prefixed by `ARGP_KEY_' and opt is a user key): + + INIT opt... NO_ARGS END SUCCESS -- No non-option arguments at all + or INIT (opt | ARG)... END SUCCESS -- All non-option args parsed + or INIT (opt | ARG)... SUCCESS -- Some non-option arg unrecognized - If an error occurs, then the parser is called with ARGP_KEY_ERR, and no - other calls are made. */ + The third case is where every parser returned ARGP_KEY_UNKNOWN for an + argument, in which case parsing stops at that argument (returning the + unparsed arguments to the caller of argp_parse if requested, or stopping + with an error message if not). + + If an error occurs (either detected by argp, or because the parsing + function returned an error value), then the parser is called with + ARGP_KEY_ERROR, and no further calls are made. */ /* This is not an option at all, but rather a command line argument. If a parser receiving this key returns success, the fact is recorded, and the @@ -160,12 +178,12 @@ typedef error_t (*argp_parser_t)(int key, char *arg, struct argp_state *state); never made, so any cleanup must be done here). */ #define ARGP_KEY_ERROR 0x1000005 -/* An argp structure contains a set of getopt options declarations, a - function to deal with getting one, and an optional pointer to another - argp structure. When actually parsing options, getopt is called with - the union of all the argp structures chained together through their - CHILD pointers, with conflicts being resolved in favor of the first - occurance in the chain. */ +/* An argp structure contains a set of options declarations, a function to + deal with parsing one, documentation string, a possible vector of child + argp's, and perhaps a function to filter help output. When actually + parsing options, getopt is called with the union of all the argp + structures chained together through their CHILD pointers, with conflicts + being resolved in favor of the first occurance in the chain. */ struct argp { /* An array of argp_option structures, terminated by an entry with both @@ -220,6 +238,9 @@ struct argp #define ARGP_KEY_HELP_HEADER 0x2000003 /* Option header string. */ #define ARGP_KEY_HELP_EXTRA 0x2000004 /* After all other documentation; TEXT is NULL for this key. */ +/* Explanatory note emitted when duplicate option arguments have been + suppressed. */ +#define ARGP_KEY_HELP_DUP_ARGS_NOTE 0x2000005 /* When an argp has a non-zero CHILDREN field, it should point to a vector of argp_child structures, each of which describes a subsidiary argp. */ @@ -373,7 +394,7 @@ extern void (*argp_program_version_hook) __P ((FILE *__stream, argp_help if the ARGP_HELP_BUG_ADDR flag is set (as it is by various standard help messages), embedded in a sentence that says something like `Report bugs to ADDR.'. */ -extern char *argp_program_bug_address; +__const extern char *argp_program_bug_address; /* Flags for argp_help. */ #define ARGP_HELP_USAGE 0x01 /* a Usage: message. */ @@ -421,22 +442,22 @@ extern void __argp_help __P ((__const struct argp *__argp, FILE *__stream, /* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are from the set ARGP_HELP_*. */ -extern void argp_state_help __P ((struct argp_state *__state, FILE *__stream, - unsigned __flags)); -extern void __argp_state_help __P ((struct argp_state *__state, FILE *__stream, - unsigned __flags)); +extern void argp_state_help __P ((__const struct argp_state *__state, + FILE *__stream, unsigned __flags)); +extern void __argp_state_help __P ((__const struct argp_state *__state, + FILE *__stream, unsigned __flags)); /* Possibly output the standard usage message for ARGP to stderr and exit. */ -extern void argp_usage __P ((struct argp_state *__state)); -extern void __argp_usage __P ((struct argp_state *__state)); +extern void argp_usage __P ((__const struct argp_state *__state)); +extern void __argp_usage __P ((__const struct argp_state *__state)); /* If appropriate, print the printf string FMT and following args, preceded by the program name and `:', to stderr, and followed by a `Try ... --help' message, then exit (1). */ -extern void argp_error __P ((struct argp_state *__state, __const char *__fmt, - ...)) +extern void argp_error __P ((__const struct argp_state *__state, + __const char *__fmt, ...)) __attribute__ ((__format__ (__printf__, 2, 3))); -extern void __argp_error __P ((struct argp_state *__state, +extern void __argp_error __P ((__const struct argp_state *__state, __const char *__fmt, ...)) __attribute__ ((__format__ (__printf__, 2, 3))); @@ -448,11 +469,13 @@ extern void __argp_error __P ((struct argp_state *__state, difference between this function and argp_error is that the latter is for *parsing errors*, and the former is for other problems that occur during parsing but don't reflect a (syntactic) problem with the input. */ -extern void argp_failure __P ((struct argp_state *__state, int __status, - int __errnum, __const char *__fmt, ...)) +extern void argp_failure __P ((__const struct argp_state *__state, + int __status, int __errnum, + __const char *__fmt, ...)) __attribute__ ((__format__ (__printf__, 4, 5))); -extern void __argp_failure __P ((struct argp_state *__state, int __status, - int __errnum, __const char *__fmt, ...)) +extern void __argp_failure __P ((__const struct argp_state *__state, + int __status, int __errnum, + __const char *__fmt, ...)) __attribute__ ((__format__ (__printf__, 4, 5))); /* Returns true if the option OPT is a valid short option. */ @@ -485,7 +508,7 @@ extern void *__argp_input __P ((__const struct argp *argp, #endif ARGP_EI void -__argp_usage (struct argp_state *__state) +__argp_usage (__const struct argp_state *__state) { __argp_state_help (__state, stderr, ARGP_HELP_STD_USAGE); } -- cgit v1.2.1