12#include "fuse_config.h"
22struct fuse_opt_context {
39 for (i = 0; i < args->
argc; i++)
49static int alloc_failed(
void)
51 fuse_log(FUSE_LOG_ERR,
"fuse: memory allocation failed\n");
64 return alloc_failed();
66 newargv = realloc(args->
argv, (args->
argc + 2) *
sizeof(
char *));
69 return alloc_failed();
79static int fuse_opt_insert_arg_common(
struct fuse_args *args,
int pos,
82 assert(pos <= args->
argc);
86 if (pos != args->
argc - 1) {
87 char *newarg = args->
argv[args->
argc - 1];
88 memmove(&args->
argv[pos + 1], &args->
argv[pos],
89 sizeof(
char *) * (args->
argc - pos - 1));
90 args->
argv[pos] = newarg;
97 return fuse_opt_insert_arg_common(args, pos, arg);
100static int next_arg(
struct fuse_opt_context *ctx,
const char *opt)
102 if (ctx->argctr + 1 >= ctx->argc) {
103 fuse_log(FUSE_LOG_ERR,
"fuse: missing argument after `%s'\n", opt);
110static int add_arg(
struct fuse_opt_context *ctx,
const char *arg)
115static int add_opt_common(
char **opts,
const char *opt,
int esc)
117 unsigned oldlen = *opts ? strlen(*opts) : 0;
118 char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1);
121 return alloc_failed();
129 for (; *opt; opt++) {
130 if (esc && (*opt ==
',' || *opt ==
'\\'))
141 return add_opt_common(opts, opt, 0);
146 return add_opt_common(opts, opt, 1);
149static int add_opt(
struct fuse_opt_context *ctx,
const char *opt)
151 return add_opt_common(&ctx->opts, opt, 1);
154static int call_proc(
struct fuse_opt_context *ctx,
const char *arg,
int key,
161 int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
162 if (res == -1 || !res)
166 return add_opt(ctx, arg);
168 return add_arg(ctx, arg);
171static int match_template(
const char *t,
const char *arg,
unsigned *sepp)
173 int arglen = strlen(arg);
174 const char *sep = strchr(t,
'=');
175 sep = sep ? sep : strchr(t,
' ');
176 if (sep && (!sep[1] || sep[1] ==
'%')) {
180 if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
185 if (strcmp(t, arg) == 0) {
193 const char *arg,
unsigned *sepp)
195 for (; opt && opt->
templ; opt++)
196 if (match_template(opt->
templ, arg, sepp))
204 return find_opt(opts, opt, &dummy) ? 1 : 0;
207static int process_opt_param(
void *var,
const char *format,
const char *param,
210 assert(format[0] ==
'%');
211 if (format[1] ==
's') {
213 char *copy = strdup(param);
215 return alloc_failed();
220 if (sscanf(param, format, var) != 1) {
221 fuse_log(FUSE_LOG_ERR,
"fuse: invalid parameter in option `%s'\n", arg);
228static int process_opt(
struct fuse_opt_context *ctx,
229 const struct fuse_opt *opt,
unsigned sep,
230 const char *arg,
int iso)
233 if (call_proc(ctx, arg, opt->
value, iso) == -1)
236 void *var = (
char *)ctx->data + opt->
offset;
237 if (sep && opt->
templ[sep + 1]) {
238 const char *param = arg + sep;
239 if (opt->
templ[sep] ==
'=')
241 if (process_opt_param(var, opt->
templ + sep + 1,
245 *(
int *)var = opt->
value;
250static int process_opt_sep_arg(
struct fuse_opt_context *ctx,
251 const struct fuse_opt *opt,
unsigned sep,
252 const char *arg,
int iso)
258 if (next_arg(ctx, arg) == -1)
261 param = ctx->argv[ctx->argctr];
262 newarg = malloc(sep + strlen(param) + 1);
264 return alloc_failed();
266 memcpy(newarg, arg, sep);
267 strcpy(newarg + sep, param);
268 res = process_opt(ctx, opt, sep, newarg, iso);
274static int process_gopt(
struct fuse_opt_context *ctx,
const char *arg,
int iso)
277 const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
279 for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
281 if (sep && opt->
templ[sep] ==
' ' && !arg[sep])
282 res = process_opt_sep_arg(ctx, opt, sep, arg,
285 res = process_opt(ctx, opt, sep, arg, iso);
294static int process_real_option_group(
struct fuse_opt_context *ctx,
char *opts)
303 if (*s ==
',' || end) {
307 res = process_gopt(ctx, opts, 1);
312 if (s[0] ==
'\\' && s[1] !=
'\0') {
314 if (s[0] >=
'0' && s[0] <=
'3' &&
315 s[1] >=
'0' && s[1] <=
'7' &&
316 s[2] >=
'0' && s[2] <=
'7') {
317 *d++ = (s[0] -
'0') * 0100 +
318 (s[1] -
'0') * 0010 +
334static int process_option_group(
struct fuse_opt_context *ctx,
const char *opts)
337 char *copy = strdup(opts);
340 fuse_log(FUSE_LOG_ERR,
"fuse: memory allocation failed\n");
343 res = process_real_option_group(ctx, copy);
348static int process_one(
struct fuse_opt_context *ctx,
const char *arg)
350 if (ctx->nonopt || arg[0] !=
'-')
352 else if (arg[1] ==
'o') {
354 return process_option_group(ctx, arg + 2);
356 if (next_arg(ctx, arg) == -1)
359 return process_option_group(ctx,
360 ctx->argv[ctx->argctr]);
362 }
else if (arg[1] ==
'-' && !arg[2]) {
363 if (add_arg(ctx, arg) == -1)
365 ctx->nonopt = ctx->outargs.argc;
368 return process_gopt(ctx, arg, 0);
371static int opt_parse(
struct fuse_opt_context *ctx)
374 if (add_arg(ctx, ctx->argv[0]) == -1)
378 for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
379 if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
389 if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc &&
390 strcmp(ctx->outargs.argv[ctx->outargs.argc - 1],
"--") == 0) {
391 free(ctx->outargs.argv[ctx->outargs.argc - 1]);
392 ctx->outargs.argv[--ctx->outargs.argc] = NULL;
402 struct fuse_opt_context ctx = {
408 if (!args || !args->
argv || !args->
argc)
411 ctx.argc = args->
argc;
412 ctx.argv = args->
argv;
414 res = opt_parse(&ctx);
void fuse_log(enum fuse_log_level level, const char *fmt,...)
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
void fuse_opt_free_args(struct fuse_args *args)
int(* fuse_opt_proc_t)(void *data, const char *arg, int key, struct fuse_args *outargs)
int fuse_opt_add_opt_escaped(char **opts, const char *opt)
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
#define FUSE_OPT_KEY_NONOPT
#define FUSE_OPT_KEY_DISCARD
#define FUSE_OPT_KEY_KEEP
int fuse_opt_add_opt(char **opts, const char *opt)
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
int fuse_opt_match(const struct fuse_opt opts[], const char *opt)