| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include <string.h> | ||
| 2 | #include "serialize.h" | ||
| 3 | #include "util/ascii.h" | ||
| 4 | #include "util/numtostr.h" | ||
| 5 | |||
| 6 | typedef enum { | ||
| 7 | NO_QUOTE, | ||
| 8 | SINGLE_QUOTE, | ||
| 9 | DOUBLE_QUOTE, | ||
| 10 | } SerializeType; | ||
| 11 | |||
| 12 | static const char escmap[] = { | ||
| 13 | [0x07] = 'a', | ||
| 14 | [0x08] = 'b', | ||
| 15 | [0x09] = 't', | ||
| 16 | [0x0A] = 'n', | ||
| 17 | [0x0B] = 'v', | ||
| 18 | [0x0C] = 'f', | ||
| 19 | [0x0D] = 'r', | ||
| 20 | [0x1B] = 'e', | ||
| 21 | ['"'] = '"', | ||
| 22 | ['\\'] = '\\', | ||
| 23 | }; | ||
| 24 | |||
| 25 | 13 | static void string_append_dquoted_arg(String *s, StringView arg) | |
| 26 | { | ||
| 27 | 13 | string_append_byte(s, '"'); | |
| 28 | |||
| 29 |
2/2✓ Branch 12 → 4 taken 473 times.
✓ Branch 12 → 13 taken 13 times.
|
486 | for (size_t i = 0, n = arg.length; i < n; i++) { |
| 30 | 473 | char *buf = string_reserve_space(s, 4); | |
| 31 | 473 | size_t pos = 0; | |
| 32 | 473 | unsigned char ch = arg.data[i]; | |
| 33 |
4/4✓ Branch 5 → 6 taken 133 times.
✓ Branch 5 → 8 taken 340 times.
✓ Branch 6 → 7 taken 23 times.
✓ Branch 6 → 8 taken 110 times.
|
473 | if (unlikely(ch < sizeof(escmap) && escmap[ch])) { |
| 34 | 23 | buf[pos++] = '\\'; | |
| 35 | 23 | ch = escmap[ch]; | |
| 36 |
2/2✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 11 taken 448 times.
|
450 | } else if (unlikely(ascii_iscntrl(ch))) { |
| 37 | 2 | pos += copyliteral(buf + pos, "\\x"); | |
| 38 | 2 | buf[pos++] = hextable[(ch >> 4) & 0xF]; | |
| 39 | 2 | ch = hextable[ch & 0xF]; | |
| 40 | } | ||
| 41 | 473 | buf[pos++] = ch; | |
| 42 | 473 | s->len += pos; | |
| 43 | } | ||
| 44 | |||
| 45 | 13 | string_append_byte(s, '"'); | |
| 46 | 13 | } | |
| 47 | |||
| 48 | 1268 | static SerializeType get_serialize_type(const char *arg, size_t n) | |
| 49 | { | ||
| 50 | 1268 | SerializeType type = NO_QUOTE; | |
| 51 |
2/2✓ Branch 10 → 3 taken 14357 times.
✓ Branch 10 → 11 taken 1255 times.
|
15612 | for (size_t i = 0; i < n; i++) { |
| 52 | 14357 | const unsigned char c = arg[i]; | |
| 53 |
3/4✓ Branch 3 → 4 taken 14344 times.
✓ Branch 3 → 11 taken 13 times.
✓ Branch 4 → 5 taken 14344 times.
✗ Branch 4 → 11 not taken.
|
14357 | if (c == '\'' || c < 0x20 || c == 0x7F) { |
| 54 | return DOUBLE_QUOTE; | ||
| 55 | } | ||
| 56 |
6/6✓ Branch 5 → 6 taken 13952 times.
✓ Branch 5 → 8 taken 392 times.
✓ Branch 6 → 7 taken 13925 times.
✓ Branch 6 → 8 taken 27 times.
✓ Branch 7 → 8 taken 44 times.
✓ Branch 7 → 9 taken 13881 times.
|
14344 | if (c == ' ' || c == '"' || c == '$' || c == ';' || c == '\\') { |
| 57 | 463 | type = SINGLE_QUOTE; | |
| 58 | } | ||
| 59 | } | ||
| 60 | return type; | ||
| 61 | } | ||
| 62 | |||
| 63 | // Append `arg` to `s`, escaping dterc(5) special characters and/or | ||
| 64 | // quoting as appropriate, so that the appended string round-trips | ||
| 65 | // back to `arg` when passed to parse_command_arg(). If escape_tilde | ||
| 66 | // is true, any leading "~/" substring will be escaped, so as to not | ||
| 67 | // expand to $HOME/. | ||
| 68 | 1276 | void string_append_escaped_arg_sv(String *s, StringView arg, bool escape_tilde) | |
| 69 | { | ||
| 70 | 1276 | char *buf = string_reserve_space(s, arg.length + STRLEN("~/''")); | |
| 71 |
2/2✓ Branch 3 → 4 taken 8 times.
✓ Branch 3 → 6 taken 1268 times.
|
1276 | if (arg.length == 0) { |
| 72 | 8 | s->len += copyliteral(buf, "''"); | |
| 73 | 8 | return; | |
| 74 | } | ||
| 75 | |||
| 76 | 1268 | bool has_tilde_slash_prefix = strview_has_prefix(arg, "~/"); | |
| 77 |
2/2✓ Branch 7 → 8 taken 7 times.
✓ Branch 7 → 10 taken 1261 times.
|
1268 | if (has_tilde_slash_prefix && !escape_tilde) { |
| 78 | // Print "~/" and skip past it, so it doesn't get quoted | ||
| 79 | 7 | size_t skip = copyliteral(buf, "~/"); | |
| 80 | 7 | buf += skip; | |
| 81 | 7 | s->len += skip; | |
| 82 | 7 | strview_remove_prefix(&arg, skip); | |
| 83 | } | ||
| 84 | |||
| 85 | 1268 | SerializeType type = get_serialize_type(arg.data, arg.length); | |
| 86 |
2/2✓ Branch 10 → 11 taken 13 times.
✓ Branch 10 → 13 taken 1255 times.
|
1268 | if (type == DOUBLE_QUOTE) { |
| 87 | 13 | string_append_dquoted_arg(s, arg); | |
| 88 | 13 | return; | |
| 89 | } | ||
| 90 | |||
| 91 | 1255 | size_t n = 0; | |
| 92 |
2/2✓ Branch 13 → 14 taken 165 times.
✓ Branch 13 → 15 taken 1090 times.
|
1255 | if (type == SINGLE_QUOTE) { |
| 93 | 165 | buf[n++] = '\''; | |
| 94 |
2/2✓ Branch 15 → 16 taken 2 times.
✓ Branch 15 → 17 taken 1088 times.
|
1090 | } else if (has_tilde_slash_prefix && escape_tilde) { |
| 95 | 2 | buf[n++] = '\\'; | |
| 96 | } | ||
| 97 | 1255 | n += copystrn(buf + n, arg.data, arg.length); | |
| 98 |
2/2✓ Branch 18 → 19 taken 165 times.
✓ Branch 18 → 20 taken 1090 times.
|
1255 | if (type == SINGLE_QUOTE) { |
| 99 | 165 | buf[n++] = '\''; | |
| 100 | } | ||
| 101 | 1255 | s->len += n; | |
| 102 | } | ||
| 103 |