summaryrefslogtreecommitdiffstats
path: root/cmd-queue.c
diff options
context:
space:
mode:
authornicm <nicm>2020-04-13 15:55:51 +0000
committernicm <nicm>2020-04-13 15:55:51 +0000
commit3f86d6d46014ca55e42cecd570d7f269b1d386b3 (patch)
tree94a72dc0995badc04a7471edb4782ce9707a4930 /cmd-queue.c
parentadb76fd1ce8753a958d4ffe14db724f9f4d674ea (diff)
When adding a list of commands to the queue, instead of automatically
creating a new state for each group of commands, require the caller to create one and use it for all the commands in the list. This means the current target works even with list with multiple groups (which can happen if they are defined with newlines).
Diffstat (limited to 'cmd-queue.c')
-rw-r--r--cmd-queue.c170
1 files changed, 107 insertions, 63 deletions
diff --git a/cmd-queue.c b/cmd-queue.c
index 40db3fef..97d19f81 100644
--- a/cmd-queue.c
+++ b/cmd-queue.c
@@ -145,6 +145,13 @@ cmdq_get_client(struct cmdq_item *item)
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 @@ cmdq_get_flags(struct cmdq_item *item)
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 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
/* 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 @@ cmdq_insert_hook(struct session *s, struct cmdq_item *item,
}
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 @@ cmdq_continue(struct cmdq_item *item)
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,45 +416,34 @@ cmdq_remove_group(struct cmdq_item *item)
/* 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;
- log_debug("%s: %s group %u", __func__, item->name, item->group);
-
- state->references++;
cmdlist->references++;
+ log_debug("%s: %s group %u", __func__, item->name, item->group);
if (first == NULL)
first = item;
@@ -393,8 +451,11 @@ cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
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 @@ cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
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;
@@ -518,25 +581,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. */
u_int
cmdq_next(struct client *c)