Root/tools/perf/util/string.c

1#include "string.h"
2#include "util.h"
3
4static 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 */
19int 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
37char *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 */
53s64 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;
74kilo:
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;
85mega:
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;
96giga:
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;
107tera:
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
123out_err:
124    length = -1;
125out:
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 */
133static const char *skip_sep(const char *cp)
134{
135    while (*cp && isspace(*cp))
136        cp++;
137
138    return cp;
139}
140
141static const char *skip_arg(const char *cp)
142{
143    while (*cp && !isspace(*cp))
144        cp++;
145
146    return cp;
147}
148
149static 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 */
170void 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 */
191char **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
222out:
223    return argv;
224
225fail:
226    argv_free(argv);
227    return NULL;
228}
229
230/* Character class matching */
231static 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
256end:
257    while (*pat && *pat != ']') /* Searching closing */
258        pat++;
259    if (!*pat)
260        goto error;
261    *npat = pat + 1;
262    return complement ? !ret : ret;
263
264error:
265    return false;
266}
267
268/* Glob/lazy pattern matching */
269static 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 */
323bool 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 */
336bool strlazymatch(const char *str, const char *pat)
337{
338    return __match_glob(str, pat, true);
339}
340

Archive Download this file



interactive