diff options
author | Ulrich Drepper <drepper@redhat.com> | 1997-02-19 04:43:53 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 1997-02-19 04:43:53 +0000 |
commit | 1fb05e3db1891142410bc58c320dfe281749fffe (patch) | |
tree | 46299dbecec282055e3493787910444e77099fe7 /argp | |
parent | c84142e8fe3cbcce43ae35ac957a74ac8216d11d (diff) | |
download | glibc-1fb05e3db1891142410bc58c320dfe281749fffe.tar.gz glibc-1fb05e3db1891142410bc58c320dfe281749fffe.tar.xz glibc-1fb05e3db1891142410bc58c320dfe281749fffe.zip |
update from main archive 970218 cvs/libc-970221 cvs/libc-970220 cvs/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')
-rw-r--r-- | argp/argp-help.c | 324 | ||||
-rw-r--r-- | argp/argp-namefrob.h | 2 | ||||
-rw-r--r-- | argp/argp-parse.c | 31 | ||||
-rw-r--r-- | argp/argp-test.c | 98 | ||||
-rw-r--r-- | argp/argp.h | 66 |
5 files changed, 384 insertions, 137 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) { diff --git a/argp/argp-namefrob.h b/argp/argp-namefrob.h index fab7c9d94a..983ae9fc0a 100644 --- a/argp/argp-namefrob.h +++ b/argp/argp-namefrob.h @@ -30,6 +30,8 @@ #define __option_is_end _option_is_end #undef __option_is_short #define __option_is_short _option_is_short +#undef __argp_input +#define __argp_input _argp_input /* argp-help functions */ #undef __argp_help diff --git a/argp/argp-parse.c b/argp/argp-parse.c index f1f4ce9dfc..af27757273 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_name = arg; + program_invocation_short_name = arg; /* [Note that some systems only have PROGRAM_INVOCATION_SHORT_NAME (aka __PROGNAME), in which case, PROGRAM_INVOCATION_NAME is just defined @@ -119,7 +119,8 @@ argp_default_parser (int key, char *arg, struct argp_state *state) if ((state->flags & (ARGP_PARSE_ARGV0 | ARGP_NO_ERRS)) == ARGP_PARSE_ARGV0) - state->argv[0] = program_invocation_name; /* Update what getopt uses too. */ + /* Update what getopt uses too. */ + state->argv[0] = program_invocation_short_name; break; @@ -231,6 +232,9 @@ struct group /* This group's parsing function. */ argp_parser_t parser; + /* Which argp this group is from. */ + const struct argp *argp; + /* Points to the point in SHORT_OPTS corresponding to the end of the short options for this group. We use it to determine from which group a particular short options is from. */ @@ -380,6 +384,7 @@ convert_options (const struct argp *argp, } group->parser = argp->parser; + group->argp = argp; group->short_end = cvt->short_end; group->args_processed = 0; group->parent = parent; @@ -526,6 +531,7 @@ parser_init (struct parser *parser, const struct argp *argp, parser->state.err_stream = stderr; parser->state.out_stream = stdout; parser->state.next = 0; /* Tell getopt to initialize. */ + parser->state.pstate = parser; /* Call each parser for the first time, giving it a chance to propagate values to child parsers. */ @@ -848,3 +854,24 @@ __argp_parse (const struct argp *argp, int argc, char **argv, unsigned flags, #ifdef weak_alias weak_alias (__argp_parse, argp_parse) #endif + +/* Return the input field for ARGP in the parser corresponding to STATE; used + by the help routines. */ +void * +__argp_input (const struct argp *argp, const struct argp_state *state) +{ + if (state) + { + struct group *group; + struct parser *parser = state->pstate; + + for (group = parser->groups; group < parser->egroup; group++) + if (group->argp == argp) + return group->input; + } + + return 0; +} +#ifdef weak_alias +weak_alias (__argp_input, _argp_input) +#endif diff --git a/argp/argp-test.c b/argp/argp-test.c index ae72b2230c..1ce48c3e3f 100644 --- a/argp/argp-test.c +++ b/argp/argp-test.c @@ -22,9 +22,12 @@ #include <config.h> #endif +#include <stdlib.h> +#include <time.h> +#include <string.h> #include <argp.h> -char *argp_program_version = "argp-test 1.0"; +const char *argp_program_version = "argp-test 1.0"; struct argp_option sub_options[] = { @@ -64,10 +67,27 @@ sub_parse_opt (int key, char *arg, struct argp_state *state) return 0; } +static char * +sub_help_filter (int key, const char *text, void *input) +{ + if (key == ARGP_KEY_HELP_EXTRA) + return strdup ("This is some extra text from the sub parser (note that it \ +is preceded by a blank line)."); + else + return (char *)text; +} + static struct argp sub_argp = { - sub_options, sub_parse_opt, sub_args_doc, sub_doc + sub_options, sub_parse_opt, sub_args_doc, sub_doc, 0, sub_help_filter }; +/* Structure used to communicate with the parsing functions. */ +struct params +{ + unsigned foonly; /* Value parsed for foonly. */ + unsigned foonly_default; /* Default value for it. */ +}; + #define OPT_PGRP 1 #define OPT_SESS 2 @@ -89,7 +109,7 @@ struct argp_option options[] = " the current process)" }, {0,0,0,0, "Here are some more options:"}, - {"foonly", 'f', "ZOT", 0, "Glork a foonly"}, + {"foonly", 'f', "ZOT", OPTION_ARG_OPTIONAL, "Glork a foonly"}, {"zaza", 'z', 0, 0, "Snit a zar"}, {0} @@ -98,11 +118,28 @@ struct argp_option options[] = static const char args_doc[] = "STRING"; static const char doc[] = "Test program for argp." "\vThis doc string comes after the options." - "\nHey! Some manual formatting!"; + "\nHey! Some manual formatting!" + "\nThe current time is: %s"; + +static void +popt (int key, char *arg) +{ + char buf[10]; + if (isprint (key)) + sprintf (buf, "%c", key); + else + sprintf (buf, "%d", key); + if (arg) + printf ("KEY %s: %s\n", buf, arg); + else + printf ("KEY %s\n", buf); +} static error_t parse_opt (int key, char *arg, struct argp_state *state) { + struct params *params = state->input; + switch (key) { case ARGP_KEY_NO_ARGS: @@ -115,19 +152,17 @@ parse_opt (int key, char *arg, struct argp_state *state) printf ("ARG: %s\n", arg); break; + case 'f': + if (arg) + params->foonly = atoi (arg); + else + params->foonly = params->foonly_default; + popt (key, arg); + break; + case 'p': case 'P': case OPT_PGRP: case 'x': case 'Q': - case 'r': case OPT_SESS: case 'f': case 'z': - { - char buf[10]; - if (isprint (key)) - sprintf (buf, "%c", key); - else - sprintf (buf, "%d", key); - if (arg) - printf ("KEY %s: %s\n", buf, arg); - else - printf ("KEY %s\n", buf); - } + case 'r': case OPT_SESS: case 'z': + popt (key, arg); break; default: @@ -136,12 +171,39 @@ parse_opt (int key, char *arg, struct argp_state *state) return 0; } +static char * +help_filter (int key, const char *text, void *input) +{ + char *new_text; + struct params *params = input; + + if (key == ARGP_KEY_HELP_POST_DOC && text) + { + time_t now = time (0); + asprintf (&new_text, text, ctime (&now)); + } + else if (key == 'f') + /* Show the default for the --foonly option. */ + asprintf (&new_text, "%s (ZOT defaults to %x)", + text, params->foonly_default); + else + new_text = (char *) text; + + return new_text; +} + static struct argp_child argp_children[] = { { &sub_argp }, { 0 } }; -static struct argp argp = { options, parse_opt, args_doc, doc, argp_children }; +static struct argp argp = { + options, parse_opt, args_doc, doc, argp_children, help_filter +}; int main (int argc, char **argv) { - argp_parse (&argp, argc, argv, 0, 0, 0); + struct params params; + params.foonly = 0; + params.foonly_default = random (); + argp_parse (&argp, argc, argv, 0, 0, ¶ms); + printf ("After parsing: foonly = %x\n", params.foonly); return 0; } diff --git a/argp/argp.h b/argp/argp.h index be727561a1..2e20ea67f3 100644 --- a/argp/argp.h +++ b/argp/argp.h @@ -22,14 +22,20 @@ #define __ARGP_H__ #include <stdio.h> -#include <errno.h> #include <ctype.h> #include <getopt.h> +#define __need_error_t +#include <errno.h> + #ifndef __const #define __const const #endif +#ifndef __error_t_defined +typedef int error_t; +#endif + #ifndef __P # if (defined (__STDC__) && __STDC__) || defined (__cplusplus) # define __P(args) args @@ -194,7 +200,26 @@ struct argp their own argp structure, which you want to use in conjunction with your own. */ __const struct argp_child *children; + + /* If non-zero, this should be a function to filter the output of help + messages. KEY is either a key from an option, in which case TEXT is + that option's help text, or a special key from the ARGP_KEY_HELP_ + defines, below, describing which other help text TEXT is. The function + should return either TEXT, if it should be used as-is, a replacement + string, which should be malloced, and will be freed by argp, or NULL, + meaning `print nothing'. The value for TEXT is *after* any translation + has been done, so if any of the replacement text also needs translation, + that should be done by the filter function. INPUT is either the input + supplied to argp_parse, or NULL, if argp_help was called directly. */ + char *(*help_filter)(int __key, __const char *__text, void *__input); }; + +/* Possible KEY arguments to a help filter function. */ +#define ARGP_KEY_HELP_PRE_DOC 0x2000001 /* Help text preceeding options. */ +#define ARGP_KEY_HELP_POST_DOC 0x2000002 /* Help text following options. */ +#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. */ /* 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. */ @@ -265,6 +290,8 @@ struct argp_state /* Streams used when argp prints something. */ FILE *err_stream; /* For errors; initialized to stderr. */ FILE *out_stream; /* For information; initialized to stdout. */ + + void *pstate; /* Private, for use by argp. */ }; /* Flags for argp_parse (note that the defaults are those that are @@ -318,20 +345,20 @@ struct argp_state routine returned a non-zero value, it is returned; otherwise 0 is returned. This function may also call exit unless the ARGP_NO_HELP flag is set. INPUT is a pointer to a value to be passed in to the parser. */ -error_t argp_parse __P ((__const struct argp *__argp, - int __argc, char **__argv, unsigned __flags, - int *__arg_index, void *__input)); -error_t __argp_parse __P ((__const struct argp *__argp, - int __argc, char **__argv, unsigned __flags, - int *__arg_index, void *__input)); +extern error_t argp_parse __P ((__const struct argp *__argp, + int __argc, char **__argv, unsigned __flags, + int *__arg_index, void *__input)); +extern error_t __argp_parse __P ((__const struct argp *__argp, + int __argc, char **__argv, unsigned __flags, + int *__arg_index, void *__input)); /* Global variables. */ /* If defined or set by the user program to a non-zero value, then a default option --version is added (unless the ARGP_NO_HELP flag is used), which - will print this this string followed by a newline and exit (unless the + will print this string followed by a newline and exit (unless the ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */ -extern char *argp_program_version; +extern const char *argp_program_version; /* If defined or set by the user program to a non-zero value, then a default option --version is added (unless the ARGP_NO_HELP flag is used), which @@ -406,9 +433,11 @@ extern void __argp_usage __P ((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). */ -void argp_error __P ((struct argp_state *__state, __const char *__fmt, ...)) +extern void argp_error __P ((struct argp_state *__state, __const char *__fmt, + ...)) __attribute__ ((__format__ (__printf__, 2, 3))); -void __argp_error __P ((struct argp_state *__state, __const char *__fmt, ...)) +extern void __argp_error __P ((struct argp_state *__state, + __const char *__fmt, ...)) __attribute__ ((__format__ (__printf__, 2, 3))); /* Similar to the standard gnu error-reporting function error(), but will @@ -419,11 +448,11 @@ void __argp_error __P ((struct argp_state *__state, __const char *__fmt, ...)) 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. */ -void argp_failure __P ((struct argp_state *__state, - int __status, int __errnum, __const char *__fmt, ...)) +extern void argp_failure __P ((struct argp_state *__state, int __status, + int __errnum, __const char *__fmt, ...)) __attribute__ ((__format__ (__printf__, 4, 5))); -void __argp_failure __P ((struct argp_state *__state, - int __status, int __errnum, __const char *__fmt, ...)) +extern void __argp_failure __P ((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. */ @@ -434,6 +463,13 @@ extern int __option_is_short __P ((__const struct argp_option *__opt)); options array. */ extern int _option_is_end __P ((__const struct argp_option *__opt)); extern int __option_is_end __P ((__const struct argp_option *__opt)); + +/* Return the input field for ARGP in the parser corresponding to STATE; used + by the help routines. */ +extern void *_argp_input __P ((__const struct argp *argp, + __const struct argp_state *state)); +extern void *__argp_input __P ((__const struct argp *argp, + __const struct argp_state *state)); #ifdef __OPTIMIZE__ |