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 | 12 | static void string_append_dquoted_arg(String *s, StringView arg) | |
26 | { | ||
27 | 12 | string_append_byte(s, '"'); | |
28 | |||
29 |
2/2✓ Branch 0 (12→4) taken 189 times.
✓ Branch 1 (12→13) taken 12 times.
|
201 | for (size_t i = 0, n = arg.length; i < n; i++) { |
30 | 189 | char *buf = string_reserve_space(s, 4); | |
31 | 189 | size_t pos = 0; | |
32 | 189 | unsigned char ch = arg.data[i]; | |
33 |
4/4✓ Branch 0 (5→6) taken 74 times.
✓ Branch 1 (5→8) taken 115 times.
✓ Branch 2 (6→7) taken 16 times.
✓ Branch 3 (6→8) taken 58 times.
|
189 | if (unlikely(ch < sizeof(escmap) && escmap[ch])) { |
34 | 16 | buf[pos++] = '\\'; | |
35 | 16 | ch = escmap[ch]; | |
36 |
2/2✓ Branch 0 (8→9) taken 2 times.
✓ Branch 1 (8→11) taken 171 times.
|
173 | } 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 | 189 | buf[pos++] = ch; | |
42 | 189 | s->len += pos; | |
43 | } | ||
44 | |||
45 | 12 | string_append_byte(s, '"'); | |
46 | 12 | } | |
47 | |||
48 | 1263 | static SerializeType get_serialize_type(const char *arg, size_t n) | |
49 | { | ||
50 | 1263 | SerializeType type = NO_QUOTE; | |
51 |
2/2✓ Branch 0 (10→3) taken 14287 times.
✓ Branch 1 (10→11) taken 1251 times.
|
15538 | for (size_t i = 0; i < n; i++) { |
52 | 14287 | const unsigned char c = arg[i]; | |
53 |
3/4✓ Branch 0 (3→4) taken 14275 times.
✓ Branch 1 (3→11) taken 12 times.
✓ Branch 2 (4→5) taken 14275 times.
✗ Branch 3 (4→11) not taken.
|
14287 | if (c == '\'' || c < 0x20 || c == 0x7F) { |
54 | return DOUBLE_QUOTE; | ||
55 | } | ||
56 |
6/6✓ Branch 0 (5→6) taken 13879 times.
✓ Branch 1 (5→8) taken 396 times.
✓ Branch 2 (6→7) taken 13852 times.
✓ Branch 3 (6→8) taken 27 times.
✓ Branch 4 (7→8) taken 44 times.
✓ Branch 5 (7→9) taken 13808 times.
|
14275 | 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 | 1272 | void string_append_escaped_arg_sv(String *s, StringView arg, bool escape_tilde) | |
69 | { | ||
70 | 1272 | char *buf = string_reserve_space(s, arg.length + STRLEN("~/''")); | |
71 |
2/2✓ Branch 0 (3→4) taken 9 times.
✓ Branch 1 (3→6) taken 1263 times.
|
1272 | if (arg.length == 0) { |
72 | 9 | s->len += copyliteral(buf, "''"); | |
73 | 9 | return; | |
74 | } | ||
75 | |||
76 | 1263 | bool has_tilde_slash_prefix = strview_has_prefix(arg, "~/"); | |
77 |
2/2✓ Branch 0 (7→8) taken 7 times.
✓ Branch 1 (7→10) taken 1256 times.
|
1263 | 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 | 1263 | SerializeType type = get_serialize_type(arg.data, arg.length); | |
86 |
2/2✓ Branch 0 (10→11) taken 12 times.
✓ Branch 1 (10→13) taken 1251 times.
|
1263 | if (type == DOUBLE_QUOTE) { |
87 | 12 | string_append_dquoted_arg(s, arg); | |
88 | 12 | return; | |
89 | } | ||
90 | |||
91 | 1251 | size_t n = 0; | |
92 |
2/2✓ Branch 0 (13→14) taken 165 times.
✓ Branch 1 (13→15) taken 1086 times.
|
1251 | if (type == SINGLE_QUOTE) { |
93 | 165 | buf[n++] = '\''; | |
94 |
2/2✓ Branch 0 (15→16) taken 2 times.
✓ Branch 1 (15→17) taken 1084 times.
|
1086 | } else if (has_tilde_slash_prefix && escape_tilde) { |
95 | 2 | buf[n++] = '\\'; | |
96 | } | ||
97 | 1251 | n += copystrn(buf + n, arg.data, arg.length); | |
98 |
2/2✓ Branch 0 (18→19) taken 165 times.
✓ Branch 1 (18→20) taken 1086 times.
|
1251 | if (type == SINGLE_QUOTE) { |
99 | 165 | buf[n++] = '\''; | |
100 | } | ||
101 | 1251 | s->len += n; | |
102 | } | ||
103 |