18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include "string2.h" 38c2ecf20Sopenharmony_ci#include <linux/kernel.h> 48c2ecf20Sopenharmony_ci#include <linux/string.h> 58c2ecf20Sopenharmony_ci#include <stdlib.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/ctype.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ciconst char *graph_dotted_line = 108c2ecf20Sopenharmony_ci "---------------------------------------------------------------------" 118c2ecf20Sopenharmony_ci "---------------------------------------------------------------------" 128c2ecf20Sopenharmony_ci "---------------------------------------------------------------------"; 138c2ecf20Sopenharmony_ciconst char *dots = 148c2ecf20Sopenharmony_ci "....................................................................." 158c2ecf20Sopenharmony_ci "....................................................................." 168c2ecf20Sopenharmony_ci "....................................................................."; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define K 1024LL 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * perf_atoll() 218c2ecf20Sopenharmony_ci * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB") 228c2ecf20Sopenharmony_ci * and return its numeric value 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_cis64 perf_atoll(const char *str) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci s64 length; 278c2ecf20Sopenharmony_ci char *p; 288c2ecf20Sopenharmony_ci char c; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (!isdigit(str[0])) 318c2ecf20Sopenharmony_ci goto out_err; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci length = strtoll(str, &p, 10); 348c2ecf20Sopenharmony_ci switch (c = *p++) { 358c2ecf20Sopenharmony_ci case 'b': case 'B': 368c2ecf20Sopenharmony_ci if (*p) 378c2ecf20Sopenharmony_ci goto out_err; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci __fallthrough; 408c2ecf20Sopenharmony_ci case '\0': 418c2ecf20Sopenharmony_ci return length; 428c2ecf20Sopenharmony_ci default: 438c2ecf20Sopenharmony_ci goto out_err; 448c2ecf20Sopenharmony_ci /* two-letter suffices */ 458c2ecf20Sopenharmony_ci case 'k': case 'K': 468c2ecf20Sopenharmony_ci length <<= 10; 478c2ecf20Sopenharmony_ci break; 488c2ecf20Sopenharmony_ci case 'm': case 'M': 498c2ecf20Sopenharmony_ci length <<= 20; 508c2ecf20Sopenharmony_ci break; 518c2ecf20Sopenharmony_ci case 'g': case 'G': 528c2ecf20Sopenharmony_ci length <<= 30; 538c2ecf20Sopenharmony_ci break; 548c2ecf20Sopenharmony_ci case 't': case 'T': 558c2ecf20Sopenharmony_ci length <<= 40; 568c2ecf20Sopenharmony_ci break; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci /* we want the cases to match */ 598c2ecf20Sopenharmony_ci if (islower(c)) { 608c2ecf20Sopenharmony_ci if (strcmp(p, "b") != 0) 618c2ecf20Sopenharmony_ci goto out_err; 628c2ecf20Sopenharmony_ci } else { 638c2ecf20Sopenharmony_ci if (strcmp(p, "B") != 0) 648c2ecf20Sopenharmony_ci goto out_err; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci return length; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ciout_err: 698c2ecf20Sopenharmony_ci return -1; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* Character class matching */ 738c2ecf20Sopenharmony_cistatic bool __match_charclass(const char *pat, char c, const char **npat) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci bool complement = false, ret = true; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (*pat == '!') { 788c2ecf20Sopenharmony_ci complement = true; 798c2ecf20Sopenharmony_ci pat++; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci if (*pat++ == c) /* First character is special */ 828c2ecf20Sopenharmony_ci goto end; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci while (*pat && *pat != ']') { /* Matching */ 858c2ecf20Sopenharmony_ci if (*pat == '-' && *(pat + 1) != ']') { /* Range */ 868c2ecf20Sopenharmony_ci if (*(pat - 1) <= c && c <= *(pat + 1)) 878c2ecf20Sopenharmony_ci goto end; 888c2ecf20Sopenharmony_ci if (*(pat - 1) > *(pat + 1)) 898c2ecf20Sopenharmony_ci goto error; 908c2ecf20Sopenharmony_ci pat += 2; 918c2ecf20Sopenharmony_ci } else if (*pat++ == c) 928c2ecf20Sopenharmony_ci goto end; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci if (!*pat) 958c2ecf20Sopenharmony_ci goto error; 968c2ecf20Sopenharmony_ci ret = false; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ciend: 998c2ecf20Sopenharmony_ci while (*pat && *pat != ']') /* Searching closing */ 1008c2ecf20Sopenharmony_ci pat++; 1018c2ecf20Sopenharmony_ci if (!*pat) 1028c2ecf20Sopenharmony_ci goto error; 1038c2ecf20Sopenharmony_ci *npat = pat + 1; 1048c2ecf20Sopenharmony_ci return complement ? !ret : ret; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cierror: 1078c2ecf20Sopenharmony_ci return false; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* Glob/lazy pattern matching */ 1118c2ecf20Sopenharmony_cistatic bool __match_glob(const char *str, const char *pat, bool ignore_space, 1128c2ecf20Sopenharmony_ci bool case_ins) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci while (*str && *pat && *pat != '*') { 1158c2ecf20Sopenharmony_ci if (ignore_space) { 1168c2ecf20Sopenharmony_ci /* Ignore spaces for lazy matching */ 1178c2ecf20Sopenharmony_ci if (isspace(*str)) { 1188c2ecf20Sopenharmony_ci str++; 1198c2ecf20Sopenharmony_ci continue; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci if (isspace(*pat)) { 1228c2ecf20Sopenharmony_ci pat++; 1238c2ecf20Sopenharmony_ci continue; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci if (*pat == '?') { /* Matches any single character */ 1278c2ecf20Sopenharmony_ci str++; 1288c2ecf20Sopenharmony_ci pat++; 1298c2ecf20Sopenharmony_ci continue; 1308c2ecf20Sopenharmony_ci } else if (*pat == '[') /* Character classes/Ranges */ 1318c2ecf20Sopenharmony_ci if (__match_charclass(pat + 1, *str, &pat)) { 1328c2ecf20Sopenharmony_ci str++; 1338c2ecf20Sopenharmony_ci continue; 1348c2ecf20Sopenharmony_ci } else 1358c2ecf20Sopenharmony_ci return false; 1368c2ecf20Sopenharmony_ci else if (*pat == '\\') /* Escaped char match as normal char */ 1378c2ecf20Sopenharmony_ci pat++; 1388c2ecf20Sopenharmony_ci if (case_ins) { 1398c2ecf20Sopenharmony_ci if (tolower(*str) != tolower(*pat)) 1408c2ecf20Sopenharmony_ci return false; 1418c2ecf20Sopenharmony_ci } else if (*str != *pat) 1428c2ecf20Sopenharmony_ci return false; 1438c2ecf20Sopenharmony_ci str++; 1448c2ecf20Sopenharmony_ci pat++; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci /* Check wild card */ 1478c2ecf20Sopenharmony_ci if (*pat == '*') { 1488c2ecf20Sopenharmony_ci while (*pat == '*') 1498c2ecf20Sopenharmony_ci pat++; 1508c2ecf20Sopenharmony_ci if (!*pat) /* Tail wild card matches all */ 1518c2ecf20Sopenharmony_ci return true; 1528c2ecf20Sopenharmony_ci while (*str) 1538c2ecf20Sopenharmony_ci if (__match_glob(str++, pat, ignore_space, case_ins)) 1548c2ecf20Sopenharmony_ci return true; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci return !*str && !*pat; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/** 1608c2ecf20Sopenharmony_ci * strglobmatch - glob expression pattern matching 1618c2ecf20Sopenharmony_ci * @str: the target string to match 1628c2ecf20Sopenharmony_ci * @pat: the pattern string to match 1638c2ecf20Sopenharmony_ci * 1648c2ecf20Sopenharmony_ci * This returns true if the @str matches @pat. @pat can includes wildcards 1658c2ecf20Sopenharmony_ci * ('*','?') and character classes ([CHARS], complementation and ranges are 1668c2ecf20Sopenharmony_ci * also supported). Also, this supports escape character ('\') to use special 1678c2ecf20Sopenharmony_ci * characters as normal character. 1688c2ecf20Sopenharmony_ci * 1698c2ecf20Sopenharmony_ci * Note: if @pat syntax is broken, this always returns false. 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_cibool strglobmatch(const char *str, const char *pat) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci return __match_glob(str, pat, false, false); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cibool strglobmatch_nocase(const char *str, const char *pat) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return __match_glob(str, pat, false, true); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/** 1828c2ecf20Sopenharmony_ci * strlazymatch - matching pattern strings lazily with glob pattern 1838c2ecf20Sopenharmony_ci * @str: the target string to match 1848c2ecf20Sopenharmony_ci * @pat: the pattern string to match 1858c2ecf20Sopenharmony_ci * 1868c2ecf20Sopenharmony_ci * This is similar to strglobmatch, except this ignores spaces in 1878c2ecf20Sopenharmony_ci * the target string. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_cibool strlazymatch(const char *str, const char *pat) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci return __match_glob(str, pat, true, false); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/** 1958c2ecf20Sopenharmony_ci * strtailcmp - Compare the tail of two strings 1968c2ecf20Sopenharmony_ci * @s1: 1st string to be compared 1978c2ecf20Sopenharmony_ci * @s2: 2nd string to be compared 1988c2ecf20Sopenharmony_ci * 1998c2ecf20Sopenharmony_ci * Return 0 if whole of either string is same as another's tail part. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ciint strtailcmp(const char *s1, const char *s2) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci int i1 = strlen(s1); 2048c2ecf20Sopenharmony_ci int i2 = strlen(s2); 2058c2ecf20Sopenharmony_ci while (--i1 >= 0 && --i2 >= 0) { 2068c2ecf20Sopenharmony_ci if (s1[i1] != s2[i2]) 2078c2ecf20Sopenharmony_ci return s1[i1] - s2[i2]; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci return 0; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cichar *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci /* 2158c2ecf20Sopenharmony_ci * FIXME: replace this with an expression using log10() when we 2168c2ecf20Sopenharmony_ci * find a suitable implementation, maybe the one in the dvb drivers... 2178c2ecf20Sopenharmony_ci * 2188c2ecf20Sopenharmony_ci * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci size_t size = nints * 28 + 1; /* \0 */ 2218c2ecf20Sopenharmony_ci size_t i, printed = 0; 2228c2ecf20Sopenharmony_ci char *expr = malloc(size); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (expr) { 2258c2ecf20Sopenharmony_ci const char *or_and = "||", *eq_neq = "=="; 2268c2ecf20Sopenharmony_ci char *e = expr; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (!in) { 2298c2ecf20Sopenharmony_ci or_and = "&&"; 2308c2ecf20Sopenharmony_ci eq_neq = "!="; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci for (i = 0; i < nints; ++i) { 2348c2ecf20Sopenharmony_ci if (printed == size) 2358c2ecf20Sopenharmony_ci goto out_err_overflow; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (i > 0) 2388c2ecf20Sopenharmony_ci printed += scnprintf(e + printed, size - printed, " %s ", or_and); 2398c2ecf20Sopenharmony_ci printed += scnprintf(e + printed, size - printed, 2408c2ecf20Sopenharmony_ci "%s %s %d", var, eq_neq, ints[i]); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return expr; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciout_err_overflow: 2478c2ecf20Sopenharmony_ci free(expr); 2488c2ecf20Sopenharmony_ci return NULL; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci/* Like strpbrk(), but not break if it is right after a backslash (escaped) */ 2528c2ecf20Sopenharmony_cichar *strpbrk_esc(char *str, const char *stopset) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci char *ptr; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci do { 2578c2ecf20Sopenharmony_ci ptr = strpbrk(str, stopset); 2588c2ecf20Sopenharmony_ci if (ptr == str || 2598c2ecf20Sopenharmony_ci (ptr == str + 1 && *(ptr - 1) != '\\')) 2608c2ecf20Sopenharmony_ci break; 2618c2ecf20Sopenharmony_ci str = ptr + 1; 2628c2ecf20Sopenharmony_ci } while (ptr && *(ptr - 1) == '\\' && *(ptr - 2) != '\\'); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return ptr; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* Like strdup, but do not copy a single backslash */ 2688c2ecf20Sopenharmony_cichar *strdup_esc(const char *str) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci char *s, *d, *p, *ret = strdup(str); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (!ret) 2738c2ecf20Sopenharmony_ci return NULL; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci d = strchr(ret, '\\'); 2768c2ecf20Sopenharmony_ci if (!d) 2778c2ecf20Sopenharmony_ci return ret; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci s = d + 1; 2808c2ecf20Sopenharmony_ci do { 2818c2ecf20Sopenharmony_ci if (*s == '\0') { 2828c2ecf20Sopenharmony_ci *d = '\0'; 2838c2ecf20Sopenharmony_ci break; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci p = strchr(s + 1, '\\'); 2868c2ecf20Sopenharmony_ci if (p) { 2878c2ecf20Sopenharmony_ci memmove(d, s, p - s); 2888c2ecf20Sopenharmony_ci d += p - s; 2898c2ecf20Sopenharmony_ci s = p + 1; 2908c2ecf20Sopenharmony_ci } else 2918c2ecf20Sopenharmony_ci memmove(d, s, strlen(s) + 1); 2928c2ecf20Sopenharmony_ci } while (p); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return ret; 2958c2ecf20Sopenharmony_ci} 296