Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <mhiramat@kernel.org>
Cc: Alexander Lobakin <aleksander.lobakin@intel.com>
Cc: Dima Kogan <dima@secretsauce.net>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Link: https://lore.kernel.org/r/173099116045.2431889.15772916605719019533.stgit@mhiramat.roam.corp.google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Masami Hiramatsu (Google) and committed by
Arnaldo Carvalho de Melo
313026f3 b9e57722

+102
+100
tools/perf/util/string.c
··· 263 263 return ptr; 264 264 } 265 265 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 + 266 294 /* Like strdup, but do not copy a single backslash */ 267 295 char *strdup_esc(const char *str) 268 296 { ··· 319 291 } while (p); 320 292 321 293 return ret; 294 + } 295 + 296 + /* Remove backslash right before quote and return next quote address. */ 297 + static char *remove_consumed_esc(char *str, int len, int quote) 298 + { 299 + char *ptr = str, *end = str + len; 300 + 301 + while (*ptr != quote && ptr < end) { 302 + if (*ptr == '\\' && *(ptr + 1) == quote) { 303 + memmove(ptr, ptr + 1, end - (ptr + 1)); 304 + /* now *ptr is `quote`. */ 305 + end--; 306 + } 307 + ptr++; 308 + } 309 + 310 + return *ptr == quote ? ptr : NULL; 311 + } 312 + 313 + /* 314 + * Like strdup_esc, but keep quoted string as it is (and single backslash 315 + * before quote is removed). If there is no closed quote, return NULL. 316 + */ 317 + char *strdup_esq(const char *str) 318 + { 319 + char *d, *ret; 320 + 321 + /* If there is no quote, return normal strdup_esc() */ 322 + d = strpbrk_esc((char *)str, "\"'"); 323 + if (!d) 324 + return strdup_esc(str); 325 + 326 + ret = strdup(str); 327 + if (!ret) 328 + return NULL; 329 + 330 + d = ret; 331 + do { 332 + d = strpbrk(d, "\\\"\'"); 333 + if (!d) 334 + break; 335 + 336 + if (*d == '"' || *d == '\'') { 337 + /* This is non-escaped quote */ 338 + int quote = *d; 339 + int len = strlen(d + 1) + 1; 340 + 341 + /* 342 + * Remove the start quote and remove consumed escape (backslash 343 + * before quote) and remove the end quote. If there is no end 344 + * quote, it is the input error. 345 + */ 346 + memmove(d, d + 1, len); 347 + d = remove_consumed_esc(d, len, quote); 348 + if (!d) 349 + goto error; 350 + memmove(d, d + 1, strlen(d + 1) + 1); 351 + } 352 + if (*d == '\\') { 353 + memmove(d, d + 1, strlen(d + 1) + 1); 354 + if (*d == '\\') { 355 + /* double backslash -- keep the second one. */ 356 + d++; 357 + } 358 + } 359 + } while (*d != '\0'); 360 + 361 + return ret; 362 + 363 + error: 364 + free(ret); 365 + return NULL; 322 366 } 323 367 324 368 unsigned int hex(char c)
+2
tools/perf/util/string2.h
··· 37 37 38 38 char *strpbrk_esc(char *str, const char *stopset); 39 39 char *strdup_esc(const char *str); 40 + char *strpbrk_esq(char *str, const char *stopset); 41 + char *strdup_esq(const char *str); 40 42 41 43 unsigned int hex(char c); 42 44 char *strreplace_chars(char needle, const char *haystack, const char *replace);