Optimize 'string-hash'.
[bpt/guile.git] / libguile / hooks.c
CommitLineData
1a531c80 1/* Copyright (C) 1995,1996,1998,1999,2000,2001, 2003, 2006, 2008, 2009 Free Software Foundation, Inc.
abd95148 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
abd95148 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
abd95148 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
abd95148 18
abd95148
MD
19
20\f
dbb605f5
LC
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
abd95148
MD
24
25#include <stdio.h>
26#include "libguile/_scm.h"
27
28#include "libguile/eval.h"
29#include "libguile/ports.h"
30#include "libguile/procprop.h"
31#include "libguile/root.h"
32#include "libguile/smob.h"
33#include "libguile/strings.h"
34
35#include "libguile/validate.h"
36#include "libguile/hooks.h"
37
38\f
39/* C level hooks
40 *
41 * Currently, this implementation is separate from the Scheme level
42 * hooks. The possibility exists to implement the Scheme level hooks
43 * using C level hooks.
44 */
45
1a531c80
LC
46/* Hint for `scm_gc_malloc ()' and friends. */
47static const char hook_entry_gc_hint[] = "hook entry";
48
abd95148 49void
387d418c 50scm_c_hook_init (scm_t_c_hook *hook, void *hook_data, scm_t_c_hook_type type)
abd95148
MD
51{
52 hook->first = 0;
53 hook->type = type;
54 hook->data = hook_data;
55}
56
57void
92c2555f
MV
58scm_c_hook_add (scm_t_c_hook *hook,
59 scm_t_c_hook_function func,
5c004b6d 60 void *fn_data,
abd95148
MD
61 int appendp)
62{
1a531c80 63 scm_t_c_hook_entry *entry;
92c2555f 64 scm_t_c_hook_entry **loc = &hook->first;
1a531c80
LC
65
66 entry = scm_gc_malloc (sizeof (scm_t_c_hook_entry), hook_entry_gc_hint);
abd95148
MD
67 if (appendp)
68 while (*loc)
c35738c1 69 loc = &(*loc)->next;
abd95148
MD
70 entry->next = *loc;
71 entry->func = func;
5c004b6d 72 entry->data = fn_data;
abd95148
MD
73 *loc = entry;
74}
75
76void
92c2555f
MV
77scm_c_hook_remove (scm_t_c_hook *hook,
78 scm_t_c_hook_function func,
5c004b6d 79 void *fn_data)
abd95148 80{
92c2555f 81 scm_t_c_hook_entry **loc = &hook->first;
abd95148
MD
82 while (*loc)
83 {
5c004b6d 84 if ((*loc)->func == func && (*loc)->data == fn_data)
abd95148 85 {
abd95148 86 *loc = (*loc)->next;
abd95148
MD
87 return;
88 }
89 loc = &(*loc)->next;
90 }
91 fprintf (stderr, "Attempt to remove non-existent hook function\n");
92 abort ();
93}
94
95void *
92c2555f 96scm_c_hook_run (scm_t_c_hook *hook, void *data)
abd95148 97{
92c2555f 98 scm_t_c_hook_entry *entry = hook->first;
387d418c 99 scm_t_c_hook_type type = hook->type;
abd95148
MD
100 void *res = 0;
101 while (entry)
102 {
103 res = (entry->func) (hook->data, entry->data, data);
104 if (res)
105 {
106 if (type == SCM_C_HOOK_OR)
107 break;
108 }
109 else
110 {
111 if (type == SCM_C_HOOK_AND)
112 break;
113 }
114 entry = entry->next;
115 }
116 return res;
117}
118
119\f
120/* Scheme level hooks
121 *
122 * A hook is basically a list of procedures to be called at well defined
123 * points in time.
124 *
e11f8b42
DH
125 * Hook arity is not a full member of this type and therefore lacks an
126 * accessor. It exists to aid debugging and is not intended to be used in
127 * programs.
abd95148
MD
128 */
129
92c2555f 130scm_t_bits scm_tc16_hook;
abd95148
MD
131
132
abd95148 133static int
e841c3e0 134hook_print (SCM hook, SCM port, scm_print_state *pstate)
abd95148
MD
135{
136 SCM ls, name;
137 scm_puts ("#<hook ", port);
abd95148
MD
138 scm_intprint (SCM_HOOK_ARITY (hook), 10, port);
139 scm_putc (' ', port);
0345e278 140 scm_uintprint (SCM_UNPACK (hook), 16, port);
abd95148
MD
141 ls = SCM_HOOK_PROCEDURES (hook);
142 while (SCM_NIMP (ls))
143 {
144 scm_putc (' ', port);
145 name = scm_procedure_name (SCM_CAR (ls));
7888309b 146 if (scm_is_true (name))
abd95148
MD
147 scm_iprin1 (name, port, pstate);
148 else
149 scm_putc ('?', port);
150 ls = SCM_CDR (ls);
151 }
152 scm_putc ('>', port);
153 return 1;
154}
155
abd95148 156
abd95148
MD
157SCM_DEFINE (scm_make_hook, "make-hook", 0, 1, 0,
158 (SCM n_args),
f91e4547
MG
159 "Create a hook for storing procedure of arity @var{n_args}.\n"
160 "@var{n_args} defaults to zero. The returned value is a hook\n"
161 "object to be used with the other hook procedures.")
abd95148
MD
162#define FUNC_NAME s_scm_make_hook
163{
a55c2b68 164 unsigned int n;
fde50407
ML
165
166 if (SCM_UNBNDP (n_args))
a55c2b68 167 n = 0;
fde50407 168 else
a55c2b68 169 n = scm_to_unsigned_integer (n_args, 0, 16);
fde50407
ML
170
171 SCM_RETURN_NEWSMOB (scm_tc16_hook + (n << 16), SCM_UNPACK (SCM_EOL));
abd95148
MD
172}
173#undef FUNC_NAME
174
175
176SCM_DEFINE (scm_hook_p, "hook?", 1, 0, 0,
177 (SCM x),
4d66be54 178 "Return @code{#t} if @var{x} is a hook, @code{#f} otherwise.")
abd95148
MD
179#define FUNC_NAME s_scm_hook_p
180{
7888309b 181 return scm_from_bool (SCM_HOOKP (x));
abd95148
MD
182}
183#undef FUNC_NAME
184
185
186SCM_DEFINE (scm_hook_empty_p, "hook-empty?", 1, 0, 0,
187 (SCM hook),
4d66be54
MG
188 "Return @code{#t} if @var{hook} is an empty hook, @code{#f}\n"
189 "otherwise.")
abd95148
MD
190#define FUNC_NAME s_scm_hook_empty_p
191{
192 SCM_VALIDATE_HOOK (1, hook);
d2e53ed6 193 return scm_from_bool (scm_is_null (SCM_HOOK_PROCEDURES (hook)));
abd95148
MD
194}
195#undef FUNC_NAME
196
197
198SCM_DEFINE (scm_add_hook_x, "add-hook!", 2, 1, 0,
199 (SCM hook, SCM proc, SCM append_p),
8d1b3ae9
MG
200 "Add the procedure @var{proc} to the hook @var{hook}. The\n"
201 "procedure is added to the end if @var{append_p} is true,\n"
f91e4547
MG
202 "otherwise it is added to the front. The return value of this\n"
203 "procedure is not specified.")
abd95148
MD
204#define FUNC_NAME s_scm_add_hook_x
205{
314b8716
AW
206 SCM rest;
207 int n_args, p_req, p_opt, p_rest;
34d19ef6 208 SCM_VALIDATE_HOOK (1, hook);
314b8716 209 SCM_ASSERT (scm_i_procedure_arity (proc, &p_req, &p_opt, &p_rest),
abd95148
MD
210 proc, SCM_ARG2, FUNC_NAME);
211 n_args = SCM_HOOK_ARITY (hook);
314b8716 212 if (p_req > n_args || (!p_rest && p_req + p_opt < n_args))
abd95148
MD
213 scm_wrong_type_arg (FUNC_NAME, 2, proc);
214 rest = scm_delq_x (proc, SCM_HOOK_PROCEDURES (hook));
215 SCM_SET_HOOK_PROCEDURES (hook,
7888309b 216 (!SCM_UNBNDP (append_p) && scm_is_true (append_p)
1afff620 217 ? scm_append_x (scm_list_2 (rest, scm_list_1 (proc)))
abd95148
MD
218 : scm_cons (proc, rest)));
219 return SCM_UNSPECIFIED;
220}
221#undef FUNC_NAME
222
223
224SCM_DEFINE (scm_remove_hook_x, "remove-hook!", 2, 0, 0,
225 (SCM hook, SCM proc),
f91e4547
MG
226 "Remove the procedure @var{proc} from the hook @var{hook}. The\n"
227 "return value of this procedure is not specified.")
abd95148
MD
228#define FUNC_NAME s_scm_remove_hook_x
229{
230 SCM_VALIDATE_HOOK (1, hook);
231 SCM_SET_HOOK_PROCEDURES (hook,
232 scm_delq_x (proc, SCM_HOOK_PROCEDURES (hook)));
233 return SCM_UNSPECIFIED;
234}
235#undef FUNC_NAME
236
237
238SCM_DEFINE (scm_reset_hook_x, "reset-hook!", 1, 0, 0,
239 (SCM hook),
f91e4547
MG
240 "Remove all procedures from the hook @var{hook}. The return\n"
241 "value of this procedure is not specified.")
abd95148
MD
242#define FUNC_NAME s_scm_reset_hook_x
243{
34d19ef6 244 SCM_VALIDATE_HOOK (1, hook);
abd95148
MD
245 SCM_SET_HOOK_PROCEDURES (hook, SCM_EOL);
246 return SCM_UNSPECIFIED;
247}
248#undef FUNC_NAME
249
250
251SCM_DEFINE (scm_run_hook, "run-hook", 1, 0, 1,
252 (SCM hook, SCM args),
8d1b3ae9 253 "Apply all procedures from the hook @var{hook} to the arguments\n"
4d66be54 254 "@var{args}. The order of the procedure application is first to\n"
f91e4547 255 "last. The return value of this procedure is not specified.")
abd95148
MD
256#define FUNC_NAME s_scm_run_hook
257{
34d19ef6 258 SCM_VALIDATE_HOOK (1, hook);
abd95148
MD
259 if (scm_ilength (args) != SCM_HOOK_ARITY (hook))
260 SCM_MISC_ERROR ("Hook ~S requires ~A arguments",
e11e83f3 261 scm_list_2 (hook, scm_from_int (SCM_HOOK_ARITY (hook))));
abd95148
MD
262 scm_c_run_hook (hook, args);
263 return SCM_UNSPECIFIED;
264}
265#undef FUNC_NAME
266
267
268void
269scm_c_run_hook (SCM hook, SCM args)
270{
271 SCM procs = SCM_HOOK_PROCEDURES (hook);
272 while (SCM_NIMP (procs))
273 {
fdc28395 274 scm_apply_0 (SCM_CAR (procs), args);
abd95148
MD
275 procs = SCM_CDR (procs);
276 }
277}
278
86fd6dff
AW
279void
280scm_c_run_hookn (SCM hook, SCM *argv, size_t nargs)
281{
282 SCM procs = SCM_HOOK_PROCEDURES (hook);
283 while (SCM_NIMP (procs))
284 {
285 scm_call_n (SCM_CAR (procs), argv, nargs);
286 procs = SCM_CDR (procs);
287 }
288}
289
abd95148
MD
290
291SCM_DEFINE (scm_hook_to_list, "hook->list", 1, 0, 0,
292 (SCM hook),
8d1b3ae9 293 "Convert the procedure list of @var{hook} to a list.")
abd95148
MD
294#define FUNC_NAME s_scm_hook_to_list
295{
296 SCM_VALIDATE_HOOK (1, hook);
297 return scm_list_copy (SCM_HOOK_PROCEDURES (hook));
298}
299#undef FUNC_NAME
300
301
302\f
303
304void
305scm_init_hooks ()
306{
307 scm_tc16_hook = scm_make_smob_type ("hook", 0);
e841c3e0 308 scm_set_smob_print (scm_tc16_hook, hook_print);
abd95148
MD
309#include "libguile/hooks.x"
310}
311
312/*
313 Local Variables:
314 c-file-style: "gnu"
315 End:
316*/