diff options
Diffstat (limited to 'lib/argv_split.c')
-rw-r--r-- | lib/argv_split.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/lib/argv_split.c b/lib/argv_split.c new file mode 100644 index 000000000000..4096ed42f490 --- /dev/null +++ b/lib/argv_split.c | |||
@@ -0,0 +1,105 @@ | |||
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); | ||