2 * UCW Library -- Formatting of command-line option help
4 * (c) 2013 Jan Moskyto Matejka <mq@ucw.cz>
5 * (c) 2014 Martin Mares <mj@ucw.cz>
7 * This software may be freely distributed and used according to the terms
8 * of the GNU Lesser General Public License.
13 #include <ucw/opt-internal.h>
14 #include <ucw/mempool.h>
21 struct help_line *lines; // A growing array of lines
29 static void opt_help_scan_item(struct help *h, struct opt_precomputed *opt)
31 const struct opt_item *item = opt->item;
37 if (item->cls == OPT_CL_HELP) {
38 if (item->flags & OPT_HELP_COL) {
41 struct help_line *l = GARY_PUSH(h->lines);
42 l->extra = item->help;
47 if (item->letter >= OPT_POSITIONAL_TAIL)
50 struct help_line *first = GARY_PUSH(h->lines);
51 char *text = mp_strdup(h->pool, item->help);
52 struct help_line *l = first;
54 char *eol = strchr(text, '\n');
58 int field = (l == first && !force_col1 ? 1 : 0);
61 char *tab = strchr(f, '\t');
65 l->fields[field++] = f;
71 l = GARY_PUSH(h->lines);
75 char *val = first->fields[1] ? : "";
76 if (opt->flags & OPT_REQUIRED_VALUE)
77 val = mp_printf(h->pool, "=%s", val);
78 else if (!(opt->flags & OPT_NO_VALUE))
79 val = mp_printf(h->pool, "[=%s]", val);
80 first->fields[1] = mp_printf(h->pool, "--%s%s", item->name, val);
85 first->fields[0] = mp_printf(h->pool, "-%c, ", item->letter);
87 char *val = first->fields[1] ? : "";
88 if (!(opt->flags & OPT_REQUIRED_VALUE) && !(opt->flags & OPT_NO_VALUE))
89 val = mp_printf(h->pool, "[%s]", val);
90 first->fields[0] = mp_printf(h->pool, "-%c%s", item->letter, val);
91 first->fields[1] = NULL;
96 static void opt_help_scan(struct help *h, const struct opt_section *sec)
98 for (const struct opt_item * item = sec->opt; item->cls != OPT_CL_END; item++) {
99 if (item->cls == OPT_CL_SECTION)
100 opt_help_scan(h, item->u.section);
101 else if (item->cls == OPT_CL_HOOK)
104 struct opt_precomputed opt;
105 opt_precompute(&opt, item);
106 opt_help_scan_item(h, &opt);
111 void opt_help(const struct opt_section * sec) {
114 h.pool = mp_new(4096);
115 GARY_INIT_ZERO(h.lines, 0);
116 opt_help_scan(&h, sec);
118 // Calculate natural width of each column
119 uint n = GARY_SIZE(h.lines);
120 uint widths[3] = { 0, 0, 0 };
121 for (uint i=0; i<n; i++) {
122 struct help_line *l = &h.lines[i];
123 for (uint f=0; f<3; f++) {
126 uint w = strlen(l->fields[f]);
127 widths[f] = MAX(widths[f], w);
132 * This is tricky: if there are short options, which have an argument,
133 * but no long variant, we are willing to let column 0 overflow to column 1.
135 widths[1] = MAX(widths[1], widths[0] - 4);
141 for (uint i=0; i<n; i++) {
142 struct help_line *l = &h.lines[i];
147 for (uint f=0; f<3; f++) {
149 t -= printf("%s", l->fields[f]);
164 void opt_handle_help(const struct opt_item * opt UNUSED, const char * value UNUSED, void * data)
166 struct opt_context *oc = data;
167 opt_help(oc->options);