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 | 11 | static void string_append_dquoted_arg(String *s, StringView arg) | |
26 | { | ||
27 | 11 | string_append_byte(s, '"'); | |
28 | |||
29 |
2/2✓ Branch 0 taken 125 times.
✓ Branch 1 taken 11 times.
|
136 | for (size_t i = 0, n = arg.length; i < n; i++) { |
30 | 125 | char *buf = string_reserve_space(s, 4); | |
31 | 125 | size_t pos = 0; | |
32 | 125 | unsigned char ch = arg.data[i]; | |
33 |
4/4✓ Branch 0 taken 63 times.
✓ Branch 1 taken 62 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 48 times.
|
125 | if (unlikely(ch < sizeof(escmap) && escmap[ch])) { |
34 | 15 | buf[pos++] = '\\'; | |
35 | 15 | ch = escmap[ch]; | |
36 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 108 times.
|
110 | } else if (unlikely(ascii_iscntrl(ch))) { |
37 | 2 | pos += copyliteral(buf + pos, "\\x"); | |
38 | 2 | buf[pos++] = hextab_upper[(ch >> 4) & 0xF]; | |
39 | 2 | ch = hextab_upper[ch & 0xF]; | |
40 | } | ||
41 | 125 | buf[pos++] = ch; | |
42 | 125 | s->len += pos; | |
43 | } | ||
44 | |||
45 | 11 | string_append_byte(s, '"'); | |
46 | 11 | } | |
47 | |||
48 | 829 | static SerializeType get_serialize_type(const unsigned char *arg, size_t n) | |
49 | { | ||
50 | 829 | SerializeType type = NO_QUOTE; | |
51 |
2/2✓ Branch 0 taken 6649 times.
✓ Branch 1 taken 818 times.
|
7467 | for (size_t i = 0; i < n; i++) { |
52 | 6649 | const unsigned char c = arg[i]; | |
53 |
3/3✓ Branch 0 taken 395 times.
✓ Branch 1 taken 6243 times.
✓ Branch 2 taken 11 times.
|
6649 | if (c == '\'' || c < 0x20 || c == 0x7F) { |
54 | return DOUBLE_QUOTE; | ||
55 | } | ||
56 | if (c == ' ' || c == '"' || c == '$' || c == ';' || c == '\\') { | ||
57 | 395 | 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 | 832 | void string_append_escaped_arg_sv(String *s, StringView arg, bool escape_tilde) | |
69 | { | ||
70 | 832 | char *buf = string_reserve_space(s, arg.length + STRLEN("~/''")); | |
71 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 829 times.
|
832 | if (arg.length == 0) { |
72 | 3 | s->len += copyliteral(buf, "''"); | |
73 | 3 | return; | |
74 | } | ||
75 | |||
76 | 829 | bool has_tilde_slash_prefix = strview_has_prefix(&arg, "~/"); | |
77 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 822 times.
|
829 | 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 | 829 | SerializeType type = get_serialize_type(arg.data, arg.length); | |
86 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 818 times.
|
829 | if (type == DOUBLE_QUOTE) { |
87 | 11 | string_append_dquoted_arg(s, arg); | |
88 | 11 | return; | |
89 | } | ||
90 | |||
91 | 818 | size_t n = 0; | |
92 |
2/2✓ Branch 0 taken 142 times.
✓ Branch 1 taken 676 times.
|
818 | if (type == SINGLE_QUOTE) { |
93 | 142 | buf[n++] = '\''; | |
94 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 674 times.
|
676 | } else if (has_tilde_slash_prefix && escape_tilde) { |
95 | 2 | buf[n++] = '\\'; | |
96 | } | ||
97 | 818 | n += copystrn(buf + n, arg.data, arg.length); | |
98 |
2/2✓ Branch 0 taken 142 times.
✓ Branch 1 taken 676 times.
|
818 | if (type == SINGLE_QUOTE) { |
99 | 142 | buf[n++] = '\''; | |
100 | } | ||
101 | 818 | s->len += n; | |
102 | } | ||
103 |