=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/cmd-queue.c,v retrieving revision 1.87 retrieving revision 1.88 diff -u -r1.87 -r1.88 --- src/usr.bin/tmux/cmd-queue.c 2020/04/13 14:46:04 1.87 +++ src/usr.bin/tmux/cmd-queue.c 2020/04/13 15:55:51 1.88 @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-queue.c,v 1.87 2020/04/13 14:46:04 nicm Exp $ */ +/* $OpenBSD: cmd-queue.c,v 1.88 2020/04/13 15:55:51 nicm Exp $ */ /* * Copyright (c) 2013 Nicholas Marriott @@ -145,6 +145,13 @@ return (item->client); } +/* Get item state. */ +struct cmdq_state * +cmdq_get_state(struct cmdq_item *item) +{ + return (item->state); +} + /* Get item target. */ struct cmd_find_state * cmdq_get_target(struct cmdq_item *item) @@ -180,6 +187,70 @@ return (item->state->flags); } +/* Create a new state. */ +struct cmdq_state * +cmdq_new_state(struct cmd_find_state *current, struct key_event *event, + int flags) +{ + struct cmdq_state *state; + + state = xcalloc(1, sizeof *state); + state->references = 1; + state->flags = flags; + + if (event != NULL) + memcpy(&state->event, event, sizeof state->event); + else + state->event.key = KEYC_NONE; + if (current != NULL && cmd_find_valid_state(current)) + cmd_find_copy_state(&state->current, current); + else + cmd_find_clear_state(&state->current, 0); + + return (state); +} + +/* Add a reference to a state. */ +struct cmdq_state * +cmdq_link_state(struct cmdq_state *state) +{ + state->references++; + return (state); +} + +/* Make a copy of a state. */ +struct cmdq_state * +cmdq_copy_state(struct cmdq_state *state) +{ + return (cmdq_new_state(&state->current, &state->event, state->flags)); +} + +/* Free a state. */ +void +cmdq_free_state(struct cmdq_state *state) +{ + if (--state->references == 0) + free(state); +} + +/* Add a format to command queue. */ +void +cmdq_add_format(struct cmdq_state *state, const char *key, const char *fmt, ...) +{ + va_list ap; + char *value; + + va_start(ap, fmt); + xvasprintf(&value, fmt, ap); + va_end(ap); + + if (state->formats == NULL) + state->formats = format_create(NULL, NULL, FORMAT_NONE, 0); + format_add(state->formats, key, "%s", value); + + free(value); +} + /* Merge formats from item. */ void cmdq_merge_formats(struct cmdq_item *item, struct format_tree *ft) @@ -249,12 +320,14 @@ /* Insert a hook. */ void cmdq_insert_hook(struct session *s, struct cmdq_item *item, - struct cmd_find_state *fs, const char *fmt, ...) + struct cmd_find_state *current, const char *fmt, ...) { + struct cmdq_state *state = item->state; struct options *oo; va_list ap; char *name; struct cmdq_item *new_item; + struct cmdq_state *new_state; struct options_entry *o; struct options_array_item *a; struct cmd_list *cmdlist; @@ -277,25 +350,27 @@ } log_debug("running hook %s (parent %p)", name, item); + /* + * The hooks get a new state because they should not update the current + * target or formats for any subsequent commands. + */ + new_state = cmdq_new_state(current, &state->event, CMDQ_STATE_NOHOOKS); + cmdq_add_format(new_state, "hook", "%s", name); + a = options_array_first(o); while (a != NULL) { cmdlist = options_array_item_value(a)->cmdlist; - if (cmdlist == NULL) { - a = options_array_next(a); - continue; + if (cmdlist != NULL) { + new_item = cmdq_get_command(cmdlist, new_state); + if (item != NULL) + item = cmdq_insert_after(item, new_item); + else + item = cmdq_append(NULL, new_item); } - - new_item = cmdq_get_command(cmdlist, fs, NULL, - CMDQ_STATE_NOHOOKS); - cmdq_format(new_item, "hook", "%s", name); - if (item != NULL) - item = cmdq_insert_after(item, new_item); - else - item = cmdq_append(NULL, new_item); - a = options_array_next(a); } + cmdq_free_state(new_state); free(name); } @@ -310,17 +385,11 @@ static void cmdq_remove(struct cmdq_item *item) { - if (item->state != NULL && --item->state->references == 0) { - if (item->state->formats != NULL) - format_free(item->state->formats); - free(item->state); - } - if (item->client != NULL) server_client_unref(item->client); - if (item->cmdlist != NULL) cmd_list_free(item->cmdlist); + cmdq_free_state(item->state); TAILQ_REMOVE(item->queue, item, entry); @@ -347,54 +416,46 @@ /* Get a command for the command queue. */ struct cmdq_item * -cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current, - struct key_event *event, int flags) +cmdq_get_command(struct cmd_list *cmdlist, struct cmdq_state *state) { struct cmdq_item *item, *first = NULL, *last = NULL; struct cmd *cmd; const struct cmd_entry *entry; - struct cmdq_state *state = NULL; - u_int group, last_group = 0; + int created = 0; - cmd = cmd_list_first(cmdlist, &group); + if (state == NULL) { + state = cmdq_new_state(NULL, NULL, 0); + created = 1; + } + + cmd = cmd_list_first(cmdlist); while (cmd != NULL) { - if (group != last_group) { - state = xcalloc(1, sizeof *state); - if (current != NULL) - cmd_find_copy_state(&state->current, current); - else - cmd_find_clear_state(&state->current, 0); - if (event != NULL) { - memcpy(&state->event, event, - sizeof state->event); - } - state->flags = flags; - last_group = group; - } entry = cmd_get_entry(cmd); item = xcalloc(1, sizeof *item); xasprintf(&item->name, "[%s/%p]", entry->name, item); item->type = CMDQ_COMMAND; - item->group = group; - item->state = state; + item->group = cmd_get_group(cmd); + item->state = cmdq_link_state(state); + item->cmdlist = cmdlist; item->cmd = cmd; + cmdlist->references++; log_debug("%s: %s group %u", __func__, item->name, item->group); - state->references++; - cmdlist->references++; - if (first == NULL) first = item; if (last != NULL) last->next = item; last = item; - cmd = cmd_list_next(cmd, &group); + cmd = cmd_list_next(cmd); } + + if (created) + cmdq_free_state(state); return (first); } @@ -484,7 +545,9 @@ item = xcalloc(1, sizeof *item); xasprintf(&item->name, "[%s/%p]", name, item); item->type = CMDQ_CALLBACK; + item->group = 0; + item->state = cmdq_new_state(NULL, NULL, 0); item->cb = cb; item->data = data; @@ -516,25 +579,6 @@ cmdq_fire_callback(struct cmdq_item *item) { return (item->cb(item, item->data)); -} - -/* Add a format to command queue. */ -void -cmdq_format(struct cmdq_item *item, const char *key, const char *fmt, ...) -{ - struct cmdq_state *state = item->state; - va_list ap; - char *value; - - va_start(ap, fmt); - xvasprintf(&value, fmt, ap); - va_end(ap); - - if (state->formats == NULL) - state->formats = format_create(NULL, NULL, FORMAT_NONE, 0); - format_add(state->formats, key, "%s", value); - - free(value); } /* Process next item on command queue. */