blob: e716a6e5bb19cf37aed1e421c30b08926735494e [file] [log] [blame]
Hitoshi Mitaked2fb8b42009-11-15 20:36:53 +09001#include "util.h"
Jiri Olsab232e072012-09-10 18:50:17 +02002#include "linux/string.h"
Arnaldo Carvalho de Meloea5cc872009-06-01 22:31:03 -03003
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -03004#include "sane_ctype.h"
5
Hitoshi Mitaked2fb8b42009-11-15 20:36:53 +09006#define K 1024LL
7/*
8 * perf_atoll()
9 * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
10 * and return its numeric value
11 */
12s64 perf_atoll(const char *str)
13{
Al Viro8ba7f6c2014-08-29 12:37:29 -040014 s64 length;
15 char *p;
16 char c;
Hitoshi Mitaked2fb8b42009-11-15 20:36:53 +090017
18 if (!isdigit(str[0]))
19 goto out_err;
20
Al Viro8ba7f6c2014-08-29 12:37:29 -040021 length = strtoll(str, &p, 10);
22 switch (c = *p++) {
23 case 'b': case 'B':
24 if (*p)
Hitoshi Mitaked2fb8b42009-11-15 20:36:53 +090025 goto out_err;
Arnaldo Carvalho de Melo94bdd5e2017-02-08 17:01:46 -030026
27 __fallthrough;
Al Viro8ba7f6c2014-08-29 12:37:29 -040028 case '\0':
29 return length;
Hitoshi Mitaked2fb8b42009-11-15 20:36:53 +090030 default:
Al Viro8ba7f6c2014-08-29 12:37:29 -040031 goto out_err;
32 /* two-letter suffices */
33 case 'k': case 'K':
34 length <<= 10;
Hitoshi Mitaked2fb8b42009-11-15 20:36:53 +090035 break;
Al Viro8ba7f6c2014-08-29 12:37:29 -040036 case 'm': case 'M':
37 length <<= 20;
38 break;
39 case 'g': case 'G':
40 length <<= 30;
41 break;
42 case 't': case 'T':
43 length <<= 40;
44 break;
Hitoshi Mitaked2fb8b42009-11-15 20:36:53 +090045 }
Al Viro8ba7f6c2014-08-29 12:37:29 -040046 /* we want the cases to match */
47 if (islower(c)) {
48 if (strcmp(p, "b") != 0)
49 goto out_err;
50 } else {
51 if (strcmp(p, "B") != 0)
52 goto out_err;
53 }
54 return length;
Hitoshi Mitaked2fb8b42009-11-15 20:36:53 +090055
56out_err:
Al Viro8ba7f6c2014-08-29 12:37:29 -040057 return -1;
Hitoshi Mitaked2fb8b42009-11-15 20:36:53 +090058}
Masami Hiramatsue1c01d62009-11-30 19:20:05 -050059
60/*
61 * Helper function for splitting a string into an argv-like array.
Lucas De Marchi25985ed2011-03-30 22:57:33 -030062 * originally copied from lib/argv_split.c
Masami Hiramatsue1c01d62009-11-30 19:20:05 -050063 */
64static const char *skip_sep(const char *cp)
65{
66 while (*cp && isspace(*cp))
67 cp++;
68
69 return cp;
70}
71
72static const char *skip_arg(const char *cp)
73{
74 while (*cp && !isspace(*cp))
75 cp++;
76
77 return cp;
78}
79
80static int count_argc(const char *str)
81{
82 int count = 0;
83
84 while (*str) {
85 str = skip_sep(str);
86 if (*str) {
87 count++;
88 str = skip_arg(str);
89 }
90 }
91
92 return count;
93}
94
95/**
96 * argv_free - free an argv
97 * @argv - the argument vector to be freed
98 *
99 * Frees an argv and the strings it points to.
100 */
101void argv_free(char **argv)
102{
103 char **p;
104 for (p = argv; *p; p++)
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -0300105 zfree(p);
Masami Hiramatsue1c01d62009-11-30 19:20:05 -0500106
107 free(argv);
108}
109
110/**
111 * argv_split - split a string at whitespace, returning an argv
112 * @str: the string to be split
113 * @argcp: returned argument count
114 *
115 * Returns an array of pointers to strings which are split out from
116 * @str. This is performed by strictly splitting on white-space; no
117 * quote processing is performed. Multiple whitespace characters are
118 * considered to be a single argument separator. The returned array
119 * is always NULL-terminated. Returns NULL on memory allocation
120 * failure.
121 */
122char **argv_split(const char *str, int *argcp)
123{
124 int argc = count_argc(str);
125 char **argv = zalloc(sizeof(*argv) * (argc+1));
126 char **argvp;
127
128 if (argv == NULL)
129 goto out;
130
131 if (argcp)
132 *argcp = argc;
133
134 argvp = argv;
135
136 while (*str) {
137 str = skip_sep(str);
138
139 if (*str) {
140 const char *p = str;
141 char *t;
142
143 str = skip_arg(str);
144
145 t = strndup(p, str-p);
146 if (t == NULL)
147 goto fail;
148 *argvp++ = t;
149 }
150 }
151 *argvp = NULL;
152
153out:
154 return argv;
155
156fail:
157 argv_free(argv);
158 return NULL;
159}
Masami Hiramatsubbbb5212009-12-15 10:32:10 -0500160
Masami Hiramatsu6964cd22010-01-05 17:47:24 -0500161/* Character class matching */
162static bool __match_charclass(const char *pat, char c, const char **npat)
163{
164 bool complement = false, ret = true;
165
166 if (*pat == '!') {
167 complement = true;
168 pat++;
169 }
170 if (*pat++ == c) /* First character is special */
171 goto end;
172
173 while (*pat && *pat != ']') { /* Matching */
174 if (*pat == '-' && *(pat + 1) != ']') { /* Range */
175 if (*(pat - 1) <= c && c <= *(pat + 1))
176 goto end;
177 if (*(pat - 1) > *(pat + 1))
178 goto error;
179 pat += 2;
180 } else if (*pat++ == c)
181 goto end;
182 }
183 if (!*pat)
184 goto error;
185 ret = false;
186
187end:
188 while (*pat && *pat != ']') /* Searching closing */
189 pat++;
190 if (!*pat)
191 goto error;
192 *npat = pat + 1;
193 return complement ? !ret : ret;
194
195error:
196 return false;
197}
198
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500199/* Glob/lazy pattern matching */
Andi Kleen38d14f02016-10-19 10:50:01 -0700200static bool __match_glob(const char *str, const char *pat, bool ignore_space,
201 bool case_ins)
Masami Hiramatsubbbb5212009-12-15 10:32:10 -0500202{
203 while (*str && *pat && *pat != '*') {
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500204 if (ignore_space) {
205 /* Ignore spaces for lazy matching */
206 if (isspace(*str)) {
207 str++;
208 continue;
209 }
210 if (isspace(*pat)) {
211 pat++;
212 continue;
213 }
214 }
Masami Hiramatsu6964cd22010-01-05 17:47:24 -0500215 if (*pat == '?') { /* Matches any single character */
Masami Hiramatsubbbb5212009-12-15 10:32:10 -0500216 str++;
217 pat++;
Masami Hiramatsu6964cd22010-01-05 17:47:24 -0500218 continue;
219 } else if (*pat == '[') /* Character classes/Ranges */
220 if (__match_charclass(pat + 1, *str, &pat)) {
221 str++;
222 continue;
223 } else
Masami Hiramatsubbbb5212009-12-15 10:32:10 -0500224 return false;
Masami Hiramatsu6964cd22010-01-05 17:47:24 -0500225 else if (*pat == '\\') /* Escaped char match as normal char */
226 pat++;
Andi Kleen38d14f02016-10-19 10:50:01 -0700227 if (case_ins) {
228 if (tolower(*str) != tolower(*pat))
229 return false;
230 } else if (*str != *pat)
Masami Hiramatsu6964cd22010-01-05 17:47:24 -0500231 return false;
Andi Kleen38d14f02016-10-19 10:50:01 -0700232 str++;
233 pat++;
Masami Hiramatsubbbb5212009-12-15 10:32:10 -0500234 }
235 /* Check wild card */
236 if (*pat == '*') {
237 while (*pat == '*')
238 pat++;
239 if (!*pat) /* Tail wild card matches all */
240 return true;
241 while (*str)
Andi Kleen38d14f02016-10-19 10:50:01 -0700242 if (__match_glob(str++, pat, ignore_space, case_ins))
Masami Hiramatsubbbb5212009-12-15 10:32:10 -0500243 return true;
244 }
245 return !*str && !*pat;
246}
247
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500248/**
249 * strglobmatch - glob expression pattern matching
250 * @str: the target string to match
251 * @pat: the pattern string to match
252 *
253 * This returns true if the @str matches @pat. @pat can includes wildcards
254 * ('*','?') and character classes ([CHARS], complementation and ranges are
255 * also supported). Also, this supports escape character ('\') to use special
256 * characters as normal character.
257 *
258 * Note: if @pat syntax is broken, this always returns false.
259 */
260bool strglobmatch(const char *str, const char *pat)
261{
Andi Kleen38d14f02016-10-19 10:50:01 -0700262 return __match_glob(str, pat, false, false);
263}
264
265bool strglobmatch_nocase(const char *str, const char *pat)
266{
267 return __match_glob(str, pat, false, true);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500268}
269
270/**
271 * strlazymatch - matching pattern strings lazily with glob pattern
272 * @str: the target string to match
273 * @pat: the pattern string to match
274 *
275 * This is similar to strglobmatch, except this ignores spaces in
276 * the target string.
277 */
278bool strlazymatch(const char *str, const char *pat)
279{
Andi Kleen38d14f02016-10-19 10:50:01 -0700280 return __match_glob(str, pat, true, false);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500281}
Masami Hiramatsubad03ae2011-06-27 16:27:15 +0900282
283/**
284 * strtailcmp - Compare the tail of two strings
285 * @s1: 1st string to be compared
286 * @s2: 2nd string to be compared
287 *
288 * Return 0 if whole of either string is same as another's tail part.
289 */
290int strtailcmp(const char *s1, const char *s2)
291{
292 int i1 = strlen(s1);
293 int i2 = strlen(s2);
294 while (--i1 >= 0 && --i2 >= 0) {
295 if (s1[i1] != s2[i2])
296 return s1[i1] - s2[i2];
297 }
298 return 0;
299}
300
Arnaldo Carvalho de Melocb1a28a2012-06-07 18:23:31 -0300301/**
Jiri Olsaea36c462012-10-27 23:18:31 +0200302 * strxfrchar - Locate and replace character in @s
303 * @s: The string to be searched/changed.
304 * @from: Source character to be replaced.
305 * @to: Destination character.
306 *
307 * Return pointer to the changed string.
308 */
309char *strxfrchar(char *s, char from, char to)
310{
311 char *p = s;
312
313 while ((p = strchr(p, from)) != NULL)
314 *p++ = to;
315
316 return s;
317}
318
319/**
Namhyung Kim08aa9cc2013-01-22 18:09:41 +0900320 * ltrim - Removes leading whitespace from @s.
321 * @s: The string to be stripped.
322 *
323 * Return pointer to the first non-whitespace character in @s.
324 */
325char *ltrim(char *s)
326{
Arnaldo Carvalho de Meloecbe5e12017-04-07 12:19:38 -0300327 while (isspace(*s))
Namhyung Kim08aa9cc2013-01-22 18:09:41 +0900328 s++;
Namhyung Kim08aa9cc2013-01-22 18:09:41 +0900329
330 return s;
331}
332
333/**
Arnaldo Carvalho de Melocb1a28a2012-06-07 18:23:31 -0300334 * rtrim - Removes trailing whitespace from @s.
335 * @s: The string to be stripped.
336 *
337 * Note that the first trailing whitespace is replaced with a %NUL-terminator
338 * in the given string @s. Returns @s.
339 */
340char *rtrim(char *s)
341{
342 size_t size = strlen(s);
343 char *end;
344
345 if (!size)
346 return s;
347
348 end = s + size - 1;
349 while (end >= s && isspace(*end))
350 end--;
351 *(end + 1) = '\0';
352
353 return s;
354}
Jiri Olsab232e072012-09-10 18:50:17 +0200355
Arnaldo Carvalho de Melo93ec4ce2015-07-02 17:48:23 -0300356char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
357{
358 /*
359 * FIXME: replace this with an expression using log10() when we
360 * find a suitable implementation, maybe the one in the dvb drivers...
361 *
362 * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators
363 */
364 size_t size = nints * 28 + 1; /* \0 */
365 size_t i, printed = 0;
366 char *expr = malloc(size);
367
368 if (expr) {
369 const char *or_and = "||", *eq_neq = "==";
370 char *e = expr;
371
372 if (!in) {
373 or_and = "&&";
374 eq_neq = "!=";
375 }
376
377 for (i = 0; i < nints; ++i) {
378 if (printed == size)
379 goto out_err_overflow;
380
381 if (i > 0)
382 printed += snprintf(e + printed, size - printed, " %s ", or_and);
383 printed += scnprintf(e + printed, size - printed,
384 "%s %s %d", var, eq_neq, ints[i]);
385 }
386 }
387
388 return expr;
389
390out_err_overflow:
391 free(expr);
392 return NULL;
393}