Major rework of fuse_opt_parse(3) so that it supports all the functionality of the original function
This commit is contained in:
parent
a1889144f5
commit
fd86259521
|
@ -1,9 +1,8 @@
|
|||
$NetBSD: TODO,v 1.3 2007/05/03 21:02:54 agc Exp $
|
||||
$NetBSD: TODO,v 1.4 2016/11/16 16:11:42 pho Exp $
|
||||
|
||||
To Do
|
||||
=====
|
||||
address all XXX
|
||||
implement all fuse_opt
|
||||
implement proper lookup (pending some libpuffs stuff)
|
||||
support fuse_mt (i.e. worker threads, but that'll probably be smarter
|
||||
to do inside of libpuffs)
|
||||
|
@ -23,3 +22,4 @@ special directory handling in open()
|
|||
Finish off manual page
|
||||
fuse_setup
|
||||
fuse_teardown
|
||||
fuse_opt
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: refuse_opt.c,v 1.17 2016/11/15 00:34:19 pho Exp $ */
|
||||
/* $NetBSD: refuse_opt.c,v 1.18 2016/11/16 16:11:42 pho Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2007 Juan Romero Pardines.
|
||||
|
@ -25,15 +25,6 @@
|
|||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* * -oblah,foo... works, but the options are not enabled.
|
||||
* * -ofoo=%s (accepts a string) or -ofoo=%u (int) is not
|
||||
* supported for now.
|
||||
* * void *data: how is it used? I think it's used to enable
|
||||
* options or pass values for the matching options.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <err.h>
|
||||
|
@ -50,21 +41,6 @@
|
|||
#define DPRINTF(x)
|
||||
#endif
|
||||
|
||||
enum {
|
||||
KEY_HELP,
|
||||
KEY_VERBOSE,
|
||||
KEY_VERSION
|
||||
};
|
||||
|
||||
struct fuse_opt_option {
|
||||
const struct fuse_opt *fop;
|
||||
char *option;
|
||||
int key;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static int fuse_opt_popt(struct fuse_opt_option *, const struct fuse_opt *);
|
||||
|
||||
/*
|
||||
* Public API.
|
||||
*/
|
||||
|
@ -124,14 +100,17 @@ fuse_opt_deep_copy_args(int argc, char **argv)
|
|||
void
|
||||
fuse_opt_free_args(struct fuse_args *ap)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ap->argc; i++) {
|
||||
free(ap->argv[i]);
|
||||
if (ap) {
|
||||
if (ap->allocated) {
|
||||
int i;
|
||||
for (i = 0; i < ap->argc; i++) {
|
||||
free(ap->argv[i]);
|
||||
}
|
||||
free(ap->argv);
|
||||
}
|
||||
ap->argv = NULL;
|
||||
ap->allocated = ap->argc = 0;
|
||||
}
|
||||
free(ap->argv);
|
||||
ap->argv = NULL;
|
||||
ap->allocated = ap->argc = 0;
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
|
@ -207,7 +186,7 @@ int fuse_opt_add_opt_escaped(char **opts, const char *opt)
|
|||
return add_opt(opts, opt, true);
|
||||
}
|
||||
|
||||
static bool match_templ(const char *templ, const char *opt, size_t *sep_idx)
|
||||
static bool match_templ(const char *templ, const char *opt, int *sep_idx)
|
||||
{
|
||||
const char *sep = strpbrk(templ, "= ");
|
||||
|
||||
|
@ -227,7 +206,7 @@ static bool match_templ(const char *templ, const char *opt, size_t *sep_idx)
|
|||
else {
|
||||
if (strcmp(templ, opt) == 0) {
|
||||
if (sep_idx != NULL)
|
||||
*sep_idx = 0;
|
||||
*sep_idx = -1;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -237,7 +216,7 @@ static bool match_templ(const char *templ, const char *opt, size_t *sep_idx)
|
|||
}
|
||||
|
||||
static const struct fuse_opt *
|
||||
find_opt(const struct fuse_opt *opts, const char *opt, size_t *sep_idx)
|
||||
find_opt(const struct fuse_opt *opts, const char *opt, int *sep_idx)
|
||||
{
|
||||
for (; opts != NULL && opts->templ != NULL; opts++) {
|
||||
if (match_templ(opts->templ, opt, sep_idx))
|
||||
|
@ -256,167 +235,293 @@ fuse_opt_match(const struct fuse_opt *opts, const char *opt)
|
|||
return find_opt(opts, opt, NULL) != NULL ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 0 if foo->option was matched with any option from opts,
|
||||
* and sets the following on match:
|
||||
*
|
||||
* * foo->key is set to the foo->fop->value if offset == -1.
|
||||
* * foo->fop points to the matched struct opts.
|
||||
*
|
||||
* otherwise returns 1.
|
||||
*/
|
||||
static int
|
||||
fuse_opt_popt(struct fuse_opt_option *foo, const struct fuse_opt *opts)
|
||||
static int call_proc(fuse_opt_proc_t proc, void* data,
|
||||
const char* arg, int key, struct fuse_args *outargs, bool is_opt)
|
||||
{
|
||||
int i, found = 0;
|
||||
char *match;
|
||||
|
||||
if (!foo->option) {
|
||||
(void)fprintf(stderr, "fuse: missing argument after -o\n");
|
||||
return 1;
|
||||
if (key == FUSE_OPT_KEY_DISCARD)
|
||||
return 0;
|
||||
|
||||
if (key != FUSE_OPT_KEY_KEEP && proc != NULL) {
|
||||
const int rv = proc(data, arg, key, outargs);
|
||||
|
||||
if (rv == -1 || /* error */
|
||||
rv == 0 /* discard */)
|
||||
return rv;
|
||||
}
|
||||
/*
|
||||
* iterate over argv and opts to see
|
||||
* if there's a match with any template.
|
||||
*/
|
||||
for (match = strtok(foo->option, ",");
|
||||
match; match = strtok(NULL, ",")) {
|
||||
|
||||
DPRINTF(("%s: specified option='%s'\n", __func__, match));
|
||||
found = 0;
|
||||
|
||||
for (i = 0; opts && opts->templ; opts++, i++) {
|
||||
|
||||
DPRINTF(("%s: opts->templ='%s' opts->offset=%d "
|
||||
"opts->value=%d\n", __func__, opts->templ,
|
||||
opts->offset, opts->value));
|
||||
|
||||
/* option is ok */
|
||||
if (strcmp(match, opts->templ) == 0) {
|
||||
DPRINTF(("%s: option matched='%s'\n",
|
||||
__func__, match));
|
||||
found++;
|
||||
/*
|
||||
* our fop pointer now points
|
||||
* to the matched struct opts.
|
||||
*/
|
||||
foo->fop = opts;
|
||||
/*
|
||||
* assign default key value, necessary for
|
||||
* KEY_HELP, KEY_VERSION and KEY_VERBOSE.
|
||||
*/
|
||||
if (foo->fop->offset == -1)
|
||||
foo->key = foo->fop->value;
|
||||
/* reset counter */
|
||||
opts -= i;
|
||||
break;
|
||||
}
|
||||
if (is_opt) {
|
||||
/* Do we already have "-o" at the beginning of outargs? */
|
||||
if (outargs->argc >= 3 && strcmp(outargs->argv[1], "-o") == 0) {
|
||||
/* Append the option to the comma-separated list. */
|
||||
if (fuse_opt_add_opt_escaped(&outargs->argv[2], arg) == -1)
|
||||
return -1;
|
||||
}
|
||||
/* invalid option */
|
||||
if (!found) {
|
||||
(void)fprintf(stderr, "fuse: '%s' is not a "
|
||||
"valid option\n", match);
|
||||
return 1;
|
||||
else {
|
||||
/* Insert -o arg at the beginning. */
|
||||
if (fuse_opt_insert_arg(outargs, 1, "-o") == -1)
|
||||
return -1;
|
||||
if (fuse_opt_insert_arg(outargs, 2, arg) == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (fuse_opt_add_arg(outargs, arg) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ARGSUSED1 */
|
||||
int
|
||||
fuse_opt_parse(struct fuse_args *args, void *data,
|
||||
const struct fuse_opt *opts, fuse_opt_proc_t proc)
|
||||
/* Skip the current argv if possible. */
|
||||
static int next_arg(const struct fuse_args *args, int *i)
|
||||
{
|
||||
struct fuse_opt_option foo;
|
||||
char *buf;
|
||||
int i, rv = 0;
|
||||
|
||||
if (!args || !args->argv || !args->argc || !proc)
|
||||
if (*i + 1 >= args->argc) {
|
||||
(void)fprintf(stderr, "fuse: missing argument"
|
||||
" after '%s'\n", args->argv[*i]);
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
*i += 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
foo.data = data;
|
||||
if (args->argc == 1)
|
||||
return proc(foo.data, *args->argv, FUSE_OPT_KEY_OPT, args);
|
||||
/* Parse a single argument with a matched template. */
|
||||
static int
|
||||
parse_matched_arg(const char* arg, struct fuse_args *outargs,
|
||||
const struct fuse_opt* opt, int sep_idx, void* data,
|
||||
fuse_opt_proc_t proc, bool is_opt)
|
||||
{
|
||||
if (opt->offset == -1) {
|
||||
/* The option description does not want any variables to be
|
||||
* updated.*/
|
||||
if (call_proc(proc, data, arg, opt->value, outargs, is_opt) == -1)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
void *var = (char*)data + opt->offset;
|
||||
|
||||
/* the real loop to process the arguments */
|
||||
for (i = 1; i < args->argc; i++) {
|
||||
if (sep_idx > 0 && opt->templ[sep_idx + 1] == '%') {
|
||||
/* "foo=%y" or "-x %y" */
|
||||
const char* param =
|
||||
opt->templ[sep_idx] == '=' ? &arg[sep_idx + 1] : &arg[sep_idx];
|
||||
|
||||
/* assign current argv string */
|
||||
foo.option = buf = args->argv[i];
|
||||
if (opt->templ[sep_idx + 2] == 's') {
|
||||
char* dup = strdup(param);
|
||||
if (dup == NULL)
|
||||
return -1;
|
||||
|
||||
/* argvn != -foo... */
|
||||
if (buf[0] != '-') {
|
||||
|
||||
foo.key = FUSE_OPT_KEY_NONOPT;
|
||||
rv = proc(foo.data, foo.option, foo.key, args);
|
||||
if (rv != 0)
|
||||
break;
|
||||
|
||||
/* -o was specified... */
|
||||
} else if (buf[0] == '-' && buf[1] == 'o') {
|
||||
|
||||
/* -oblah,foo... */
|
||||
if (buf[2]) {
|
||||
/* skip -o */
|
||||
foo.option = args->argv[i] + 2;
|
||||
/* -o blah,foo... */
|
||||
} else {
|
||||
/*
|
||||
* skip current argv and pass to the
|
||||
* next one to parse the options.
|
||||
*/
|
||||
++i;
|
||||
foo.option = args->argv[i];
|
||||
*(char **)var = dup;
|
||||
}
|
||||
|
||||
rv = fuse_opt_popt(&foo, opts);
|
||||
if (rv != 0)
|
||||
break;
|
||||
|
||||
/* help/version/verbose argument */
|
||||
} else if (buf[0] == '-' && buf[1] != 'o') {
|
||||
/*
|
||||
* check if the argument matches
|
||||
* with any template in opts.
|
||||
*/
|
||||
rv = fuse_opt_popt(&foo, opts);
|
||||
if (rv != 0) {
|
||||
break;
|
||||
} else {
|
||||
DPRINTF(("%s: foo.fop->templ='%s' "
|
||||
"foo.fop->offset: %d "
|
||||
"foo.fop->value: %d\n",
|
||||
__func__, foo.fop->templ,
|
||||
foo.fop->offset, foo.fop->value));
|
||||
|
||||
/* argument needs to be discarded */
|
||||
if (foo.key == FUSE_OPT_KEY_DISCARD) {
|
||||
rv = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* process help/version argument */
|
||||
if (foo.key != KEY_VERBOSE &&
|
||||
foo.key != FUSE_OPT_KEY_KEEP) {
|
||||
rv = proc(foo.data, foo.option,
|
||||
foo.key, args);
|
||||
break;
|
||||
} else {
|
||||
/* process verbose argument */
|
||||
rv = proc(foo.data, foo.option,
|
||||
foo.key, args);
|
||||
if (rv != 0)
|
||||
break;
|
||||
else {
|
||||
/* The format string is not a literal. We all know
|
||||
* this is a bad idea but it's exactly what fuse_opt
|
||||
* wants to do... */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
if (sscanf(param, &opt->templ[sep_idx + 1], var) == -1) {
|
||||
#pragma GCC diagnostic pop
|
||||
(void)fprintf(stderr, "fuse: '%s' is not a "
|
||||
"valid parameter for option '%.*s'\n",
|
||||
param, sep_idx, opt->templ);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* unknown option, how could that happen? */
|
||||
} else {
|
||||
DPRINTF(("%s: unknown option\n", __func__));
|
||||
rv = 1;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
/* No parameter format is given. */
|
||||
*(int *)var = opt->value;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse a single argument with matching templates. */
|
||||
static int
|
||||
parse_arg(struct fuse_args* args, int *argi, const char* arg,
|
||||
struct fuse_args *outargs, void *data,
|
||||
const struct fuse_opt *opts, fuse_opt_proc_t proc, bool is_opt)
|
||||
{
|
||||
int sep_idx;
|
||||
const struct fuse_opt *opt = find_opt(opts, arg, &sep_idx);
|
||||
|
||||
if (opt) {
|
||||
/* An argument can match to multiple templates. Process them
|
||||
* all. */
|
||||
for (; opt != NULL && opt->templ != NULL;
|
||||
opt = find_opt(++opt, arg, &sep_idx)) {
|
||||
|
||||
if (sep_idx > 0 && opt->templ[sep_idx] == ' ' &&
|
||||
arg[sep_idx] == '\0') {
|
||||
/* The template "-x %y" requests a separate
|
||||
* parameter "%y". Try to find one. */
|
||||
char *new_arg;
|
||||
int rv;
|
||||
|
||||
if (next_arg(args, argi) == -1)
|
||||
return -1;
|
||||
|
||||
/* ...but processor callbacks expect a concatenated
|
||||
* argument "-xfoo". */
|
||||
if ((new_arg = malloc(sep_idx +
|
||||
strlen(args->argv[*argi]) + 1)) == NULL)
|
||||
return -1;
|
||||
|
||||
strncpy(new_arg, arg, sep_idx); /* -x */
|
||||
strcpy(new_arg + sep_idx, args->argv[*argi]); /* foo */
|
||||
rv = parse_matched_arg(new_arg, outargs, opt, sep_idx,
|
||||
data, proc, is_opt);
|
||||
free(new_arg);
|
||||
|
||||
if (rv == -1)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
int rv;
|
||||
rv = parse_matched_arg(arg, outargs, opt, sep_idx,
|
||||
data, proc, is_opt);
|
||||
if (rv == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* No templates matched to it so just invoke the callback. */
|
||||
return call_proc(proc, data, arg, FUSE_OPT_KEY_OPT, outargs, is_opt);
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse a comma-separated list of options which possibly has escaped
|
||||
* characters. */
|
||||
static int
|
||||
parse_opts(struct fuse_args *args, int *argi, const char* arg,
|
||||
struct fuse_args *outargs, void *data,
|
||||
const struct fuse_opt *opts, fuse_opt_proc_t proc)
|
||||
{
|
||||
char *opt;
|
||||
size_t i, opt_len = 0;
|
||||
|
||||
/* An unescaped option can never be longer than the original
|
||||
* list. */
|
||||
if ((opt = malloc(strlen(arg) + 1)) == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < strlen(arg); i++) {
|
||||
if (arg[i] == ',') {
|
||||
opt[opt_len] = '\0';
|
||||
if (parse_arg(args, argi, opt, outargs,
|
||||
data, opts, proc, true) == -1) {
|
||||
free(opt);
|
||||
return -1;
|
||||
}
|
||||
/* Start a new option. */
|
||||
opt_len = 0;
|
||||
}
|
||||
else if (arg[i] == '\\' && arg[i+1] != '\0') {
|
||||
/* Unescape it. */
|
||||
opt[opt_len++] = arg[i+1];
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
opt[opt_len++] = arg[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the last option here. */
|
||||
opt[opt_len] = '\0';
|
||||
if (parse_arg(args, argi, opt, outargs, data, opts, proc, true) == -1) {
|
||||
free(opt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(opt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_all(struct fuse_args *args, struct fuse_args *outargs, void *data,
|
||||
const struct fuse_opt *opts, fuse_opt_proc_t proc)
|
||||
{
|
||||
bool nonopt = false; /* Have we seen the "--" marker? */
|
||||
int i;
|
||||
|
||||
/* The first argument, the program name, is implicitly
|
||||
* FUSE_OPT_KEY_KEEP. */
|
||||
if (args->argc > 0) {
|
||||
if (fuse_opt_add_arg(outargs, args->argv[0]) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* the real loop to process the arguments */
|
||||
for (i = 1; i < args->argc; i++) {
|
||||
const char *arg = args->argv[i];
|
||||
|
||||
/* argvn != -foo... */
|
||||
if (nonopt || arg[0] != '-') {
|
||||
if (call_proc(proc, data, arg, FUSE_OPT_KEY_NONOPT,
|
||||
outargs, false) == -1)
|
||||
return -1;
|
||||
}
|
||||
/* -o or -ofoo */
|
||||
else if (arg[1] == 'o') {
|
||||
/* -oblah,foo... */
|
||||
if (arg[2] != '\0') {
|
||||
/* skip -o */
|
||||
if (parse_opts(args, &i, arg + 2, outargs,
|
||||
data, opts, proc) == -1)
|
||||
return -1;
|
||||
}
|
||||
/* -o blah,foo... */
|
||||
else {
|
||||
if (next_arg(args, &i) == -1)
|
||||
return -1;
|
||||
if (parse_opts(args, &i, args->argv[i], outargs,
|
||||
data, opts, proc) == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* -- */
|
||||
else if (arg[1] == '-' && arg[2] == '\0') {
|
||||
if (fuse_opt_add_arg(outargs, arg) == -1)
|
||||
return -1;
|
||||
nonopt = true;
|
||||
}
|
||||
/* -foo */
|
||||
else {
|
||||
if (parse_arg(args, &i, arg, outargs,
|
||||
data, opts, proc, false) == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The "--" marker at the last of outargs should be removed */
|
||||
if (nonopt && strcmp(outargs->argv[outargs->argc - 1], "--") == 0) {
|
||||
free(outargs->argv[outargs->argc - 1]);
|
||||
outargs->argv[--outargs->argc] = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fuse_opt_parse(struct fuse_args *args, void *data,
|
||||
const struct fuse_opt *opts, fuse_opt_proc_t proc)
|
||||
{
|
||||
struct fuse_args outargs = FUSE_ARGS_INIT(0, NULL);
|
||||
int rv;
|
||||
|
||||
if (!args || !args->argv || !args->argc)
|
||||
return 0;
|
||||
|
||||
rv = parse_all(args, &outargs, data, opts, proc);
|
||||
if (rv != -1) {
|
||||
/* Succeeded. Swap the outargs and args. */
|
||||
struct fuse_args tmp = *args;
|
||||
*args = outargs;
|
||||
outargs = tmp;
|
||||
}
|
||||
|
||||
fuse_opt_free_args(&outargs);
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: t_refuse_opt.c,v 1.5 2016/11/15 10:05:22 martin Exp $ */
|
||||
/* $NetBSD: t_refuse_opt.c,v 1.6 2016/11/16 16:11:42 pho Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2016 The NetBSD Foundation, Inc.
|
||||
|
@ -26,7 +26,7 @@
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: t_refuse_opt.c,v 1.5 2016/11/15 10:05:22 martin Exp $");
|
||||
__RCSID("$NetBSD: t_refuse_opt.c,v 1.6 2016/11/16 16:11:42 pho Exp $");
|
||||
|
||||
#define _KERNTYPES
|
||||
#include <machine/types.h>
|
||||
|
@ -148,6 +148,260 @@ ATF_TC_BODY(t_fuse_opt_match, tc)
|
|||
ATF_CHECK(fuse_opt_match(o6, "bar" ) == 0);
|
||||
}
|
||||
|
||||
struct foofs_config {
|
||||
int number;
|
||||
char *string;
|
||||
char* nonopt;
|
||||
};
|
||||
|
||||
#define FOOFS_OPT(t, p, v) { t, offsetof(struct foofs_config, p), v }
|
||||
|
||||
static struct fuse_opt foofs_opts[] = {
|
||||
FOOFS_OPT("number=%i" , number, 0),
|
||||
FOOFS_OPT("-n %i" , number, 0),
|
||||
FOOFS_OPT("string=%s" , string, 0),
|
||||
FOOFS_OPT("number1" , number, 1),
|
||||
FOOFS_OPT("number2" , number, 2),
|
||||
FOOFS_OPT("--number=three", number, 3),
|
||||
FOOFS_OPT("--number=four" , number, 4),
|
||||
FUSE_OPT_END
|
||||
};
|
||||
|
||||
static int foo_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) {
|
||||
struct foofs_config *config = data;
|
||||
|
||||
if (key == FUSE_OPT_KEY_NONOPT && config->nonopt == NULL) {
|
||||
config->nonopt = strdup(arg);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TC(t_fuse_opt_parse_null_args);
|
||||
ATF_TC_HEAD(t_fuse_opt_parse_null_args, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "descr", "NULL args means an empty arguments vector");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(t_fuse_opt_parse_null_args, tc)
|
||||
{
|
||||
struct foofs_config config;
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
ATF_CHECK(fuse_opt_parse(NULL, &config, NULL, NULL) == 0);
|
||||
ATF_CHECK_EQ(config.number, 0);
|
||||
ATF_CHECK_EQ(config.string, NULL);
|
||||
ATF_CHECK_EQ(config.nonopt, NULL);
|
||||
}
|
||||
|
||||
ATF_TC(t_fuse_opt_parse_null_opts);
|
||||
ATF_TC_HEAD(t_fuse_opt_parse_null_opts, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "descr", "NULL opts means an opts array which only has FUSE_OPT_END");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(t_fuse_opt_parse_null_opts, tc)
|
||||
{
|
||||
struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
|
||||
struct foofs_config config;
|
||||
|
||||
RZ(fuse_opt_add_arg(&args, "foofs"));
|
||||
RZ(fuse_opt_add_arg(&args, "-o"));
|
||||
RZ(fuse_opt_add_arg(&args, "number=1,string=foo"));
|
||||
RZ(fuse_opt_add_arg(&args, "bar"));
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
ATF_CHECK(fuse_opt_parse(&args, &config, NULL, NULL) == 0);
|
||||
ATF_CHECK_EQ(config.number, 0);
|
||||
ATF_CHECK_EQ(config.string, NULL);
|
||||
ATF_CHECK_EQ(config.nonopt, NULL);
|
||||
ATF_CHECK_EQ(args.argc, 4);
|
||||
ATF_CHECK_STREQ(args.argv[0], "foofs");
|
||||
ATF_CHECK_STREQ(args.argv[1], "-o");
|
||||
ATF_CHECK_STREQ(args.argv[2], "number=1,string=foo");
|
||||
ATF_CHECK_STREQ(args.argv[3], "bar");
|
||||
}
|
||||
|
||||
ATF_TC(t_fuse_opt_parse_null_proc);
|
||||
ATF_TC_HEAD(t_fuse_opt_parse_null_proc, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "descr", "NULL proc means a processor function always returning 1,"
|
||||
" i.e. keep the argument");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(t_fuse_opt_parse_null_proc, tc)
|
||||
{
|
||||
struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
|
||||
struct foofs_config config;
|
||||
|
||||
RZ(fuse_opt_add_arg(&args, "foofs"));
|
||||
RZ(fuse_opt_add_arg(&args, "-o"));
|
||||
RZ(fuse_opt_add_arg(&args, "number=1,string=foo"));
|
||||
RZ(fuse_opt_add_arg(&args, "bar"));
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, NULL) == 0);
|
||||
ATF_CHECK_EQ(config.number, 1);
|
||||
ATF_CHECK_STREQ(config.string, "foo");
|
||||
ATF_CHECK_EQ(config.nonopt, NULL);
|
||||
ATF_CHECK_EQ(args.argc, 2);
|
||||
ATF_CHECK_STREQ(args.argv[0], "foofs");
|
||||
ATF_CHECK_STREQ(args.argv[1], "bar");
|
||||
}
|
||||
|
||||
ATF_TC(t_fuse_opt_parse);
|
||||
ATF_TC_HEAD(t_fuse_opt_parse, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "descr", "Check that fuse_opt_parse(3) fully works");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(t_fuse_opt_parse, tc)
|
||||
{
|
||||
struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
|
||||
struct foofs_config config;
|
||||
|
||||
/* Standard form */
|
||||
fuse_opt_free_args(&args);
|
||||
RZ(fuse_opt_add_arg(&args, "foofs"));
|
||||
RZ(fuse_opt_add_arg(&args, "-o"));
|
||||
RZ(fuse_opt_add_arg(&args, "number=1,string=foo"));
|
||||
RZ(fuse_opt_add_arg(&args, "bar"));
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
|
||||
ATF_CHECK_EQ(config.number, 1);
|
||||
ATF_CHECK_STREQ(config.string, "foo");
|
||||
ATF_CHECK_STREQ(config.nonopt, "bar");
|
||||
ATF_CHECK_EQ(args.argc, 1);
|
||||
ATF_CHECK_STREQ(args.argv[0], "foofs");
|
||||
|
||||
/* Concatenated -o */
|
||||
fuse_opt_free_args(&args);
|
||||
RZ(fuse_opt_add_arg(&args, "foofs"));
|
||||
RZ(fuse_opt_add_arg(&args, "-onumber=1,unknown,string=foo"));
|
||||
RZ(fuse_opt_add_arg(&args, "bar"));
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
|
||||
ATF_CHECK_EQ(config.number, 1);
|
||||
ATF_CHECK_STREQ(config.string, "foo");
|
||||
ATF_CHECK_STREQ(config.nonopt, "bar");
|
||||
ATF_CHECK_EQ(args.argc, 3);
|
||||
ATF_CHECK_STREQ(args.argv[0], "foofs");
|
||||
ATF_CHECK_STREQ(args.argv[1], "-o");
|
||||
ATF_CHECK_STREQ(args.argv[2], "unknown");
|
||||
|
||||
/* Sparse -o */
|
||||
fuse_opt_free_args(&args);
|
||||
RZ(fuse_opt_add_arg(&args, "foofs"));
|
||||
RZ(fuse_opt_add_arg(&args, "bar"));
|
||||
RZ(fuse_opt_add_arg(&args, "baz"));
|
||||
RZ(fuse_opt_add_arg(&args, "-o"));
|
||||
RZ(fuse_opt_add_arg(&args, "number=1"));
|
||||
RZ(fuse_opt_add_arg(&args, "-o"));
|
||||
RZ(fuse_opt_add_arg(&args, "unknown"));
|
||||
RZ(fuse_opt_add_arg(&args, "-o"));
|
||||
RZ(fuse_opt_add_arg(&args, "string=foo"));
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
|
||||
ATF_CHECK_EQ(config.number, 1);
|
||||
ATF_CHECK_STREQ(config.string, "foo");
|
||||
ATF_CHECK_STREQ(config.nonopt, "bar");
|
||||
ATF_CHECK_EQ(args.argc, 4);
|
||||
ATF_CHECK_STREQ(args.argv[0], "foofs");
|
||||
ATF_CHECK_STREQ(args.argv[1], "-o");
|
||||
ATF_CHECK_STREQ(args.argv[2], "unknown");
|
||||
ATF_CHECK_STREQ(args.argv[3], "baz");
|
||||
|
||||
/* Separate -n %i */
|
||||
fuse_opt_free_args(&args);
|
||||
RZ(fuse_opt_add_arg(&args, "foofs"));
|
||||
RZ(fuse_opt_add_arg(&args, "-n"));
|
||||
RZ(fuse_opt_add_arg(&args, "3"));
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
|
||||
ATF_CHECK_EQ(config.number, 3);
|
||||
ATF_CHECK_EQ(config.string, NULL);
|
||||
ATF_CHECK_EQ(config.nonopt, NULL);
|
||||
ATF_CHECK_EQ(args.argc, 1);
|
||||
ATF_CHECK_STREQ(args.argv[0], "foofs");
|
||||
|
||||
/* Concatenated -n %i */
|
||||
fuse_opt_free_args(&args);
|
||||
RZ(fuse_opt_add_arg(&args, "foofs"));
|
||||
RZ(fuse_opt_add_arg(&args, "-n3"));
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
|
||||
ATF_CHECK_EQ(config.number, 3);
|
||||
ATF_CHECK_EQ(config.string, NULL);
|
||||
ATF_CHECK_EQ(config.nonopt, NULL);
|
||||
ATF_CHECK_EQ(args.argc, 1);
|
||||
ATF_CHECK_STREQ(args.argv[0], "foofs");
|
||||
|
||||
/* -o constant */
|
||||
fuse_opt_free_args(&args);
|
||||
RZ(fuse_opt_add_arg(&args, "foofs"));
|
||||
RZ(fuse_opt_add_arg(&args, "-o"));
|
||||
RZ(fuse_opt_add_arg(&args, "number2"));
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
|
||||
ATF_CHECK_EQ(config.number, 2);
|
||||
ATF_CHECK_EQ(config.string, NULL);
|
||||
ATF_CHECK_EQ(config.nonopt, NULL);
|
||||
ATF_CHECK_EQ(args.argc, 1);
|
||||
ATF_CHECK_STREQ(args.argv[0], "foofs");
|
||||
|
||||
/* -x constant */
|
||||
fuse_opt_free_args(&args);
|
||||
RZ(fuse_opt_add_arg(&args, "foofs"));
|
||||
RZ(fuse_opt_add_arg(&args, "--number=four"));
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
|
||||
ATF_CHECK_EQ(config.number, 4);
|
||||
ATF_CHECK_EQ(config.string, NULL);
|
||||
ATF_CHECK_EQ(config.nonopt, NULL);
|
||||
ATF_CHECK_EQ(args.argc, 1);
|
||||
ATF_CHECK_STREQ(args.argv[0], "foofs");
|
||||
|
||||
/* end-of-options "--" marker */
|
||||
fuse_opt_free_args(&args);
|
||||
RZ(fuse_opt_add_arg(&args, "foofs"));
|
||||
RZ(fuse_opt_add_arg(&args, "--"));
|
||||
RZ(fuse_opt_add_arg(&args, "-onumber=1"));
|
||||
RZ(fuse_opt_add_arg(&args, "-ostring=foo"));
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
|
||||
ATF_CHECK_EQ(config.number, 0);
|
||||
ATF_CHECK_EQ(config.string, NULL);
|
||||
ATF_CHECK_STREQ(config.nonopt, "-onumber=1");
|
||||
ATF_CHECK_EQ(args.argc, 3);
|
||||
ATF_CHECK_STREQ(args.argv[0], "foofs");
|
||||
ATF_CHECK_STREQ(args.argv[1], "--");
|
||||
ATF_CHECK_STREQ(args.argv[2], "-ostring=foo");
|
||||
|
||||
/* The "--" marker at the last of outargs should be removed */
|
||||
fuse_opt_free_args(&args);
|
||||
RZ(fuse_opt_add_arg(&args, "foofs"));
|
||||
RZ(fuse_opt_add_arg(&args, "--"));
|
||||
RZ(fuse_opt_add_arg(&args, "-onumber=1"));
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
ATF_CHECK(fuse_opt_parse(&args, &config, foofs_opts, foo_opt_proc) == 0);
|
||||
ATF_CHECK_EQ(config.number, 0);
|
||||
ATF_CHECK_EQ(config.string, NULL);
|
||||
ATF_CHECK_STREQ(config.nonopt, "-onumber=1");
|
||||
ATF_CHECK_EQ(args.argc, 1);
|
||||
ATF_CHECK_STREQ(args.argv[0], "foofs");
|
||||
}
|
||||
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
ATF_TP_ADD_TC(tp, t_fuse_opt_add_arg);
|
||||
|
@ -155,6 +409,10 @@ ATF_TP_ADD_TCS(tp)
|
|||
ATF_TP_ADD_TC(tp, t_fuse_opt_add_opt);
|
||||
ATF_TP_ADD_TC(tp, t_fuse_opt_add_opt_escaped);
|
||||
ATF_TP_ADD_TC(tp, t_fuse_opt_match);
|
||||
ATF_TP_ADD_TC(tp, t_fuse_opt_parse_null_args);
|
||||
ATF_TP_ADD_TC(tp, t_fuse_opt_parse_null_opts);
|
||||
ATF_TP_ADD_TC(tp, t_fuse_opt_parse_null_proc);
|
||||
ATF_TP_ADD_TC(tp, t_fuse_opt_parse);
|
||||
|
||||
return atf_no_error();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue