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