Home | History | Annotate | Download | only in util
      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  */
     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 
    298 /**
    299  * strtailcmp - Compare the tail of two strings
    300  * @s1: 1st string to be compared
    301  * @s2: 2nd string to be compared
    302  *
    303  * Return 0 if whole of either string is same as another's tail part.
    304  */
    305 int strtailcmp(const char *s1, const char *s2)
    306 {
    307 	int i1 = strlen(s1);
    308 	int i2 = strlen(s2);
    309 	while (--i1 >= 0 && --i2 >= 0) {
    310 		if (s1[i1] != s2[i2])
    311 			return s1[i1] - s2[i2];
    312 	}
    313 	return 0;
    314 }
    315 
    316 /**
    317  * strxfrchar - Locate and replace character in @s
    318  * @s:    The string to be searched/changed.
    319  * @from: Source character to be replaced.
    320  * @to:   Destination character.
    321  *
    322  * Return pointer to the changed string.
    323  */
    324 char *strxfrchar(char *s, char from, char to)
    325 {
    326 	char *p = s;
    327 
    328 	while ((p = strchr(p, from)) != NULL)
    329 		*p++ = to;
    330 
    331 	return s;
    332 }
    333 
    334 /**
    335  * ltrim - Removes leading whitespace from @s.
    336  * @s: The string to be stripped.
    337  *
    338  * Return pointer to the first non-whitespace character in @s.
    339  */
    340 char *ltrim(char *s)
    341 {
    342 	int len = strlen(s);
    343 
    344 	while (len && isspace(*s)) {
    345 		len--;
    346 		s++;
    347 	}
    348 
    349 	return s;
    350 }
    351 
    352 /**
    353  * rtrim - Removes trailing whitespace from @s.
    354  * @s: The string to be stripped.
    355  *
    356  * Note that the first trailing whitespace is replaced with a %NUL-terminator
    357  * in the given string @s. Returns @s.
    358  */
    359 char *rtrim(char *s)
    360 {
    361 	size_t size = strlen(s);
    362 	char *end;
    363 
    364 	if (!size)
    365 		return s;
    366 
    367 	end = s + size - 1;
    368 	while (end >= s && isspace(*end))
    369 		end--;
    370 	*(end + 1) = '\0';
    371 
    372 	return s;
    373 }
    374 
    375 /**
    376  * memdup - duplicate region of memory
    377  * @src: memory region to duplicate
    378  * @len: memory region length
    379  */
    380 void *memdup(const void *src, size_t len)
    381 {
    382 	void *p;
    383 
    384 	p = malloc(len);
    385 	if (p)
    386 		memcpy(p, src, len);
    387 
    388 	return p;
    389 }
    390 
    391 /**
    392  * str_append - reallocate string and append another
    393  * @s: pointer to string pointer
    394  * @len: pointer to len (initialized)
    395  * @a: string to append.
    396  */
    397 int str_append(char **s, int *len, const char *a)
    398 {
    399 	int olen = *s ? strlen(*s) : 0;
    400 	int nlen = olen + strlen(a) + 1;
    401 	if (*len < nlen) {
    402 		*len = *len * 2;
    403 		if (*len < nlen)
    404 			*len = nlen;
    405 		*s = realloc(*s, *len);
    406 		if (!*s)
    407 			return -ENOMEM;
    408 		if (olen == 0)
    409 			**s = 0;
    410 	}
    411 	strcat(*s, a);
    412 	return 0;
    413 }
    414