diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/include/util.h | 18 | ||||
| -rw-r--r-- | lib/src/split_argv.c | 109 | 
2 files changed, 75 insertions, 52 deletions
| diff --git a/lib/include/util.h b/lib/include/util.h index c13b942..d824b22 100644 --- a/lib/include/util.h +++ b/lib/include/util.h @@ -100,13 +100,25 @@ int rdline(rdline_t *t);  int unescape(char *src);  /* +	Replace spaces in 'str' with null bytes. Tread strings (started and +	terminated with double-quotes which can be escaped) as a single block. +	Such strings are run through unescap(). All elements are tightly +	packed together and the function returns the number of consecutive +	argument strings that are now inside 'str'. + +	Returns a negative value if unescape() fails, a string is not +	termianted or two such strings touch each other without a white +	space in between. +*/ +int pack_argv(char *str); + +/*  	Split a space seperated string into a sequence of null-terminated  	strings. Return a NULL terminated array of strings pointing to the  	start of each sub string. -	If a double quote is encountered, the entire string up to to the next, -	unescaped double quite is interpreted as a single sub string and -	fed through the unescape function. +	It basically runs pack_argv on 'str' and then constructs the argv +	vector from that, with each entry pointing into 'str'.  	The returned array must be freed with free().  */ diff --git a/lib/src/split_argv.c b/lib/src/split_argv.c index 9beec5c..b95720d 100644 --- a/lib/src/split_argv.c +++ b/lib/src/split_argv.c @@ -16,78 +16,89 @@   * along with this program.  If not, see <https://www.gnu.org/licenses/>.   */  #include <stdlib.h> +#include <string.h>  #include <ctype.h>  #include <errno.h> +#include <stdio.h>  #include "util.h" -char **split_argv(char *str) +int pack_argv(char *str)  { -	size_t i = 0, cap = 0, new_cap; -	char **argv = NULL, **new; -	char *ptr; +	char *dst, *start; +	int count = 0; -	ptr = str; +	dst = str;  	for (;;) { -		if (*ptr == ' ') { -			++ptr; -			continue; -		} - -		if (i == cap) { -			new_cap = cap ? cap * 2 : 16; -			new = realloc(argv, sizeof(argv[0]) * new_cap); - -			if (new == NULL) { -				free(argv); -				errno = ENOMEM; -				return NULL; -			} - -			cap = new_cap; -			argv = new; -		} +		while (*str == ' ') +			++str; -		if (*ptr == '\0') { -			argv[i++] = NULL; +		if (*str == '\0')  			break; -		} - -		argv[i++] = ptr; -		if (*ptr == '"') { -			++ptr; -			while (*ptr != '\0' && *ptr != '"') { -				if (ptr[0] == '\\' && ptr[1] != '\0') -					++ptr; +		if (*str == '"') { +			start = dst; +			*(dst++) = *(str++); -				++ptr; +			while (*str != '"') { +				if (*str == '\0') +					goto fail_str; +				if (str[0] == '\\' && str[1] != '\0') +					*(dst++) = *(str++); +				*(dst++) = *(str++);  			} -			if (*ptr == '"') -				++ptr; +			*(dst++) = *(str++); -			if (*ptr == ' ') { -				*(ptr++) = '\0'; -			} else if (*ptr != '\0') { +			if (*str != ' ' && *str != '\0')  				goto fail_str; -			} +			if (*str == ' ') +				++str; -			if (unescape(argv[i - 1])) +			*(dst++) = '\0'; + +			if (unescape(start))  				goto fail_str; -		} else { -			while (*ptr != '\0' && *ptr != ' ') -				++ptr; -			if (*ptr == ' ') -				*(ptr++) = '\0'; +			dst = start + strlen(start) + 1; +		} else { +			while (*str != '\0' && *str != ' ') +				*(dst++) = *(str++); +			if (*str == ' ') { +				++str; +				*(dst++) = '\0'; +			}  		} + +		++count;  	} -	return argv; +	*dst = '\0'; +	return count;  fail_str: -	free(argv);  	errno = EINVAL; -	return NULL; +	return -1; +} + +char **split_argv(char *str) +{ +	char **argv = NULL; +	int i, count; + +	count = pack_argv(str); +	if (count <= 0) +		return NULL; + +	argv = malloc(sizeof(argv[0]) * (count + 1)); +	if (argv == NULL) +		return NULL; + +	for (i = 0; i < count; ++i) { +		argv[i] = str; +		str += strlen(str) + 1; +	} + +	argv[i] = NULL; +	return argv;  } | 
