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