X-Git-Url: https://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fargp-help.c;h=1a4131fd99b48bf4b1e888f85cb38f481a071125;hb=6684d992bfedd21bf8dea1fbb52392c1d7c8159b;hp=7af716c786c2e9e06982c6a245ec1f2d8dc5b347;hpb=0da836338cf9d8c10da7d0b9825bcbceeff57090;p=gnulib.git diff --git a/lib/argp-help.c b/lib/argp-help.c index 7af716c78..1a4131fd9 100644 --- a/lib/argp-help.c +++ b/lib/argp-help.c @@ -1,5 +1,5 @@ /* Hierarchial argument parsing help output - Copyright (C) 1995-2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1995-2005, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Miles Bader . @@ -50,7 +50,6 @@ #include "argp.h" #include "argp-fmtstream.h" #include "argp-namefrob.h" -#include "dirname.h" #ifndef SIZE_MAX # define SIZE_MAX ((size_t) -1) @@ -90,15 +89,15 @@ struct uparams 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. */ + int short_opt_col; /* column in which short options start */ + int long_opt_col; /* column in which long options start */ + int doc_opt_col; /* column in which doc options start */ + int opt_doc_col; /* column in which option text starts */ + int header_col; /* column in which group headers are printed */ + int usage_indent; /* indentation of wrapped usage lines */ + int rmargin; /* right margin used for wrapping */ + + int valid; /* True when the values in here are valid. */ }; /* This is a global variable, as user options are only ever read once. */ @@ -132,91 +131,126 @@ static const struct uparam_name uparam_names[] = { 0 } }; -/* Read user options from the environment, and fill in UPARAMS appropiately. */ +static void +validate_uparams (const struct argp_state *state, struct uparams *upptr) +{ + const struct uparam_name *up; + + for (up = uparam_names; up->name; up++) + { + if (up->is_bool + || up->uparams_offs == offsetof (struct uparams, rmargin)) + continue; + if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin) + { + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, + "\ +ARGP_HELP_FMT: %s value is less than or equal to %s"), + "rmargin", up->name); + return; + } + } + uparams = *upptr; + uparams.valid = 1; +} + +/* 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); + struct uparams new_params = uparams; + +#define SKIPWS(p) do { while (isspace ((unsigned char) *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); + { + /* Parse var. */ + while (*var) + { + SKIPWS (var); + + if (isalpha ((unsigned char) *var)) + { + size_t var_len; + const struct uparam_name *un; + int unspec = 0, val = 0; + const char *arg = var; - if (*arg == '\0' || *arg == ',') - unspec = 1; - else if (*arg == '=') - { + while (isalnum ((unsigned char) *arg) || *arg == '-' || *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)) + var_len = arg - var; + + SKIPWS (arg); + + if (*arg == '\0' || *arg == ',') + unspec = 1; + else if (*arg == '=') + { arg++; - SKIPWS (arg); - } - - for (un = uparam_names; un->name; un++) - if (strlen (un->name) == var_len - && strncmp (var, un->name, var_len) == 0) + SKIPWS (arg); + } + + if (unspec) { - if (unspec && !un->is_bool) - __argp_failure (state, 0, 0, - dgettext (state->root_argp->argp_domain, "\ -%.*s: ARGP_HELP_FMT parameter requires a value"), - (int) var_len, var); + if (var[0] == 'n' && var[1] == 'o' && var[2] == '-') + { + val = 0; + var += 3; + var_len -= 3; + } else - *(int *)((char *)&uparams + un->uparams_offs) = val; - break; + val = 1; } - if (! un->name) - __argp_failure (state, 0, 0, - dgettext (state->root_argp->argp_domain, "\ + else if (isdigit ((unsigned char) *arg)) + { + val = atoi (arg); + while (isdigit ((unsigned char) *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, + dgettext (state->root_argp->argp_domain, + "\ +%.*s: ARGP_HELP_FMT parameter requires a value"), + (int) var_len, var); + else if (val < 0) + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, + "\ +%.*s: ARGP_HELP_FMT parameter must be positive"), + (int) var_len, var); + else + *(int *)((char *)&new_params + un->uparams_offs) = val; + break; + } + if (! un->name) + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, "\ %.*s: Unknown ARGP_HELP_FMT parameter"), - (int) var_len, var); + (int) var_len, var); - var = arg; - if (*var == ',') - var++; - } - else if (*var) - { - __argp_failure (state, 0, 0, - dgettext (state->root_argp->argp_domain, - "Garbage in ARGP_HELP_FMT: %s"), var); - break; - } - } + var = arg; + if (*var == ',') + var++; + } + else if (*var) + { + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, + "Garbage in ARGP_HELP_FMT: %s"), var); + break; + } + } + validate_uparams (state, &new_params); + } } /* Returns true if OPT hasn't been marked invisible. Visibility only affects @@ -341,6 +375,9 @@ struct hol_entry /* The argp from which this option came. */ const struct argp *argp; + + /* Position in the array */ + unsigned ord; }; /* A cluster of entries to reflect the argp tree structure. */ @@ -558,7 +595,7 @@ hol_entry_long_iterate (const struct hol_entry *entry, } /* Iterator that returns true for the first short option. */ -static inline int +static int until_short (const struct argp_option *opt, const struct argp_option *real, const char *domain, void *cookie) { @@ -639,10 +676,12 @@ static int hol_cluster_cmp (const struct hol_cluster *cl1, const struct hol_cluster *cl2) { /* If one cluster is deeper than the other, use its ancestor at the same - level, so that finding the common ancestor is straightforward. */ - while (cl1->depth < cl2->depth) + level, so that finding the common ancestor is straightforward. + + clN->depth > 0 means that clN->parent != NULL (see hol_add_cluster) */ + while (cl1->depth > cl2->depth) cl1 = cl1->parent; - while (cl2->depth < cl1->depth) + while (cl2->depth > cl1->depth) cl2 = cl2->parent; /* Now reduce both clusters to their ancestors at the point where both have @@ -686,17 +725,19 @@ canon_doc_option (const char **name) else { /* Skip initial whitespace. */ - while (isspace (**name)) + while (isspace ((unsigned char) **name)) (*name)++; /* Decide whether this looks like an option (leading `-') or not. */ non_opt = (**name != '-'); /* Skip until part of name used for sorting. */ - while (**name && !isalnum (**name)) + while (**name && !isalnum ((unsigned char) **name)) (*name)++; } return non_opt; } +#define HOL_ENTRY_PTRCMP(a,b) ((a)->ord < (b)->ord ? -1 : 1) + /* Order ENTRY1 & ENTRY2 by the order which they should appear in a help listing. */ static int @@ -706,6 +747,7 @@ hol_entry_cmp (const struct hol_entry *entry1, /* The group numbers by which the entries should be ordered; if either is in a cluster, then this is just the group within the cluster. */ int group1 = entry1->group, group2 = entry2->group; + int rc; if (entry1->cluster != entry2->cluster) { @@ -722,7 +764,8 @@ hol_entry_cmp (const struct hol_entry *entry1, return group_cmp (hol_cluster_base (entry1->cluster)->group, group2, 1); else /* Both entries are in clusters, we can just compare the clusters. */ - return hol_cluster_cmp (entry1->cluster, entry2->cluster); + return (rc = hol_cluster_cmp (entry1->cluster, entry2->cluster)) ? + rc : HOL_ENTRY_PTRCMP(entry1, entry2); } else if (group1 == group2) /* The entries are both in the same cluster and group, so compare them @@ -746,7 +789,8 @@ hol_entry_cmp (const struct hol_entry *entry1, return doc1 - doc2; else if (!short1 && !short2 && long1 && long2) /* Only long options. */ - return __strcasecmp (long1, long2); + return (rc = __strcasecmp (long1, long2)) ? + rc : HOL_ENTRY_PTRCMP(entry1, entry2); else /* Compare short/short, long/short, short/long, using the first character of long options. Entries without *any* valid @@ -763,13 +807,15 @@ hol_entry_cmp (const struct hol_entry *entry1, #endif /* Compare ignoring case, except when the options are both the same letter, in which case lower-case always comes first. */ - return lower_cmp ? lower_cmp : first2 - first1; + return lower_cmp ? lower_cmp : + (rc = first2 - first1) ? + rc : HOL_ENTRY_PTRCMP(entry1, entry2); } } else /* Within the same cluster, but not the same group, so just compare groups. */ - return group_cmp (group1, group2, 0); + return group_cmp (group1, group2, HOL_ENTRY_PTRCMP(entry1, entry2)); } /* Version of hol_entry_cmp with correct signature for qsort. */ @@ -786,8 +832,14 @@ static void hol_sort (struct hol *hol) { if (hol->num_entries > 0) - qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry), - hol_entry_qcmp); + { + unsigned i; + struct hol_entry *e; + for (i = 0, e = hol->entries; i < hol->num_entries; i++, e++) + e->ord = i; + qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry), + hol_entry_qcmp); + } } /* Append MORE to HOL, destroying MORE in the process. Options in HOL shadow @@ -1270,7 +1322,7 @@ usage_long_opt (const struct argp_option *opt, if (! arg) arg = real->arg; - if (! (flags & OPTION_NO_USAGE)) + if (! (flags & OPTION_NO_USAGE) && !odoc (opt)) { if (arg) { @@ -1441,46 +1493,51 @@ argp_doc (const struct argp *argp, const struct argp_state *state, { const char *text; const char *inp_text; + size_t inp_text_len = 0; + const char *trans_text; void *input = 0; int anything = 0; - size_t inp_text_limit = 0; - const char *doc = dgettext (argp->argp_domain, argp->doc); const struct argp_child *child = argp->children; - if (doc) + if (argp->doc) { - char *vt = strchr (doc, '\v'); - inp_text = post ? (vt ? vt + 1 : 0) : doc; - inp_text_limit = (!post && vt) ? (vt - doc) : 0; + char *vt = strchr (argp->doc, '\v'); + if (vt) + { + if (post) + inp_text = vt + 1; + else + { + inp_text_len = vt - argp->doc; + inp_text = __strndup (argp->doc, inp_text_len); + } + } + else + inp_text = post ? 0 : argp->doc; + trans_text = inp_text ? dgettext (argp->argp_domain, inp_text) : NULL; } else - inp_text = 0; + trans_text = inp_text = 0; 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); + trans_text, input); } else - text = (const char *) inp_text; + text = (const char *) trans_text; if (text) { if (pre_blank) __argp_fmtstream_putc (stream, '\n'); - if (text == inp_text && inp_text_limit) - __argp_fmtstream_write (stream, inp_text, inp_text_limit); - else - __argp_fmtstream_puts (stream, text); + __argp_fmtstream_puts (stream, text); if (__argp_fmtstream_point (stream) > __argp_fmtstream_lmargin (stream)) __argp_fmtstream_putc (stream, '\n'); @@ -1488,9 +1545,10 @@ argp_doc (const struct argp *argp, const struct argp_state *state, anything = 1; } - if (text && text != inp_text) + if (text && text != trans_text) free ((char *) text); /* Free TEXT returned from the help filter. */ - if (inp_text && inp_text_limit && argp->help_filter) + + if (inp_text && inp_text_len) free ((char *) inp_text); /* We copied INP_TEXT, so free it now. */ if (post && argp->help_filter) @@ -1679,15 +1737,6 @@ void __argp_help (const struct argp *argp, FILE *stream, weak_alias (__argp_help, argp_help) #endif -char * -__argp_base_name (char *name) -{ - char *p; - for (p = name + strlen (name); p > name && !ISSLASH (p[-1]); p--) - ; - return p; -} - #if ! (defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME) char * __argp_short_program_name (void)