ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/libio/misc/hook.c
Revision: 85
Committed: Wed Oct 5 14:29:35 2005 UTC (20 years, 10 months ago) by adx
Content type: text/x-csrc
File size: 4715 byte(s)
Log Message:
- register_callback: always restore the original handler at the end
  of the chain, not only when the chain is empty

File Contents

# User Rev Content
1 adx 61 /*
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 knight 71 * $Id$
24 adx 61 */
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 adx 85 dlinkAddTail(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
58     return (cb);
59 adx 61 }
60    
61     cb = MyMalloc(sizeof(struct Callback));
62     if (func != NULL)
63     dlinkAdd(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
64     if (name != NULL)
65     {
66     DupString(cb->name, name);
67     dlinkAdd(cb, &cb->node, &callback_list);
68     }
69     return (cb);
70     }
71    
72     /*
73     * execute_callback()
74     *
75     * Passes control down the callback hook chain.
76     *
77     * inputs:
78     * callback - pointer to Callback structure
79     * param - argument to pass
80     * output: function return value
81     */
82     void *
83     execute_callback(struct Callback *cb, ...)
84     {
85     void *res;
86     va_list args;
87    
88     cb->called++;
89     cb->last = CurrentTime;
90    
91     if (!is_callback_present(cb))
92     return (NULL);
93    
94     va_start(args, cb);
95     res = ((CBFUNC *) cb->chain.head->data)(args);
96     va_end(args);
97     return (res);
98     }
99    
100     /*
101     * pass_callback()
102     *
103     * Called by a hook function to pass code flow further
104     * in the hook chain.
105     *
106     * inputs:
107     * this_hook - pointer to dlink_node of the current hook function
108     * ... - (original or modified) arguments to be passed
109     * output: callback return value
110     */
111     void *
112     pass_callback(dlink_node *this_hook, ...)
113     {
114     void *res;
115     va_list args;
116    
117     if (this_hook->next == NULL)
118     return (NULL); /* reached the last one */
119    
120     va_start(args, this_hook);
121     res = ((CBFUNC *) this_hook->next->data)(args);
122     va_end(args);
123     return (res);
124     }
125    
126     /*
127     * find_callback()
128     *
129     * Finds a named callback.
130     *
131     * inputs:
132     * name - name of the callback
133     * output: pointer to Callback structure or NULL if not found
134     */
135     struct Callback *
136     find_callback(const char *name)
137     {
138     struct Callback *cb;
139     dlink_node *ptr;
140    
141     DLINK_FOREACH(ptr, callback_list.head)
142     {
143     cb = ptr->data;
144     if (!irccmp(cb->name, name))
145     return (cb);
146     }
147    
148     return (NULL);
149     }
150    
151     /*
152     * install_hook()
153     *
154     * Installs a hook for the given callback.
155     *
156     * inputs:
157     * cb - pointer to Callback structure
158     * hook - address of hook function
159     * output: pointer to dlink_node of the hook (used when
160     * passing control to the next hook in the chain);
161     * valid till uninstall_hook() is called
162     *
163     * NOTE: The new hook is installed at the beginning of the chain,
164     * so it has full control over functions installed earlier.
165     */
166     dlink_node *
167     install_hook(struct Callback *cb, CBFUNC *hook)
168     {
169     dlink_node *node = MyMalloc(sizeof(dlink_node));
170    
171     dlinkAdd(hook, node, &cb->chain);
172     return (node);
173     }
174    
175     /*
176     * uninstall_hook()
177     *
178     * Removes a specific hook for the given callback.
179     *
180     * inputs:
181     * cb - pointer to Callback structure
182     * hook - address of hook function
183     * output: none
184     */
185     void
186     uninstall_hook(struct Callback *cb, CBFUNC *hook)
187     {
188     /* let it core if not found */
189     dlink_node *ptr = dlinkFind(&cb->chain, hook);
190    
191     dlinkDelete(ptr, &cb->chain);
192     MyFree(ptr);
193     }

Properties

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