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