Somewhat reorganised set-hooks to have the same syntax as set-option and similar error messages. Also added a missing free(cause) and cmd_list_free().
I changed the name member of struct hook to be const char * which is better (I know it struct option it is just char *, that could change too maybe). Also renamed some variables in hooks.c although the code itself is fine. diff --git a/Makefile.am b/Makefile.am index 690e466..8a38068 100644 --- a/Makefile.am +++ b/Makefile.am @@ -125,8 +125,10 @@ dist_tmux_SOURCES = \ cmd-server-info.c \ cmd-set-buffer.c \ cmd-set-environment.c \ + cmd-set-hook.c \ cmd-set-option.c \ cmd-show-environment.c \ + cmd-show-hooks.c \ cmd-show-messages.c \ cmd-show-options.c \ cmd-source-file.c \ @@ -149,6 +151,7 @@ dist_tmux_SOURCES = \ grid-cell.c \ grid-view.c \ grid.c \ + hooks.c \ input-keys.c \ input.c \ job.c \ diff --git a/cmd-set-hook.c b/cmd-set-hook.c new file mode 100644 index 0000000..b602933 --- /dev/null +++ b/cmd-set-hook.c @@ -0,0 +1,93 @@ +/* $Id$ */ + +/* + * Copyright (c) 2012 Thomas Adam <tho...@xteddy.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <stdlib.h> +#include <string.h> + +#include "tmux.h" + +/* + * Set a global or session hook. + */ + +enum cmd_retval cmd_set_hook_exec(struct cmd *, struct cmd_q *); +void cmd_set_hook_prepare(struct cmd *, struct cmd_q *); + +const struct cmd_entry cmd_set_hook_entry = { + "set-hook", NULL, + "gt:u", 1, 2, + "[-gu]" CMD_TARGET_SESSION_USAGE " hook-name [command]", + 0, + NULL, + cmd_set_hook_exec, +}; + +enum cmd_retval +cmd_set_hook_exec(struct cmd *self, struct cmd_q *cmdq) +{ + struct args *args = self->args; + struct session *s; + struct cmd_list *cmdlist; + struct hooks *hooks; + struct hook *hook; + char *cause; + const char *name, *cmd; + + if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) + return (CMD_RETURN_ERROR); + hooks = args_has(args, 'g') ? &global_hooks : &s->hooks; + + name = args->argv[0]; + if (*name == '\0') { + cmdq_error(cmdq, "invalid hook name"); + return (CMD_RETURN_ERROR); + } + if (args->argc < 2) + cmd = NULL; + else + cmd = args->argv[1]; + + if (args_has(args, 'u')) { + if (cmd != NULL) { + cmdq_error(cmdq, "command passed to unset hook: %s", + name); + return (CMD_RETURN_ERROR); + } + if ((hook = hooks_find(hooks, name)) != NULL) + hooks_remove(hooks, hook); + return (CMD_RETURN_NORMAL); + } + + if (cmd == NULL) { + cmdq_error(cmdq, "no command to set hook: %s", name); + return (CMD_RETURN_ERROR); + } + if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) { + if (cause != NULL) { + cmdq_error(cmdq, "%s", cause); + free(cause); + } + return (CMD_RETURN_ERROR); + } + hooks_add(hooks, name, cmdlist); + cmd_list_free(cmdlist); + + return (CMD_RETURN_NORMAL); +} diff --git a/cmd-show-hooks.c b/cmd-show-hooks.c new file mode 100644 index 0000000..384e664 --- /dev/null +++ b/cmd-show-hooks.c @@ -0,0 +1,63 @@ +/* $Id$ */ + +/* + * Copyright (c) 2012 Thomas Adam <tho...@xteddy.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <stdlib.h> +#include <string.h> + +#include "tmux.h" + +/* + * Show global or session hooks. + */ + +enum cmd_retval cmd_show_hooks_exec(struct cmd *, struct cmd_q *); +void cmd_show_hooks_prepare(struct cmd *, struct cmd_q *); + +const struct cmd_entry cmd_show_hooks_entry = { + "show-hooks", NULL, + "gt:", 0, 1, + "[-g] " CMD_TARGET_SESSION_USAGE, + 0, + NULL, + cmd_show_hooks_exec +}; + +enum cmd_retval +cmd_show_hooks_exec(struct cmd *self, struct cmd_q *cmdq) +{ + struct args *args = self->args; + struct session *s; + struct hooks *hooks; + struct hook *hook; + char tmp[BUFSIZ]; + size_t used; + + if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) + return (CMD_RETURN_ERROR); + hooks = args_has(args, 'g') ? &global_hooks : &s->hooks; + + RB_FOREACH(hook, hooks_tree, &hooks->tree) { + used = xsnprintf(tmp, sizeof tmp, "%s -> ", hook->name); + cmd_list_print(hook->cmdlist, tmp + used, (sizeof tmp) - used); + cmdq_print(cmdq, "%s", tmp); + } + + return (CMD_RETURN_NORMAL); +} diff --git a/cmd.c b/cmd.c index 414c906..72c336a 100644 --- a/cmd.c +++ b/cmd.c @@ -95,11 +95,13 @@ const struct cmd_entry *cmd_table[] = { &cmd_send_prefix_entry, &cmd_server_info_entry, &cmd_set_buffer_entry, + &cmd_set_hook_entry, &cmd_set_environment_entry, &cmd_set_option_entry, &cmd_set_window_option_entry, &cmd_show_buffer_entry, &cmd_show_environment_entry, + &cmd_show_hooks_entry, &cmd_show_messages_entry, &cmd_show_options_entry, &cmd_show_window_options_entry, diff --git a/hooks.c b/hooks.c new file mode 100644 index 0000000..7157eef --- /dev/null +++ b/hooks.c @@ -0,0 +1,109 @@ +/* $Id$ */ + +/* + * Copyright (c) 2012 Thomas Adam <tho...@xteddy.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <stdlib.h> +#include <string.h> + +#include "tmux.h" + +RB_GENERATE(hooks_tree, hook, entry, hooks_cmp); + +struct hook *hooks_find1(struct hooks *, const char *); + +int +hooks_cmp(struct hook *hook1, struct hook *hook2) +{ + return (strcmp(hook1->name, hook2->name)); +} + +void +hooks_init(struct hooks *hooks, struct hooks *parent) +{ + RB_INIT(&hooks->tree); + hooks->parent = parent; +} + +void +hooks_free(struct hooks *hooks) +{ + struct hook *hook, *hook1; + + RB_FOREACH_SAFE(hook, hooks_tree, &hooks->tree, hook1) + hooks_remove(hooks, hook); +} + +void +hooks_add(struct hooks *hooks, const char *name, struct cmd_list *cmdlist) +{ + struct hook *hook; + + if ((hook = hooks_find1(hooks, name)) != NULL) + hooks_remove(hooks, hook); + + hook = xcalloc(1, sizeof *hook); + hook->name = xstrdup(name); + hook->cmdlist = cmdlist; + hook->cmdlist->references++; + + RB_INSERT(hooks_tree, &hooks->tree, hook); +} + +void +hooks_remove(struct hooks *hooks, struct hook *hook) +{ + RB_REMOVE(hooks_tree, &hooks->tree, hook); + cmd_list_free(hook->cmdlist); + free((char *) hook->name); + free(hook); +} + +struct hook * +hooks_find1(struct hooks *hooks, const char *name) +{ + struct hook hook; + + hook.name = name; + return (RB_FIND(hooks_tree, &hooks->tree, &hook)); +} + +struct hook * +hooks_find(struct hooks *hooks, const char *name) +{ + struct hook hook0, *hook; + + hook0.name = name; + hook = RB_FIND(hooks_tree, &hooks->tree, &hook0); + while (hook == NULL) { + hooks = hooks->parent; + if (hooks == NULL) + break; + hook = RB_FIND(hooks_tree, &hooks->tree, &hook0); + } + return (hook); +} + +void +hooks_run(struct hook *hook, struct cmd_q *cmdq) +{ + struct cmd *cmd; + + TAILQ_FOREACH(cmd, &hook->cmdlist->list, qentry) + cmd->entry->exec(cmd, cmdq); +} diff --git a/options.c b/options.c index 7360906..776f250 100644 --- a/options.c +++ b/options.c @@ -25,8 +25,8 @@ #include "tmux.h" /* - * Option handling; each option has a name, type and value and is stored in - * a splay tree. + * Option handling; each option has a name, type and value and is stored in a + * tree. */ RB_GENERATE(options_tree, options_entry, entry, options_cmp); diff --git a/session.c b/session.c index 66a52bc..a27c8aa 100644 --- a/session.c +++ b/session.c @@ -103,6 +103,7 @@ session_create(const char *name, const char *cmd, int cwd, struct environ *env, TAILQ_INIT(&s->lastw); RB_INIT(&s->windows); + hooks_init(&s->hooks, &global_hooks); options_init(&s->options, &global_s_options); environ_init(&s->environ); if (env != NULL) @@ -160,6 +161,7 @@ session_destroy(struct session *s) session_group_remove(s); environ_free(&s->environ); options_free(&s->options); + hooks_free(&s->hooks); while (!TAILQ_EMPTY(&s->lastw)) winlink_stack_remove(&s->lastw, TAILQ_FIRST(&s->lastw)); diff --git a/tmux.c b/tmux.c index 1e6edd9..47b3dee 100644 --- a/tmux.c +++ b/tmux.c @@ -38,6 +38,7 @@ struct options global_options; /* server options */ struct options global_s_options; /* session options */ struct options global_w_options; /* window options */ struct environ global_environ; +struct hooks global_hooks; struct event_base *ev_base; @@ -288,6 +289,7 @@ main(int argc, char **argv) flags |= CLIENT_UTF8; } + hooks_init(&global_hooks, NULL); environ_init(&global_environ); for (var = environ; *var != NULL; var++) environ_put(&global_environ, *var); diff --git a/tmux.h b/tmux.h index 84ad164..5d16dac 100644 --- a/tmux.h +++ b/tmux.h @@ -1041,6 +1041,18 @@ struct environ_entry { }; RB_HEAD(environ, environ_entry); +/* Hooks. */ +struct hook { + const char *name; + struct cmd_list *cmdlist; + RB_ENTRY(hook) entry; +}; + +struct hooks { + RB_HEAD(hooks_tree, hook) tree; + struct hooks *parent; +}; + /* Client session. */ struct session_group { TAILQ_HEAD(, session) sessions; @@ -1066,6 +1078,7 @@ struct session { struct winlink_stack lastw; struct winlinks windows; + struct hooks hooks; struct options options; #define SESSION_UNATTACHED 0x1 /* not attached to any clients */ @@ -1479,6 +1492,7 @@ RB_HEAD(format_tree, format_entry); #define CMD_BUFFER_USAGE "[-b buffer-index]" /* tmux.c */ +extern struct hooks global_hooks; extern struct options global_options; extern struct options global_s_options; extern struct options global_w_options; @@ -1526,6 +1540,17 @@ void format_window_pane(struct format_tree *, void format_paste_buffer(struct format_tree *, struct paste_buffer *); +/* hooks.c */ +int hooks_cmp(struct hook *, struct hook *); +RB_PROTOTYPE(hooks_tree, hook, entry, hooks_cmp); +void hooks_init(struct hooks *, struct hooks *); +void hooks_free(struct hooks *); +void hooks_add(struct hooks *, const char *, struct cmd_list *); +void hooks_copy(struct hooks *, struct hooks *); +void hooks_remove(struct hooks *, struct hook *); +void hooks_run(struct hook *, struct cmd_q *); +struct hook *hooks_find(struct hooks *, const char *); + /* mode-key.c */ extern const struct mode_key_table mode_key_tables[]; extern struct mode_key_tree mode_key_tree_vi_edit; @@ -1800,10 +1825,12 @@ extern const struct cmd_entry cmd_send_prefix_entry; extern const struct cmd_entry cmd_server_info_entry; extern const struct cmd_entry cmd_set_buffer_entry; extern const struct cmd_entry cmd_set_environment_entry; +extern const struct cmd_entry cmd_set_hook_entry; extern const struct cmd_entry cmd_set_option_entry; extern const struct cmd_entry cmd_set_window_option_entry; extern const struct cmd_entry cmd_show_buffer_entry; extern const struct cmd_entry cmd_show_environment_entry; +extern const struct cmd_entry cmd_show_hooks_entry; extern const struct cmd_entry cmd_show_messages_entry; extern const struct cmd_entry cmd_show_options_entry; extern const struct cmd_entry cmd_show_window_options_entry; On Sat, Aug 24, 2013 at 04:41:16PM +0100, Thomas Adam wrote: > This adds an implementation hooks using a RB tree to store the name of the > hook and the command-list it uses. These will be accessed via commands to > add/remove hooks. > --- > Makefile.am | 3 ++ > cmd-set-hook.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++ > cmd-show-hooks.c | 69 +++++++++++++++++++++++++++++++++++ > hooks.c | 109 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > session.c | 2 + > tmux.c | 2 + > tmux.h | 27 ++++++++++++++ > 7 files changed, 310 insertions(+) > create mode 100644 cmd-set-hook.c > create mode 100644 cmd-show-hooks.c > create mode 100644 hooks.c > > diff --git a/Makefile.am b/Makefile.am > index fb707df..a1e8374 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -125,8 +125,10 @@ dist_tmux_SOURCES = \ > cmd-server-info.c \ > cmd-set-buffer.c \ > cmd-set-environment.c \ > + cmd-set-hook.c \ > cmd-set-option.c \ > cmd-show-environment.c \ > + cmd-show-hooks.c \ > cmd-show-messages.c \ > cmd-show-options.c \ > cmd-source-file.c \ > @@ -149,6 +151,7 @@ dist_tmux_SOURCES = \ > grid-cell.c \ > grid-view.c \ > grid.c \ > + hooks.c \ > input-keys.c \ > input.c \ > job.c \ > diff --git a/cmd-set-hook.c b/cmd-set-hook.c > new file mode 100644 > index 0000000..ae29b99 > --- /dev/null > +++ b/cmd-set-hook.c > @@ -0,0 +1,98 @@ > +/* $Id$ */ > + > +/* > + * Copyright (c) 2012 Thomas Adam <tho...@xteddy.org> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER > + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING > + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <sys/types.h> > + > +#include <stdlib.h> > +#include <string.h> > + > +#include "tmux.h" > + > +enum cmd_retval cmd_set_hook_exec(struct cmd *, struct cmd_q *); > +void cmd_set_hook_prepare(struct cmd *, struct cmd_q *); > + > +const struct cmd_entry cmd_set_hook_entry = { > + "set-hook", NULL, > + "gn:t:u", 0, 1, > + "[-n hook-name] [-g]" CMD_TARGET_SESSION_USAGE " [-u hook-name] > [command]", > + 0, > + NULL, > + NULL, > + cmd_set_hook_exec, > + cmd_set_hook_prepare > +}; > + > +void > +cmd_set_hook_prepare(struct cmd *self, struct cmd_q *cmdq) > +{ > + struct args *args = self->args; > + > + cmdq->cmd_ctx.s = cmd_find_session(cmdq, args_get(args, 't'), 0); > +} > + > +enum cmd_retval > +cmd_set_hook_exec(struct cmd *self, struct cmd_q *cmdq) > +{ > + struct args *args = self->args; > + struct session *s; > + struct cmd_list *cmdlist; > + struct hooks *hooks; > + struct hook *hook; > + char *cause; > + const char *hook_name, *hook_cmd; > + > + s = cmdq->cmd_ctx.s; > + > + if (args_has(args, 't') && s == NULL) > + return (CMD_RETURN_ERROR); > + > + if (s == NULL && cmdq->client != NULL) > + s = cmdq->client->session; > + > + if ((hook_name = args_get(args, 'n')) == NULL) { > + cmdq_error(cmdq, "no hook name given"); > + return (CMD_RETURN_ERROR); > + } > + > + hooks = args_has(args, 'g') ? &global_hooks : &s->hooks; > + > + if (s != NULL && args_has(args, 'u')) { > + if ((hook = hooks_find(hooks, (char *)hook_name)) != NULL) > + hooks_remove(hooks, hook); > + return (CMD_RETURN_NORMAL); > + } > + > + if (args->argc == 0) { > + cmdq_error(cmdq, "no command for hook '%s' given", hook_name); > + return (CMD_RETURN_ERROR); > + } > + hook_cmd = args->argv[0]; > + > + if (cmd_string_parse(hook_cmd, &cmdlist, NULL, 0, &cause) != 0) { > + if (cmdlist == NULL || cause != NULL) { > + cmdq_error(cmdq, "hook error: (%s)", cause); > + return (CMD_RETURN_ERROR); > + } > + } > + > + if (cmdlist == NULL) > + return (CMD_RETURN_ERROR); > + > + hooks_add(hooks, hook_name, cmdlist); > + return (CMD_RETURN_NORMAL); > +} > diff --git a/cmd-show-hooks.c b/cmd-show-hooks.c > new file mode 100644 > index 0000000..8de7ab8 > --- /dev/null > +++ b/cmd-show-hooks.c > @@ -0,0 +1,69 @@ > +/* $Id$ */ > + > +/* > + * Copyright (c) 2012 Thomas Adam <tho...@xteddy.org> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER > + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING > + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <sys/types.h> > + > +#include <stdlib.h> > +#include <string.h> > + > +#include "tmux.h" > + > +enum cmd_retval cmd_show_hooks_exec(struct cmd *, struct cmd_q *); > +void cmd_show_hooks_prepare(struct cmd *, struct cmd_q *); > + > +const struct cmd_entry cmd_show_hooks_entry = { > + "show-hooks", NULL, > + "gt:", 0, 1, > + "[-g] " CMD_TARGET_SESSION_USAGE, > + 0, > + NULL, > + NULL, > + cmd_show_hooks_exec, > + cmd_show_hooks_prepare > +}; > + > +void > +cmd_show_hooks_prepare(struct cmd *self, struct cmd_q *cmdq) > +{ > + struct args *args = self->args; > + > + cmdq->cmd_ctx.s = cmd_find_session(cmdq, args_get(args, 't'), 0); > +} > + > +enum cmd_retval > +cmd_show_hooks_exec(struct cmd *self, struct cmd_q *cmdq) > +{ > + struct args *args = self->args; > + struct session *s; > + struct hooks *hooks; > + struct hook *hook; > + char tmp[BUFSIZ]; > + size_t used; > + > + if ((s = cmdq->cmd_ctx.s) == NULL) > + return (CMD_RETURN_ERROR); > + > + hooks = args_has(args, 'g') ? &global_hooks : &s->hooks; > + > + RB_FOREACH(hook, hooks_tree, &hooks->tree) { > + used = xsnprintf(tmp, sizeof tmp, "%s -> ", hook->name); > + cmd_list_print(hook->cmdlist, tmp + used, (sizeof tmp) - used); > + cmdq_print(cmdq, "%s", tmp); > + } > + return (CMD_RETURN_NORMAL); > +} > diff --git a/hooks.c b/hooks.c > new file mode 100644 > index 0000000..e2aa8d7 > --- /dev/null > +++ b/hooks.c > @@ -0,0 +1,109 @@ > +/* $Id$ */ > + > +/* > + * Copyright (c) 2012 Thomas Adam <tho...@xteddy.org> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER > + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING > + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <sys/types.h> > + > +#include <stdlib.h> > +#include <string.h> > + > +#include "tmux.h" > + > +RB_GENERATE(hooks_tree, hook, entry, hooks_cmp); > + > +struct hook *hooks_find1(struct hooks *, const char *); > + > +int > +hooks_cmp(struct hook *hook1, struct hook *hook2) > +{ > + return (strcmp(hook1->name, hook2->name)); > +} > + > +void > +hooks_init(struct hooks *hooks, struct hooks *copy) > +{ > + RB_INIT(&hooks->tree); > + hooks->parent = copy; > +} > + > +void > +hooks_free(struct hooks *hooks) > +{ > + struct hook *h, *h2; > + > + RB_FOREACH_SAFE(h, hooks_tree, &hooks->tree, h2) > + hooks_remove(hooks, h); > +} > + > +void > +hooks_add(struct hooks *hooks, const char *name, struct cmd_list *cmdlist) > +{ > + struct hook *h; > + > + if ((h = hooks_find1(hooks, name)) != NULL) > + hooks_remove(hooks, h); > + > + h = xcalloc(1, sizeof *h); > + h->name = xstrdup(name); > + h->cmdlist = cmdlist; > + h->cmdlist->references++; > + > + RB_INSERT(hooks_tree, &hooks->tree, h); > +} > + > +void > +hooks_remove(struct hooks *hooks, struct hook *h) > +{ > + RB_REMOVE(hooks_tree, &hooks->tree, h); > + cmd_list_free(h->cmdlist); > + free(h->name); > + free(h); > +} > + > +struct hook * > +hooks_find1(struct hooks *hooks, const char *name) > +{ > + struct hook h; > + > + h.name = (char *) name; > + return (RB_FIND(hooks_tree, &hooks->tree, &h)); > +} > + > +struct hook * > +hooks_find(struct hooks *hooks, const char *name) > +{ > + struct hook h, *he; > + > + h.name = (char *) name; > + he = RB_FIND(hooks_tree, &hooks->tree, &h); > + while (he == NULL) { > + hooks = hooks->parent; > + if (hooks == NULL) > + break; > + he = RB_FIND(hooks_tree, &hooks->tree, &h); > + } > + return (he); > +} > + > +void > +hooks_run(struct hook *hook, struct cmd_q *cmdq) > +{ > + struct cmd *cmd; > + > + TAILQ_FOREACH(cmd, &hook->cmdlist->list, qentry) > + cmd->entry->exec(cmd, cmdq); > +} > diff --git a/session.c b/session.c > index bb742d8..526cb85 100644 > --- a/session.c > +++ b/session.c > @@ -104,6 +104,7 @@ session_create(const char *name, const char *cmd, const > char *cwd, > TAILQ_INIT(&s->lastw); > RB_INIT(&s->windows); > > + hooks_init(&s->hooks, &global_hooks); > options_init(&s->options, &global_s_options); > environ_init(&s->environ); > if (env != NULL) > @@ -161,6 +162,7 @@ session_destroy(struct session *s) > session_group_remove(s); > environ_free(&s->environ); > options_free(&s->options); > + hooks_free(&s->hooks); > > while (!TAILQ_EMPTY(&s->lastw)) > winlink_stack_remove(&s->lastw, TAILQ_FIRST(&s->lastw)); > diff --git a/tmux.c b/tmux.c > index 606c574..31b72c5 100644 > --- a/tmux.c > +++ b/tmux.c > @@ -38,6 +38,7 @@ struct options global_options; /* server > options */ > struct options global_s_options; /* session options */ > struct options global_w_options; /* window options */ > struct environ global_environ; > +struct hooks global_hooks; > > struct event_base *ev_base; > > @@ -321,6 +322,7 @@ main(int argc, char **argv) > flags |= IDENTIFY_UTF8; > } > > + hooks_init(&global_hooks, NULL); > environ_init(&global_environ); > for (var = environ; *var != NULL; var++) > environ_put(&global_environ, *var); > diff --git a/tmux.h b/tmux.h > index 63eddd1..8581a10 100644 > --- a/tmux.h > +++ b/tmux.h > @@ -1080,6 +1080,18 @@ struct environ_entry { > }; > RB_HEAD(environ, environ_entry); > > +/* Hooks. */ > +struct hook { > + char *name; > + struct cmd_list *cmdlist; > + RB_ENTRY(hook) entry; > +}; > + > +struct hooks { > + RB_HEAD(hooks_tree, hook) tree; > + struct hooks *parent; > +}; > + > /* Client session. */ > struct session_group { > TAILQ_HEAD(, session) sessions; > @@ -1105,6 +1117,7 @@ struct session { > struct winlink_stack lastw; > struct winlinks windows; > > + struct hooks hooks; > struct options options; > > #define SESSION_UNATTACHED 0x1 /* not attached to any clients */ > @@ -1513,6 +1526,7 @@ RB_HEAD(format_tree, format_entry); > #define CMD_BUFFER_USAGE "[-b buffer-index]" > > /* tmux.c */ > +extern struct hooks global_hooks; > extern struct options global_options; > extern struct options global_s_options; > extern struct options global_w_options; > @@ -1563,6 +1577,17 @@ void format_window_pane(struct format_tree > *, > void format_paste_buffer(struct format_tree *, > struct paste_buffer *); > > +/* hooks.c */ > +int hooks_cmp(struct hook *, struct hook *); > +RB_PROTOTYPE(hooks_tree, hook, entry, hooks_cmp); > +void hooks_init(struct hooks *, struct hooks *); > +void hooks_free(struct hooks *); > +void hooks_add(struct hooks *, const char *, struct cmd_list *); > +void hooks_copy(struct hooks *, struct hooks *); > +void hooks_remove(struct hooks *, struct hook *); > +void hooks_run(struct hook *, struct cmd_q *); > +struct hook *hooks_find(struct hooks *, const char *); > + > /* mode-key.c */ > extern const struct mode_key_table mode_key_tables[]; > extern struct mode_key_tree mode_key_tree_vi_edit; > @@ -1838,10 +1863,12 @@ extern const struct cmd_entry cmd_send_prefix_entry; > extern const struct cmd_entry cmd_server_info_entry; > extern const struct cmd_entry cmd_set_buffer_entry; > extern const struct cmd_entry cmd_set_environment_entry; > +extern const struct cmd_entry cmd_set_hook_entry; > extern const struct cmd_entry cmd_set_option_entry; > extern const struct cmd_entry cmd_set_window_option_entry; > extern const struct cmd_entry cmd_show_buffer_entry; > extern const struct cmd_entry cmd_show_environment_entry; > +extern const struct cmd_entry cmd_show_hooks_entry; > extern const struct cmd_entry cmd_show_messages_entry; > extern const struct cmd_entry cmd_show_options_entry; > extern const struct cmd_entry cmd_show_window_options_entry; > -- > 1.8.4.rc2 > > > ------------------------------------------------------------------------------ > Introducing Performance Central, a new site from SourceForge and > AppDynamics. Performance Central is your source for news, insights, > analysis and resources for efficient Application Performance Management. > Visit us today! > http://pubads.g.doubleclick.net/gampad/clk?id=48897511&iu=/4140/ostg.clktrk > _______________________________________________ > tmux-users mailing list > tmux-users@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/tmux-users ------------------------------------------------------------------------------ October Webinars: Code for Performance Free Intel webinars can help you accelerate application performance. Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from the latest Intel processors and coprocessors. See abstracts and register > http://pubads.g.doubleclick.net/gampad/clk?id=60135031&iu=/4140/ostg.clktrk _______________________________________________ tmux-users mailing list tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users