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