summaryrefslogtreecommitdiff
path: root/src/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.c')
-rw-r--r--src/util.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/util.c b/src/util.c
index a2ab156..0e3485c 100644
--- a/src/util.c
+++ b/src/util.c
@@ -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;
+}