dte test coverage


Directory: ./
File: src/command/run.c
Date: 2025-05-08 15:05:54
Exec Total Coverage
Lines: 66 66 100.0%
Functions: 3 3 100.0%
Branches: 31 32 96.9%

Line Branch Exec Source
1 #include "run.h"
2 #include "args.h"
3 #include "parse.h"
4 #include "change.h"
5 #include "util/debug.h"
6 #include "util/ptr-array.h"
7 #include "util/xmalloc.h"
8
9 enum {
10 MAX_RECURSION_DEPTH = 16, // Maximum number of `alias` expansions
11 };
12
13 static bool run_commands(CommandRunner *runner, const PointerArray *array);
14
15 // Recursion is limited by MAX_RECURSION_DEPTH
16 // NOLINTNEXTLINE(misc-no-recursion)
17 6952 static bool run_command(CommandRunner *runner, char **av)
18 {
19 6952 const CommandSet *cmds = runner->cmds;
20 6952 const Command *cmd = cmds->lookup(av[0]);
21 6952 struct EditorState *e = runner->e;
22 6952 ErrorBuffer *ebuf = runner->ebuf;
23
24
2/2
✓ Branch 0 (3→4) taken 32 times.
✓ Branch 1 (3→24) taken 6920 times.
6952 if (!cmd) {
25 32 const char *name = av[0];
26
2/2
✓ Branch 0 (4→5) taken 1 times.
✓ Branch 1 (4→6) taken 31 times.
32 if (!runner->lookup_alias) {
27 1 return error_msg_for_cmd(ebuf, NULL, "No such command: %s", name);
28 }
29
30 31 const char *alias_value = runner->lookup_alias(e, name);
31
2/2
✓ Branch 0 (7→8) taken 1 times.
✓ Branch 1 (7→9) taken 30 times.
31 if (unlikely(!alias_value)) {
32 1 return error_msg_for_cmd(ebuf, NULL, "No such command or alias: %s", name);
33 }
34
35 30 PointerArray array = PTR_ARRAY_INIT;
36 30 CommandParseError err = parse_commands(runner, &array, alias_value);
37
2/2
✓ Branch 0 (10→11) taken 1 times.
✓ Branch 1 (10→14) taken 29 times.
30 if (unlikely(err != CMDERR_NONE)) {
38 1 const char *err_msg = command_parse_error_to_string(err);
39 1 ptr_array_free(&array);
40 1 return error_msg_for_cmd(ebuf, NULL, "Parsing alias %s: %s", name, err_msg);
41 }
42
43 // Remove NULL
44 29 array.count--;
45
46
2/2
✓ Branch 0 (18→15) taken 35 times.
✓ Branch 1 (18→19) taken 29 times.
64 for (size_t i = 1; av[i]; i++) {
47 35 ptr_array_append(&array, xstrdup(av[i]));
48 }
49 29 ptr_array_append(&array, NULL);
50
51 29 bool r = run_commands(runner, &array);
52 29 ptr_array_free(&array);
53 29 return r;
54 }
55
56
4/4
✓ Branch 0 (24→25) taken 6317 times.
✓ Branch 1 (24→27) taken 603 times.
✓ Branch 2 (25→26) taken 1 times.
✓ Branch 3 (25→27) taken 6316 times.
6920 if (unlikely(ebuf->config_filename && !(cmd->cmdopts & CMDOPT_ALLOW_IN_RC))) {
57 1 return error_msg_for_cmd(ebuf, NULL, "Command %s not allowed in config file", cmd->name);
58 }
59
60 // Record command in macro buffer, if recording (this needs to be done
61 // before parse_args() mutates the array)
62
3/4
✓ Branch 0 (27→28) taken 5 times.
✓ Branch 1 (27→30) taken 6914 times.
✓ Branch 2 (28→29) taken 5 times.
✗ Branch 3 (28→30) not taken.
6919 if (runner->allow_recording && runner->cmds->macro_record) {
63 5 runner->cmds->macro_record(e, cmd, av + 1);
64 }
65
66 // By default change can't be merged with previous one.
67 // Any command can override this by calling begin_change() again.
68 6919 begin_change(CHANGE_MERGE_NONE);
69
70 6919 CommandArgs a = cmdargs_new(av + 1);
71
4/4
✓ Branch 0 (32→33) taken 6912 times.
✓ Branch 1 (32→36) taken 7 times.
✓ Branch 2 (34→35) taken 126 times.
✓ Branch 3 (34→36) taken 6786 times.
6919 bool r = likely(parse_args(cmd, &a, ebuf)) && command_func_call(e, ebuf, cmd, &a);
72
73 6919 end_change();
74 6919 return r;
75 }
76
77 // Recursion is limited by MAX_RECURSION_DEPTH
78 // NOLINTNEXTLINE(misc-no-recursion)
79 8311 static bool run_commands(CommandRunner *runner, const PointerArray *array)
80 {
81
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 8310 times.
8311 if (unlikely(runner->recursion_count > MAX_RECURSION_DEPTH)) {
82 1 return error_msg_for_cmd(runner->ebuf, NULL, "alias recursion limit reached");
83 }
84
85 8310 void **ptrs = array->ptrs;
86 8310 size_t len = array->count;
87 8310 size_t nfailed = 0;
88 8310 BUG_ON(len == 0);
89 8310 BUG_ON(ptrs[len - 1] != NULL);
90 8310 runner->recursion_count++;
91
92
2/2
✓ Branch 0 (17→11) taken 8369 times.
✓ Branch 1 (17→18) taken 8310 times.
16679 for (size_t s = 0, e = 0; s < len; ) {
93 // Iterate over strings, until a terminating NULL is encountered
94 32745 while (ptrs[e]) {
95 24376 e++;
96 32745 BUG_ON(e >= len);
97 }
98
99 // If the value of `e` (end) changed, there's a run of at least
100 // 1 string, which is a command followed by 0 or more arguments
101
2/2
✓ Branch 0 (12→13) taken 6952 times.
✓ Branch 1 (12→16) taken 1417 times.
8369 if (e != s) {
102
2/2
✓ Branch 0 (14→15) taken 154 times.
✓ Branch 1 (14→16) taken 6798 times.
6952 if (!run_command(runner, (char**)ptrs + s)) {
103 154 nfailed++;
104 }
105 }
106
107 // Skip past the NULL, onto the next command (if any)
108 8369 s = ++e;
109 }
110
111 8310 runner->recursion_count--;
112 8310 return (nfailed == 0);
113 }
114
115 8287 bool handle_command(CommandRunner *runner, const char *cmd)
116 {
117 8287 BUG_ON(runner->recursion_count != 0);
118 8287 PointerArray array = PTR_ARRAY_INIT;
119 8287 CommandParseError err = parse_commands(runner, &array, cmd);
120 8287 bool r;
121
2/2
✓ Branch 0 (5→6) taken 8282 times.
✓ Branch 1 (5→9) taken 5 times.
8287 if (likely(err == CMDERR_NONE)) {
122 8282 r = run_commands(runner, &array);
123 8282 BUG_ON(runner->recursion_count != 0);
124 } else {
125 5 const char *str = command_parse_error_to_string(err);
126 5 error_msg_for_cmd(runner->ebuf, NULL, "Command syntax error: %s", str);
127 5 r = false;
128 }
129 8287 ptr_array_free(&array);
130 8287 return r;
131 }
132