/* This helps opt_usage. */
opt_argv0 = argv[0];
- while ((ret = parse_one(argc, argv, 0, &offset, errlog)) == 1);
+ while ((ret = parse_one(argc, argv, 0, &offset, errlog, false)) == 1);
/* parse_one returns 0 on finish, -1 on error */
return (ret == 0);
}
-bool opt_early_parse(int argc, char *argv[],
- void (*errlog)(const char *fmt, ...))
+static bool early_parse(int argc, char *argv[],
+ void (*errlog)(const char *fmt, ...),
+ bool ignore_unknown)
{
int ret;
unsigned off = 0;
/* This helps opt_usage. */
opt_argv0 = argv[0];
- while ((ret = parse_one(&argc, tmpargv, OPT_EARLY, &off, errlog)) == 1);
+ while ((ret = parse_one(&argc, tmpargv, OPT_EARLY, &off, errlog, ignore_unknown)) == 1);
opt_alloc.free(tmpargv);
return (ret == 0);
}
+bool opt_early_parse(int argc, char *argv[],
+ void (*errlog)(const char *fmt, ...))
+{
+ return early_parse(argc, argv, errlog, false);
+}
+
+bool opt_early_parse_incomplete(int argc, char *argv[],
+ void (*errlog)(const char *fmt, ...))
+{
+ return early_parse(argc, argv, errlog, true);
+}
+
void opt_free_table(void)
{
opt_alloc.free(opt_table);
bool opt_early_parse(int argc, char *argv[],
void (*errlog)(const char *fmt, ...));
+/**
+ * opt_early_parse_incomplete - parse early arguments, ignoring unknown ones.
+ * @argc: argc
+ * @argv: argv array.
+ * @errlog: the function to print errors
+ *
+ * If you have plugins, you might need to do early parsing (eg. to find the
+ * plugin directory) but you don't know what options the plugins will want.
+ *
+ * Thus, this function is just like opt_early_parse, but ignores unknown options.
+ *
+ * Example:
+ * if (!opt_early_parse_incomplete(argc, argv, opt_log_stderr)) {
+ * printf("You screwed up, aborting!\n");
+ * exit(1);
+ * }
+ *
+ * See Also:
+ * opt_early_parse()
+ */
+bool opt_early_parse_incomplete(int argc, char *argv[],
+ void (*errlog)(const char *fmt, ...));
+
+
/**
* opt_free_table - reset the opt library.
*
/* Returns 1 if argument consumed, 0 if all done, -1 on error. */
int parse_one(int *argc, char *argv[], enum opt_type is_early, unsigned *offset,
- void (*errlog)(const char *fmt, ...))
+ void (*errlog)(const char *fmt, ...), bool unknown_ok)
{
unsigned i, arg, len;
const char *o, *optarg = NULL;
continue;
break;
}
- if (!o)
+ if (!o) {
+ if (unknown_ok)
+ goto ok;
return parse_err(errlog, argv[0],
argv[arg], strlen(argv[arg]),
"unrecognized option");
+ }
/* For error messages, we include the leading '--' */
o -= 2;
len += 2;
(*offset)++;
break;
}
- if (!o)
+ if (!o) {
+ if (unknown_ok) {
+ (*offset)++;
+ goto ok;
+ }
return parse_err(errlog, argv[0],
argv[arg], strlen(argv[arg]),
"unrecognized option");
+ }
/* For error messages, we include the leading '-' */
o--;
len = 2;
return -1;
}
+ok:
/* If no more letters in that short opt, reset offset. */
if (*offset && !argv[arg][*offset + 1])
*offset = 0;
extern struct opt_alloc opt_alloc;
int parse_one(int *argc, char *argv[], enum opt_type is_early, unsigned *offset,
- void (*errlog)(const char *fmt, ...));
+ void (*errlog)(const char *fmt, ...), bool unknown_ok);
#endif /* CCAN_OPT_PRIVATE_H */
--- /dev/null
+/* With errlog == NULL, we never get a "failure". */
+#include <ccan/tap/tap.h>
+#include <stdlib.h>
+#include <ccan/opt/opt.c>
+#include <ccan/opt/usage.c>
+#include <ccan/opt/helpers.c>
+#include <ccan/opt/parse.c>
+#include "utils.h"
+
+int main(int argc, char *argv[])
+{
+ plan_tests(8);
+
+ /* Simple short args.*/
+ opt_register_noarg("-a", test_noarg, NULL, "All");
+ opt_register_early_noarg("-b|--blong", test_noarg, NULL, "All");
+
+ /* This is OK. */
+ ok1(parse_early_args_incomplete(&argc, &argv, "-c", NULL));
+ ok1(test_cb_called == 0);
+
+ /* Skips letters correctly */
+ ok1(parse_early_args_incomplete(&argc, &argv, "-ca", NULL));
+ ok1(test_cb_called == 0); /* a is not an early arg! */
+
+ test_cb_called = 0;
+ ok1(parse_early_args_incomplete(&argc, &argv, "-bca", NULL));
+ ok1(test_cb_called == 1);
+
+ test_cb_called = 0;
+ ok1(parse_early_args_incomplete(&argc, &argv, "--unknown", "--also-unknown", "--blong", NULL));
+ ok1(test_cb_called == 1);
+
+ /* parse_args allocates argv */
+ free(argv);
+ return exit_status();
+}
return opt_early_parse(*argc, *argv, save_err_output);
}
+bool parse_early_args_incomplete(int *argc, char ***argv, ...)
+{
+ char **a;
+ va_list ap;
+
+ va_start(ap, argv);
+ *argc = 1;
+ a = malloc(sizeof(*a) * (*argc + 1));
+ a[0] = (*argv)[0];
+ while ((a[*argc] = va_arg(ap, char *)) != NULL) {
+ (*argc)++;
+ a = realloc(a, sizeof(*a) * (*argc + 1));
+ }
+
+ if (allocated)
+ free(*argv);
+
+ *argv = a;
+ allocated = true;
+
+ return opt_early_parse_incomplete(*argc, *argv, save_err_output);
+}
+
struct opt_table short_table[] = {
/* Short opts, different args. */
OPT_WITHOUT_ARG("-a", test_noarg, "a", "Description of a"),
bool parse_args(int *argc, char ***argv, ...);
bool parse_early_args(int *argc, char ***argv, ...);
+bool parse_early_args_incomplete(int *argc, char ***argv, ...);
extern char *err_output;
void save_err_output(const char *fmt, ...);
void reset_options(void);