Fix bytevector-fill! to accept fill arguments greater than 127.
[bpt/guile.git] / libguile / throw.c
CommitLineData
4a655e50 1/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2003, 2004, 2006, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
0f2d19dd 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.
0f2d19dd 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.
0f2d19dd 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 */
1bbd0b84 18
1bbd0b84 19
0f2d19dd 20\f
dbb605f5
LC
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
0f2d19dd
JB
24
25#include <stdio.h>
27646f41 26#include <unistdio.h>
a0599745
MD
27#include "libguile/_scm.h"
28#include "libguile/smob.h"
a0599745
MD
29#include "libguile/eval.h"
30#include "libguile/eq.h"
416f26c7 31#include "libguile/control.h"
e10cf6b9 32#include "libguile/deprecation.h"
a0599745 33#include "libguile/backtrace.h"
a0599745 34#include "libguile/debug.h"
a0599745
MD
35#include "libguile/stackchk.h"
36#include "libguile/stacks.h"
37#include "libguile/fluids.h"
38#include "libguile/ports.h"
a0599745 39#include "libguile/validate.h"
416f26c7 40#include "libguile/vm.h"
a0599745 41#include "libguile/throw.h"
9de87eea 42#include "libguile/init.h"
a2c40dc7 43#include "libguile/strings.h"
0f2d19dd 44
22fc179a
HWN
45#include "libguile/private-options.h"
46
47
416f26c7
AW
48/* Pleasantly enough, the guts of catch are defined in Scheme, in terms of
49 prompt, abort, and the %exception-handler fluid. This file just provides
50 shims so that it's easy to have catch functionality from C.
0f2d19dd 51
416f26c7
AW
52 All of these function names and prototypes carry a fair bit of historical
53 baggage. */
c209c88e 54
0f2d19dd 55
416f26c7
AW
56\f
57
60617d81
MW
58static SCM catch_var, throw_var, with_throw_handler_var;
59
416f26c7
AW
60SCM
61scm_catch (SCM key, SCM thunk, SCM handler)
0f2d19dd 62{
60617d81 63 return scm_call_3 (scm_variable_ref (catch_var), key, thunk, handler);
0f2d19dd
JB
64}
65
416f26c7
AW
66SCM
67scm_catch_with_pre_unwind_handler (SCM key, SCM thunk, SCM handler,
68 SCM pre_unwind_handler)
0f2d19dd 69{
416f26c7
AW
70 if (SCM_UNBNDP (pre_unwind_handler))
71 return scm_catch (key, thunk, handler);
72 else
60617d81
MW
73 return scm_call_4 (scm_variable_ref (catch_var), key, thunk, handler,
74 pre_unwind_handler);
75}
76
77static void
78init_with_throw_handler_var (void)
79{
80 with_throw_handler_var
81 = scm_module_variable (scm_the_root_module (),
82 scm_from_latin1_symbol ("with-throw-handler"));
0f2d19dd
JB
83}
84
416f26c7
AW
85SCM
86scm_with_throw_handler (SCM key, SCM thunk, SCM handler)
87{
60617d81
MW
88 static scm_i_pthread_once_t once = SCM_I_PTHREAD_ONCE_INIT;
89 scm_i_pthread_once (&once, init_with_throw_handler_var);
416f26c7 90
60617d81
MW
91 return scm_call_3 (scm_variable_ref (with_throw_handler_var),
92 key, thunk, handler);
416f26c7 93}
74229f75 94
416f26c7
AW
95SCM
96scm_throw (SCM key, SCM args)
0f2d19dd 97{
60617d81 98 return scm_apply_1 (scm_variable_ref (throw_var), key, args);
416f26c7
AW
99}
100
101\f
0f2d19dd 102
416f26c7 103/* Now some support for C bodies and catch handlers */
650fa1ab 104
416f26c7 105static scm_t_bits tc16_catch_closure;
43e01b1e 106
416f26c7
AW
107enum {
108 CATCH_CLOSURE_BODY,
109 CATCH_CLOSURE_HANDLER
43e01b1e
NJ
110};
111
416f26c7
AW
112static SCM
113make_catch_body_closure (scm_t_catch_body body, void *body_data)
114{
115 SCM ret;
116 SCM_NEWSMOB2 (ret, tc16_catch_closure, body, body_data);
117 SCM_SET_SMOB_FLAGS (ret, CATCH_CLOSURE_BODY);
118 return ret;
119}
120
121static SCM
122make_catch_handler_closure (scm_t_catch_handler handler, void *handler_data)
123{
124 SCM ret;
125 SCM_NEWSMOB2 (ret, tc16_catch_closure, handler, handler_data);
126 SCM_SET_SMOB_FLAGS (ret, CATCH_CLOSURE_HANDLER);
127 return ret;
128}
43e01b1e 129
416f26c7
AW
130static SCM
131apply_catch_closure (SCM clo, SCM args)
132{
133 void *data = (void*)SCM_SMOB_DATA_2 (clo);
650fa1ab 134
416f26c7
AW
135 switch (SCM_SMOB_FLAGS (clo))
136 {
137 case CATCH_CLOSURE_BODY:
138 {
139 scm_t_catch_body body = (void*)SCM_SMOB_DATA (clo);
140 return body (data);
141 }
142 case CATCH_CLOSURE_HANDLER:
143 {
144 scm_t_catch_handler handler = (void*)SCM_SMOB_DATA (clo);
145 return handler (data, scm_car (args), scm_cdr (args));
146 }
147 default:
148 abort ();
149 }
150}
650fa1ab 151
416f26c7 152/* TAG is the catch tag. Typically, this is a symbol, but this
650fa1ab
JB
153 function doesn't actually care about that.
154
155 BODY is a pointer to a C function which runs the body of the catch;
156 this is the code you can throw from. We call it like this:
19b27fa2 157 BODY (BODY_DATA)
650fa1ab 158 where:
816a6f06
JB
159 BODY_DATA is just the BODY_DATA argument we received; we pass it
160 through to BODY as its first argument. The caller can make
161 BODY_DATA point to anything useful that BODY might need.
650fa1ab
JB
162
163 HANDLER is a pointer to a C function to deal with a throw to TAG,
164 should one occur. We call it like this:
86327304 165 HANDLER (HANDLER_DATA, THROWN_TAG, THROW_ARGS)
650fa1ab 166 where
816a6f06
JB
167 HANDLER_DATA is the HANDLER_DATA argument we recevied; it's the
168 same idea as BODY_DATA above.
86327304
JB
169 THROWN_TAG is the tag that the user threw to; usually this is
170 TAG, but it could be something else if TAG was #t (i.e., a
171 catch-all), or the user threw to a jmpbuf.
650fa1ab 172 THROW_ARGS is the list of arguments the user passed to the THROW
4dd8323f 173 function, after the tag.
650fa1ab 174
3eed3475
JB
175 BODY_DATA is just a pointer we pass through to BODY. HANDLER_DATA
176 is just a pointer we pass through to HANDLER. We don't actually
177 use either of those pointers otherwise ourselves. The idea is
178 that, if our caller wants to communicate something to BODY or
179 HANDLER, it can pass a pointer to it as MUMBLE_DATA, which BODY and
180 HANDLER can then use. Think of it as a way to make BODY and
181 HANDLER closures, not just functions; MUMBLE_DATA points to the
182 enclosed variables.
183
184 Of course, it's up to the caller to make sure that any data a
185 MUMBLE_DATA needs is protected from GC. A common way to do this is
186 to make MUMBLE_DATA a pointer to data stored in an automatic
187 structure variable; since the collector must scan the stack for
188 references anyway, this assures that any references in MUMBLE_DATA
189 will be found. */
650fa1ab 190
0f2d19dd 191SCM
43e01b1e
NJ
192scm_c_catch (SCM tag,
193 scm_t_catch_body body, void *body_data,
194 scm_t_catch_handler handler, void *handler_data,
195 scm_t_catch_handler pre_unwind_handler, void *pre_unwind_handler_data)
0f2d19dd 196{
416f26c7
AW
197 SCM sbody, shandler, spre_unwind_handler;
198
199 sbody = make_catch_body_closure (body, body_data);
200 shandler = make_catch_handler_closure (handler, handler_data);
201 if (pre_unwind_handler)
202 spre_unwind_handler = make_catch_handler_closure (pre_unwind_handler,
203 pre_unwind_handler_data);
0f2d19dd 204 else
416f26c7
AW
205 spre_unwind_handler = SCM_UNDEFINED;
206
207 return scm_catch_with_pre_unwind_handler (tag, sbody, shandler,
208 spre_unwind_handler);
0f2d19dd
JB
209}
210
43e01b1e
NJ
211SCM
212scm_internal_catch (SCM tag,
213 scm_t_catch_body body, void *body_data,
214 scm_t_catch_handler handler, void *handler_data)
215{
416f26c7
AW
216 return scm_c_catch (tag,
217 body, body_data,
218 handler, handler_data,
219 NULL, NULL);
18eadcbe
JB
220}
221
18eadcbe 222
18eadcbe 223SCM
43e01b1e
NJ
224scm_c_with_throw_handler (SCM tag,
225 scm_t_catch_body body,
226 void *body_data,
227 scm_t_catch_handler handler,
228 void *handler_data,
229 int lazy_catch_p)
18eadcbe 230{
416f26c7 231 SCM sbody, shandler;
18eadcbe 232
e10cf6b9
AW
233 if (lazy_catch_p)
234 scm_c_issue_deprecation_warning
235 ("The LAZY_CATCH_P argument to `scm_c_with_throw_handler' is no longer.\n"
236 "supported. Instead the handler will be invoked from within the dynamic\n"
237 "context of the corresponding `throw'.\n"
238 "\nTHIS COULD CHANGE YOUR PROGRAM'S BEHAVIOR.\n\n"
239 "Please modify your program to pass 0 as the LAZY_CATCH_P argument,\n"
240 "and adapt it (if necessary) to expect to be within the dynamic context\n"
241 "of the throw.");
242
416f26c7
AW
243 sbody = make_catch_body_closure (body, body_data);
244 shandler = make_catch_handler_closure (handler, handler_data);
245
246 return scm_with_throw_handler (tag, sbody, shandler);
18eadcbe
JB
247}
248
95384717 249\f
95384717 250/* body and handler functions for use with any of the above catch variants */
18eadcbe 251
816a6f06 252/* This is a body function you can pass to scm_internal_catch if you
492960a4 253 want the body to be like Scheme's `catch' --- a thunk.
650fa1ab 254
74229f75
JB
255 BODY_DATA is a pointer to a scm_body_thunk_data structure, which
256 contains the Scheme procedure to invoke as the body, and the tag
492960a4 257 we're catching. */
650fa1ab 258
816a6f06 259SCM
6e8d25a6 260scm_body_thunk (void *body_data)
650fa1ab 261{
816a6f06 262 struct scm_body_thunk_data *c = (struct scm_body_thunk_data *) body_data;
650fa1ab 263
fdc28395 264 return scm_call_0 (c->body_proc);
650fa1ab
JB
265}
266
267
74229f75 268/* This is a handler function you can pass to scm_internal_catch if
4dd8323f
JB
269 you want the handler to act like Scheme's catch: (throw TAG ARGS ...)
270 applies a handler procedure to (TAG ARGS ...).
74229f75
JB
271
272 If the user does a throw to this catch, this function runs a
816a6f06
JB
273 handler procedure written in Scheme. HANDLER_DATA is a pointer to
274 an SCM variable holding the Scheme procedure object to invoke. It
74229f75
JB
275 ought to be a pointer to an automatic variable (i.e., one living on
276 the stack), or the procedure object should be otherwise protected
277 from GC. */
816a6f06 278SCM
6e8d25a6 279scm_handle_by_proc (void *handler_data, SCM tag, SCM throw_args)
650fa1ab 280{
816a6f06 281 SCM *handler_proc_p = (SCM *) handler_data;
650fa1ab 282
fdc28395 283 return scm_apply_1 (*handler_proc_p, tag, throw_args);
650fa1ab
JB
284}
285
1345df5d
MV
286/* SCM_HANDLE_BY_PROC_CATCHING_ALL is like SCM_HANDLE_BY_PROC but
287 catches all throws that the handler might emit itself. The handler
288 used for these `secondary' throws is SCM_HANDLE_BY_MESSAGE_NO_EXIT. */
289
290struct hbpca_data {
291 SCM proc;
292 SCM args;
293};
294
295static SCM
6e8d25a6 296hbpca_body (void *body_data)
1345df5d
MV
297{
298 struct hbpca_data *data = (struct hbpca_data *)body_data;
fdc28395 299 return scm_apply_0 (data->proc, data->args);
1345df5d
MV
300}
301
302SCM
6e8d25a6 303scm_handle_by_proc_catching_all (void *handler_data, SCM tag, SCM throw_args)
1345df5d
MV
304{
305 SCM *handler_proc_p = (SCM *) handler_data;
306 struct hbpca_data data;
307 data.proc = *handler_proc_p;
308 data.args = scm_cons (tag, throw_args);
309
310 return scm_internal_catch (SCM_BOOL_T,
311 hbpca_body, &data,
312 scm_handle_by_message_noexit, NULL);
313}
650fa1ab 314
f032b8a8
JB
315/* Derive the an exit status from the arguments to (quit ...). */
316int
6e8d25a6 317scm_exit_status (SCM args)
f032b8a8 318{
c96d76b8 319 if (!SCM_NULL_OR_NIL_P (args))
f032b8a8
JB
320 {
321 SCM cqa = SCM_CAR (args);
322
e11e83f3
MV
323 if (scm_is_integer (cqa))
324 return (scm_to_int (cqa));
7888309b 325 else if (scm_is_false (cqa))
f032b8a8
JB
326 return 1;
327 }
328 return 0;
329}
330
74229f75 331
e0c70a8b
AW
332static int
333should_print_backtrace (SCM tag, SCM stack)
334{
335 return SCM_BACKTRACE_P
336 && scm_is_true (stack)
337 && scm_initialized_p
338 /* It's generally not useful to print backtraces for errors reading
339 or expanding code in these fallback catch statements. */
340 && !scm_is_eq (tag, scm_from_latin1_symbol ("read-error"))
341 && !scm_is_eq (tag, scm_from_latin1_symbol ("syntax-error"));
342}
343
f032b8a8
JB
344static void
345handler_message (void *handler_data, SCM tag, SCM args)
e68b42c1 346{
e0c70a8b 347 SCM p, stack, frame;
650fa1ab 348
e0c70a8b 349 p = scm_current_error_port ();
39d41afe
AW
350 /* Usually we get here via a throw to a catch-all. In that case
351 there is the throw frame active, and the catch closure, so narrow by
352 two frames. It is possible for a user to invoke
353 scm_handle_by_message directly, though, so it could be this
354 narrows too much. We'll have to see how this works out in
355 practice. */
356 stack = scm_make_stack (SCM_BOOL_T, scm_list_1 (scm_from_int (2)));
e0c70a8b 357 frame = scm_is_true (stack) ? scm_stack_ref (stack, SCM_INUM0) : SCM_BOOL_F;
eeb48bc2 358
e0c70a8b 359 if (should_print_backtrace (tag, stack))
74229f75 360 {
e0c70a8b
AW
361 scm_puts ("Backtrace:\n", p);
362 scm_display_backtrace_with_highlights (stack, p,
363 SCM_BOOL_F, SCM_BOOL_F,
364 SCM_EOL);
365 scm_newline (p);
74229f75 366 }
f64056d1 367
e0c70a8b 368 scm_print_exception (p, frame, tag, args);
f032b8a8
JB
369}
370
371
372/* This is a handler function to use if you want scheme to print a
373 message and die. Useful for dealing with throws to uncaught keys
374 at the top level.
375
376 At boot time, we establish a catch-all that uses this as its handler.
377 1) If the user wants something different, they can use (catch #t
378 ...) to do what they like.
379 2) Outside the context of a read-eval-print loop, there isn't
380 anything else good to do; libguile should not assume the existence
381 of a read-eval-print loop.
382 3) Given that we shouldn't do anything complex, it's much more
383 robust to do it in C code.
384
385 HANDLER_DATA, if non-zero, is assumed to be a char * pointing to a
386 message header to print; if zero, we use "guile" instead. That
387 text is followed by a colon, then the message described by ARGS. */
388
5a2a5407
DH
389/* Dirk:FIXME:: The name of the function should make clear that the
390 * application gets terminated.
391 */
392
f032b8a8 393SCM
6e8d25a6 394scm_handle_by_message (void *handler_data, SCM tag, SCM args)
f032b8a8 395{
4a655e50 396 if (scm_is_true (scm_eq_p (tag, scm_from_latin1_symbol ("quit"))))
9de87eea 397 exit (scm_exit_status (args));
f032b8a8
JB
398
399 handler_message (handler_data, tag, args);
9de87eea 400 scm_i_pthread_exit (NULL);
23f2b9a3
KR
401
402 /* this point not reached, but suppress gcc warning about no return value
403 in case scm_i_pthread_exit isn't marked as "noreturn" (which seemed not
404 to be the case on cygwin for instance) */
405 return SCM_BOOL_F;
74229f75
JB
406}
407
408
f032b8a8
JB
409/* This is just like scm_handle_by_message, but it doesn't exit; it
410 just returns #f. It's useful in cases where you don't really know
411 enough about the body to handle things in a better way, but don't
412 want to let throws fall off the bottom of the wind list. */
413SCM
6e8d25a6 414scm_handle_by_message_noexit (void *handler_data, SCM tag, SCM args)
74229f75 415{
4a655e50 416 if (scm_is_true (scm_eq_p (tag, scm_from_latin1_symbol ("quit"))))
9de87eea
MV
417 exit (scm_exit_status (args));
418
f032b8a8
JB
419 handler_message (handler_data, tag, args);
420
421 return SCM_BOOL_F;
e68b42c1
MD
422}
423
3eed3475 424
e158e4f4 425SCM
e81d98ec 426scm_handle_by_throw (void *handler_data SCM_UNUSED, SCM tag, SCM args)
e158e4f4
MD
427{
428 scm_ithrow (tag, args, 1);
429 return SCM_UNSPECIFIED; /* never returns */
430}
431
43e01b1e 432SCM
36c40440 433scm_ithrow (SCM key, SCM args, int no_return SCM_UNUSED)
ad310508 434{
416f26c7 435 return scm_throw (key, args);
ad310508
MD
436}
437
416f26c7
AW
438/* Unfortunately we have to support catch and throw before boot-9 has, um,
439 booted. So here are lame versions, which will get replaced with their scheme
440 equivalents. */
c6a32a2c
AW
441
442SCM_SYMBOL (sym_pre_init_catch_tag, "%pre-init-catch-tag");
443
416f26c7
AW
444static SCM
445pre_init_catch (SCM tag, SCM thunk, SCM handler, SCM pre_unwind_handler)
0f2d19dd 446{
416f26c7 447 SCM vm, prompt, res;
492960a4 448
416f26c7
AW
449 /* Only handle catch-alls without pre-unwind handlers */
450 if (!SCM_UNBNDP (pre_unwind_handler))
451 abort ();
452 if (scm_is_false (scm_eqv_p (tag, SCM_BOOL_T)))
d6580119 453 abort ();
43e01b1e 454
416f26c7 455 vm = scm_the_vm ();
c6a32a2c 456 prompt = scm_c_make_prompt (sym_pre_init_catch_tag,
416f26c7 457 SCM_VM_DATA (vm)->fp, SCM_VM_DATA (vm)->sp,
adbdfd6d
AW
458 SCM_VM_DATA (vm)->ip, 1, -1, scm_i_dynwinds ());
459 scm_i_set_dynwinds (scm_cons (prompt, SCM_PROMPT_DYNWINDS (prompt)));
43e01b1e 460
416f26c7
AW
461 if (SCM_PROMPT_SETJMP (prompt))
462 {
463 /* nonlocal exit */
572eef50 464 SCM args = scm_i_prompt_pop_abort_args_x (vm);
416f26c7
AW
465 /* cdr past the continuation */
466 return scm_apply_0 (handler, scm_cdr (args));
11702758 467 }
3eed3475 468
416f26c7
AW
469 res = scm_call_0 (thunk);
470 scm_i_set_dynwinds (scm_cdr (scm_i_dynwinds ()));
346e4402 471
416f26c7 472 return res;
0f2d19dd
JB
473}
474
5a588521
AW
475static int
476find_pre_init_catch (void)
477{
478 SCM winds;
479
480 /* Search the wind list for an appropriate prompt.
481 "Waiter, please bring us the wind list." */
482 for (winds = scm_i_dynwinds (); scm_is_pair (winds); winds = SCM_CDR (winds))
483 if (SCM_PROMPT_P (SCM_CAR (winds))
484 && scm_is_eq (SCM_PROMPT_TAG (SCM_CAR (winds)), sym_pre_init_catch_tag))
485 return 1;
486
487 return 0;
488}
489
416f26c7 490static SCM
5a588521 491pre_init_throw (SCM k, SCM args)
416f26c7 492{
5a588521
AW
493 if (find_pre_init_catch ())
494 return scm_at_abort (sym_pre_init_catch_tag, scm_cons (k, args));
495 else
496 {
cd4f274c
AW
497 static int error_printing_error = 0;
498 static int error_printing_fallback = 0;
499
500 if (error_printing_fallback)
501 fprintf (stderr, "\nFailed to print exception.\n");
502 else if (error_printing_error)
503 {
504 fprintf (stderr, "\nError while printing exception:\n");
505 error_printing_fallback = 1;
506 fprintf (stderr, "Key: ");
507 scm_write (k, scm_current_error_port ());
508 fprintf (stderr, ", args: ");
509 scm_write (args, scm_current_error_port ());
510 scm_newline (scm_current_error_port ());
511 }
512 else
513 {
514 fprintf (stderr, "Throw without catch before boot:\n");
515 error_printing_error = 1;
516 scm_handle_by_message_noexit (NULL, k, args);
517 }
518
e7450642
AW
519 fprintf (stderr, "Aborting.\n");
520 abort ();
5a588521
AW
521 return SCM_BOOL_F; /* not reached */
522 }
416f26c7 523}
0f2d19dd 524
0f2d19dd
JB
525void
526scm_init_throw ()
0f2d19dd 527{
416f26c7
AW
528 tc16_catch_closure = scm_make_smob_type ("catch-closure", 0);
529 scm_set_smob_apply (tc16_catch_closure, apply_catch_closure, 0, 0, 1);
e841c3e0 530
60617d81
MW
531 catch_var = scm_c_define ("catch", scm_c_make_gsubr ("catch", 3, 1, 0,
532 pre_init_catch));
533 throw_var = scm_c_define ("throw", scm_c_make_gsubr ("throw", 1, 0, 1,
534 pre_init_throw));
e841c3e0 535
a0599745 536#include "libguile/throw.x"
0f2d19dd 537}
89e00824
ML
538
539/*
540 Local Variables:
541 c-file-style: "gnu"
542 End:
543*/