uspace_rtapi_string.c
1 // Copyright 2005-2014, various authors 2 // 3 // This program is free software; you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation; either version 2 of the License, or 6 // (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU General Public License for more details. 12 // 13 // You should have received a copy of the GNU General Public License 14 // along with this program; if not, write to the Free Software 15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 17 // 18 // This file contains some handy string parsing functions lifted from Linux 19 // 2.6.27.44, from the files mm/util.c and lib/argv_split.c. 20 // 21 // It gets compiled into the hostmot2 driver if the kernel does not provide 22 // its own versions of these functions: argv_split(), argv_free(), and 23 // kstrndup(). 24 // 25 26 27 #include <rtapi_ctype.h> 28 #include <rtapi_slab.h> 29 #include <rtapi_string.h> 30 31 /** 32 * rtapi_kstrndup - allocate space for and copy an existing string 33 * @s: the string to duplicate 34 * @max: read at most @max chars from @s 35 * @gfp: the GFP mask used in the rtapi_kmalloc() call when allocating memory 36 */ 37 char *rtapi_kstrndup(const char *s, size_t max, rtapi_gfp_t gfp) 38 { 39 size_t len; 40 char *buf; 41 42 if (!s) 43 return NULL; 44 45 len = strnlen(s, max); 46 buf = rtapi_kmalloc(len+1, gfp); 47 if (buf) { 48 memcpy(buf, s, len); 49 buf[len] = '\0'; 50 } 51 return buf; 52 } 53 54 55 /* 56 * Helper function for splitting a string into an argv-like array. 57 */ 58 59 static const char *skip_sep(const char *cp) 60 { 61 while (*cp && isspace(*cp)) 62 cp++; 63 64 return cp; 65 } 66 67 static const char *skip_arg(const char *cp) 68 { 69 while (*cp && !isspace(*cp)) 70 cp++; 71 72 return cp; 73 } 74 75 static int count_argc(const char *str) 76 { 77 int count = 0; 78 79 while (*str) { 80 str = skip_sep(str); 81 if (*str) { 82 count++; 83 str = skip_arg(str); 84 } 85 } 86 87 return count; 88 } 89 90 /** 91 * rtapi_argv_free - free an argv 92 * @argv - the argument vector to be freed 93 * 94 * Frees an argv and the strings it points to. 95 */ 96 void rtapi_argv_free(char **argv) 97 { 98 char **p; 99 for (p = argv; *p; p++) 100 rtapi_kfree(*p); 101 102 rtapi_kfree(argv); 103 } 104 105 /** 106 * rtapi_argv_split - split a string at whitespace, returning an argv 107 * @gfp: the GFP mask used to allocate memory 108 * @str: the string to be split 109 * @argcp: returned argument count 110 * 111 * Returns an array of pointers to strings which are split out from 112 * @str. This is performed by strictly splitting on white-space; no 113 * quote processing is performed. Multiple whitespace characters are 114 * considered to be a single argument separator. The returned array 115 * is always NULL-terminated. Returns NULL on memory allocation 116 * failure. 117 */ 118 char **rtapi_argv_split(rtapi_gfp_t gfp, const char *str, int *argcp) 119 { 120 int argc = count_argc(str); 121 char **argv = rtapi_kzalloc(sizeof(*argv) * (argc+1), gfp); 122 char **argvp; 123 124 if (argv == NULL) 125 goto out; 126 127 if (argcp) 128 *argcp = argc; 129 130 argvp = argv; 131 132 while (*str) { 133 str = skip_sep(str); 134 135 if (*str) { 136 const char *p = str; 137 char *t; 138 139 str = skip_arg(str); 140 141 t = rtapi_kstrndup(p, str-p, gfp); 142 if (t == NULL) 143 goto fail; 144 *argvp++ = t; 145 } 146 } 147 *argvp = NULL; 148 149 out: 150 return argv; 151 152 fail: 153 rtapi_argv_free(argv); 154 return NULL; 155 } 156 157 EXPORT_SYMBOL(rtapi_kstrndup); 158 EXPORT_SYMBOL(rtapi_argv_split); 159 EXPORT_SYMBOL(rtapi_argv_free);