version 1.87, 2020/04/13 14:46:04 |
version 1.88, 2020/04/13 15:55:51 |
|
|
return (item->client); |
return (item->client); |
} |
} |
|
|
|
/* Get item state. */ |
|
struct cmdq_state * |
|
cmdq_get_state(struct cmdq_item *item) |
|
{ |
|
return (item->state); |
|
} |
|
|
/* Get item target. */ |
/* Get item target. */ |
struct cmd_find_state * |
struct cmd_find_state * |
cmdq_get_target(struct cmdq_item *item) |
cmdq_get_target(struct cmdq_item *item) |
|
|
return (item->state->flags); |
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. */ |
/* Merge formats from item. */ |
void |
void |
cmdq_merge_formats(struct cmdq_item *item, struct format_tree *ft) |
cmdq_merge_formats(struct cmdq_item *item, struct format_tree *ft) |
|
|
/* Insert a hook. */ |
/* Insert a hook. */ |
void |
void |
cmdq_insert_hook(struct session *s, struct cmdq_item *item, |
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; |
struct options *oo; |
va_list ap; |
va_list ap; |
char *name; |
char *name; |
struct cmdq_item *new_item; |
struct cmdq_item *new_item; |
|
struct cmdq_state *new_state; |
struct options_entry *o; |
struct options_entry *o; |
struct options_array_item *a; |
struct options_array_item *a; |
struct cmd_list *cmdlist; |
struct cmd_list *cmdlist; |
|
|
} |
} |
log_debug("running hook %s (parent %p)", name, 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); |
a = options_array_first(o); |
while (a != NULL) { |
while (a != NULL) { |
cmdlist = options_array_item_value(a)->cmdlist; |
cmdlist = options_array_item_value(a)->cmdlist; |
if (cmdlist == NULL) { |
if (cmdlist != NULL) { |
a = options_array_next(a); |
new_item = cmdq_get_command(cmdlist, new_state); |
continue; |
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); |
a = options_array_next(a); |
} |
} |
|
|
|
cmdq_free_state(new_state); |
free(name); |
free(name); |
} |
} |
|
|
|
|
static void |
static void |
cmdq_remove(struct cmdq_item *item) |
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) |
if (item->client != NULL) |
server_client_unref(item->client); |
server_client_unref(item->client); |
|
|
if (item->cmdlist != NULL) |
if (item->cmdlist != NULL) |
cmd_list_free(item->cmdlist); |
cmd_list_free(item->cmdlist); |
|
cmdq_free_state(item->state); |
|
|
TAILQ_REMOVE(item->queue, item, entry); |
TAILQ_REMOVE(item->queue, item, entry); |
|
|
|
|
|
|
/* Get a command for the command queue. */ |
/* Get a command for the command queue. */ |
struct cmdq_item * |
struct cmdq_item * |
cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current, |
cmdq_get_command(struct cmd_list *cmdlist, struct cmdq_state *state) |
struct key_event *event, int flags) |
|
{ |
{ |
struct cmdq_item *item, *first = NULL, *last = NULL; |
struct cmdq_item *item, *first = NULL, *last = NULL; |
struct cmd *cmd; |
struct cmd *cmd; |
const struct cmd_entry *entry; |
const struct cmd_entry *entry; |
struct cmdq_state *state = NULL; |
int created = 0; |
u_int group, last_group = 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) { |
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); |
entry = cmd_get_entry(cmd); |
|
|
item = xcalloc(1, sizeof *item); |
item = xcalloc(1, sizeof *item); |
xasprintf(&item->name, "[%s/%p]", entry->name, item); |
xasprintf(&item->name, "[%s/%p]", entry->name, item); |
item->type = CMDQ_COMMAND; |
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->cmdlist = cmdlist; |
item->cmd = cmd; |
item->cmd = cmd; |
|
|
|
cmdlist->references++; |
log_debug("%s: %s group %u", __func__, item->name, item->group); |
log_debug("%s: %s group %u", __func__, item->name, item->group); |
|
|
state->references++; |
|
cmdlist->references++; |
|
|
|
if (first == NULL) |
if (first == NULL) |
first = item; |
first = item; |
if (last != NULL) |
if (last != NULL) |
last->next = item; |
last->next = item; |
last = item; |
last = item; |
|
|
cmd = cmd_list_next(cmd, &group); |
cmd = cmd_list_next(cmd); |
} |
} |
|
|
|
if (created) |
|
cmdq_free_state(state); |
return (first); |
return (first); |
} |
} |
|
|
|
|
item = xcalloc(1, sizeof *item); |
item = xcalloc(1, sizeof *item); |
xasprintf(&item->name, "[%s/%p]", name, item); |
xasprintf(&item->name, "[%s/%p]", name, item); |
item->type = CMDQ_CALLBACK; |
item->type = CMDQ_CALLBACK; |
|
|
item->group = 0; |
item->group = 0; |
|
item->state = cmdq_new_state(NULL, NULL, 0); |
|
|
item->cb = cb; |
item->cb = cb; |
item->data = data; |
item->data = data; |
|
|
cmdq_fire_callback(struct cmdq_item *item) |
cmdq_fire_callback(struct cmdq_item *item) |
{ |
{ |
return (item->cb(item, item->data)); |
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. */ |
/* Process next item on command queue. */ |