GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/tmux/hooks.c Lines: 0 81 0.0 %
Date: 2016-12-06 Branches: 0 234 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: hooks.c,v 1.4 2015/12/16 21:50: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_PROTOTYPE(hooks_tree, hook, entry, hooks_cmp);
33
RB_GENERATE(hooks_tree, hook, entry, hooks_cmp);
34
35
static struct hook	*hooks_find1(struct hooks *, const char *);
36
static void		 hooks_free1(struct hooks *, struct hook *);
37
static void		 hooks_emptyfn(struct cmd_q *);
38
39
static int
40
hooks_cmp(struct hook *hook1, struct hook *hook2)
41
{
42
	return (strcmp(hook1->name, hook2->name));
43
}
44
45
struct hooks *
46
hooks_get(struct session *s)
47
{
48
	if (s != NULL)
49
		return (s->hooks);
50
	return (global_hooks);
51
}
52
53
struct hooks *
54
hooks_create(struct hooks *parent)
55
{
56
	struct hooks	*hooks;
57
58
	hooks = xcalloc(1, sizeof *hooks);
59
	RB_INIT(&hooks->tree);
60
	hooks->parent = parent;
61
	return (hooks);
62
}
63
64
static void
65
hooks_free1(struct hooks *hooks, struct hook *hook)
66
{
67
	RB_REMOVE(hooks_tree, &hooks->tree, hook);
68
	cmd_list_free(hook->cmdlist);
69
	free((char *)hook->name);
70
	free(hook);
71
}
72
73
void
74
hooks_free(struct hooks *hooks)
75
{
76
	struct hook	*hook, *hook1;
77
78
	RB_FOREACH_SAFE(hook, hooks_tree, &hooks->tree, hook1)
79
		hooks_free1(hooks, hook);
80
	free(hooks);
81
}
82
83
struct hook *
84
hooks_first(struct hooks *hooks)
85
{
86
	return (RB_MIN(hooks_tree, &hooks->tree));
87
}
88
89
struct hook *
90
hooks_next(struct hook *hook)
91
{
92
	return (RB_NEXT(hooks_tree, &hooks->tree, hook));
93
}
94
95
void
96
hooks_add(struct hooks *hooks, const char *name, struct cmd_list *cmdlist)
97
{
98
	struct hook	*hook;
99
100
	if ((hook = hooks_find1(hooks, name)) != NULL)
101
		hooks_free1(hooks, hook);
102
103
	hook = xcalloc(1, sizeof *hook);
104
	hook->name = xstrdup(name);
105
	hook->cmdlist = cmdlist;
106
	hook->cmdlist->references++;
107
	RB_INSERT(hooks_tree, &hooks->tree, hook);
108
}
109
110
void
111
hooks_remove(struct hooks *hooks, const char *name)
112
{
113
	struct hook	*hook;
114
115
	if ((hook = hooks_find1(hooks, name)) != NULL)
116
		hooks_free1(hooks, hook);
117
}
118
119
static struct hook *
120
hooks_find1(struct hooks *hooks, const char *name)
121
{
122
	struct hook	hook;
123
124
	hook.name = name;
125
	return (RB_FIND(hooks_tree, &hooks->tree, &hook));
126
}
127
128
struct hook *
129
hooks_find(struct hooks *hooks, const char *name)
130
{
131
	struct hook	 hook0, *hook;
132
133
	hook0.name = name;
134
	hook = RB_FIND(hooks_tree, &hooks->tree, &hook0);
135
	while (hook == NULL) {
136
		hooks = hooks->parent;
137
		if (hooks == NULL)
138
			break;
139
		hook = RB_FIND(hooks_tree, &hooks->tree, &hook0);
140
	}
141
	return (hook);
142
}
143
144
static void
145
hooks_emptyfn(struct cmd_q *hooks_cmdq)
146
{
147
	struct cmd_q	*cmdq = hooks_cmdq->data;
148
149
	if (cmdq != NULL) {
150
		if (hooks_cmdq->client_exit >= 0)
151
			cmdq->client_exit = hooks_cmdq->client_exit;
152
		if (!cmdq_free(cmdq))
153
			cmdq_continue(cmdq);
154
	}
155
	cmdq_free(hooks_cmdq);
156
}
157
158
int
159
hooks_run(struct hooks *hooks, struct client *c, struct cmd_find_state *fs,
160
    const char *fmt, ...)
161
{
162
	struct hook	*hook;
163
	struct cmd_q	*hooks_cmdq;
164
	va_list		 ap;
165
	char		*name;
166
167
	va_start(ap, fmt);
168
	xvasprintf(&name, fmt, ap);
169
	va_end(ap);
170
171
	hook = hooks_find(hooks, name);
172
	if (hook == NULL) {
173
		free(name);
174
		return (-1);
175
	}
176
	log_debug("running hook %s", name);
177
	free(name);
178
179
	hooks_cmdq = cmdq_new(c);
180
	hooks_cmdq->flags |= CMD_Q_NOHOOKS;
181
182
	if (fs != NULL)
183
		cmd_find_copy_state(&hooks_cmdq->current, fs);
184
	hooks_cmdq->parent = NULL;
185
186
	cmdq_run(hooks_cmdq, hook->cmdlist, NULL);
187
	cmdq_free(hooks_cmdq);
188
	return (0);
189
}
190
191
int
192
hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, struct cmd_find_state *fs,
193
    const char *fmt, ...)
194
{
195
	struct hook	*hook;
196
	struct cmd_q	*hooks_cmdq;
197
	va_list		 ap;
198
	char		*name;
199
200
	va_start(ap, fmt);
201
	xvasprintf(&name, fmt, ap);
202
	va_end(ap);
203
204
	hook = hooks_find(hooks, name);
205
	if (hook == NULL) {
206
		free(name);
207
		return (-1);
208
	}
209
	log_debug("running hook %s (parent %p)", name, cmdq);
210
	free(name);
211
212
	hooks_cmdq = cmdq_new(cmdq->client);
213
	hooks_cmdq->flags |= CMD_Q_NOHOOKS;
214
215
	if (fs != NULL)
216
		cmd_find_copy_state(&hooks_cmdq->current, fs);
217
	hooks_cmdq->parent = cmdq;
218
219
	hooks_cmdq->emptyfn = hooks_emptyfn;
220
	hooks_cmdq->data = cmdq;
221
222
	if (cmdq != NULL)
223
		cmdq->references++;
224
	cmdq_run(hooks_cmdq, hook->cmdlist, NULL);
225
	return (0);
226
}