Line | Branch | Exec | Source |
---|---|---|---|
1 | #include <stdlib.h> | ||
2 | #include <string.h> | ||
3 | #include "cache.h" | ||
4 | #include "args.h" | ||
5 | #include "parse.h" | ||
6 | #include "util/log.h" | ||
7 | #include "util/ptr-array.h" | ||
8 | #include "util/str-array.h" | ||
9 | #include "util/xmalloc.h" | ||
10 | |||
11 | // Takes a command string and returns a struct containing the resolved | ||
12 | // Command and pre-parsed arguments, or a NULL Command if uncacheable. | ||
13 | // In both cases, CachedCommand::cmd_str is filled with a copy of the | ||
14 | // original string. This caching is done to allow handle_binding() to | ||
15 | // avoid repeated parsing/allocation each time a key binding is used. | ||
16 | 1189 | CachedCommand *cached_command_new(const CommandRunner *runner, const char *cmd_str) | |
17 | { | ||
18 | 1189 | const size_t cmd_str_len = strlen(cmd_str); | |
19 | 1189 | CachedCommand *cached = xmalloc(sizeof(*cached) + cmd_str_len + 1); | |
20 | 1189 | memcpy(cached->cmd_str, cmd_str, cmd_str_len + 1); | |
21 | |||
22 | 1189 | const char *reason; | |
23 | 1189 | PointerArray array = PTR_ARRAY_INIT; | |
24 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1186 times.
|
1189 | if (parse_commands(runner, &array, cmd_str) != CMDERR_NONE) { |
25 | 3 | reason = "parsing failed"; | |
26 | 3 | goto nocache; | |
27 | } | ||
28 | |||
29 | 1186 | ptr_array_trim_nulls(&array); | |
30 | 1186 | size_t n = array.count; | |
31 |
4/4✓ Branch 0 taken 1185 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1184 times.
|
1186 | if (n < 2 || ptr_array_xindex(&array, NULL) != n - 1) { |
32 | 2 | reason = "multiple commands"; | |
33 | 2 | goto nocache; | |
34 | } | ||
35 | |||
36 | 1184 | const Command *cmd = runner->cmds->lookup(array.ptrs[0]); | |
37 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1177 times.
|
1184 | if (!cmd) { |
38 | // Aliases and non-existent commands can't be cached, because the | ||
39 | // command they expand to could later be invalidated by cmd_alias(). | ||
40 | 7 | reason = "contains aliases"; | |
41 | 7 | goto nocache; | |
42 | } | ||
43 | |||
44 | // TODO: Make this condition more precise | ||
45 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1176 times.
|
1177 | if (memchr(cmd_str, '$', cmd_str_len)) { |
46 | 1 | reason = "may contain variables"; | |
47 | 1 | goto nocache; | |
48 | } | ||
49 | |||
50 | 1176 | free(ptr_array_remove_index(&array, 0)); | |
51 | 1176 | CommandArgs cmdargs = cmdargs_new((char**)array.ptrs); | |
52 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1173 times.
|
1176 | if (do_parse_args(cmd, &cmdargs) != ARGERR_NONE) { |
53 | 3 | reason = "argument parsing failed"; | |
54 | 3 | goto nocache; | |
55 | } | ||
56 | |||
57 | // Command can be cached; cache takes ownership of args array | ||
58 | 1173 | cached->cmd = cmd; | |
59 | 1173 | cached->a = cmdargs; | |
60 | 1173 | return cached; | |
61 | |||
62 | 16 | nocache: | |
63 | 16 | LOG_TRACE("skipping command cache (%s): %s", reason, cmd_str); | |
64 | 16 | ptr_array_free(&array); | |
65 | 16 | cached->cmd = NULL; | |
66 | 16 | return cached; | |
67 | } | ||
68 | |||
69 | 2368 | void cached_command_free(CachedCommand *cc) | |
70 | { | ||
71 |
2/2✓ Branch 0 taken 1189 times.
✓ Branch 1 taken 1179 times.
|
2368 | if (!cc) { |
72 | return; | ||
73 | } | ||
74 |
2/2✓ Branch 0 taken 1173 times.
✓ Branch 1 taken 16 times.
|
1189 | if (cc->cmd) { |
75 | 1173 | free_string_array(cc->a.args); | |
76 | } | ||
77 | 1189 | free(cc); | |
78 | } | ||
79 |