3 * Copyright (C) 1999 Steve Tell
5 * based heavily on callbacks.c from SCWM:
6 * Copyright (C) 1997-1999 Maciej Stachowiak and Greg J. Badros
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, or (at your option)
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.
18 * You should have received a copy of the GNU General Public License
19 * along with this software; see the file COPYING.GPL. If not, write to
20 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
21 * Boston, MA 02111-1307 USA
36 #include <libguile/fluids.h>
38 #include "scwm_guile.h"
39 #include "guile-compat.h"
45 extern char *prog_name
;
47 XSCM_HOOK(error_hook
, "error-hook", 5, (SCM a
, SCM b
, SCM c
, SCM d
, SCM e
),
48 "Called on all kinds of errors and exceptions."
49 "Whenever an error or other uncaught throw occurs on any callback,"
50 "whether a hook, a mouse binding, a key binding, a menu entry, a file"
51 "being processed, or anything else, error-hook will be invoked. Each"
52 "procedure in the hook will be called with the throw arguments; these"
53 "will generally include information about the nature of the error.");
55 struct scwm_body_apply_data
{
62 scwm_body_apply (void *body_data
)
64 struct scwm_body_apply_data
*ad
= (struct scwm_body_apply_data
*) body_data
;
65 return scm_apply(ad
->proc
, ad
->args
, SCM_EOL
);
68 /* Use scm_internal_cwdr to establish a new dynamic root - this causes
69 all throws to be caught and prevents continuations from exiting the
70 dynamic scope of the callback. This is needed to prevent callbacks
71 from disrupting scwm's flow control, which would likely cause a
72 crash. Use scm_internal_stack_catch to save the stack so we can
73 display a backtrace. scm_internal_stack_cwdr is the combination of
74 both. Note that the current implementation causes three(!) distinct
75 catch-like constructs to be used; this may have negative, perhaps
76 even significantly so, performance implications. */
81 scm_t_catch_body body
;
83 scm_t_catch_handler handler
;
87 cwssdr_body (void *data
)
89 struct cwssdr_data
*d
= (struct cwssdr_data
*) data
;
90 return scm_internal_stack_catch (d
->tag
, d
->body
, d
->data
, d
->handler
,
95 scm_internal_stack_cwdr (scm_t_catch_body body
,
97 scm_t_catch_handler handler
,
99 SCM_STACKITEM
*stack_item
)
101 struct cwssdr_data d
;
106 return scm_internal_cwdr(cwssdr_body
, &d
, handler
, handler_data
,
113 scwm_safe_apply (SCM proc
, SCM args
)
115 SCM_STACKITEM stack_item
;
116 struct scwm_body_apply_data apply_data
;
118 apply_data
.proc
= proc
;
119 apply_data
.args
= args
;
121 return scm_internal_stack_cwdr(scwm_body_apply
, &apply_data
,
122 scwm_handle_error
, prog_name
,
128 scwm_safe_apply_message_only (SCM proc
, SCM args
)
130 SCM_STACKITEM stack_item
;
131 struct scwm_body_apply_data apply_data
;
133 apply_data
.proc
= proc
;
134 apply_data
.args
= args
;
136 return scm_internal_cwdr(scwm_body_apply
, &apply_data
,
137 scm_handle_by_message_noexit
, prog_name
,
143 scwm_safe_call0 (SCM thunk
)
145 return scwm_safe_apply (thunk
, SCM_EOL
);
150 scwm_safe_call1 (SCM proc
, SCM arg
)
152 /* This means w must cons (albeit only once) on each callback of
153 size one - seems lame. */
154 return scwm_safe_apply (proc
, scm_list_1(arg
));
159 scwm_safe_call2 (SCM proc
, SCM arg1
, SCM arg2
)
161 /* This means w must cons (albeit only once) on each callback of
162 size two - seems lame. */
163 return scwm_safe_apply (proc
, scm_list_2(arg1
, arg2
));
167 scwm_safe_call3 (SCM proc
, SCM arg1
, SCM arg2
, SCM arg3
)
169 /* This means w must cons (albeit only once) on each callback of
170 size two - seems lame. */
171 return scwm_safe_apply (proc
, scm_list_3(arg1
, arg2
, arg3
));
175 scwm_safe_call4 (SCM proc
, SCM arg1
, SCM arg2
, SCM arg3
, SCM arg4
)
177 /* This means w must cons (albeit only once) on each callback of
178 size two - seems lame. */
179 return scwm_safe_apply (proc
, scm_list_4(arg1
, arg2
, arg3
, arg4
));
183 scwm_safe_call5 (SCM proc
, SCM arg1
, SCM arg2
, SCM arg3
, SCM arg4
, SCM arg5
)
185 /* This means w must cons (albeit only once) on each callback of
186 size two - seems lame. */
187 return scwm_safe_apply (proc
, scm_list_5(arg1
, arg2
, arg3
, arg4
, arg5
));
191 scwm_safe_call6 (SCM proc
, SCM arg1
, SCM arg2
, SCM arg3
, SCM arg4
, SCM arg5
, SCM arg6
)
193 return scwm_safe_apply (proc
, scm_list_n(arg1
, arg2
, arg3
, arg4
, arg5
, arg6
, SCM_UNDEFINED
));
197 scwm_safe_call7 (SCM proc
, SCM arg1
, SCM arg2
, SCM arg3
, SCM arg4
, SCM arg5
, SCM arg6
, SCM arg7
)
199 return scwm_safe_apply (proc
, scm_list_n(arg1
, arg2
, arg3
, arg4
, arg5
, arg6
, arg7
, SCM_UNDEFINED
));
203 static SCM run_hook_proc
;
205 SCM
scwm_run_hook(SCM hook
, SCM args
)
208 return scwm_safe_apply(run_hook_proc
, scm_cons(hook
,args
));
211 SCM
scwm_run_hook_message_only(SCM hook
, SCM args
)
213 return scwm_safe_apply_message_only(run_hook_proc
, scm_cons(hook
,args
));
217 SCM
call0_hooks(SCM hook
)
219 return scwm_run_hook(hook
,SCM_EOL
);
222 SCM
call1_hooks(SCM hook
, SCM arg1
)
224 return scwm_run_hook(hook
,scm_list_1(arg1
));
227 SCM
call2_hooks(SCM hook
, SCM arg1
, SCM arg2
)
229 return scwm_run_hook(hook
,scm_list_2(arg1
,arg2
));
232 SCM
call3_hooks(SCM hook
, SCM arg1
, SCM arg2
, SCM arg3
)
234 return scwm_run_hook(hook
,scm_list_n(arg1
,arg2
,arg3
,SCM_UNDEFINED
));
237 SCM
call4_hooks(SCM hook
, SCM arg1
, SCM arg2
, SCM arg3
, SCM arg4
)
239 return scwm_run_hook(hook
,scm_list_n(arg1
,arg2
,arg3
,arg4
,SCM_UNDEFINED
));
242 SCM
call5_hooks(SCM hook
, SCM arg1
, SCM arg2
, SCM arg3
, SCM arg4
, SCM arg5
)
244 return scwm_run_hook(hook
,scm_list_n(arg1
,arg2
,arg3
,arg4
,arg5
,SCM_UNDEFINED
));
247 SCM
call6_hooks(SCM hook
, SCM arg1
, SCM arg2
, SCM arg3
, SCM arg4
, SCM arg5
, SCM arg6
)
249 return scwm_run_hook(hook
,scm_list_n(arg1
,arg2
,arg3
,arg4
,arg5
,arg6
,SCM_UNDEFINED
));
252 SCM
call7_hooks(SCM hook
, SCM arg1
, SCM arg2
, SCM arg3
, SCM arg4
, SCM arg5
, SCM arg6
, SCM arg7
)
254 return scwm_run_hook(hook
,scm_list_n(arg1
,arg2
,arg3
,arg4
,arg5
,arg6
,arg7
,SCM_UNDEFINED
));
258 scm_empty_hook_p(SCM hook
)
260 return scm_hook_empty_p(hook
);
264 /* Slightly tricky - we want to catch errors per expression, but only
265 establish a new dynamic root per load operation, as it's perfectly
266 OK for a file to invoke a continuation created by a different
267 expression in the file as far as scwm is concerned. So we set a
268 dynamic root for the whole load operation, but also catch on each
272 scwm_body_eval_x (void *body_data
)
274 SCM expr
= *(SCM
*) body_data
;
275 return scm_eval_x (expr
, scm_current_module() );
279 scwm_catching_eval_x (SCM expr
) {
280 return scm_internal_stack_catch (SCM_BOOL_T
, scwm_body_eval_x
, &expr
,
281 scwm_handle_error
, prog_name
);
285 scwm_catching_load_from_port (SCM port
)
288 SCM answer
= SCM_UNSPECIFIED
;
290 while (!SCM_EOF_OBJECT_P(expr
= scm_read (port
))) {
291 answer
= scwm_catching_eval_x (expr
);
293 scm_close_port (port
);
299 scwm_body_load (void *body_data
)
301 SCM filename
= *(SCM
*) body_data
;
302 SCM port
= scm_open_file (filename
, scm_makfrom0str("r"));
303 return scwm_catching_load_from_port (port
);
307 scwm_body_eval_str (void *body_data
)
309 char *string
= (char *) body_data
;
310 SCM port
= scm_mkstrport (SCM_MAKINUM (0), scm_makfrom0str(string
),
311 SCM_OPN
| SCM_RDNG
, "scwm_safe_eval_str");
312 return scwm_catching_load_from_port (port
);
317 scwm_handle_error (void *ARG_IGNORE(data
), SCM tag
, SCM throw_args
)
319 #if 0 /* GJB:FIXME:: */
320 SCM port
= scm_mkstrport(SCM_INUM0
,
321 scm_make_string(SCM_MAKINUM(200), SCM_UNDEFINED
),
325 SCM port
= scm_current_error_port();
328 /* GJB:FIXME:MS: is this a guile compatibility test that can be dropped
330 if (scm_ilength (throw_args
) >= 3)
333 fl
= SCM_VARIABLE_REF (scm_the_last_stack_fluid_var
);
335 /* GJB:FIXME:MS: This is a horrible hack,
336 but DEREF_LAST_STACK macro was throwing a wrong type
337 argument at weird times, and I'm trying to avoid
338 a crash when I demo to RMS tomorrow, hence this
339 ugly hack --04/27/99 gjb */
340 if (SCM_NIMP (fl
) && SCM_FLUIDP (fl
)) {
341 SCM stack
= DEREF_LAST_STACK
;
342 SCM subr
= SCM_CAR (throw_args
);
343 SCM message
= SCM_CADR (throw_args
);
344 SCM args
= SCM_CADDR (throw_args
);
347 scm_display_backtrace (stack
, port
, SCM_UNDEFINED
, SCM_UNDEFINED
);
349 scm_display_error (stack
, port
, subr
, message
, args
, SCM_EOL
);
351 /* scwm_msg(ERR,"scwm_handle_error","scm_the_last_stack_fluid not holding a fluid!"); */
356 scm_puts ("uncaught throw to ", port
);
357 scm_prin1 (tag
, port
, 0);
358 scm_puts (": ", port
);
359 scm_prin1 (throw_args
, port
, 1);
360 scm_putc ('\n', port
);
363 /* GJB:FIXME:MS: can the scheme code display a backtrace without the
365 return scwm_run_hook_message_only(error_hook
, scm_cons(tag
, throw_args
));
369 SCM_DEFINE(safe_load
, "safe-load", 1, 0, 0,
371 "Load file FNAME while trapping and displaying errors."
372 "Each individual top-level-expression is evaluated separately and all"
373 "errors are trapped and displayed. You should use this procedure if"
374 "you need to make sure most of a file loads, even if it may contain"
376 #define FUNC_NAME s_safe_load
378 SCM_STACKITEM stack_item
;
379 VALIDATE_ARG_STR(1,fname
);
380 return scm_internal_cwdr(scwm_body_load
, &fname
,
381 scm_handle_by_message_noexit
, prog_name
,
386 SCM
scwm_safe_load (char *filename
)
388 return safe_load(scm_makfrom0str(filename
));
391 SCM
scwm_safe_eval_str (char *string
)
393 SCM_STACKITEM stack_item
;
394 return scm_internal_cwdr(scwm_body_eval_str
, string
,
395 scm_handle_by_message_noexit
, prog_name
,
399 void init_scwm_guile()
401 run_hook_proc
= gh_lookup("run-hook");
403 #ifndef SCM_MAGIC_SNARF_INITS
404 #include "scwm_guile.x"
409 /* Local Variables: */
411 /* c-basic-offset: 2 */