]> git.ipfire.org Git - thirdparty/bash.git/blob - unwind_prot.c
Imported from ../bash-2.05.tar.gz.
[thirdparty/bash.git] / unwind_prot.c
1 /* I can't stand it anymore! Please can't we just write the
2 whole Unix system in lisp or something? */
3
4 /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
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 2, or (at your option) any later
11 version.
12
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
16 for more details.
17
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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
21
22 /* **************************************************************** */
23 /* */
24 /* Unwind Protection Scheme for Bash */
25 /* */
26 /* **************************************************************** */
27 #include "config.h"
28
29 #include "bashtypes.h"
30 #include "bashansi.h"
31
32 #if defined (HAVE_UNISTD_H)
33 # include <unistd.h>
34 #endif
35
36 #include "command.h"
37 #include "general.h"
38 #include "unwind_prot.h"
39 #include "quit.h"
40 #include "sig.h"
41
42 /* If CLEANUP is null, then ARG contains a tag to throw back to. */
43 typedef struct _uwp {
44 struct _uwp *next;
45 Function *cleanup;
46 char *arg;
47 } UNWIND_ELT;
48
49 /* Structure describing a saved variable and the value to restore it to.
50 If a cleanup function is set to restore_variable, the `arg' pointer
51 points to this. */
52 typedef struct {
53 int *variable;
54 char *desired_setting;
55 int size;
56 } SAVED_VAR;
57
58 static void without_interrupts ();
59 static void unwind_frame_discard_internal ();
60 static void unwind_frame_run_internal ();
61 static void add_unwind_protect_internal ();
62 static void remove_unwind_protect_internal ();
63 static void run_unwind_protects_internal ();
64 static void clear_unwind_protects_internal ();
65 static void restore_variable ();
66 static void discard_saved_var ();
67
68 static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
69
70 extern int interrupt_immediately;
71
72 /* Run a function without interrupts. This relies on the fact that the
73 FUNCTION cannot change the value of interrupt_immediately. (I.e., does
74 not call QUIT (). */
75 static void
76 without_interrupts (function, arg1, arg2)
77 VFunction *function;
78 char *arg1, *arg2;
79 {
80 int old_interrupt_immediately;
81
82 old_interrupt_immediately = interrupt_immediately;
83 interrupt_immediately = 0;
84
85 (*function)(arg1, arg2);
86
87 interrupt_immediately = old_interrupt_immediately;
88 }
89
90 /* Start the beginning of a region. */
91 void
92 begin_unwind_frame (tag)
93 char *tag;
94 {
95 add_unwind_protect ((Function *)NULL, tag);
96 }
97
98 /* Discard the unwind protects back to TAG. */
99 void
100 discard_unwind_frame (tag)
101 char *tag;
102 {
103 if (unwind_protect_list)
104 without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
105 }
106
107 /* Run the unwind protects back to TAG. */
108 void
109 run_unwind_frame (tag)
110 char *tag;
111 {
112 if (unwind_protect_list)
113 without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
114 }
115
116 /* Add the function CLEANUP with ARG to the list of unwindable things. */
117 void
118 add_unwind_protect (cleanup, arg)
119 Function *cleanup;
120 char *arg;
121 {
122 without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
123 }
124
125 /* Remove the top unwind protect from the list. */
126 void
127 remove_unwind_protect ()
128 {
129 if (unwind_protect_list)
130 without_interrupts
131 (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
132 }
133
134 /* Run the list of cleanup functions in unwind_protect_list. */
135 void
136 run_unwind_protects ()
137 {
138 if (unwind_protect_list)
139 without_interrupts
140 (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
141 }
142
143 /* Erase the unwind-protect list. If flags is 1, free the elements. */
144 void
145 clear_unwind_protect_list (flags)
146 int flags;
147 {
148 if (unwind_protect_list)
149 without_interrupts
150 (clear_unwind_protects_internal, (char *)flags, (char *)NULL);
151 }
152
153 /* **************************************************************** */
154 /* */
155 /* The Actual Functions */
156 /* */
157 /* **************************************************************** */
158
159 static void
160 add_unwind_protect_internal (cleanup, arg)
161 Function *cleanup;
162 char *arg;
163 {
164 UNWIND_ELT *elt;
165
166 elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT));
167 elt->cleanup = cleanup;
168 elt->arg = arg;
169 elt->next = unwind_protect_list;
170 unwind_protect_list = elt;
171 }
172
173 static void
174 remove_unwind_protect_internal (ignore1, ignore2)
175 char *ignore1, *ignore2;
176 {
177 UNWIND_ELT *elt;
178
179 elt = unwind_protect_list;
180 if (elt)
181 {
182 unwind_protect_list = unwind_protect_list->next;
183 if (elt->cleanup && elt->cleanup == (Function *)restore_variable)
184 discard_saved_var ((SAVED_VAR *)elt->arg);
185 free (elt);
186 }
187 }
188
189 static void
190 run_unwind_protects_internal (ignore1, ignore2)
191 char *ignore1, *ignore2;
192 {
193 UNWIND_ELT *t, *elt = unwind_protect_list;
194
195 while (elt)
196 {
197 /* This function can be run at strange times, like when unwinding
198 the entire world of unwind protects. Thus, we may come across
199 an element which is simply a label for a catch frame. Don't call
200 the non-existant function. */
201 if (elt->cleanup)
202 (*(elt->cleanup)) (elt->arg);
203
204 t = elt;
205 elt = elt->next;
206 free (t);
207 }
208 unwind_protect_list = elt;
209 }
210
211 static void
212 clear_unwind_protects_internal (flag, ignore)
213 char *flag, *ignore;
214 {
215 int free_elts = (int)flag;
216 UNWIND_ELT *elt;
217
218 if (free_elts != 0 && unwind_protect_list)
219 {
220 while (unwind_protect_list)
221 remove_unwind_protect_internal ((char *)NULL, (char *)NULL);
222 }
223 unwind_protect_list = (UNWIND_ELT *)NULL;
224 }
225
226 static void
227 unwind_frame_discard_internal (tag, ignore)
228 char *tag, *ignore;
229 {
230 UNWIND_ELT *elt;
231
232 while (elt = unwind_protect_list)
233 {
234 unwind_protect_list = unwind_protect_list->next;
235 if (elt->cleanup == 0 && (STREQ (elt->arg, tag)))
236 {
237 free (elt);
238 break;
239 }
240 else if (elt->cleanup && elt->cleanup == (Function *)restore_variable)
241 {
242 discard_saved_var ((SAVED_VAR *)elt->arg);
243 free (elt);
244 }
245 else
246 free (elt);
247 }
248 }
249
250 static void
251 unwind_frame_run_internal (tag, ignore)
252 char *tag, *ignore;
253 {
254 UNWIND_ELT *elt;
255
256 while (elt = unwind_protect_list)
257 {
258 unwind_protect_list = elt->next;
259
260 /* If tag, then compare. */
261 if (!elt->cleanup)
262 {
263 if (STREQ (elt->arg, tag))
264 {
265 free (elt);
266 break;
267 }
268 free (elt);
269 continue;
270 }
271 else
272 {
273 (*(elt->cleanup)) (elt->arg);
274 free (elt);
275 }
276 }
277 }
278
279 static void
280 discard_saved_var (sv)
281 SAVED_VAR *sv;
282 {
283 if (sv->size != sizeof (int))
284 free (sv->desired_setting);
285 free (sv);
286 }
287
288 /* Restore the value of a variable, based on the contents of SV. If
289 sv->size is greater than sizeof (int), sv->desired_setting points to
290 a block of memory SIZE bytes long holding the value, rather than the
291 value itself. This block of memory is copied back into the variable. */
292 static void
293 restore_variable (sv)
294 SAVED_VAR *sv;
295 {
296 if (sv->size != sizeof (int))
297 {
298 FASTCOPY ((char *)sv->desired_setting, (char *)sv->variable, sv->size);
299 free (sv->desired_setting);
300 }
301 else
302 *(sv->variable) = (int)sv->desired_setting;
303
304 free (sv);
305 }
306
307 /* Save the value of a variable so it will be restored when unwind-protects
308 are run. VAR is a pointer to the variable. VALUE is the value to be
309 saved. SIZE is the size in bytes of VALUE. If SIZE is bigger than what
310 can be saved in an int, memory will be allocated and the value saved
311 into that using bcopy (). */
312 void
313 unwind_protect_var (var, value, size)
314 int *var;
315 char *value;
316 int size;
317 {
318 SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR));
319
320 s->variable = var;
321 if (size != sizeof (int))
322 {
323 s->desired_setting = (char *)xmalloc (size);
324 FASTCOPY (value, (char *)s->desired_setting, size);
325 }
326 else
327 s->desired_setting = value;
328 s->size = size;
329 add_unwind_protect ((Function *)restore_variable, (char *)s);
330 }