xref: /kernel/linux/linux-6.6/tools/lib/argv_split.c (revision 62306a36)
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