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