xref: /linux/tools/perf/util/string.c (revision 5499b45190237ca90dd2ac86395cf464fe1f4cc7)
1 #include "string.h"
2 #include "util.h"
3 
4 static int hex(char ch)
5 {
6 	if ((ch >= '0') && (ch <= '9'))
7 		return ch - '0';
8 	if ((ch >= 'a') && (ch <= 'f'))
9 		return ch - 'a' + 10;
10 	if ((ch >= 'A') && (ch <= 'F'))
11 		return ch - 'A' + 10;
12 	return -1;
13 }
14 
15 /*
16  * While we find nice hex chars, build a long_val.
17  * Return number of chars processed.
18  */
19 int hex2u64(const char *ptr, u64 *long_val)
20 {
21 	const char *p = ptr;
22 	*long_val = 0;
23 
24 	while (*p) {
25 		const int hex_val = hex(*p);
26 
27 		if (hex_val < 0)
28 			break;
29 
30 		*long_val = (*long_val << 4) | hex_val;
31 		p++;
32 	}
33 
34 	return p - ptr;
35 }
36 
37 char *strxfrchar(char *s, char from, char to)
38 {
39 	char *p = s;
40 
41 	while ((p = strchr(p, from)) != NULL)
42 		*p++ = to;
43 
44 	return s;
45 }
46 
47 #define K 1024LL
48 /*
49  * perf_atoll()
50  * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
51  * and return its numeric value
52  */
53 s64 perf_atoll(const char *str)
54 {
55 	unsigned int i;
56 	s64 length = -1, unit = 1;
57 
58 	if (!isdigit(str[0]))
59 		goto out_err;
60 
61 	for (i = 1; i < strlen(str); i++) {
62 		switch (str[i]) {
63 		case 'B':
64 		case 'b':
65 			break;
66 		case 'K':
67 			if (str[i + 1] != 'B')
68 				goto out_err;
69 			else
70 				goto kilo;
71 		case 'k':
72 			if (str[i + 1] != 'b')
73 				goto out_err;
74 kilo:
75 			unit = K;
76 			break;
77 		case 'M':
78 			if (str[i + 1] != 'B')
79 				goto out_err;
80 			else
81 				goto mega;
82 		case 'm':
83 			if (str[i + 1] != 'b')
84 				goto out_err;
85 mega:
86 			unit = K * K;
87 			break;
88 		case 'G':
89 			if (str[i + 1] != 'B')
90 				goto out_err;
91 			else
92 				goto giga;
93 		case 'g':
94 			if (str[i + 1] != 'b')
95 				goto out_err;
96 giga:
97 			unit = K * K * K;
98 			break;
99 		case 'T':
100 			if (str[i + 1] != 'B')
101 				goto out_err;
102 			else
103 				goto tera;
104 		case 't':
105 			if (str[i + 1] != 'b')
106 				goto out_err;
107 tera:
108 			unit = K * K * K * K;
109 			break;
110 		case '\0':	/* only specified figures */
111 			unit = 1;
112 			break;
113 		default:
114 			if (!isdigit(str[i]))
115 				goto out_err;
116 			break;
117 		}
118 	}
119 
120 	length = atoll(str) * unit;
121 	goto out;
122 
123 out_err:
124 	length = -1;
125 out:
126 	return length;
127 }
128 
129 /*
130  * Helper function for splitting a string into an argv-like array.
131  * originaly copied from lib/argv_split.c
132  */
133 static const char *skip_sep(const char *cp)
134 {
135 	while (*cp && isspace(*cp))
136 		cp++;
137 
138 	return cp;
139 }
140 
141 static const char *skip_arg(const char *cp)
142 {
143 	while (*cp && !isspace(*cp))
144 		cp++;
145 
146 	return cp;
147 }
148 
149 static int count_argc(const char *str)
150 {
151 	int count = 0;
152 
153 	while (*str) {
154 		str = skip_sep(str);
155 		if (*str) {
156 			count++;
157 			str = skip_arg(str);
158 		}
159 	}
160 
161 	return count;
162 }
163 
164 /**
165  * argv_free - free an argv
166  * @argv - the argument vector to be freed
167  *
168  * Frees an argv and the strings it points to.
169  */
170 void argv_free(char **argv)
171 {
172 	char **p;
173 	for (p = argv; *p; p++)
174 		free(*p);
175 
176 	free(argv);
177 }
178 
179 /**
180  * argv_split - split a string at whitespace, returning an argv
181  * @str: the string to be split
182  * @argcp: returned argument count
183  *
184  * Returns an array of pointers to strings which are split out from
185  * @str.  This is performed by strictly splitting on white-space; no
186  * quote processing is performed.  Multiple whitespace characters are
187  * considered to be a single argument separator.  The returned array
188  * is always NULL-terminated.  Returns NULL on memory allocation
189  * failure.
190  */
191 char **argv_split(const char *str, int *argcp)
192 {
193 	int argc = count_argc(str);
194 	char **argv = zalloc(sizeof(*argv) * (argc+1));
195 	char **argvp;
196 
197 	if (argv == NULL)
198 		goto out;
199 
200 	if (argcp)
201 		*argcp = argc;
202 
203 	argvp = argv;
204 
205 	while (*str) {
206 		str = skip_sep(str);
207 
208 		if (*str) {
209 			const char *p = str;
210 			char *t;
211 
212 			str = skip_arg(str);
213 
214 			t = strndup(p, str-p);
215 			if (t == NULL)
216 				goto fail;
217 			*argvp++ = t;
218 		}
219 	}
220 	*argvp = NULL;
221 
222 out:
223 	return argv;
224 
225 fail:
226 	argv_free(argv);
227 	return NULL;
228 }
229 
230 /* Character class matching */
231 static bool __match_charclass(const char *pat, char c, const char **npat)
232 {
233 	bool complement = false, ret = true;
234 
235 	if (*pat == '!') {
236 		complement = true;
237 		pat++;
238 	}
239 	if (*pat++ == c)	/* First character is special */
240 		goto end;
241 
242 	while (*pat && *pat != ']') {	/* Matching */
243 		if (*pat == '-' && *(pat + 1) != ']') {	/* Range */
244 			if (*(pat - 1) <= c && c <= *(pat + 1))
245 				goto end;
246 			if (*(pat - 1) > *(pat + 1))
247 				goto error;
248 			pat += 2;
249 		} else if (*pat++ == c)
250 			goto end;
251 	}
252 	if (!*pat)
253 		goto error;
254 	ret = false;
255 
256 end:
257 	while (*pat && *pat != ']')	/* Searching closing */
258 		pat++;
259 	if (!*pat)
260 		goto error;
261 	*npat = pat + 1;
262 	return complement ? !ret : ret;
263 
264 error:
265 	return false;
266 }
267 
268 /**
269  * strglobmatch - glob expression pattern matching
270  * @str: the target string to match
271  * @pat: the pattern string to match
272  *
273  * This returns true if the @str matches @pat. @pat can includes wildcards
274  * ('*','?') and character classes ([CHARS], complementation and ranges are
275  * also supported). Also, this supports escape character ('\') to use special
276  * characters as normal character.
277  *
278  * Note: if @pat syntax is broken, this always returns false.
279  */
280 bool strglobmatch(const char *str, const char *pat)
281 {
282 	while (*str && *pat && *pat != '*') {
283 		if (*pat == '?') {	/* Matches any single character */
284 			str++;
285 			pat++;
286 			continue;
287 		} else if (*pat == '[')	/* Character classes/Ranges */
288 			if (__match_charclass(pat + 1, *str, &pat)) {
289 				str++;
290 				continue;
291 			} else
292 				return false;
293 		else if (*pat == '\\') /* Escaped char match as normal char */
294 			pat++;
295 		if (*str++ != *pat++)
296 			return false;
297 	}
298 	/* Check wild card */
299 	if (*pat == '*') {
300 		while (*pat == '*')
301 			pat++;
302 		if (!*pat)	/* Tail wild card matches all */
303 			return true;
304 		while (*str)
305 			if (strglobmatch(str++, pat))
306 				return true;
307 	}
308 	return !*str && !*pat;
309 }
310 
311