2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
16 struct fuse_opt_context
{
18 const struct fuse_opt
*opt
;
23 struct fuse_args outargs
;
28 void fuse_opt_free_args(struct fuse_args
*args
)
30 if (args
&& args
->argv
&& args
->allocated
) {
32 for (i
= 0; i
< args
->argc
; i
++)
41 static int alloc_failed(void)
43 fprintf(stderr
, "fuse: memory allocation failed\n");
47 int fuse_opt_add_arg(struct fuse_args
*args
, const char *arg
)
52 assert(!args
->argv
|| args
->allocated
);
54 newargv
= realloc(args
->argv
, (args
->argc
+ 2) * sizeof(char *));
55 newarg
= newargv
? strdup(arg
) : NULL
;
56 if (!newargv
|| !newarg
)
57 return alloc_failed();
61 args
->argv
[args
->argc
++] = newarg
;
62 args
->argv
[args
->argc
] = NULL
;
66 int fuse_opt_insert_arg(struct fuse_args
*args
, int pos
, const char *arg
)
68 assert(pos
<= args
->argc
);
69 if (fuse_opt_add_arg(args
, arg
) == -1)
72 if (pos
!= args
->argc
- 1) {
73 char *newarg
= args
->argv
[args
->argc
- 1];
74 memmove(&args
->argv
[pos
+ 1], &args
->argv
[pos
],
75 sizeof(char *) * (args
->argc
- pos
- 1));
76 args
->argv
[pos
] = newarg
;
81 static int next_arg(struct fuse_opt_context
*ctx
, const char *opt
)
83 if (ctx
->argctr
+ 1 >= ctx
->argc
) {
84 fprintf(stderr
, "fuse: missing argument after `%s'\n", opt
);
91 static int add_arg(struct fuse_opt_context
*ctx
, const char *arg
)
93 return fuse_opt_add_arg(&ctx
->outargs
, arg
);
96 int fuse_opt_add_opt(char **opts
, const char *opt
)
100 newopts
= strdup(opt
);
102 unsigned oldlen
= strlen(*opts
);
103 newopts
= realloc(*opts
, oldlen
+ 1 + strlen(opt
) + 1);
105 newopts
[oldlen
] = ',';
106 strcpy(newopts
+ oldlen
+ 1, opt
);
110 return alloc_failed();
116 static int add_opt(struct fuse_opt_context
*ctx
, const char *opt
)
118 return fuse_opt_add_opt(&ctx
->opts
, opt
);
121 static int call_proc(struct fuse_opt_context
*ctx
, const char *arg
, int key
,
124 if (key
== FUSE_OPT_KEY_DISCARD
)
127 if (key
!= FUSE_OPT_KEY_KEEP
&& ctx
->proc
) {
128 int res
= ctx
->proc(ctx
->data
, arg
, key
, &ctx
->outargs
);
129 if (res
== -1 || !res
)
133 return add_opt(ctx
, arg
);
135 return add_arg(ctx
, arg
);
138 static int match_template(const char *t
, const char *arg
, unsigned *sepp
)
140 int arglen
= strlen(arg
);
141 const char *sep
= strchr(t
, '=');
142 sep
= sep
? sep
: strchr(t
, ' ');
143 if (sep
&& (!sep
[1] || sep
[1] == '%')) {
147 if (arglen
>= tlen
&& strncmp(arg
, t
, tlen
) == 0) {
152 if (strcmp(t
, arg
) == 0) {
159 static const struct fuse_opt
*find_opt(const struct fuse_opt
*opt
,
160 const char *arg
, unsigned *sepp
)
162 for (; opt
&& opt
->templ
; opt
++)
163 if (match_template(opt
->templ
, arg
, sepp
))
168 int fuse_opt_match(const struct fuse_opt
*opts
, const char *opt
)
171 return find_opt(opts
, opt
, &dummy
) ? 1 : 0;
174 static int process_opt_param(void *var
, const char *format
, const char *param
,
177 assert(format
[0] == '%');
178 if (format
[1] == 's') {
179 char *copy
= strdup(param
);
181 return alloc_failed();
183 *(char **) var
= copy
;
185 if (sscanf(param
, format
, var
) != 1) {
186 fprintf(stderr
, "fuse: invalid parameter in option `%s'\n", arg
);
193 static int process_opt(struct fuse_opt_context
*ctx
,
194 const struct fuse_opt
*opt
, unsigned sep
,
195 const char *arg
, int iso
)
197 if (opt
->offset
== -1U) {
198 if (call_proc(ctx
, arg
, opt
->value
, iso
) == -1)
201 void *var
= ctx
->data
+ opt
->offset
;
202 if (sep
&& opt
->templ
[sep
+ 1]) {
203 const char *param
= arg
+ sep
;
204 if (opt
->templ
[sep
] == '=')
206 if (process_opt_param(var
, opt
->templ
+ sep
+ 1,
210 *(int *)var
= opt
->value
;
215 static int process_opt_sep_arg(struct fuse_opt_context
*ctx
,
216 const struct fuse_opt
*opt
, unsigned sep
,
217 const char *arg
, int iso
)
223 if (next_arg(ctx
, arg
) == -1)
226 param
= ctx
->argv
[ctx
->argctr
];
227 newarg
= malloc(sep
+ strlen(param
) + 1);
229 return alloc_failed();
231 memcpy(newarg
, arg
, sep
);
232 strcpy(newarg
+ sep
, param
);
233 res
= process_opt(ctx
, opt
, sep
, newarg
, iso
);
239 static int process_gopt(struct fuse_opt_context
*ctx
, const char *arg
, int iso
)
242 const struct fuse_opt
*opt
= find_opt(ctx
->opt
, arg
, &sep
);
244 for (; opt
; opt
= find_opt(opt
+ 1, arg
, &sep
)) {
246 if (sep
&& opt
->templ
[sep
] == ' ' && !arg
[sep
])
247 res
= process_opt_sep_arg(ctx
, opt
, sep
, arg
, iso
);
249 res
= process_opt(ctx
, opt
, sep
, arg
, iso
);
255 return call_proc(ctx
, arg
, FUSE_OPT_KEY_OPT
, iso
);
258 static int process_real_option_group(struct fuse_opt_context
*ctx
, char *opts
)
264 sep
= strchr(opts
, ',');
267 res
= process_gopt(ctx
, opts
, 1);
276 static int process_option_group(struct fuse_opt_context
*ctx
, const char *opts
)
280 const char *sep
= strchr(opts
, ',');
282 return process_gopt(ctx
, opts
, 1);
286 fprintf(stderr
, "fuse: memory allocation failed\n");
289 res
= process_real_option_group(ctx
, copy
);
294 static int process_one(struct fuse_opt_context
*ctx
, const char *arg
)
296 if (ctx
->nonopt
|| arg
[0] != '-')
297 return call_proc(ctx
, arg
, FUSE_OPT_KEY_NONOPT
, 0);
298 else if (arg
[1] == 'o') {
300 return process_option_group(ctx
, arg
+ 2);
302 if (next_arg(ctx
, arg
) == -1)
305 return process_option_group(ctx
, ctx
->argv
[ctx
->argctr
]);
307 } else if (arg
[1] == '-' && !arg
[2]) {
308 if (add_arg(ctx
, arg
) == -1)
310 ctx
->nonopt
= ctx
->outargs
.argc
;
313 return process_gopt(ctx
, arg
, 0);
316 static int opt_parse(struct fuse_opt_context
*ctx
)
319 if (add_arg(ctx
, ctx
->argv
[0]) == -1)
323 for (ctx
->argctr
= 1; ctx
->argctr
< ctx
->argc
; ctx
->argctr
++)
324 if (process_one(ctx
, ctx
->argv
[ctx
->argctr
]) == -1)
328 if (fuse_opt_insert_arg(&ctx
->outargs
, 1, "-o") == -1 ||
329 fuse_opt_insert_arg(&ctx
->outargs
, 2, ctx
->opts
) == -1)
332 if (ctx
->nonopt
&& ctx
->nonopt
== ctx
->outargs
.argc
) {
333 free(ctx
->outargs
.argv
[ctx
->outargs
.argc
- 1]);
334 ctx
->outargs
.argv
[--ctx
->outargs
.argc
] = NULL
;
340 int fuse_opt_parse(struct fuse_args
*args
, void *data
,
341 const struct fuse_opt opts
[], fuse_opt_proc_t proc
)
344 struct fuse_opt_context ctx
= {
350 if (!args
|| !args
->argv
|| !args
->argc
)
353 ctx
.argc
= args
->argc
;
354 ctx
.argv
= args
->argv
;
356 res
= opt_parse(&ctx
);
358 struct fuse_args tmp
= *args
;
363 fuse_opt_free_args(&ctx
.outargs
);