Skip to content

Commit 313026f

Browse files
mhiramatacmel
authored andcommitted
perf string: Add strpbrk_esq() and strdup_esq() for escape and quote
strpbrk_esq() and strdup_esq() are new variants for strpbrk() and strdup() which handles escaped characters and quoted strings. - strpbrk_esq() searches specified set of characters but ignores the escaped characters and quoted strings. e.g. strpbrk_esq("'quote\d' \queue quiz", "qd") returns "quiz". - strdup_esq() duplicates string but removes backslash and quotes which is used for quotation. It also keeps the string (including backslash) in the quoted part. e.g. strdup_esq("'quote\d' \queue quiz") returns "quote\d queue quiz". The (single, double) quotes in the quoted part should be escaped by backslash. In this case, strdup_esq() removes that backslash. The same quotes must be paired. If you use double quotation, you need to use the double quotation to close the quoted part. Signed-off-by: Masami Hiramatsu <[email protected]> Cc: Alexander Lobakin <[email protected]> Cc: Dima Kogan <[email protected]> Cc: Ian Rogers <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Przemek Kitszel <[email protected]> Link: https://lore.kernel.org/r/173099116045.2431889.15772916605719019533.stgit@mhiramat.roam.corp.google.com Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent b9e5772 commit 313026f

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

tools/perf/util/string.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,34 @@ char *strpbrk_esc(char *str, const char *stopset)
263263
return ptr;
264264
}
265265

266+
/* Like strpbrk_esc(), but not break if it is quoted with single/double quotes */
267+
char *strpbrk_esq(char *str, const char *stopset)
268+
{
269+
char *_stopset = NULL;
270+
char *ptr;
271+
const char *squote = "'";
272+
const char *dquote = "\"";
273+
274+
if (asprintf(&_stopset, "%s%c%c", stopset, *squote, *dquote) < 0)
275+
return NULL;
276+
277+
do {
278+
ptr = strpbrk_esc(str, _stopset);
279+
if (!ptr)
280+
break;
281+
if (*ptr == *squote)
282+
ptr = strpbrk_esc(ptr + 1, squote);
283+
else if (*ptr == *dquote)
284+
ptr = strpbrk_esc(ptr + 1, dquote);
285+
else
286+
break;
287+
str = ptr + 1;
288+
} while (ptr);
289+
290+
free(_stopset);
291+
return ptr;
292+
}
293+
266294
/* Like strdup, but do not copy a single backslash */
267295
char *strdup_esc(const char *str)
268296
{
@@ -293,6 +321,78 @@ char *strdup_esc(const char *str)
293321
return ret;
294322
}
295323

324+
/* Remove backslash right before quote and return next quote address. */
325+
static char *remove_consumed_esc(char *str, int len, int quote)
326+
{
327+
char *ptr = str, *end = str + len;
328+
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`. */
333+
end--;
334+
}
335+
ptr++;
336+
}
337+
338+
return *ptr == quote ? ptr : NULL;
339+
}
340+
341+
/*
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.
344+
*/
345+
char *strdup_esq(const char *str)
346+
{
347+
char *d, *ret;
348+
349+
/* If there is no quote, return normal strdup_esc() */
350+
d = strpbrk_esc((char *)str, "\"'");
351+
if (!d)
352+
return strdup_esc(str);
353+
354+
ret = strdup(str);
355+
if (!ret)
356+
return NULL;
357+
358+
d = ret;
359+
do {
360+
d = strpbrk(d, "\\\"\'");
361+
if (!d)
362+
break;
363+
364+
if (*d == '"' || *d == '\'') {
365+
/* This is non-escaped quote */
366+
int quote = *d;
367+
int len = strlen(d + 1) + 1;
368+
369+
/*
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.
373+
*/
374+
memmove(d, d + 1, len);
375+
d = remove_consumed_esc(d, len, quote);
376+
if (!d)
377+
goto error;
378+
memmove(d, d + 1, strlen(d + 1) + 1);
379+
}
380+
if (*d == '\\') {
381+
memmove(d, d + 1, strlen(d + 1) + 1);
382+
if (*d == '\\') {
383+
/* double backslash -- keep the second one. */
384+
d++;
385+
}
386+
}
387+
} while (*d != '\0');
388+
389+
return ret;
390+
391+
error:
392+
free(ret);
393+
return NULL;
394+
}
395+
296396
unsigned int hex(char c)
297397
{
298398
if (c >= '0' && c <= '9')

tools/perf/util/string2.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ char *asprintf__tp_filter_pids(size_t npids, pid_t *pids);
3737

3838
char *strpbrk_esc(char *str, const char *stopset);
3939
char *strdup_esc(const char *str);
40+
char *strpbrk_esq(char *str, const char *stopset);
41+
char *strdup_esq(const char *str);
4042

4143
unsigned int hex(char c);
4244
char *strreplace_chars(char needle, const char *haystack, const char *replace);

0 commit comments

Comments
 (0)