root/tools/perf/util/string.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. perf_atoll
  2. __match_charclass
  3. __match_glob
  4. strglobmatch
  5. strglobmatch_nocase
  6. strlazymatch
  7. strtailcmp
  8. asprintf_expr_inout_ints
  9. strpbrk_esc
  10. strdup_esc

   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 #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  */
  24 s64 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 
  68 out_err:
  69         return -1;
  70 }
  71 
  72 /* Character class matching */
  73 static 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 
  98 end:
  99         while (*pat && *pat != ']')     /* Searching closing */
 100                 pat++;
 101         if (!*pat)
 102                 goto error;
 103         *npat = pat + 1;
 104         return complement ? !ret : ret;
 105 
 106 error:
 107         return false;
 108 }
 109 
 110 /* Glob/lazy pattern matching */
 111 static 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  */
 171 bool strglobmatch(const char *str, const char *pat)
 172 {
 173         return __match_glob(str, pat, false, false);
 174 }
 175 
 176 bool 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  */
 189 bool 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  */
 201 int 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 
 212 char *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 
 246 out_err_overflow:
 247         free(expr);
 248         return NULL;
 249 }
 250 
 251 /* Like strpbrk(), but not break if it is right after a backslash (escaped) */
 252 char *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 */
 268 char *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 }

/* [<][>][^][v][top][bottom][index][help] */