aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/stringop.c56
1 files changed, 40 insertions, 16 deletions
diff --git a/common/stringop.c b/common/stringop.c
index dea152cc..ac7df296 100644
--- a/common/stringop.c
+++ b/common/stringop.c
@@ -251,37 +251,61 @@ char *join_args(char **argv, int argc) {
return res;
}
-char *argsep(char **stringp, const char *delim) {
+static inline char *argsep_next_interesting(const char *src, const char *delim) {
+ char *special = strpbrk(src, "\"'\\");
+ char *next_delim = strpbrk(src, delim);
+ if (!special) {
+ return next_delim;
+ }
+ if (!next_delim) {
+ return special;
+ }
+ return (next_delim < special) ? next_delim : special;
+}
+
+char *argsep(char **stringp, const char *delim, char *matched) {
char *start = *stringp;
char *end = start;
bool in_string = false;
bool in_char = false;
bool escaped = false;
- while (1) {
- if (*end == '"' && !in_char && !escaped) {
+ char *interesting = NULL;
+
+ while ((interesting = argsep_next_interesting(end, delim))) {
+ if (escaped && interesting != end) {
+ escaped = false;
+ }
+ if (*interesting == '"' && !in_char && !escaped) {
in_string = !in_string;
- } else if (*end == '\'' && !in_string && !escaped) {
+ end = interesting + 1;
+ } else if (*interesting == '\'' && !in_string && !escaped) {
in_char = !in_char;
- } else if (*end == '\\') {
+ end = interesting + 1;
+ } else if (*interesting == '\\') {
escaped = !escaped;
- } else if (*end == '\0') {
- *stringp = NULL;
- break;
- } else if (!in_string && !in_char && !escaped && strchr(delim, *end)) {
+ end = interesting + 1;
+ } else if (!in_string && !in_char && !escaped) {
+ // We must have matched a separator
+ end = interesting;
+ if (matched) {
+ *matched = *end;
+ }
if (end - start) {
*(end++) = 0;
- *stringp = end + strspn(end, delim);;
- if (!**stringp) *stringp = NULL;
+ *stringp = end;
break;
} else {
- ++start;
- end = start;
+ end = ++start;
}
+ } else {
+ end++;
}
- if (*end != '\\') {
- escaped = false;
+ }
+ if (!interesting) {
+ *stringp = NULL;
+ if (matched) {
+ *matched = '\0';
}
- ++end;
}
return start;
}