static const char *first_opt(unsigned *i, unsigned *len)
{
for (*i = 0; *i < opt_count; (*i)++) {
- if (opt_table[*i].flags == OPT_SUBTABLE)
+ if (opt_table[*i].type == OPT_SUBTABLE)
continue;
return first_name(opt_table[*i].names, len);
}
static const char *next_opt(const char *p, unsigned *i, unsigned *len)
{
for (; *i < opt_count; (*i)++) {
- if (opt_table[*i].flags == OPT_SUBTABLE)
+ if (opt_table[*i].type == OPT_SUBTABLE)
continue;
if (!p)
return first_name(opt_table[*i].names, len);
const char *p;
unsigned len;
- assert(entry->flags == OPT_HASARG || entry->flags == OPT_NOARG);
+ if (entry->type != OPT_HASARG && entry->type != OPT_NOARG)
+ errx(1, "Option %s: unknown entry type %u",
+ entry->names, entry->type);
+
+ if (!entry->desc)
+ errx(1, "Option %s: description cannot be NULL", entry->names);
+
+
+ if (entry->names[0] != '-')
+ errx(1, "Option %s: does not begin with '-'", entry->names);
- assert(entry->names[0] == '-');
for (p = first_name(entry->names, &len); p; p = next_name(p, &len)) {
if (*p == '-') {
- assert(len > 1);
+ if (len == 1)
+ errx(1, "Option %s: invalid long option '--'",
+ entry->names);
opt_num_long++;
} else {
- assert(len == 1);
- assert(*p != ':');
+ if (len != 1)
+ errx(1, "Option %s: invalid short option"
+ " '%.*s'", entry->names, len+1, p-1);
+ if (*p == ':')
+ errx(1, "Option %s: invalid short option '-:'",
+ entry->names);
opt_num_short++;
- if (entry->flags == OPT_HASARG) {
+ if (entry->type == OPT_HASARG) {
opt_num_short_arg++;
- /* FIXME: -? with ops breaks getopt_long */
- assert(*p != '?');
+ if (*p == '?')
+ errx(1, "Option %s: '-?' cannot take"
+ " an argument", entry->names);
}
}
/* Don't document args unless there are some. */
- if (entry->flags == OPT_NOARG)
- assert(p[len] != ' ' && p[len] != '=');
+ if (entry->type == OPT_NOARG) {
+ if (p[len] == ' ' || p[len] == '=')
+ errx(1, "Option %s: does not take arguments"
+ "'%s'", entry->names, p+len+1);
+ }
}
}
opt_table[opt_count++] = *entry;
}
-void _opt_register(const char *names, enum opt_flags flags,
+void _opt_register(const char *names, enum opt_type type,
char *(*cb)(void *arg),
char *(*cb_arg)(const char *optarg, void *arg),
void (*show)(char buf[OPT_SHOW_LEN], const void *arg),
{
struct opt_table opt;
opt.names = names;
- opt.flags = flags;
+ opt.type = type;
opt.cb = cb;
opt.cb_arg = cb_arg;
opt.show = show;
struct opt_table heading = OPT_SUBTABLE(NULL, desc);
add_opt(&heading);
}
- for (i = 0; entry[i].flags != OPT_END; i++) {
- if (entry[i].flags == OPT_SUBTABLE)
+ for (i = 0; entry[i].type != OPT_END; i++) {
+ if (entry[i].type == OPT_SUBTABLE)
opt_register_table(subtable_of(&entry[i]),
entry[i].desc);
else {
str[num++] = ':';
for (p = first_sopt(&i); p; p = next_sopt(p, &i)) {
str[num++] = *p;
- if (opt_table[i].flags == OPT_HASARG)
+ if (opt_table[i].type == OPT_HASARG)
str[num++] = ':';
}
str[num++] = '\0';
memcpy(buf, p, len);
buf[len] = 0;
options[num].name = buf;
- options[num].has_arg = (opt_table[i].flags == OPT_HASARG);
+ options[num].has_arg = (opt_table[i].type == OPT_HASARG);
options[num].flag = NULL;
options[num].val = 0;
num++;
else
e = find_long(longidx, &name);
- if (e->flags == OPT_HASARG)
+ if (e->type == OPT_HASARG)
problem = e->cb_arg(optarg, e->arg);
else
problem = e->cb(e->arg);
/* You can use this directly to build tables, but the macros will ensure
* consistency and type safety. */
-enum opt_flags {
+enum opt_type {
OPT_NOARG = 1, /* -f/--foo */
OPT_HASARG = 2, /* -f arg/--foo=arg/--foo arg */
OPT_SUBTABLE = 4, /* Actually, longopt points to a subtable... */
struct opt_table {
const char *names; /* slash-separated names, --longopt or -s */
- enum opt_flags flags;
+ enum opt_type type;
char *(*cb)(void *arg); /* OPT_NOARG */
char *(*cb_arg)(const char *optarg, void *arg); /* OPT_HASARG */
void (*show)(char buf[OPT_SHOW_LEN], const void *arg);
* @names: the names of the option eg. "--foo", "-f" or "--foo/-f/--foobar".
* @cb: the callback when the option is found.
* @arg: the argument to hand to @cb.
+ * @desc: the description for opt_usage(), or opt_hidden.
*
* This is a typesafe wrapper for intializing a struct opt_table. The callback
* of type "char *cb(type *)", "char *cb(const type *)" or "char *cb(void *)",
* See Also:
* OPT_WITH_ARG()
*/
-#define OPT_WITHOUT_ARG(names, cb, arg) \
- (names), OPT_CB_NOARG((cb), (arg))
+#define OPT_WITHOUT_ARG(names, cb, arg, desc) \
+ (names), OPT_CB_NOARG((cb), (arg)), (desc)
/**
* OPT_WITH_ARG() - macro for initializing long and short option (with arg)
* @cb: the callback when the option is found (along with <arg>).
* @show: the callback to print the value in get_usage (or NULL)
* @arg: the argument to hand to @cb and @show
+ * @desc: the description for opt_usage(), or opt_hidden.
*
* This is a typesafe wrapper for intializing a struct opt_table. The callback
* is of type "char *cb(const char *, type *)",
* See Also:
* OPT_WITHOUT_ARG()
*/
-#define OPT_WITH_ARG(name, cb, show, arg) \
- (name), OPT_CB_ARG((cb), (show), (arg))
+#define OPT_WITH_ARG(name, cb, show, arg, desc) \
+ (name), OPT_CB_ARG((cb), (show), (arg)), (desc)
/**
* OPT_SUBTABLE() - macro for including another table inside a table.
(arg)
/* Non-typesafe register function. */
-void _opt_register(const char *names, enum opt_flags flags,
+void _opt_register(const char *names, enum opt_type type,
char *(*cb)(void *arg),
char *(*cb_arg)(const char *optarg, void *arg),
void (*show)(char buf[OPT_SHOW_LEN], const void *arg),
plan_tests(12);
/* --aaa without args. */
- opt_register_arg("-a/--aaa", test_arg, NULL, "aaa", NULL);
+ opt_register_arg("-a/--aaa", test_arg, NULL, "aaa", "");
ok1(!parse_args(&argc, &argv, "--aaa", NULL));
ok1(strstr(err_output, ": --aaa: option requires an argument"));
free(err_output);
err_output = NULL;
/* Multiple */
- opt_register_arg("--bbb/-b/-c/--ccc", test_arg, NULL, "aaa", NULL);
+ opt_register_arg("--bbb/-b/-c/--ccc", test_arg, NULL, "aaa", "");
ok1(!parse_args(&argc, &argv, "--bbb", NULL));
ok1(strstr(err_output, ": --bbb: option requires an argument"));
free(err_output);
{
bool arg = false;
reset_options();
- opt_register_noarg("-a", opt_set_bool, &arg, NULL);
+ opt_register_noarg("-a", opt_set_bool, &arg, "");
ok1(parse_args(&argc, &argv, "-a", NULL));
ok1(arg);
- opt_register_arg("-b", opt_set_bool_arg, NULL, &arg, NULL);
+ opt_register_arg("-b", opt_set_bool_arg, NULL, &arg, "");
ok1(parse_args(&argc, &argv, "-b", "no", NULL));
ok1(!arg);
ok1(parse_args(&argc, &argv, "-b", "yes", NULL));
{
bool arg = true;
reset_options();
- opt_register_noarg("-a", opt_set_invbool, &arg, NULL);
+ opt_register_noarg("-a", opt_set_invbool, &arg, "");
ok1(parse_args(&argc, &argv, "-a", NULL));
ok1(!arg);
opt_register_arg("-b", opt_set_invbool_arg, NULL,
- &arg, NULL);
+ &arg, "");
ok1(parse_args(&argc, &argv, "-b", "no", NULL));
ok1(arg);
ok1(parse_args(&argc, &argv, "-b", "yes", NULL));
{
char *arg = (char *)"wrong";
reset_options();
- opt_register_arg("-a", opt_set_charp, NULL, &arg, NULL);
+ opt_register_arg("-a", opt_set_charp, NULL, &arg, "All");
ok1(parse_args(&argc, &argv, "-a", "string", NULL));
ok1(strcmp(arg, "string") == 0);
}
{
int arg = 1000;
reset_options();
- opt_register_arg("-a", opt_set_intval, NULL, &arg, NULL);
+ opt_register_arg("-a", opt_set_intval, NULL, &arg, "All");
ok1(parse_args(&argc, &argv, "-a", "9999", NULL));
ok1(arg == 9999);
ok1(parse_args(&argc, &argv, "-a", "-9999", NULL));
{
unsigned int arg = 1000;
reset_options();
- opt_register_arg("-a", opt_set_uintval, NULL, &arg, NULL);
+ opt_register_arg("-a", opt_set_uintval, NULL, &arg, "All");
ok1(parse_args(&argc, &argv, "-a", "9999", NULL));
ok1(arg == 9999);
ok1(!parse_args(&argc, &argv, "-a", "-9999", NULL));
{
long int arg = 1000;
reset_options();
- opt_register_arg("-a", opt_set_longval, NULL, &arg, NULL);
+ opt_register_arg("-a", opt_set_longval, NULL, &arg, "All");
ok1(parse_args(&argc, &argv, "-a", "9999", NULL));
ok1(arg == 9999);
ok1(parse_args(&argc, &argv, "-a", "-9999", NULL));
{
unsigned long int arg = 1000;
reset_options();
- opt_register_arg("-a", opt_set_ulongval, NULL, &arg, NULL);
+ opt_register_arg("-a", opt_set_ulongval, NULL, &arg, "All");
ok1(parse_args(&argc, &argv, "-a", "9999", NULL));
ok1(arg == 9999);
ok1(!parse_args(&argc, &argv, "-a", "-9999", NULL));
{
int arg = 1000;
reset_options();
- opt_register_noarg("-a", opt_inc_intval, &arg, NULL);
+ opt_register_noarg("-a", opt_inc_intval, &arg, "");
ok1(parse_args(&argc, &argv, "-a", NULL));
ok1(arg == 1001);
ok1(parse_args(&argc, &argv, "-a", "-a", NULL));
int exitval;
reset_options();
opt_register_noarg("-a",
- opt_version_and_exit, "1.2.3", NULL);
+ opt_version_and_exit, "1.2.3", "");
exitval = setjmp(exited);
if (exitval == 0) {
parse_args(&argc, &argv, "-a", NULL);
int exitval;
reset_options();
opt_register_noarg("-a",
- opt_usage_and_exit, "[args]", NULL);
+ opt_usage_and_exit, "[args]", "");
exitval = setjmp(exited);
if (exitval == 0) {
parse_args(&argc, &argv, "-a", NULL);
plan_tests(148);
/* Simple short arg.*/
- opt_register_noarg("-a", test_noarg, NULL, NULL);
+ opt_register_noarg("-a", test_noarg, NULL, "All");
ok1(parse_args(&argc, &argv, "-a", NULL));
ok1(argc == 1);
ok1(argv[0] == myname);
ok1(test_cb_called == 1);
/* Simple long arg. */
- opt_register_noarg("--aaa", test_noarg, NULL, NULL);
+ opt_register_noarg("--aaa", test_noarg, NULL, "AAAAll");
ok1(parse_args(&argc, &argv, "--aaa", NULL));
ok1(argc == 1);
ok1(argv[0] == myname);
ok1(test_cb_called == 2);
/* Both long and short args. */
- opt_register_noarg("--aaa/-a", test_noarg, NULL, NULL);
+ opt_register_noarg("--aaa/-a", test_noarg, NULL, "AAAAAAll");
ok1(parse_args(&argc, &argv, "--aaa", "-a", NULL));
ok1(argc == 1);
ok1(argv[0] == myname);
/* Argument variants. */
reset_options();
test_cb_called = 0;
- opt_register_arg("-a/--aaa", test_arg, NULL, "aaa", NULL);
+ opt_register_arg("-a/--aaa", test_arg, NULL, "aaa", "AAAAAAll");
ok1(parse_args(&argc, &argv, "--aaa", "aaa", NULL));
ok1(argc == 1);
ok1(argv[0] == myname);
reset_options();
/* glibc's getopt does not handle ? with arguments. */
- opt_register_noarg("-?", test_noarg, NULL, NULL);
+ opt_register_noarg("-?", test_noarg, NULL, "Help");
ok1(parse_args(&argc, &argv, "-?", NULL));
ok1(test_cb_called == 1);
ok1(parse_args(&argc, &argv, "-a", NULL) == false);
struct opt_table short_table[] = {
/* Short opts, different args. */
- { OPT_WITHOUT_ARG("-a", test_noarg, "a"), "Description of a" },
- { OPT_WITH_ARG("-b", test_arg, show_arg, "b"), "Description of b" },
+ { OPT_WITHOUT_ARG("-a", test_noarg, "a", "Description of a") },
+ { OPT_WITH_ARG("-b", test_arg, show_arg, "b", "Description of b") },
OPT_ENDTABLE
};
struct opt_table long_table[] = {
/* Long opts, different args. */
- { OPT_WITHOUT_ARG("--ddd", test_noarg, "ddd"), "Description of ddd" },
- { OPT_WITH_ARG("--eee <filename>", test_arg, show_arg, "eee"), },
+ { OPT_WITHOUT_ARG("--ddd", test_noarg, "ddd", "Description of ddd") },
+ { OPT_WITH_ARG("--eee <filename>", test_arg, show_arg, "eee", "") },
OPT_ENDTABLE
};
struct opt_table long_and_short_table[] = {
/* Short and long, different args. */
- { OPT_WITHOUT_ARG("--ggg/-g", test_noarg, "ggg"),
- "Description of ggg" },
- { OPT_WITH_ARG("-h/--hhh", test_arg, NULL, "hhh"),
- "Description of hhh"},
+ { OPT_WITHOUT_ARG("--ggg/-g", test_noarg, "ggg",
+ "Description of ggg") },
+ { OPT_WITH_ARG("-h/--hhh", test_arg, NULL, "hhh",
+ "Description of hhh") },
OPT_ENDTABLE
};
/* Sub-table test. */
struct opt_table subtables[] = {
/* Two short, and two long long, no description */
- { OPT_WITH_ARG("--jjj/-j/--lll/-l", test_arg, show_arg, "jjj") },
+ { OPT_WITH_ARG("--jjj/-j/--lll/-l", test_arg, show_arg, "jjj", "") },
/* Hidden option */
- { OPT_WITH_ARG("--mmm/-m", test_arg, show_arg, "mmm"), opt_hidden },
+ { OPT_WITH_ARG("--mmm/-m", test_arg, show_arg, "mmm", opt_hidden) },
OPT_SUBTABLE(short_table, NULL),
OPT_SUBTABLE(long_table, "long table options"),
OPT_SUBTABLE(long_and_short_table, NULL),
+ strlen("\n");
for (i = 0; i < opt_count; i++) {
- if (opt_table[i].flags == OPT_SUBTABLE) {
+ 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(" <arg>");
- if (opt_table[i].desc) {
- len += strlen(OPT_SPACE_PAD)
- + strlen(opt_table[i].desc) + 1;
- }
+ len += strlen(OPT_SPACE_PAD)
+ + strlen(opt_table[i].desc) + 1;
if (opt_table[i].show) {
len += strlen("(default: %s)")
+ OPT_SHOW_LEN + sizeof("...");
for (i = 0; i < opt_count; i++) {
if (opt_table[i].desc == opt_hidden)
continue;
- if (opt_table[i].flags == OPT_SUBTABLE) {
+ 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].flags == OPT_HASARG
+ if (opt_table[i].type == OPT_HASARG
&& !strchr(opt_table[i].names, ' ')
&& !strchr(opt_table[i].names, '='))
len += sprintf(p + len, " <arg>");
- if (opt_table[i].desc || opt_table[i].show)
- len += sprintf(p + len, "%.*s",
- len < strlen(OPT_SPACE_PAD)
- ? strlen(OPT_SPACE_PAD) - len : 1,
- OPT_SPACE_PAD);
+ len += sprintf(p + len, "%.*s",
+ len < strlen(OPT_SPACE_PAD)
+ ? strlen(OPT_SPACE_PAD) - len : 1,
+ OPT_SPACE_PAD);
- if (opt_table[i].desc)
- len += sprintf(p + len, "%s", opt_table[i].desc);
+ 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].arg);
- len += sprintf(p + len, "%s(default: %s)",
- opt_table[i].desc ? " " : "", buf);
+ len += sprintf(p + len, " (default: %s)", buf);
}
p += len;
p += sprintf(p, "\n");