18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Helper function for splitting a string into an argv-like array. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <stdlib.h> 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/ctype.h> 98c2ecf20Sopenharmony_ci#include <linux/string.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistatic const char *skip_arg(const char *cp) 128c2ecf20Sopenharmony_ci{ 138c2ecf20Sopenharmony_ci while (*cp && !isspace(*cp)) 148c2ecf20Sopenharmony_ci cp++; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci return cp; 178c2ecf20Sopenharmony_ci} 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int count_argc(const char *str) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci int count = 0; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci while (*str) { 248c2ecf20Sopenharmony_ci str = skip_spaces(str); 258c2ecf20Sopenharmony_ci if (*str) { 268c2ecf20Sopenharmony_ci count++; 278c2ecf20Sopenharmony_ci str = skip_arg(str); 288c2ecf20Sopenharmony_ci } 298c2ecf20Sopenharmony_ci } 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci return count; 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/** 358c2ecf20Sopenharmony_ci * argv_free - free an argv 368c2ecf20Sopenharmony_ci * @argv - the argument vector to be freed 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * Frees an argv and the strings it points to. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_civoid argv_free(char **argv) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci char **p; 438c2ecf20Sopenharmony_ci for (p = argv; *p; p++) { 448c2ecf20Sopenharmony_ci free(*p); 458c2ecf20Sopenharmony_ci *p = NULL; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci free(argv); 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/** 528c2ecf20Sopenharmony_ci * argv_split - split a string at whitespace, returning an argv 538c2ecf20Sopenharmony_ci * @str: the string to be split 548c2ecf20Sopenharmony_ci * @argcp: returned argument count 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * Returns an array of pointers to strings which are split out from 578c2ecf20Sopenharmony_ci * @str. This is performed by strictly splitting on white-space; no 588c2ecf20Sopenharmony_ci * quote processing is performed. Multiple whitespace characters are 598c2ecf20Sopenharmony_ci * considered to be a single argument separator. The returned array 608c2ecf20Sopenharmony_ci * is always NULL-terminated. Returns NULL on memory allocation 618c2ecf20Sopenharmony_ci * failure. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_cichar **argv_split(const char *str, int *argcp) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci int argc = count_argc(str); 668c2ecf20Sopenharmony_ci char **argv = calloc(argc + 1, sizeof(*argv)); 678c2ecf20Sopenharmony_ci char **argvp; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (argv == NULL) 708c2ecf20Sopenharmony_ci goto out; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (argcp) 738c2ecf20Sopenharmony_ci *argcp = argc; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci argvp = argv; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci while (*str) { 788c2ecf20Sopenharmony_ci str = skip_spaces(str); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (*str) { 818c2ecf20Sopenharmony_ci const char *p = str; 828c2ecf20Sopenharmony_ci char *t; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci str = skip_arg(str); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci t = strndup(p, str-p); 878c2ecf20Sopenharmony_ci if (t == NULL) 888c2ecf20Sopenharmony_ci goto fail; 898c2ecf20Sopenharmony_ci *argvp++ = t; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci *argvp = NULL; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ciout: 958c2ecf20Sopenharmony_ci return argv; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cifail: 988c2ecf20Sopenharmony_ci argv_free(argv); 998c2ecf20Sopenharmony_ci return NULL; 1008c2ecf20Sopenharmony_ci} 101