Greg's smob patch
[bpt/guile.git] / libguile / throw.c
1 /* Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41 \f
42
43 #include <stdio.h>
44 #include "_scm.h"
45 #include "genio.h"
46 #include "smob.h"
47 #include "alist.h"
48 #include "eval.h"
49 #include "eq.h"
50 #include "dynwind.h"
51 #include "backtrace.h"
52 #ifdef DEBUG_EXTENSIONS
53 #include "debug.h"
54 #endif
55 #include "continuations.h"
56 #include "stackchk.h"
57 #include "stacks.h"
58 #include "fluids.h"
59
60 #include "throw.h"
61
62 \f
63 /* the jump buffer data structure */
64 static int scm_tc16_jmpbuffer;
65
66 #define SCM_JMPBUFP(O) (SCM_TYP16(O) == scm_tc16_jmpbuffer)
67 #define JBACTIVE(O) (SCM_CAR (O) & (1L << 16L))
68 #define ACTIVATEJB(O) (SCM_SETOR_CAR (O, (1L << 16L)))
69 #define DEACTIVATEJB(O) (SCM_SETAND_CAR (O, ~(1L << 16L)))
70
71 #ifndef DEBUG_EXTENSIONS
72 #define JBJMPBUF(O) ((jmp_buf*)SCM_CDR (O) )
73 #define SETJBJMPBUF SCM_SETCDR
74 #else
75 #define SCM_JBDFRAME(O) ((scm_debug_frame*)SCM_CAR (SCM_CDR (O)) )
76 #define JBJMPBUF(O) ((jmp_buf*)SCM_CDR (SCM_CDR (O)) )
77 #define SCM_SETJBDFRAME(O,X) SCM_SETCAR (SCM_CDR (O), (SCM)(X))
78 #define SETJBJMPBUF(O,X) SCM_SETCDR(SCM_CDR (O), X)
79
80 static scm_sizet freejb SCM_P ((SCM jbsmob));
81
82 static scm_sizet
83 freejb (jbsmob)
84 SCM jbsmob;
85 {
86 scm_must_free ((char *) SCM_CDR (jbsmob));
87 return sizeof (scm_cell);
88 }
89 #endif
90
91 static int printjb SCM_P ((SCM exp, SCM port, scm_print_state *pstate));
92 static int
93 printjb (exp, port, pstate)
94 SCM exp;
95 SCM port;
96 scm_print_state *pstate;
97 {
98 scm_puts ("#<jmpbuffer ", port);
99 scm_puts (JBACTIVE(exp) ? "(active) " : "(inactive) ", port);
100 scm_intprint((SCM) JBJMPBUF(exp), 16, port);
101 scm_putc ('>', port);
102 return 1 ;
103 }
104
105
106 static SCM make_jmpbuf SCM_P ((void));
107 static SCM
108 make_jmpbuf ()
109 {
110 SCM answer;
111 SCM_REDEFER_INTS;
112 {
113 #ifdef DEBUG_EXTENSIONS
114 char *mem = scm_must_malloc (sizeof (scm_cell), "jb");
115 #endif
116 #ifdef DEBUG_EXTENSIONS
117 SCM_NEWSMOB (answer, scm_tc16_jmpbuffer, mem);
118 #else
119 SCM_NEWSMOB (answer, scm_tc16_jmpbuffer, 0);
120 #endif
121 SETJBJMPBUF(answer, (jmp_buf *)0);
122 DEACTIVATEJB(answer);
123 }
124 SCM_REALLOW_INTS;
125 return answer;
126 }
127
128 \f
129 /* scm_internal_catch (the guts of catch) */
130
131 struct jmp_buf_and_retval /* use only on the stack, in scm_catch */
132 {
133 jmp_buf buf; /* must be first */
134 SCM throw_tag;
135 SCM retval;
136 };
137
138
139 /* scm_internal_catch is the guts of catch. It handles all the
140 mechanics of setting up a catch target, invoking the catch body,
141 and perhaps invoking the handler if the body does a throw.
142
143 The function is designed to be usable from C code, but is general
144 enough to implement all the semantics Guile Scheme expects from
145 throw.
146
147 TAG is the catch tag. Typically, this is a symbol, but this
148 function doesn't actually care about that.
149
150 BODY is a pointer to a C function which runs the body of the catch;
151 this is the code you can throw from. We call it like this:
152 BODY (BODY_DATA, JMPBUF)
153 where:
154 BODY_DATA is just the BODY_DATA argument we received; we pass it
155 through to BODY as its first argument. The caller can make
156 BODY_DATA point to anything useful that BODY might need.
157 JMPBUF is the Scheme jmpbuf object corresponding to this catch,
158 which we have just created and initialized.
159
160 HANDLER is a pointer to a C function to deal with a throw to TAG,
161 should one occur. We call it like this:
162 HANDLER (HANDLER_DATA, THROWN_TAG, THROW_ARGS)
163 where
164 HANDLER_DATA is the HANDLER_DATA argument we recevied; it's the
165 same idea as BODY_DATA above.
166 THROWN_TAG is the tag that the user threw to; usually this is
167 TAG, but it could be something else if TAG was #t (i.e., a
168 catch-all), or the user threw to a jmpbuf.
169 THROW_ARGS is the list of arguments the user passed to the THROW
170 function, after the tag.
171
172 BODY_DATA is just a pointer we pass through to BODY. HANDLER_DATA
173 is just a pointer we pass through to HANDLER. We don't actually
174 use either of those pointers otherwise ourselves. The idea is
175 that, if our caller wants to communicate something to BODY or
176 HANDLER, it can pass a pointer to it as MUMBLE_DATA, which BODY and
177 HANDLER can then use. Think of it as a way to make BODY and
178 HANDLER closures, not just functions; MUMBLE_DATA points to the
179 enclosed variables.
180
181 Of course, it's up to the caller to make sure that any data a
182 MUMBLE_DATA needs is protected from GC. A common way to do this is
183 to make MUMBLE_DATA a pointer to data stored in an automatic
184 structure variable; since the collector must scan the stack for
185 references anyway, this assures that any references in MUMBLE_DATA
186 will be found. */
187
188 SCM
189 scm_internal_catch (tag, body, body_data, handler, handler_data)
190 SCM tag;
191 scm_catch_body_t body;
192 void *body_data;
193 scm_catch_handler_t handler;
194 void *handler_data;
195 {
196 struct jmp_buf_and_retval jbr;
197 SCM jmpbuf;
198 SCM answer;
199
200 jmpbuf = make_jmpbuf ();
201 answer = SCM_EOL;
202 scm_dynwinds = scm_acons (tag, jmpbuf, scm_dynwinds);
203 SETJBJMPBUF(jmpbuf, &jbr.buf);
204 #ifdef DEBUG_EXTENSIONS
205 SCM_SETJBDFRAME(jmpbuf, scm_last_debug_frame);
206 #endif
207 if (setjmp (jbr.buf))
208 {
209 SCM throw_tag;
210 SCM throw_args;
211
212 #ifdef STACK_CHECKING
213 scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
214 #endif
215 SCM_REDEFER_INTS;
216 DEACTIVATEJB (jmpbuf);
217 scm_dynwinds = SCM_CDR (scm_dynwinds);
218 SCM_REALLOW_INTS;
219 throw_args = jbr.retval;
220 throw_tag = jbr.throw_tag;
221 jbr.throw_tag = SCM_EOL;
222 jbr.retval = SCM_EOL;
223 answer = handler (handler_data, throw_tag, throw_args);
224 }
225 else
226 {
227 ACTIVATEJB (jmpbuf);
228 answer = body (body_data);
229 SCM_REDEFER_INTS;
230 DEACTIVATEJB (jmpbuf);
231 scm_dynwinds = SCM_CDR (scm_dynwinds);
232 SCM_REALLOW_INTS;
233 }
234 return answer;
235 }
236
237
238 \f
239 /* scm_internal_lazy_catch (the guts of lazy catching) */
240
241 /* The smob tag for lazy_catch smobs. */
242 static long tc16_lazy_catch;
243
244 /* This is the structure we put on the wind list for a lazy catch. It
245 stores the handler function to call, and the data pointer to pass
246 through to it. It's not a Scheme closure, but it is a function
247 with data, so the term "closure" is appropriate in its broader
248 sense.
249
250 (We don't need anything like this in the "eager" catch code,
251 because the same C frame runs both the body and the handler.) */
252 struct lazy_catch {
253 scm_catch_handler_t handler;
254 void *handler_data;
255 };
256
257 /* Strictly speaking, we could just pass a zero for our print
258 function, because we don't need to print them. They should never
259 appear in normal data structures, only in the wind list. However,
260 it might be nice for debugging someday... */
261 static int
262 print_lazy_catch (SCM closure, SCM port, scm_print_state *pstate)
263 {
264 struct lazy_catch *c = (struct lazy_catch *) SCM_CDR (closure);
265 char buf[200];
266
267 sprintf (buf, "#<lazy-catch 0x%lx 0x%lx>",
268 (long) c->handler, (long) c->handler_data);
269 scm_puts (buf, port);
270
271 return 1;
272 }
273
274
275 /* Given a pointer to a lazy catch structure, return a smob for it,
276 suitable for inclusion in the wind list. ("Ah yes, a Château
277 Gollombiere '72, non?"). */
278 static SCM
279 make_lazy_catch (struct lazy_catch *c)
280 {
281 SCM_RETURN_NEWSMOB (tc16_lazy_catch, c);
282 }
283
284 #define SCM_LAZY_CATCH_P(obj) \
285 (SCM_NIMP (obj) && (SCM_CAR (obj) == tc16_lazy_catch))
286
287
288 /* Exactly like scm_internal_catch, except:
289 - It does not unwind the stack (this is the major difference).
290 - If handler returns, its value is returned from the throw. */
291 SCM
292 scm_internal_lazy_catch (tag, body, body_data, handler, handler_data)
293 SCM tag;
294 scm_catch_body_t body;
295 void *body_data;
296 scm_catch_handler_t handler;
297 void *handler_data;
298 {
299 SCM lazy_catch, answer;
300 struct lazy_catch c;
301
302 c.handler = handler;
303 c.handler_data = handler_data;
304 lazy_catch = make_lazy_catch (&c);
305
306 SCM_REDEFER_INTS;
307 scm_dynwinds = scm_acons (tag, lazy_catch, scm_dynwinds);
308 SCM_REALLOW_INTS;
309
310 answer = (*body) (body_data);
311
312 SCM_REDEFER_INTS;
313 scm_dynwinds = SCM_CDR (scm_dynwinds);
314 SCM_REALLOW_INTS;
315
316 return answer;
317 }
318
319 \f
320 /* scm_internal_stack_catch
321 Use this one if you want debugging information to be stored in
322 scm_the_last_stack_fluid on error. */
323
324 static SCM
325 ss_handler (void *data, SCM tag, SCM throw_args)
326 {
327 /* Save the stack */
328 scm_fluid_set_x (SCM_CDR (scm_the_last_stack_fluid),
329 scm_make_stack (scm_cons (SCM_BOOL_T, SCM_EOL)));
330 /* Throw the error */
331 return scm_throw (tag, throw_args);
332 }
333
334 struct cwss_data
335 {
336 SCM tag;
337 scm_catch_body_t body;
338 void *data;
339 };
340
341 static SCM
342 cwss_body (void *data)
343 {
344 struct cwss_data *d = data;
345 return scm_internal_lazy_catch (d->tag, d->body, d->data, ss_handler, NULL);
346 }
347
348 SCM
349 scm_internal_stack_catch (SCM tag,
350 scm_catch_body_t body,
351 void *body_data,
352 scm_catch_handler_t handler,
353 void *handler_data)
354 {
355 struct cwss_data d;
356 d.tag = tag;
357 d.body = body;
358 d.data = body_data;
359 return scm_internal_catch (tag, cwss_body, &d, handler, handler_data);
360 }
361
362
363 \f
364 /* body and handler functions for use with any of the above catch variants */
365
366 /* This is a body function you can pass to scm_internal_catch if you
367 want the body to be like Scheme's `catch' --- a thunk.
368
369 BODY_DATA is a pointer to a scm_body_thunk_data structure, which
370 contains the Scheme procedure to invoke as the body, and the tag
371 we're catching. */
372
373 SCM
374 scm_body_thunk (body_data)
375 void *body_data;
376 {
377 struct scm_body_thunk_data *c = (struct scm_body_thunk_data *) body_data;
378
379 return scm_apply (c->body_proc, SCM_EOL, SCM_EOL);
380 }
381
382
383 /* This is a handler function you can pass to scm_internal_catch if
384 you want the handler to act like Scheme's catch: (throw TAG ARGS ...)
385 applies a handler procedure to (TAG ARGS ...).
386
387 If the user does a throw to this catch, this function runs a
388 handler procedure written in Scheme. HANDLER_DATA is a pointer to
389 an SCM variable holding the Scheme procedure object to invoke. It
390 ought to be a pointer to an automatic variable (i.e., one living on
391 the stack), or the procedure object should be otherwise protected
392 from GC. */
393 SCM
394 scm_handle_by_proc (handler_data, tag, throw_args)
395 void *handler_data;
396 SCM tag;
397 SCM throw_args;
398 {
399 SCM *handler_proc_p = (SCM *) handler_data;
400
401 return scm_apply (*handler_proc_p, scm_cons (tag, throw_args), SCM_EOL);
402 }
403
404 /* SCM_HANDLE_BY_PROC_CATCHING_ALL is like SCM_HANDLE_BY_PROC but
405 catches all throws that the handler might emit itself. The handler
406 used for these `secondary' throws is SCM_HANDLE_BY_MESSAGE_NO_EXIT. */
407
408 struct hbpca_data {
409 SCM proc;
410 SCM args;
411 };
412
413 static SCM
414 hbpca_body (body_data)
415 void *body_data;
416 {
417 struct hbpca_data *data = (struct hbpca_data *)body_data;
418 return scm_apply (data->proc, data->args, SCM_EOL);
419 }
420
421 SCM
422 scm_handle_by_proc_catching_all (handler_data, tag, throw_args)
423 void *handler_data;
424 SCM tag;
425 SCM throw_args;
426 {
427 SCM *handler_proc_p = (SCM *) handler_data;
428 struct hbpca_data data;
429 data.proc = *handler_proc_p;
430 data.args = scm_cons (tag, throw_args);
431
432 return scm_internal_catch (SCM_BOOL_T,
433 hbpca_body, &data,
434 scm_handle_by_message_noexit, NULL);
435 }
436
437 /* Derive the an exit status from the arguments to (quit ...). */
438 int
439 scm_exit_status (args)
440 SCM args;
441 {
442 if (SCM_NNULLP (args))
443 {
444 SCM cqa = SCM_CAR (args);
445
446 if (SCM_INUMP (cqa))
447 return (SCM_INUM (cqa));
448 else if (SCM_FALSEP (cqa))
449 return 1;
450 }
451 return 0;
452 }
453
454
455 static void
456 handler_message (void *handler_data, SCM tag, SCM args)
457 {
458 char *prog_name = (char *) handler_data;
459 SCM p = scm_cur_errp;
460
461 if (scm_ilength (args) >= 3)
462 {
463 SCM stack = scm_make_stack (SCM_LIST1 (SCM_BOOL_T));
464 SCM subr = SCM_CAR (args);
465 SCM message = SCM_CADR (args);
466 SCM parts = SCM_CADDR (args);
467 SCM rest = SCM_CDDDR (args);
468
469 scm_display_error (stack, p, subr, message, parts, rest);
470 }
471 else
472 {
473 if (! prog_name)
474 prog_name = "guile";
475
476 scm_puts (prog_name, p);
477 scm_puts (": ", p);
478
479 scm_puts ("uncaught throw to ", p);
480 scm_prin1 (tag, p, 0);
481 scm_puts (": ", p);
482 scm_prin1 (args, p, 1);
483 scm_putc ('\n', p);
484 }
485 }
486
487
488 /* This is a handler function to use if you want scheme to print a
489 message and die. Useful for dealing with throws to uncaught keys
490 at the top level.
491
492 At boot time, we establish a catch-all that uses this as its handler.
493 1) If the user wants something different, they can use (catch #t
494 ...) to do what they like.
495 2) Outside the context of a read-eval-print loop, there isn't
496 anything else good to do; libguile should not assume the existence
497 of a read-eval-print loop.
498 3) Given that we shouldn't do anything complex, it's much more
499 robust to do it in C code.
500
501 HANDLER_DATA, if non-zero, is assumed to be a char * pointing to a
502 message header to print; if zero, we use "guile" instead. That
503 text is followed by a colon, then the message described by ARGS. */
504
505 SCM
506 scm_handle_by_message (handler_data, tag, args)
507 void *handler_data;
508 SCM tag;
509 SCM args;
510 {
511 if (SCM_NFALSEP (scm_eq_p (tag, SCM_CAR (scm_intern0 ("quit")))))
512 {
513 exit (scm_exit_status (args));
514 }
515
516 handler_message (handler_data, tag, args);
517 /* try to flush the error message first before the rest of the
518 ports: if any throw error, it currently causes a bus
519 exception. */
520 exit (2);
521 }
522
523
524 /* This is just like scm_handle_by_message, but it doesn't exit; it
525 just returns #f. It's useful in cases where you don't really know
526 enough about the body to handle things in a better way, but don't
527 want to let throws fall off the bottom of the wind list. */
528 SCM
529 scm_handle_by_message_noexit (handler_data, tag, args)
530 void *handler_data;
531 SCM tag;
532 SCM args;
533 {
534 handler_message (handler_data, tag, args);
535
536 return SCM_BOOL_F;
537 }
538
539
540 SCM
541 scm_handle_by_throw (handler_data, tag, args)
542 void *handler_data;
543 SCM tag;
544 SCM args;
545 {
546 scm_ithrow (tag, args, 1);
547 return SCM_UNSPECIFIED; /* never returns */
548 }
549
550
551 \f
552 /* the Scheme-visible CATCH and LAZY-CATCH functions */
553
554 SCM_PROC(s_catch, "catch", 3, 0, 0, scm_catch);
555 SCM
556 scm_catch (tag, thunk, handler)
557 SCM tag;
558 SCM thunk;
559 SCM handler;
560 {
561 struct scm_body_thunk_data c;
562
563 SCM_ASSERT ((SCM_NIMP(tag) && SCM_SYMBOLP(tag)) || tag == SCM_BOOL_T,
564 tag,
565 SCM_ARG1,
566 s_catch);
567
568 c.tag = tag;
569 c.body_proc = thunk;
570
571 /* scm_internal_catch takes care of all the mechanics of setting up
572 a catch tag; we tell it to call scm_body_thunk to run the body,
573 and scm_handle_by_proc to deal with any throws to this catch.
574 The former receives a pointer to c, telling it how to behave.
575 The latter receives a pointer to HANDLER, so it knows who to call. */
576 return scm_internal_catch (tag,
577 scm_body_thunk, &c,
578 scm_handle_by_proc, &handler);
579 }
580
581
582 SCM_PROC(s_lazy_catch, "lazy-catch", 3, 0, 0, scm_lazy_catch);
583 SCM
584 scm_lazy_catch (tag, thunk, handler)
585 SCM tag;
586 SCM thunk;
587 SCM handler;
588 {
589 struct scm_body_thunk_data c;
590
591 SCM_ASSERT ((SCM_NIMP(tag) && SCM_SYMBOLP(tag))
592 || (tag == SCM_BOOL_T),
593 tag, SCM_ARG1, s_lazy_catch);
594
595 c.tag = tag;
596 c.body_proc = thunk;
597
598 /* scm_internal_lazy_catch takes care of all the mechanics of
599 setting up a lazy catch tag; we tell it to call scm_body_thunk to
600 run the body, and scm_handle_by_proc to deal with any throws to
601 this catch. The former receives a pointer to c, telling it how
602 to behave. The latter receives a pointer to HANDLER, so it knows
603 who to call. */
604 return scm_internal_lazy_catch (tag,
605 scm_body_thunk, &c,
606 scm_handle_by_proc, &handler);
607 }
608
609
610 \f
611 /* throwing */
612
613 SCM_PROC(s_throw, "throw", 1, 0, 1, scm_throw);
614 SCM
615 scm_throw (key, args)
616 SCM key;
617 SCM args;
618 {
619 SCM_ASSERT (SCM_NIMP (key) && SCM_SYMBOLP (key), key, SCM_ARG1, s_throw);
620 /* May return if handled by lazy catch. */
621 return scm_ithrow (key, args, 1);
622 }
623
624
625 SCM
626 scm_ithrow (key, args, noreturn)
627 SCM key;
628 SCM args;
629 int noreturn;
630 {
631 SCM jmpbuf = SCM_UNDEFINED;
632 SCM wind_goal;
633
634 SCM dynpair = SCM_UNDEFINED;
635 SCM winds;
636
637 /* Search the wind list for an appropriate catch.
638 "Waiter, please bring us the wind list." */
639 for (winds = scm_dynwinds; SCM_NIMP (winds); winds = SCM_CDR (winds))
640 {
641 if (! SCM_CONSP (winds))
642 abort ();
643
644 dynpair = SCM_CAR (winds);
645 if (SCM_NIMP (dynpair) && SCM_CONSP (dynpair))
646 {
647 SCM this_key = SCM_CAR (dynpair);
648
649 if (this_key == SCM_BOOL_T || this_key == key)
650 break;
651 }
652 }
653
654 /* If we didn't find anything, abort. scm_boot_guile should
655 have established a catch-all, but obviously things are
656 thoroughly screwed up. */
657 if (winds == SCM_EOL)
658 abort ();
659
660 /* If the wind list is malformed, bail. */
661 if (SCM_IMP (winds) || SCM_NCONSP (winds))
662 abort ();
663
664 if (dynpair != SCM_BOOL_F)
665 jmpbuf = SCM_CDR (dynpair);
666 else
667 {
668 if (!noreturn)
669 return SCM_UNSPECIFIED;
670 else
671 {
672 scm_exitval = scm_cons (key, args);
673 scm_dowinds (SCM_EOL, scm_ilength (scm_dynwinds));
674 #ifdef DEBUG_EXTENSIONS
675 scm_last_debug_frame = SCM_DFRAME (scm_rootcont);
676 #endif
677 longjmp (SCM_JMPBUF (scm_rootcont), 1);
678 }
679 }
680
681 for (wind_goal = scm_dynwinds;
682 SCM_CDAR (wind_goal) != jmpbuf;
683 wind_goal = SCM_CDR (wind_goal))
684 ;
685
686 /* Is a lazy catch? In wind list entries for lazy catches, the key
687 is bound to a lazy_catch smob, not a jmpbuf. */
688 if (SCM_LAZY_CATCH_P (jmpbuf))
689 {
690 struct lazy_catch *c = (struct lazy_catch *) SCM_CDR (jmpbuf);
691 SCM oldwinds = scm_dynwinds;
692 SCM handle, answer;
693 scm_dowinds (wind_goal, (scm_ilength (scm_dynwinds)
694 - scm_ilength (wind_goal)));
695 SCM_REDEFER_INTS;
696 handle = scm_dynwinds;
697 scm_dynwinds = SCM_CDR (scm_dynwinds);
698 SCM_REALLOW_INTS;
699 answer = (c->handler) (c->handler_data, key, args);
700 SCM_REDEFER_INTS;
701 SCM_SETCDR (handle, scm_dynwinds);
702 scm_dynwinds = handle;
703 SCM_REALLOW_INTS;
704 scm_dowinds (oldwinds, (scm_ilength (scm_dynwinds)
705 - scm_ilength (oldwinds)));
706 return answer;
707 }
708
709 /* Otherwise, it's a normal catch. */
710 else if (SCM_JMPBUFP (jmpbuf))
711 {
712 struct jmp_buf_and_retval * jbr;
713 scm_dowinds (wind_goal, (scm_ilength (scm_dynwinds)
714 - scm_ilength (wind_goal)));
715 jbr = (struct jmp_buf_and_retval *)JBJMPBUF (jmpbuf);
716 jbr->throw_tag = key;
717 jbr->retval = args;
718 }
719
720 /* Otherwise, it's some random piece of junk. */
721 else
722 abort ();
723
724 #ifdef DEBUG_EXTENSIONS
725 scm_last_debug_frame = SCM_JBDFRAME (jmpbuf);
726 #endif
727 longjmp (*JBJMPBUF (jmpbuf), 1);
728 }
729
730
731 void
732 scm_init_throw ()
733 {
734 #ifdef DEBUG_EXTENSIONS
735 scm_tc16_jmpbuffer = scm_make_smob_type_mfpe ("jmpbuffer",
736 sizeof (scm_cell),
737 NULL, /* mark */
738 freejb,
739 printjb,
740 NULL);
741 #else
742 scm_tc16_jmpbuffer = scm_make_smob_type_mfpe ("jmpbuffer",
743 0,
744 NULL, /* mark */
745 NULL
746 printjb,
747 NULL);
748 #endif
749
750 tc16_lazy_catch = scm_make_smob_type_mfpe ("lazy-catch", 0,
751 NULL,
752 NULL,
753 print_lazy_catch,
754 NULL);
755 #include "throw.x"
756 }