1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2a067558eSArnaldo Carvalho de Melo #include "string2.h" 3a067558eSArnaldo Carvalho de Melo #include <linux/kernel.h> 4a067558eSArnaldo Carvalho de Melo #include <linux/string.h> 5a067558eSArnaldo Carvalho de Melo #include <stdlib.h> 686470930SIngo Molnar 73052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h> 83d689ed6SArnaldo Carvalho de Melo 96a9fa4e3SArnaldo Carvalho de Melo const char *graph_dotted_line = 106a9fa4e3SArnaldo Carvalho de Melo "---------------------------------------------------------------------" 116a9fa4e3SArnaldo Carvalho de Melo "---------------------------------------------------------------------" 126a9fa4e3SArnaldo Carvalho de Melo "---------------------------------------------------------------------"; 136a9fa4e3SArnaldo Carvalho de Melo const char *dots = 146a9fa4e3SArnaldo Carvalho de Melo "....................................................................." 156a9fa4e3SArnaldo Carvalho de Melo "....................................................................." 166a9fa4e3SArnaldo Carvalho de Melo "....................................................................."; 176a9fa4e3SArnaldo Carvalho de Melo 18d2fb8b41SHitoshi Mitake #define K 1024LL 19d2fb8b41SHitoshi Mitake /* 20d2fb8b41SHitoshi Mitake * perf_atoll() 21d2fb8b41SHitoshi Mitake * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB") 22d2fb8b41SHitoshi Mitake * and return its numeric value 23d2fb8b41SHitoshi Mitake */ 24d2fb8b41SHitoshi Mitake s64 perf_atoll(const char *str) 25d2fb8b41SHitoshi Mitake { 268ba7f6c2SAl Viro s64 length; 278ba7f6c2SAl Viro char *p; 288ba7f6c2SAl Viro char c; 29d2fb8b41SHitoshi Mitake 30d2fb8b41SHitoshi Mitake if (!isdigit(str[0])) 31d2fb8b41SHitoshi Mitake goto out_err; 32d2fb8b41SHitoshi Mitake 338ba7f6c2SAl Viro length = strtoll(str, &p, 10); 348ba7f6c2SAl Viro switch (c = *p++) { 358ba7f6c2SAl Viro case 'b': case 'B': 368ba7f6c2SAl Viro if (*p) 37d2fb8b41SHitoshi Mitake goto out_err; 3894bdd5edSArnaldo Carvalho de Melo 3994bdd5edSArnaldo Carvalho de Melo __fallthrough; 408ba7f6c2SAl Viro case '\0': 418ba7f6c2SAl Viro return length; 42d2fb8b41SHitoshi Mitake default: 43d2fb8b41SHitoshi Mitake goto out_err; 448ba7f6c2SAl Viro /* two-letter suffices */ 458ba7f6c2SAl Viro case 'k': case 'K': 468ba7f6c2SAl Viro length <<= 10; 478ba7f6c2SAl Viro break; 488ba7f6c2SAl Viro case 'm': case 'M': 498ba7f6c2SAl Viro length <<= 20; 508ba7f6c2SAl Viro break; 518ba7f6c2SAl Viro case 'g': case 'G': 528ba7f6c2SAl Viro length <<= 30; 538ba7f6c2SAl Viro break; 548ba7f6c2SAl Viro case 't': case 'T': 558ba7f6c2SAl Viro length <<= 40; 56d2fb8b41SHitoshi Mitake break; 57d2fb8b41SHitoshi Mitake } 588ba7f6c2SAl Viro /* we want the cases to match */ 598ba7f6c2SAl Viro if (islower(c)) { 608ba7f6c2SAl Viro if (strcmp(p, "b") != 0) 618ba7f6c2SAl Viro goto out_err; 628ba7f6c2SAl Viro } else { 638ba7f6c2SAl Viro if (strcmp(p, "B") != 0) 648ba7f6c2SAl Viro goto out_err; 65d2fb8b41SHitoshi Mitake } 668ba7f6c2SAl Viro return length; 67d2fb8b41SHitoshi Mitake 68d2fb8b41SHitoshi Mitake out_err: 698ba7f6c2SAl Viro return -1; 70d2fb8b41SHitoshi Mitake } 71e1c01d61SMasami Hiramatsu 726964cd2cSMasami Hiramatsu /* Character class matching */ 736964cd2cSMasami Hiramatsu static bool __match_charclass(const char *pat, char c, const char **npat) 746964cd2cSMasami Hiramatsu { 756964cd2cSMasami Hiramatsu bool complement = false, ret = true; 766964cd2cSMasami Hiramatsu 776964cd2cSMasami Hiramatsu if (*pat == '!') { 786964cd2cSMasami Hiramatsu complement = true; 796964cd2cSMasami Hiramatsu pat++; 806964cd2cSMasami Hiramatsu } 816964cd2cSMasami Hiramatsu if (*pat++ == c) /* First character is special */ 826964cd2cSMasami Hiramatsu goto end; 836964cd2cSMasami Hiramatsu 846964cd2cSMasami Hiramatsu while (*pat && *pat != ']') { /* Matching */ 856964cd2cSMasami Hiramatsu if (*pat == '-' && *(pat + 1) != ']') { /* Range */ 866964cd2cSMasami Hiramatsu if (*(pat - 1) <= c && c <= *(pat + 1)) 876964cd2cSMasami Hiramatsu goto end; 886964cd2cSMasami Hiramatsu if (*(pat - 1) > *(pat + 1)) 896964cd2cSMasami Hiramatsu goto error; 906964cd2cSMasami Hiramatsu pat += 2; 916964cd2cSMasami Hiramatsu } else if (*pat++ == c) 926964cd2cSMasami Hiramatsu goto end; 936964cd2cSMasami Hiramatsu } 946964cd2cSMasami Hiramatsu if (!*pat) 956964cd2cSMasami Hiramatsu goto error; 966964cd2cSMasami Hiramatsu ret = false; 976964cd2cSMasami Hiramatsu 986964cd2cSMasami Hiramatsu end: 996964cd2cSMasami Hiramatsu while (*pat && *pat != ']') /* Searching closing */ 1006964cd2cSMasami Hiramatsu pat++; 1016964cd2cSMasami Hiramatsu if (!*pat) 1026964cd2cSMasami Hiramatsu goto error; 1036964cd2cSMasami Hiramatsu *npat = pat + 1; 1046964cd2cSMasami Hiramatsu return complement ? !ret : ret; 1056964cd2cSMasami Hiramatsu 1066964cd2cSMasami Hiramatsu error: 1076964cd2cSMasami Hiramatsu return false; 1086964cd2cSMasami Hiramatsu } 1096964cd2cSMasami Hiramatsu 1102a9c8c36SMasami Hiramatsu /* Glob/lazy pattern matching */ 11138d14f0cSAndi Kleen static bool __match_glob(const char *str, const char *pat, bool ignore_space, 11238d14f0cSAndi Kleen bool case_ins) 113bbbb521bSMasami Hiramatsu { 114bbbb521bSMasami Hiramatsu while (*str && *pat && *pat != '*') { 1152a9c8c36SMasami Hiramatsu if (ignore_space) { 1162a9c8c36SMasami Hiramatsu /* Ignore spaces for lazy matching */ 1172a9c8c36SMasami Hiramatsu if (isspace(*str)) { 1182a9c8c36SMasami Hiramatsu str++; 1192a9c8c36SMasami Hiramatsu continue; 1202a9c8c36SMasami Hiramatsu } 1212a9c8c36SMasami Hiramatsu if (isspace(*pat)) { 1222a9c8c36SMasami Hiramatsu pat++; 1232a9c8c36SMasami Hiramatsu continue; 1242a9c8c36SMasami Hiramatsu } 1252a9c8c36SMasami Hiramatsu } 1266964cd2cSMasami Hiramatsu if (*pat == '?') { /* Matches any single character */ 127bbbb521bSMasami Hiramatsu str++; 128bbbb521bSMasami Hiramatsu pat++; 1296964cd2cSMasami Hiramatsu continue; 1306964cd2cSMasami Hiramatsu } else if (*pat == '[') /* Character classes/Ranges */ 1316964cd2cSMasami Hiramatsu if (__match_charclass(pat + 1, *str, &pat)) { 1326964cd2cSMasami Hiramatsu str++; 1336964cd2cSMasami Hiramatsu continue; 134bbbb521bSMasami Hiramatsu } else 1356964cd2cSMasami Hiramatsu return false; 1366964cd2cSMasami Hiramatsu else if (*pat == '\\') /* Escaped char match as normal char */ 1376964cd2cSMasami Hiramatsu pat++; 13838d14f0cSAndi Kleen if (case_ins) { 13938d14f0cSAndi Kleen if (tolower(*str) != tolower(*pat)) 140bbbb521bSMasami Hiramatsu return false; 14138d14f0cSAndi Kleen } else if (*str != *pat) 14238d14f0cSAndi Kleen return false; 14338d14f0cSAndi Kleen str++; 14438d14f0cSAndi Kleen pat++; 145bbbb521bSMasami Hiramatsu } 146bbbb521bSMasami Hiramatsu /* Check wild card */ 147bbbb521bSMasami Hiramatsu if (*pat == '*') { 148bbbb521bSMasami Hiramatsu while (*pat == '*') 149bbbb521bSMasami Hiramatsu pat++; 150bbbb521bSMasami Hiramatsu if (!*pat) /* Tail wild card matches all */ 151bbbb521bSMasami Hiramatsu return true; 152bbbb521bSMasami Hiramatsu while (*str) 15338d14f0cSAndi Kleen if (__match_glob(str++, pat, ignore_space, case_ins)) 154bbbb521bSMasami Hiramatsu return true; 155bbbb521bSMasami Hiramatsu } 156bbbb521bSMasami Hiramatsu return !*str && !*pat; 157bbbb521bSMasami Hiramatsu } 158bbbb521bSMasami Hiramatsu 1592a9c8c36SMasami Hiramatsu /** 1602a9c8c36SMasami Hiramatsu * strglobmatch - glob expression pattern matching 1612a9c8c36SMasami Hiramatsu * @str: the target string to match 1622a9c8c36SMasami Hiramatsu * @pat: the pattern string to match 1632a9c8c36SMasami Hiramatsu * 1642a9c8c36SMasami Hiramatsu * This returns true if the @str matches @pat. @pat can includes wildcards 1652a9c8c36SMasami Hiramatsu * ('*','?') and character classes ([CHARS], complementation and ranges are 1662a9c8c36SMasami Hiramatsu * also supported). Also, this supports escape character ('\') to use special 1672a9c8c36SMasami Hiramatsu * characters as normal character. 1682a9c8c36SMasami Hiramatsu * 1692a9c8c36SMasami Hiramatsu * Note: if @pat syntax is broken, this always returns false. 1702a9c8c36SMasami Hiramatsu */ 1712a9c8c36SMasami Hiramatsu bool strglobmatch(const char *str, const char *pat) 1722a9c8c36SMasami Hiramatsu { 17338d14f0cSAndi Kleen return __match_glob(str, pat, false, false); 17438d14f0cSAndi Kleen } 17538d14f0cSAndi Kleen 17638d14f0cSAndi Kleen bool strglobmatch_nocase(const char *str, const char *pat) 17738d14f0cSAndi Kleen { 17838d14f0cSAndi Kleen return __match_glob(str, pat, false, true); 1792a9c8c36SMasami Hiramatsu } 1802a9c8c36SMasami Hiramatsu 1812a9c8c36SMasami Hiramatsu /** 1822a9c8c36SMasami Hiramatsu * strlazymatch - matching pattern strings lazily with glob pattern 1832a9c8c36SMasami Hiramatsu * @str: the target string to match 1842a9c8c36SMasami Hiramatsu * @pat: the pattern string to match 1852a9c8c36SMasami Hiramatsu * 1862a9c8c36SMasami Hiramatsu * This is similar to strglobmatch, except this ignores spaces in 1872a9c8c36SMasami Hiramatsu * the target string. 1882a9c8c36SMasami Hiramatsu */ 1892a9c8c36SMasami Hiramatsu bool strlazymatch(const char *str, const char *pat) 1902a9c8c36SMasami Hiramatsu { 19138d14f0cSAndi Kleen return __match_glob(str, pat, true, false); 1922a9c8c36SMasami Hiramatsu } 193bad03ae4SMasami Hiramatsu 194bad03ae4SMasami Hiramatsu /** 195bad03ae4SMasami Hiramatsu * strtailcmp - Compare the tail of two strings 196bad03ae4SMasami Hiramatsu * @s1: 1st string to be compared 197bad03ae4SMasami Hiramatsu * @s2: 2nd string to be compared 198bad03ae4SMasami Hiramatsu * 199bad03ae4SMasami Hiramatsu * Return 0 if whole of either string is same as another's tail part. 200bad03ae4SMasami Hiramatsu */ 201bad03ae4SMasami Hiramatsu int strtailcmp(const char *s1, const char *s2) 202bad03ae4SMasami Hiramatsu { 203bad03ae4SMasami Hiramatsu int i1 = strlen(s1); 204bad03ae4SMasami Hiramatsu int i2 = strlen(s2); 205bad03ae4SMasami Hiramatsu while (--i1 >= 0 && --i2 >= 0) { 206bad03ae4SMasami Hiramatsu if (s1[i1] != s2[i2]) 207bad03ae4SMasami Hiramatsu return s1[i1] - s2[i2]; 208bad03ae4SMasami Hiramatsu } 209bad03ae4SMasami Hiramatsu return 0; 210bad03ae4SMasami Hiramatsu } 211bad03ae4SMasami Hiramatsu 21293ec4ce7SArnaldo Carvalho de Melo char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints) 21393ec4ce7SArnaldo Carvalho de Melo { 21493ec4ce7SArnaldo Carvalho de Melo /* 21593ec4ce7SArnaldo Carvalho de Melo * FIXME: replace this with an expression using log10() when we 21693ec4ce7SArnaldo Carvalho de Melo * find a suitable implementation, maybe the one in the dvb drivers... 21793ec4ce7SArnaldo Carvalho de Melo * 21893ec4ce7SArnaldo Carvalho de Melo * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators 21993ec4ce7SArnaldo Carvalho de Melo */ 22093ec4ce7SArnaldo Carvalho de Melo size_t size = nints * 28 + 1; /* \0 */ 22193ec4ce7SArnaldo Carvalho de Melo size_t i, printed = 0; 22293ec4ce7SArnaldo Carvalho de Melo char *expr = malloc(size); 22393ec4ce7SArnaldo Carvalho de Melo 22493ec4ce7SArnaldo Carvalho de Melo if (expr) { 22593ec4ce7SArnaldo Carvalho de Melo const char *or_and = "||", *eq_neq = "=="; 22693ec4ce7SArnaldo Carvalho de Melo char *e = expr; 22793ec4ce7SArnaldo Carvalho de Melo 22893ec4ce7SArnaldo Carvalho de Melo if (!in) { 22993ec4ce7SArnaldo Carvalho de Melo or_and = "&&"; 23093ec4ce7SArnaldo Carvalho de Melo eq_neq = "!="; 23193ec4ce7SArnaldo Carvalho de Melo } 23293ec4ce7SArnaldo Carvalho de Melo 23393ec4ce7SArnaldo Carvalho de Melo for (i = 0; i < nints; ++i) { 23493ec4ce7SArnaldo Carvalho de Melo if (printed == size) 23593ec4ce7SArnaldo Carvalho de Melo goto out_err_overflow; 23693ec4ce7SArnaldo Carvalho de Melo 23793ec4ce7SArnaldo Carvalho de Melo if (i > 0) 238a067558eSArnaldo Carvalho de Melo printed += scnprintf(e + printed, size - printed, " %s ", or_and); 23993ec4ce7SArnaldo Carvalho de Melo printed += scnprintf(e + printed, size - printed, 24093ec4ce7SArnaldo Carvalho de Melo "%s %s %d", var, eq_neq, ints[i]); 24193ec4ce7SArnaldo Carvalho de Melo } 24293ec4ce7SArnaldo Carvalho de Melo } 24393ec4ce7SArnaldo Carvalho de Melo 24493ec4ce7SArnaldo Carvalho de Melo return expr; 24593ec4ce7SArnaldo Carvalho de Melo 24693ec4ce7SArnaldo Carvalho de Melo out_err_overflow: 24793ec4ce7SArnaldo Carvalho de Melo free(expr); 24893ec4ce7SArnaldo Carvalho de Melo return NULL; 24993ec4ce7SArnaldo Carvalho de Melo } 2501e9f9e8aSMasami Hiramatsu 2511e9f9e8aSMasami Hiramatsu /* Like strpbrk(), but not break if it is right after a backslash (escaped) */ 2521e9f9e8aSMasami Hiramatsu char *strpbrk_esc(char *str, const char *stopset) 2531e9f9e8aSMasami Hiramatsu { 2541e9f9e8aSMasami Hiramatsu char *ptr; 2551e9f9e8aSMasami Hiramatsu 2561e9f9e8aSMasami Hiramatsu do { 2571e9f9e8aSMasami Hiramatsu ptr = strpbrk(str, stopset); 2581e9f9e8aSMasami Hiramatsu if (ptr == str || 2591e9f9e8aSMasami Hiramatsu (ptr == str + 1 && *(ptr - 1) != '\\')) 2601e9f9e8aSMasami Hiramatsu break; 2611e9f9e8aSMasami Hiramatsu str = ptr + 1; 2621e9f9e8aSMasami Hiramatsu } while (ptr && *(ptr - 1) == '\\' && *(ptr - 2) != '\\'); 2631e9f9e8aSMasami Hiramatsu 2641e9f9e8aSMasami Hiramatsu return ptr; 2651e9f9e8aSMasami Hiramatsu } 2661e9f9e8aSMasami Hiramatsu 2671e9f9e8aSMasami Hiramatsu /* Like strdup, but do not copy a single backslash */ 2681e9f9e8aSMasami Hiramatsu char *strdup_esc(const char *str) 2691e9f9e8aSMasami Hiramatsu { 2701e9f9e8aSMasami Hiramatsu char *s, *d, *p, *ret = strdup(str); 2711e9f9e8aSMasami Hiramatsu 2721e9f9e8aSMasami Hiramatsu if (!ret) 2731e9f9e8aSMasami Hiramatsu return NULL; 2741e9f9e8aSMasami Hiramatsu 2751e9f9e8aSMasami Hiramatsu d = strchr(ret, '\\'); 2761e9f9e8aSMasami Hiramatsu if (!d) 2771e9f9e8aSMasami Hiramatsu return ret; 2781e9f9e8aSMasami Hiramatsu 2791e9f9e8aSMasami Hiramatsu s = d + 1; 2801e9f9e8aSMasami Hiramatsu do { 2811e9f9e8aSMasami Hiramatsu if (*s == '\0') { 2821e9f9e8aSMasami Hiramatsu *d = '\0'; 2831e9f9e8aSMasami Hiramatsu break; 2841e9f9e8aSMasami Hiramatsu } 2851e9f9e8aSMasami Hiramatsu p = strchr(s + 1, '\\'); 2861e9f9e8aSMasami Hiramatsu if (p) { 2871e9f9e8aSMasami Hiramatsu memmove(d, s, p - s); 2881e9f9e8aSMasami Hiramatsu d += p - s; 2891e9f9e8aSMasami Hiramatsu s = p + 1; 2901e9f9e8aSMasami Hiramatsu } else 2911e9f9e8aSMasami Hiramatsu memmove(d, s, strlen(s) + 1); 2921e9f9e8aSMasami Hiramatsu } while (p); 2931e9f9e8aSMasami Hiramatsu 2941e9f9e8aSMasami Hiramatsu return ret; 2951e9f9e8aSMasami Hiramatsu } 296*cef7af25SFabian Hemmer 297*cef7af25SFabian Hemmer unsigned int hex(char c) 298*cef7af25SFabian Hemmer { 299*cef7af25SFabian Hemmer if (c >= '0' && c <= '9') 300*cef7af25SFabian Hemmer return c - '0'; 301*cef7af25SFabian Hemmer if (c >= 'a' && c <= 'f') 302*cef7af25SFabian Hemmer return c - 'a' + 10; 303*cef7af25SFabian Hemmer return c - 'A' + 10; 304*cef7af25SFabian Hemmer } 305