+static char *add_str(char *base, size_t *len, size_t *max, const char *str)
+{
+ return add_str_len(base, len, max, str, strlen(str));
+}
+
+static char *add_indent(char *base, size_t *len, size_t *max, size_t indent)
+{
+ if (indent >= *max - *len)
+ base = realloc(base, *max = (*max * 2 + indent + 1));
+ memset(base + *len, ' ', indent);
+ *len += indent;
+ return base;
+}
+
+static char *add_desc(char *base, size_t *len, size_t *max,
+ unsigned int indent, unsigned int width,
+ const struct opt_table *opt)
+{
+ size_t off, prefix, l;
+ const char *p;
+ bool same_line = false;
+
+ base = add_str(base, len, max, opt->names);
+ off = strlen(opt->names);
+ if (opt->type == OPT_HASARG
+ && !strchr(opt->names, ' ')
+ && !strchr(opt->names, '=')) {
+ base = add_str(base, len, max, " <arg>");
+ off += strlen(" <arg>");
+ }
+
+ /* Do we start description on next line? */
+ if (off + 2 > indent) {
+ base = add_str(base, len, max, "\n");
+ off = 0;
+ } else {
+ base = add_indent(base, len, max, indent - off);
+ off = indent;
+ same_line = true;
+ }
+
+ /* Indent description. */
+ p = opt->desc;
+ while ((l = consume_words(p, width - indent, &prefix)) != 0) {
+ if (!same_line)
+ base = add_indent(base, len, max, indent);
+ p += prefix;
+ base = add_str_len(base, len, max, p, l);
+ base = add_str(base, len, max, "\n");
+ off = indent + l;
+ p += l;
+ same_line = false;
+ }
+
+ /* Empty description? Make it match normal case. */
+ if (same_line)
+ base = add_str(base, len, max, "\n");
+
+ if (opt->show) {
+ char buf[OPT_SHOW_LEN + sizeof("...")];
+ strcpy(buf + OPT_SHOW_LEN, "...");
+ opt->show(buf, opt->u.arg);
+
+ /* If it doesn't fit on this line, indent. */
+ if (off + strlen(" (default: ") + strlen(buf) + strlen(")")
+ > width) {
+ base = add_indent(base, len, max, indent);
+ } else {
+ /* Remove \n. */
+ (*len)--;
+ }
+
+ base = add_str(base, len, max, " (default: ");
+ base = add_str(base, len, max, buf);
+ base = add_str(base, len, max, ")\n");
+ }
+ return base;
+}