diff options
Diffstat (limited to 'src/util.c')
-rw-r--r-- | src/util.c | 112 |
1 files changed, 112 insertions, 0 deletions
@@ -128,3 +128,115 @@ void util_format_addr(const util_sockaddr *s, char *dst) { break; } } + + + +typedef vec_t(char) util_buf; /* Abusing vec as a string library */ + +static int unquote_double(const char *orig, util_buf *buf) { + const char *str = orig; + str++; + while(*str) { + switch(*str) { + case '"': return str-orig+1; + case '\\': + str++; + switch(*str) { + case '\0': + return -1; + case '"': + case '\\': + case '`': + case '$': + case '\n': + vec_append(*buf, *str); + break; + default: + vec_append(*buf, '\\'); + str--; /* Didn't mean to escape this char */ + } + break; + default: + vec_append(*buf, *str); + } + str++; + } + return -1; +} + + +static int unquote_single(const char *orig, util_buf *buf) { + const char *str = orig; + str++; + while(*str) { + if(*str == '\'') + return str-orig+1; + vec_append(*buf, *str); + str++; + } + return -1; +} + + +void util_free_argv(util_argv *arg) { + size_t i; + for(i=0; i<arg->n; i++) + free(arg->a[i]); + vec_clear(*arg); +} + + +int util_parse_argv(const char *str, util_argv *arg) { + memset(arg, 0, sizeof(util_argv)); + util_buf buf = {0}; + int n; + + while(*str) { + switch(*str) { + case ' ': + case '\t': + case '\n': + if(buf.a) { + vec_append(buf, 0); + vec_append(*arg, buf.a); + memset(&buf, 0, sizeof(buf)); + } else + vec_clear(buf); + break; + case '\\': + str++; + switch(*str) { + case '\n': break; + case '\0': + free(buf.a); + util_free_argv(arg); + return -1; + default: + vec_append(buf, *str); + } + break; + case '"': + case '\'': + if(!buf.a) /* Make sure we create a token, even if it's an empty string */ + vec_grow(buf); + n = (*str == '"' ? unquote_double : unquote_single)(str, &buf); + if(n < 0) { + free(buf.a); + util_free_argv(arg); + return -1; + } + str += n-1; + break; + default: + vec_append(buf, *str); + } + str++; + } + + if(buf.a) { + vec_append(buf, 0); + vec_append(*arg, buf.a); + } + vec_append(*arg, NULL); + return 0; +} |