1 // SPDX-License-Identifier: GPL-2.0 2 #include "string2.h" 3 #include <linux/kernel.h> 4 #include <linux/string.h> 5 #include <stdlib.h> 6 7 #include <linux/ctype.h> 8 9 const char *graph_dotted_line = 10 "---------------------------------------------------------------------" 11 "---------------------------------------------------------------------" 12 "---------------------------------------------------------------------"; 13 const char *dots = 14 "....................................................................." 15 "....................................................................." 16 "....................................................................."; 17 18 /* 19 * perf_atoll() 20 * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB") 21 * and return its numeric value 22 */ 23 s64 perf_atoll(const char *str) 24 { 25 s64 length; 26 char *p; 27 char c; 28 29 if (!isdigit(str[0])) 30 goto out_err; 31 32 length = strtoll(str, &p, 10); 33 switch (c = *p++) { 34 case 'b': case 'B': 35 if (*p) 36 goto out_err; 37 38 fallthrough; 39 case '\0': 40 return length; 41 default: 42 goto out_err; 43 /* two-letter suffices */ 44 case 'k': case 'K': 45 length <<= 10; 46 break; 47 case 'm': case 'M': 48 length <<= 20; 49 break; 50 case 'g': case 'G': 51 length <<= 30; 52 break; 53 case 't': case 'T': 54 length <<= 40; 55 break; 56 } 57 /* we want the cases to match */ 58 if (islower(c)) { 59 if (strcmp(p, "b") != 0) 60 goto out_err; 61 } else { 62 if (strcmp(p, "B") != 0) 63 goto out_err; 64 } 65 return length; 66 67 out_err: 68 return -1; 69 } 70 71 /* Character class matching */ 72 static bool __match_charclass(const char *pat, char c, const char **npat) 73 { 74 bool complement = false, ret = true; 75 76 if (*pat == '!') { 77 complement = true; 78 pat++; 79 } 80 if (*pat++ == c) /* First character is special */ 81 goto end; 82 83 while (*pat && *pat != ']') { /* Matching */ 84 if (*pat == '-' && *(pat + 1) != ']') { /* Range */ 85 if (*(pat - 1) <= c && c <= *(pat + 1)) 86 goto end; 87 if (*(pat - 1) > *(pat + 1)) 88 goto error; 89 pat += 2; 90 } else if (*pat++ == c) 91 goto end; 92 } 93 if (!*pat) 94 goto error; 95 ret = false; 96 97 end: 98 while (*pat && *pat != ']') /* Searching closing */ 99 pat++; 100 if (!*pat) 101 goto error; 102 *npat = pat + 1; 103 return complement ? !ret : ret; 104 105 error: 106 return false; 107 } 108 109 /* Glob/lazy pattern matching */ 110 static bool __match_glob(const char *str, const char *pat, bool ignore_space, 111 bool case_ins) 112 { 113 while (*str && *pat && *pat != '*') { 114 if (ignore_space) { 115 /* Ignore spaces for lazy matching */ 116 if (isspace(*str)) { 117 str++; 118 continue; 119 } 120 if (isspace(*pat)) { 121 pat++; 122 continue; 123 } 124 } 125 if (*pat == '?') { /* Matches any single character */ 126 str++; 127 pat++; 128 continue; 129 } else if (*pat == '[') /* Character classes/Ranges */ 130 if (__match_charclass(pat + 1, *str, &pat)) { 131 str++; 132 continue; 133 } else 134 return false; 135 else if (*pat == '\\') /* Escaped char match as normal char */ 136 pat++; 137 if (case_ins) { 138 if (tolower(*str) != tolower(*pat)) 139 return false; 140 } else if (*str != *pat) 141 return false; 142 str++; 143 pat++; 144 } 145 /* Check wild card */ 146 if (*pat == '*') { 147 while (*pat == '*') 148 pat++; 149 if (!*pat) /* Tail wild card matches all */ 150 return true; 151 while (*str) 152 if (__match_glob(str++, pat, ignore_space, case_ins)) 153 return true; 154 } 155 return !*str && !*pat; 156 } 157 158 /** 159 * strglobmatch - glob expression pattern matching 160 * @str: the target string to match 161 * @pat: the pattern string to match 162 * 163 * This returns true if the @str matches @pat. @pat can includes wildcards 164 * ('*','?') and character classes ([CHARS], complementation and ranges are 165 * also supported). Also, this supports escape character ('\') to use special 166 * characters as normal character. 167 * 168 * Note: if @pat syntax is broken, this always returns false. 169 */ 170 bool strglobmatch(const char *str, const char *pat) 171 { 172 return __match_glob(str, pat, false, false); 173 } 174 175 bool strglobmatch_nocase(const char *str, const char *pat) 176 { 177 return __match_glob(str, pat, false, true); 178 } 179 180 /** 181 * strlazymatch - matching pattern strings lazily with glob pattern 182 * @str: the target string to match 183 * @pat: the pattern string to match 184 * 185 * This is similar to strglobmatch, except this ignores spaces in 186 * the target string. 187 */ 188 bool strlazymatch(const char *str, const char *pat) 189 { 190 return __match_glob(str, pat, true, false); 191 } 192 193 /** 194 * strtailcmp - Compare the tail of two strings 195 * @s1: 1st string to be compared 196 * @s2: 2nd string to be compared 197 * 198 * Return 0 if whole of either string is same as another's tail part. 199 */ 200 int strtailcmp(const char *s1, const char *s2) 201 { 202 int i1 = strlen(s1); 203 int i2 = strlen(s2); 204 while (--i1 >= 0 && --i2 >= 0) { 205 if (s1[i1] != s2[i2]) 206 return s1[i1] - s2[i2]; 207 } 208 return 0; 209 } 210 211 char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints) 212 { 213 /* 214 * FIXME: replace this with an expression using log10() when we 215 * find a suitable implementation, maybe the one in the dvb drivers... 216 * 217 * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators 218 */ 219 size_t size = nints * 28 + 1; /* \0 */ 220 size_t i, printed = 0; 221 char *expr = malloc(size); 222 223 if (expr) { 224 const char *or_and = "||", *eq_neq = "=="; 225 char *e = expr; 226 227 if (!in) { 228 or_and = "&&"; 229 eq_neq = "!="; 230 } 231 232 for (i = 0; i < nints; ++i) { 233 if (printed == size) 234 goto out_err_overflow; 235 236 if (i > 0) 237 printed += scnprintf(e + printed, size - printed, " %s ", or_and); 238 printed += scnprintf(e + printed, size - printed, 239 "%s %s %d", var, eq_neq, ints[i]); 240 } 241 } 242 243 return expr; 244 245 out_err_overflow: 246 free(expr); 247 return NULL; 248 } 249 250 /* Like strpbrk(), but not break if it is right after a backslash (escaped) */ 251 char *strpbrk_esc(char *str, const char *stopset) 252 { 253 char *ptr; 254 255 do { 256 ptr = strpbrk(str, stopset); 257 if (ptr == str || 258 (ptr == str + 1 && *(ptr - 1) != '\\')) 259 break; 260 str = ptr + 1; 261 } while (ptr && *(ptr - 1) == '\\' && *(ptr - 2) != '\\'); 262 263 return ptr; 264 } 265 266 /* Like strdup, but do not copy a single backslash */ 267 char *strdup_esc(const char *str) 268 { 269 char *s, *d, *p, *ret = strdup(str); 270 271 if (!ret) 272 return NULL; 273 274 d = strchr(ret, '\\'); 275 if (!d) 276 return ret; 277 278 s = d + 1; 279 do { 280 if (*s == '\0') { 281 *d = '\0'; 282 break; 283 } 284 p = strchr(s + 1, '\\'); 285 if (p) { 286 memmove(d, s, p - s); 287 d += p - s; 288 s = p + 1; 289 } else 290 memmove(d, s, strlen(s) + 1); 291 } while (p); 292 293 return ret; 294 } 295 296 unsigned int hex(char c) 297 { 298 if (c >= '0' && c <= '9') 299 return c - '0'; 300 if (c >= 'a' && c <= 'f') 301 return c - 'a' + 10; 302 return c - 'A' + 10; 303 } 304 305 /* 306 * Replace all occurrences of character 'needle' in string 'haystack' with 307 * string 'replace' 308 * 309 * The new string could be longer so a new string is returned which must be 310 * freed. 311 */ 312 char *strreplace_chars(char needle, const char *haystack, const char *replace) 313 { 314 int replace_len = strlen(replace); 315 char *new_s, *to; 316 const char *loc = strchr(haystack, needle); 317 const char *from = haystack; 318 int num = 0; 319 320 /* Count occurrences */ 321 while (loc) { 322 loc = strchr(loc + 1, needle); 323 num++; 324 } 325 326 /* Allocate enough space for replacements and reset first location */ 327 new_s = malloc(strlen(haystack) + (num * (replace_len - 1) + 1)); 328 if (!new_s) 329 return NULL; 330 loc = strchr(haystack, needle); 331 to = new_s; 332 333 while (loc) { 334 /* Copy original string up to found char and update positions */ 335 memcpy(to, from, 1 + loc - from); 336 to += loc - from; 337 from = loc + 1; 338 339 /* Copy replacement string and update positions */ 340 memcpy(to, replace, replace_len); 341 to += replace_len; 342 343 /* needle next occurrence or end of string */ 344 loc = strchr(from, needle); 345 } 346 347 /* Copy any remaining chars + null */ 348 strcpy(to, from); 349 350 return new_s; 351 } 352