diff options
Diffstat (limited to 'common')
| -rw-r--r-- | common/stringop.c | 56 | 
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;  }  | 
