1 |
|
|
/* $OpenBSD: hooks.c,v 1.9 2016/10/16 19:36:37 nicm Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER |
15 |
|
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
16 |
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <sys/types.h> |
20 |
|
|
|
21 |
|
|
#include <stdlib.h> |
22 |
|
|
#include <string.h> |
23 |
|
|
|
24 |
|
|
#include "tmux.h" |
25 |
|
|
|
26 |
|
|
struct hooks { |
27 |
|
|
RB_HEAD(hooks_tree, hook) tree; |
28 |
|
|
struct hooks *parent; |
29 |
|
|
}; |
30 |
|
|
|
31 |
|
|
static int hooks_cmp(struct hook *, struct hook *); |
32 |
|
|
RB_GENERATE_STATIC(hooks_tree, hook, entry, hooks_cmp); |
33 |
|
|
|
34 |
|
|
static struct hook *hooks_find1(struct hooks *, const char *); |
35 |
|
|
static void hooks_free1(struct hooks *, struct hook *); |
36 |
|
|
|
37 |
|
|
static int |
38 |
|
|
hooks_cmp(struct hook *hook1, struct hook *hook2) |
39 |
|
|
{ |
40 |
|
|
return (strcmp(hook1->name, hook2->name)); |
41 |
|
|
} |
42 |
|
|
|
43 |
|
|
struct hooks * |
44 |
|
|
hooks_get(struct session *s) |
45 |
|
|
{ |
46 |
|
|
if (s != NULL) |
47 |
|
|
return (s->hooks); |
48 |
|
|
return (global_hooks); |
49 |
|
|
} |
50 |
|
|
|
51 |
|
|
struct hooks * |
52 |
|
|
hooks_create(struct hooks *parent) |
53 |
|
|
{ |
54 |
|
|
struct hooks *hooks; |
55 |
|
|
|
56 |
|
|
hooks = xcalloc(1, sizeof *hooks); |
57 |
|
|
RB_INIT(&hooks->tree); |
58 |
|
|
hooks->parent = parent; |
59 |
|
|
return (hooks); |
60 |
|
|
} |
61 |
|
|
|
62 |
|
|
static void |
63 |
|
|
hooks_free1(struct hooks *hooks, struct hook *hook) |
64 |
|
|
{ |
65 |
|
|
RB_REMOVE(hooks_tree, &hooks->tree, hook); |
66 |
|
|
cmd_list_free(hook->cmdlist); |
67 |
|
|
free((char *)hook->name); |
68 |
|
|
free(hook); |
69 |
|
|
} |
70 |
|
|
|
71 |
|
|
void |
72 |
|
|
hooks_free(struct hooks *hooks) |
73 |
|
|
{ |
74 |
|
|
struct hook *hook, *hook1; |
75 |
|
|
|
76 |
|
|
RB_FOREACH_SAFE(hook, hooks_tree, &hooks->tree, hook1) |
77 |
|
|
hooks_free1(hooks, hook); |
78 |
|
|
free(hooks); |
79 |
|
|
} |
80 |
|
|
|
81 |
|
|
struct hook * |
82 |
|
|
hooks_first(struct hooks *hooks) |
83 |
|
|
{ |
84 |
|
|
return (RB_MIN(hooks_tree, &hooks->tree)); |
85 |
|
|
} |
86 |
|
|
|
87 |
|
|
struct hook * |
88 |
|
|
hooks_next(struct hook *hook) |
89 |
|
|
{ |
90 |
|
|
return (RB_NEXT(hooks_tree, &hooks->tree, hook)); |
91 |
|
|
} |
92 |
|
|
|
93 |
|
|
void |
94 |
|
|
hooks_add(struct hooks *hooks, const char *name, struct cmd_list *cmdlist) |
95 |
|
|
{ |
96 |
|
|
struct hook *hook; |
97 |
|
|
|
98 |
|
|
if ((hook = hooks_find1(hooks, name)) != NULL) |
99 |
|
|
hooks_free1(hooks, hook); |
100 |
|
|
|
101 |
|
|
hook = xcalloc(1, sizeof *hook); |
102 |
|
|
hook->name = xstrdup(name); |
103 |
|
|
hook->cmdlist = cmdlist; |
104 |
|
|
hook->cmdlist->references++; |
105 |
|
|
RB_INSERT(hooks_tree, &hooks->tree, hook); |
106 |
|
|
} |
107 |
|
|
|
108 |
|
|
void |
109 |
|
|
hooks_remove(struct hooks *hooks, const char *name) |
110 |
|
|
{ |
111 |
|
|
struct hook *hook; |
112 |
|
|
|
113 |
|
|
if ((hook = hooks_find1(hooks, name)) != NULL) |
114 |
|
|
hooks_free1(hooks, hook); |
115 |
|
|
} |
116 |
|
|
|
117 |
|
|
static struct hook * |
118 |
|
|
hooks_find1(struct hooks *hooks, const char *name) |
119 |
|
|
{ |
120 |
|
|
struct hook hook; |
121 |
|
|
|
122 |
|
|
hook.name = name; |
123 |
|
|
return (RB_FIND(hooks_tree, &hooks->tree, &hook)); |
124 |
|
|
} |
125 |
|
|
|
126 |
|
|
struct hook * |
127 |
|
|
hooks_find(struct hooks *hooks, const char *name) |
128 |
|
|
{ |
129 |
|
|
struct hook hook0, *hook; |
130 |
|
|
|
131 |
|
|
hook0.name = name; |
132 |
|
|
hook = RB_FIND(hooks_tree, &hooks->tree, &hook0); |
133 |
|
|
while (hook == NULL) { |
134 |
|
|
hooks = hooks->parent; |
135 |
|
|
if (hooks == NULL) |
136 |
|
|
break; |
137 |
|
|
hook = RB_FIND(hooks_tree, &hooks->tree, &hook0); |
138 |
|
|
} |
139 |
|
|
return (hook); |
140 |
|
|
} |
141 |
|
|
|
142 |
|
|
void |
143 |
|
|
hooks_run(struct hooks *hooks, struct client *c, struct cmd_find_state *fs, |
144 |
|
|
const char *fmt, ...) |
145 |
|
|
{ |
146 |
|
|
struct hook *hook; |
147 |
|
|
va_list ap; |
148 |
|
|
char *name; |
149 |
|
|
struct cmdq_item *new_item; |
150 |
|
|
|
151 |
|
|
va_start(ap, fmt); |
152 |
|
|
xvasprintf(&name, fmt, ap); |
153 |
|
|
va_end(ap); |
154 |
|
|
|
155 |
|
|
hook = hooks_find(hooks, name); |
156 |
|
|
if (hook == NULL) { |
157 |
|
|
free(name); |
158 |
|
|
return; |
159 |
|
|
} |
160 |
|
|
log_debug("running hook %s", name); |
161 |
|
|
|
162 |
|
|
new_item = cmdq_get_command(hook->cmdlist, fs, NULL, CMDQ_NOHOOKS); |
163 |
|
|
cmdq_format(new_item, "hook", "%s", name); |
164 |
|
|
cmdq_append(c, new_item); |
165 |
|
|
|
166 |
|
|
free(name); |
167 |
|
|
} |
168 |
|
|
|
169 |
|
|
void |
170 |
|
|
hooks_insert(struct hooks *hooks, struct cmdq_item *item, |
171 |
|
|
struct cmd_find_state *fs, const char *fmt, ...) |
172 |
|
|
{ |
173 |
|
|
struct hook *hook; |
174 |
|
|
va_list ap; |
175 |
|
|
char *name; |
176 |
|
|
struct cmdq_item *new_item; |
177 |
|
|
|
178 |
|
|
if (item->flags & CMDQ_NOHOOKS) |
179 |
|
|
return; |
180 |
|
|
|
181 |
|
|
va_start(ap, fmt); |
182 |
|
|
xvasprintf(&name, fmt, ap); |
183 |
|
|
va_end(ap); |
184 |
|
|
|
185 |
|
|
hook = hooks_find(hooks, name); |
186 |
|
|
if (hook == NULL) { |
187 |
|
|
free(name); |
188 |
|
|
return; |
189 |
|
|
} |
190 |
|
|
log_debug("running hook %s (parent %p)", name, item); |
191 |
|
|
|
192 |
|
|
new_item = cmdq_get_command(hook->cmdlist, fs, NULL, CMDQ_NOHOOKS); |
193 |
|
|
cmdq_format(new_item, "hook", "%s", name); |
194 |
|
|
if (item != NULL) |
195 |
|
|
cmdq_insert_after(item, new_item); |
196 |
|
|
else |
197 |
|
|
cmdq_append(NULL, new_item); |
198 |
|
|
|
199 |
|
|
free(name); |
200 |
|
|
} |