dte test coverage


Directory: ./
File: src/command/serialize.c
Date: 2024-12-21 16:03:22
Exec Total Coverage
Lines: 47 47 100.0%
Functions: 3 3 100.0%
Branches: 25 25 100.0%

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