diff --git a/inc/fuse/fuse_opt.h b/inc/fuse/fuse_opt.h index f235001b..1caa1277 100644 --- a/inc/fuse/fuse_opt.h +++ b/inc/fuse/fuse_opt.h @@ -35,6 +35,14 @@ extern "C" { #endif #endif +#define FSP_FUSE_MEMFN_P void *(*memalloc)(size_t), void (*memfree)(void *) +#define FSP_FUSE_MEMFN_A memalloc, memfree +#if defined(WINFSP_DLL_INTERNAL) +#define FSP_FUSE_MEMFN_V MemAlloc, MemFree +#else +#define FSP_FUSE_MEMFN_V malloc, free +#endif + #define FUSE_OPT_KEY(templ, key) { templ, -1U, key } #define FUSE_OPT_END { NULL, 0, 0 } @@ -63,48 +71,62 @@ typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key, struct fuse_args *outargs); FSP_FUSE_API int fsp_fuse_opt_parse(struct fuse_args *args, void *data, - const struct fuse_opt opts[], fuse_opt_proc_t proc); -FSP_FUSE_API int fsp_fuse_opt_add_opt(char **opts, const char *opt); -FSP_FUSE_API int fsp_fuse_opt_add_opt_escaped(char **opts, const char *opt); -FSP_FUSE_API int fsp_fuse_opt_add_arg(struct fuse_args *args, const char *arg); -FSP_FUSE_API int fsp_fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg); -FSP_FUSE_API void fsp_fuse_opt_free_args(struct fuse_args *args); -FSP_FUSE_API int fsp_fuse_opt_match(const struct fuse_opt opts[], const char *opt); + const struct fuse_opt opts[], fuse_opt_proc_t proc, + FSP_FUSE_MEMFN_P); +FSP_FUSE_API int fsp_fuse_opt_add_arg(struct fuse_args *args, const char *arg, + FSP_FUSE_MEMFN_P); +FSP_FUSE_API int fsp_fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg, + FSP_FUSE_MEMFN_P); +FSP_FUSE_API void fsp_fuse_opt_free_args(struct fuse_args *args, + FSP_FUSE_MEMFN_P); +FSP_FUSE_API int fsp_fuse_opt_add_opt(char **opts, const char *opt, + FSP_FUSE_MEMFN_P); +FSP_FUSE_API int fsp_fuse_opt_add_opt_escaped(char **opts, const char *opt, + FSP_FUSE_MEMFN_P); +FSP_FUSE_API int fsp_fuse_opt_match(const struct fuse_opt opts[], const char *opt, + FSP_FUSE_MEMFN_P); static inline int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc) { - return fsp_fuse_opt_parse(args, data, opts, proc); -} - -static inline int fuse_opt_add_opt(char **opts, const char *opt) -{ - return fsp_fuse_opt_add_opt(opts, opt); -} - -static inline int fuse_opt_add_opt_escaped(char **opts, const char *opt) -{ - return fsp_fuse_opt_add_opt_escaped(opts, opt); + return fsp_fuse_opt_parse(args, data, opts, proc, + FSP_FUSE_MEMFN_V); } static inline int fuse_opt_add_arg(struct fuse_args *args, const char *arg) { - return fsp_fuse_opt_add_arg(args, arg); + return fsp_fuse_opt_add_arg(args, arg, + FSP_FUSE_MEMFN_V); } static inline int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg) { - return fsp_fuse_opt_insert_arg(args, pos, arg); + return fsp_fuse_opt_insert_arg(args, pos, arg, + FSP_FUSE_MEMFN_V); } static inline void fuse_opt_free_args(struct fuse_args *args) { - fsp_fuse_opt_free_args(args); + fsp_fuse_opt_free_args(args, + FSP_FUSE_MEMFN_V); +} + +static inline int fuse_opt_add_opt(char **opts, const char *opt) +{ + return fsp_fuse_opt_add_opt(opts, opt, + FSP_FUSE_MEMFN_V); +} + +static inline int fuse_opt_add_opt_escaped(char **opts, const char *opt) +{ + return fsp_fuse_opt_add_opt_escaped(opts, opt, + FSP_FUSE_MEMFN_V); } static inline int fuse_opt_match(const struct fuse_opt opts[], const char *opt) { - return fsp_fuse_opt_match(opts, opt); + return fsp_fuse_opt_match(opts, opt, + FSP_FUSE_MEMFN_V); } #ifdef __cplusplus diff --git a/src/dll/fuse/fuse_opt.c b/src/dll/fuse/fuse_opt.c index 63e6a92c..96fba275 100644 --- a/src/dll/fuse/fuse_opt.c +++ b/src/dll/fuse/fuse_opt.c @@ -18,44 +18,304 @@ #include #include +#define fsp_fuse_opt_match_none ((const char *)0) /* no option match */ +#define fsp_fuse_opt_match_exact ((const char *)1) /* exact option match */ +#define fsp_fuse_opt_match_next ((const char *)2) /* option match, value is next arg */ + +static void fsp_fuse_opt_match_templ( + const char *templ, const char **pspec, + const char **parg, const char *argend) +{ + const char *p, *q; + + *pspec = 0; + + for (p = templ, q = *parg;; p++, q++) + if ('\0' == *q || (0 != argend && q >= argend)) + { + if ('\0' == *p) + *parg = fsp_fuse_opt_match_exact; + else if (' ' == *p) + *pspec = p + 1, *parg = fsp_fuse_opt_match_next; + else + *parg = fsp_fuse_opt_match_none; + break; + } + else if ('=' == *p) + { + if (*q == *p) + *pspec = p + 1, *parg = q + 1; + else + *parg = fsp_fuse_opt_match_none; + break; + } + else if (' ' == *p) + { + *pspec = p + 1, *parg = q; + break; + } + else if (*q != *p) + { + *parg = fsp_fuse_opt_match_none; + break; + } +} + +static const struct fuse_opt *fsp_fuse_opt_find( + const struct fuse_opt opts[], const char **pspec, + const char **parg, const char *argend) +{ + const struct fuse_opt *opt; + const char *arg; + + for (opt = opts; 0 != opt->templ; opt++) + { + arg = *parg; + fsp_fuse_opt_match_templ(opt->templ, pspec, &arg, argend); + if (fsp_fuse_opt_match_none != arg) + { + *parg = arg; + return opt; + } + } + + return 0; +} + +static int fsp_fuse_opt_process_arg(const struct fuse_opt *opt, + fuse_opt_proc_t proc, void *data, + const char *arg, + struct fuse_args *outargs) +{ + return 0; +} + +static int fsp_fuse_opt_parse_arg(const struct fuse_opt opts[], + fuse_opt_proc_t proc, void *data, + const char *arg0, const char *argend, const char *arg1, + struct fuse_args *outargs) +{ + const struct fuse_opt *opt; + const char *arg, *spec; + + arg = arg0; + opt = opts; + while (0 != (opt = fsp_fuse_opt_find(opt, &spec, &arg, argend))) + { + if (fsp_fuse_opt_match_exact == arg) + { + arg = 0; + } + else if (fsp_fuse_opt_match_next == arg) + { + if (0 == arg1) + return -1; /* missing argument for option */ + arg = arg1; + } + + if (-1 == fsp_fuse_opt_process_arg(opt, proc, data, arg, outargs)) + return -1; + + arg = arg0; + opt++; + } + + return 0; +} + +static int fsp_fuse_opt_proc0(void *data, const char *arg, int key, + struct fuse_args *outargs) +{ + return 1; +} + FSP_FUSE_API int fsp_fuse_opt_parse(struct fuse_args *args, void *data, - const struct fuse_opt opts[], fuse_opt_proc_t proc) + const struct fuse_opt opts[], fuse_opt_proc_t proc, + FSP_FUSE_MEMFN_P) { - // !!!: NEEDIMPL + static struct fuse_args args0 = FUSE_ARGS_INIT(0, 0); + static struct fuse_opt opts0[1] = { FUSE_OPT_END }; + struct fuse_args outargs = FUSE_ARGS_INIT(0, 0); + const char *arg, *argend; + int dashdash = 0; + + if (0 == args) + args = &args0; + if (0 == opts) + opts = opts0; + if (0 == proc) + proc = fsp_fuse_opt_proc0; + + for (int argi = 0; args->argc > argi; argi++) + { + arg = args->argv[argi]; + if ('-' == arg[0] && !dashdash) + { + switch (arg[1]) + { + case 'o': + if ('\0' == arg[2]) + { + if (args->argc <= argi + 1) + goto fail; /* missing argument for option "-o" */ + arg = args->argv[++argi]; + } + else + arg += 2; + for (argend = arg;; argend++) + { + if ('\0' == *argend || ',' == *argend) + { + if (-1 == fsp_fuse_opt_parse_arg(opts, proc, data, + arg, argend, 0, &outargs)) + goto fail; + } + else if ('\\' == *argend && '\0' != argend[1]) + argend++; + } + break; + case '-': + if ('\0' == arg[2]) + { + dashdash = 1; + break; + } + /* fall through */ + default: + if (-1 == fsp_fuse_opt_parse_arg(opts, proc, data, + arg, 0, args->argv[argi + 1], &outargs)) + goto fail; + break; + } + } + else + { + } + } + + return 0; + +fail: + return -1; +} + +FSP_FUSE_API int fsp_fuse_opt_add_arg(struct fuse_args *args, const char *arg, + FSP_FUSE_MEMFN_P) +{ + return fsp_fuse_opt_insert_arg(args, args->argc, arg, FSP_FUSE_MEMFN_A); +} + +FSP_FUSE_API int fsp_fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg, + FSP_FUSE_MEMFN_P) +{ + char **argv; + int argsize; + + if (0 == args) + return -1; + if (!args->allocated && 0 != args->argv) + return -1; + if (0 > pos || pos > args->argc) + return -1; + + argv = memalloc((args->argc + 2) * sizeof(char *)); + if (0 == argv) + return -1; + argsize = lstrlenA(arg) + 1; + argv[pos] = memalloc(argsize); + if (0 == argv[pos]) + { + memfree(argv); + return -1; + } + + memcpy(argv[pos], arg, argsize); + memcpy(argv, args->argv, pos); + memcpy(argv + pos + 1, args->argv + pos, args->argc - pos); + + memfree(args->argv); + + args->argc++; + args->argv = argv; + argv[args->argc] = 0; + return 0; } -FSP_FUSE_API int fsp_fuse_opt_add_opt(char **opts, const char *opt) +FSP_FUSE_API void fsp_fuse_opt_free_args(struct fuse_args *args, + FSP_FUSE_MEMFN_P) { - // !!!: NEEDIMPL + if (0 == args) + return; + + if (args->allocated && 0 != args->argv) + { + for (int argi = 0; args->argc > argi; argi++) + memfree(args->argv[argi]); + + memfree(args->argv); + } + + args->argc = 0; + args->argv = 0; + args->allocated = 0; +} + +static int fsp_fuse_opt_add_opt_internal(char **opts, const char *opt, int escaped, + FSP_FUSE_MEMFN_P) +{ + size_t optsize, optlen; + char *newopts; + const char *p; + + optsize = 0 != *opts ? lstrlenA(*opts) + 1 : 0; + for (p = opt, optlen = 0; *p; p++, optlen++) + if (escaped && (',' == *p || '\\' == *p)) + optlen++; + + newopts = memalloc(optsize + optlen + 1); + if (0 == newopts) + return -1; + memfree(*opts); + *opts = newopts; + + if (0 != optsize) + { + memcpy(newopts, *opts, optsize - 1); + newopts[optsize - 1] = ','; + newopts += optsize; + } + + for (p = opt; *p; p++, newopts++) + { + if (escaped && (',' == *p || '\\' == *p)) + *newopts++ = '\\'; + *newopts = *p; + } + return 0; } -FSP_FUSE_API int fsp_fuse_opt_add_opt_escaped(char **opts, const char *opt) +FSP_FUSE_API int fsp_fuse_opt_add_opt(char **opts, const char *opt, + FSP_FUSE_MEMFN_P) { - // !!!: NEEDIMPL - return 0; + return fsp_fuse_opt_add_opt_internal(opts, opt, 0, + FSP_FUSE_MEMFN_A); } -FSP_FUSE_API int fsp_fuse_opt_add_arg(struct fuse_args *args, const char *arg) +FSP_FUSE_API int fsp_fuse_opt_add_opt_escaped(char **opts, const char *opt, + FSP_FUSE_MEMFN_P) { - // !!!: NEEDIMPL - return 0; + return fsp_fuse_opt_add_opt_internal(opts, opt, 1, + FSP_FUSE_MEMFN_A); } -FSP_FUSE_API int fsp_fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg) +FSP_FUSE_API int fsp_fuse_opt_match(const struct fuse_opt opts[], const char *arg, + FSP_FUSE_MEMFN_P) { - // !!!: NEEDIMPL - return 0; -} + if (0 == opts) + return 0; -FSP_FUSE_API void fsp_fuse_opt_free_args(struct fuse_args *args) -{ - // !!!: NEEDIMPL -} - -FSP_FUSE_API int fsp_fuse_opt_match(const struct fuse_opt opts[], const char *opt) -{ - // !!!: NEEDIMPL - return 0; + const char *spec; + return fsp_fuse_opt_find(opts, &spec, &arg, 0) ? 1 : 0; }