1 /* I can't stand it anymore! Please can't we just write the
2 whole Unix system in lisp or something? */
4 /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
6 This file is part of GNU Bash, the Bourne Again SHell.
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 1, or (at your option) any later
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING. If not, write to the Free Software
20 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
22 /* **************************************************************** */
24 /* Unwind Protection Scheme for Bash */
26 /* **************************************************************** */
27 #include "bashtypes.h"
32 #include "unwind_prot.h"
35 /* If CLEANUP is null, then ARG contains a tag to throw back to. */
43 unwind_frame_discard_internal (), unwind_frame_run_internal (),
44 add_unwind_protect_internal (), remove_unwind_protect_internal (),
45 run_unwind_protects_internal (), without_interrupts ();
47 static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
49 extern int interrupt_immediately;
51 /* Run a function without interrupts. This relies on the fact that the
52 FUNCTION cannot change the value of interrupt_immediately. (I.e., does
55 without_interrupts (function, arg1, arg2)
59 int old_interrupt_immediately;
61 old_interrupt_immediately = interrupt_immediately;
62 interrupt_immediately = 0;
64 (*function)(arg1, arg2);
66 interrupt_immediately = old_interrupt_immediately;
69 /* Start the beginning of a region. */
71 begin_unwind_frame (tag)
74 add_unwind_protect ((Function *)NULL, tag);
77 /* Discard the unwind protects back to TAG. */
79 discard_unwind_frame (tag)
82 if (unwind_protect_list)
83 without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
86 /* Run the unwind protects back to TAG. */
88 run_unwind_frame (tag)
91 if (unwind_protect_list)
92 without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
95 /* Add the function CLEANUP with ARG to the list of unwindable things. */
97 add_unwind_protect (cleanup, arg)
101 without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
104 /* Remove the top unwind protect from the list. */
106 remove_unwind_protect ()
108 if (unwind_protect_list)
110 (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
113 /* Run the list of cleanup functions in unwind_protect_list. */
115 run_unwind_protects ()
117 if (unwind_protect_list)
119 (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
122 /* **************************************************************** */
124 /* The Actual Functions */
126 /* **************************************************************** */
129 add_unwind_protect_internal (cleanup, arg)
135 elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT));
136 elt->cleanup = cleanup;
138 elt->next = unwind_protect_list;
139 unwind_protect_list = elt;
143 remove_unwind_protect_internal ()
145 UNWIND_ELT *elt = unwind_protect_list;
149 unwind_protect_list = unwind_protect_list->next;
155 run_unwind_protects_internal ()
157 UNWIND_ELT *t, *elt = unwind_protect_list;
161 /* This function can be run at strange times, like when unwinding
162 the entire world of unwind protects. Thus, we may come across
163 an element which is simply a label for a catch frame. Don't call
164 the non-existant function. */
166 (*(elt->cleanup)) (elt->arg);
172 unwind_protect_list = elt;
176 unwind_frame_discard_internal (tag)
181 while (elt = unwind_protect_list)
183 unwind_protect_list = unwind_protect_list->next;
184 if (!elt->cleanup && (STREQ (elt->arg, tag)))
195 unwind_frame_run_internal (tag)
200 while (elt = unwind_protect_list)
202 unwind_protect_list = elt->next;
204 /* If tag, then compare. */
207 if (STREQ (elt->arg, tag))
217 (*(elt->cleanup)) (elt->arg);
223 /* Structure describing a saved variable and the value to restore it to. */
226 char *desired_setting;
230 /* Restore the value of a variable, based on the contents of SV. If
231 sv->size is greater than sizeof (int), sv->desired_setting points to
232 a block of memory SIZE bytes long holding the value, rather than the
233 value itself. This block of memory is copied back into the variable. */
235 restore_variable (sv)
238 if (sv->size > sizeof (int))
240 bcopy ((char *)sv->desired_setting, (char *)sv->variable, sv->size);
241 free (sv->desired_setting);
244 *(sv->variable) = (int)sv->desired_setting;
249 /* Save the value of a variable so it will be restored when unwind-protects
250 are run. VAR is a pointer to the variable. VALUE is the value to be
251 saved. SIZE is the size in bytes of VALUE. If SIZE is bigger than what
252 can be saved in an int, memory will be allocated and the value saved
253 into that using bcopy (). */
255 unwind_protect_var (var, value, size)
260 SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR));
263 if (size > sizeof (int))
265 s->desired_setting = (char *)xmalloc (size);
266 bcopy (value, (char *)s->desired_setting, size);
269 s->desired_setting = value;
271 add_unwind_protect ((Function *)restore_variable, (char *)s);