| 101 | } |
| 102 | |
| 103 | static char *add_desc(char *base, size_t *len, size_t *max, |
| 104 | unsigned int indent, unsigned int width, |
| 105 | const struct opt_table *opt) |
| 106 | { |
| 107 | size_t off, prefix, l; |
| 108 | const char *p; |
| 109 | bool same_line = false, start = true; |
| 110 | |
| 111 | base = add_str(base, len, max, opt->names); |
| 112 | off = strlen(opt->names); |
| 113 | if ((opt->type & OPT_HASARG) |
| 114 | && !strchr(opt->names, ' ') |
| 115 | && !strchr(opt->names, '=')) { |
| 116 | base = add_str(base, len, max, " <arg>"); |
| 117 | off += strlen(" <arg>"); |
| 118 | } |
| 119 | |
| 120 | /* Do we start description on next line? */ |
| 121 | if (off + 2 > indent) { |
| 122 | base = add_str(base, len, max, "\n"); |
| 123 | off = 0; |
| 124 | } else { |
| 125 | base = add_indent(base, len, max, indent - off); |
| 126 | off = indent; |
| 127 | same_line = true; |
| 128 | } |
| 129 | |
| 130 | /* Indent description. */ |
| 131 | p = opt->desc; |
| 132 | while ((l = consume_words(p, width - indent, &prefix, &start)) != 0) { |
| 133 | if (!same_line) |
| 134 | base = add_indent(base, len, max, indent); |
| 135 | p += prefix; |
| 136 | base = add_str_len(base, len, max, p, l); |
| 137 | base = add_str(base, len, max, "\n"); |
| 138 | off = indent + l; |
| 139 | p += l; |
| 140 | same_line = false; |
| 141 | } |
| 142 | |
| 143 | /* Empty description? Make it match normal case. */ |
| 144 | if (same_line) |
| 145 | base = add_str(base, len, max, "\n"); |
| 146 | |
| 147 | if (opt->show) { |
| 148 | char buf[OPT_SHOW_LEN + sizeof("...")]; |
| 149 | strcpy(buf + OPT_SHOW_LEN, "..."); |
| 150 | opt->show(buf, opt->u.arg); |
| 151 | |
| 152 | /* If it doesn't fit on this line, indent. */ |
| 153 | if (off + strlen(" (default: ") + strlen(buf) + strlen(")") |
| 154 | > width) { |
| 155 | base = add_indent(base, len, max, indent); |
| 156 | } else { |
| 157 | /* Remove \n. */ |
| 158 | (*len)--; |
| 159 | } |
| 160 | |