perf probe: Add lazy line matching support
[safe/jmp/linux-2.6] / tools / perf / util / string.c
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 /* Glob/lazy pattern matching */
269 static bool __match_glob(const char *str, const char *pat, bool ignore_space)
270 {
271         while (*str && *pat && *pat != '*') {
272                 if (ignore_space) {
273                         /* Ignore spaces for lazy matching */
274                         if (isspace(*str)) {
275                                 str++;
276                                 continue;
277                         }
278                         if (isspace(*pat)) {
279                                 pat++;
280                                 continue;
281                         }
282                 }
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 /**
312  * strglobmatch - glob expression pattern matching
313  * @str: the target string to match
314  * @pat: the pattern string to match
315  *
316  * This returns true if the @str matches @pat. @pat can includes wildcards
317  * ('*','?') and character classes ([CHARS], complementation and ranges are
318  * also supported). Also, this supports escape character ('\') to use special
319  * characters as normal character.
320  *
321  * Note: if @pat syntax is broken, this always returns false.
322  */
323 bool strglobmatch(const char *str, const char *pat)
324 {
325         return __match_glob(str, pat, false);
326 }
327
328 /**
329  * strlazymatch - matching pattern strings lazily with glob pattern
330  * @str: the target string to match
331  * @pat: the pattern string to match
332  *
333  * This is similar to strglobmatch, except this ignores spaces in
334  * the target string.
335  */
336 bool strlazymatch(const char *str, const char *pat)
337 {
338         return __match_glob(str, pat, true);
339 }