xref: /openbmc/linux/tools/lib/argv_split.c (revision 0898782247ae533d1f4e47a06bc5d4870931b284)
1*9c10548cSArnaldo Carvalho de Melo // SPDX-License-Identifier: GPL-2.0
2*9c10548cSArnaldo Carvalho de Melo /*
3*9c10548cSArnaldo Carvalho de Melo  * Helper function for splitting a string into an argv-like array.
4*9c10548cSArnaldo Carvalho de Melo  */
5*9c10548cSArnaldo Carvalho de Melo 
6*9c10548cSArnaldo Carvalho de Melo #include <stdlib.h>
7*9c10548cSArnaldo Carvalho de Melo #include <linux/kernel.h>
8*9c10548cSArnaldo Carvalho de Melo #include <linux/ctype.h>
9*9c10548cSArnaldo Carvalho de Melo #include <linux/string.h>
10*9c10548cSArnaldo Carvalho de Melo 
skip_arg(const char * cp)11*9c10548cSArnaldo Carvalho de Melo static const char *skip_arg(const char *cp)
12*9c10548cSArnaldo Carvalho de Melo {
13*9c10548cSArnaldo Carvalho de Melo 	while (*cp && !isspace(*cp))
14*9c10548cSArnaldo Carvalho de Melo 		cp++;
15*9c10548cSArnaldo Carvalho de Melo 
16*9c10548cSArnaldo Carvalho de Melo 	return cp;
17*9c10548cSArnaldo Carvalho de Melo }
18*9c10548cSArnaldo Carvalho de Melo 
count_argc(const char * str)19*9c10548cSArnaldo Carvalho de Melo static int count_argc(const char *str)
20*9c10548cSArnaldo Carvalho de Melo {
21*9c10548cSArnaldo Carvalho de Melo 	int count = 0;
22*9c10548cSArnaldo Carvalho de Melo 
23*9c10548cSArnaldo Carvalho de Melo 	while (*str) {
24*9c10548cSArnaldo Carvalho de Melo 		str = skip_spaces(str);
25*9c10548cSArnaldo Carvalho de Melo 		if (*str) {
26*9c10548cSArnaldo Carvalho de Melo 			count++;
27*9c10548cSArnaldo Carvalho de Melo 			str = skip_arg(str);
28*9c10548cSArnaldo Carvalho de Melo 		}
29*9c10548cSArnaldo Carvalho de Melo 	}
30*9c10548cSArnaldo Carvalho de Melo 
31*9c10548cSArnaldo Carvalho de Melo 	return count;
32*9c10548cSArnaldo Carvalho de Melo }
33*9c10548cSArnaldo Carvalho de Melo 
34*9c10548cSArnaldo Carvalho de Melo /**
35*9c10548cSArnaldo Carvalho de Melo  * argv_free - free an argv
36*9c10548cSArnaldo Carvalho de Melo  * @argv - the argument vector to be freed
37*9c10548cSArnaldo Carvalho de Melo  *
38*9c10548cSArnaldo Carvalho de Melo  * Frees an argv and the strings it points to.
39*9c10548cSArnaldo Carvalho de Melo  */
argv_free(char ** argv)40*9c10548cSArnaldo Carvalho de Melo void argv_free(char **argv)
41*9c10548cSArnaldo Carvalho de Melo {
42*9c10548cSArnaldo Carvalho de Melo 	char **p;
43*9c10548cSArnaldo Carvalho de Melo 	for (p = argv; *p; p++) {
44*9c10548cSArnaldo Carvalho de Melo 		free(*p);
45*9c10548cSArnaldo Carvalho de Melo 		*p = NULL;
46*9c10548cSArnaldo Carvalho de Melo 	}
47*9c10548cSArnaldo Carvalho de Melo 
48*9c10548cSArnaldo Carvalho de Melo 	free(argv);
49*9c10548cSArnaldo Carvalho de Melo }
50*9c10548cSArnaldo Carvalho de Melo 
51*9c10548cSArnaldo Carvalho de Melo /**
52*9c10548cSArnaldo Carvalho de Melo  * argv_split - split a string at whitespace, returning an argv
53*9c10548cSArnaldo Carvalho de Melo  * @str: the string to be split
54*9c10548cSArnaldo Carvalho de Melo  * @argcp: returned argument count
55*9c10548cSArnaldo Carvalho de Melo  *
56*9c10548cSArnaldo Carvalho de Melo  * Returns an array of pointers to strings which are split out from
57*9c10548cSArnaldo Carvalho de Melo  * @str.  This is performed by strictly splitting on white-space; no
58*9c10548cSArnaldo Carvalho de Melo  * quote processing is performed.  Multiple whitespace characters are
59*9c10548cSArnaldo Carvalho de Melo  * considered to be a single argument separator.  The returned array
60*9c10548cSArnaldo Carvalho de Melo  * is always NULL-terminated.  Returns NULL on memory allocation
61*9c10548cSArnaldo Carvalho de Melo  * failure.
62*9c10548cSArnaldo Carvalho de Melo  */
argv_split(const char * str,int * argcp)63*9c10548cSArnaldo Carvalho de Melo char **argv_split(const char *str, int *argcp)
64*9c10548cSArnaldo Carvalho de Melo {
65*9c10548cSArnaldo Carvalho de Melo 	int argc = count_argc(str);
66*9c10548cSArnaldo Carvalho de Melo 	char **argv = calloc(argc + 1, sizeof(*argv));
67*9c10548cSArnaldo Carvalho de Melo 	char **argvp;
68*9c10548cSArnaldo Carvalho de Melo 
69*9c10548cSArnaldo Carvalho de Melo 	if (argv == NULL)
70*9c10548cSArnaldo Carvalho de Melo 		goto out;
71*9c10548cSArnaldo Carvalho de Melo 
72*9c10548cSArnaldo Carvalho de Melo 	if (argcp)
73*9c10548cSArnaldo Carvalho de Melo 		*argcp = argc;
74*9c10548cSArnaldo Carvalho de Melo 
75*9c10548cSArnaldo Carvalho de Melo 	argvp = argv;
76*9c10548cSArnaldo Carvalho de Melo 
77*9c10548cSArnaldo Carvalho de Melo 	while (*str) {
78*9c10548cSArnaldo Carvalho de Melo 		str = skip_spaces(str);
79*9c10548cSArnaldo Carvalho de Melo 
80*9c10548cSArnaldo Carvalho de Melo 		if (*str) {
81*9c10548cSArnaldo Carvalho de Melo 			const char *p = str;
82*9c10548cSArnaldo Carvalho de Melo 			char *t;
83*9c10548cSArnaldo Carvalho de Melo 
84*9c10548cSArnaldo Carvalho de Melo 			str = skip_arg(str);
85*9c10548cSArnaldo Carvalho de Melo 
86*9c10548cSArnaldo Carvalho de Melo 			t = strndup(p, str-p);
87*9c10548cSArnaldo Carvalho de Melo 			if (t == NULL)
88*9c10548cSArnaldo Carvalho de Melo 				goto fail;
89*9c10548cSArnaldo Carvalho de Melo 			*argvp++ = t;
90*9c10548cSArnaldo Carvalho de Melo 		}
91*9c10548cSArnaldo Carvalho de Melo 	}
92*9c10548cSArnaldo Carvalho de Melo 	*argvp = NULL;
93*9c10548cSArnaldo Carvalho de Melo 
94*9c10548cSArnaldo Carvalho de Melo out:
95*9c10548cSArnaldo Carvalho de Melo 	return argv;
96*9c10548cSArnaldo Carvalho de Melo 
97*9c10548cSArnaldo Carvalho de Melo fail:
98*9c10548cSArnaldo Carvalho de Melo 	argv_free(argv);
99*9c10548cSArnaldo Carvalho de Melo 	return NULL;
100*9c10548cSArnaldo Carvalho de Melo }
101