1 // SPDX-License-Identifier: GPL-2.0
3 #include <linux/kernel.h>
4 #include <linux/string.h>
7 #include <linux/ctype.h>
9 const char *graph_dotted_line
=
10 "---------------------------------------------------------------------"
11 "---------------------------------------------------------------------"
12 "---------------------------------------------------------------------";
14 "....................................................................."
15 "....................................................................."
16 ".....................................................................";
20 * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
21 * and return its numeric value
23 s64
perf_atoll(const char *str
)
32 length
= strtoll(str
, &p
, 10);
43 /* two-letter suffices */
57 /* we want the cases to match */
59 if (strcmp(p
, "b") != 0)
62 if (strcmp(p
, "B") != 0)
71 /* Character class matching */
72 static bool __match_charclass(const char *pat
, char c
, const char **npat
)
74 bool complement
= false, ret
= true;
80 if (*pat
++ == c
) /* First character is special */
83 while (*pat
&& *pat
!= ']') { /* Matching */
84 if (*pat
== '-' && *(pat
+ 1) != ']') { /* Range */
85 if (*(pat
- 1) <= c
&& c
<= *(pat
+ 1))
87 if (*(pat
- 1) > *(pat
+ 1))
90 } else if (*pat
++ == c
)
98 while (*pat
&& *pat
!= ']') /* Searching closing */
103 return complement
? !ret
: ret
;
109 /* Glob/lazy pattern matching */
110 static bool __match_glob(const char *str
, const char *pat
, bool ignore_space
,
113 while (*str
&& *pat
&& *pat
!= '*') {
115 /* Ignore spaces for lazy matching */
125 if (*pat
== '?') { /* Matches any single character */
129 } else if (*pat
== '[') /* Character classes/Ranges */
130 if (__match_charclass(pat
+ 1, *str
, &pat
)) {
135 else if (*pat
== '\\') /* Escaped char match as normal char */
138 if (tolower(*str
) != tolower(*pat
))
140 } else if (*str
!= *pat
)
145 /* Check wild card */
149 if (!*pat
) /* Tail wild card matches all */
152 if (__match_glob(str
++, pat
, ignore_space
, case_ins
))
155 return !*str
&& !*pat
;
159 * strglobmatch - glob expression pattern matching
160 * @str: the target string to match
161 * @pat: the pattern string to match
163 * This returns true if the @str matches @pat. @pat can includes wildcards
164 * ('*','?') and character classes ([CHARS], complementation and ranges are
165 * also supported). Also, this supports escape character ('\') to use special
166 * characters as normal character.
168 * Note: if @pat syntax is broken, this always returns false.
170 bool strglobmatch(const char *str
, const char *pat
)
172 return __match_glob(str
, pat
, false, false);
175 bool strglobmatch_nocase(const char *str
, const char *pat
)
177 return __match_glob(str
, pat
, false, true);
181 * strlazymatch - matching pattern strings lazily with glob pattern
182 * @str: the target string to match
183 * @pat: the pattern string to match
185 * This is similar to strglobmatch, except this ignores spaces in
188 bool strlazymatch(const char *str
, const char *pat
)
190 return __match_glob(str
, pat
, true, false);
194 * strtailcmp - Compare the tail of two strings
195 * @s1: 1st string to be compared
196 * @s2: 2nd string to be compared
198 * Return 0 if whole of either string is same as another's tail part.
200 int strtailcmp(const char *s1
, const char *s2
)
204 while (--i1
>= 0 && --i2
>= 0) {
205 if (s1
[i1
] != s2
[i2
])
206 return s1
[i1
] - s2
[i2
];
211 char *asprintf_expr_inout_ints(const char *var
, bool in
, size_t nints
, int *ints
)
214 * FIXME: replace this with an expression using log10() when we
215 * find a suitable implementation, maybe the one in the dvb drivers...
217 * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators
219 size_t size
= nints
* 28 + 1; /* \0 */
220 size_t i
, printed
= 0;
221 char *expr
= malloc(size
);
224 const char *or_and
= "||", *eq_neq
= "==";
232 for (i
= 0; i
< nints
; ++i
) {
234 goto out_err_overflow
;
237 printed
+= scnprintf(e
+ printed
, size
- printed
, " %s ", or_and
);
238 printed
+= scnprintf(e
+ printed
, size
- printed
,
239 "%s %s %d", var
, eq_neq
, ints
[i
]);
250 /* Like strpbrk(), but not break if it is right after a backslash (escaped) */
251 char *strpbrk_esc(char *str
, const char *stopset
)
256 ptr
= strpbrk(str
, stopset
);
258 (ptr
== str
+ 1 && *(ptr
- 1) != '\\'))
261 } while (ptr
&& *(ptr
- 1) == '\\' && *(ptr
- 2) != '\\');
266 /* Like strpbrk_esc(), but not break if it is quoted with single/double quotes */
267 char *strpbrk_esq(char *str
, const char *stopset
)
269 char *_stopset
= NULL
;
271 const char *squote
= "'";
272 const char *dquote
= "\"";
274 if (asprintf(&_stopset
, "%s%c%c", stopset
, *squote
, *dquote
) < 0)
278 ptr
= strpbrk_esc(str
, _stopset
);
282 ptr
= strpbrk_esc(ptr
+ 1, squote
);
283 else if (*ptr
== *dquote
)
284 ptr
= strpbrk_esc(ptr
+ 1, dquote
);
294 /* Like strdup, but do not copy a single backslash */
295 char *strdup_esc(const char *str
)
297 char *s
, *d
, *p
, *ret
= strdup(str
);
302 d
= strchr(ret
, '\\');
312 p
= strchr(s
+ 1, '\\');
314 memmove(d
, s
, p
- s
);
318 memmove(d
, s
, strlen(s
) + 1);
324 /* Remove backslash right before quote and return next quote address. */
325 static char *remove_consumed_esc(char *str
, int len
, int quote
)
327 char *ptr
= str
, *end
= str
+ len
;
329 while (*ptr
!= quote
&& ptr
< end
) {
330 if (*ptr
== '\\' && *(ptr
+ 1) == quote
) {
331 memmove(ptr
, ptr
+ 1, end
- (ptr
+ 1));
332 /* now *ptr is `quote`. */
338 return *ptr
== quote
? ptr
: NULL
;
342 * Like strdup_esc, but keep quoted string as it is (and single backslash
343 * before quote is removed). If there is no closed quote, return NULL.
345 char *strdup_esq(const char *str
)
349 /* If there is no quote, return normal strdup_esc() */
350 d
= strpbrk_esc((char *)str
, "\"'");
352 return strdup_esc(str
);
360 d
= strpbrk(d
, "\\\"\'");
364 if (*d
== '"' || *d
== '\'') {
365 /* This is non-escaped quote */
367 int len
= strlen(d
+ 1) + 1;
370 * Remove the start quote and remove consumed escape (backslash
371 * before quote) and remove the end quote. If there is no end
372 * quote, it is the input error.
374 memmove(d
, d
+ 1, len
);
375 d
= remove_consumed_esc(d
, len
, quote
);
378 memmove(d
, d
+ 1, strlen(d
+ 1) + 1);
381 memmove(d
, d
+ 1, strlen(d
+ 1) + 1);
383 /* double backslash -- keep the second one. */
387 } while (*d
!= '\0');
396 unsigned int hex(char c
)
398 if (c
>= '0' && c
<= '9')
400 if (c
>= 'a' && c
<= 'f')
406 * Replace all occurrences of character 'needle' in string 'haystack' with
409 * The new string could be longer so a new string is returned which must be
412 char *strreplace_chars(char needle
, const char *haystack
, const char *replace
)
414 int replace_len
= strlen(replace
);
416 const char *loc
= strchr(haystack
, needle
);
417 const char *from
= haystack
;
420 /* Count occurrences */
422 loc
= strchr(loc
+ 1, needle
);
426 /* Allocate enough space for replacements and reset first location */
427 new_s
= malloc(strlen(haystack
) + (num
* (replace_len
- 1) + 1));
430 loc
= strchr(haystack
, needle
);
434 /* Copy original string up to found char and update positions */
435 memcpy(to
, from
, 1 + loc
- from
);
439 /* Copy replacement string and update positions */
440 memcpy(to
, replace
, replace_len
);
443 /* needle next occurrence or end of string */
444 loc
= strchr(from
, needle
);
447 /* Copy any remaining chars + null */