va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
va_end(ap);
}
+void opt_log_stderr_exit(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ exit(1);
+}
+
char *opt_invalid_argument(const char *arg)
{
char *str = malloc(sizeof("Invalid argument '%s'") + strlen(arg));
* opt_parse - parse arguments.
* @argc: pointer to argc
* @argv: argv array.
- * @errlog: the function to print errors (usually opt_log_stderr).
+ * @errlog: the function to print errors
*
* This iterates through the command line and calls callbacks registered with
* opt_register_table()/opt_register_arg()/opt_register_noarg(). If there
*
* Example:
* if (!opt_parse(&argc, argv, opt_log_stderr)) {
- * printf("%s", opt_usage(argv[0], "<args>..."));
+ * printf("You screwed up, aborting!\n");
* exit(1);
* }
+ *
+ * See Also:
+ * opt_log_stderr, opt_log_stderr_exit
*/
bool opt_parse(int *argc, char *argv[], void (*errlog)(const char *fmt, ...));
* opt_log_stderr - print message to stderr.
* @fmt: printf-style format.
*
- * This is the standard helper for opt_parse, to print errors.
+ * This is a helper for opt_parse, to print errors to stderr.
+ *
+ * See Also:
+ * opt_log_stderr_exit
*/
void opt_log_stderr(const char *fmt, ...);
+/**
+ * opt_log_stderr_exit - print message to stderr, then exit(1)
+ * @fmt: printf-style format.
+ *
+ * Just like opt_log_stderr, only then does exit(1). This means that
+ * when handed to opt_parse, opt_parse will never return false.
+ *
+ * Example:
+ * // This never returns false; just exits if there's an erorr.
+ * opt_parse(&argc, argv, opt_log_stderr_exit);
+ */
+void opt_log_stderr_exit(const char *fmt, ...);
+
/**
* opt_invalid_argument - helper to allocate an "Invalid argument '%s'" string
* @arg: the argument which was invalid.
* and a table of all the options with their descriptions. If an option has
* description opt_hidden, it is not shown here.
*
+ * If "extra" is NULL, then the extra information is taken from any
+ * registered option which calls opt_usage_and_exit(). This avoids duplicating
+ * that string in the common case.
+ *
* The result should be passed to free().
*/
char *opt_usage(const char *argv0, const char *extra);
#include <stdlib.h>
#include <ccan/opt/opt.c>
#include <ccan/opt/usage.c>
+#include <ccan/opt/helpers.c>
#include "utils.h"
int main(int argc, char *argv[])
#define printf saved_printf
static int saved_printf(const char *fmt, ...);
+#define fprintf saved_fprintf
+static int saved_fprintf(FILE *ignored, const char *fmt, ...);
+
+#define vfprintf(f, fmt, ap) saved_vprintf(fmt, ap)
+static int saved_vprintf(const char *fmt, va_list ap);
+
#include <ccan/opt/helpers.c>
#include <ccan/opt/opt.c>
#include <ccan/opt/usage.c>
static char *output = NULL;
-static int saved_printf(const char *fmt, ...)
+static int saved_vprintf(const char *fmt, va_list ap)
{
- va_list ap;
char *p;
- int ret;
-
- va_start(ap, fmt);
- ret = vasprintf(&p, fmt, ap);
- va_end(ap);
+ int ret = vasprintf(&p, fmt, ap);
if (output) {
output = realloc(output, strlen(output) + strlen(p) + 1);
free(p);
} else
output = p;
+ return ret;
+}
+
+static int saved_printf(const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = saved_vprintf(fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+static int saved_fprintf(FILE *ignored, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+ va_start(ap, fmt);
+ ret = saved_vprintf(fmt, ap);
+ va_end(ap);
return ret;
}
/* Test helpers. */
int main(int argc, char *argv[])
{
- plan_tests(96);
+ plan_tests(100);
/* opt_set_bool */
{
ok1(buf[OPT_SHOW_LEN] == '!');
}
+ /* opt_log_stderr. */
+ {
+ reset_options();
+ opt_register_noarg("-a",
+ opt_usage_and_exit, "[args]", "");
+
+ argc = 2;
+ argv = malloc(sizeof(argv[0]) * 3);
+ argv[0] = "thisprog";
+ argv[1] = "--garbage";
+ argv[2] = NULL;
+ ok1(!opt_parse(&argc, argv, opt_log_stderr));
+ ok1(!strcmp(output,
+ "thisprog: --garbage: unrecognized option\n"));
+ free(output);
+ output = NULL;
+ }
+
+ /* opt_log_stderr_exit. */
+ {
+ int exitval;
+ reset_options();
+ opt_register_noarg("-a",
+ opt_usage_and_exit, "[args]", "");
+ exitval = setjmp(exited);
+ if (exitval == 0) {
+ argc = 2;
+ argv = malloc(sizeof(argv[0]) * 3);
+ argv[0] = "thisprog";
+ argv[1] = "--garbage";
+ argv[2] = NULL;
+ opt_parse(&argc, argv, opt_log_stderr_exit);
+ fail("opt_log_stderr_exit returned?");
+ } else {
+ ok1(exitval - 1 == 1);
+ }
+ ok1(!strcmp(output,
+ "thisprog: --garbage: unrecognized option\n"));
+ free(output);
+ output = NULL;
+ }
+
return exit_status();
}
#include "utils.h"
#include <ccan/opt/opt.c>
#include <ccan/opt/usage.c>
+#include <ccan/opt/helpers.c>
/* Test iterators. */
int main(int argc, char *argv[])
#include <stdlib.h>
#include <ccan/opt/opt.c>
#include <ccan/opt/usage.c>
+#include <ccan/opt/helpers.c>
#include "utils.h"
int main(int argc, char *argv[])
#include "utils.h"
#include <ccan/opt/opt.c>
#include <ccan/opt/usage.c>
+#include <ccan/opt/helpers.c>
static char *my_cb(void *p)
{
{
char *output;
- plan_tests(19);
+ plan_tests(38);
opt_register_table(subtables, NULL);
opt_register_noarg("--kkk/-k", my_cb, NULL, "magic kkk option");
+ opt_register_noarg("-?", opt_usage_and_exit, "<MyArgs>...",
+ "This message");
output = opt_usage("my name", "ExTrA Args");
diag("%s", output);
ok1(strstr(output, "Usage: my name"));
ok1(strstr(output, "magic kkk option"));
/* This entry is hidden. */
ok1(!strstr(output, "--mmm/-m"));
+ free(output);
+ /* NULL should use string from registered options. */
+ output = opt_usage("my name", NULL);
+ diag("%s", output);
+ ok1(strstr(output, "Usage: my name"));
+ ok1(strstr(output, "--jjj/-j/--lll/-l <arg>"));
+ ok1(strstr(output, "<MyArgs>..."));
+ ok1(strstr(output, "-a "));
+ ok1(strstr(output, " Description of a\n"));
+ ok1(strstr(output, "-b <arg>"));
+ ok1(strstr(output, " Description of b (default: b)\n"));
+ ok1(strstr(output, "--ddd "));
+ ok1(strstr(output, " Description of ddd\n"));
+ ok1(strstr(output, "--eee <filename> "));
+ ok1(strstr(output, " (default: eee)\n"));
+ ok1(strstr(output, "long table options:\n"));
+ ok1(strstr(output, "--ggg/-g "));
+ ok1(strstr(output, " Description of ggg\n"));
+ ok1(strstr(output, "-h/--hhh <arg>"));
+ ok1(strstr(output, " Description of hhh\n"));
+ ok1(strstr(output, "--kkk/-k"));
+ ok1(strstr(output, "magic kkk option"));
+ /* This entry is hidden. */
+ ok1(!strstr(output, "--mmm/-m"));
free(output);
return exit_status();
#include <stdlib.h>
#include <ccan/opt/opt.c>
#include <ccan/opt/usage.c>
+#include <ccan/opt/helpers.c>
#include "utils.h"
static void reset_options(void)
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].arg) {
+ extra = opt_table[i].arg;
+ break;
+ }
+ }
+ }
+
/* An overestimate of our length. */
len = strlen("Usage: %s ") + strlen(argv0)
+ strlen("[-%.*s]") + opt_num_short + 1