Home | History | Annotate | Line # | Download | only in librefuse
refuse_opt.c revision 1.4
      1 /* 	$NetBSD: refuse_opt.c,v 1.4 2007/03/13 22:47:04 agc 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  * 3. The name of the company nor the name of the author may be used to
     16  *    endorse or promote products derived from this software without
     17  *    specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 /*
     32  * TODO:
     33  * 	* -oblah,foo... works, but the options are not enabled.
     34  * 	* -ofoo=%s (accepts a string) or -ofoo=%u (int) is not
     35  * 	  supported for now.
     36  * 	* void *data: how is it used? I think it's used to enable
     37  * 	  options or pass values for the matching options.
     38  */
     39 
     40 #include "defs.h"
     41 #include "fuse.h"
     42 #include "fuse_opt.h"
     43 
     44 #ifdef FUSE_OPT_DEBUG
     45 #define DPRINTF(x)	do { printf x; } while ( /* CONSTCOND */ 0)
     46 #else
     47 #define DPRINTF(x)
     48 #endif
     49 
     50 enum {
     51 	KEY_HELP,
     52 	KEY_VERBOSE,
     53 	KEY_VERSION
     54 };
     55 
     56 struct fuse_opt_option {
     57 	const struct fuse_opt *fop;
     58 	char *option;
     59 	int key;
     60 	void *data;
     61 };
     62 
     63 static int fuse_opt_popt(struct fuse_opt_option *, const struct fuse_opt *);
     64 
     65 /*
     66  * Public API.
     67  *
     68  * The following functions always return 0:
     69  *
     70  * int	fuse_opt_add_arg(struct fuse_args *, const char *);
     71  * int	fuse_opt_add_opt(char **, const char *);
     72  * void	fuse_opt_free_args(struct fuse_args *);
     73  * int	fuse_opt_insert_arg(struct fuse_args *, const char *);
     74  *
     75  * We implement the next ones:
     76  *
     77  * int	fuse_opt_match(const struct fuse_opt *, const char *);
     78  * int	fuse_opt_parse(struct fuse_args *, void *,
     79  * 		       const struct fuse_opt *, fuse_opt_proc_t);
     80  *
     81  */
     82 
     83 /* ARGSUSED */
     84 int
     85 fuse_opt_add_arg(struct fuse_args *args, const char *arg)
     86 {
     87 	DPRINTF(("%s: arguments passed: [arg:%s]\n", __func__, arg));
     88         return EXIT_SUCCESS;
     89 }
     90 
     91 /* ARGSUSED */
     92 void
     93 fuse_opt_free_args(struct fuse_args *args)
     94 {
     95 	/* nada */
     96 }
     97 
     98 /* ARGSUSED */
     99 int
    100 fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
    101 {
    102 	DPRINTF(("%s: arguments passed: [pos=%d] [arg=%s]\n",
    103 	    __func__, pos, arg));
    104 	return EXIT_SUCCESS;
    105 }
    106 
    107 /* ARGSUSED */
    108 int fuse_opt_add_opt(char **opts, const char *opt)
    109 {
    110 	DPRINTF(("%s: arguments passed: [opts=%s] [opt=%s]\n",
    111 	    __func__, *opts, opt));
    112 	return EXIT_SUCCESS;
    113 }
    114 
    115 /*
    116  * Returns 0 if opt was matched with any option from opts,
    117  * otherwise returns 1.
    118  */
    119 int
    120 fuse_opt_match(const struct fuse_opt *opts, const char *opt)
    121 {
    122 	while (opts++) {
    123 		if (strcmp(opt, opts->templ) == 0)
    124 			return EXIT_SUCCESS;
    125 	}
    126 
    127 	return EXIT_FAILURE;
    128 }
    129 
    130 /*
    131  * Returns 0 if foo->option was matched with any option from opts,
    132  * and sets the following on match:
    133  *
    134  * 	* foo->key is set to the foo->fop->value if offset == -1.
    135  * 	* foo->fop points to the matched struct opts.
    136  *
    137  * otherwise returns 1.
    138  */
    139 static int
    140 fuse_opt_popt(struct fuse_opt_option *foo, const struct fuse_opt *opts)
    141 {
    142 	int i, found = 0;
    143 	char *match;
    144 
    145 	if (!foo->option) {
    146 		(void)fprintf(stderr, "fuse: missing argument after -o\n");
    147 		return EXIT_FAILURE;
    148 	}
    149 	/*
    150 	 * iterate over argv and opts to see
    151 	 * if there's a match with any template.
    152 	 */
    153 	for (match = strtok(foo->option, ",");
    154 	     match; match = strtok(NULL, ",")) {
    155 
    156 		DPRINTF(("%s: specified option='%s'\n", __func__, match));
    157 		found = 0;
    158 
    159 		for (i = 0; opts && opts->templ; opts++, i++) {
    160 
    161 			DPRINTF(("%s: opts->templ='%s' opts->offset=%d "
    162 			    "opts->value=%d\n", __func__, opts->templ,
    163 			    opts->offset, opts->value));
    164 
    165 			/* option is ok */
    166 			if (strcmp(match, opts->templ) == 0) {
    167 				DPRINTF(("%s: option matched='%s'\n",
    168 				    __func__, match));
    169 				found++;
    170 				/*
    171 				 * our fop pointer now points
    172 				 * to the matched struct opts.
    173 				 */
    174 				foo->fop = opts;
    175 				/*
    176 				 * assign default key value, necessary for
    177 				 * KEY_HELP, KEY_VERSION and KEY_VERBOSE.
    178 				 */
    179 				if (foo->fop->offset == -1)
    180 					foo->key = foo->fop->value;
    181 				/* reset counter */
    182 				opts -= i;
    183 				break;
    184 			}
    185 		}
    186 		/* invalid option */
    187 		if (!found) {
    188 			(void)fprintf(stderr, "fuse: '%s' is not a "
    189 			    "valid option\n", match);
    190 			return EXIT_FAILURE;
    191 		}
    192 	}
    193 
    194 	return EXIT_SUCCESS;
    195 }
    196 
    197 /* ARGSUSED1 */
    198 int
    199 fuse_opt_parse(struct fuse_args *args, void *data,
    200         const struct fuse_opt *opts, fuse_opt_proc_t proc)
    201 {
    202 	struct fuse_opt_option foo;
    203 	char *buf;
    204 	int i, rv = EXIT_SUCCESS;
    205 
    206 	if (!args || !args->argv || !args->argc || !proc)
    207 		return 0;
    208 
    209 	if (args->argc == 1)
    210 		return proc(foo.data, *args->argv, FUSE_OPT_KEY_OPT, args);
    211 
    212 	/* the real loop to process the arguments */
    213 	for (i = 1; i < args->argc; i++) {
    214 
    215 		/* assign current argv string */
    216 		foo.option = buf = args->argv[i];
    217 
    218 		/* argvn != -foo... */
    219 		if (buf[0] != '-') {
    220 
    221 			foo.key = FUSE_OPT_KEY_NONOPT;
    222 			rv = proc(foo.data, foo.option, foo.key, args);
    223 			if (rv != 0)
    224 				break;
    225 
    226 		/* -o was specified... */
    227 		} else if (buf[0] == '-' && buf[1] == 'o') {
    228 
    229 			/* -oblah,foo... */
    230 			if (buf[2]) {
    231 				/* skip -o */
    232 				foo.option = args->argv[i] + 2;
    233 			/* -o blah,foo... */
    234 			} else {
    235 				/*
    236 			 	 * skip current argv and pass to the
    237 			 	 * next one to parse the options.
    238 				 */
    239 				++i;
    240 				foo.option = args->argv[i];
    241 			}
    242 
    243 			rv = fuse_opt_popt(&foo, opts);
    244 			if (rv != 0)
    245 				break;
    246 
    247 		/* help/version/verbose argument */
    248 		} else if (buf[0] == '-' && buf[1] != 'o') {
    249 			/*
    250 			 * check if the argument matches
    251 			 * with any template in opts.
    252 			 */
    253 			rv = fuse_opt_popt(&foo, opts);
    254 			if (rv != 0) {
    255 				break;
    256 			} else {
    257 				DPRINTF(("%s: foo.fop->templ='%s' "
    258 			    	    "foo.fop->offset: %d "
    259 			    	    "foo.fop->value: %d\n",
    260 			    	    __func__, foo.fop->templ,
    261 			    	    foo.fop->offset, foo.fop->value));
    262 
    263 				/* argument needs to be discarded */
    264 				if (foo.key == FUSE_OPT_KEY_DISCARD) {
    265 					rv = EXIT_FAILURE;
    266 					break;
    267 				}
    268 
    269 				/* process help/version argument */
    270 				if (foo.key != KEY_VERBOSE &&
    271 				    foo.key != FUSE_OPT_KEY_KEEP) {
    272 					rv = proc(foo.data, foo.option,
    273 				    		  foo.key, args);
    274 					break;
    275 				} else {
    276 					/* process verbose argument */
    277 					rv = proc(foo.data, foo.option,
    278 						       foo.key, args);
    279 					if (rv != 0)
    280 						break;
    281 				}
    282 			}
    283 		/* unknown option, how could that happen? */
    284 		} else {
    285 			DPRINTF(("%s: unknown option\n", __func__));
    286 			rv = EXIT_FAILURE;
    287 			break;
    288 		}
    289 	}
    290 
    291 	return rv;
    292 }
    293