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