#include #include #include #include #include #include "private.h" /* We only use this for pointer comparisons. */ const char opt_hidden[1] = { 0 }; static unsigned write_short_options(char *str) { unsigned int i, num = 0; const char *p; for (p = first_sopt(&i); p; p = next_sopt(p, &i)) { if (opt_table[i].desc != opt_hidden) str[num++] = *p; } return num; } #define OPT_SPACE_PAD " " /* FIXME: Get all purdy. */ char *opt_usage(const char *argv0, const char *extra) { unsigned int i, num, len; char *ret, *p; if (!extra) { extra = ""; for (i = 0; i < opt_count; i++) { if (opt_table[i].cb == (void *)opt_usage_and_exit && opt_table[i].u.carg) { extra = (const char *)opt_table[i].u.carg; break; } } } /* An overestimate of our length. */ len = strlen("Usage: %s ") + strlen(argv0) + strlen("[-%.*s]") + opt_num_short + 1 + strlen(" ") + strlen(extra) + strlen("\n"); for (i = 0; i < opt_count; i++) { if (opt_table[i].type == OPT_SUBTABLE) { len += strlen("\n") + strlen(opt_table[i].desc) + strlen(":\n"); } else if (opt_table[i].desc != opt_hidden) { len += strlen(opt_table[i].names) + strlen(" "); len += strlen(OPT_SPACE_PAD) + strlen(opt_table[i].desc) + 1; if (opt_table[i].show) { len += strlen("(default: %s)") + OPT_SHOW_LEN + sizeof("..."); } len += strlen("\n"); } } p = ret = (char *)malloc(len); if (!ret) return NULL; p += sprintf(p, "Usage: %s", argv0); p += sprintf(p, " [-"); num = write_short_options(p); if (num) { p += num; p += sprintf(p, "]"); } else { /* Remove start of single-entry options */ p -= 3; } if (extra) p += sprintf(p, " %s", extra); p += sprintf(p, "\n"); for (i = 0; i < opt_count; i++) { if (opt_table[i].desc == opt_hidden) continue; if (opt_table[i].type == OPT_SUBTABLE) { p += sprintf(p, "%s:\n", opt_table[i].desc); continue; } len = sprintf(p, "%s", opt_table[i].names); if (opt_table[i].type == OPT_HASARG && !strchr(opt_table[i].names, ' ') && !strchr(opt_table[i].names, '=')) len += sprintf(p + len, " "); len += sprintf(p + len, "%.*s", len < strlen(OPT_SPACE_PAD) ? (unsigned)strlen(OPT_SPACE_PAD) - len : 1, OPT_SPACE_PAD); len += sprintf(p + len, "%s", opt_table[i].desc); if (opt_table[i].show) { char buf[OPT_SHOW_LEN + sizeof("...")]; strcpy(buf + OPT_SHOW_LEN, "..."); opt_table[i].show(buf, opt_table[i].u.arg); len += sprintf(p + len, " (default: %s)", buf); } p += len; p += sprintf(p, "\n"); } *p = '\0'; return ret; }