Git fork
at reftables-rust 586 lines 13 kB view raw
1#define DISABLE_SIGN_COMPARE_WARNINGS 2 3#include "git-compat-util.h" 4#include "path.h" 5#include "quote.h" 6#include "strbuf.h" 7#include "strvec.h" 8 9int quote_path_fully = 1; 10 11static inline int need_bs_quote(char c) 12{ 13 return (c == '\'' || c == '!'); 14} 15 16/* Help to copy the thing properly quoted for the shell safety. 17 * any single quote is replaced with '\'', any exclamation point 18 * is replaced with '\!', and the whole thing is enclosed in a 19 * single quote pair. 20 * 21 * E.g. 22 * original sq_quote result 23 * name ==> name ==> 'name' 24 * a b ==> a b ==> 'a b' 25 * a'b ==> a'\''b ==> 'a'\''b' 26 * a!b ==> a'\!'b ==> 'a'\!'b' 27 */ 28void sq_quote_buf(struct strbuf *dst, const char *src) 29{ 30 char *to_free = NULL; 31 32 if (dst->buf == src) 33 to_free = strbuf_detach(dst, NULL); 34 35 strbuf_addch(dst, '\''); 36 while (*src) { 37 size_t len = strcspn(src, "'!"); 38 strbuf_add(dst, src, len); 39 src += len; 40 while (need_bs_quote(*src)) { 41 strbuf_addstr(dst, "'\\"); 42 strbuf_addch(dst, *src++); 43 strbuf_addch(dst, '\''); 44 } 45 } 46 strbuf_addch(dst, '\''); 47 free(to_free); 48} 49 50void sq_quote_buf_pretty(struct strbuf *dst, const char *src) 51{ 52 static const char ok_punct[] = "+,-./:=@_^"; 53 const char *p; 54 55 /* Avoid losing a zero-length string by adding '' */ 56 if (!*src) { 57 strbuf_addstr(dst, "''"); 58 return; 59 } 60 61 for (p = src; *p; p++) { 62 if (!isalnum(*p) && !strchr(ok_punct, *p)) { 63 sq_quote_buf(dst, src); 64 return; 65 } 66 } 67 68 /* if we get here, we did not need quoting */ 69 strbuf_addstr(dst, src); 70} 71 72void sq_quotef(struct strbuf *dst, const char *fmt, ...) 73{ 74 struct strbuf src = STRBUF_INIT; 75 76 va_list ap; 77 va_start(ap, fmt); 78 strbuf_vaddf(&src, fmt, ap); 79 va_end(ap); 80 81 sq_quote_buf(dst, src.buf); 82 strbuf_release(&src); 83} 84 85void sq_quote_argv(struct strbuf *dst, const char **argv) 86{ 87 int i; 88 89 /* Copy into destination buffer. */ 90 strbuf_grow(dst, 255); 91 for (i = 0; argv[i]; ++i) { 92 strbuf_addch(dst, ' '); 93 sq_quote_buf(dst, argv[i]); 94 } 95} 96 97/* 98 * Legacy function to append each argv value, quoted as necessasry, 99 * with whitespace before each value. This results in a leading 100 * space in the result. 101 */ 102void sq_quote_argv_pretty(struct strbuf *dst, const char **argv) 103{ 104 if (argv[0]) 105 strbuf_addch(dst, ' '); 106 sq_append_quote_argv_pretty(dst, argv); 107} 108 109/* 110 * Append each argv value, quoted as necessary, with whitespace between them. 111 */ 112void sq_append_quote_argv_pretty(struct strbuf *dst, const char **argv) 113{ 114 int i; 115 116 for (i = 0; argv[i]; i++) { 117 if (i > 0) 118 strbuf_addch(dst, ' '); 119 sq_quote_buf_pretty(dst, argv[i]); 120 } 121} 122 123char *sq_dequote_step(char *arg, char **next) 124{ 125 char *dst = arg; 126 char *src = arg; 127 char c; 128 129 if (*src != '\'') 130 return NULL; 131 for (;;) { 132 c = *++src; 133 if (!c) 134 return NULL; 135 if (c != '\'') { 136 *dst++ = c; 137 continue; 138 } 139 /* We stepped out of sq */ 140 switch (*++src) { 141 case '\0': 142 *dst = 0; 143 if (next) 144 *next = NULL; 145 return arg; 146 case '\\': 147 /* 148 * Allow backslashed characters outside of 149 * single-quotes only if they need escaping, 150 * and only if we resume the single-quoted part 151 * afterward. 152 */ 153 if (need_bs_quote(src[1]) && src[2] == '\'') { 154 *dst++ = src[1]; 155 src += 2; 156 continue; 157 } 158 /* Fallthrough */ 159 default: 160 if (!next) 161 return NULL; 162 *dst = 0; 163 *next = src; 164 return arg; 165 } 166 } 167} 168 169char *sq_dequote(char *arg) 170{ 171 return sq_dequote_step(arg, NULL); 172} 173 174static int sq_dequote_to_argv_internal(char *arg, 175 const char ***argv, int *nr, int *alloc, 176 struct strvec *array) 177{ 178 char *next = arg; 179 180 if (!*arg) 181 return 0; 182 do { 183 char *dequoted = sq_dequote_step(next, &next); 184 if (!dequoted) 185 return -1; 186 if (next) { 187 char c; 188 if (!isspace(*next)) 189 return -1; 190 do { 191 c = *++next; 192 } while (isspace(c)); 193 } 194 if (argv) { 195 ALLOC_GROW(*argv, *nr + 1, *alloc); 196 (*argv)[(*nr)++] = dequoted; 197 } 198 if (array) 199 strvec_push(array, dequoted); 200 } while (next); 201 202 return 0; 203} 204 205int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc) 206{ 207 return sq_dequote_to_argv_internal(arg, argv, nr, alloc, NULL); 208} 209 210int sq_dequote_to_strvec(char *arg, struct strvec *array) 211{ 212 return sq_dequote_to_argv_internal(arg, NULL, NULL, NULL, array); 213} 214 215/* 1 means: quote as octal 216 * 0 means: quote as octal if (quote_path_fully) 217 * -1 means: never quote 218 * c: quote as "\\c" 219 */ 220#define X8(x) x, x, x, x, x, x, x, x 221#define X16(x) X8(x), X8(x) 222static signed char const cq_lookup[256] = { 223 /* 0 1 2 3 4 5 6 7 */ 224 /* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 'a', 225 /* 0x08 */ 'b', 't', 'n', 'v', 'f', 'r', 1, 1, 226 /* 0x10 */ X16(1), 227 /* 0x20 */ -1, -1, '"', -1, -1, -1, -1, -1, 228 /* 0x28 */ X16(-1), X16(-1), X16(-1), 229 /* 0x58 */ -1, -1, -1, -1,'\\', -1, -1, -1, 230 /* 0x60 */ X16(-1), X8(-1), 231 /* 0x78 */ -1, -1, -1, -1, -1, -1, -1, 1, 232 /* 0x80 */ /* set to 0 */ 233}; 234 235static inline int cq_must_quote(char c) 236{ 237 return cq_lookup[(unsigned char)c] + quote_path_fully > 0; 238} 239 240/* returns the longest prefix not needing a quote up to maxlen if positive. 241 This stops at the first \0 because it's marked as a character needing an 242 escape */ 243static size_t next_quote_pos(const char *s, ssize_t maxlen) 244{ 245 size_t len; 246 if (maxlen < 0) { 247 for (len = 0; !cq_must_quote(s[len]); len++); 248 } else { 249 for (len = 0; len < maxlen && !cq_must_quote(s[len]); len++); 250 } 251 return len; 252} 253 254/* 255 * C-style name quoting. 256 * 257 * (1) if sb and fp are both NULL, inspect the input name and counts the 258 * number of bytes that are needed to hold c_style quoted version of name, 259 * counting the double quotes around it but not terminating NUL, and 260 * returns it. 261 * However, if name does not need c_style quoting, it returns 0. 262 * 263 * (2) if sb or fp are not NULL, it emits the c_style quoted version 264 * of name, enclosed with double quotes if asked and needed only. 265 * Return value is the same as in (1). 266 */ 267static size_t quote_c_style_counted(const char *name, ssize_t maxlen, 268 struct strbuf *sb, FILE *fp, unsigned flags) 269{ 270#undef EMIT 271#define EMIT(c) \ 272 do { \ 273 if (sb) strbuf_addch(sb, (c)); \ 274 if (fp) fputc((c), fp); \ 275 count++; \ 276 } while (0) 277#define EMITBUF(s, l) \ 278 do { \ 279 if (sb) strbuf_add(sb, (s), (l)); \ 280 if (fp) fwrite((s), (l), 1, fp); \ 281 count += (l); \ 282 } while (0) 283 284 int no_dq = !!(flags & CQUOTE_NODQ); 285 size_t len, count = 0; 286 const char *p = name; 287 288 for (;;) { 289 int ch; 290 291 len = next_quote_pos(p, maxlen); 292 if (len == maxlen || (maxlen < 0 && !p[len])) 293 break; 294 295 if (!no_dq && p == name) 296 EMIT('"'); 297 298 EMITBUF(p, len); 299 EMIT('\\'); 300 p += len; 301 ch = (unsigned char)*p++; 302 if (maxlen >= 0) 303 maxlen -= len + 1; 304 if (cq_lookup[ch] >= ' ') { 305 EMIT(cq_lookup[ch]); 306 } else { 307 EMIT(((ch >> 6) & 03) + '0'); 308 EMIT(((ch >> 3) & 07) + '0'); 309 EMIT(((ch >> 0) & 07) + '0'); 310 } 311 } 312 313 EMITBUF(p, len); 314 if (p == name) /* no ending quote needed */ 315 return 0; 316 317 if (!no_dq) 318 EMIT('"'); 319 return count; 320} 321 322size_t quote_c_style(const char *name, struct strbuf *sb, FILE *fp, unsigned flags) 323{ 324 return quote_c_style_counted(name, -1, sb, fp, flags); 325} 326 327void quote_two_c_style(struct strbuf *sb, const char *prefix, const char *path, 328 unsigned flags) 329{ 330 int nodq = !!(flags & CQUOTE_NODQ); 331 if (quote_c_style(prefix, NULL, NULL, 0) || 332 quote_c_style(path, NULL, NULL, 0)) { 333 if (!nodq) 334 strbuf_addch(sb, '"'); 335 quote_c_style(prefix, sb, NULL, CQUOTE_NODQ); 336 quote_c_style(path, sb, NULL, CQUOTE_NODQ); 337 if (!nodq) 338 strbuf_addch(sb, '"'); 339 } else { 340 strbuf_addstr(sb, prefix); 341 strbuf_addstr(sb, path); 342 } 343} 344 345void write_name_quoted(const char *name, FILE *fp, int terminator) 346{ 347 if (terminator) { 348 quote_c_style(name, NULL, fp, 0); 349 } else { 350 fputs(name, fp); 351 } 352 fputc(terminator, fp); 353} 354 355void write_name_quoted_relative(const char *name, const char *prefix, 356 FILE *fp, int terminator) 357{ 358 struct strbuf sb = STRBUF_INIT; 359 360 name = relative_path(name, prefix, &sb); 361 write_name_quoted(name, fp, terminator); 362 363 strbuf_release(&sb); 364} 365 366/* quote path as relative to the given prefix */ 367char *quote_path(const char *in, const char *prefix, struct strbuf *out, unsigned flags) 368{ 369 struct strbuf sb = STRBUF_INIT; 370 const char *rel = relative_path(in, prefix, &sb); 371 int force_dq = ((flags & QUOTE_PATH_QUOTE_SP) && strchr(rel, ' ')); 372 373 strbuf_reset(out); 374 375 /* 376 * If the caller wants us to enclose the output in a dq-pair 377 * whether quote_c_style_counted() needs to, we do it ourselves 378 * and tell quote_c_style_counted() not to. 379 */ 380 if (force_dq) 381 strbuf_addch(out, '"'); 382 quote_c_style_counted(rel, strlen(rel), out, NULL, 383 force_dq ? CQUOTE_NODQ : 0); 384 if (force_dq) 385 strbuf_addch(out, '"'); 386 strbuf_release(&sb); 387 388 return out->buf; 389} 390 391/* 392 * C-style name unquoting. 393 * 394 * Quoted should point at the opening double quote. 395 * + Returns 0 if it was able to unquote the string properly, and appends the 396 * result in the strbuf `sb'. 397 * + Returns -1 in case of error, and doesn't touch the strbuf. Though note 398 * that this function will allocate memory in the strbuf, so calling 399 * strbuf_release is mandatory whichever result unquote_c_style returns. 400 * 401 * Updates endp pointer to point at one past the ending double quote if given. 402 */ 403int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp) 404{ 405 size_t oldlen = sb->len, len; 406 int ch, ac; 407 408 if (*quoted++ != '"') 409 return -1; 410 411 for (;;) { 412 len = strcspn(quoted, "\"\\"); 413 strbuf_add(sb, quoted, len); 414 quoted += len; 415 416 switch (*quoted++) { 417 case '"': 418 if (endp) 419 *endp = quoted; 420 return 0; 421 case '\\': 422 break; 423 default: 424 goto error; 425 } 426 427 switch ((ch = *quoted++)) { 428 case 'a': ch = '\a'; break; 429 case 'b': ch = '\b'; break; 430 case 'f': ch = '\f'; break; 431 case 'n': ch = '\n'; break; 432 case 'r': ch = '\r'; break; 433 case 't': ch = '\t'; break; 434 case 'v': ch = '\v'; break; 435 436 case '\\': case '"': 437 break; /* verbatim */ 438 439 /* octal values with first digit over 4 overflow */ 440 case '0': case '1': case '2': case '3': 441 ac = ((ch - '0') << 6); 442 if ((ch = *quoted++) < '0' || '7' < ch) 443 goto error; 444 ac |= ((ch - '0') << 3); 445 if ((ch = *quoted++) < '0' || '7' < ch) 446 goto error; 447 ac |= (ch - '0'); 448 ch = ac; 449 break; 450 default: 451 goto error; 452 } 453 strbuf_addch(sb, ch); 454 } 455 456 error: 457 strbuf_setlen(sb, oldlen); 458 return -1; 459} 460 461/* quoting as a string literal for other languages */ 462 463void perl_quote_buf(struct strbuf *sb, const char *src) 464{ 465 const char sq = '\''; 466 const char bq = '\\'; 467 char c; 468 469 strbuf_addch(sb, sq); 470 while ((c = *src++)) { 471 if (c == sq || c == bq) 472 strbuf_addch(sb, bq); 473 strbuf_addch(sb, c); 474 } 475 strbuf_addch(sb, sq); 476} 477 478void perl_quote_buf_with_len(struct strbuf *sb, const char *src, size_t len) 479{ 480 const char sq = '\''; 481 const char bq = '\\'; 482 const char *c = src; 483 const char *end = src + len; 484 485 strbuf_addch(sb, sq); 486 while (c != end) { 487 if (*c == sq || *c == bq) 488 strbuf_addch(sb, bq); 489 strbuf_addch(sb, *c); 490 c++; 491 } 492 strbuf_addch(sb, sq); 493} 494 495void python_quote_buf(struct strbuf *sb, const char *src) 496{ 497 const char sq = '\''; 498 const char bq = '\\'; 499 const char nl = '\n'; 500 char c; 501 502 strbuf_addch(sb, sq); 503 while ((c = *src++)) { 504 if (c == nl) { 505 strbuf_addch(sb, bq); 506 strbuf_addch(sb, 'n'); 507 continue; 508 } 509 if (c == sq || c == bq) 510 strbuf_addch(sb, bq); 511 strbuf_addch(sb, c); 512 } 513 strbuf_addch(sb, sq); 514} 515 516void tcl_quote_buf(struct strbuf *sb, const char *src) 517{ 518 char c; 519 520 strbuf_addch(sb, '"'); 521 while ((c = *src++)) { 522 switch (c) { 523 case '[': case ']': 524 case '{': case '}': 525 case '$': case '\\': case '"': 526 strbuf_addch(sb, '\\'); 527 /* fallthrough */ 528 default: 529 strbuf_addch(sb, c); 530 break; 531 case '\f': 532 strbuf_addstr(sb, "\\f"); 533 break; 534 case '\r': 535 strbuf_addstr(sb, "\\r"); 536 break; 537 case '\n': 538 strbuf_addstr(sb, "\\n"); 539 break; 540 case '\t': 541 strbuf_addstr(sb, "\\t"); 542 break; 543 case '\v': 544 strbuf_addstr(sb, "\\v"); 545 break; 546 } 547 } 548 strbuf_addch(sb, '"'); 549} 550 551void basic_regex_quote_buf(struct strbuf *sb, const char *src) 552{ 553 char c; 554 555 if (*src == '^') { 556 /* only beginning '^' is special and needs quoting */ 557 strbuf_addch(sb, '\\'); 558 strbuf_addch(sb, *src++); 559 } 560 if (*src == '*') 561 /* beginning '*' is not special, no quoting */ 562 strbuf_addch(sb, *src++); 563 564 while ((c = *src++)) { 565 switch (c) { 566 case '[': 567 case '.': 568 case '\\': 569 case '*': 570 strbuf_addch(sb, '\\'); 571 strbuf_addch(sb, c); 572 break; 573 574 case '$': 575 /* only the end '$' is special and needs quoting */ 576 if (*src == '\0') 577 strbuf_addch(sb, '\\'); 578 strbuf_addch(sb, c); 579 break; 580 581 default: 582 strbuf_addch(sb, c); 583 break; 584 } 585 } 586}