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