=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/cmd-queue.c,v retrieving revision 1.87 retrieving revision 1.88 diff -c -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 **** ! /* $OpenBSD: cmd-queue.c,v 1.87 2020/04/13 14:46:04 nicm Exp $ */ /* * Copyright (c) 2013 Nicholas Marriott --- 1,4 ---- ! /* $OpenBSD: cmd-queue.c,v 1.88 2020/04/13 15:55:51 nicm Exp $ */ /* * Copyright (c) 2013 Nicholas Marriott *************** *** 145,150 **** --- 145,157 ---- 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,185 **** --- 187,256 ---- 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,260 **** /* Insert a hook. */ void cmdq_insert_hook(struct session *s, struct cmdq_item *item, ! struct cmd_find_state *fs, const char *fmt, ...) { struct options *oo; va_list ap; char *name; struct cmdq_item *new_item; struct options_entry *o; struct options_array_item *a; struct cmd_list *cmdlist; --- 320,333 ---- /* Insert a hook. */ void cmdq_insert_hook(struct session *s, struct cmdq_item *item, ! 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,301 **** } log_debug("running hook %s (parent %p)", name, item); a = options_array_first(o); while (a != NULL) { cmdlist = options_array_item_value(a)->cmdlist; ! if (cmdlist == NULL) { ! a = options_array_next(a); ! continue; } - - 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); } free(name); } --- 350,376 ---- } 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) { ! 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); } a = options_array_next(a); } + cmdq_free_state(new_state); free(name); } *************** *** 310,326 **** 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); TAILQ_REMOVE(item->queue, item, entry); --- 385,395 ---- static void cmdq_remove(struct cmdq_item *item) { 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,400 **** /* 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) { 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; ! cmd = cmd_list_first(cmdlist, &group); 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->cmdlist = cmdlist; item->cmd = cmd; 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); } return (first); } --- 416,461 ---- /* Get a command for the command queue. */ struct cmdq_item * ! 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; ! int created = 0; ! if (state == NULL) { ! state = cmdq_new_state(NULL, NULL, 0); ! created = 1; ! } ! ! cmd = cmd_list_first(cmdlist); while (cmd != NULL) { entry = cmd_get_entry(cmd); item = xcalloc(1, sizeof *item); xasprintf(&item->name, "[%s/%p]", entry->name, item); item->type = CMDQ_COMMAND; ! 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); if (first == NULL) first = item; if (last != NULL) last->next = item; last = item; ! cmd = cmd_list_next(cmd); } + + if (created) + cmdq_free_state(state); return (first); } *************** *** 484,490 **** --- 545,553 ---- 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,540 **** 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. */ --- 579,584 ----