Full rework of quote_c_style and write_name_quoted.
[git/dscho.git] / quote.c
blobb1efe188d4380b7885cdfbe1cc81072e1604249b
1 #include "cache.h"
2 #include "quote.h"
4 /* Help to copy the thing properly quoted for the shell safety.
5 * any single quote is replaced with '\'', any exclamation point
6 * is replaced with '\!', and the whole thing is enclosed in a
8 * E.g.
9 * original sq_quote result
10 * name ==> name ==> 'name'
11 * a b ==> a b ==> 'a b'
12 * a'b ==> a'\''b ==> 'a'\''b'
13 * a!b ==> a'\!'b ==> 'a'\!'b'
15 #undef EMIT
16 #define EMIT(x) do { if (++len < n) *bp++ = (x); } while(0)
18 static inline int need_bs_quote(char c)
20 return (c == '\'' || c == '!');
23 static size_t sq_quote_buf(char *dst, size_t n, const char *src)
25 char c;
26 char *bp = dst;
27 size_t len = 0;
29 EMIT('\'');
30 while ((c = *src++)) {
31 if (need_bs_quote(c)) {
32 EMIT('\'');
33 EMIT('\\');
34 EMIT(c);
35 EMIT('\'');
36 } else {
37 EMIT(c);
40 EMIT('\'');
42 if ( n )
43 *bp = 0;
45 return len;
48 void sq_quote_print(FILE *stream, const char *src)
50 char c;
52 fputc('\'', stream);
53 while ((c = *src++)) {
54 if (need_bs_quote(c)) {
55 fputs("'\\", stream);
56 fputc(c, stream);
57 fputc('\'', stream);
58 } else {
59 fputc(c, stream);
62 fputc('\'', stream);
65 char *sq_quote_argv(const char** argv, int count)
67 char *buf, *to;
68 int i;
69 size_t len = 0;
71 /* Count argv if needed. */
72 if (count < 0) {
73 for (count = 0; argv[count]; count++)
74 ; /* just counting */
77 /* Special case: no argv. */
78 if (!count)
79 return xcalloc(1,1);
81 /* Get destination buffer length. */
82 for (i = 0; i < count; i++)
83 len += sq_quote_buf(NULL, 0, argv[i]) + 1;
85 /* Alloc destination buffer. */
86 to = buf = xmalloc(len + 1);
88 /* Copy into destination buffer. */
89 for (i = 0; i < count; ++i) {
90 *to++ = ' ';
91 to += sq_quote_buf(to, len, argv[i]);
94 return buf;
98 * Append a string to a string buffer, with or without shell quoting.
99 * Return true if the buffer overflowed.
101 int add_to_string(char **ptrp, int *sizep, const char *str, int quote)
103 char *p = *ptrp;
104 int size = *sizep;
105 int oc;
106 int err = 0;
108 if (quote)
109 oc = sq_quote_buf(p, size, str);
110 else {
111 oc = strlen(str);
112 memcpy(p, str, (size <= oc) ? size - 1 : oc);
115 if (size <= oc) {
116 err = 1;
117 oc = size - 1;
120 *ptrp += oc;
121 **ptrp = '\0';
122 *sizep -= oc;
123 return err;
126 char *sq_dequote(char *arg)
128 char *dst = arg;
129 char *src = arg;
130 char c;
132 if (*src != '\'')
133 return NULL;
134 for (;;) {
135 c = *++src;
136 if (!c)
137 return NULL;
138 if (c != '\'') {
139 *dst++ = c;
140 continue;
142 /* We stepped out of sq */
143 switch (*++src) {
144 case '\0':
145 *dst = 0;
146 return arg;
147 case '\\':
148 c = *++src;
149 if (need_bs_quote(c) && *++src == '\'') {
150 *dst++ = c;
151 continue;
153 /* Fallthrough */
154 default:
155 return NULL;
160 /* 1 means: quote as octal
161 * 0 means: quote as octal if (quote_path_fully)
162 * -1 means: never quote
163 * c: quote as "\\c"
165 #define X8(x) x, x, x, x, x, x, x, x
166 #define X16(x) X8(x), X8(x)
167 static signed char const sq_lookup[256] = {
168 /* 0 1 2 3 4 5 6 7 */
169 /* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 'a',
170 /* 0x08 */ 'b', 't', 'n', 'v', 'f', 'r', 1, 1,
171 /* 0x10 */ X16(1),
172 /* 0x20 */ -1, -1, '"', -1, -1, -1, -1, -1,
173 /* 0x28 */ X16(-1), X16(-1), X16(-1),
174 /* 0x58 */ -1, -1, -1, -1,'\\', -1, -1, -1,
175 /* 0x60 */ X16(-1), X8(-1),
176 /* 0x78 */ -1, -1, -1, -1, -1, -1, -1, 1,
177 /* 0x80 */ /* set to 0 */
180 static inline int sq_must_quote(char c) {
181 return sq_lookup[(unsigned char)c] + quote_path_fully > 0;
184 /* returns the longest prefix not needing a quote up to maxlen if positive.
185 This stops at the first \0 because it's marked as a character needing an
186 escape */
187 static size_t next_quote_pos(const char *s, ssize_t maxlen)
189 size_t len;
190 if (maxlen < 0) {
191 for (len = 0; !sq_must_quote(s[len]); len++);
192 } else {
193 for (len = 0; len < maxlen && !sq_must_quote(s[len]); len++);
195 return len;
199 * C-style name quoting.
201 * (1) if sb and fp are both NULL, inspect the input name and counts the
202 * number of bytes that are needed to hold c_style quoted version of name,
203 * counting the double quotes around it but not terminating NUL, and
204 * returns it.
205 * However, if name does not need c_style quoting, it returns 0.
207 * (2) if sb or fp are not NULL, it emits the c_style quoted version
208 * of name, enclosed with double quotes if asked and needed only.
209 * Return value is the same as in (1).
211 static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
212 struct strbuf *sb, FILE *fp, int no_dq)
214 #undef EMIT
215 #define EMIT(c) \
216 do { \
217 if (sb) strbuf_addch(sb, (c)); \
218 if (fp) fputc((c), fp); \
219 count++; \
220 } while (0)
221 #define EMITBUF(s, l) \
222 do { \
223 if (sb) strbuf_add(sb, (s), (l)); \
224 if (fp) fwrite((s), (l), 1, fp); \
225 count += (l); \
226 } while (0)
228 size_t len, count = 0;
229 const char *p = name;
231 for (;;) {
232 int ch;
234 len = next_quote_pos(p, maxlen);
235 if (len == maxlen || !p[len])
236 break;
238 if (!no_dq && p == name)
239 EMIT('"');
241 EMITBUF(p, len);
242 EMIT('\\');
243 p += len;
244 ch = (unsigned char)*p++;
245 if (sq_lookup[ch] >= ' ') {
246 EMIT(sq_lookup[ch]);
247 } else {
248 EMIT(((ch >> 6) & 03) + '0');
249 EMIT(((ch >> 3) & 07) + '0');
250 EMIT(((ch >> 0) & 07) + '0');
254 EMITBUF(p, len);
255 if (p == name) /* no ending quote needed */
256 return 0;
258 if (!no_dq)
259 EMIT('"');
260 return count;
263 size_t quote_c_style(const char *name, struct strbuf *sb, FILE *fp, int nodq)
265 return quote_c_style_counted(name, -1, sb, fp, nodq);
268 void write_name_quoted(const char *name, FILE *fp, int terminator)
270 if (terminator) {
271 quote_c_style(name, NULL, fp, 0);
272 } else {
273 fputs(name, fp);
275 fputc(terminator, fp);
278 extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
279 const char *name, FILE *fp, int terminator)
281 int needquote = 0;
283 if (terminator) {
284 needquote = next_quote_pos(pfx, pfxlen) < pfxlen
285 || name[next_quote_pos(name, -1)];
287 if (needquote) {
288 fputc('"', fp);
289 quote_c_style_counted(pfx, pfxlen, NULL, fp, 1);
290 quote_c_style(name, NULL, fp, 1);
291 fputc('"', fp);
292 } else {
293 fwrite(pfx, pfxlen, 1, fp);
294 fputs(name, fp);
296 fputc(terminator, fp);
300 * C-style name unquoting.
302 * Quoted should point at the opening double quote.
303 * + Returns 0 if it was able to unquote the string properly, and appends the
304 * result in the strbuf `sb'.
305 * + Returns -1 in case of error, and doesn't touch the strbuf. Though note
306 * that this function will allocate memory in the strbuf, so calling
307 * strbuf_release is mandatory whichever result unquote_c_style returns.
309 * Updates endp pointer to point at one past the ending double quote if given.
311 int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp)
313 size_t oldlen = sb->len, len;
314 int ch, ac;
316 if (*quoted++ != '"')
317 return -1;
319 for (;;) {
320 len = strcspn(quoted, "\"\\");
321 strbuf_add(sb, quoted, len);
322 quoted += len;
324 switch (*quoted++) {
325 case '"':
326 if (endp)
327 *endp = quoted + 1;
328 return 0;
329 case '\\':
330 break;
331 default:
332 goto error;
335 switch ((ch = *quoted++)) {
336 case 'a': ch = '\a'; break;
337 case 'b': ch = '\b'; break;
338 case 'f': ch = '\f'; break;
339 case 'n': ch = '\n'; break;
340 case 'r': ch = '\r'; break;
341 case 't': ch = '\t'; break;
342 case 'v': ch = '\v'; break;
344 case '\\': case '"':
345 break; /* verbatim */
347 /* octal values with first digit over 4 overflow */
348 case '0': case '1': case '2': case '3':
349 ac = ((ch - '0') << 6);
350 if ((ch = *quoted++) < '0' || '7' < ch)
351 goto error;
352 ac |= ((ch - '0') << 3);
353 if ((ch = *quoted++) < '0' || '7' < ch)
354 goto error;
355 ac |= (ch - '0');
356 ch = ac;
357 break;
358 default:
359 goto error;
361 strbuf_addch(sb, ch);
364 error:
365 strbuf_setlen(sb, oldlen);
366 return -1;
369 /* quoting as a string literal for other languages */
371 void perl_quote_print(FILE *stream, const char *src)
373 const char sq = '\'';
374 const char bq = '\\';
375 char c;
377 fputc(sq, stream);
378 while ((c = *src++)) {
379 if (c == sq || c == bq)
380 fputc(bq, stream);
381 fputc(c, stream);
383 fputc(sq, stream);
386 void python_quote_print(FILE *stream, const char *src)
388 const char sq = '\'';
389 const char bq = '\\';
390 const char nl = '\n';
391 char c;
393 fputc(sq, stream);
394 while ((c = *src++)) {
395 if (c == nl) {
396 fputc(bq, stream);
397 fputc('n', stream);
398 continue;
400 if (c == sq || c == bq)
401 fputc(bq, stream);
402 fputc(c, stream);
404 fputc(sq, stream);
407 void tcl_quote_print(FILE *stream, const char *src)
409 char c;
411 fputc('"', stream);
412 while ((c = *src++)) {
413 switch (c) {
414 case '[': case ']':
415 case '{': case '}':
416 case '$': case '\\': case '"':
417 fputc('\\', stream);
418 default:
419 fputc(c, stream);
420 break;
421 case '\f':
422 fputs("\\f", stream);
423 break;
424 case '\r':
425 fputs("\\r", stream);
426 break;
427 case '\n':
428 fputs("\\n", stream);
429 break;
430 case '\t':
431 fputs("\\t", stream);
432 break;
433 case '\v':
434 fputs("\\v", stream);
435 break;
438 fputc('"', stream);