xref: /linux/tools/perf/util/string.c (revision cef7af25c9d3a7ea5d0c82424dc8bf93a95b6fc3)
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 #define K 1024LL
19d2fb8b41SHitoshi Mitake /*
20d2fb8b41SHitoshi Mitake  * perf_atoll()
21d2fb8b41SHitoshi Mitake  * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
22d2fb8b41SHitoshi Mitake  * and return its numeric value
23d2fb8b41SHitoshi Mitake  */
24d2fb8b41SHitoshi Mitake s64 perf_atoll(const char *str)
25d2fb8b41SHitoshi Mitake {
268ba7f6c2SAl Viro 	s64 length;
278ba7f6c2SAl Viro 	char *p;
288ba7f6c2SAl Viro 	char c;
29d2fb8b41SHitoshi Mitake 
30d2fb8b41SHitoshi Mitake 	if (!isdigit(str[0]))
31d2fb8b41SHitoshi Mitake 		goto out_err;
32d2fb8b41SHitoshi Mitake 
338ba7f6c2SAl Viro 	length = strtoll(str, &p, 10);
348ba7f6c2SAl Viro 	switch (c = *p++) {
358ba7f6c2SAl Viro 		case 'b': case 'B':
368ba7f6c2SAl Viro 			if (*p)
37d2fb8b41SHitoshi Mitake 				goto out_err;
3894bdd5edSArnaldo Carvalho de Melo 
3994bdd5edSArnaldo Carvalho de Melo 			__fallthrough;
408ba7f6c2SAl Viro 		case '\0':
418ba7f6c2SAl Viro 			return length;
42d2fb8b41SHitoshi Mitake 		default:
43d2fb8b41SHitoshi Mitake 			goto out_err;
448ba7f6c2SAl Viro 		/* two-letter suffices */
458ba7f6c2SAl Viro 		case 'k': case 'K':
468ba7f6c2SAl Viro 			length <<= 10;
478ba7f6c2SAl Viro 			break;
488ba7f6c2SAl Viro 		case 'm': case 'M':
498ba7f6c2SAl Viro 			length <<= 20;
508ba7f6c2SAl Viro 			break;
518ba7f6c2SAl Viro 		case 'g': case 'G':
528ba7f6c2SAl Viro 			length <<= 30;
538ba7f6c2SAl Viro 			break;
548ba7f6c2SAl Viro 		case 't': case 'T':
558ba7f6c2SAl Viro 			length <<= 40;
56d2fb8b41SHitoshi Mitake 			break;
57d2fb8b41SHitoshi Mitake 	}
588ba7f6c2SAl Viro 	/* we want the cases to match */
598ba7f6c2SAl Viro 	if (islower(c)) {
608ba7f6c2SAl Viro 		if (strcmp(p, "b") != 0)
618ba7f6c2SAl Viro 			goto out_err;
628ba7f6c2SAl Viro 	} else {
638ba7f6c2SAl Viro 		if (strcmp(p, "B") != 0)
648ba7f6c2SAl Viro 			goto out_err;
65d2fb8b41SHitoshi Mitake 	}
668ba7f6c2SAl Viro 	return length;
67d2fb8b41SHitoshi Mitake 
68d2fb8b41SHitoshi Mitake out_err:
698ba7f6c2SAl Viro 	return -1;
70d2fb8b41SHitoshi Mitake }
71e1c01d61SMasami Hiramatsu 
726964cd2cSMasami Hiramatsu /* Character class matching */
736964cd2cSMasami Hiramatsu static bool __match_charclass(const char *pat, char c, const char **npat)
746964cd2cSMasami Hiramatsu {
756964cd2cSMasami Hiramatsu 	bool complement = false, ret = true;
766964cd2cSMasami Hiramatsu 
776964cd2cSMasami Hiramatsu 	if (*pat == '!') {
786964cd2cSMasami Hiramatsu 		complement = true;
796964cd2cSMasami Hiramatsu 		pat++;
806964cd2cSMasami Hiramatsu 	}
816964cd2cSMasami Hiramatsu 	if (*pat++ == c)	/* First character is special */
826964cd2cSMasami Hiramatsu 		goto end;
836964cd2cSMasami Hiramatsu 
846964cd2cSMasami Hiramatsu 	while (*pat && *pat != ']') {	/* Matching */
856964cd2cSMasami Hiramatsu 		if (*pat == '-' && *(pat + 1) != ']') {	/* Range */
866964cd2cSMasami Hiramatsu 			if (*(pat - 1) <= c && c <= *(pat + 1))
876964cd2cSMasami Hiramatsu 				goto end;
886964cd2cSMasami Hiramatsu 			if (*(pat - 1) > *(pat + 1))
896964cd2cSMasami Hiramatsu 				goto error;
906964cd2cSMasami Hiramatsu 			pat += 2;
916964cd2cSMasami Hiramatsu 		} else if (*pat++ == c)
926964cd2cSMasami Hiramatsu 			goto end;
936964cd2cSMasami Hiramatsu 	}
946964cd2cSMasami Hiramatsu 	if (!*pat)
956964cd2cSMasami Hiramatsu 		goto error;
966964cd2cSMasami Hiramatsu 	ret = false;
976964cd2cSMasami Hiramatsu 
986964cd2cSMasami Hiramatsu end:
996964cd2cSMasami Hiramatsu 	while (*pat && *pat != ']')	/* Searching closing */
1006964cd2cSMasami Hiramatsu 		pat++;
1016964cd2cSMasami Hiramatsu 	if (!*pat)
1026964cd2cSMasami Hiramatsu 		goto error;
1036964cd2cSMasami Hiramatsu 	*npat = pat + 1;
1046964cd2cSMasami Hiramatsu 	return complement ? !ret : ret;
1056964cd2cSMasami Hiramatsu 
1066964cd2cSMasami Hiramatsu error:
1076964cd2cSMasami Hiramatsu 	return false;
1086964cd2cSMasami Hiramatsu }
1096964cd2cSMasami Hiramatsu 
1102a9c8c36SMasami Hiramatsu /* Glob/lazy pattern matching */
11138d14f0cSAndi Kleen static bool __match_glob(const char *str, const char *pat, bool ignore_space,
11238d14f0cSAndi Kleen 			bool case_ins)
113bbbb521bSMasami Hiramatsu {
114bbbb521bSMasami Hiramatsu 	while (*str && *pat && *pat != '*') {
1152a9c8c36SMasami Hiramatsu 		if (ignore_space) {
1162a9c8c36SMasami Hiramatsu 			/* Ignore spaces for lazy matching */
1172a9c8c36SMasami Hiramatsu 			if (isspace(*str)) {
1182a9c8c36SMasami Hiramatsu 				str++;
1192a9c8c36SMasami Hiramatsu 				continue;
1202a9c8c36SMasami Hiramatsu 			}
1212a9c8c36SMasami Hiramatsu 			if (isspace(*pat)) {
1222a9c8c36SMasami Hiramatsu 				pat++;
1232a9c8c36SMasami Hiramatsu 				continue;
1242a9c8c36SMasami Hiramatsu 			}
1252a9c8c36SMasami Hiramatsu 		}
1266964cd2cSMasami Hiramatsu 		if (*pat == '?') {	/* Matches any single character */
127bbbb521bSMasami Hiramatsu 			str++;
128bbbb521bSMasami Hiramatsu 			pat++;
1296964cd2cSMasami Hiramatsu 			continue;
1306964cd2cSMasami Hiramatsu 		} else if (*pat == '[')	/* Character classes/Ranges */
1316964cd2cSMasami Hiramatsu 			if (__match_charclass(pat + 1, *str, &pat)) {
1326964cd2cSMasami Hiramatsu 				str++;
1336964cd2cSMasami Hiramatsu 				continue;
134bbbb521bSMasami Hiramatsu 			} else
1356964cd2cSMasami Hiramatsu 				return false;
1366964cd2cSMasami Hiramatsu 		else if (*pat == '\\') /* Escaped char match as normal char */
1376964cd2cSMasami Hiramatsu 			pat++;
13838d14f0cSAndi Kleen 		if (case_ins) {
13938d14f0cSAndi Kleen 			if (tolower(*str) != tolower(*pat))
140bbbb521bSMasami Hiramatsu 				return false;
14138d14f0cSAndi Kleen 		} else if (*str != *pat)
14238d14f0cSAndi Kleen 			return false;
14338d14f0cSAndi Kleen 		str++;
14438d14f0cSAndi Kleen 		pat++;
145bbbb521bSMasami Hiramatsu 	}
146bbbb521bSMasami Hiramatsu 	/* Check wild card */
147bbbb521bSMasami Hiramatsu 	if (*pat == '*') {
148bbbb521bSMasami Hiramatsu 		while (*pat == '*')
149bbbb521bSMasami Hiramatsu 			pat++;
150bbbb521bSMasami Hiramatsu 		if (!*pat)	/* Tail wild card matches all */
151bbbb521bSMasami Hiramatsu 			return true;
152bbbb521bSMasami Hiramatsu 		while (*str)
15338d14f0cSAndi Kleen 			if (__match_glob(str++, pat, ignore_space, case_ins))
154bbbb521bSMasami Hiramatsu 				return true;
155bbbb521bSMasami Hiramatsu 	}
156bbbb521bSMasami Hiramatsu 	return !*str && !*pat;
157bbbb521bSMasami Hiramatsu }
158bbbb521bSMasami Hiramatsu 
1592a9c8c36SMasami Hiramatsu /**
1602a9c8c36SMasami Hiramatsu  * strglobmatch - glob expression pattern matching
1612a9c8c36SMasami Hiramatsu  * @str: the target string to match
1622a9c8c36SMasami Hiramatsu  * @pat: the pattern string to match
1632a9c8c36SMasami Hiramatsu  *
1642a9c8c36SMasami Hiramatsu  * This returns true if the @str matches @pat. @pat can includes wildcards
1652a9c8c36SMasami Hiramatsu  * ('*','?') and character classes ([CHARS], complementation and ranges are
1662a9c8c36SMasami Hiramatsu  * also supported). Also, this supports escape character ('\') to use special
1672a9c8c36SMasami Hiramatsu  * characters as normal character.
1682a9c8c36SMasami Hiramatsu  *
1692a9c8c36SMasami Hiramatsu  * Note: if @pat syntax is broken, this always returns false.
1702a9c8c36SMasami Hiramatsu  */
1712a9c8c36SMasami Hiramatsu bool strglobmatch(const char *str, const char *pat)
1722a9c8c36SMasami Hiramatsu {
17338d14f0cSAndi Kleen 	return __match_glob(str, pat, false, false);
17438d14f0cSAndi Kleen }
17538d14f0cSAndi Kleen 
17638d14f0cSAndi Kleen bool strglobmatch_nocase(const char *str, const char *pat)
17738d14f0cSAndi Kleen {
17838d14f0cSAndi Kleen 	return __match_glob(str, pat, false, true);
1792a9c8c36SMasami Hiramatsu }
1802a9c8c36SMasami Hiramatsu 
1812a9c8c36SMasami Hiramatsu /**
1822a9c8c36SMasami Hiramatsu  * strlazymatch - matching pattern strings lazily with glob pattern
1832a9c8c36SMasami Hiramatsu  * @str: the target string to match
1842a9c8c36SMasami Hiramatsu  * @pat: the pattern string to match
1852a9c8c36SMasami Hiramatsu  *
1862a9c8c36SMasami Hiramatsu  * This is similar to strglobmatch, except this ignores spaces in
1872a9c8c36SMasami Hiramatsu  * the target string.
1882a9c8c36SMasami Hiramatsu  */
1892a9c8c36SMasami Hiramatsu bool strlazymatch(const char *str, const char *pat)
1902a9c8c36SMasami Hiramatsu {
19138d14f0cSAndi Kleen 	return __match_glob(str, pat, true, false);
1922a9c8c36SMasami Hiramatsu }
193bad03ae4SMasami Hiramatsu 
194bad03ae4SMasami Hiramatsu /**
195bad03ae4SMasami Hiramatsu  * strtailcmp - Compare the tail of two strings
196bad03ae4SMasami Hiramatsu  * @s1: 1st string to be compared
197bad03ae4SMasami Hiramatsu  * @s2: 2nd string to be compared
198bad03ae4SMasami Hiramatsu  *
199bad03ae4SMasami Hiramatsu  * Return 0 if whole of either string is same as another's tail part.
200bad03ae4SMasami Hiramatsu  */
201bad03ae4SMasami Hiramatsu int strtailcmp(const char *s1, const char *s2)
202bad03ae4SMasami Hiramatsu {
203bad03ae4SMasami Hiramatsu 	int i1 = strlen(s1);
204bad03ae4SMasami Hiramatsu 	int i2 = strlen(s2);
205bad03ae4SMasami Hiramatsu 	while (--i1 >= 0 && --i2 >= 0) {
206bad03ae4SMasami Hiramatsu 		if (s1[i1] != s2[i2])
207bad03ae4SMasami Hiramatsu 			return s1[i1] - s2[i2];
208bad03ae4SMasami Hiramatsu 	}
209bad03ae4SMasami Hiramatsu 	return 0;
210bad03ae4SMasami Hiramatsu }
211bad03ae4SMasami Hiramatsu 
21293ec4ce7SArnaldo Carvalho de Melo char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
21393ec4ce7SArnaldo Carvalho de Melo {
21493ec4ce7SArnaldo Carvalho de Melo 	/*
21593ec4ce7SArnaldo Carvalho de Melo 	 * FIXME: replace this with an expression using log10() when we
21693ec4ce7SArnaldo Carvalho de Melo 	 * find a suitable implementation, maybe the one in the dvb drivers...
21793ec4ce7SArnaldo Carvalho de Melo 	 *
21893ec4ce7SArnaldo Carvalho de Melo 	 * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators
21993ec4ce7SArnaldo Carvalho de Melo 	 */
22093ec4ce7SArnaldo Carvalho de Melo 	size_t size = nints * 28 + 1; /* \0 */
22193ec4ce7SArnaldo Carvalho de Melo 	size_t i, printed = 0;
22293ec4ce7SArnaldo Carvalho de Melo 	char *expr = malloc(size);
22393ec4ce7SArnaldo Carvalho de Melo 
22493ec4ce7SArnaldo Carvalho de Melo 	if (expr) {
22593ec4ce7SArnaldo Carvalho de Melo 		const char *or_and = "||", *eq_neq = "==";
22693ec4ce7SArnaldo Carvalho de Melo 		char *e = expr;
22793ec4ce7SArnaldo Carvalho de Melo 
22893ec4ce7SArnaldo Carvalho de Melo 		if (!in) {
22993ec4ce7SArnaldo Carvalho de Melo 			or_and = "&&";
23093ec4ce7SArnaldo Carvalho de Melo 			eq_neq = "!=";
23193ec4ce7SArnaldo Carvalho de Melo 		}
23293ec4ce7SArnaldo Carvalho de Melo 
23393ec4ce7SArnaldo Carvalho de Melo 		for (i = 0; i < nints; ++i) {
23493ec4ce7SArnaldo Carvalho de Melo 			if (printed == size)
23593ec4ce7SArnaldo Carvalho de Melo 				goto out_err_overflow;
23693ec4ce7SArnaldo Carvalho de Melo 
23793ec4ce7SArnaldo Carvalho de Melo 			if (i > 0)
238a067558eSArnaldo Carvalho de Melo 				printed += scnprintf(e + printed, size - printed, " %s ", or_and);
23993ec4ce7SArnaldo Carvalho de Melo 			printed += scnprintf(e + printed, size - printed,
24093ec4ce7SArnaldo Carvalho de Melo 					     "%s %s %d", var, eq_neq, ints[i]);
24193ec4ce7SArnaldo Carvalho de Melo 		}
24293ec4ce7SArnaldo Carvalho de Melo 	}
24393ec4ce7SArnaldo Carvalho de Melo 
24493ec4ce7SArnaldo Carvalho de Melo 	return expr;
24593ec4ce7SArnaldo Carvalho de Melo 
24693ec4ce7SArnaldo Carvalho de Melo out_err_overflow:
24793ec4ce7SArnaldo Carvalho de Melo 	free(expr);
24893ec4ce7SArnaldo Carvalho de Melo 	return NULL;
24993ec4ce7SArnaldo Carvalho de Melo }
2501e9f9e8aSMasami Hiramatsu 
2511e9f9e8aSMasami Hiramatsu /* Like strpbrk(), but not break if it is right after a backslash (escaped) */
2521e9f9e8aSMasami Hiramatsu char *strpbrk_esc(char *str, const char *stopset)
2531e9f9e8aSMasami Hiramatsu {
2541e9f9e8aSMasami Hiramatsu 	char *ptr;
2551e9f9e8aSMasami Hiramatsu 
2561e9f9e8aSMasami Hiramatsu 	do {
2571e9f9e8aSMasami Hiramatsu 		ptr = strpbrk(str, stopset);
2581e9f9e8aSMasami Hiramatsu 		if (ptr == str ||
2591e9f9e8aSMasami Hiramatsu 		    (ptr == str + 1 && *(ptr - 1) != '\\'))
2601e9f9e8aSMasami Hiramatsu 			break;
2611e9f9e8aSMasami Hiramatsu 		str = ptr + 1;
2621e9f9e8aSMasami Hiramatsu 	} while (ptr && *(ptr - 1) == '\\' && *(ptr - 2) != '\\');
2631e9f9e8aSMasami Hiramatsu 
2641e9f9e8aSMasami Hiramatsu 	return ptr;
2651e9f9e8aSMasami Hiramatsu }
2661e9f9e8aSMasami Hiramatsu 
2671e9f9e8aSMasami Hiramatsu /* Like strdup, but do not copy a single backslash */
2681e9f9e8aSMasami Hiramatsu char *strdup_esc(const char *str)
2691e9f9e8aSMasami Hiramatsu {
2701e9f9e8aSMasami Hiramatsu 	char *s, *d, *p, *ret = strdup(str);
2711e9f9e8aSMasami Hiramatsu 
2721e9f9e8aSMasami Hiramatsu 	if (!ret)
2731e9f9e8aSMasami Hiramatsu 		return NULL;
2741e9f9e8aSMasami Hiramatsu 
2751e9f9e8aSMasami Hiramatsu 	d = strchr(ret, '\\');
2761e9f9e8aSMasami Hiramatsu 	if (!d)
2771e9f9e8aSMasami Hiramatsu 		return ret;
2781e9f9e8aSMasami Hiramatsu 
2791e9f9e8aSMasami Hiramatsu 	s = d + 1;
2801e9f9e8aSMasami Hiramatsu 	do {
2811e9f9e8aSMasami Hiramatsu 		if (*s == '\0') {
2821e9f9e8aSMasami Hiramatsu 			*d = '\0';
2831e9f9e8aSMasami Hiramatsu 			break;
2841e9f9e8aSMasami Hiramatsu 		}
2851e9f9e8aSMasami Hiramatsu 		p = strchr(s + 1, '\\');
2861e9f9e8aSMasami Hiramatsu 		if (p) {
2871e9f9e8aSMasami Hiramatsu 			memmove(d, s, p - s);
2881e9f9e8aSMasami Hiramatsu 			d += p - s;
2891e9f9e8aSMasami Hiramatsu 			s = p + 1;
2901e9f9e8aSMasami Hiramatsu 		} else
2911e9f9e8aSMasami Hiramatsu 			memmove(d, s, strlen(s) + 1);
2921e9f9e8aSMasami Hiramatsu 	} while (p);
2931e9f9e8aSMasami Hiramatsu 
2941e9f9e8aSMasami Hiramatsu 	return ret;
2951e9f9e8aSMasami Hiramatsu }
296*cef7af25SFabian Hemmer 
297*cef7af25SFabian Hemmer unsigned int hex(char c)
298*cef7af25SFabian Hemmer {
299*cef7af25SFabian Hemmer 	if (c >= '0' && c <= '9')
300*cef7af25SFabian Hemmer 		return c - '0';
301*cef7af25SFabian Hemmer 	if (c >= 'a' && c <= 'f')
302*cef7af25SFabian Hemmer 		return c - 'a' + 10;
303*cef7af25SFabian Hemmer 	return c - 'A' + 10;
304*cef7af25SFabian Hemmer }
305