diff options
Diffstat (limited to 'lib/fuse_opt.c')
-rw-r--r-- | lib/fuse_opt.c | 100 |
1 files changed, 68 insertions, 32 deletions
diff --git a/lib/fuse_opt.c b/lib/fuse_opt.c index 3bacf74..a2999f3 100644 --- a/lib/fuse_opt.c +++ b/lib/fuse_opt.c @@ -19,6 +19,7 @@ #include <stdlib.h> #include <string.h> #include <assert.h> +#include <stdbool.h> struct fuse_opt_context { void *data; @@ -292,46 +293,81 @@ static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso) return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso); } -static int process_real_option_group(struct fuse_opt_context *ctx, char *opts) +/* ---- Neue robuste -o-Aufspaltung mit Escape/Quotes -------------------- */ + +static void unescape_commas(char *s) { - char *s = opts; - char *d = s; - int end = 0; - - while (!end) { - if (*s == '\0') - end = 1; - if (*s == ',' || end) { - int res; + char *w = s, *r = s; + while (*r) { + if (r[0] == '\\' && r[1] == ',') { *w++ = ','; r += 2; continue; } + if (r[0] == '\\' && r[1] == '\\'){ *w++ = '\\'; r += 2; continue; } + *w++ = *r++; + } + *w = '\0'; +} - *d = '\0'; - res = process_gopt(ctx, opts, 1); - if (res == -1) - return -1; - d = opts; - } else { - if (s[0] == '\\' && s[1] != '\0') { - s++; - if (s[0] >= '0' && s[0] <= '3' && - s[1] >= '0' && s[1] <= '7' && - s[2] >= '0' && s[2] <= '7') { - *d++ = (s[0] - '0') * 0100 + - (s[1] - '0') * 0010 + - (s[2] - '0'); - s += 2; - } else { - *d++ = *s; - } - } else { - *d++ = *s; +static void foreach_o_subopt(const char *oarg, + void (*cb)(const char *opt, void *user), + void *user) +{ + const char *p = oarg, *start = oarg; + bool esc = false, in_sq = false, in_dq = false; + + for (; *p; ++p) { + if (esc) { esc = false; continue; } + if (*p == '\\') { esc = true; continue; } + if (*p == '\'' && !in_dq) { in_sq = !in_sq; continue; } + if (*p == '\"' && !in_sq) { in_dq = !in_dq; continue; } + + /* Nur ein nicht gequotetes und nicht ge-escaptes Komma trennt */ + if (*p == ',' && !in_sq && !in_dq) { + size_t len = (size_t)(p - start); + if (len) { + char *tmp = (char*)malloc(len + 1); + memcpy(tmp, start, len); + tmp[len] = '\0'; + unescape_commas(tmp); + cb(tmp, user); + free(tmp); } + start = p + 1; } - s++; } - return 0; + if (p > start) { + size_t len = (size_t)(p - start); + char *tmp = (char*)malloc(len + 1); + memcpy(tmp, start, len); + tmp[len] = '\0'; + unescape_commas(tmp); + cb(tmp, user); + free(tmp); + } } +struct oproc_ctx { + struct fuse_opt_context *ctx; + int rc; +}; + +static void process_o_subopt_cb(const char *opt, void *user) +{ + struct oproc_ctx *st = (struct oproc_ctx*)user; + if (st->rc != 0) return; /* vorheriger Fehler? */ + if (opt[0] == '\0') return; /* leere Teil-Option ignorieren */ + st->rc = process_gopt(st->ctx, opt, 1); +} + +static int process_real_option_group(struct fuse_opt_context *ctx, char *opts) +{ + struct oproc_ctx st = { ctx, 0 }; + /* Robustes Splitting: beachtet \, sowie '...' und "..." */ + foreach_o_subopt(opts, process_o_subopt_cb, &st); + return st.rc; +} + +/* ---------------------------------------------------------------------- */ + static int process_option_group(struct fuse_opt_context *ctx, const char *opts) { int res; |