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