summaryrefslogtreecommitdiff
path: root/argp/argp-help.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1997-02-19 04:43:53 +0000
committerUlrich Drepper <drepper@redhat.com>1997-02-19 04:43:53 +0000
commit1fb05e3db1891142410bc58c320dfe281749fffe (patch)
tree46299dbecec282055e3493787910444e77099fe7 /argp/argp-help.c
parentc84142e8fe3cbcce43ae35ac957a74ac8216d11d (diff)
update from main archive 970218cvs/libc-970221cvs/libc-970220cvs/libc-970219
1997-02-19 03:28 Miles Bader <miles@gnu.ai.mit.edu> * argp/argp-help.c: Add support for user provided filter of help messages. * argp/argp-parse.c: Likewise. * argp/argp.h: Likewise. * argp/argp-namefrob.h: Define __argp_input. * argp/argp-test.c: Add example for filter. 1997-02-19 02:58 Ulrich Drepper <drepper@cygnus.com> * argp.h: New file. * locale/programs/locale.c: Switch to use argp. * errno.h: Make it possible to get definition of error_t even after having errno.h already. * elf/dl-hash.h: New file. ELF hashing function. Extracted from dl-lookup.c. * elf/dl-lookup.c (_dl_elf_hash): Remove definition. * elf/dl-load.c: Rename _dl_does_name_match_p to _dl_name_match_p. * elf/dl-version.c: Likewise. * elf/dl-lookup.c: Implement new versioning lookup scheme. * elf/dl-version.c (_dl_check_map_versions): Initialize new field in l_versions member. * elf/dlvsym.c: Correct call of _dl_lookup_versioned_symbol_skip and _dl_lookup_versioned_symbol. * elf/link.h: Rename hash_name_pair to struct r_found_version. * sysdeps/alpha/dl-machine.h: Likewise. * sysdeps/i386/dl-machine.h: Likewise. * sysdeps/m68k/dl-machine.h: Likewise. * sysdeps/mips/dl-machine.h: Likewise. * intl/l10nflist.c: (_nl_make_l10nflist): Fix bug in computation of length of abs_filename. * locale/Makefile (CPPFLAGS): Define LOCALE_ALIAS_PATH. * locale/programs/ld-monetary.c (monetary_add): Allow value 0 in mon_grouping information. This means no more grouping. * locale/programs/ld-numeric.c (numeric_add): Write value \377 when seein value 0 in grouping information. * locale/programs/linereader.c (lr_close): Don't free fname since it might be used in error messages. * locale/programs/locale.c: Check whether output of `locale -a' really is locale directory. Also print locale aliases. * misc/search.h (__action_fn_t): Parameters VALUE and LEVEL cannot be const. 1997-02-19 02:16 Ulrich Drepper <drepper@cygnus.com> * sysdeps/unix/bsd/sun/sunos4/resourcebits.h: Correct #defin to #define. Reported by Rick Flower <FLOWER@sdvax2.sdd.TRW.COM>. 1997-02-19 01:37 Erik Troan <ewt@redhat.com> * shadow/sgetspent_r.c: Accept empty third, fourth and fifth fields. 1997-02-19 01:02 Ulrich Drepper <drepper@cygnus.com> * sysdeps/unix/mman/syscalls.list: msync takes 3 arguments. Reported by Andreas Jaeger <aj@arthur.pfalz.de>. * sysdeps/stub/msync.c (msync): Add missing third parameter. 1997-02-19 00:29 Ulrich Drepper <drepper@cygnus.com> * sysdeps/unix/bsd/sigsuspend.c: Call __sigpause with needed additional argument. 1997-02-18 22:13 Ulrich Drepper <drepper@cygnus.com> * inet/net/ethernet.h: New file. * sysdeps/unix/sysv/linux/netinet/if_ether.c: Add BSD compatibility. * sysdeps/unix/sysv/linux/net/if_slip.h: New file. Contributed by a sun <asun@zoology.washington.edu>. * sysdeps/unix/sysv/linux/net/if_arp.h: Include <sys/socket.h>. * sunrpc/rpc/rpc_msg.h: Include <rpc/clnt.h>. Reported by a sun <asun@zoology.washington.edu>. 1997-02-16 14:25 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * Makerules ((common-objpfx)distinfo-$(subdir)): Depend on sysdep makefiles which may change the distinfo variables. 1997-02-16 14:03 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * sysdeps/unix/sysv/linux/Makefile (sysdep_headers) [$(subdir)=misc]: Add sys/quota.h. (sysdep_headers) [$(subdir)=inet]: Add netinet/udp.h. 1997-02-17 13:12 aleph1@dfw.net * sunrpc/clnt_simp.c (callrpc): Prevent buffer overflow by using strncpy. 1997-02-18 03:28 Ulrich Drepper <drepper@cygnus.com> * stdio-common/bug10.c (main): Correct parameter. 1997-02-17 02:51 Ulrich Drepper <drepper@cygnus.com> * malloc/obstack.h: Add `extern "C"' protection. * posix/regex.h: Likewise. * io/ftw.h: Likewise. * misc/libgen.h: Likewise. * login/utmp.h: Likewise. * sysdeps/unix/sysv/linux/sys/reboot.h: Likewise. * sysdeps/unix/sysv/linux/netinet/in.h: Likewise. * sunrpc/rpc/pmap_rmt.h: Likewise. * sunrpc/rpc/auth_des.h: Likewise. * elf/link.h: Likewise. Reported by HJ Lu. 1997-02-17 01:45 a sun <asun@zoology.washington.edu> Linux specific network headers. * sysdeps/unix/sysv/linux/netinet/if_fddi.h: New file. * sysdeps/unix/sysv/linux/netinet/if_tr.h: New file. * sysdeps/unix/sysv/linux/netinet/ip_icmp.h: New file. * sysdeps/unix/sysv/linux/netinet/ip_fw.h: New file. * sysdeps/unix/sysv/linux/netinet/igmp.h: New file. * sysdeps/unix/sysv/linux/netinet/icmp.h: New file. * sysdeps/unix/sysv/linux/netinet/ip.h: New file. * sysdeps/unix/sysv/linux/netinet/tcp.h: New file. * sysdeps/unix/sysv/linux/netipx/ipx.h: New file. * sysdeps/unix/sysv/linux/netatalk/atalk.h: New file. * sysdeps/unix/sysv/linux/Dist: Add new network headers. * sysdeps/unix/sysv/linux/Makefile [$(subdir)=misc] (sysdep_headers): Add sys/quota.h. [$(subdir)=inet] (sysdep_headers): Add new network header. * sysdeps/unix/sysv/linux/netinet/udp.h: Add Linux specific changes. * inet/netinet/ip.h: Move to sysdeps/generic. * inet/netinet/tcp.h: Likewise. * sysdeps/generic/netinet/ip.h: Moved to here from inet/netinet. * sysdeps/generic/netinet/tcp.h: Likewise. 1997-02-17 01:18 Ulrich Drepper <drepper@cygnus.com> * misc/sys/syslog.h (prioritynames): Correct definition to use braces where necessary. (facilitynames): Likewise. Patch by Ronald F. Guilmette <rfg@monkeys.com>. Comment and beautify declarations. 1997-02-16 19:54 1997 Philip Blundell <Philip.Blundell@pobox.com> * inet/Makefile (routines): Add in6_addr, getnameinfo. * inet/getnameinfo.c: New file. Implementation of getnameinfo() by Craig Metz. * inet/in6_addr.c: New file. IPv6 addressing constants. * posix/Makefile (routines): Add gai_strerror. * resolv/netdb.h: Add more constants for IPv6 basic API. * sysdeps/posix/gai_strerror.c: New file. * sysdeps/stub/gai_strerror.c New file. * sysdeps/unix/sysv/linux/netinet/in.h: Add definitions for IPv6 basic API. * sysdeps/posix/getaddrinfo.c: Update from latest version by Craig Metz and use reentrant getXXbyYY functions. 1997-02-15 14:32 Andreas Jaeger <aj@arthur.pfalz.de> * argp/argp.h: Declare argp_program_version as const char. * argp/argp-test.c: Likewise * stdlib/testrand.c (main): Declare main prototype. * stdlib/testdiv.c (main): Likewise. * string/testcopy.c (main): Likewise. * string/test-ffs.c (main): Likewise. * time/test_time.c (main): Likewise. * locale/duplocale.c (__duplocale): Return result. 1997-02-16 03:54 Ulrich Drepper <drepper@cygnus.com> * sysdeps/unix/sysv/linux/netinet/in.h: Declare bindresvport. Reported by fabsoft@fabserver1.zarm.uni-bremen.de. * nss/nss.h: Remove declaration of __nss_shlib_revision. * nss/nsswitch.c: Don't use NSS_SHLIB_VERSION macro. 1997-02-16 03:48 Thorsten Kukuk <kukuk@weber.uni-paderborn.de> * nis/nss_nis/nis-ethers.c (_nss_nis_getethernam_r): Rename to _nss_nis_gethostton_r. (_nss_nis_getetherbyaddr_r): Rename to _nss_nis_getntohost_r. 1997-02-15 22:37 Andy Berkheimer <andy@tho.org> * resolv/gethnamaddr.c (gethostbyname2): Test for ':' in name before trying to resolv name as numeric IPv6 address. * nss/digits_dots.c: Likewise. Sat Feb 15 04:51:08 1997 Ulrich Drepper <drepper@cygnus.com> * locale/setlocale.c (setlocale): Don't try to be clever about unused locales. When the existence of the locale files isn't tested the result of setlocale might be different. 1997-02-15 03:34 Ulrich Drepper <drepper@cygnus.com> * locale/setlocale.c (setlocale): Don't increment usage_count of new locale if it already has the value MAX_USAGE_COUNT (it might be the C locale data which is read-only).
Diffstat (limited to 'argp/argp-help.c')
-rw-r--r--argp/argp-help.c324
1 files changed, 222 insertions, 102 deletions
diff --git a/argp/argp-help.c b/argp/argp-help.c
index 5d7df5454a..84f9ca51c9 100644
--- a/argp/argp-help.c
+++ b/argp/argp-help.c
@@ -169,6 +169,9 @@ struct hol_entry
/* The cluster of options this entry belongs to, or 0 if none. */
struct hol_cluster *cluster;
+
+ /* The argp from which this option came. */
+ const struct argp *argp;
};
/* A cluster of entries to reflect the argp tree structure. */
@@ -190,6 +193,9 @@ struct hol_cluster
level. */
struct hol_cluster *parent;
+ /* The argp from which this cluster is (eventually) derived. */
+ const struct argp *argp;
+
/* The distance this cluster is from the root. */
int depth;
@@ -215,13 +221,14 @@ struct hol
struct hol_cluster *clusters;
};
-/* Create a struct hol from an array of struct argp_option. CLUSTER is the
+/* Create a struct hol from the options in ARGP. CLUSTER is the
hol_cluster in which these entries occur, or 0, if at the root. */
static struct hol *
-make_hol (const struct argp_option *opt, struct hol_cluster *cluster)
+make_hol (const struct argp *argp, struct hol_cluster *cluster)
{
char *so;
const struct argp_option *o;
+ const struct argp_option *opts = argp->options;
struct hol_entry *entry;
unsigned num_short_options = 0;
struct hol *hol = malloc (sizeof (struct hol));
@@ -231,15 +238,15 @@ make_hol (const struct argp_option *opt, struct hol_cluster *cluster)
hol->num_entries = 0;
hol->clusters = 0;
- if (opt)
+ if (opts)
{
int cur_group = 0;
/* The first option must not be an alias. */
- assert (! oalias (opt));
+ assert (! oalias (opts));
/* Calculate the space needed. */
- for (o = opt; ! oend (o); o++)
+ for (o = opts; ! oend (o); o++)
{
if (! oalias (o))
hol->num_entries++;
@@ -254,7 +261,7 @@ make_hol (const struct argp_option *opt, struct hol_cluster *cluster)
/* Fill in the entries. */
so = hol->short_options;
- for (o = opt, entry = hol->entries; ! oend (o); entry++)
+ for (o = opts, entry = hol->entries; ! oend (o); entry++)
{
entry->opt = o;
entry->num = 0;
@@ -266,6 +273,7 @@ make_hol (const struct argp_option *opt, struct hol_cluster *cluster)
? cur_group + 1
: cur_group);
entry->cluster = cluster;
+ entry->argp = argp;
do
{
@@ -285,10 +293,10 @@ make_hol (const struct argp_option *opt, struct hol_cluster *cluster)
/* Add a new cluster to HOL, with the given GROUP and HEADER (taken from the
associated argp child list entry), INDEX, and PARENT, and return a pointer
- to it. */
+ to it. ARGP is the argp that this cluster results from. */
static struct hol_cluster *
hol_add_cluster (struct hol *hol, int group, const char *header, int index,
- struct hol_cluster *parent)
+ struct hol_cluster *parent, const struct argp *argp)
{
struct hol_cluster *cl = malloc (sizeof (struct hol_cluster));
if (cl)
@@ -298,6 +306,7 @@ hol_add_cluster (struct hol *hol, int group, const char *header, int index,
cl->index = index;
cl->parent = parent;
+ cl->argp = argp;
cl->next = hol->clusters;
hol->clusters = cl;
@@ -657,8 +666,8 @@ hol_append (struct hol *hol, struct hol *more)
if (oshort (opt) && ch == opt->key)
/* The next short option in MORE_SO, CH, is from OPT. */
{
- if (! find_char (ch,
- short_options, short_options + hol_so_len))
+ if (! find_char (ch, short_options,
+ short_options + hol_so_len))
/* The short option CH isn't shadowed by HOL's options,
so add it to the sum. */
*so++ = ch;
@@ -689,6 +698,18 @@ indent_to (argp_fmtstream_t stream, unsigned col)
__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 void
+space (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. */
@@ -715,44 +736,79 @@ struct pentry_state
struct hol_entry **prev_entry;
int *sep_groups;
- int first; /* True if nothing's been printed so far. */
+ /* 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,
+ struct pentry_state *pest)
+{
+ if (argp->help_filter)
+ /* We must apply a user filter to this output. */
+ {
+ void *input = __argp_input (argp, pest->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. Note
+ 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 void
-print_header (const char *str, struct pentry_state *st)
+print_header (const char *str, const struct argp *argp,
+ struct pentry_state *pest)
{
- if (*str)
+ const char *tstr = gettext (str);
+ const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_HEADER, argp, pest);
+
+ if (fstr)
{
- if (st->prev_entry && *st->prev_entry)
- __argp_fmtstream_putc (st->stream, '\n'); /* Precede with a blank line. */
- indent_to (st->stream, HEADER_COL);
- __argp_fmtstream_set_lmargin (st->stream, HEADER_COL);
- __argp_fmtstream_set_wmargin (st->stream, HEADER_COL);
- __argp_fmtstream_puts (st->stream, str);
- __argp_fmtstream_set_lmargin (st->stream, 0);
+ if (*fstr)
+ {
+ if (pest->prev_entry && *pest->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);
+ __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. */
}
- if (st->sep_groups)
- *st->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. Also clears FIRST. */
+ 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 void
-comma (unsigned col, struct pentry_state *st)
+comma (unsigned col, struct pentry_state *pest)
{
- if (st->first)
+ if (pest->first)
{
- const struct hol_entry *pe = st->prev_entry ? *st->prev_entry : 0;
- const struct hol_cluster *cl = st->entry->cluster;
+ const struct hol_entry *pe = pest->prev_entry ? *pest->prev_entry : 0;
+ const struct hol_cluster *cl = pest->entry->cluster;
- if (st->sep_groups && *st->sep_groups
- && pe && st->entry->group != pe->group)
- __argp_fmtstream_putc (st->stream, '\n');
+ if (pest->sep_groups && *pest->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))
@@ -761,18 +817,17 @@ comma (unsigned col, struct pentry_state *st)
(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 (st->stream);
- print_header (cl->header, st);
- __argp_fmtstream_putc (st->stream, '\n');
- __argp_fmtstream_set_wmargin (st->stream, old_wm);
+ int old_wm = __argp_fmtstream_wmargin (pest->stream);
+ print_header (cl->header, cl->argp, pest);
+ __argp_fmtstream_set_wmargin (pest->stream, old_wm);
}
- st->first = 0;
+ pest->first = 0;
}
else
- __argp_fmtstream_puts (st->stream, ", ");
+ __argp_fmtstream_puts (pest->stream, ", ");
- indent_to (st->stream, col);
+ indent_to (pest->stream, col);
}
/* Print help for ENTRY to STREAM. *PREV_ENTRY should contain the last entry
@@ -781,15 +836,19 @@ comma (unsigned col, struct pentry_state *st)
printed before any output. *SEP_GROUPS is also set to true if a
user-specified group header is printed. */
static void
-hol_entry_help (struct hol_entry *entry, argp_fmtstream_t stream,
+hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
+ argp_fmtstream_t stream,
struct hol_entry **prev_entry, int *sep_groups)
{
unsigned num;
const struct argp_option *real = entry->opt, *opt;
char *so = entry->short_options;
+ /* Saved margins. */
int old_lm = __argp_fmtstream_set_lmargin (stream, 0);
int old_wm = __argp_fmtstream_wmargin (stream);
- struct pentry_state pest = { entry, stream, prev_entry, sep_groups, 1 };
+ /* 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 };
/* First emit short options. */
__argp_fmtstream_set_wmargin (stream, SHORT_OPT_COL); /* For truly bizarre cases. */
@@ -809,7 +868,7 @@ hol_entry_help (struct hol_entry *entry, argp_fmtstream_t stream,
/* Now, long options. */
if (odoc (real))
- /* Really a `documentation' option. */
+ /* A `documentation' option. */
{
__argp_fmtstream_set_wmargin (stream, DOC_OPT_COL);
for (opt = real, num = entry->num; num > 0; opt++, num--)
@@ -823,7 +882,7 @@ hol_entry_help (struct hol_entry *entry, argp_fmtstream_t stream,
}
}
else
- /* A realy long option. */
+ /* A real long option. */
{
__argp_fmtstream_set_wmargin (stream, LONG_OPT_COL);
for (opt = real, num = entry->num; num > 0; opt++, num--)
@@ -835,39 +894,45 @@ hol_entry_help (struct hol_entry *entry, argp_fmtstream_t stream,
}
}
+ /* 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 && real->doc)
+ if (!oshort (real) && !real->name)
/* This is a group header, print it nicely. */
- print_header (real->doc, &pest);
+ 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 if (real->doc)
- /* Now the option documentation. */
+ else
{
- unsigned col = __argp_fmtstream_point (stream);
- const char *doc = real->doc;
+ const char *tstr = real->doc ? gettext (real->doc) : 0;
+ const char *fstr = filter_doc (tstr, real->key, entry->argp, &pest);
+ 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, OPT_DOC_COL);
+ __argp_fmtstream_set_wmargin (stream, OPT_DOC_COL);
- if (col > OPT_DOC_COL + 3)
- __argp_fmtstream_putc (stream, '\n');
- else if (col >= OPT_DOC_COL)
- __argp_fmtstream_puts (stream, " ");
- else
- indent_to (stream, OPT_DOC_COL);
+ if (col > OPT_DOC_COL + 3)
+ __argp_fmtstream_putc (stream, '\n');
+ else if (col >= OPT_DOC_COL)
+ __argp_fmtstream_puts (stream, " ");
+ else
+ indent_to (stream, OPT_DOC_COL);
- __argp_fmtstream_puts (stream, doc);
+ __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');
}
- __argp_fmtstream_putc (stream, '\n');
-
if (prev_entry)
*prev_entry = entry;
@@ -878,7 +943,8 @@ cleanup:
/* Output a long help message about the options in HOL to STREAM. */
static void
-hol_help (struct hol *hol, argp_fmtstream_t stream)
+hol_help (struct hol *hol, const struct argp_state *state,
+ argp_fmtstream_t stream)
{
unsigned num;
struct hol_entry *entry;
@@ -886,7 +952,7 @@ hol_help (struct hol *hol, argp_fmtstream_t stream)
int sep_groups = 0; /* True if we should separate different
sections with blank lines. */
for (entry = hol->entries, num = hol->num_entries; num > 0; entry++, num--)
- hol_entry_help (entry, stream, &last_entry, &sep_groups);
+ hol_entry_help (entry, state, stream, &last_entry, &sep_groups);
}
/* Helper functions for hol_usage. */
@@ -927,11 +993,7 @@ usage_argful_short_opt (const struct argp_option *opt,
{
/* Manually do line wrapping so that it (probably) won't
get wrapped at the embedded space. */
- if (__argp_fmtstream_point (stream) + 6 + strlen (arg)
- >= __argp_fmtstream_rmargin (stream))
- __argp_fmtstream_putc (stream, '\n');
- else
- __argp_fmtstream_putc (stream, ' ');
+ space (stream, 6 + strlen (arg));
__argp_fmtstream_printf (stream, "[-%c %s]", opt->key, arg);
}
}
@@ -1008,7 +1070,7 @@ 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->options, cluster);
+ struct hol *hol = make_hol (argp, cluster);
if (child)
while (child->argp)
{
@@ -1016,7 +1078,7 @@ argp_hol (const struct argp *argp, struct hol_cluster *cluster)
((child->group || child->header)
/* Put CHILD->argp within its own cluster. */
? hol_add_cluster (hol, child->group, child->header,
- child - argp->children, cluster)
+ child - argp->children, cluster, argp)
/* Just merge it into the parent's cluster. */
: cluster);
hol_append (hol, argp_hol (child->argp, child_cluster)) ;
@@ -1075,11 +1137,7 @@ argp_args_usage (const struct argp *argp, char **levels, int advance,
/* Manually do line wrapping so that it (probably) won't get wrapped at
any embedded spaces. */
- if (__argp_fmtstream_point (stream) + 1 + nl - doc
- >= __argp_fmtstream_rmargin (stream))
- __argp_fmtstream_putc (stream, '\n');
- else
- __argp_fmtstream_putc (stream, ' ');
+ space (stream, 1 + nl - doc);
__argp_fmtstream_write (stream, doc, nl - doc);
}
@@ -1111,46 +1169,98 @@ argp_args_usage (const struct argp *argp, char **levels, int advance,
then the first is as well. If FIRST_ONLY is true, only the first
occurance is output. Returns true if anything was output. */
static int
-argp_doc (const struct argp *argp, int post, int pre_blank, int first_only,
+argp_doc (const struct argp *argp, const struct argp_state *state,
+ int post, int pre_blank, int first_only,
argp_fmtstream_t stream)
{
- const struct argp_child *child = argp->children;
- const char *doc = argp->doc;
+ const char *text;
+ const char *inp_text;
+ void *input = 0;
int anything = 0;
+ size_t inp_text_limit = 0;
+ const char *doc = gettext (argp->doc);
+ const struct argp_child *child = argp->children;
if (doc)
{
char *vt = strchr (doc, '\v');
+ inp_text = post ? (vt ? vt + 1 : 0) : doc;
+ inp_text_limit = (!post && vt) ? (vt - doc) : 0;
+ }
+ else
+ inp_text = 0;
- if (pre_blank && (vt || !post))
+ if (argp->help_filter)
+ /* We have to filter the doc strings. */
+ {
+ if (inp_text_limit)
+ /* Copy INP_TEXT so that it's nul-terminated. */
+ inp_text = strndup (inp_text, inp_text_limit);
+ input = __argp_input (argp, state);
+ text =
+ (*argp->help_filter) (post
+ ? ARGP_KEY_HELP_POST_DOC
+ : ARGP_KEY_HELP_PRE_DOC,
+ inp_text, input);
+ }
+ else
+ text = (const char *) inp_text;
+
+ if (text)
+ {
+ if (pre_blank)
__argp_fmtstream_putc (stream, '\n');
- if (vt)
- if (post)
- __argp_fmtstream_puts (stream, vt + 1);
- else
- __argp_fmtstream_write (stream, doc, vt - doc);
+ if (text == inp_text && inp_text_limit)
+ __argp_fmtstream_write (stream, inp_text, inp_text_limit);
else
- if (! post)
- __argp_fmtstream_puts (stream, doc);
+ __argp_fmtstream_puts (stream, text);
+
if (__argp_fmtstream_point (stream) > __argp_fmtstream_lmargin (stream))
__argp_fmtstream_putc (stream, '\n');
anything = 1;
}
+
+ if (text && text != inp_text)
+ free ((char *) text); /* Free TEXT returned from the help filter. */
+ if (inp_text && inp_text_limit && argp->help_filter)
+ free ((char *) inp_text); /* We copied INP_TEXT, so free it now. */
+
+ if (post && argp->help_filter)
+ /* Now see if we have to output a ARGP_KEY_HELP_EXTRA text. */
+ {
+ text = (*argp->help_filter) (ARGP_KEY_HELP_EXTRA, 0, input);
+ if (text)
+ {
+ if (anything || pre_blank)
+ __argp_fmtstream_putc (stream, '\n');
+ __argp_fmtstream_puts (stream, text);
+ free ((char *) text);
+ if (__argp_fmtstream_point (stream)
+ > __argp_fmtstream_lmargin (stream))
+ __argp_fmtstream_putc (stream, '\n');
+ anything = 1;
+ }
+ }
+
if (child)
while (child->argp && !(first_only && anything))
anything |=
- argp_doc ((child++)->argp, post, anything || pre_blank, first_only,
+ argp_doc ((child++)->argp, state,
+ post, anything || pre_blank, first_only,
stream);
return anything;
}
-/* Output a usage message for ARGP to STREAM. FLAGS are from the set
- ARGP_HELP_*. NAME is what to use wherever a `program name' is needed. */
-void __argp_help (const struct argp *argp, FILE *stream,
- unsigned flags, char *name)
+/* Output a usage message for ARGP to STREAM. If called from
+ argp_state_help, STATE is the relevent parsing state. FLAGS are from the
+ set ARGP_HELP_*. NAME is what to use wherever a `program name' is
+ needed. */
+static void
+_help (const struct argp *argp, const struct argp_state *state, FILE *stream,
+ unsigned flags, char *name)
{
int anything = 0; /* Whether we've output anything. */
struct hol *hol = 0;
@@ -1190,7 +1300,8 @@ void __argp_help (const struct argp *argp, FILE *stream,
char *levels = pattern_levels;
__argp_fmtstream_printf (fs, "%s %s",
- first_pattern ? "Usage:" : " or: ", name);
+ _(first_pattern ? "Usage:" : " or: "),
+ name);
/* We set the lmargin as well as the wmargin, because hol_usage
manually wraps options with newline to avoid annoying breaks. */
@@ -1200,7 +1311,7 @@ void __argp_help (const struct argp *argp, FILE *stream,
/* Just show where the options go. */
{
if (hol->num_entries > 0)
- __argp_fmtstream_puts (fs, " [OPTION...]");
+ __argp_fmtstream_puts (fs, _(" [OPTION...]"));
}
else
/* Actually print the options. */
@@ -1223,13 +1334,13 @@ void __argp_help (const struct argp *argp, FILE *stream,
}
if (flags & ARGP_HELP_PRE_DOC)
- anything |= argp_doc (argp, 0, 0, 1, fs);
+ anything |= argp_doc (argp, state, 0, 0, 1, fs);
if (flags & ARGP_HELP_SEE)
{
- __argp_fmtstream_printf (fs,
- "Try `%s --help' or `%s --usage' for more information.\n",
- name, name);
+ __argp_fmtstream_printf (fs, _("\
+Try `%s --help' or `%s --usage' for more information.\n"),
+ name, name);
anything = 1;
}
@@ -1241,20 +1352,21 @@ void __argp_help (const struct argp *argp, FILE *stream,
{
if (anything)
__argp_fmtstream_putc (fs, '\n');
- hol_help (hol, fs);
+ hol_help (hol, state, fs);
anything = 1;
}
}
if (flags & ARGP_HELP_POST_DOC)
/* Print any documentation strings at the end. */
- anything |= argp_doc (argp, 1, anything, 0, fs);
+ anything |= argp_doc (argp, state, 1, anything, 0, fs);
if ((flags & ARGP_HELP_BUG_ADDR) && argp_program_bug_address)
{
if (anything)
__argp_fmtstream_putc (fs, '\n');
- __argp_fmtstream_printf (fs, "Report bugs to %s.\n", argp_program_bug_address);
+ __argp_fmtstream_printf (fs, _("Report bugs to %s.\n"),
+ argp_program_bug_address);
anything = 1;
}
@@ -1263,6 +1375,14 @@ void __argp_help (const struct argp *argp, FILE *stream,
__argp_fmtstream_free (fs);
}
+
+/* Output a usage message for ARGP to STREAM. FLAGS are from the set
+ ARGP_HELP_*. NAME is what to use wherever a `program name' is needed. */
+void __argp_help (const struct argp *argp, FILE *stream,
+ unsigned flags, char *name)
+{
+ _help (argp, 0, stream, flags, name);
+}
#ifdef weak_alias
weak_alias (__argp_help, argp_help)
#endif
@@ -1277,8 +1397,8 @@ __argp_state_help (struct argp_state *state, FILE *stream, unsigned flags)
if (state && (state->flags & ARGP_LONG_ONLY))
flags |= ARGP_HELP_LONG_ONLY;
- __argp_help (state ? state->argp : 0, stream, flags,
- state ? state->name : program_invocation_name);
+ _help (state ? state->argp : 0, state, stream, flags,
+ state ? state->name : program_invocation_short_name);
if (!state || ! (state->flags & ARGP_NO_EXIT))
{
@@ -1307,7 +1427,7 @@ __argp_error (struct argp_state *state, const char *fmt, ...)
{
va_list ap;
- fputs (state ? state->name : program_invocation_name, stream);
+ fputs (state ? state->name : program_invocation_short_name, stream);
putc (':', stream);
putc (' ', stream);
@@ -1343,7 +1463,7 @@ __argp_failure (struct argp_state *state, int status, int errnum,
if (stream)
{
- fputs (state ? state->name : program_invocation_name, stream);
+ fputs (state ? state->name : program_invocation_short_name, stream);
if (fmt)
{