X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=util%2Fstring-util.c;h=9e2f728fc6750c586f3effed3ecac5673ea980e0;hb=029790d3ff6e9fccfed2214efac777b8c438e318;hp=7a71049a098d70d7788e13098ac6c28c3d33f6e3;hpb=25cf5f5dc45cac42f15643f6df09b46d51d7b5ec;p=notmuch diff --git a/util/string-util.c b/util/string-util.c index 7a71049a..9e2f728f 100644 --- a/util/string-util.c +++ b/util/string-util.c @@ -22,6 +22,7 @@ #include "string-util.h" #include "talloc.h" +#include #include char * @@ -36,6 +37,28 @@ strtok_len (char *s, const char *delim, size_t *len) return *len ? s : NULL; } +char * +sanitize_string (const void *ctx, const char *str) +{ + char *out, *loop; + + if (! str) + return NULL; + + out = talloc_strdup (ctx, str); + if (! out) + return NULL; + + for (loop = out; *loop; loop++) { + if (*loop == '\t' || *loop == '\n') + *loop = ' '; + else if ((unsigned char)(*loop) < 32) + *loop = '?'; + } + + return out; +} + static int is_unquoted_terminator (unsigned char c) { @@ -107,3 +130,84 @@ make_boolean_term (void *ctx, const char *prefix, const char *term, return 0; } + +static const char* +skip_space (const char *str) +{ + while (*str && isspace ((unsigned char) *str)) + ++str; + return str; +} + +int +parse_boolean_term (void *ctx, const char *str, + char **prefix_out, char **term_out) +{ + int err = EINVAL; + *prefix_out = *term_out = NULL; + + /* Parse prefix */ + str = skip_space (str); + const char *pos = strchr (str, ':'); + if (! pos || pos == str) + goto FAIL; + *prefix_out = talloc_strndup (ctx, str, pos - str); + if (! *prefix_out) { + err = ENOMEM; + goto FAIL; + } + ++pos; + + /* Implement de-quoting compatible with make_boolean_term. */ + if (*pos == '"') { + char *out = talloc_array (ctx, char, strlen (pos)); + int closed = 0; + if (! out) { + err = ENOMEM; + goto FAIL; + } + *term_out = out; + /* Skip the opening quote, find the closing quote, and + * un-double doubled internal quotes. */ + for (++pos; *pos; ) { + if (*pos == '"') { + ++pos; + if (*pos != '"') { + /* Found the closing quote. */ + closed = 1; + pos = skip_space (pos); + break; + } + } + *out++ = *pos++; + } + /* Did the term terminate without a closing quote or is there + * trailing text after the closing quote? */ + if (!closed || *pos) + goto FAIL; + *out = '\0'; + } else { + const char *start = pos; + /* Check for text after the boolean term. */ + while (! is_unquoted_terminator (*pos)) + ++pos; + if (*skip_space (pos)) { + err = EINVAL; + goto FAIL; + } + /* No trailing text; dup the string so the caller can free + * it. */ + *term_out = talloc_strndup (ctx, start, pos - start); + if (! *term_out) { + err = ENOMEM; + goto FAIL; + } + } + return 0; + + FAIL: + talloc_free (*prefix_out); + talloc_free (*term_out); + errno = err; + return -1; +}