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