1 /* $NetBSD: refuse_opt.c,v 1.13 2007/11/05 13:41:52 pooka Exp $ */
4 * Copyright (c) 2007 Juan Romero Pardines.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * * -oblah,foo... works, but the options are not enabled.
31 * * -ofoo=%s (accepts a string) or -ofoo=%u (int) is not
33 * * void *data: how is it used? I think it's used to enable
34 * options or pass values for the matching options.
37 #include <sys/types.h>
47 #define DPRINTF(x) do { printf x; } while ( /* CONSTCOND */ 0)
58 struct fuse_opt_option
{
59 const struct fuse_opt
*fop
;
65 static int fuse_opt_popt(struct fuse_opt_option
*, const struct fuse_opt
*);
70 * The following functions always return 0:
72 * int fuse_opt_add_opt(char **, const char *);
74 * We implement the next ones:
76 * int fuse_opt_add_arg(struct fuse_args *, const char *);
77 * void fuse_opt_free_args(struct fuse_args *);
78 * int fuse_opt_insert_arg(struct fuse_args *, const char *);
79 * int fuse_opt_match(const struct fuse_opt *, const char *);
80 * int fuse_opt_parse(struct fuse_args *, void *,
81 * const struct fuse_opt *, fuse_opt_proc_t);
87 fuse_opt_add_arg(struct fuse_args
*args
, const char *arg
)
91 if (args
->allocated
== 0) {
92 ap
= fuse_opt_deep_copy_args(args
->argc
, args
->argv
);
93 args
->argv
= ap
->argv
;
94 args
->argc
= ap
->argc
;
95 args
->allocated
= ap
->allocated
;
97 } else if (args
->allocated
== args
->argc
) {
99 int na
= args
->allocated
+ 10;
101 if ((a
= realloc(args
->argv
, na
* sizeof(*args
->argv
))) == NULL
)
105 args
->allocated
= na
;
107 DPRINTF(("%s: arguments passed: [arg:%s]\n", __func__
, arg
));
108 if ((args
->argv
[args
->argc
++] = strdup(arg
)) == NULL
)
109 err(1, "fuse_opt_add_arg");
110 args
->argv
[args
->argc
] = NULL
;
115 fuse_opt_deep_copy_args(int argc
, char **argv
)
117 struct fuse_args
*ap
;
120 if ((ap
= malloc(sizeof(*ap
))) == NULL
)
121 err(1, "_fuse_deep_copy_args");
122 /* deep copy args structure into channel args */
123 ap
->allocated
= ((argc
/ 10) + 1) * 10;
125 if ((ap
->argv
= calloc((size_t)ap
->allocated
,
126 sizeof(*ap
->argv
))) == NULL
)
127 err(1, "_fuse_deep_copy_args");
129 for (i
= 0; i
< argc
; i
++) {
130 if ((ap
->argv
[i
] = strdup(argv
[i
])) == NULL
)
131 err(1, "_fuse_deep_copy_args");
133 ap
->argv
[ap
->argc
= i
] = NULL
;
138 fuse_opt_free_args(struct fuse_args
*ap
)
142 for (i
= 0; i
< ap
->argc
; i
++) {
147 ap
->allocated
= ap
->argc
= 0;
152 fuse_opt_insert_arg(struct fuse_args
*args
, int pos
, const char *arg
)
158 DPRINTF(("%s: arguments passed: [pos=%d] [arg=%s]\n",
159 __func__
, pos
, arg
));
160 if (args
->argv
== NULL
) {
162 a
= malloc(na
* sizeof(*args
->argv
));
164 na
= args
->allocated
+ 10;
165 a
= realloc(args
->argv
, na
* sizeof(*args
->argv
));
168 warn("fuse_opt_insert_arg");
172 args
->allocated
= na
;
174 for (i
= args
->argc
++; i
> pos
; --i
) {
175 args
->argv
[i
] = args
->argv
[i
- 1];
177 if ((args
->argv
[pos
] = strdup(arg
)) == NULL
)
178 err(1, "fuse_opt_insert_arg");
179 args
->argv
[args
->argc
] = NULL
;
184 int fuse_opt_add_opt(char **opts
, const char *opt
)
186 DPRINTF(("%s: arguments passed: [opts=%s] [opt=%s]\n",
187 __func__
, *opts
, opt
));
192 * Returns 0 if opt was matched with any option from opts,
193 * otherwise returns 1.
196 fuse_opt_match(const struct fuse_opt
*opts
, const char *opt
)
199 if (strcmp(opt
, opts
->templ
) == 0)
207 * Returns 0 if foo->option was matched with any option from opts,
208 * and sets the following on match:
210 * * foo->key is set to the foo->fop->value if offset == -1.
211 * * foo->fop points to the matched struct opts.
213 * otherwise returns 1.
216 fuse_opt_popt(struct fuse_opt_option
*foo
, const struct fuse_opt
*opts
)
222 (void)fprintf(stderr
, "fuse: missing argument after -o\n");
226 * iterate over argv and opts to see
227 * if there's a match with any template.
229 for (match
= strtok(foo
->option
, ",");
230 match
; match
= strtok(NULL
, ",")) {
232 DPRINTF(("%s: specified option='%s'\n", __func__
, match
));
235 for (i
= 0; opts
&& opts
->templ
; opts
++, i
++) {
237 DPRINTF(("%s: opts->templ='%s' opts->offset=%d "
238 "opts->value=%d\n", __func__
, opts
->templ
,
239 opts
->offset
, opts
->value
));
242 if (strcmp(match
, opts
->templ
) == 0) {
243 DPRINTF(("%s: option matched='%s'\n",
247 * our fop pointer now points
248 * to the matched struct opts.
252 * assign default key value, necessary for
253 * KEY_HELP, KEY_VERSION and KEY_VERBOSE.
255 if (foo
->fop
->offset
== -1)
256 foo
->key
= foo
->fop
->value
;
264 (void)fprintf(stderr
, "fuse: '%s' is not a "
265 "valid option\n", match
);
275 fuse_opt_parse(struct fuse_args
*args
, void *data
,
276 const struct fuse_opt
*opts
, fuse_opt_proc_t proc
)
278 struct fuse_opt_option foo
;
282 if (!args
|| !args
->argv
|| !args
->argc
|| !proc
)
286 return proc(foo
.data
, *args
->argv
, FUSE_OPT_KEY_OPT
, args
);
288 /* the real loop to process the arguments */
289 for (i
= 1; i
< args
->argc
; i
++) {
291 /* assign current argv string */
292 foo
.option
= buf
= args
->argv
[i
];
294 /* argvn != -foo... */
297 foo
.key
= FUSE_OPT_KEY_NONOPT
;
298 rv
= proc(foo
.data
, foo
.option
, foo
.key
, args
);
302 /* -o was specified... */
303 } else if (buf
[0] == '-' && buf
[1] == 'o') {
308 foo
.option
= args
->argv
[i
] + 2;
312 * skip current argv and pass to the
313 * next one to parse the options.
316 foo
.option
= args
->argv
[i
];
319 rv
= fuse_opt_popt(&foo
, opts
);
323 /* help/version/verbose argument */
324 } else if (buf
[0] == '-' && buf
[1] != 'o') {
326 * check if the argument matches
327 * with any template in opts.
329 rv
= fuse_opt_popt(&foo
, opts
);
333 DPRINTF(("%s: foo.fop->templ='%s' "
334 "foo.fop->offset: %d "
335 "foo.fop->value: %d\n",
336 __func__
, foo
.fop
->templ
,
337 foo
.fop
->offset
, foo
.fop
->value
));
339 /* argument needs to be discarded */
340 if (foo
.key
== FUSE_OPT_KEY_DISCARD
) {
345 /* process help/version argument */
346 if (foo
.key
!= KEY_VERBOSE
&&
347 foo
.key
!= FUSE_OPT_KEY_KEEP
) {
348 rv
= proc(foo
.data
, foo
.option
,
352 /* process verbose argument */
353 rv
= proc(foo
.data
, foo
.option
,
359 /* unknown option, how could that happen? */
361 DPRINTF(("%s: unknown option\n", __func__
));