xref: /linux/tools/perf/util/string.c (revision 3d689ed6099a1a11c38bb78aff7498e78e287e0b)
1 #include "util.h"
2 #include "linux/string.h"
3 
4 #include "sane_ctype.h"
5 
6 #define K 1024LL
7 /*
8  * perf_atoll()
9  * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
10  * and return its numeric value
11  */
12 s64 perf_atoll(const char *str)
13 {
14 	s64 length;
15 	char *p;
16 	char c;
17 
18 	if (!isdigit(str[0]))
19 		goto out_err;
20 
21 	length = strtoll(str, &p, 10);
22 	switch (c = *p++) {
23 		case 'b': case 'B':
24 			if (*p)
25 				goto out_err;
26 
27 			__fallthrough;
28 		case '\0':
29 			return length;
30 		default:
31 			goto out_err;
32 		/* two-letter suffices */
33 		case 'k': case 'K':
34 			length <<= 10;
35 			break;
36 		case 'm': case 'M':
37 			length <<= 20;
38 			break;
39 		case 'g': case 'G':
40 			length <<= 30;
41 			break;
42 		case 't': case 'T':
43 			length <<= 40;
44 			break;
45 	}
46 	/* we want the cases to match */
47 	if (islower(c)) {
48 		if (strcmp(p, "b") != 0)
49 			goto out_err;
50 	} else {
51 		if (strcmp(p, "B") != 0)
52 			goto out_err;
53 	}
54 	return length;
55 
56 out_err:
57 	return -1;
58 }
59 
60 /*
61  * Helper function for splitting a string into an argv-like array.
62  * originally copied from lib/argv_split.c
63  */
64 static const char *skip_sep(const char *cp)
65 {
66 	while (*cp && isspace(*cp))
67 		cp++;
68 
69 	return cp;
70 }
71 
72 static const char *skip_arg(const char *cp)
73 {
74 	while (*cp && !isspace(*cp))
75 		cp++;
76 
77 	return cp;
78 }
79 
80 static int count_argc(const char *str)
81 {
82 	int count = 0;
83 
84 	while (*str) {
85 		str = skip_sep(str);
86 		if (*str) {
87 			count++;
88 			str = skip_arg(str);
89 		}
90 	}
91 
92 	return count;
93 }
94 
95 /**
96  * argv_free - free an argv
97  * @argv - the argument vector to be freed
98  *
99  * Frees an argv and the strings it points to.
100  */
101 void argv_free(char **argv)
102 {
103 	char **p;
104 	for (p = argv; *p; p++)
105 		zfree(p);
106 
107 	free(argv);
108 }
109 
110 /**
111  * argv_split - split a string at whitespace, returning an argv
112  * @str: the string to be split
113  * @argcp: returned argument count
114  *
115  * Returns an array of pointers to strings which are split out from
116  * @str.  This is performed by strictly splitting on white-space; no
117  * quote processing is performed.  Multiple whitespace characters are
118  * considered to be a single argument separator.  The returned array
119  * is always NULL-terminated.  Returns NULL on memory allocation
120  * failure.
121  */
122 char **argv_split(const char *str, int *argcp)
123 {
124 	int argc = count_argc(str);
125 	char **argv = zalloc(sizeof(*argv) * (argc+1));
126 	char **argvp;
127 
128 	if (argv == NULL)
129 		goto out;
130 
131 	if (argcp)
132 		*argcp = argc;
133 
134 	argvp = argv;
135 
136 	while (*str) {
137 		str = skip_sep(str);
138 
139 		if (*str) {
140 			const char *p = str;
141 			char *t;
142 
143 			str = skip_arg(str);
144 
145 			t = strndup(p, str-p);
146 			if (t == NULL)
147 				goto fail;
148 			*argvp++ = t;
149 		}
150 	}
151 	*argvp = NULL;
152 
153 out:
154 	return argv;
155 
156 fail:
157 	argv_free(argv);
158 	return NULL;
159 }
160 
161 /* Character class matching */
162 static bool __match_charclass(const char *pat, char c, const char **npat)
163 {
164 	bool complement = false, ret = true;
165 
166 	if (*pat == '!') {
167 		complement = true;
168 		pat++;
169 	}
170 	if (*pat++ == c)	/* First character is special */
171 		goto end;
172 
173 	while (*pat && *pat != ']') {	/* Matching */
174 		if (*pat == '-' && *(pat + 1) != ']') {	/* Range */
175 			if (*(pat - 1) <= c && c <= *(pat + 1))
176 				goto end;
177 			if (*(pat - 1) > *(pat + 1))
178 				goto error;
179 			pat += 2;
180 		} else if (*pat++ == c)
181 			goto end;
182 	}
183 	if (!*pat)
184 		goto error;
185 	ret = false;
186 
187 end:
188 	while (*pat && *pat != ']')	/* Searching closing */
189 		pat++;
190 	if (!*pat)
191 		goto error;
192 	*npat = pat + 1;
193 	return complement ? !ret : ret;
194 
195 error:
196 	return false;
197 }
198 
199 /* Glob/lazy pattern matching */
200 static bool __match_glob(const char *str, const char *pat, bool ignore_space,
201 			bool case_ins)
202 {
203 	while (*str && *pat && *pat != '*') {
204 		if (ignore_space) {
205 			/* Ignore spaces for lazy matching */
206 			if (isspace(*str)) {
207 				str++;
208 				continue;
209 			}
210 			if (isspace(*pat)) {
211 				pat++;
212 				continue;
213 			}
214 		}
215 		if (*pat == '?') {	/* Matches any single character */
216 			str++;
217 			pat++;
218 			continue;
219 		} else if (*pat == '[')	/* Character classes/Ranges */
220 			if (__match_charclass(pat + 1, *str, &pat)) {
221 				str++;
222 				continue;
223 			} else
224 				return false;
225 		else if (*pat == '\\') /* Escaped char match as normal char */
226 			pat++;
227 		if (case_ins) {
228 			if (tolower(*str) != tolower(*pat))
229 				return false;
230 		} else if (*str != *pat)
231 			return false;
232 		str++;
233 		pat++;
234 	}
235 	/* Check wild card */
236 	if (*pat == '*') {
237 		while (*pat == '*')
238 			pat++;
239 		if (!*pat)	/* Tail wild card matches all */
240 			return true;
241 		while (*str)
242 			if (__match_glob(str++, pat, ignore_space, case_ins))
243 				return true;
244 	}
245 	return !*str && !*pat;
246 }
247 
248 /**
249  * strglobmatch - glob expression pattern matching
250  * @str: the target string to match
251  * @pat: the pattern string to match
252  *
253  * This returns true if the @str matches @pat. @pat can includes wildcards
254  * ('*','?') and character classes ([CHARS], complementation and ranges are
255  * also supported). Also, this supports escape character ('\') to use special
256  * characters as normal character.
257  *
258  * Note: if @pat syntax is broken, this always returns false.
259  */
260 bool strglobmatch(const char *str, const char *pat)
261 {
262 	return __match_glob(str, pat, false, false);
263 }
264 
265 bool strglobmatch_nocase(const char *str, const char *pat)
266 {
267 	return __match_glob(str, pat, false, true);
268 }
269 
270 /**
271  * strlazymatch - matching pattern strings lazily with glob pattern
272  * @str: the target string to match
273  * @pat: the pattern string to match
274  *
275  * This is similar to strglobmatch, except this ignores spaces in
276  * the target string.
277  */
278 bool strlazymatch(const char *str, const char *pat)
279 {
280 	return __match_glob(str, pat, true, false);
281 }
282 
283 /**
284  * strtailcmp - Compare the tail of two strings
285  * @s1: 1st string to be compared
286  * @s2: 2nd string to be compared
287  *
288  * Return 0 if whole of either string is same as another's tail part.
289  */
290 int strtailcmp(const char *s1, const char *s2)
291 {
292 	int i1 = strlen(s1);
293 	int i2 = strlen(s2);
294 	while (--i1 >= 0 && --i2 >= 0) {
295 		if (s1[i1] != s2[i2])
296 			return s1[i1] - s2[i2];
297 	}
298 	return 0;
299 }
300 
301 /**
302  * strxfrchar - Locate and replace character in @s
303  * @s:    The string to be searched/changed.
304  * @from: Source character to be replaced.
305  * @to:   Destination character.
306  *
307  * Return pointer to the changed string.
308  */
309 char *strxfrchar(char *s, char from, char to)
310 {
311 	char *p = s;
312 
313 	while ((p = strchr(p, from)) != NULL)
314 		*p++ = to;
315 
316 	return s;
317 }
318 
319 /**
320  * ltrim - Removes leading whitespace from @s.
321  * @s: The string to be stripped.
322  *
323  * Return pointer to the first non-whitespace character in @s.
324  */
325 char *ltrim(char *s)
326 {
327 	while (isspace(*s))
328 		s++;
329 
330 	return s;
331 }
332 
333 /**
334  * rtrim - Removes trailing whitespace from @s.
335  * @s: The string to be stripped.
336  *
337  * Note that the first trailing whitespace is replaced with a %NUL-terminator
338  * in the given string @s. Returns @s.
339  */
340 char *rtrim(char *s)
341 {
342 	size_t size = strlen(s);
343 	char *end;
344 
345 	if (!size)
346 		return s;
347 
348 	end = s + size - 1;
349 	while (end >= s && isspace(*end))
350 		end--;
351 	*(end + 1) = '\0';
352 
353 	return s;
354 }
355 
356 char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
357 {
358 	/*
359 	 * FIXME: replace this with an expression using log10() when we
360 	 * find a suitable implementation, maybe the one in the dvb drivers...
361 	 *
362 	 * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators
363 	 */
364 	size_t size = nints * 28 + 1; /* \0 */
365 	size_t i, printed = 0;
366 	char *expr = malloc(size);
367 
368 	if (expr) {
369 		const char *or_and = "||", *eq_neq = "==";
370 		char *e = expr;
371 
372 		if (!in) {
373 			or_and = "&&";
374 			eq_neq = "!=";
375 		}
376 
377 		for (i = 0; i < nints; ++i) {
378 			if (printed == size)
379 				goto out_err_overflow;
380 
381 			if (i > 0)
382 				printed += snprintf(e + printed, size - printed, " %s ", or_and);
383 			printed += scnprintf(e + printed, size - printed,
384 					     "%s %s %d", var, eq_neq, ints[i]);
385 		}
386 	}
387 
388 	return expr;
389 
390 out_err_overflow:
391 	free(expr);
392 	return NULL;
393 }
394