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