| 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 "trace.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 | 1966 | CachedCommand *cached_command_new(const CommandRunner *runner, const char *cmd_str) | |
| 17 | { | ||
| 18 | 1966 | const size_t cmd_str_len = strlen(cmd_str); | |
| 19 | 1966 | CachedCommand *cached = xmalloc(xadd3(sizeof(*cached), cmd_str_len, 1)); | |
| 20 | 1966 | memcpy(cached->cmd_str, cmd_str, cmd_str_len + 1); | |
| 21 | |||
| 22 | 1966 | const char *reason; | |
| 23 | 1966 | PointerArray array = PTR_ARRAY_INIT; | |
| 24 |
2/2✓ Branch 5 → 6 taken 3 times.
✓ Branch 5 → 7 taken 1963 times.
|
1966 | if (parse_commands(runner, &array, cmd_str) != CMDERR_NONE) { |
| 25 | 3 | reason = "parsing failed"; | |
| 26 | 3 | goto nocache; | |
| 27 | } | ||
| 28 | |||
| 29 | 1963 | ptr_array_trim_nulls(&array); | |
| 30 | 1963 | size_t n = array.count; | |
| 31 |
4/4✓ Branch 8 → 9 taken 1962 times.
✓ Branch 8 → 11 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 12 taken 1961 times.
|
1963 | if (n < 2 || ptr_array_xindex(&array, NULL) != n - 1) { |
| 32 | 2 | reason = "multiple commands"; | |
| 33 | 2 | goto nocache; | |
| 34 | } | ||
| 35 | |||
| 36 | 1961 | const Command *cmd = runner->cmds->lookup(array.ptrs[0]); | |
| 37 |
2/2✓ Branch 13 → 14 taken 10 times.
✓ Branch 13 → 15 taken 1951 times.
|
1961 | 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 | 10 | reason = "contains aliases"; | |
| 41 | 10 | goto nocache; | |
| 42 | } | ||
| 43 | |||
| 44 | // TODO: Make this condition more precise | ||
| 45 |
2/2✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 17 taken 1950 times.
|
1951 | if (memchr(cmd_str, '$', cmd_str_len)) { |
| 46 | 1 | reason = "may contain variables"; | |
| 47 | 1 | goto nocache; | |
| 48 | } | ||
| 49 | |||
| 50 | 1950 | free(ptr_array_remove_index(&array, 0)); | |
| 51 | 1950 | CommandArgs cmdargs = cmdargs_new((char**)array.ptrs); | |
| 52 |
2/2✓ Branch 19 → 20 taken 3 times.
✓ Branch 19 → 21 taken 1947 times.
|
1950 | 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 | 1947 | cached->cmd = cmd; | |
| 59 | 1947 | cached->a = cmdargs; | |
| 60 | 1947 | return cached; | |
| 61 | |||
| 62 | 19 | nocache: | |
| 63 | 19 | TRACE_CMD("skipping command cache (%s): %s", reason, cmd_str); | |
| 64 | 19 | ptr_array_free(&array); | |
| 65 | 19 | cached->cmd = NULL; | |
| 66 | 19 | return cached; | |
| 67 | } | ||
| 68 | |||
| 69 | 3922 | void cached_command_free(CachedCommand *cc) | |
| 70 | { | ||
| 71 |
4/4✓ Branch 2 → 3 taken 1966 times.
✓ Branch 2 → 5 taken 1956 times.
✓ Branch 3 → 4 taken 1947 times.
✓ Branch 3 → 5 taken 19 times.
|
3922 | if (cc && cc->cmd) { |
| 72 | 1947 | free_string_array(cc->a.args); | |
| 73 | } | ||
| 74 | 3922 | free(cc); | |
| 75 | 3922 | } | |
| 76 |