root/lib/argv_split.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. count_argc
  2. argv_free
  3. argv_split

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Helper function for splitting a string into an argv-like array.
   4  */
   5 
   6 #include <linux/kernel.h>
   7 #include <linux/ctype.h>
   8 #include <linux/string.h>
   9 #include <linux/slab.h>
  10 #include <linux/export.h>
  11 
  12 static int count_argc(const char *str)
  13 {
  14         int count = 0;
  15         bool was_space;
  16 
  17         for (was_space = true; *str; str++) {
  18                 if (isspace(*str)) {
  19                         was_space = true;
  20                 } else if (was_space) {
  21                         was_space = false;
  22                         count++;
  23                 }
  24         }
  25 
  26         return count;
  27 }
  28 
  29 /**
  30  * argv_free - free an argv
  31  * @argv - the argument vector to be freed
  32  *
  33  * Frees an argv and the strings it points to.
  34  */
  35 void argv_free(char **argv)
  36 {
  37         argv--;
  38         kfree(argv[0]);
  39         kfree(argv);
  40 }
  41 EXPORT_SYMBOL(argv_free);
  42 
  43 /**
  44  * argv_split - split a string at whitespace, returning an argv
  45  * @gfp: the GFP mask used to allocate memory
  46  * @str: the string to be split
  47  * @argcp: returned argument count
  48  *
  49  * Returns an array of pointers to strings which are split out from
  50  * @str.  This is performed by strictly splitting on white-space; no
  51  * quote processing is performed.  Multiple whitespace characters are
  52  * considered to be a single argument separator.  The returned array
  53  * is always NULL-terminated.  Returns NULL on memory allocation
  54  * failure.
  55  *
  56  * The source string at `str' may be undergoing concurrent alteration via
  57  * userspace sysctl activity (at least).  The argv_split() implementation
  58  * attempts to handle this gracefully by taking a local copy to work on.
  59  */
  60 char **argv_split(gfp_t gfp, const char *str, int *argcp)
  61 {
  62         char *argv_str;
  63         bool was_space;
  64         char **argv, **argv_ret;
  65         int argc;
  66 
  67         argv_str = kstrndup(str, KMALLOC_MAX_SIZE - 1, gfp);
  68         if (!argv_str)
  69                 return NULL;
  70 
  71         argc = count_argc(argv_str);
  72         argv = kmalloc_array(argc + 2, sizeof(*argv), gfp);
  73         if (!argv) {
  74                 kfree(argv_str);
  75                 return NULL;
  76         }
  77 
  78         *argv = argv_str;
  79         argv_ret = ++argv;
  80         for (was_space = true; *argv_str; argv_str++) {
  81                 if (isspace(*argv_str)) {
  82                         was_space = true;
  83                         *argv_str = 0;
  84                 } else if (was_space) {
  85                         was_space = false;
  86                         *argv++ = argv_str;
  87                 }
  88         }
  89         *argv = NULL;
  90 
  91         if (argcp)
  92                 *argcp = argc;
  93         return argv_ret;
  94 }
  95 EXPORT_SYMBOL(argv_split);

/* [<][>][^][v][top][bottom][index][help] */