diff options
-rw-r--r-- | src/misc.c | 265 | ||||
-rw-r--r-- | src/misc.h | 25 |
2 files changed, 240 insertions, 50 deletions
@@ -24,6 +24,34 @@ #include <stdlib.h> #include <string.h> #include <assert.h> +#include "arena.h" + +static char *arena_strdup(struct arena *a, const char *s) +{ + size_t n = strlen(s) + 1; + char *p = (char *)arena_malloc(a, n); + if (!p) { + fprintf(stderr, "bindfs: arena allocation failed\n"); + abort(); + } + memcpy(p, s, n); + return p; +} + +/* Konkateniert zwei Strings in der Arena: out = s1 + s2 */ +static char *arena_strcat2(struct arena *a, const char *s1, const char *s2) +{ + size_t n1 = strlen(s1); + size_t n2 = strlen(s2); + char *p = (char *)arena_malloc(a, n1 + n2 + 1); + if (!p) { + fprintf(stderr, "bindfs: arena allocation failed\n"); + abort(); + } + memcpy(p, s1, n1); + memcpy(p + n1, s2, n2 + 1); + return p; +} int count_chars(const char *s, char ch) { @@ -220,55 +248,212 @@ static void merge_o_args( } } -void filter_o_opts( - bool (*keep)(const char* opt), - int orig_argc, - const char * const *orig_argv, - int *new_argc, - char ***new_argv, - struct arena* arena -) +char *strtok_escape_r(char *str, const char *delim, char escape, char **saveptr) { - int argc = orig_argc; - char **argv = dup_argv(argc, orig_argv, arena); + char *r, *w, *start; - merge_o_args(&argc, argv, arena); + if (str == NULL) { + if (saveptr == NULL || *saveptr == NULL) return NULL; + str = *saveptr; + } - for (int i = 0; i < argc; i++) { - char *arg = argv[i]; - if (strncmp(arg, "-o", 2) == 0) { - char *filtered = arena_malloc(arena, strlen(arg) + 1); - char *filtered_end = filtered; - - const char *tok = strtok(arg + 2, ","); - while (tok != NULL) { - size_t tok_len = strlen(tok); - if ((*keep)(tok)) { - if (filtered_end == filtered) { - *(filtered_end++) = '-'; - *(filtered_end++) = 'o'; - } else { - *(filtered_end++) = ','; - } - memcpy(filtered_end, tok, tok_len + 1); - filtered_end += tok_len; // We'll overwrite the null terminator if we append more. - } - tok = strtok(NULL, ","); - } + r = str; + while (*r && strchr(delim, *r) != NULL) { + r++; + } + + if (*r == '\0') { + *saveptr = r; + return NULL; + } - if (filtered != filtered_end) { - argv[i] = filtered; + start = w = r; + + for (;;) + { + if (*r == '\0') { + *w = '\0'; + *saveptr = r; + return start; + } + + if (*r == escape) { + if (r[1] != '\0') { + char c = r[1]; + *w++ = c; + r += 2; + continue; } else { - for (int j = i; j < argc - 1; ++j) { - argv[j] = argv[j + 1]; - } - --argc; + r++; + continue; + } + } + + if (strchr(delim, *r) != NULL) { + *w = '\0'; + r++; + while (*r && strchr(delim, *r) != NULL) r++; + *saveptr = r; + return start; + } + + *w++ = *r++; + } +} + +char *strtok_escape(char *str, const char *delim, char escape) +{ + static char *save; + return strtok_escape_r(str, delim, escape, &save); +} + +char *strtok_escape_preserve_r(char *str, const char *delim, char escape, char **saveptr) +{ + char *s = str ? str : *saveptr; + char *r = s; + char *w = s; + + if (s == NULL) return NULL; + + /* führende Delimiter überspringen (kollabieren) */ + while (*r && strchr(delim, *r)) r++; + if (!*r) { *saveptr = r; return NULL; } + + for (;;) { + if (*r == '\0') { + *w = '\0'; + *saveptr = r; + return s; + } + if (*r == escape) { + if (r[1] == '\0') { + /* dangling escape: '\' wörtlich übernehmen */ + *w++ = *r++; + *w = '\0'; + *saveptr = r; + return s; + } + /* WICHTIG: Backslash BEHALTEN und nächstes Zeichen wörtlich kopieren */ + *w++ = escape; + *w++ = r[1]; + r += 2; + continue; + } + if (strchr(delim, *r)) { + /* Ende des Tokens; nachfolgende Delimiter kollabieren */ + *w = '\0'; + do { r++; } while (*r && strchr(delim, *r)); + *saveptr = r; + return s; + } + *w++ = *r++; + } +} + +char *strtok_escape_preserve(char *str, const char *delim, char escape) +{ + static char *saveptr_pres; + return strtok_escape_preserve_r(str, delim, escape, &saveptr_pres); +} + +int join_strings(char **res, const char *a, const char *b, const char *sep) +{ + size_t la = a ? strlen(a) : 0; + size_t lb = b ? strlen(b) : 0; + size_t ls = sep ? strlen(sep) : 0; + size_t old = *res ? strlen(*res) : 0; + size_t extra = (old ? ls : 0) + la + lb; + + char *d = realloc(*res, old + extra + 1); + if (!d) return -1; + + char *p = d + old; + if (old && sep) { memcpy(p, sep, ls); p += ls; } + if (a) { memcpy(p, a, la); p += la; } + if (b) { memcpy(p, b, lb); p += lb; } + *p = '\0'; + *res = d; + return 0; +} + +int add_option(char ***argv, int *argc, const char *opt) +{ + char **newv = realloc(*argv, sizeof(char*) * (*argc + 2)); + if (!newv) return -1; + newv[*argc] = strdup(opt); + if (!newv[*argc]) return -1; + (*argc)++; + newv[*argc] = NULL; + *argv = newv; + return 0; +} + +int add_options(char ***argv, int *argc, const char *o1, const char *o2) +{ + if (add_option(argv, argc, o1) == -1) return -1; + if (o2) return add_option(argv, argc, o2); + return 0; +} + +void remove_option(char **argv, int *argc, int idx) +{ + free(argv[idx]); + for (int i = idx; i + 1 < *argc; ++i) argv[i] = argv[i+1]; + (*argc)--; + argv[*argc] = NULL; +} + +void filter_o_opts(bool (*keep_option)(const char *opt), + int argc_in, + const char * const *argv_in, + int *argc_out, + char ***argv_out, + struct arena *arena) +{ + (void)keep_option; /* aktuell nicht genutzt; API bleibt stabil */ + + /* Worst-case: gleich viele Ausgabeargumente wie Eingabe. + (Bei Zusammenziehen von "-o" "<wert>" werden es sogar weniger.) */ + char **outv = (char **)arena_malloc(arena, + (size_t)(argc_in > 0 ? argc_in : 1) * sizeof(char *)); + if (!outv) { + fprintf(stderr, "bindfs: arena allocation failed\n"); + abort(); + } + + int outc = 0; + + for (int i = 0; i < argc_in; ++i) { + const char *arg = argv_in[i]; + + if (arg[0] == '-' && arg[1] == 'o') { + /* Fall A: "-o<wert>" -> unverändert übernehmen */ + if (arg[2] != '\0') { + outv[outc++] = arena_strdup(arena, arg); + continue; } + + /* Fall B: separates "-o" + "<wert>" zusammenziehen */ + if (i + 1 < argc_in) { + const char *val = argv_in[i + 1]; + char *merged = arena_strcat2(arena, "-o", val); + outv[outc++] = merged; + ++i; /* den Wert haben wir verbraucht */ + continue; + } + + /* Edge case: nacktes "-o" am Ende – übernimm es trotzdem, + libfuse meldet später einen sinnvollen Fehler. */ + outv[outc++] = arena_strdup(arena, arg); + continue; } + + /* alle anderen Argumente 1:1 durchreichen */ + outv[outc++] = arena_strdup(arena, arg); } - *new_argc = argc; - *new_argv = argv; + *argc_out = outc; + *argv_out = outv; } void grow_array_impl(void **array, int *capacity, int member_size) @@ -35,6 +35,8 @@ int count_substrs(const char *s, const char *sub); an end character is reached. */ char *strdup_until(const char *s, const char *endchars); +char *strdup_or_die(const char *s); + /* Like sprintf but writes to an automatically malloc'ed buffer. */ char *sprintf_new(const char *format, ...); @@ -57,16 +59,19 @@ const char *my_dirname(char *path); Assumes 'strlen(prefix) == prefix_len'. */ bool path_starts_with(const char *path, const char* prefix, size_t prefix_len); -/* Filters arguments in comma-separated lists prefixed by '-o'. - * Allocates 'new_argv' and its strings, as well as some temporary data, into 'arena'. */ -void filter_o_opts( - bool (*keep)(const char* opt), - int argc, - const char * const *argv, - int *new_argc, - char ***new_argv, - struct arena *arena -); +char *strtok_escape_r(char *str, const char *delim, char escape, char **saveptr); +char *strtok_escape(char *str, const char *delim, char escape); + +/* NEW: like above, but preserves the backslash in the token ("\," stays two chars) */ +char *strtok_escape_preserve_r(char *str, const char *delim, char escape, char **saveptr); +char *strtok_escape_preserve(char *str, const char *delim, char escape); + +void filter_o_opts(bool (*keep_option)(const char *opt), + int argc_in, + const char * const *argv_in, + int *argc_out, + char ***argv_out, + struct arena *arena); /* Reallocs `*array` (may be NULL) to be at least one larger than `*capacity` (may be 0) and stores the new capacity |