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