Linux Perf
string.c
Go to the documentation of this file.
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 "sane_ctype.h"
8 
9 #define K 1024LL
10 /*
11  * perf_atoll()
12  * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
13  * and return its numeric value
14  */
15 s64 perf_atoll(const char *str)
16 {
17  s64 length;
18  char *p;
19  char c;
20 
21  if (!isdigit(str[0]))
22  goto out_err;
23 
24  length = strtoll(str, &p, 10);
25  switch (c = *p++) {
26  case 'b': case 'B':
27  if (*p)
28  goto out_err;
29 
30  __fallthrough;
31  case '\0':
32  return length;
33  default:
34  goto out_err;
35  /* two-letter suffices */
36  case 'k': case 'K':
37  length <<= 10;
38  break;
39  case 'm': case 'M':
40  length <<= 20;
41  break;
42  case 'g': case 'G':
43  length <<= 30;
44  break;
45  case 't': case 'T':
46  length <<= 40;
47  break;
48  }
49  /* we want the cases to match */
50  if (islower(c)) {
51  if (strcmp(p, "b") != 0)
52  goto out_err;
53  } else {
54  if (strcmp(p, "B") != 0)
55  goto out_err;
56  }
57  return length;
58 
59 out_err:
60  return -1;
61 }
62 
63 /*
64  * Helper function for splitting a string into an argv-like array.
65  * originally copied from lib/argv_split.c
66  */
67 static const char *skip_sep(const char *cp)
68 {
69  while (*cp && isspace(*cp))
70  cp++;
71 
72  return cp;
73 }
74 
75 static const char *skip_arg(const char *cp)
76 {
77  while (*cp && !isspace(*cp))
78  cp++;
79 
80  return cp;
81 }
82 
83 static int count_argc(const char *str)
84 {
85  int count = 0;
86 
87  while (*str) {
88  str = skip_sep(str);
89  if (*str) {
90  count++;
91  str = skip_arg(str);
92  }
93  }
94 
95  return count;
96 }
97 
104 void argv_free(char **argv)
105 {
106  char **p;
107  for (p = argv; *p; p++) {
108  free(*p);
109  *p = NULL;
110  }
111 
112  free(argv);
113 }
114 
127 char **argv_split(const char *str, int *argcp)
128 {
129  int argc = count_argc(str);
130  char **argv = calloc(argc + 1, sizeof(*argv));
131  char **argvp;
132 
133  if (argv == NULL)
134  goto out;
135 
136  if (argcp)
137  *argcp = argc;
138 
139  argvp = argv;
140 
141  while (*str) {
142  str = skip_sep(str);
143 
144  if (*str) {
145  const char *p = str;
146  char *t;
147 
148  str = skip_arg(str);
149 
150  t = strndup(p, str-p);
151  if (t == NULL)
152  goto fail;
153  *argvp++ = t;
154  }
155  }
156  *argvp = NULL;
157 
158 out:
159  return argv;
160 
161 fail:
162  argv_free(argv);
163  return NULL;
164 }
165 
166 /* Character class matching */
167 static bool __match_charclass(const char *pat, char c, const char **npat)
168 {
169  bool complement = false, ret = true;
170 
171  if (*pat == '!') {
172  complement = true;
173  pat++;
174  }
175  if (*pat++ == c) /* First character is special */
176  goto end;
177 
178  while (*pat && *pat != ']') { /* Matching */
179  if (*pat == '-' && *(pat + 1) != ']') { /* Range */
180  if (*(pat - 1) <= c && c <= *(pat + 1))
181  goto end;
182  if (*(pat - 1) > *(pat + 1))
183  goto error;
184  pat += 2;
185  } else if (*pat++ == c)
186  goto end;
187  }
188  if (!*pat)
189  goto error;
190  ret = false;
191 
192 end:
193  while (*pat && *pat != ']') /* Searching closing */
194  pat++;
195  if (!*pat)
196  goto error;
197  *npat = pat + 1;
198  return complement ? !ret : ret;
199 
200 error:
201  return false;
202 }
203 
204 /* Glob/lazy pattern matching */
205 static bool __match_glob(const char *str, const char *pat, bool ignore_space,
206  bool case_ins)
207 {
208  while (*str && *pat && *pat != '*') {
209  if (ignore_space) {
210  /* Ignore spaces for lazy matching */
211  if (isspace(*str)) {
212  str++;
213  continue;
214  }
215  if (isspace(*pat)) {
216  pat++;
217  continue;
218  }
219  }
220  if (*pat == '?') { /* Matches any single character */
221  str++;
222  pat++;
223  continue;
224  } else if (*pat == '[') /* Character classes/Ranges */
225  if (__match_charclass(pat + 1, *str, &pat)) {
226  str++;
227  continue;
228  } else
229  return false;
230  else if (*pat == '\\') /* Escaped char match as normal char */
231  pat++;
232  if (case_ins) {
233  if (tolower(*str) != tolower(*pat))
234  return false;
235  } else if (*str != *pat)
236  return false;
237  str++;
238  pat++;
239  }
240  /* Check wild card */
241  if (*pat == '*') {
242  while (*pat == '*')
243  pat++;
244  if (!*pat) /* Tail wild card matches all */
245  return true;
246  while (*str)
247  if (__match_glob(str++, pat, ignore_space, case_ins))
248  return true;
249  }
250  return !*str && !*pat;
251 }
252 
265 bool strglobmatch(const char *str, const char *pat)
266 {
267  return __match_glob(str, pat, false, false);
268 }
269 
270 bool strglobmatch_nocase(const char *str, const char *pat)
271 {
272  return __match_glob(str, pat, false, true);
273 }
274 
283 bool strlazymatch(const char *str, const char *pat)
284 {
285  return __match_glob(str, pat, true, false);
286 }
287 
295 int strtailcmp(const char *s1, const char *s2)
296 {
297  int i1 = strlen(s1);
298  int i2 = strlen(s2);
299  while (--i1 >= 0 && --i2 >= 0) {
300  if (s1[i1] != s2[i2])
301  return s1[i1] - s2[i2];
302  }
303  return 0;
304 }
305 
314 char *strxfrchar(char *s, char from, char to)
315 {
316  char *p = s;
317 
318  while ((p = strchr(p, from)) != NULL)
319  *p++ = to;
320 
321  return s;
322 }
323 
330 char *ltrim(char *s)
331 {
332  while (isspace(*s))
333  s++;
334 
335  return s;
336 }
337 
345 char *rtrim(char *s)
346 {
347  size_t size = strlen(s);
348  char *end;
349 
350  if (!size)
351  return s;
352 
353  end = s + size - 1;
354  while (end >= s && isspace(*end))
355  end--;
356  *(end + 1) = '\0';
357 
358  return s;
359 }
360 
361 char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
362 {
363  /*
364  * FIXME: replace this with an expression using log10() when we
365  * find a suitable implementation, maybe the one in the dvb drivers...
366  *
367  * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators
368  */
369  size_t size = nints * 28 + 1; /* \0 */
370  size_t i, printed = 0;
371  char *expr = malloc(size);
372 
373  if (expr) {
374  const char *or_and = "||", *eq_neq = "==";
375  char *e = expr;
376 
377  if (!in) {
378  or_and = "&&";
379  eq_neq = "!=";
380  }
381 
382  for (i = 0; i < nints; ++i) {
383  if (printed == size)
384  goto out_err_overflow;
385 
386  if (i > 0)
387  printed += scnprintf(e + printed, size - printed, " %s ", or_and);
388  printed += scnprintf(e + printed, size - printed,
389  "%s %s %d", var, eq_neq, ints[i]);
390  }
391  }
392 
393  return expr;
394 
395 out_err_overflow:
396  free(expr);
397  return NULL;
398 }
399 
400 /* Like strpbrk(), but not break if it is right after a backslash (escaped) */
401 char *strpbrk_esc(char *str, const char *stopset)
402 {
403  char *ptr;
404 
405  do {
406  ptr = strpbrk(str, stopset);
407  if (ptr == str ||
408  (ptr == str + 1 && *(ptr - 1) != '\\'))
409  break;
410  str = ptr + 1;
411  } while (ptr && *(ptr - 1) == '\\' && *(ptr - 2) != '\\');
412 
413  return ptr;
414 }
415 
416 /* Like strdup, but do not copy a single backslash */
417 char *strdup_esc(const char *str)
418 {
419  char *s, *d, *p, *ret = strdup(str);
420 
421  if (!ret)
422  return NULL;
423 
424  d = strchr(ret, '\\');
425  if (!d)
426  return ret;
427 
428  s = d + 1;
429  do {
430  if (*s == '\0') {
431  *d = '\0';
432  break;
433  }
434  p = strchr(s + 1, '\\');
435  if (p) {
436  memmove(d, s, p - s);
437  d += p - s;
438  s = p + 1;
439  } else
440  memmove(d, s, strlen(s) + 1);
441  } while (p);
442 
443  return ret;
444 }
size_t size
Definition: evsel.c:60
#define isspace(x)
Definition: sane_ctype.h:33
void argv_free(char **argv)
Definition: string.c:104
bool strglobmatch(const char *str, const char *pat)
Definition: string.c:265
char * ltrim(char *s)
Definition: string.c:330
s64 perf_atoll(const char *str)
Definition: string.c:15
void * malloc(YYSIZE_T)
char * rtrim(char *s)
Definition: string.c:345
static const char * skip_sep(const char *cp)
Definition: string.c:67
static bool __match_charclass(const char *pat, char c, const char **npat)
Definition: string.c:167
static int str(yyscan_t scanner, int token)
char * strxfrchar(char *s, char from, char to)
Definition: string.c:314
static bool __match_glob(const char *str, const char *pat, bool ignore_space, bool case_ins)
Definition: string.c:205
char * strpbrk_esc(char *str, const char *stopset)
Definition: string.c:401
static int count_argc(const char *str)
Definition: string.c:83
static const char * skip_arg(const char *cp)
Definition: string.c:75
bool strglobmatch_nocase(const char *str, const char *pat)
Definition: string.c:270
int strtailcmp(const char *s1, const char *s2)
Definition: string.c:295
bool strlazymatch(const char *str, const char *pat)
Definition: string.c:283
void free(void *)
#define islower(x)
Definition: sane_ctype.h:40
char * asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
Definition: string.c:361
#define isdigit(x)
Definition: sane_ctype.h:34
char * strdup_esc(const char *str)
Definition: string.c:417
#define tolower(x)
Definition: sane_ctype.h:42
char ** argv_split(const char *str, int *argcp)
Definition: string.c:127