Commit f8b1841d authored by Rusty Russell's avatar Rusty Russell

opt: add support for showing default value.

parent d7d5abe9
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
#include <stdio.h> #include <stdio.h>
#include "private.h" #include "private.h"
/* Upper bound to sprintf this simple type? Each 3 bits < 1 digit. */
#define CHAR_SIZE(type) (((sizeof(type)*CHAR_BIT + 2) / 3) + 1)
/* FIXME: asprintf module? */ /* FIXME: asprintf module? */
static char *arg_bad(const char *fmt, const char *arg) static char *arg_bad(const char *fmt, const char *arg)
{ {
...@@ -116,7 +119,7 @@ char *opt_inc_intval(int *i) ...@@ -116,7 +119,7 @@ char *opt_inc_intval(int *i)
} }
/* Display version string. */ /* Display version string. */
char *opt_show_version_and_exit(const char *version) char *opt_version_and_exit(const char *version)
{ {
printf("%s\n", version); printf("%s\n", version);
exit(0); exit(0);
...@@ -127,3 +130,44 @@ char *opt_usage_and_exit(const char *extra) ...@@ -127,3 +130,44 @@ char *opt_usage_and_exit(const char *extra)
printf("%s", opt_usage(opt_argv0, extra)); printf("%s", opt_usage(opt_argv0, extra));
exit(0); exit(0);
} }
void opt_show_bool(char buf[OPT_SHOW_LEN], const bool *b)
{
strncpy(buf, *b ? "true" : "false", OPT_SHOW_LEN);
}
void opt_show_invbool(char buf[OPT_SHOW_LEN], const bool *b)
{
strncpy(buf, *b ? "false" : "true", OPT_SHOW_LEN);
}
void opt_show_charp(char buf[OPT_SHOW_LEN], char *const *p)
{
size_t len = strlen(*p);
buf[0] = '"';
if (len > OPT_SHOW_LEN - 2)
len = OPT_SHOW_LEN - 2;
strncpy(buf+1, *p, len);
buf[1+len] = '"';
}
/* Set an integer value, various forms. Sets to 1 on arg == NULL. */
void opt_show_intval(char buf[OPT_SHOW_LEN], const int *i)
{
snprintf(buf, OPT_SHOW_LEN, "%i", *i);
}
void opt_show_uintval(char buf[OPT_SHOW_LEN], const unsigned int *ui)
{
snprintf(buf, OPT_SHOW_LEN, "%u", *ui);
}
void opt_show_longval(char buf[OPT_SHOW_LEN], const long *l)
{
snprintf(buf, OPT_SHOW_LEN, "%li", *l);
}
void opt_show_ulongval(char buf[OPT_SHOW_LEN], const unsigned long *ul)
{
snprintf(buf, OPT_SHOW_LEN, "%lu", *ul);
}
...@@ -31,6 +31,7 @@ static void add_opt(const struct opt_table *entry) ...@@ -31,6 +31,7 @@ static void add_opt(const struct opt_table *entry)
void _opt_register(const char *longopt, char shortopt, enum opt_flags flags, void _opt_register(const char *longopt, char shortopt, enum opt_flags flags,
char *(*cb)(void *arg), char *(*cb)(void *arg),
char *(*cb_arg)(const char *optarg, void *arg), char *(*cb_arg)(const char *optarg, void *arg),
void (*show)(char buf[OPT_SHOW_LEN], const void *arg),
void *arg, const char *desc) void *arg, const char *desc)
{ {
struct opt_table opt; struct opt_table opt;
...@@ -39,6 +40,7 @@ void _opt_register(const char *longopt, char shortopt, enum opt_flags flags, ...@@ -39,6 +40,7 @@ void _opt_register(const char *longopt, char shortopt, enum opt_flags flags,
opt.flags = flags; opt.flags = flags;
opt.cb = cb; opt.cb = cb;
opt.cb_arg = cb_arg; opt.cb_arg = cb_arg;
opt.show = show;
opt.arg = arg; opt.arg = arg;
opt.desc = desc; opt.desc = desc;
check_opt(&opt); check_opt(&opt);
......
...@@ -12,12 +12,16 @@ enum opt_flags { ...@@ -12,12 +12,16 @@ enum opt_flags {
OPT_END = 8, /* End of the table. */ OPT_END = 8, /* End of the table. */
}; };
/* Maximum length of arg to show in opt_usage */
#define OPT_SHOW_LEN 80
struct opt_table { struct opt_table {
const char *longopt; /* --longopt, or NULL */ const char *longopt; /* --longopt, or NULL */
char shortopt; /* -s, or 0 */ char shortopt; /* -s, or 0 */
enum opt_flags flags; enum opt_flags flags;
char *(*cb)(void *arg); /* OPT_NOARG */ char *(*cb)(void *arg); /* OPT_NOARG */
char *(*cb_arg)(const char *optarg, void *arg); /* OPT_HASARG */ char *(*cb_arg)(const char *optarg, void *arg); /* OPT_HASARG */
void (*show)(char buf[OPT_SHOW_LEN], const void *arg);
void *arg; void *arg;
const char *desc; const char *desc;
}; };
...@@ -48,22 +52,28 @@ struct opt_table { ...@@ -48,22 +52,28 @@ struct opt_table {
* @longopt: the name of the argument (eg. "foo" for "--foo <arg>"), or NULL. * @longopt: the name of the argument (eg. "foo" for "--foo <arg>"), or NULL.
* @shortopt: the character of the argument (eg. 'f' for "-f <arg>"), or 0. * @shortopt: the character of the argument (eg. 'f' for "-f <arg>"), or 0.
* @cb: the callback when the option is found (along with <arg>). * @cb: the callback when the option is found (along with <arg>).
* @arg: the argument to hand to @cb. * @show: the callback to print the value in get_usage (or NULL)
* @arg: the argument to hand to @cb and @show
* *
* This is a typesafe wrapper for intializing a struct opt_table. The callback * This is a typesafe wrapper for intializing a struct opt_table. The callback
* is of type "bool cb(const char *, type *)", * is of type "char *cb(const char *, type *)",
* "bool cb(const char *, const type *)" or "bool cb(const char *, void *)", * "char *cb(const char *, const type *)" or "char *cb(const char *, void *)",
* where "type" is the type of the @arg argument. The first argument to the * where "type" is the type of the @arg argument. The first argument to the
* @cb is the argument found on the commandline. * @cb is the argument found on the commandline.
* *
* Similarly, if @show is not NULL, it should be of type "void *show(char *,
* const type *)". It should write up to OPT_SHOW_LEN bytes into the first
* argument; unless it uses the entire OPT_SHOW_LEN bytes it should
* nul-terminate that buffer.
*
* At least one of @longopt and @shortopt must be non-zero. If the * At least one of @longopt and @shortopt must be non-zero. If the
* @cb returns false, opt_parse() will stop parsing and return false. * @cb returns false, opt_parse() will stop parsing and return false.
* *
* See Also: * See Also:
* OPT_WITH_ARG() * OPT_WITHOUT_ARG()
*/ */
#define OPT_WITH_ARG(longopt, shortopt, cb, arg) \ #define OPT_WITH_ARG(longopt, shortopt, cb, show, arg) \
(longopt), (shortopt), OPT_CB_ARG((cb), (arg)) (longopt), (shortopt), OPT_CB_ARG((cb), (show), (arg))
/** /**
* OPT_SUBTABLE() - macro for including another table inside a table. * OPT_SUBTABLE() - macro for including another table inside a table.
...@@ -74,7 +84,7 @@ struct opt_table { ...@@ -74,7 +84,7 @@ struct opt_table {
*/ */
#define OPT_SUBTABLE(table, desc) \ #define OPT_SUBTABLE(table, desc) \
{ (const char *)(table), sizeof(_check_is_entry(table)), \ { (const char *)(table), sizeof(_check_is_entry(table)), \
OPT_SUBTABLE, NULL, NULL, NULL, (desc) } OPT_SUBTABLE, NULL, NULL, NULL, NULL, (desc) }
/** /**
* opt_table_hidden - string for undocumented option tables. * opt_table_hidden - string for undocumented option tables.
...@@ -125,8 +135,8 @@ void opt_register_table(const struct opt_table table[], const char *desc); ...@@ -125,8 +135,8 @@ void opt_register_table(const struct opt_table table[], const char *desc);
* This is used for registering a single commandline option which takes * This is used for registering a single commandline option which takes
* no argument. * no argument.
* *
* The callback is of type "bool cb(type *)", "bool cb(const type *)" * The callback is of type "char *cb(type *)", "char *cb(const type *)"
* or "bool cb(void *)", where "type" is the type of the @arg * or "char *cb(void *)", where "type" is the type of the @arg
* argument. * argument.
* *
* At least one of @longopt and @shortopt must be non-zero. If the * At least one of @longopt and @shortopt must be non-zero. If the
...@@ -140,14 +150,15 @@ void opt_register_table(const struct opt_table table[], const char *desc); ...@@ -140,14 +150,15 @@ void opt_register_table(const struct opt_table table[], const char *desc);
* @longopt: the name of the argument (eg. "foo" for "--foo"), or NULL. * @longopt: the name of the argument (eg. "foo" for "--foo"), or NULL.
* @shortopt: the character of the argument (eg. 'f' for "-f"), or 0. * @shortopt: the character of the argument (eg. 'f' for "-f"), or 0.
* @cb: the callback when the option is found. * @cb: the callback when the option is found.
* @show: the callback when the option is found.
* @arg: the argument to hand to @cb. * @arg: the argument to hand to @cb.
* @desc: the verbose desction of the option (for opt_usage()), or NULL. * @desc: the verbose desction of the option (for opt_usage()), or NULL.
* *
* This is used for registering a single commandline option which takes * This is used for registering a single commandline option which takes
* an argument. * an argument.
* *
* The callback is of type "bool cb(const char *, type *)", * The callback is of type "char *cb(const char *, type *)",
* "bool cb(const char *, const type *)" or "bool cb(const char *, void *)", * "char *cb(const char *, const type *)" or "char *cb(const char *, void *)",
* where "type" is the type of the @arg argument. The first argument to the * where "type" is the type of the @arg argument. The first argument to the
* @cb is the argument found on the commandline. * @cb is the argument found on the commandline.
* *
...@@ -158,8 +169,8 @@ void opt_register_table(const struct opt_table table[], const char *desc); ...@@ -158,8 +169,8 @@ void opt_register_table(const struct opt_table table[], const char *desc);
* opt_register_arg("explode", 'e', explode_cb, NULL, * opt_register_arg("explode", 'e', explode_cb, NULL,
* "Make the machine explode (developers only)"); * "Make the machine explode (developers only)");
*/ */
#define opt_register_arg(longopt, shortopt, cb, arg, desc) \ #define opt_register_arg(longopt, shortopt, cb, show, arg, desc) \
_opt_register((longopt), (shortopt), OPT_CB_ARG((cb), (arg)), (desc)) _opt_register((longopt), (shortopt), OPT_CB_ARG((cb), (show), (arg)), (desc))
/** /**
* opt_parse - parse arguments. * opt_parse - parse arguments.
...@@ -216,24 +227,32 @@ char *opt_usage(const char *argv0, const char *extra); ...@@ -216,24 +227,32 @@ char *opt_usage(const char *argv0, const char *extra);
char *opt_set_bool(bool *b); char *opt_set_bool(bool *b);
/* Sets @b based on arg: (yes/no/true/false). */ /* Sets @b based on arg: (yes/no/true/false). */
char *opt_set_bool_arg(const char *arg, bool *b); char *opt_set_bool_arg(const char *arg, bool *b);
void opt_show_bool(char buf[OPT_SHOW_LEN], const bool *b);
/* The inverse */ /* The inverse */
char *opt_set_invbool(bool *b); char *opt_set_invbool(bool *b);
void opt_show_invbool(char buf[OPT_SHOW_LEN], const bool *b);
/* Sets @b based on !arg: (yes/no/true/false). */
char *opt_set_invbool_arg(const char *arg, bool *b); char *opt_set_invbool_arg(const char *arg, bool *b);
/* Set a char *. */ /* Set a char *. */
char *opt_set_charp(const char *arg, char **p); char *opt_set_charp(const char *arg, char **p);
void opt_show_charp(char buf[OPT_SHOW_LEN], char *const *p);
/* Set an integer value, various forms. Sets to 1 on arg == NULL. */ /* Set an integer value, various forms. Sets to 1 on arg == NULL. */
char *opt_set_intval(const char *arg, int *i); char *opt_set_intval(const char *arg, int *i);
void opt_show_intval(char buf[OPT_SHOW_LEN], const int *i);
char *opt_set_uintval(const char *arg, unsigned int *ui); char *opt_set_uintval(const char *arg, unsigned int *ui);
void opt_show_uintval(char buf[OPT_SHOW_LEN], const unsigned int *ui);
char *opt_set_longval(const char *arg, long *l); char *opt_set_longval(const char *arg, long *l);
void opt_show_longval(char buf[OPT_SHOW_LEN], const long *l);
char *opt_set_ulongval(const char *arg, unsigned long *ul); char *opt_set_ulongval(const char *arg, unsigned long *ul);
void opt_show_ulongval(char buf[OPT_SHOW_LEN], const unsigned long *ul);
/* Increment. */ /* Increment. */
char *opt_inc_intval(int *i); char *opt_inc_intval(int *i);
/* Display version string to stdout, exit(0). */ /* Display version string to stdout, exit(0). */
char *opt_show_version_and_exit(const char *version); char *opt_version_and_exit(const char *version);
/* Display usage string to stdout, exit(0). */ /* Display usage string to stdout, exit(0). */
char *opt_usage_and_exit(const char *extra); char *opt_usage_and_exit(const char *extra);
...@@ -245,22 +264,25 @@ char *opt_usage_and_exit(const char *extra); ...@@ -245,22 +264,25 @@ char *opt_usage_and_exit(const char *extra);
cast_if_any(char *(*)(void *), (cb), &*(cb), \ cast_if_any(char *(*)(void *), (cb), &*(cb), \
char *(*)(typeof(*(arg))*), \ char *(*)(typeof(*(arg))*), \
char *(*)(const typeof(*(arg))*), \ char *(*)(const typeof(*(arg))*), \
char *(*)(const typeof(*(arg))*)), \ char *(*)(const void *)), \
NULL, (arg) NULL, NULL, (arg)
/* Resolves to the four parameters for arg callbacks. */ /* Resolves to the four parameters for arg callbacks. */
#define OPT_CB_ARG(cb, arg) \ #define OPT_CB_ARG(cb, show, arg) \
OPT_HASARG, NULL, \ OPT_HASARG, NULL, \
cast_if_any(char *(*)(const char *,void *), (cb), &*(cb), \ cast_if_any(char *(*)(const char *,void *), (cb), &*(cb), \
char *(*)(const char *, typeof(*(arg))*), \ char *(*)(const char *, typeof(*(arg))*), \
char *(*)(const char *, const typeof(*(arg))*), \ char *(*)(const char *, const typeof(*(arg))*), \
char *(*)(const char *, const typeof(*(arg))*)), \ char *(*)(const char *, const void *)), \
cast_if_type(void (*)(char buf[], const void *), (show), &*(show), \
void (*)(char buf[], const typeof(*(arg))*)), \
(arg) (arg)
/* Non-typesafe register function. */ /* Non-typesafe register function. */
void _opt_register(const char *longopt, char shortopt, enum opt_flags flags, void _opt_register(const char *longopt, char shortopt, enum opt_flags flags,
char *(*cb)(void *arg), char *(*cb)(void *arg),
char *(*cb_arg)(const char *optarg, void *arg), char *(*cb_arg)(const char *optarg, void *arg),
void (*show)(char buf[OPT_SHOW_LEN], const void *arg),
void *arg, const char *desc); void *arg, const char *desc);
/* We use this to get typechecking for OPT_SUBTABLE */ /* We use this to get typechecking for OPT_SUBTABLE */
......
#define _GNU_SOURCE
#include <stdio.h>
#include <ccan/tap/tap.h>
#include <setjmp.h>
#include <stdlib.h>
#include "utils.h"
/* We don't actually want it to exit... */
static jmp_buf exited;
#define exit(status) longjmp(exited, (status) + 1)
#define printf saved_printf
static int saved_printf(const char *fmt, ...);
#include <ccan/opt/helpers.c>
#include <ccan/opt/opt.c>
#include <ccan/opt/usage.c>
static void reset_options(void)
{
free(opt_table);
opt_table = NULL;
opt_count = 0;
}
static char *output = NULL;
static int saved_printf(const char *fmt, ...)
{
va_list ap;
char *p;
int ret;
va_start(ap, fmt);
ret = vasprintf(&p, fmt, ap);
va_end(ap);
if (output) {
output = realloc(output, strlen(output) + strlen(p) + 1);
strcat(output, p);
free(p);
} else
output = p;
return ret;
}
/* Test helpers. */
int main(int argc, char *argv[])
{
plan_tests(88);
/* opt_set_bool */
{
bool arg = false;
reset_options();
opt_register_noarg(NULL, 'a', opt_set_bool, &arg, NULL);
ok1(parse_args(&argc, &argv, "-a", NULL));
ok1(arg);
opt_register_arg(NULL, 'b', opt_set_bool_arg, NULL, &arg, NULL);
ok1(parse_args(&argc, &argv, "-b", "no", NULL));
ok1(!arg);
ok1(parse_args(&argc, &argv, "-b", "yes", NULL));
ok1(arg);
ok1(parse_args(&argc, &argv, "-b", "false", NULL));
ok1(!arg);
ok1(parse_args(&argc, &argv, "-b", "true", NULL));
ok1(arg);
}
/* opt_set_invbool */
{
bool arg = true;
reset_options();
opt_register_noarg(NULL, 'a', opt_set_invbool, &arg, NULL);
ok1(parse_args(&argc, &argv, "-a", NULL));
ok1(!arg);
opt_register_arg(NULL, 'b', opt_set_invbool_arg, NULL,
&arg, NULL);
ok1(parse_args(&argc, &argv, "-b", "no", NULL));
ok1(arg);
ok1(parse_args(&argc, &argv, "-b", "yes", NULL));
ok1(!arg);
ok1(parse_args(&argc, &argv, "-b", "false", NULL));
ok1(arg);
ok1(parse_args(&argc, &argv, "-b", "true", NULL));
ok1(!arg);
}
/* opt_set_charp */
{
char *arg = (char *)"wrong";
reset_options();
opt_register_arg(NULL, 'a', opt_set_charp, NULL, &arg, NULL);
ok1(parse_args(&argc, &argv, "-a", "string", NULL));
ok1(strcmp(arg, "string") == 0);
}
/* opt_set_intval */
{
int arg = 1000;
reset_options();
opt_register_arg(NULL, 'a', opt_set_intval, NULL, &arg, NULL);
ok1(parse_args(&argc, &argv, "-a", "9999", NULL));
ok1(arg == 9999);
ok1(parse_args(&argc, &argv, "-a", "-9999", NULL));
ok1(arg == -9999);
ok1(parse_args(&argc, &argv, "-a", "0", NULL));
ok1(arg == 0);
ok1(!parse_args(&argc, &argv, "-a", "100crap", NULL));
if (sizeof(int) == 4)
ok1(!parse_args(&argc, &argv, "-a", "4294967296", NULL));
else
fail("Handle other int sizes");
}
/* opt_set_uintval */
{
unsigned int arg = 1000;
reset_options();
opt_register_arg(NULL, 'a', opt_set_uintval, NULL, &arg, NULL);
ok1(parse_args(&argc, &argv, "-a", "9999", NULL));
ok1(arg == 9999);
ok1(!parse_args(&argc, &argv, "-a", "-9999", NULL));
ok1(parse_args(&argc, &argv, "-a", "0", NULL));
ok1(arg == 0);
ok1(!parse_args(&argc, &argv, "-a", "100crap", NULL));
ok1(!parse_args(&argc, &argv, "-a", "4294967296", NULL));
}
/* opt_set_longval */
{
long int arg = 1000;
reset_options();
opt_register_arg(NULL, 'a', opt_set_longval, NULL, &arg, NULL);
ok1(parse_args(&argc, &argv, "-a", "9999", NULL));
ok1(arg == 9999);
ok1(parse_args(&argc, &argv, "-a", "-9999", NULL));
ok1(arg == -9999);
ok1(parse_args(&argc, &argv, "-a", "0", NULL));
ok1(arg == 0);
ok1(!parse_args(&argc, &argv, "-a", "100crap", NULL));
if (sizeof(long) == 4)
ok1(!parse_args(&argc, &argv, "-a", "4294967296", NULL));
else if (sizeof(long)== 8)
ok1(!parse_args(&argc, &argv, "-a", "18446744073709551616", NULL));
else
fail("FIXME: Handle other long sizes");
}
/* opt_set_ulongval */
{
unsigned long int arg = 1000;
reset_options();
opt_register_arg(NULL, 'a', opt_set_ulongval, NULL, &arg, NULL);
ok1(parse_args(&argc, &argv, "-a", "9999", NULL));
ok1(arg == 9999);
ok1(!parse_args(&argc, &argv, "-a", "-9999", NULL));
ok1(parse_args(&argc, &argv, "-a", "0", NULL));
ok1(arg == 0);
ok1(!parse_args(&argc, &argv, "-a", "100crap", NULL));
if (sizeof(long) == 4)
ok1(!parse_args(&argc, &argv, "-a", "4294967296", NULL));
else if (sizeof(long)== 8)
ok1(!parse_args(&argc, &argv, "-a", "18446744073709551616", NULL));
else
fail("FIXME: Handle other long sizes");
}
/* opt_inc_intval */
{
int arg = 1000;
reset_options();
opt_register_noarg(NULL, 'a', opt_inc_intval, &arg, NULL);
ok1(parse_args(&argc, &argv, "-a", NULL));
ok1(arg == 1001);
ok1(parse_args(&argc, &argv, "-a", "-a", NULL));
ok1(arg == 1003);
ok1(parse_args(&argc, &argv, "-aa", NULL));
ok1(arg == 1005);
}
/* opt_show_version_and_exit. */
{
int exitval;
reset_options();
opt_register_noarg(NULL, 'a',
opt_version_and_exit, "1.2.3", NULL);
exitval = setjmp(exited);
if (exitval == 0) {
parse_args(&argc, &argv, "-a", NULL);
fail("opt_show_version_and_exit returned?");
} else {
ok1(exitval - 1 == 0);
}
ok1(strcmp(output, "1.2.3\n") == 0);
free(output);
output = NULL;
}
/* opt_usage_and_exit. */
{
int exitval;
reset_options();
opt_register_noarg(NULL, 'a',
opt_usage_and_exit, "[args]", NULL);
exitval = setjmp(exited);
if (exitval == 0) {
parse_args(&argc, &argv, "-a", NULL);
fail("opt_usage_and_exit returned?");
} else {
ok1(exitval - 1 == 0);
}
ok1(strstr(output, "[args]"));
ok1(strstr(output, argv[0]));
ok1(strstr(output, "[-a]"));
free(output);
output = NULL;
}
/* opt_show_bool */
{
bool b;
char buf[OPT_SHOW_LEN+2] = { 0 };
buf[OPT_SHOW_LEN] = '!';
b = true;
opt_show_bool(buf, &b);
ok1(strcmp(buf, "true") == 0);
ok1(buf[OPT_SHOW_LEN] == '!');
b = false;
opt_show_bool(buf, &b);
ok1(strcmp(buf, "false") == 0);
ok1(buf[OPT_SHOW_LEN] == '!');
}
/* opt_show_invbool */
{
bool b;
char buf[OPT_SHOW_LEN+2] = { 0 };
buf[OPT_SHOW_LEN] = '!';
b = true;
opt_show_invbool(buf, &b);
ok1(strcmp(buf, "false") == 0);
ok1(buf[OPT_SHOW_LEN] == '!');
b = false;
opt_show_invbool(buf, &b);
ok1(strcmp(buf, "true") == 0);
ok1(buf[OPT_SHOW_LEN] == '!');
}
/* opt_show_charp */
{
char str[OPT_SHOW_LEN*2], *p;
char buf[OPT_SHOW_LEN+2] = { 0 };
buf[OPT_SHOW_LEN] = '!';
/* Short test. */
p = str;
strcpy(p, "short");
opt_show_charp(buf, &p);
ok1(strcmp(buf, "\"short\"") == 0);
ok1(buf[OPT_SHOW_LEN] == '!');
/* Truncate test. */
memset(p, 'x', OPT_SHOW_LEN*2);
p[OPT_SHOW_LEN*2-1] = '\0';
opt_show_charp(buf, &p);
ok1(buf[0] == '"');
ok1(buf[OPT_SHOW_LEN-1] == '"');
ok1(buf[OPT_SHOW_LEN] == '!');
ok1(strspn(buf+1, "x") == OPT_SHOW_LEN-2);
}
/* opt_show_intval */
{
int i;
char buf[OPT_SHOW_LEN+2] = { 0 };
buf[OPT_SHOW_LEN] = '!';
i = -77;
opt_show_intval(buf, &i);
ok1(strcmp(buf, "-77") == 0);
ok1(buf[OPT_SHOW_LEN] == '!');
i = 77;
opt_show_intval(buf, &i);
ok1(strcmp(buf, "77") == 0);
ok1(buf[OPT_SHOW_LEN] == '!');
}
/* opt_show_uintval */
{
unsigned int ui;
char buf[OPT_SHOW_LEN+2] = { 0 };
buf[OPT_SHOW_LEN] = '!';
ui = 4294967295U;
opt_show_uintval(buf, &ui);
ok1(strcmp(buf, "4294967295") == 0);
ok1(buf[OPT_SHOW_LEN] == '!');
}
/* opt_show_longval */
{
long l;
char buf[OPT_SHOW_LEN+2] = { 0 };
buf[OPT_SHOW_LEN] = '!';
l = 1234567890L;
opt_show_longval(buf, &l);
ok1(strcmp(buf, "1234567890") == 0);
ok1(buf[OPT_SHOW_LEN] == '!');
}
/* opt_show_ulongval */
{
unsigned long ul;
char buf[OPT_SHOW_LEN+2] = { 0 };
buf[OPT_SHOW_LEN] = '!';
ul = 4294967295UL;
opt_show_ulongval(buf, &ul);
ok1(strcmp(buf, "4294967295") == 0);
ok1(buf[OPT_SHOW_LEN] == '!');
}
return exit_status();
}
...@@ -19,7 +19,7 @@ int main(int argc, char *argv[]) ...@@ -19,7 +19,7 @@ int main(int argc, char *argv[])
char *output; char *output;
plan_tests(18); plan_tests(18);
opt_register_table(subtables, NULL); opt_register_table(subtables, NULL);
opt_register_noarg("--kkk", 'k', my_cb, NULL, "magic kkk option"); opt_register_noarg("kkk", 'k', my_cb, NULL, "magic kkk option");
output = opt_usage("my name", "ExTrA Args"); output = opt_usage("my name", "ExTrA Args");
diag("%s", output); diag("%s", output);
ok1(strstr(output, "Usage: my name")); ok1(strstr(output, "Usage: my name"));
...@@ -28,11 +28,11 @@ int main(int argc, char *argv[]) ...@@ -28,11 +28,11 @@ int main(int argc, char *argv[])
ok1(strstr(output, "-a ")); ok1(strstr(output, "-a "));
ok1(strstr(output, " Description of a\n")); ok1(strstr(output, " Description of a\n"));
ok1(strstr(output, "-b <arg>")); ok1(strstr(output, "-b <arg>"));
ok1(strstr(output, " Description of b\n")); ok1(strstr(output, " Description of b (default: b)\n"));
ok1(strstr(output, "--ddd ")); ok1(strstr(output, "--ddd "));
ok1(strstr(output, " Description of ddd\n")); ok1(strstr(output, " Description of ddd\n"));
ok1(strstr(output, "--eee <arg> ")); ok1(strstr(output, "--eee <arg> "));
ok1(strstr(output, " Description of eee\n")); ok1(strstr(output, " (default: eee)\n"));
ok1(strstr(output, "long table options:\n")); ok1(strstr(output, "long table options:\n"));
/* This table is hidden. */ /* This table is hidden. */
ok1(!strstr(output, "--ggg/-g ")); ok1(!strstr(output, "--ggg/-g "));
......
...@@ -54,7 +54,7 @@ int main(int argc, char *argv[]) ...@@ -54,7 +54,7 @@ int main(int argc, char *argv[])
/* Argument variants. */ /* Argument variants. */
reset_options(); reset_options();
test_cb_called = 0; test_cb_called = 0;
opt_register_arg("aaa", 'a', test_arg, "aaa", NULL); opt_register_arg("aaa", 'a', test_arg, NULL, "aaa", NULL);
ok1(parse_args(&argc, &argv, "--aaa", "aaa", NULL)); ok1(parse_args(&argc, &argv, "--aaa", "aaa", NULL));
ok1(argc == 1); ok1(argc == 1);
ok1(argv[0] == myname); ok1(argv[0] == myname);
......
...@@ -15,13 +15,18 @@ char *test_noarg(void *arg) ...@@ -15,13 +15,18 @@ char *test_noarg(void *arg)
return NULL; return NULL;
} }
char *test_arg(const char *optarg, void *arg) char *test_arg(const char *optarg, const char *arg)
{ {
test_cb_called++; test_cb_called++;
ok1(strcmp(optarg, arg) == 0); ok1(strcmp(optarg, arg) == 0);
return NULL; return NULL;
} }
void show_arg(char buf[OPT_SHOW_LEN], const char *arg)
{
strncpy(buf, arg, OPT_SHOW_LEN);
}
char *err_output = NULL; char *err_output = NULL;
static void save_err_output(const char *fmt, ...) static void save_err_output(const char *fmt, ...)
...@@ -66,14 +71,14 @@ bool parse_args(int *argc, char ***argv, ...) ...@@ -66,14 +71,14 @@ bool parse_args(int *argc, char ***argv, ...)
struct opt_table short_table[] = { struct opt_table short_table[] = {
/* Short opts, different args. */ /* Short opts, different args. */
{ OPT_WITHOUT_ARG(NULL, 'a', test_noarg, "a"), "Description of a" }, { OPT_WITHOUT_ARG(NULL, 'a', test_noarg, "a"), "Description of a" },
{ OPT_WITH_ARG(NULL, 'b', test_arg, "b"), "Description of b" }, { OPT_WITH_ARG(NULL, 'b', test_arg, show_arg, "b"), "Description of b" },
OPT_ENDTABLE OPT_ENDTABLE
}; };
struct opt_table long_table[] = { struct opt_table long_table[] = {
/* Long opts, different args. */ /* Long opts, different args. */
{ OPT_WITHOUT_ARG("ddd", 0, test_noarg, "ddd"), "Description of ddd" }, { OPT_WITHOUT_ARG("ddd", 0, test_noarg, "ddd"), "Description of ddd" },
{ OPT_WITH_ARG("eee", 0, test_arg, "eee"), "Description of eee" }, { OPT_WITH_ARG("eee", 0, test_arg, show_arg, "eee"), },
OPT_ENDTABLE OPT_ENDTABLE
}; };
...@@ -81,14 +86,15 @@ struct opt_table long_and_short_table[] = { ...@@ -81,14 +86,15 @@ struct opt_table long_and_short_table[] = {
/* Short and long, different args. */ /* Short and long, different args. */
{ OPT_WITHOUT_ARG("ggg", 'g', test_noarg, "ggg"), { OPT_WITHOUT_ARG("ggg", 'g', test_noarg, "ggg"),
"Description of ggg" }, "Description of ggg" },
{ OPT_WITH_ARG("hhh", 'h', test_arg, "hhh"), "Description of hhh"}, { OPT_WITH_ARG("hhh", 'h', test_arg, NULL, "hhh"),
"Description of hhh"},
OPT_ENDTABLE OPT_ENDTABLE
}; };
/* Sub-table test. */ /* Sub-table test. */
struct opt_table subtables[] = { struct opt_table subtables[] = {
/* Short and long, no description */ /* Short and long, no description */
{ OPT_WITH_ARG("jjj", 'j', test_arg, "jjj") }, { OPT_WITH_ARG("jjj", 'j', test_arg, show_arg, "jjj") },
OPT_SUBTABLE(short_table, NULL), OPT_SUBTABLE(short_table, NULL),
OPT_SUBTABLE(long_table, "long table options"), OPT_SUBTABLE(long_table, "long table options"),
OPT_SUBTABLE(long_and_short_table, opt_table_hidden), OPT_SUBTABLE(long_and_short_table, opt_table_hidden),
......
...@@ -8,7 +8,8 @@ extern char *err_output; ...@@ -8,7 +8,8 @@ extern char *err_output;
extern unsigned int test_cb_called; extern unsigned int test_cb_called;
char *test_noarg(void *arg); char *test_noarg(void *arg);
char *test_arg(const char *optarg, void *arg); char *test_arg(const char *optarg, const char *arg);
void show_arg(char buf[OPT_SHOW_LEN], const char *arg);
extern struct opt_table short_table[]; extern struct opt_table short_table[];
extern struct opt_table long_table[]; extern struct opt_table long_table[];
......
...@@ -25,6 +25,8 @@ static unsigned write_short_options(char *str) ...@@ -25,6 +25,8 @@ static unsigned write_short_options(char *str)
return num; return num;
} }
#define OPT_SPACE_PAD " "
/* FIXME: Get all purdy. */ /* FIXME: Get all purdy. */
char *opt_usage(const char *argv0, const char *extra) char *opt_usage(const char *argv0, const char *extra)
{ {
...@@ -45,8 +47,14 @@ char *opt_usage(const char *argv0, const char *extra) ...@@ -45,8 +47,14 @@ char *opt_usage(const char *argv0, const char *extra)
len += strlen("--%s/-%c") + strlen(" <arg>"); len += strlen("--%s/-%c") + strlen(" <arg>");
if (opt_table[i].longopt) if (opt_table[i].longopt)
len += strlen(opt_table[i].longopt); len += strlen(opt_table[i].longopt);
if (opt_table[i].desc) if (opt_table[i].desc) {
len += 20 + strlen(opt_table[i].desc); 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"); len += strlen("\n");
} }
} }
...@@ -89,11 +97,20 @@ char *opt_usage(const char *argv0, const char *extra) ...@@ -89,11 +97,20 @@ char *opt_usage(const char *argv0, const char *extra)
len = sprintf(p, "--%s", opt_table[i].longopt); len = sprintf(p, "--%s", opt_table[i].longopt);
if (opt_table[i].flags == OPT_HASARG) if (opt_table[i].flags == OPT_HASARG)
len += sprintf(p + len, " <arg>"); len += sprintf(p + len, " <arg>");
if (opt_table[i].desc) { if (opt_table[i].desc || opt_table[i].show)
len += sprintf(p + len, "%.*s", len += sprintf(p + len, "%.*s",
len < 20 ? 20 - len : 1, 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);
} }
p += len; p += len;
p += sprintf(p, "\n"); p += sprintf(p, "\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment