From 4beec8f055fd3b0cc4ef618cce8b52c58dd0ee08 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Wed, 6 Sep 2017 17:40:06 +0300 Subject: Add implementation --- libpkgconf/argvsplit.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 libpkgconf/argvsplit.c (limited to 'libpkgconf/argvsplit.c') diff --git a/libpkgconf/argvsplit.c b/libpkgconf/argvsplit.c new file mode 100644 index 0000000..85f7f57 --- /dev/null +++ b/libpkgconf/argvsplit.c @@ -0,0 +1,156 @@ +/* + * argvsplit.c + * argv_split() routine + * + * Copyright (c) 2012, 2017 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include + +/* + * !doc + * + * libpkgconf `argvsplit` module + * ============================= + * + * This is a lowlevel module which provides parsing of strings into argument vectors, + * similar to what a shell would do. + */ + +/* + * !doc + * + * .. c:function:: void pkgconf_argv_free(char **argv) + * + * Frees an argument vector. + * + * :param char** argv: The argument vector to free. + * :return: nothing + */ +void +pkgconf_argv_free(char **argv) +{ + free(argv[0]); + free(argv); +} + +/* + * !doc + * + * .. c:function:: int pkgconf_argv_split(const char *src, int *argc, char ***argv) + * + * Splits a string into an argument vector. + * + * :param char* src: The string to split. + * :param int* argc: A pointer to an integer to store the argument count. + * :param char*** argv: A pointer to a pointer for an argument vector. + * :return: 0 on success, -1 on error. + * :rtype: int + */ +int +pkgconf_argv_split(const char *src, int *argc, char ***argv) +{ + char *buf = malloc(strlen(src) + 1); + const char *src_iter; + char *dst_iter; + int argc_count = 0; + int argv_size = 5; + char quote = 0; + bool escaped = false; + + src_iter = src; + dst_iter = buf; + + memset(buf, 0, strlen(src) + 1); + + *argv = calloc(sizeof (void *), argv_size); + (*argv)[argc_count] = dst_iter; + + while (*src_iter) + { + if (escaped) + { + /* POSIX: only \CHAR is special inside a double quote if CHAR is {$, `, ", \, newline}. */ + if (quote == '\"') + { + if (!(*src_iter == '$' || *src_iter == '`' || *src_iter == '"' || *src_iter == '\\')) + *dst_iter++ = '\\'; + + *dst_iter++ = *src_iter; + } + else + { + if (isspace((unsigned int) *src_iter)) + *dst_iter++ = '\\'; + + *dst_iter++ = *src_iter; + } + + escaped = false; + } + else if (quote) + { + if (*src_iter == quote) + quote = 0; + else if (*src_iter == '\\') + escaped = true; + else + *dst_iter++ = *src_iter; + } + else if (isspace((unsigned int)*src_iter)) + { + if ((*argv)[argc_count] != NULL) + { + argc_count++, dst_iter++; + + if (argc_count == argv_size) + { + argv_size += 5; + *argv = realloc(*argv, sizeof(void *) * argv_size); + } + + (*argv)[argc_count] = dst_iter; + } + } + else switch(*src_iter) + { + case '\\': + escaped = true; + break; + + case '\"': + case '\'': + quote = *src_iter; + break; + + default: + *dst_iter++ = *src_iter; + break; + } + + src_iter++; + } + + if (escaped || quote) + { + free(*argv); + free(buf); + return -1; + } + + if (strlen((*argv)[argc_count])) + { + argc_count++; + } + + *argc = argc_count; + return 0; +} -- cgit v1.1