GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/tmux/hooks.c Lines: 4 70 5.7 %
Date: 2017-11-07 Branches: 0 184 0.0 %

Line Branch Exec Source
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
12
	hooks = xcalloc(1, sizeof *hooks);
57
6
	RB_INIT(&hooks->tree);
58
6
	hooks->parent = parent;
59
6
	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
}