ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hook.c
Revision: 1155
Committed: Tue Aug 9 20:27:45 2011 UTC (14 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/src/hook.c
File size: 5832 byte(s)
Log Message:
- recreate "trunk"

File Contents

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

Properties

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