| 166 | } |
| 167 | |
| 168 | char *opt_usage(const char *argv0, const char *extra) |
| 169 | { |
| 170 | unsigned int i; |
| 171 | size_t max, len, width, indent; |
| 172 | char *ret; |
| 173 | |
| 174 | width = get_columns(); |
| 175 | if (width < MIN_TOTAL_WIDTH) |
| 176 | width = MIN_TOTAL_WIDTH; |
| 177 | |
| 178 | /* Figure out longest option. */ |
| 179 | indent = 0; |
| 180 | for (i = 0; i < opt_count; i++) { |
| 181 | size_t l; |
| 182 | if (opt_table[i].desc == opt_hidden) |
| 183 | continue; |
| 184 | if (opt_table[i].type == OPT_SUBTABLE) |
| 185 | continue; |
| 186 | l = strlen(opt_table[i].names); |
| 187 | if (opt_table[i].type == OPT_HASARG |
| 188 | && !strchr(opt_table[i].names, ' ') |
| 189 | && !strchr(opt_table[i].names, '=')) |
| 190 | l += strlen(" <arg>"); |
| 191 | if (l + 2 > indent) |
| 192 | indent = l + 2; |
| 193 | } |
| 194 | |
| 195 | /* Now we know how much to indent */ |
| 196 | if (indent + MIN_DESC_WIDTH > width) |
| 197 | indent = width - MIN_DESC_WIDTH; |
| 198 | |
| 199 | len = max = 0; |
| 200 | ret = NULL; |
| 201 | |
| 202 | ret = add_str(ret, &len, &max, "Usage: "); |
| 203 | ret = add_str(ret, &len, &max, argv0); |
| 204 | |
| 205 | /* Find usage message from among registered options if necessary. */ |
| 206 | if (!extra) { |
| 207 | extra = ""; |
| 208 | for (i = 0; i < opt_count; i++) { |
| 209 | if (opt_table[i].cb == (void *)opt_usage_and_exit |
| 210 | && opt_table[i].u.carg) { |
| 211 | extra = opt_table[i].u.carg; |
| 212 | break; |
| 213 | } |
| 214 | } |
| 215 | } |
| 216 | ret = add_str(ret, &len, &max, " "); |
| 217 | ret = add_str(ret, &len, &max, extra); |
| 218 | ret = add_str(ret, &len, &max, "\n"); |
| 219 | |
| 220 | for (i = 0; i < opt_count; i++) { |
| 221 | if (opt_table[i].desc == opt_hidden) |
| 222 | continue; |
| 223 | if (opt_table[i].type == OPT_SUBTABLE) { |
| 224 | ret = add_str(ret, &len, &max, opt_table[i].desc); |
| 225 | ret = add_str(ret, &len, &max, ":\n"); |