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