1 #include "util.h" 2 #include "string.h" 3 4 #define K 1024LL 5 /* 6 * perf_atoll() 7 * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB") 8 * and return its numeric value 9 */ 10 s64 perf_atoll(const char *str) 11 { 12 unsigned int i; 13 s64 length = -1, unit = 1; 14 15 if (!isdigit(str[0])) 16 goto out_err; 17 18 for (i = 1; i < strlen(str); i++) { 19 switch (str[i]) { 20 case 'B': 21 case 'b': 22 break; 23 case 'K': 24 if (str[i + 1] != 'B') 25 goto out_err; 26 else 27 goto kilo; 28 case 'k': 29 if (str[i + 1] != 'b') 30 goto out_err; 31 kilo: 32 unit = K; 33 break; 34 case 'M': 35 if (str[i + 1] != 'B') 36 goto out_err; 37 else 38 goto mega; 39 case 'm': 40 if (str[i + 1] != 'b') 41 goto out_err; 42 mega: 43 unit = K * K; 44 break; 45 case 'G': 46 if (str[i + 1] != 'B') 47 goto out_err; 48 else 49 goto giga; 50 case 'g': 51 if (str[i + 1] != 'b') 52 goto out_err; 53 giga: 54 unit = K * K * K; 55 break; 56 case 'T': 57 if (str[i + 1] != 'B') 58 goto out_err; 59 else 60 goto tera; 61 case 't': 62 if (str[i + 1] != 'b') 63 goto out_err; 64 tera: 65 unit = K * K * K * K; 66 break; 67 case '\0': /* only specified figures */ 68 unit = 1; 69 break; 70 default: 71 if (!isdigit(str[i])) 72 goto out_err; 73 break; 74 } 75 } 76 77 length = atoll(str) * unit; 78 goto out; 79 80 out_err: 81 length = -1; 82 out: 83 return length; 84 } 85 86 /* 87 * Helper function for splitting a string into an argv-like array. 88 * originally copied from lib/argv_split.c 89 */ 90 static const char *skip_sep(const char *cp) 91 { 92 while (*cp && isspace(*cp)) 93 cp++; 94 95 return cp; 96 } 97 98 static const char *skip_arg(const char *cp) 99 { 100 while (*cp && !isspace(*cp)) 101 cp++; 102 103 return cp; 104 } 105 106 static int count_argc(const char *str) 107 { 108 int count = 0; 109 110 while (*str) { 111 str = skip_sep(str); 112 if (*str) { 113 count++; 114 str = skip_arg(str); 115 } 116 } 117 118 return count; 119 } 120 121 /** 122 * argv_free - free an argv 123 * @argv - the argument vector to be freed 124 * 125 * Frees an argv and the strings it points to. 126 */ 127 void argv_free(char **argv) 128 { 129 char **p; 130 for (p = argv; *p; p++) 131 free(*p); 132 133 free(argv); 134 } 135 136 /** 137 * argv_split - split a string at whitespace, returning an argv 138 * @str: the string to be split 139 * @argcp: returned argument count 140 * 141 * Returns an array of pointers to strings which are split out from 142 * @str. This is performed by strictly splitting on white-space; no 143 * quote processing is performed. Multiple whitespace characters are 144 * considered to be a single argument separator. The returned array 145 * is always NULL-terminated. Returns NULL on memory allocation 146 * failure. 147 */ 148 char **argv_split(const char *str, int *argcp) 149 { 150 int argc = count_argc(str); 151 char **argv = zalloc(sizeof(*argv) * (argc+1)); 152 char **argvp; 153 154 if (argv == NULL) 155 goto out; 156 157 if (argcp) 158 *argcp = argc; 159 160 argvp = argv; 161 162 while (*str) { 163 str = skip_sep(str); 164 165 if (*str) { 166 const char *p = str; 167 char *t; 168 169 str = skip_arg(str); 170 171 t = strndup(p, str-p); 172 if (t == NULL) 173 goto fail; 174 *argvp++ = t; 175 } 176 } 177 *argvp = NULL; 178 179 out: 180 return argv; 181 182 fail: 183 argv_free(argv); 184 return NULL; 185 } 186 187 /* Character class matching */ 188 static bool __match_charclass(const char *pat, char c, const char **npat) 189 { 190 bool complement = false, ret = true; 191 192 if (*pat == '!') { 193 complement = true; 194 pat++; 195 } 196 if (*pat++ == c) /* First character is special */ 197 goto end; 198 199 while (*pat && *pat != ']') { /* Matching */ 200 if (*pat == '-' && *(pat + 1) != ']') { /* Range */ 201 if (*(pat - 1) <= c && c <= *(pat + 1)) 202 goto end; 203 if (*(pat - 1) > *(pat + 1)) 204 goto error; 205 pat += 2; 206 } else if (*pat++ == c) 207 goto end; 208 } 209 if (!*pat) 210 goto error; 211 ret = false; 212 213 end: 214 while (*pat && *pat != ']') /* Searching closing */ 215 pat++; 216 if (!*pat) 217 goto error; 218 *npat = pat + 1; 219 return complement ? !ret : ret; 220 221 error: 222 return false; 223 } 224 225 /* Glob/lazy pattern matching */ 226 static bool __match_glob(const char *str, const char *pat, bool ignore_space) 227 { 228 while (*str && *pat && *pat != '*') { 229 if (ignore_space) { 230 /* Ignore spaces for lazy matching */ 231 if (isspace(*str)) { 232 str++; 233 continue; 234 } 235 if (isspace(*pat)) { 236 pat++; 237 continue; 238 } 239 } 240 if (*pat == '?') { /* Matches any single character */ 241 str++; 242 pat++; 243 continue; 244 } else if (*pat == '[') /* Character classes/Ranges */ 245 if (__match_charclass(pat + 1, *str, &pat)) { 246 str++; 247 continue; 248 } else 249 return false; 250 else if (*pat == '\\') /* Escaped char match as normal char */ 251 pat++; 252 if (*str++ != *pat++) 253 return false; 254 } 255 /* Check wild card */ 256 if (*pat == '*') { 257 while (*pat == '*') 258 pat++; 259 if (!*pat) /* Tail wild card matches all */ 260 return true; 261 while (*str) 262 if (__match_glob(str++, pat, ignore_space)) 263 return true; 264 } 265 return !*str && !*pat; 266 } 267 268 /** 269 * strglobmatch - glob expression pattern matching 270 * @str: the target string to match 271 * @pat: the pattern string to match 272 * 273 * This returns true if the @str matches @pat. @pat can includes wildcards 274 * ('*','?') and character classes ([CHARS], complementation and ranges are 275 * also supported). Also, this supports escape character ('\') to use special 276 * characters as normal character. 277 * 278 * Note: if @pat syntax is broken, this always returns false. 279 */ 280 bool strglobmatch(const char *str, const char *pat) 281 { 282 return __match_glob(str, pat, false); 283 } 284 285 /** 286 * strlazymatch - matching pattern strings lazily with glob pattern 287 * @str: the target string to match 288 * @pat: the pattern string to match 289 * 290 * This is similar to strglobmatch, except this ignores spaces in 291 * the target string. 292 */ 293 bool strlazymatch(const char *str, const char *pat) 294 { 295 return __match_glob(str, pat, true); 296 } 297