1 #include "util.h" 2 #include "linux/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 s64 length; 13 char *p; 14 char c; 15 16 if (!isdigit(str[0])) 17 goto out_err; 18 19 length = strtoll(str, &p, 10); 20 switch (c = *p++) { 21 case 'b': case 'B': 22 if (*p) 23 goto out_err; 24 25 __fallthrough; 26 case '\0': 27 return length; 28 default: 29 goto out_err; 30 /* two-letter suffices */ 31 case 'k': case 'K': 32 length <<= 10; 33 break; 34 case 'm': case 'M': 35 length <<= 20; 36 break; 37 case 'g': case 'G': 38 length <<= 30; 39 break; 40 case 't': case 'T': 41 length <<= 40; 42 break; 43 } 44 /* we want the cases to match */ 45 if (islower(c)) { 46 if (strcmp(p, "b") != 0) 47 goto out_err; 48 } else { 49 if (strcmp(p, "B") != 0) 50 goto out_err; 51 } 52 return length; 53 54 out_err: 55 return -1; 56 } 57 58 /* 59 * Helper function for splitting a string into an argv-like array. 60 * originally copied from lib/argv_split.c 61 */ 62 static const char *skip_sep(const char *cp) 63 { 64 while (*cp && isspace(*cp)) 65 cp++; 66 67 return cp; 68 } 69 70 static const char *skip_arg(const char *cp) 71 { 72 while (*cp && !isspace(*cp)) 73 cp++; 74 75 return cp; 76 } 77 78 static int count_argc(const char *str) 79 { 80 int count = 0; 81 82 while (*str) { 83 str = skip_sep(str); 84 if (*str) { 85 count++; 86 str = skip_arg(str); 87 } 88 } 89 90 return count; 91 } 92 93 /** 94 * argv_free - free an argv 95 * @argv - the argument vector to be freed 96 * 97 * Frees an argv and the strings it points to. 98 */ 99 void argv_free(char **argv) 100 { 101 char **p; 102 for (p = argv; *p; p++) 103 zfree(p); 104 105 free(argv); 106 } 107 108 /** 109 * argv_split - split a string at whitespace, returning an argv 110 * @str: the string to be split 111 * @argcp: returned argument count 112 * 113 * Returns an array of pointers to strings which are split out from 114 * @str. This is performed by strictly splitting on white-space; no 115 * quote processing is performed. Multiple whitespace characters are 116 * considered to be a single argument separator. The returned array 117 * is always NULL-terminated. Returns NULL on memory allocation 118 * failure. 119 */ 120 char **argv_split(const char *str, int *argcp) 121 { 122 int argc = count_argc(str); 123 char **argv = zalloc(sizeof(*argv) * (argc+1)); 124 char **argvp; 125 126 if (argv == NULL) 127 goto out; 128 129 if (argcp) 130 *argcp = argc; 131 132 argvp = argv; 133 134 while (*str) { 135 str = skip_sep(str); 136 137 if (*str) { 138 const char *p = str; 139 char *t; 140 141 str = skip_arg(str); 142 143 t = strndup(p, str-p); 144 if (t == NULL) 145 goto fail; 146 *argvp++ = t; 147 } 148 } 149 *argvp = NULL; 150 151 out: 152 return argv; 153 154 fail: 155 argv_free(argv); 156 return NULL; 157 } 158 159 /* Character class matching */ 160 static bool __match_charclass(const char *pat, char c, const char **npat) 161 { 162 bool complement = false, ret = true; 163 164 if (*pat == '!') { 165 complement = true; 166 pat++; 167 } 168 if (*pat++ == c) /* First character is special */ 169 goto end; 170 171 while (*pat && *pat != ']') { /* Matching */ 172 if (*pat == '-' && *(pat + 1) != ']') { /* Range */ 173 if (*(pat - 1) <= c && c <= *(pat + 1)) 174 goto end; 175 if (*(pat - 1) > *(pat + 1)) 176 goto error; 177 pat += 2; 178 } else if (*pat++ == c) 179 goto end; 180 } 181 if (!*pat) 182 goto error; 183 ret = false; 184 185 end: 186 while (*pat && *pat != ']') /* Searching closing */ 187 pat++; 188 if (!*pat) 189 goto error; 190 *npat = pat + 1; 191 return complement ? !ret : ret; 192 193 error: 194 return false; 195 } 196 197 /* Glob/lazy pattern matching */ 198 static bool __match_glob(const char *str, const char *pat, bool ignore_space, 199 bool case_ins) 200 { 201 while (*str && *pat && *pat != '*') { 202 if (ignore_space) { 203 /* Ignore spaces for lazy matching */ 204 if (isspace(*str)) { 205 str++; 206 continue; 207 } 208 if (isspace(*pat)) { 209 pat++; 210 continue; 211 } 212 } 213 if (*pat == '?') { /* Matches any single character */ 214 str++; 215 pat++; 216 continue; 217 } else if (*pat == '[') /* Character classes/Ranges */ 218 if (__match_charclass(pat + 1, *str, &pat)) { 219 str++; 220 continue; 221 } else 222 return false; 223 else if (*pat == '\\') /* Escaped char match as normal char */ 224 pat++; 225 if (case_ins) { 226 if (tolower(*str) != tolower(*pat)) 227 return false; 228 } else if (*str != *pat) 229 return false; 230 str++; 231 pat++; 232 } 233 /* Check wild card */ 234 if (*pat == '*') { 235 while (*pat == '*') 236 pat++; 237 if (!*pat) /* Tail wild card matches all */ 238 return true; 239 while (*str) 240 if (__match_glob(str++, pat, ignore_space, case_ins)) 241 return true; 242 } 243 return !*str && !*pat; 244 } 245 246 /** 247 * strglobmatch - glob expression pattern matching 248 * @str: the target string to match 249 * @pat: the pattern string to match 250 * 251 * This returns true if the @str matches @pat. @pat can includes wildcards 252 * ('*','?') and character classes ([CHARS], complementation and ranges are 253 * also supported). Also, this supports escape character ('\') to use special 254 * characters as normal character. 255 * 256 * Note: if @pat syntax is broken, this always returns false. 257 */ 258 bool strglobmatch(const char *str, const char *pat) 259 { 260 return __match_glob(str, pat, false, false); 261 } 262 263 bool strglobmatch_nocase(const char *str, const char *pat) 264 { 265 return __match_glob(str, pat, false, true); 266 } 267 268 /** 269 * strlazymatch - matching pattern strings lazily with glob pattern 270 * @str: the target string to match 271 * @pat: the pattern string to match 272 * 273 * This is similar to strglobmatch, except this ignores spaces in 274 * the target string. 275 */ 276 bool strlazymatch(const char *str, const char *pat) 277 { 278 return __match_glob(str, pat, true, false); 279 } 280 281 /** 282 * strtailcmp - Compare the tail of two strings 283 * @s1: 1st string to be compared 284 * @s2: 2nd string to be compared 285 * 286 * Return 0 if whole of either string is same as another's tail part. 287 */ 288 int strtailcmp(const char *s1, const char *s2) 289 { 290 int i1 = strlen(s1); 291 int i2 = strlen(s2); 292 while (--i1 >= 0 && --i2 >= 0) { 293 if (s1[i1] != s2[i2]) 294 return s1[i1] - s2[i2]; 295 } 296 return 0; 297 } 298 299 /** 300 * strxfrchar - Locate and replace character in @s 301 * @s: The string to be searched/changed. 302 * @from: Source character to be replaced. 303 * @to: Destination character. 304 * 305 * Return pointer to the changed string. 306 */ 307 char *strxfrchar(char *s, char from, char to) 308 { 309 char *p = s; 310 311 while ((p = strchr(p, from)) != NULL) 312 *p++ = to; 313 314 return s; 315 } 316 317 /** 318 * ltrim - Removes leading whitespace from @s. 319 * @s: The string to be stripped. 320 * 321 * Return pointer to the first non-whitespace character in @s. 322 */ 323 char *ltrim(char *s) 324 { 325 int len = strlen(s); 326 327 while (len && isspace(*s)) { 328 len--; 329 s++; 330 } 331 332 return s; 333 } 334 335 /** 336 * rtrim - Removes trailing whitespace from @s. 337 * @s: The string to be stripped. 338 * 339 * Note that the first trailing whitespace is replaced with a %NUL-terminator 340 * in the given string @s. Returns @s. 341 */ 342 char *rtrim(char *s) 343 { 344 size_t size = strlen(s); 345 char *end; 346 347 if (!size) 348 return s; 349 350 end = s + size - 1; 351 while (end >= s && isspace(*end)) 352 end--; 353 *(end + 1) = '\0'; 354 355 return s; 356 } 357 358 char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints) 359 { 360 /* 361 * FIXME: replace this with an expression using log10() when we 362 * find a suitable implementation, maybe the one in the dvb drivers... 363 * 364 * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators 365 */ 366 size_t size = nints * 28 + 1; /* \0 */ 367 size_t i, printed = 0; 368 char *expr = malloc(size); 369 370 if (expr) { 371 const char *or_and = "||", *eq_neq = "=="; 372 char *e = expr; 373 374 if (!in) { 375 or_and = "&&"; 376 eq_neq = "!="; 377 } 378 379 for (i = 0; i < nints; ++i) { 380 if (printed == size) 381 goto out_err_overflow; 382 383 if (i > 0) 384 printed += snprintf(e + printed, size - printed, " %s ", or_and); 385 printed += scnprintf(e + printed, size - printed, 386 "%s %s %d", var, eq_neq, ints[i]); 387 } 388 } 389 390 return expr; 391 392 out_err_overflow: 393 free(expr); 394 return NULL; 395 } 396