Home | History | Annotate | Line # | Download | only in librefuse
refuse_opt.c revision 1.1
      1 /* 	$NetBSD: refuse_opt.c,v 1.1 2007/02/28 16:23:00 xtraeme 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 (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 int
    198 fuse_opt_parse(struct fuse_args *args, void *data,
    199         const struct fuse_opt *opts, fuse_opt_proc_t proc)
    200 {
    201 	struct fuse_opt_option foo;
    202 	char *buf;
    203 	int i, rv = EXIT_SUCCESS;
    204 
    205 	if (!args || !args->argv || !args->argc || !proc)
    206 		return 0;
    207 
    208 	if (args->argc == 1)
    209 		return proc(foo.data, *args->argv, FUSE_OPT_KEY_OPT, args);
    210 
    211 	/* the real loop to process the arguments */
    212 	for (i = 1; i < args->argc; i++) {
    213 
    214 		/* assign current argv string */
    215 		foo.option = buf = args->argv[i];
    216 
    217 		/* argvn != -foo... */
    218 		if (buf[0] != '-') {
    219 
    220 			foo.key = FUSE_OPT_KEY_NONOPT;
    221 			if ((rv = proc(foo.data, foo.option, foo.key, args)))
    222 				break;
    223 
    224 		/* -o was specified... */
    225 		} else if (buf[0] == '-' && buf[1] == 'o') {
    226 
    227 			/* -oblah,foo... */
    228 			if (buf[2]) {
    229 				/* skip -o */
    230 				foo.option = args->argv[i] + 2;
    231 			/* -o blah,foo... */
    232 			} else {
    233 				/*
    234 			 	 * skip current argv and pass to the
    235 			 	 * next one to parse the options.
    236 				 */
    237 				++i;
    238 				foo.option = args->argv[i];
    239 			}
    240 
    241 			if ((rv = fuse_opt_popt(&foo, opts)))
    242 				break;
    243 
    244 		/* help/version/verbose argument */
    245 		} else if (buf[0] == '-' && buf[1] != 'o') {
    246 			/*
    247 			 * check if the argument matches
    248 			 * with any template in opts.
    249 			 */
    250 			if ((rv = fuse_opt_popt(&foo, opts))) {
    251 				break;
    252 			} else {
    253 				DPRINTF(("%s: foo.fop->templ='%s' "
    254 			    	    "foo.fop->offset: %d "
    255 			    	    "foo.fop->value: %d\n",
    256 			    	    __func__, foo.fop->templ,
    257 			    	    foo.fop->offset, foo.fop->value));
    258 
    259 				/* argument needs to be discarded */
    260 				if (foo.key == FUSE_OPT_KEY_DISCARD) {
    261 					rv = EXIT_FAILURE;
    262 					break;
    263 				}
    264 
    265 				/* process help/version argument */
    266 				if (foo.key != KEY_VERBOSE &&
    267 				    foo.key != FUSE_OPT_KEY_KEEP) {
    268 					rv = proc(foo.data, foo.option,
    269 				    		  foo.key, args);
    270 					break;
    271 				} else {
    272 					/* process verbose argument */
    273 					if ((rv = proc(foo.data, foo.option,
    274 						       foo.key, args)))
    275 						break;
    276 				}
    277 			}
    278 		/* unknown option, how could that happen? */
    279 		} else {
    280 			DPRINTF(("%s: unknown option\n", __func__));
    281 			rv = EXIT_FAILURE;
    282 			break;
    283 		}
    284 	}
    285 
    286 	return rv;
    287 }
    288