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