1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2a067558eSArnaldo Carvalho de Melo #include "string2.h"
3a067558eSArnaldo Carvalho de Melo #include <linux/kernel.h>
4a067558eSArnaldo Carvalho de Melo #include <linux/string.h>
5a067558eSArnaldo Carvalho de Melo #include <stdlib.h>
686470930SIngo Molnar
73052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h>
83d689ed6SArnaldo Carvalho de Melo
96a9fa4e3SArnaldo Carvalho de Melo const char *graph_dotted_line =
106a9fa4e3SArnaldo Carvalho de Melo "---------------------------------------------------------------------"
116a9fa4e3SArnaldo Carvalho de Melo "---------------------------------------------------------------------"
126a9fa4e3SArnaldo Carvalho de Melo "---------------------------------------------------------------------";
136a9fa4e3SArnaldo Carvalho de Melo const char *dots =
146a9fa4e3SArnaldo Carvalho de Melo "....................................................................."
156a9fa4e3SArnaldo Carvalho de Melo "....................................................................."
166a9fa4e3SArnaldo Carvalho de Melo ".....................................................................";
176a9fa4e3SArnaldo Carvalho de Melo
18d2fb8b41SHitoshi Mitake /*
19d2fb8b41SHitoshi Mitake * perf_atoll()
20d2fb8b41SHitoshi Mitake * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
21d2fb8b41SHitoshi Mitake * and return its numeric value
22d2fb8b41SHitoshi Mitake */
perf_atoll(const char * str)23d2fb8b41SHitoshi Mitake s64 perf_atoll(const char *str)
24d2fb8b41SHitoshi Mitake {
258ba7f6c2SAl Viro s64 length;
268ba7f6c2SAl Viro char *p;
278ba7f6c2SAl Viro char c;
28d2fb8b41SHitoshi Mitake
29d2fb8b41SHitoshi Mitake if (!isdigit(str[0]))
30d2fb8b41SHitoshi Mitake goto out_err;
31d2fb8b41SHitoshi Mitake
328ba7f6c2SAl Viro length = strtoll(str, &p, 10);
338ba7f6c2SAl Viro switch (c = *p++) {
348ba7f6c2SAl Viro case 'b': case 'B':
358ba7f6c2SAl Viro if (*p)
36d2fb8b41SHitoshi Mitake goto out_err;
3794bdd5edSArnaldo Carvalho de Melo
38f7a858bfSLiam Howlett fallthrough;
398ba7f6c2SAl Viro case '\0':
408ba7f6c2SAl Viro return length;
41d2fb8b41SHitoshi Mitake default:
42d2fb8b41SHitoshi Mitake goto out_err;
438ba7f6c2SAl Viro /* two-letter suffices */
448ba7f6c2SAl Viro case 'k': case 'K':
458ba7f6c2SAl Viro length <<= 10;
468ba7f6c2SAl Viro break;
478ba7f6c2SAl Viro case 'm': case 'M':
488ba7f6c2SAl Viro length <<= 20;
498ba7f6c2SAl Viro break;
508ba7f6c2SAl Viro case 'g': case 'G':
518ba7f6c2SAl Viro length <<= 30;
528ba7f6c2SAl Viro break;
538ba7f6c2SAl Viro case 't': case 'T':
548ba7f6c2SAl Viro length <<= 40;
55d2fb8b41SHitoshi Mitake break;
56d2fb8b41SHitoshi Mitake }
578ba7f6c2SAl Viro /* we want the cases to match */
588ba7f6c2SAl Viro if (islower(c)) {
598ba7f6c2SAl Viro if (strcmp(p, "b") != 0)
608ba7f6c2SAl Viro goto out_err;
618ba7f6c2SAl Viro } else {
628ba7f6c2SAl Viro if (strcmp(p, "B") != 0)
638ba7f6c2SAl Viro goto out_err;
64d2fb8b41SHitoshi Mitake }
658ba7f6c2SAl Viro return length;
66d2fb8b41SHitoshi Mitake
67d2fb8b41SHitoshi Mitake out_err:
688ba7f6c2SAl Viro return -1;
69d2fb8b41SHitoshi Mitake }
70e1c01d61SMasami Hiramatsu
716964cd2cSMasami Hiramatsu /* Character class matching */
__match_charclass(const char * pat,char c,const char ** npat)726964cd2cSMasami Hiramatsu static bool __match_charclass(const char *pat, char c, const char **npat)
736964cd2cSMasami Hiramatsu {
746964cd2cSMasami Hiramatsu bool complement = false, ret = true;
756964cd2cSMasami Hiramatsu
766964cd2cSMasami Hiramatsu if (*pat == '!') {
776964cd2cSMasami Hiramatsu complement = true;
786964cd2cSMasami Hiramatsu pat++;
796964cd2cSMasami Hiramatsu }
806964cd2cSMasami Hiramatsu if (*pat++ == c) /* First character is special */
816964cd2cSMasami Hiramatsu goto end;
826964cd2cSMasami Hiramatsu
836964cd2cSMasami Hiramatsu while (*pat && *pat != ']') { /* Matching */
846964cd2cSMasami Hiramatsu if (*pat == '-' && *(pat + 1) != ']') { /* Range */
856964cd2cSMasami Hiramatsu if (*(pat - 1) <= c && c <= *(pat + 1))
866964cd2cSMasami Hiramatsu goto end;
876964cd2cSMasami Hiramatsu if (*(pat - 1) > *(pat + 1))
886964cd2cSMasami Hiramatsu goto error;
896964cd2cSMasami Hiramatsu pat += 2;
906964cd2cSMasami Hiramatsu } else if (*pat++ == c)
916964cd2cSMasami Hiramatsu goto end;
926964cd2cSMasami Hiramatsu }
936964cd2cSMasami Hiramatsu if (!*pat)
946964cd2cSMasami Hiramatsu goto error;
956964cd2cSMasami Hiramatsu ret = false;
966964cd2cSMasami Hiramatsu
976964cd2cSMasami Hiramatsu end:
986964cd2cSMasami Hiramatsu while (*pat && *pat != ']') /* Searching closing */
996964cd2cSMasami Hiramatsu pat++;
1006964cd2cSMasami Hiramatsu if (!*pat)
1016964cd2cSMasami Hiramatsu goto error;
1026964cd2cSMasami Hiramatsu *npat = pat + 1;
1036964cd2cSMasami Hiramatsu return complement ? !ret : ret;
1046964cd2cSMasami Hiramatsu
1056964cd2cSMasami Hiramatsu error:
1066964cd2cSMasami Hiramatsu return false;
1076964cd2cSMasami Hiramatsu }
1086964cd2cSMasami Hiramatsu
1092a9c8c36SMasami Hiramatsu /* Glob/lazy pattern matching */
__match_glob(const char * str,const char * pat,bool ignore_space,bool case_ins)11038d14f0cSAndi Kleen static bool __match_glob(const char *str, const char *pat, bool ignore_space,
11138d14f0cSAndi Kleen bool case_ins)
112bbbb521bSMasami Hiramatsu {
113bbbb521bSMasami Hiramatsu while (*str && *pat && *pat != '*') {
1142a9c8c36SMasami Hiramatsu if (ignore_space) {
1152a9c8c36SMasami Hiramatsu /* Ignore spaces for lazy matching */
1162a9c8c36SMasami Hiramatsu if (isspace(*str)) {
1172a9c8c36SMasami Hiramatsu str++;
1182a9c8c36SMasami Hiramatsu continue;
1192a9c8c36SMasami Hiramatsu }
1202a9c8c36SMasami Hiramatsu if (isspace(*pat)) {
1212a9c8c36SMasami Hiramatsu pat++;
1222a9c8c36SMasami Hiramatsu continue;
1232a9c8c36SMasami Hiramatsu }
1242a9c8c36SMasami Hiramatsu }
1256964cd2cSMasami Hiramatsu if (*pat == '?') { /* Matches any single character */
126bbbb521bSMasami Hiramatsu str++;
127bbbb521bSMasami Hiramatsu pat++;
1286964cd2cSMasami Hiramatsu continue;
1296964cd2cSMasami Hiramatsu } else if (*pat == '[') /* Character classes/Ranges */
1306964cd2cSMasami Hiramatsu if (__match_charclass(pat + 1, *str, &pat)) {
1316964cd2cSMasami Hiramatsu str++;
1326964cd2cSMasami Hiramatsu continue;
133bbbb521bSMasami Hiramatsu } else
1346964cd2cSMasami Hiramatsu return false;
1356964cd2cSMasami Hiramatsu else if (*pat == '\\') /* Escaped char match as normal char */
1366964cd2cSMasami Hiramatsu pat++;
13738d14f0cSAndi Kleen if (case_ins) {
13838d14f0cSAndi Kleen if (tolower(*str) != tolower(*pat))
139bbbb521bSMasami Hiramatsu return false;
14038d14f0cSAndi Kleen } else if (*str != *pat)
14138d14f0cSAndi Kleen return false;
14238d14f0cSAndi Kleen str++;
14338d14f0cSAndi Kleen pat++;
144bbbb521bSMasami Hiramatsu }
145bbbb521bSMasami Hiramatsu /* Check wild card */
146bbbb521bSMasami Hiramatsu if (*pat == '*') {
147bbbb521bSMasami Hiramatsu while (*pat == '*')
148bbbb521bSMasami Hiramatsu pat++;
149bbbb521bSMasami Hiramatsu if (!*pat) /* Tail wild card matches all */
150bbbb521bSMasami Hiramatsu return true;
151bbbb521bSMasami Hiramatsu while (*str)
15238d14f0cSAndi Kleen if (__match_glob(str++, pat, ignore_space, case_ins))
153bbbb521bSMasami Hiramatsu return true;
154bbbb521bSMasami Hiramatsu }
155bbbb521bSMasami Hiramatsu return !*str && !*pat;
156bbbb521bSMasami Hiramatsu }
157bbbb521bSMasami Hiramatsu
1582a9c8c36SMasami Hiramatsu /**
1592a9c8c36SMasami Hiramatsu * strglobmatch - glob expression pattern matching
1602a9c8c36SMasami Hiramatsu * @str: the target string to match
1612a9c8c36SMasami Hiramatsu * @pat: the pattern string to match
1622a9c8c36SMasami Hiramatsu *
1632a9c8c36SMasami Hiramatsu * This returns true if the @str matches @pat. @pat can includes wildcards
1642a9c8c36SMasami Hiramatsu * ('*','?') and character classes ([CHARS], complementation and ranges are
1652a9c8c36SMasami Hiramatsu * also supported). Also, this supports escape character ('\') to use special
1662a9c8c36SMasami Hiramatsu * characters as normal character.
1672a9c8c36SMasami Hiramatsu *
1682a9c8c36SMasami Hiramatsu * Note: if @pat syntax is broken, this always returns false.
1692a9c8c36SMasami Hiramatsu */
strglobmatch(const char * str,const char * pat)1702a9c8c36SMasami Hiramatsu bool strglobmatch(const char *str, const char *pat)
1712a9c8c36SMasami Hiramatsu {
17238d14f0cSAndi Kleen return __match_glob(str, pat, false, false);
17338d14f0cSAndi Kleen }
17438d14f0cSAndi Kleen
strglobmatch_nocase(const char * str,const char * pat)17538d14f0cSAndi Kleen bool strglobmatch_nocase(const char *str, const char *pat)
17638d14f0cSAndi Kleen {
17738d14f0cSAndi Kleen return __match_glob(str, pat, false, true);
1782a9c8c36SMasami Hiramatsu }
1792a9c8c36SMasami Hiramatsu
1802a9c8c36SMasami Hiramatsu /**
1812a9c8c36SMasami Hiramatsu * strlazymatch - matching pattern strings lazily with glob pattern
1822a9c8c36SMasami Hiramatsu * @str: the target string to match
1832a9c8c36SMasami Hiramatsu * @pat: the pattern string to match
1842a9c8c36SMasami Hiramatsu *
1852a9c8c36SMasami Hiramatsu * This is similar to strglobmatch, except this ignores spaces in
1862a9c8c36SMasami Hiramatsu * the target string.
1872a9c8c36SMasami Hiramatsu */
strlazymatch(const char * str,const char * pat)1882a9c8c36SMasami Hiramatsu bool strlazymatch(const char *str, const char *pat)
1892a9c8c36SMasami Hiramatsu {
19038d14f0cSAndi Kleen return __match_glob(str, pat, true, false);
1912a9c8c36SMasami Hiramatsu }
192bad03ae4SMasami Hiramatsu
193bad03ae4SMasami Hiramatsu /**
194bad03ae4SMasami Hiramatsu * strtailcmp - Compare the tail of two strings
195bad03ae4SMasami Hiramatsu * @s1: 1st string to be compared
196bad03ae4SMasami Hiramatsu * @s2: 2nd string to be compared
197bad03ae4SMasami Hiramatsu *
198bad03ae4SMasami Hiramatsu * Return 0 if whole of either string is same as another's tail part.
199bad03ae4SMasami Hiramatsu */
strtailcmp(const char * s1,const char * s2)200bad03ae4SMasami Hiramatsu int strtailcmp(const char *s1, const char *s2)
201bad03ae4SMasami Hiramatsu {
202bad03ae4SMasami Hiramatsu int i1 = strlen(s1);
203bad03ae4SMasami Hiramatsu int i2 = strlen(s2);
204bad03ae4SMasami Hiramatsu while (--i1 >= 0 && --i2 >= 0) {
205bad03ae4SMasami Hiramatsu if (s1[i1] != s2[i2])
206bad03ae4SMasami Hiramatsu return s1[i1] - s2[i2];
207bad03ae4SMasami Hiramatsu }
208bad03ae4SMasami Hiramatsu return 0;
209bad03ae4SMasami Hiramatsu }
210bad03ae4SMasami Hiramatsu
asprintf_expr_inout_ints(const char * var,bool in,size_t nints,int * ints)21193ec4ce7SArnaldo Carvalho de Melo char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
21293ec4ce7SArnaldo Carvalho de Melo {
21393ec4ce7SArnaldo Carvalho de Melo /*
21493ec4ce7SArnaldo Carvalho de Melo * FIXME: replace this with an expression using log10() when we
21593ec4ce7SArnaldo Carvalho de Melo * find a suitable implementation, maybe the one in the dvb drivers...
21693ec4ce7SArnaldo Carvalho de Melo *
21793ec4ce7SArnaldo Carvalho de Melo * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators
21893ec4ce7SArnaldo Carvalho de Melo */
21993ec4ce7SArnaldo Carvalho de Melo size_t size = nints * 28 + 1; /* \0 */
22093ec4ce7SArnaldo Carvalho de Melo size_t i, printed = 0;
22193ec4ce7SArnaldo Carvalho de Melo char *expr = malloc(size);
22293ec4ce7SArnaldo Carvalho de Melo
22393ec4ce7SArnaldo Carvalho de Melo if (expr) {
22493ec4ce7SArnaldo Carvalho de Melo const char *or_and = "||", *eq_neq = "==";
22593ec4ce7SArnaldo Carvalho de Melo char *e = expr;
22693ec4ce7SArnaldo Carvalho de Melo
22793ec4ce7SArnaldo Carvalho de Melo if (!in) {
22893ec4ce7SArnaldo Carvalho de Melo or_and = "&&";
22993ec4ce7SArnaldo Carvalho de Melo eq_neq = "!=";
23093ec4ce7SArnaldo Carvalho de Melo }
23193ec4ce7SArnaldo Carvalho de Melo
23293ec4ce7SArnaldo Carvalho de Melo for (i = 0; i < nints; ++i) {
23393ec4ce7SArnaldo Carvalho de Melo if (printed == size)
23493ec4ce7SArnaldo Carvalho de Melo goto out_err_overflow;
23593ec4ce7SArnaldo Carvalho de Melo
23693ec4ce7SArnaldo Carvalho de Melo if (i > 0)
237a067558eSArnaldo Carvalho de Melo printed += scnprintf(e + printed, size - printed, " %s ", or_and);
23893ec4ce7SArnaldo Carvalho de Melo printed += scnprintf(e + printed, size - printed,
23993ec4ce7SArnaldo Carvalho de Melo "%s %s %d", var, eq_neq, ints[i]);
24093ec4ce7SArnaldo Carvalho de Melo }
24193ec4ce7SArnaldo Carvalho de Melo }
24293ec4ce7SArnaldo Carvalho de Melo
24393ec4ce7SArnaldo Carvalho de Melo return expr;
24493ec4ce7SArnaldo Carvalho de Melo
24593ec4ce7SArnaldo Carvalho de Melo out_err_overflow:
24693ec4ce7SArnaldo Carvalho de Melo free(expr);
24793ec4ce7SArnaldo Carvalho de Melo return NULL;
24893ec4ce7SArnaldo Carvalho de Melo }
2491e9f9e8aSMasami Hiramatsu
2501e9f9e8aSMasami Hiramatsu /* Like strpbrk(), but not break if it is right after a backslash (escaped) */
strpbrk_esc(char * str,const char * stopset)2511e9f9e8aSMasami Hiramatsu char *strpbrk_esc(char *str, const char *stopset)
2521e9f9e8aSMasami Hiramatsu {
2531e9f9e8aSMasami Hiramatsu char *ptr;
2541e9f9e8aSMasami Hiramatsu
2551e9f9e8aSMasami Hiramatsu do {
2561e9f9e8aSMasami Hiramatsu ptr = strpbrk(str, stopset);
2571e9f9e8aSMasami Hiramatsu if (ptr == str ||
2581e9f9e8aSMasami Hiramatsu (ptr == str + 1 && *(ptr - 1) != '\\'))
2591e9f9e8aSMasami Hiramatsu break;
2601e9f9e8aSMasami Hiramatsu str = ptr + 1;
2611e9f9e8aSMasami Hiramatsu } while (ptr && *(ptr - 1) == '\\' && *(ptr - 2) != '\\');
2621e9f9e8aSMasami Hiramatsu
2631e9f9e8aSMasami Hiramatsu return ptr;
2641e9f9e8aSMasami Hiramatsu }
2651e9f9e8aSMasami Hiramatsu
2661e9f9e8aSMasami Hiramatsu /* Like strdup, but do not copy a single backslash */
strdup_esc(const char * str)2671e9f9e8aSMasami Hiramatsu char *strdup_esc(const char *str)
2681e9f9e8aSMasami Hiramatsu {
2691e9f9e8aSMasami Hiramatsu char *s, *d, *p, *ret = strdup(str);
2701e9f9e8aSMasami Hiramatsu
2711e9f9e8aSMasami Hiramatsu if (!ret)
2721e9f9e8aSMasami Hiramatsu return NULL;
2731e9f9e8aSMasami Hiramatsu
2741e9f9e8aSMasami Hiramatsu d = strchr(ret, '\\');
2751e9f9e8aSMasami Hiramatsu if (!d)
2761e9f9e8aSMasami Hiramatsu return ret;
2771e9f9e8aSMasami Hiramatsu
2781e9f9e8aSMasami Hiramatsu s = d + 1;
2791e9f9e8aSMasami Hiramatsu do {
2801e9f9e8aSMasami Hiramatsu if (*s == '\0') {
2811e9f9e8aSMasami Hiramatsu *d = '\0';
2821e9f9e8aSMasami Hiramatsu break;
2831e9f9e8aSMasami Hiramatsu }
2841e9f9e8aSMasami Hiramatsu p = strchr(s + 1, '\\');
2851e9f9e8aSMasami Hiramatsu if (p) {
2861e9f9e8aSMasami Hiramatsu memmove(d, s, p - s);
2871e9f9e8aSMasami Hiramatsu d += p - s;
2881e9f9e8aSMasami Hiramatsu s = p + 1;
2891e9f9e8aSMasami Hiramatsu } else
2901e9f9e8aSMasami Hiramatsu memmove(d, s, strlen(s) + 1);
2911e9f9e8aSMasami Hiramatsu } while (p);
2921e9f9e8aSMasami Hiramatsu
2931e9f9e8aSMasami Hiramatsu return ret;
2941e9f9e8aSMasami Hiramatsu }
295cef7af25SFabian Hemmer
hex(char c)296cef7af25SFabian Hemmer unsigned int hex(char c)
297cef7af25SFabian Hemmer {
298cef7af25SFabian Hemmer if (c >= '0' && c <= '9')
299cef7af25SFabian Hemmer return c - '0';
300cef7af25SFabian Hemmer if (c >= 'a' && c <= 'f')
301cef7af25SFabian Hemmer return c - 'a' + 10;
302cef7af25SFabian Hemmer return c - 'A' + 10;
303cef7af25SFabian Hemmer }
304*8a55c1e2SJames Clark
305*8a55c1e2SJames Clark /*
306*8a55c1e2SJames Clark * Replace all occurrences of character 'needle' in string 'haystack' with
307*8a55c1e2SJames Clark * string 'replace'
308*8a55c1e2SJames Clark *
309*8a55c1e2SJames Clark * The new string could be longer so a new string is returned which must be
310*8a55c1e2SJames Clark * freed.
311*8a55c1e2SJames Clark */
strreplace_chars(char needle,const char * haystack,const char * replace)312*8a55c1e2SJames Clark char *strreplace_chars(char needle, const char *haystack, const char *replace)
313*8a55c1e2SJames Clark {
314*8a55c1e2SJames Clark int replace_len = strlen(replace);
315*8a55c1e2SJames Clark char *new_s, *to;
316*8a55c1e2SJames Clark const char *loc = strchr(haystack, needle);
317*8a55c1e2SJames Clark const char *from = haystack;
318*8a55c1e2SJames Clark int num = 0;
319*8a55c1e2SJames Clark
320*8a55c1e2SJames Clark /* Count occurrences */
321*8a55c1e2SJames Clark while (loc) {
322*8a55c1e2SJames Clark loc = strchr(loc + 1, needle);
323*8a55c1e2SJames Clark num++;
324*8a55c1e2SJames Clark }
325*8a55c1e2SJames Clark
326*8a55c1e2SJames Clark /* Allocate enough space for replacements and reset first location */
327*8a55c1e2SJames Clark new_s = malloc(strlen(haystack) + (num * (replace_len - 1) + 1));
328*8a55c1e2SJames Clark if (!new_s)
329*8a55c1e2SJames Clark return NULL;
330*8a55c1e2SJames Clark loc = strchr(haystack, needle);
331*8a55c1e2SJames Clark to = new_s;
332*8a55c1e2SJames Clark
333*8a55c1e2SJames Clark while (loc) {
334*8a55c1e2SJames Clark /* Copy original string up to found char and update positions */
335*8a55c1e2SJames Clark memcpy(to, from, 1 + loc - from);
336*8a55c1e2SJames Clark to += loc - from;
337*8a55c1e2SJames Clark from = loc + 1;
338*8a55c1e2SJames Clark
339*8a55c1e2SJames Clark /* Copy replacement string and update positions */
340*8a55c1e2SJames Clark memcpy(to, replace, replace_len);
341*8a55c1e2SJames Clark to += replace_len;
342*8a55c1e2SJames Clark
343*8a55c1e2SJames Clark /* needle next occurrence or end of string */
344*8a55c1e2SJames Clark loc = strchr(from, needle);
345*8a55c1e2SJames Clark }
346*8a55c1e2SJames Clark
347*8a55c1e2SJames Clark /* Copy any remaining chars + null */
348*8a55c1e2SJames Clark strcpy(to, from);
349*8a55c1e2SJames Clark
350*8a55c1e2SJames Clark return new_s;
351*8a55c1e2SJames Clark }
352