| 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 0 (12→4) taken 298 times.
✓ Branch 1 (12→13) taken 13 times.
|
311 | for (size_t i = 0, n = arg.length; i < n; i++) { |
| 30 | 298 | char *buf = string_reserve_space(s, 4); | |
| 31 | 298 | size_t pos = 0; | |
| 32 | 298 | unsigned char ch = arg.data[i]; | |
| 33 |
4/4✓ Branch 0 (5→6) taken 124 times.
✓ Branch 1 (5→8) taken 174 times.
✓ Branch 2 (6→7) taken 19 times.
✓ Branch 3 (6→8) taken 105 times.
|
298 | if (unlikely(ch < sizeof(escmap) && escmap[ch])) { |
| 34 | 19 | buf[pos++] = '\\'; | |
| 35 | 19 | ch = escmap[ch]; | |
| 36 |
2/2✓ Branch 0 (8→9) taken 2 times.
✓ Branch 1 (8→11) taken 277 times.
|
279 | } 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 | 298 | buf[pos++] = ch; | |
| 42 | 298 | s->len += pos; | |
| 43 | } | ||
| 44 | |||
| 45 | 13 | string_append_byte(s, '"'); | |
| 46 | 13 | } | |
| 47 | |||
| 48 | 1266 | static SerializeType get_serialize_type(const char *arg, size_t n) | |
| 49 | { | ||
| 50 | 1266 | SerializeType type = NO_QUOTE; | |
| 51 |
2/2✓ Branch 0 (10→3) taken 14331 times.
✓ Branch 1 (10→11) taken 1253 times.
|
15584 | for (size_t i = 0; i < n; i++) { |
| 52 | 14331 | const unsigned char c = arg[i]; | |
| 53 |
3/4✓ Branch 0 (3→4) taken 14318 times.
✓ Branch 1 (3→11) taken 13 times.
✓ Branch 2 (4→5) taken 14318 times.
✗ Branch 3 (4→11) not taken.
|
14331 | if (c == '\'' || c < 0x20 || c == 0x7F) { |
| 54 | return DOUBLE_QUOTE; | ||
| 55 | } | ||
| 56 |
6/6✓ Branch 0 (5→6) taken 13922 times.
✓ Branch 1 (5→8) taken 396 times.
✓ Branch 2 (6→7) taken 13895 times.
✓ Branch 3 (6→8) taken 27 times.
✓ Branch 4 (7→8) taken 44 times.
✓ Branch 5 (7→9) taken 13851 times.
|
14318 | if (c == ' ' || c == '"' || c == '$' || c == ';' || c == '\\') { |
| 57 | 467 | 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 | 1274 | void string_append_escaped_arg_sv(String *s, StringView arg, bool escape_tilde) | |
| 69 | { | ||
| 70 | 1274 | char *buf = string_reserve_space(s, arg.length + STRLEN("~/''")); | |
| 71 |
2/2✓ Branch 0 (3→4) taken 8 times.
✓ Branch 1 (3→6) taken 1266 times.
|
1274 | if (arg.length == 0) { |
| 72 | 8 | s->len += copyliteral(buf, "''"); | |
| 73 | 8 | return; | |
| 74 | } | ||
| 75 | |||
| 76 | 1266 | bool has_tilde_slash_prefix = strview_has_prefix(arg, "~/"); | |
| 77 |
2/2✓ Branch 0 (7→8) taken 7 times.
✓ Branch 1 (7→10) taken 1259 times.
|
1266 | 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 | 1266 | SerializeType type = get_serialize_type(arg.data, arg.length); | |
| 86 |
2/2✓ Branch 0 (10→11) taken 13 times.
✓ Branch 1 (10→13) taken 1253 times.
|
1266 | if (type == DOUBLE_QUOTE) { |
| 87 | 13 | string_append_dquoted_arg(s, arg); | |
| 88 | 13 | return; | |
| 89 | } | ||
| 90 | |||
| 91 | 1253 | size_t n = 0; | |
| 92 |
2/2✓ Branch 0 (13→14) taken 165 times.
✓ Branch 1 (13→15) taken 1088 times.
|
1253 | if (type == SINGLE_QUOTE) { |
| 93 | 165 | buf[n++] = '\''; | |
| 94 |
2/2✓ Branch 0 (15→16) taken 2 times.
✓ Branch 1 (15→17) taken 1086 times.
|
1088 | } else if (has_tilde_slash_prefix && escape_tilde) { |
| 95 | 2 | buf[n++] = '\\'; | |
| 96 | } | ||
| 97 | 1253 | n += copystrn(buf + n, arg.data, arg.length); | |
| 98 |
2/2✓ Branch 0 (18→19) taken 165 times.
✓ Branch 1 (18→20) taken 1088 times.
|
1253 | if (type == SINGLE_QUOTE) { |
| 99 | 165 | buf[n++] = '\''; | |
| 100 | } | ||
| 101 | 1253 | s->len += n; | |
| 102 | } | ||
| 103 |