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