Home | History | Annotate | Download | only in util
      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  */
     10 s64 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;
     31 kilo:
     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;
     42 mega:
     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;
     53 giga:
     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;
     64 tera:
     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 
     80 out_err:
     81 	length = -1;
     82 out:
     83 	return length;
     84 }
     85 
     86 /*
     87  * Helper function for splitting a string into an argv-like array.
     88  * originally copied from lib/argv_split.c
     89  */
     90 static const char *skip_sep(const char *cp)
     91 {
     92 	while (*cp && isspace(*cp))
     93 		cp++;
     94 
     95 	return cp;
     96 }
     97 
     98 static const char *skip_arg(const char *cp)
     99 {
    100 	while (*cp && !isspace(*cp))
    101 		cp++;
    102 
    103 	return cp;
    104 }
    105 
    106 static 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  */
    127 void 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  */
    148 char **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 
    179 out:
    180 	return argv;
    181 
    182 fail:
    183 	argv_free(argv);
    184 	return NULL;
    185 }
    186 
    187 /* Character class matching */
    188 static 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 
    213 end:
    214 	while (*pat && *pat != ']')	/* Searching closing */
    215 		pat++;
    216 	if (!*pat)
    217 		goto error;
    218 	*npat = pat + 1;
    219 	return complement ? !ret : ret;
    220 
    221 error:
    222 	return false;
    223 }
    224 
    225 /* Glob/lazy pattern matching */
    226 static 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  */
    280 bool 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  */
    293 bool strlazymatch(const char *str, const char *pat)
    294 {
    295 	return __match_glob(str, pat, true);
    296 }
    297