diff options
Diffstat (limited to 'libshouldbeinlibc')
-rw-r--r-- | libshouldbeinlibc/argp-help.c | 302 |
1 files changed, 199 insertions, 103 deletions
diff --git a/libshouldbeinlibc/argp-help.c b/libshouldbeinlibc/argp-help.c index 024c03a9..9c93a2f6 100644 --- a/libshouldbeinlibc/argp-help.c +++ b/libshouldbeinlibc/argp-help.c @@ -35,7 +35,7 @@ #define LONG_OPT_COL 6 /* column in which long options start */ #define OPT_DOC_COL 29 /* column in which option text starts */ #define USAGE_INDENT 12 /* indentation of wrapped usage lines */ -#define RMARGIN 78 /* right margin used for wrapping */ +#define RMARGIN 79 /* right margin used for wrapping */ /* Returns true if OPT hasn't been marked invisible. Visibility only affects whether OPT is displayed or used in sorting, not option shadowing. */ @@ -135,12 +135,14 @@ struct hol_entry /* A list of options for help. */ struct hol { + /* The number of entries in this hol. If this field is zero, the others + are undefined. */ + unsigned num_entries; + /* An array of hol_entry's. */ + struct hol_entry *entries; /* A string containing all short options in this HOL. Each entry contains pointers into this string, so the order can't be messed with blindly. */ char *short_options; - /* An array of hol_entry's. */ - struct hol_entry *entries; - unsigned num_entries; }; /* Create a struct hol from an array of struct argp_option. */ @@ -154,43 +156,47 @@ struct hol *make_hol (struct argp_option *opt) assert (hol); - /* The first option must not be an alias. */ - assert (! oalias (opt)); - hol->num_entries = 0; - /* Calculate the space needed. */ - for (o = opt; ! oend (o); o++) + if (opt) { - if (! oalias (o)) - hol->num_entries++; - if (oshort (o)) - num_short_options++; /* This is an upper bound. */ - } + /* The first option must not be an alias. */ + assert (! oalias (opt)); - hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries); - hol->short_options = malloc (num_short_options); + /* Calculate the space needed. */ + for (o = opt; ! oend (o); o++) + { + if (! oalias (o)) + hol->num_entries++; + if (oshort (o)) + num_short_options++; /* This is an upper bound. */ + } - assert (hol->entries && hol->short_options); + hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries); + hol->short_options = malloc (num_short_options + 1); - /* Fill in the entries. */ - so = hol->short_options; - for (o = opt, entry = hol->entries; ! oend (o); entry++) - { - entry->opt = o; - entry->num = 0; - entry->short_options = so; - entry->sort_class = 0; + assert (hol->entries && hol->short_options); - do + /* Fill in the entries. */ + so = hol->short_options; + for (o = opt, entry = hol->entries; ! oend (o); entry++) { - entry->num++; - if (oshort (o) && ! find_char (o->key, hol->short_options, so)) - /* O has a valid short option which hasn't already been used. */ - *so++ = o->key; - o++; + entry->opt = o; + entry->num = 0; + entry->short_options = so; + entry->sort_class = 0; + + do + { + entry->num++; + if (oshort (o) && ! find_char (o->key, hol->short_options, so)) + /* O has a valid short option which hasn't already been used.*/ + *so++ = o->key; + o++; + } + while (! oend (o) && oalias (o)); } - while (! oend (o) && oalias (o)); + *so = '\0'; /* null terminated so we can find the length */ } return hol; @@ -200,8 +206,11 @@ struct hol *make_hol (struct argp_option *opt) static void hol_free (struct hol *hol) { - free (hol->entries); - free (hol->short_options); + if (hol->num_entries > 0) + { + free (hol->entries); + free (hol->short_options); + } free (hol); } @@ -281,7 +290,7 @@ static struct hol_entry *hol_find_entry (struct hol *hol, char *name) while (num_entries-- > 0) { - struct argp_option *opt = entry++->opt; + struct argp_option *opt = entry->opt; unsigned num_opts = entry->num; while (num_opts-- > 0) @@ -289,6 +298,8 @@ static struct hol_entry *hol_find_entry (struct hol *hol, char *name) return entry; else opt++; + + entry++; } return 0; @@ -337,18 +348,20 @@ hol_sort (struct hol *hol) char first2 = short2 ?: long2 ? *long2 : 0; /* Compare ignoring case, except when the options are both the same letter, in which case lower-case always comes first. */ - return (tolower (first2) - tolower (first1)) ?: first2 - first1; + return (tolower (first1) - tolower (first2)) ?: first2 - first1; } } else /* Order by class: 1, 2, ..., n, 0, -m, ..., -2, -1 */ if ((class1 < 0 && class2 < 0) || (class1 > 0 && class2 > 0)) - return class2 - class1; - else return class1 - class2; + else + return class2 - class1; } - qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry), entry_cmp); + if (hol->num_entries > 0) + qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry), + entry_cmp); } /* Append MORE to HOL, destroying MORE in the process. Options in HOL shadow @@ -356,6 +369,78 @@ hol_sort (struct hol *hol) static void hol_append (struct hol *hol, struct hol *more) { + if (more->num_entries == 0) + hol_free (more); + else if (hol->num_entries == 0) + { + hol->num_entries = more->num_entries; + hol->entries = more->entries; + hol->short_options = more->short_options; + /* We've stolen everything MORE from more. Destroy the empty shell. */ + free (more); + } + else + /* append the entries in MORE to those in HOL, taking care to only add + non-shadowed SHORT_OPTIONS values. */ + { + unsigned left; + char *so, *more_so; + struct hol_entry *e; + unsigned num_entries = hol->num_entries + more->num_entries; + struct hol_entry *entries = + malloc (num_entries * sizeof (struct hol_entry)); + unsigned hol_so_len = strlen (hol->short_options); + char *short_options = + malloc (hol_so_len + strlen (more->short_options) + 1); + + bcopy (hol->entries, entries, + hol->num_entries * sizeof (struct hol_entry)); + bcopy (more->entries, entries + hol->num_entries, + more->num_entries * sizeof (struct hol_entry)); + + bcopy (hol->short_options, short_options, hol_so_len); + + /* Fix up the short options pointers from HOL. */ + for (e = entries, left = hol->num_entries; left > 0; e++, left--) + e->short_options += (short_options - hol->short_options); + + /* Now add the short options from MORE, fixing up its entries too. */ + so = short_options + hol_so_len; + more_so = more->short_options; + for (left = more->num_entries; left > 0; e++, left--) + { + int opts_left; + struct argp_option *opt; + + e->short_options = so; + + for (opts_left = e->num, opt = e->opt; opts_left; opt++, opts_left--) + { + int ch = *more_so; + 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)) + /* The short option CH isn't shadowed by HOL's options, + so add it to the sum. */ + *so++ = ch; + more_so++; + } + } + } + + *so = '\0'; + + free (hol->entries); + free (hol->short_options); + + hol->entries = entries; + hol->num_entries = num_entries; + hol->short_options = short_options; + + hol_free (more); + } } static void @@ -424,7 +509,7 @@ hol_entry_help (struct hol_entry *entry, struct line *line) if (real->doc) { unsigned col = line_column (line); - char *doc = opt->doc; + char *doc = real->doc; if (col > OPT_DOC_COL + 3) line_newline (line, OPT_DOC_COL); @@ -475,68 +560,71 @@ add_usage_item (struct line *line, char *fmt, ...) static void hol_usage (struct hol *hol, struct line *line) { - unsigned nentries; - struct hol_entry *entry; - char *short_no_arg_opts = alloca (strlen (hol->short_options)); - char *snao_end = short_no_arg_opts; - - /* First we put a list of short options without arguments. */ - for (entry = hol->entries, nentries = hol->num_entries - ; nentries > 0 - ; entry++, nentries--) + if (hol->num_entries > 0) { - inline int func2 (struct argp_option *opt, struct argp_option *real) + unsigned nentries; + struct hol_entry *entry; + char *short_no_arg_opts = alloca (strlen (hol->short_options)); + char *snao_end = short_no_arg_opts; + + /* First we put a list of short options without arguments. */ + for (entry = hol->entries, nentries = hol->num_entries + ; nentries > 0 + ; entry++, nentries--) { - if (! (opt->arg || real->arg)) - *snao_end++ = opt->key; - return 0; + inline int func2 (struct argp_option *opt, struct argp_option *real) + { + if (! (opt->arg || real->arg)) + *snao_end++ = opt->key; + return 0; + } + hol_entry_short_iterate (entry, func2); + } + if (snao_end > short_no_arg_opts) + { + *snao_end++ = 0; + add_usage_item (line, "[-%s]", short_no_arg_opts); } - hol_entry_short_iterate (entry, func2); - } - if (snao_end > short_no_arg_opts) - { - *snao_end++ = 0; - add_usage_item (line, "[-%s]", short_no_arg_opts); - } - /* Now a list of short options *with* arguments. */ - for (entry = hol->entries, nentries = hol->num_entries - ; nentries > 0 - ; entry++, nentries--) - { - inline int func3 (struct argp_option *opt, struct argp_option *real) + /* Now a list of short options *with* arguments. */ + for (entry = hol->entries, nentries = hol->num_entries + ; nentries > 0 + ; entry++, nentries--) { - if (opt->arg || real->arg) - if ((opt->flags | real->flags) & OPTION_ARG_OPTIONAL) - add_usage_item (line, "[-%c[%s]]", - opt->key, opt->arg ?: real->arg); - else - add_usage_item (line, "[-%c %s]", - opt->key, opt->arg ?: real->arg); - return 0; + inline int func3 (struct argp_option *opt, struct argp_option *real) + { + if (opt->arg || real->arg) + if ((opt->flags | real->flags) & OPTION_ARG_OPTIONAL) + add_usage_item (line, "[-%c[%s]]", + opt->key, opt->arg ?: real->arg); + else + add_usage_item (line, "[-%c %s]", + opt->key, opt->arg ?: real->arg); + return 0; + } + hol_entry_short_iterate (entry, func3); } - hol_entry_short_iterate (entry, func3); - } - /* Finally, a list of long options (whew!). */ - for (entry = hol->entries, nentries = hol->num_entries - ; nentries > 0 - ; entry++, nentries--) - { - int func4 (struct argp_option *opt, struct argp_option *real) + /* Finally, a list of long options (whew!). */ + for (entry = hol->entries, nentries = hol->num_entries + ; nentries > 0 + ; entry++, nentries--) { - if (opt->arg || real->arg) - if ((opt->flags | real->flags) & OPTION_ARG_OPTIONAL) - add_usage_item (line, "[--%s[=%s]]", - opt->name, opt->arg ?: real->arg); - else - add_usage_item (line, "[--%s=%s]", - opt->name, opt->arg ?: real->arg); - else - add_usage_item (line, "[--%s]", opt->name); - return 0; + int func4 (struct argp_option *opt, struct argp_option *real) + { + if (opt->arg || real->arg) + if ((opt->flags | real->flags) & OPTION_ARG_OPTIONAL) + add_usage_item (line, "[--%s[=%s]]", + opt->name, opt->arg ?: real->arg); + else + add_usage_item (line, "[--%s=%s]", + opt->name, opt->arg ?: real->arg); + else + add_usage_item (line, "[--%s]", opt->name); + return 0; + } + hol_entry_long_iterate (entry, func4); } - hol_entry_long_iterate (entry, func4); } } @@ -585,8 +673,8 @@ argp_doc (struct argp *argp, struct line *line) } /* Output a usage message for ARGP to STREAM. FLAGS are from the set - ARGP_USAGE_*. */ -void argp_usage (struct argp *argp, FILE *stream, unsigned flags) + ARGP_HELP_*. */ +void argp_help (struct argp *argp, FILE *stream, unsigned flags) { int first = 1; struct hol *hol = 0; @@ -599,7 +687,7 @@ void argp_usage (struct argp *argp, FILE *stream, unsigned flags) line_newline (line, 0); } - if (flags & (ARGP_USAGE_USAGE | ARGP_USAGE_HELP)) + if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG)) { hol = argp_hol (argp); @@ -610,24 +698,32 @@ void argp_usage (struct argp *argp, FILE *stream, unsigned flags) hol_sort (hol); } - if (flags & ARGP_USAGE_USAGE) - /* Print a short help message. */ + if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE)) + /* Print a short `Usage:' message. */ { line_printf (line, "Usage: %s", program_invocation_name); - hol_usage (hol, line); + if (flags & ARGP_HELP_SHORT_USAGE) + /* Just show where the options go. */ + { + if (hol->num_entries > 0) + line_puts (line, " [OPTIONS...]"); + } + else + /* Actually print the options. */ + hol_usage (hol, line); argp_args_usage (argp, line); line_newline (line, 0); first = 0; } - if (flags & ARGP_USAGE_SEE) + if (flags & ARGP_HELP_SEE) { line_printf (line, "Try `%s --help' for more information.\n", program_invocation_name); first = 0; } - if (flags & ARGP_USAGE_HELP) + if (flags & ARGP_HELP_LONG) /* Print a long, detailed help message. */ { /* Print info about all the options. */ @@ -647,8 +743,8 @@ void argp_usage (struct argp *argp, FILE *stream, unsigned flags) line_free (line); - if (flags & ARGP_USAGE_EXIT_ERR) + if (flags & ARGP_HELP_EXIT_ERR) exit (1); - if (flags & ARGP_USAGE_EXIT_OK) + if (flags & ARGP_HELP_EXIT_OK) exit (0); } |