162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Helper function for splitting a string into an argv-like array. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <stdlib.h> 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/ctype.h> 962306a36Sopenharmony_ci#include <linux/string.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic const char *skip_arg(const char *cp) 1262306a36Sopenharmony_ci{ 1362306a36Sopenharmony_ci while (*cp && !isspace(*cp)) 1462306a36Sopenharmony_ci cp++; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci return cp; 1762306a36Sopenharmony_ci} 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int count_argc(const char *str) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci int count = 0; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci while (*str) { 2462306a36Sopenharmony_ci str = skip_spaces(str); 2562306a36Sopenharmony_ci if (*str) { 2662306a36Sopenharmony_ci count++; 2762306a36Sopenharmony_ci str = skip_arg(str); 2862306a36Sopenharmony_ci } 2962306a36Sopenharmony_ci } 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci return count; 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/** 3562306a36Sopenharmony_ci * argv_free - free an argv 3662306a36Sopenharmony_ci * @argv - the argument vector to be freed 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * Frees an argv and the strings it points to. 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_civoid argv_free(char **argv) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci char **p; 4362306a36Sopenharmony_ci for (p = argv; *p; p++) { 4462306a36Sopenharmony_ci free(*p); 4562306a36Sopenharmony_ci *p = NULL; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci free(argv); 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/** 5262306a36Sopenharmony_ci * argv_split - split a string at whitespace, returning an argv 5362306a36Sopenharmony_ci * @str: the string to be split 5462306a36Sopenharmony_ci * @argcp: returned argument count 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * Returns an array of pointers to strings which are split out from 5762306a36Sopenharmony_ci * @str. This is performed by strictly splitting on white-space; no 5862306a36Sopenharmony_ci * quote processing is performed. Multiple whitespace characters are 5962306a36Sopenharmony_ci * considered to be a single argument separator. The returned array 6062306a36Sopenharmony_ci * is always NULL-terminated. Returns NULL on memory allocation 6162306a36Sopenharmony_ci * failure. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_cichar **argv_split(const char *str, int *argcp) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci int argc = count_argc(str); 6662306a36Sopenharmony_ci char **argv = calloc(argc + 1, sizeof(*argv)); 6762306a36Sopenharmony_ci char **argvp; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (argv == NULL) 7062306a36Sopenharmony_ci goto out; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (argcp) 7362306a36Sopenharmony_ci *argcp = argc; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci argvp = argv; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci while (*str) { 7862306a36Sopenharmony_ci str = skip_spaces(str); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (*str) { 8162306a36Sopenharmony_ci const char *p = str; 8262306a36Sopenharmony_ci char *t; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci str = skip_arg(str); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci t = strndup(p, str-p); 8762306a36Sopenharmony_ci if (t == NULL) 8862306a36Sopenharmony_ci goto fail; 8962306a36Sopenharmony_ci *argvp++ = t; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci *argvp = NULL; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ciout: 9562306a36Sopenharmony_ci return argv; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cifail: 9862306a36Sopenharmony_ci argv_free(argv); 9962306a36Sopenharmony_ci return NULL; 10062306a36Sopenharmony_ci} 101