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