aboutsummaryrefslogtreecommitdiff
path: root/sam.c
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2016-08-07 11:24:24 +0200
committerMarc André Tanner <mat@brain-dump.org>2016-08-07 11:24:24 +0200
commita2f2691e0ff4a0fe5a15acb167c388f167da6e1f (patch)
treefed6305747d5c3903a245dfca432fda53f7c13d8 /sam.c
parent5c2cee9461ef1199f2e80ddcda699595b11fdf08 (diff)
downloadvis-a2f2691e0ff4a0fe5a15acb167c388f167da6e1f.tar.gz
vis-a2f2691e0ff4a0fe5a15acb167c388f167da6e1f.tar.xz
sam: improve quoted argument parsing
Handling of unbalanced quotes could probably still be improved. Closes #344
Diffstat (limited to 'sam.c')
-rw-r--r--sam.c61
1 files changed, 28 insertions, 33 deletions
diff --git a/sam.c b/sam.c
index f3b4242..173aa50 100644
--- a/sam.c
+++ b/sam.c
@@ -213,16 +213,13 @@ static void skip_spaces(const char **s) {
(*s)++;
}
-static char *parse_delimited_text(const char **s) {
+static char *parse_until(const char **s, const char *until, const char *escchars) {
Buffer buf;
- bool escaped = false;
- char delim = **s;
-
- if (!delim)
- return NULL;
buffer_init(&buf);
+ size_t len = strlen(until);
+ bool escaped = false;
- for ((*s)++; **s && (**s != delim || escaped); (*s)++) {
+ for (; **s && (!memchr(until, **s, len) || escaped); (*s)++) {
if (!escaped && **s == '\\') {
escaped = true;
continue;
@@ -232,7 +229,7 @@ static char *parse_delimited_text(const char **s) {
if (escaped) {
escaped = false;
- switch (**s) {
+ switch (c) {
case '\n':
continue;
case 'n':
@@ -241,11 +238,17 @@ static char *parse_delimited_text(const char **s) {
case 't':
c = '\t';
break;
+ case '\\':
+ break;
default:
- if (**s != '\\' && **s != delim)
+ {
+ bool delim = memchr(until, c, len);
+ bool esc = escchars && memchr(escchars, c, strlen(escchars));
+ if (!delim && !esc)
buffer_append(&buf, "\\", 1);
break;
}
+ }
}
if (!buffer_append(&buf, &c, 1)) {
@@ -254,17 +257,23 @@ static char *parse_delimited_text(const char **s) {
}
}
- if (**s == delim)
- (*s)++;
-
- if (!buffer_append(&buf, "\0", 1)) {
- buffer_release(&buf);
- return NULL;
- }
+ if (buffer_length(&buf))
+ buffer_append(&buf, "\0", 1);
return buf.data;
}
+static char *parse_delimited_text(const char **s) {
+ char delim[2] = { **s, '\0' };
+ if (!delim[0])
+ return NULL;
+ (*s)++;
+ char *text = parse_until(s, delim, NULL);
+ if (**s == delim[0])
+ (*s)++;
+ return text;
+}
+
static char *parse_text(const char **s) {
skip_spaces(s);
if (**s != '\n')
@@ -287,30 +296,16 @@ static char *parse_text(const char **s) {
return buf.data;
}
-static char *parse_until(const char **s, const char *until) {
- Buffer buf;
- buffer_init(&buf);
- size_t len = strlen(until);
-
- while (**s && !memchr(until, **s, len))
- buffer_append(&buf, (*s)++, 1);
-
- if (buffer_length(&buf))
- buffer_append(&buf, "\0", 1);
-
- return buf.data;
-}
-
static char *parse_shellcmd(const char **s) {
skip_spaces(s);
- return parse_until(s, "\n");
+ return parse_until(s, "\n", NULL);
}
static char *parse_filename(const char **s) {
skip_spaces(s);
if (**s == '"' || **s == '\'')
return parse_delimited_text(s);
- return parse_until(s, "\n");
+ return parse_until(s, "\n", "\'\"");
}
static void parse_argv(const char **s, const char *argv[], size_t maxarg) {
@@ -319,7 +314,7 @@ static void parse_argv(const char **s, const char *argv[], size_t maxarg) {
if (**s == '"' || **s == '\'')
argv[i] = parse_delimited_text(s);
else
- argv[i] = parse_until(s, " \t\n");
+ argv[i] = parse_until(s, " \t\n", "\'\"");
}
}