diff options
Diffstat (limited to 'src/libudev')
-rw-r--r-- | src/libudev/util.c | 100 | ||||
-rw-r--r-- | src/libudev/util.h | 8 |
2 files changed, 47 insertions, 61 deletions
diff --git a/src/libudev/util.c b/src/libudev/util.c index 116d723a0f..5ff767b6a7 100644 --- a/src/libudev/util.c +++ b/src/libudev/util.c @@ -263,79 +263,63 @@ int safe_atolli(const char *s, long long int *ret_lli) { return 0; } +static size_t strcspn_escaped(const char *s, const char *reject) { + bool escaped = false; + size_t n; + + for (n=0; s[n]; n++) { + if (escaped) + escaped = false; + else if (s[n] == '\\') + escaped = true; + else if (strchr(reject, s[n])) + break; + } + /* if s ends in \, return index of previous char */ + return n - escaped; +} + /* Split a string into words. */ -char *split(const char *c, size_t *l, const char *separator, char **state) { - char *current; +const char* split(const char **state, size_t *l, const char *separator, bool quoted) { + const char *current; - current = *state ? *state : (char*) c; + current = *state; - if (!*current || *c == 0) + if (!*current) { + assert(**state == '\0'); return NULL; + } current += strspn(current, separator); - *l = strcspn(current, separator); - *state = current+*l; - - return (char*) current; -} - -/* Split a string into words, but consider strings enclosed in '' and - * "" as words even if they include spaces. */ -char *split_quoted(const char *c, size_t *l, char **state) { - char *current, *e; - bool escaped = false; - - current = *state ? *state : (char*) c; - - if (!*current || *c == 0) + if (!*current) { + *state = current; return NULL; + } - current += strspn(current, WHITESPACE); - - if (*current == '\'') { - current ++; + if (quoted && strchr("\'\"", *current)) { + char quotechars[2] = {*current, '\0'}; - for (e = current; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - else if (*e == '\'') - break; + *l = strcspn_escaped(current + 1, quotechars); + if (current[*l + 1] == '\0' || + (current[*l + 2] && !strchr(separator, current[*l + 2]))) { + /* right quote missing or garbage at the end*/ + *state = current; + return NULL; } - - *l = e-current; - *state = *e == 0 ? e : e+1; - } else if (*current == '\"') { - current ++; - - for (e = current; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - else if (*e == '\"') - break; - } - - *l = e-current; - *state = *e == 0 ? e : e+1; + assert(current[*l + 1] == quotechars[0]); + *state = current++ + *l + 2; + } else if (quoted) { + *l = strcspn_escaped(current, separator); + *state = current + *l; } else { - for (e = current; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - else if (strchr(WHITESPACE, *e)) - break; - } - *l = e-current; - *state = e; + *l = strcspn(current, separator); + *state = current + *l; } - return (char*) current; + return current; } + char *truncate_nl(char *s) { assert(s); diff --git a/src/libudev/util.h b/src/libudev/util.h index a38e8e61c5..15a11cc537 100644 --- a/src/libudev/util.h +++ b/src/libudev/util.h @@ -134,11 +134,13 @@ int safe_atoi(const char *s, int *ret_i); int safe_atollu(const char *s, unsigned long long *ret_u); int safe_atolli(const char *s, long long int *ret_i); -char *split(const char *c, size_t *l, const char *separator, char **state); -char *split_quoted(const char *c, size_t *l, char **state); +const char* split(const char **state, size_t *l, const char *separator, bool quoted); #define FOREACH_WORD_QUOTED(word, length, s, state) \ - for ((state) = NULL, (word) = split_quoted((s), &(length), &(state)); (word); (word) = split_quoted((s), &(length), &(state))) + _FOREACH_WORD(word, length, s, WHITESPACE, true, state) + +#define _FOREACH_WORD(word, length, s, separator, quoted, state) \ + for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) char *strappend(const char *s, const char *suffix); char *strnappend(const char *s, const char *suffix, size_t length); |