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