ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/libio/misc/hook.c
Revision: 156
Committed: Tue Oct 18 06:32:44 2005 UTC (20 years, 9 months ago) by adx
Content type: text/x-csrc
File size: 4741 byte(s)
Log Message:
- fixed register_callback re-registering

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * hook.c: Provides a generic event hooking interface.
4 *
5 * Copyright (C) 2003 Piotr Nizynski, Advanced IRC Services Project Team
6 * Copyright (C) 2005 Hybrid Development Team
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 *
23 * $Id$
24 */
25
26 #include "stdinc.h"
27
28 dlink_list callback_list = {NULL, NULL, 0};
29
30 /*
31 * register_callback()
32 *
33 * Creates a new callback.
34 *
35 * inputs:
36 * name - name used to identify the callback
37 * (can be NULL for anonymous callbacks)
38 * func - initial function attached to the chain
39 * (can be NULL to create an empty chain)
40 * output: pointer to Callback structure or NULL if already exists
41 *
42 * NOTE: Once registered, a callback should never be freed!
43 * That's because there may be modules which depend on it
44 * (even if no functions are attached). That's also why
45 * we dynamically allocate the struct here -- we don't want
46 * to allow anyone to place it in module data, which can be
47 * unloaded at any time.
48 */
49 struct Callback *
50 register_callback(const char *name, CBFUNC *func)
51 {
52 struct Callback *cb;
53
54 if (name != NULL)
55 if ((cb = find_callback(name)) != NULL)
56 {
57 if (func != NULL)
58 dlinkAddTail(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
59 return (cb);
60 }
61
62 cb = MyMalloc(sizeof(struct Callback));
63 if (func != NULL)
64 dlinkAdd(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
65 if (name != NULL)
66 {
67 DupString(cb->name, name);
68 dlinkAdd(cb, &cb->node, &callback_list);
69 }
70 return (cb);
71 }
72
73 /*
74 * execute_callback()
75 *
76 * Passes control down the callback hook chain.
77 *
78 * inputs:
79 * callback - pointer to Callback structure
80 * param - argument to pass
81 * output: function return value
82 */
83 void *
84 execute_callback(struct Callback *cb, ...)
85 {
86 void *res;
87 va_list args;
88
89 cb->called++;
90 cb->last = CurrentTime;
91
92 if (!is_callback_present(cb))
93 return (NULL);
94
95 va_start(args, cb);
96 res = ((CBFUNC *) cb->chain.head->data)(args);
97 va_end(args);
98 return (res);
99 }
100
101 /*
102 * pass_callback()
103 *
104 * Called by a hook function to pass code flow further
105 * in the hook chain.
106 *
107 * inputs:
108 * this_hook - pointer to dlink_node of the current hook function
109 * ... - (original or modified) arguments to be passed
110 * output: callback return value
111 */
112 void *
113 pass_callback(dlink_node *this_hook, ...)
114 {
115 void *res;
116 va_list args;
117
118 if (this_hook->next == NULL)
119 return (NULL); /* reached the last one */
120
121 va_start(args, this_hook);
122 res = ((CBFUNC *) this_hook->next->data)(args);
123 va_end(args);
124 return (res);
125 }
126
127 /*
128 * find_callback()
129 *
130 * Finds a named callback.
131 *
132 * inputs:
133 * name - name of the callback
134 * output: pointer to Callback structure or NULL if not found
135 */
136 struct Callback *
137 find_callback(const char *name)
138 {
139 struct Callback *cb;
140 dlink_node *ptr;
141
142 DLINK_FOREACH(ptr, callback_list.head)
143 {
144 cb = ptr->data;
145 if (!irccmp(cb->name, name))
146 return (cb);
147 }
148
149 return (NULL);
150 }
151
152 /*
153 * install_hook()
154 *
155 * Installs a hook for the given callback.
156 *
157 * inputs:
158 * cb - pointer to Callback structure
159 * hook - address of hook function
160 * output: pointer to dlink_node of the hook (used when
161 * passing control to the next hook in the chain);
162 * valid till uninstall_hook() is called
163 *
164 * NOTE: The new hook is installed at the beginning of the chain,
165 * so it has full control over functions installed earlier.
166 */
167 dlink_node *
168 install_hook(struct Callback *cb, CBFUNC *hook)
169 {
170 dlink_node *node = MyMalloc(sizeof(dlink_node));
171
172 dlinkAdd(hook, node, &cb->chain);
173 return (node);
174 }
175
176 /*
177 * uninstall_hook()
178 *
179 * Removes a specific hook for the given callback.
180 *
181 * inputs:
182 * cb - pointer to Callback structure
183 * hook - address of hook function
184 * output: none
185 */
186 void
187 uninstall_hook(struct Callback *cb, CBFUNC *hook)
188 {
189 /* let it core if not found */
190 dlink_node *ptr = dlinkFind(&cb->chain, hook);
191
192 dlinkDelete(ptr, &cb->chain);
193 MyFree(ptr);
194 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision