Bring in the "Port PUFFS from NetBSD/FreeBSD" GSoC 2011 project results.
[dragonfly.git] / lib / librefuse / refuse_opt.c
1 /*      $NetBSD: refuse_opt.c,v 1.15 2011/03/01 11:23:42 soda Exp $     */
2
3 /*-
4  * Copyright (c) 2007 Juan Romero Pardines.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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.
26  */
27
28 /*
29  * TODO:
30  *      * -oblah,foo... works, but the options are not enabled.
31  *      * -ofoo=%s (accepts a string) or -ofoo=%u (int) is not
32  *        supported for now.
33  *      * void *data: how is it used? I think it's used to enable
34  *        options or pass values for the matching options.
35  */
36
37 #include <sys/types.h>
38
39 #include <err.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "fuse.h"
45 #include "fuse_opt.h"
46
47 #ifdef FUSE_OPT_DEBUG
48 #define DPRINTF(x)      do { printf x; } while ( /* CONSTCOND */ 0)
49 #else
50 #define DPRINTF(x)
51 #endif
52
53 enum {
54         KEY_HELP,
55         KEY_VERBOSE,
56         KEY_VERSION
57 };
58
59 struct fuse_opt_option {
60         const struct fuse_opt *fop;
61         char *option;
62         int key;
63         void *data;
64 };
65
66 static int fuse_opt_popt(struct fuse_opt_option *, const struct fuse_opt *);
67 static int fuse_opt_realloc_args(struct fuse_args *args, int nargc);
68
69 /*
70  * Public API.
71  *
72  * The following functions always return 0:
73  *
74  * int  fuse_opt_add_opt(char **, const char *);
75  *
76  * We implement the next ones:
77  *
78  * int  fuse_opt_add_arg(struct fuse_args *, const char *);
79  * void fuse_opt_free_args(struct fuse_args *);
80  * int  fuse_opt_insert_arg(struct fuse_args *, const char *);
81  * int  fuse_opt_match(const struct fuse_opt *, const char *);
82  * int  fuse_opt_parse(struct fuse_args *, void *,
83  *                     const struct fuse_opt *, fuse_opt_proc_t);
84  *
85  */
86
87 /* ARGSUSED */
88 int
89 fuse_opt_add_arg(struct fuse_args *args, const char *arg)
90 {
91
92         fuse_opt_realloc_args(args, args->argc + 1);
93         DPRINTF(("%s: arguments passed: [arg:%s]\n", __func__, arg));
94         if ((args->argv[args->argc++] = strdup(arg)) == NULL)
95                 err(1, "fuse_opt_add_arg");
96         args->argv[args->argc] = NULL;
97         return 0;
98 }
99
100 struct fuse_args *
101 fuse_opt_deep_copy_args(int argc, char **argv)
102 {
103         struct fuse_args        *ap;
104         int                      i;
105
106         if ((ap = malloc(sizeof(*ap))) == NULL)
107                 err(1, "_fuse_deep_copy_args");
108         /* deep copy args structure into channel args */
109         ap->allocated = ((argc / 10) + 1) * 10;
110
111         if ((ap->argv = calloc((size_t)ap->allocated,
112             sizeof(*ap->argv))) == NULL)
113                 err(1, "_fuse_deep_copy_args");
114
115         for (i = 0; i < argc; i++) {
116                 if ((ap->argv[i] = strdup(argv[i])) == NULL)
117                         err(1, "_fuse_deep_copy_args");
118         }
119         ap->argv[ap->argc = i] = NULL;
120         return ap;
121 }
122
123 static int
124 fuse_opt_realloc_args(struct fuse_args *args, int nargc)
125 {
126         struct fuse_args        *ap;
127
128         if (args->allocated == 0) {
129                 ap = fuse_opt_deep_copy_args(args->argc, args->argv);
130                 args->argv = ap->argv;
131                 args->argc = ap->argc;
132                 args->allocated = ap->allocated;
133                 (void) free(ap);
134         } else if (args->allocated < nargc) {
135                 void *a;
136                 int na = nargc + 10;
137
138                 if ((a = realloc(args->argv, na * sizeof(*args->argv))) == NULL)
139                         return -1;
140
141                 args->argv = a;
142                 args->allocated = na;
143         }
144
145         return 0;
146 }
147
148 void
149 fuse_opt_free_args(struct fuse_args *ap)
150 {
151         int     i;
152
153         for (i = 0; i < ap->argc; i++) {
154                 free(ap->argv[i]);
155         }
156         free(ap->argv);
157         ap->argv = NULL;
158         ap->allocated = ap->argc = 0;
159 }
160
161 /* ARGSUSED */
162 int
163 fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
164 {
165         int     i;
166
167         DPRINTF(("%s: arguments passed: [pos=%d] [arg=%s]\n",
168             __func__, pos, arg));
169         fuse_opt_realloc_args(args, args->argc + 1);
170
171         for (i = args->argc++; i > pos; --i) {
172                 args->argv[i] = args->argv[i - 1];
173         }
174         if ((args->argv[pos] = strdup(arg)) == NULL)
175                 err(1, "fuse_opt_insert_arg");
176         args->argv[args->argc] = NULL;
177         return 0;
178 }
179
180 /* ARGSUSED */
181 int fuse_opt_add_opt(char **opts, const char *opt)
182 {
183         DPRINTF(("%s: arguments passed: [opts=%s] [opt=%s]\n",
184             __func__, *opts, opt));
185         return 0;
186 }
187
188 /*
189  * Returns 0 if opt was matched with any option from opts,
190  * otherwise returns 1.
191  */
192 int
193 fuse_opt_match(const struct fuse_opt *opts, const char *opt)
194 {
195         while (opts++) {
196                 if (strcmp(opt, opts->templ) == 0)
197                         return 0;
198         }
199
200         return 1;
201 }
202
203 /*
204  * Returns 0 if foo->option was matched with any option from opts,
205  * and sets the following on match:
206  *
207  *      * foo->key is set to the foo->fop->value if offset == -1.
208  *      * foo->fop points to the matched struct opts.
209  *
210  * otherwise returns 1.
211  */
212 static int
213 fuse_opt_popt(struct fuse_opt_option *foo, const struct fuse_opt *opts)
214 {
215         int i, found = 0;
216         char *match;
217
218         if (!foo->option) {
219                 (void)fprintf(stderr, "fuse: missing argument after -o\n");
220                 return 1;
221         }
222         /*
223          * iterate over argv and opts to see
224          * if there's a match with any template.
225          */
226         for (match = strtok(foo->option, ",");
227              match; match = strtok(NULL, ",")) {
228
229                 DPRINTF(("%s: specified option='%s'\n", __func__, match));
230                 found = 0;
231
232                 for (i = 0; opts && opts->templ; opts++, i++) {
233
234                         DPRINTF(("%s: opts->templ='%s' opts->offset=%d "
235                             "opts->value=%d\n", __func__, opts->templ,
236                             opts->offset, opts->value));
237
238                         /* option is ok */
239                         if (strcmp(match, opts->templ) == 0) {
240                                 DPRINTF(("%s: option matched='%s'\n",
241                                     __func__, match));
242                                 found++;
243                                 /*
244                                  * our fop pointer now points
245                                  * to the matched struct opts.
246                                  */
247                                 foo->fop = opts;
248                                 /*
249                                  * assign default key value, necessary for
250                                  * KEY_HELP, KEY_VERSION and KEY_VERBOSE.
251                                  */
252                                 if (foo->fop->offset == -1)
253                                         foo->key = foo->fop->value;
254                                 /* reset counter */
255                                 opts -= i;
256                                 break;
257                         }
258                 }
259                 /* invalid option */
260                 if (!found) {
261                         (void)fprintf(stderr, "fuse: '%s' is not a "
262                             "valid option\n", match);
263                         return 1;
264                 }
265         }
266
267         return 0;
268 }
269
270 /* ARGSUSED1 */
271 int
272 fuse_opt_parse(struct fuse_args *args, void *data,
273         const struct fuse_opt *opts, fuse_opt_proc_t proc)
274 {
275         struct fuse_opt_option foo;
276         char *buf;
277         int i, rv = 0;
278
279         if (!args || !args->argv || !args->argc || !proc)
280                 return 0;
281
282         foo.data = data;
283         if (args->argc == 1)
284                 return proc(foo.data, *args->argv, FUSE_OPT_KEY_OPT, args);
285
286         /* the real loop to process the arguments */
287         for (i = 1; i < args->argc; i++) {
288
289                 /* assign current argv string */
290                 foo.option = buf = args->argv[i];
291
292                 /* argvn != -foo... */
293                 if (buf[0] != '-') {
294
295                         foo.key = FUSE_OPT_KEY_NONOPT;
296                         rv = proc(foo.data, foo.option, foo.key, args);
297                         if (rv != 0)
298                                 break;
299
300                 /* -o was specified... */
301                 } else if (buf[0] == '-' && buf[1] == 'o') {
302
303                         /* -oblah,foo... */
304                         if (buf[2]) {
305                                 /* skip -o */
306                                 foo.option = args->argv[i] + 2;
307                         /* -o blah,foo... */
308                         } else {
309                                 /*
310                                  * skip current argv and pass to the
311                                  * next one to parse the options.
312                                  */
313                                 ++i;
314                                 foo.option = args->argv[i];
315                         }
316
317                         rv = fuse_opt_popt(&foo, opts);
318                         if (rv != 0)
319                                 break;
320
321                 /* help/version/verbose argument */
322                 } else if (buf[0] == '-' && buf[1] != 'o') {
323                         /*
324                          * check if the argument matches
325                          * with any template in opts.
326                          */
327                         rv = fuse_opt_popt(&foo, opts);
328                         if (rv != 0) {
329                                 break;
330                         } else {
331                                 DPRINTF(("%s: foo.fop->templ='%s' "
332                                     "foo.fop->offset: %d "
333                                     "foo.fop->value: %d\n",
334                                     __func__, foo.fop->templ,
335                                     foo.fop->offset, foo.fop->value));
336
337                                 /* argument needs to be discarded */
338                                 if (foo.key == FUSE_OPT_KEY_DISCARD) {
339                                         rv = 1;
340                                         break;
341                                 }
342
343                                 /* process help/version argument */
344                                 if (foo.key != KEY_VERBOSE &&
345                                     foo.key != FUSE_OPT_KEY_KEEP) {
346                                         rv = proc(foo.data, foo.option,
347                                                   foo.key, args);
348                                         break;
349                                 } else {
350                                         /* process verbose argument */
351                                         rv = proc(foo.data, foo.option,
352                                                        foo.key, args);
353                                         if (rv != 0)
354                                                 break;
355                                 }
356                         }
357                 /* unknown option, how could that happen? */
358                 } else {
359                         DPRINTF(("%s: unknown option\n", __func__));
360                         rv = 1;
361                         break;
362                 }
363         }
364
365         return rv;
366 }