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