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  /*
19   * perf_atoll()
20   * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
21   * and return its numeric value
22   */
perf_atoll(const char * str)23  s64 perf_atoll(const char *str)
24  {
25  	s64 length;
26  	char *p;
27  	char c;
28  
29  	if (!isdigit(str[0]))
30  		goto out_err;
31  
32  	length = strtoll(str, &p, 10);
33  	switch (c = *p++) {
34  		case 'b': case 'B':
35  			if (*p)
36  				goto out_err;
37  
38  			fallthrough;
39  		case '\0':
40  			return length;
41  		default:
42  			goto out_err;
43  		/* two-letter suffices */
44  		case 'k': case 'K':
45  			length <<= 10;
46  			break;
47  		case 'm': case 'M':
48  			length <<= 20;
49  			break;
50  		case 'g': case 'G':
51  			length <<= 30;
52  			break;
53  		case 't': case 'T':
54  			length <<= 40;
55  			break;
56  	}
57  	/* we want the cases to match */
58  	if (islower(c)) {
59  		if (strcmp(p, "b") != 0)
60  			goto out_err;
61  	} else {
62  		if (strcmp(p, "B") != 0)
63  			goto out_err;
64  	}
65  	return length;
66  
67  out_err:
68  	return -1;
69  }
70  
71  /* Character class matching */
__match_charclass(const char * pat,char c,const char ** npat)72  static bool __match_charclass(const char *pat, char c, const char **npat)
73  {
74  	bool complement = false, ret = true;
75  
76  	if (*pat == '!') {
77  		complement = true;
78  		pat++;
79  	}
80  	if (*pat++ == c)	/* First character is special */
81  		goto end;
82  
83  	while (*pat && *pat != ']') {	/* Matching */
84  		if (*pat == '-' && *(pat + 1) != ']') {	/* Range */
85  			if (*(pat - 1) <= c && c <= *(pat + 1))
86  				goto end;
87  			if (*(pat - 1) > *(pat + 1))
88  				goto error;
89  			pat += 2;
90  		} else if (*pat++ == c)
91  			goto end;
92  	}
93  	if (!*pat)
94  		goto error;
95  	ret = false;
96  
97  end:
98  	while (*pat && *pat != ']')	/* Searching closing */
99  		pat++;
100  	if (!*pat)
101  		goto error;
102  	*npat = pat + 1;
103  	return complement ? !ret : ret;
104  
105  error:
106  	return false;
107  }
108  
109  /* Glob/lazy pattern matching */
__match_glob(const char * str,const char * pat,bool ignore_space,bool case_ins)110  static bool __match_glob(const char *str, const char *pat, bool ignore_space,
111  			bool case_ins)
112  {
113  	while (*str && *pat && *pat != '*') {
114  		if (ignore_space) {
115  			/* Ignore spaces for lazy matching */
116  			if (isspace(*str)) {
117  				str++;
118  				continue;
119  			}
120  			if (isspace(*pat)) {
121  				pat++;
122  				continue;
123  			}
124  		}
125  		if (*pat == '?') {	/* Matches any single character */
126  			str++;
127  			pat++;
128  			continue;
129  		} else if (*pat == '[')	/* Character classes/Ranges */
130  			if (__match_charclass(pat + 1, *str, &pat)) {
131  				str++;
132  				continue;
133  			} else
134  				return false;
135  		else if (*pat == '\\') /* Escaped char match as normal char */
136  			pat++;
137  		if (case_ins) {
138  			if (tolower(*str) != tolower(*pat))
139  				return false;
140  		} else if (*str != *pat)
141  			return false;
142  		str++;
143  		pat++;
144  	}
145  	/* Check wild card */
146  	if (*pat == '*') {
147  		while (*pat == '*')
148  			pat++;
149  		if (!*pat)	/* Tail wild card matches all */
150  			return true;
151  		while (*str)
152  			if (__match_glob(str++, pat, ignore_space, case_ins))
153  				return true;
154  	}
155  	return !*str && !*pat;
156  }
157  
158  /**
159   * strglobmatch - glob expression pattern matching
160   * @str: the target string to match
161   * @pat: the pattern string to match
162   *
163   * This returns true if the @str matches @pat. @pat can includes wildcards
164   * ('*','?') and character classes ([CHARS], complementation and ranges are
165   * also supported). Also, this supports escape character ('\') to use special
166   * characters as normal character.
167   *
168   * Note: if @pat syntax is broken, this always returns false.
169   */
strglobmatch(const char * str,const char * pat)170  bool strglobmatch(const char *str, const char *pat)
171  {
172  	return __match_glob(str, pat, false, false);
173  }
174  
strglobmatch_nocase(const char * str,const char * pat)175  bool strglobmatch_nocase(const char *str, const char *pat)
176  {
177  	return __match_glob(str, pat, false, true);
178  }
179  
180  /**
181   * strlazymatch - matching pattern strings lazily with glob pattern
182   * @str: the target string to match
183   * @pat: the pattern string to match
184   *
185   * This is similar to strglobmatch, except this ignores spaces in
186   * the target string.
187   */
strlazymatch(const char * str,const char * pat)188  bool strlazymatch(const char *str, const char *pat)
189  {
190  	return __match_glob(str, pat, true, false);
191  }
192  
193  /**
194   * strtailcmp - Compare the tail of two strings
195   * @s1: 1st string to be compared
196   * @s2: 2nd string to be compared
197   *
198   * Return 0 if whole of either string is same as another's tail part.
199   */
strtailcmp(const char * s1,const char * s2)200  int strtailcmp(const char *s1, const char *s2)
201  {
202  	int i1 = strlen(s1);
203  	int i2 = strlen(s2);
204  	while (--i1 >= 0 && --i2 >= 0) {
205  		if (s1[i1] != s2[i2])
206  			return s1[i1] - s2[i2];
207  	}
208  	return 0;
209  }
210  
asprintf_expr_inout_ints(const char * var,bool in,size_t nints,int * ints)211  char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
212  {
213  	/*
214  	 * FIXME: replace this with an expression using log10() when we
215  	 * find a suitable implementation, maybe the one in the dvb drivers...
216  	 *
217  	 * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators
218  	 */
219  	size_t size = nints * 28 + 1; /* \0 */
220  	size_t i, printed = 0;
221  	char *expr = malloc(size);
222  
223  	if (expr) {
224  		const char *or_and = "||", *eq_neq = "==";
225  		char *e = expr;
226  
227  		if (!in) {
228  			or_and = "&&";
229  			eq_neq = "!=";
230  		}
231  
232  		for (i = 0; i < nints; ++i) {
233  			if (printed == size)
234  				goto out_err_overflow;
235  
236  			if (i > 0)
237  				printed += scnprintf(e + printed, size - printed, " %s ", or_and);
238  			printed += scnprintf(e + printed, size - printed,
239  					     "%s %s %d", var, eq_neq, ints[i]);
240  		}
241  	}
242  
243  	return expr;
244  
245  out_err_overflow:
246  	free(expr);
247  	return NULL;
248  }
249  
250  /* Like strpbrk(), but not break if it is right after a backslash (escaped) */
strpbrk_esc(char * str,const char * stopset)251  char *strpbrk_esc(char *str, const char *stopset)
252  {
253  	char *ptr;
254  
255  	do {
256  		ptr = strpbrk(str, stopset);
257  		if (ptr == str ||
258  		    (ptr == str + 1 && *(ptr - 1) != '\\'))
259  			break;
260  		str = ptr + 1;
261  	} while (ptr && *(ptr - 1) == '\\' && *(ptr - 2) != '\\');
262  
263  	return ptr;
264  }
265  
266  /* Like strdup, but do not copy a single backslash */
strdup_esc(const char * str)267  char *strdup_esc(const char *str)
268  {
269  	char *s, *d, *p, *ret = strdup(str);
270  
271  	if (!ret)
272  		return NULL;
273  
274  	d = strchr(ret, '\\');
275  	if (!d)
276  		return ret;
277  
278  	s = d + 1;
279  	do {
280  		if (*s == '\0') {
281  			*d = '\0';
282  			break;
283  		}
284  		p = strchr(s + 1, '\\');
285  		if (p) {
286  			memmove(d, s, p - s);
287  			d += p - s;
288  			s = p + 1;
289  		} else
290  			memmove(d, s, strlen(s) + 1);
291  	} while (p);
292  
293  	return ret;
294  }
295  
hex(char c)296  unsigned int hex(char c)
297  {
298  	if (c >= '0' && c <= '9')
299  		return c - '0';
300  	if (c >= 'a' && c <= 'f')
301  		return c - 'a' + 10;
302  	return c - 'A' + 10;
303  }
304  
305  /*
306   * Replace all occurrences of character 'needle' in string 'haystack' with
307   * string 'replace'
308   *
309   * The new string could be longer so a new string is returned which must be
310   * freed.
311   */
strreplace_chars(char needle,const char * haystack,const char * replace)312  char *strreplace_chars(char needle, const char *haystack, const char *replace)
313  {
314  	int replace_len = strlen(replace);
315  	char *new_s, *to;
316  	const char *loc = strchr(haystack, needle);
317  	const char *from = haystack;
318  	int num = 0;
319  
320  	/* Count occurrences */
321  	while (loc) {
322  		loc = strchr(loc + 1, needle);
323  		num++;
324  	}
325  
326  	/* Allocate enough space for replacements and reset first location */
327  	new_s = malloc(strlen(haystack) + (num * (replace_len - 1) + 1));
328  	if (!new_s)
329  		return NULL;
330  	loc = strchr(haystack, needle);
331  	to = new_s;
332  
333  	while (loc) {
334  		/* Copy original string up to found char and update positions */
335  		memcpy(to, from, 1 + loc - from);
336  		to += loc - from;
337  		from = loc + 1;
338  
339  		/* Copy replacement string and update positions */
340  		memcpy(to, replace, replace_len);
341  		to += replace_len;
342  
343  		/* needle next occurrence or end of string */
344  		loc = strchr(from, needle);
345  	}
346  
347  	/* Copy any remaining chars + null */
348  	strcpy(to, from);
349  
350  	return new_s;
351  }
352