tools perf: Move from sane_ctype.h obtained from git to the Linux's original
[linux-2.6-microblaze.git] / tools / perf / util / string.c
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 /*
73  * Helper function for splitting a string into an argv-like array.
74  * originally copied from lib/argv_split.c
75  */
76 static const char *skip_sep(const char *cp)
77 {
78         while (*cp && isspace(*cp))
79                 cp++;
80
81         return cp;
82 }
83
84 static const char *skip_arg(const char *cp)
85 {
86         while (*cp && !isspace(*cp))
87                 cp++;
88
89         return cp;
90 }
91
92 static int count_argc(const char *str)
93 {
94         int count = 0;
95
96         while (*str) {
97                 str = skip_sep(str);
98                 if (*str) {
99                         count++;
100                         str = skip_arg(str);
101                 }
102         }
103
104         return count;
105 }
106
107 /**
108  * argv_free - free an argv
109  * @argv - the argument vector to be freed
110  *
111  * Frees an argv and the strings it points to.
112  */
113 void argv_free(char **argv)
114 {
115         char **p;
116         for (p = argv; *p; p++) {
117                 free(*p);
118                 *p = NULL;
119         }
120
121         free(argv);
122 }
123
124 /**
125  * argv_split - split a string at whitespace, returning an argv
126  * @str: the string to be split
127  * @argcp: returned argument count
128  *
129  * Returns an array of pointers to strings which are split out from
130  * @str.  This is performed by strictly splitting on white-space; no
131  * quote processing is performed.  Multiple whitespace characters are
132  * considered to be a single argument separator.  The returned array
133  * is always NULL-terminated.  Returns NULL on memory allocation
134  * failure.
135  */
136 char **argv_split(const char *str, int *argcp)
137 {
138         int argc = count_argc(str);
139         char **argv = calloc(argc + 1, sizeof(*argv));
140         char **argvp;
141
142         if (argv == NULL)
143                 goto out;
144
145         if (argcp)
146                 *argcp = argc;
147
148         argvp = argv;
149
150         while (*str) {
151                 str = skip_sep(str);
152
153                 if (*str) {
154                         const char *p = str;
155                         char *t;
156
157                         str = skip_arg(str);
158
159                         t = strndup(p, str-p);
160                         if (t == NULL)
161                                 goto fail;
162                         *argvp++ = t;
163                 }
164         }
165         *argvp = NULL;
166
167 out:
168         return argv;
169
170 fail:
171         argv_free(argv);
172         return NULL;
173 }
174
175 /* Character class matching */
176 static bool __match_charclass(const char *pat, char c, const char **npat)
177 {
178         bool complement = false, ret = true;
179
180         if (*pat == '!') {
181                 complement = true;
182                 pat++;
183         }
184         if (*pat++ == c)        /* First character is special */
185                 goto end;
186
187         while (*pat && *pat != ']') {   /* Matching */
188                 if (*pat == '-' && *(pat + 1) != ']') { /* Range */
189                         if (*(pat - 1) <= c && c <= *(pat + 1))
190                                 goto end;
191                         if (*(pat - 1) > *(pat + 1))
192                                 goto error;
193                         pat += 2;
194                 } else if (*pat++ == c)
195                         goto end;
196         }
197         if (!*pat)
198                 goto error;
199         ret = false;
200
201 end:
202         while (*pat && *pat != ']')     /* Searching closing */
203                 pat++;
204         if (!*pat)
205                 goto error;
206         *npat = pat + 1;
207         return complement ? !ret : ret;
208
209 error:
210         return false;
211 }
212
213 /* Glob/lazy pattern matching */
214 static bool __match_glob(const char *str, const char *pat, bool ignore_space,
215                         bool case_ins)
216 {
217         while (*str && *pat && *pat != '*') {
218                 if (ignore_space) {
219                         /* Ignore spaces for lazy matching */
220                         if (isspace(*str)) {
221                                 str++;
222                                 continue;
223                         }
224                         if (isspace(*pat)) {
225                                 pat++;
226                                 continue;
227                         }
228                 }
229                 if (*pat == '?') {      /* Matches any single character */
230                         str++;
231                         pat++;
232                         continue;
233                 } else if (*pat == '[') /* Character classes/Ranges */
234                         if (__match_charclass(pat + 1, *str, &pat)) {
235                                 str++;
236                                 continue;
237                         } else
238                                 return false;
239                 else if (*pat == '\\') /* Escaped char match as normal char */
240                         pat++;
241                 if (case_ins) {
242                         if (tolower(*str) != tolower(*pat))
243                                 return false;
244                 } else if (*str != *pat)
245                         return false;
246                 str++;
247                 pat++;
248         }
249         /* Check wild card */
250         if (*pat == '*') {
251                 while (*pat == '*')
252                         pat++;
253                 if (!*pat)      /* Tail wild card matches all */
254                         return true;
255                 while (*str)
256                         if (__match_glob(str++, pat, ignore_space, case_ins))
257                                 return true;
258         }
259         return !*str && !*pat;
260 }
261
262 /**
263  * strglobmatch - glob expression pattern matching
264  * @str: the target string to match
265  * @pat: the pattern string to match
266  *
267  * This returns true if the @str matches @pat. @pat can includes wildcards
268  * ('*','?') and character classes ([CHARS], complementation and ranges are
269  * also supported). Also, this supports escape character ('\') to use special
270  * characters as normal character.
271  *
272  * Note: if @pat syntax is broken, this always returns false.
273  */
274 bool strglobmatch(const char *str, const char *pat)
275 {
276         return __match_glob(str, pat, false, false);
277 }
278
279 bool strglobmatch_nocase(const char *str, const char *pat)
280 {
281         return __match_glob(str, pat, false, true);
282 }
283
284 /**
285  * strlazymatch - matching pattern strings lazily with glob pattern
286  * @str: the target string to match
287  * @pat: the pattern string to match
288  *
289  * This is similar to strglobmatch, except this ignores spaces in
290  * the target string.
291  */
292 bool strlazymatch(const char *str, const char *pat)
293 {
294         return __match_glob(str, pat, true, false);
295 }
296
297 /**
298  * strtailcmp - Compare the tail of two strings
299  * @s1: 1st string to be compared
300  * @s2: 2nd string to be compared
301  *
302  * Return 0 if whole of either string is same as another's tail part.
303  */
304 int strtailcmp(const char *s1, const char *s2)
305 {
306         int i1 = strlen(s1);
307         int i2 = strlen(s2);
308         while (--i1 >= 0 && --i2 >= 0) {
309                 if (s1[i1] != s2[i2])
310                         return s1[i1] - s2[i2];
311         }
312         return 0;
313 }
314
315 /**
316  * strxfrchar - Locate and replace character in @s
317  * @s:    The string to be searched/changed.
318  * @from: Source character to be replaced.
319  * @to:   Destination character.
320  *
321  * Return pointer to the changed string.
322  */
323 char *strxfrchar(char *s, char from, char to)
324 {
325         char *p = s;
326
327         while ((p = strchr(p, from)) != NULL)
328                 *p++ = to;
329
330         return s;
331 }
332
333 /**
334  * ltrim - Removes leading whitespace from @s.
335  * @s: The string to be stripped.
336  *
337  * Return pointer to the first non-whitespace character in @s.
338  */
339 char *ltrim(char *s)
340 {
341         while (isspace(*s))
342                 s++;
343
344         return s;
345 }
346
347 /**
348  * rtrim - Removes trailing whitespace from @s.
349  * @s: The string to be stripped.
350  *
351  * Note that the first trailing whitespace is replaced with a %NUL-terminator
352  * in the given string @s. Returns @s.
353  */
354 char *rtrim(char *s)
355 {
356         size_t size = strlen(s);
357         char *end;
358
359         if (!size)
360                 return s;
361
362         end = s + size - 1;
363         while (end >= s && isspace(*end))
364                 end--;
365         *(end + 1) = '\0';
366
367         return s;
368 }
369
370 char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
371 {
372         /*
373          * FIXME: replace this with an expression using log10() when we
374          * find a suitable implementation, maybe the one in the dvb drivers...
375          *
376          * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators
377          */
378         size_t size = nints * 28 + 1; /* \0 */
379         size_t i, printed = 0;
380         char *expr = malloc(size);
381
382         if (expr) {
383                 const char *or_and = "||", *eq_neq = "==";
384                 char *e = expr;
385
386                 if (!in) {
387                         or_and = "&&";
388                         eq_neq = "!=";
389                 }
390
391                 for (i = 0; i < nints; ++i) {
392                         if (printed == size)
393                                 goto out_err_overflow;
394
395                         if (i > 0)
396                                 printed += scnprintf(e + printed, size - printed, " %s ", or_and);
397                         printed += scnprintf(e + printed, size - printed,
398                                              "%s %s %d", var, eq_neq, ints[i]);
399                 }
400         }
401
402         return expr;
403
404 out_err_overflow:
405         free(expr);
406         return NULL;
407 }
408
409 /* Like strpbrk(), but not break if it is right after a backslash (escaped) */
410 char *strpbrk_esc(char *str, const char *stopset)
411 {
412         char *ptr;
413
414         do {
415                 ptr = strpbrk(str, stopset);
416                 if (ptr == str ||
417                     (ptr == str + 1 && *(ptr - 1) != '\\'))
418                         break;
419                 str = ptr + 1;
420         } while (ptr && *(ptr - 1) == '\\' && *(ptr - 2) != '\\');
421
422         return ptr;
423 }
424
425 /* Like strdup, but do not copy a single backslash */
426 char *strdup_esc(const char *str)
427 {
428         char *s, *d, *p, *ret = strdup(str);
429
430         if (!ret)
431                 return NULL;
432
433         d = strchr(ret, '\\');
434         if (!d)
435                 return ret;
436
437         s = d + 1;
438         do {
439                 if (*s == '\0') {
440                         *d = '\0';
441                         break;
442                 }
443                 p = strchr(s + 1, '\\');
444                 if (p) {
445                         memmove(d, s, p - s);
446                         d += p - s;
447                         s = p + 1;
448                 } else
449                         memmove(d, s, strlen(s) + 1);
450         } while (p);
451
452         return ret;
453 }