]> git.ipfire.org Git - thirdparty/bash.git/blame - unwind_prot.c
Imported from ../bash-2.05.tar.gz.
[thirdparty/bash.git] / unwind_prot.c
CommitLineData
726f6388
JA
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
6This file is part of GNU Bash, the Bourne Again SHell.
7
8Bash is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
bb70624e 10Software Foundation; either version 2, or (at your option) any later
726f6388
JA
11version.
12
13Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License along
19with Bash; see the file COPYING. If not, write to the Free Software
bb70624e 20Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
726f6388
JA
21
22/* **************************************************************** */
23/* */
24/* Unwind Protection Scheme for Bash */
25/* */
26/* **************************************************************** */
726f6388 27#include "config.h"
ccc6cda3
JA
28
29#include "bashtypes.h"
d166f048
JA
30#include "bashansi.h"
31
ccc6cda3
JA
32#if defined (HAVE_UNISTD_H)
33# include <unistd.h>
34#endif
35
726f6388
JA
36#include "command.h"
37#include "general.h"
38#include "unwind_prot.h"
39#include "quit.h"
ccc6cda3 40#include "sig.h"
726f6388
JA
41
42/* If CLEANUP is null, then ARG contains a tag to throw back to. */
43typedef struct _uwp {
44 struct _uwp *next;
45 Function *cleanup;
46 char *arg;
47} UNWIND_ELT;
48
d166f048
JA
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. */
52typedef struct {
53 int *variable;
54 char *desired_setting;
55 int size;
56} SAVED_VAR;
57
28ef6c31
JA
58static void without_interrupts ();
59static void unwind_frame_discard_internal ();
60static void unwind_frame_run_internal ();
61static void add_unwind_protect_internal ();
62static void remove_unwind_protect_internal ();
63static void run_unwind_protects_internal ();
64static void clear_unwind_protects_internal ();
d166f048
JA
65static void restore_variable ();
66static void discard_saved_var ();
726f6388
JA
67
68static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
69
70extern 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 (). */
75static void
76without_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. */
91void
92begin_unwind_frame (tag)
93 char *tag;
94{
95 add_unwind_protect ((Function *)NULL, tag);
96}
97
98/* Discard the unwind protects back to TAG. */
99void
100discard_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. */
108void
109run_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. */
117void
118add_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. */
126void
127remove_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. */
135void
136run_unwind_protects ()
137{
138 if (unwind_protect_list)
139 without_interrupts
140 (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
141}
142
28ef6c31
JA
143/* Erase the unwind-protect list. If flags is 1, free the elements. */
144void
145clear_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
726f6388
JA
153/* **************************************************************** */
154/* */
28ef6c31 155/* The Actual Functions */
726f6388
JA
156/* */
157/* **************************************************************** */
158
159static void
160add_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
173static void
28ef6c31
JA
174remove_unwind_protect_internal (ignore1, ignore2)
175 char *ignore1, *ignore2;
726f6388 176{
d166f048 177 UNWIND_ELT *elt;
726f6388 178
d166f048 179 elt = unwind_protect_list;
726f6388
JA
180 if (elt)
181 {
182 unwind_protect_list = unwind_protect_list->next;
d166f048
JA
183 if (elt->cleanup && elt->cleanup == (Function *)restore_variable)
184 discard_saved_var ((SAVED_VAR *)elt->arg);
726f6388
JA
185 free (elt);
186 }
187}
188
189static void
28ef6c31
JA
190run_unwind_protects_internal (ignore1, ignore2)
191 char *ignore1, *ignore2;
726f6388
JA
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
d166f048 198 the entire world of unwind protects. Thus, we may come across
726f6388
JA
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
211static void
28ef6c31
JA
212clear_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
226static void
227unwind_frame_discard_internal (tag, ignore)
228 char *tag, *ignore;
726f6388
JA
229{
230 UNWIND_ELT *elt;
231
232 while (elt = unwind_protect_list)
233 {
234 unwind_protect_list = unwind_protect_list->next;
d166f048 235 if (elt->cleanup == 0 && (STREQ (elt->arg, tag)))
726f6388
JA
236 {
237 free (elt);
238 break;
239 }
d166f048 240 else if (elt->cleanup && elt->cleanup == (Function *)restore_variable)
28ef6c31
JA
241 {
242 discard_saved_var ((SAVED_VAR *)elt->arg);
243 free (elt);
244 }
726f6388
JA
245 else
246 free (elt);
247 }
248}
249
250static void
28ef6c31
JA
251unwind_frame_run_internal (tag, ignore)
252 char *tag, *ignore;
726f6388
JA
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
d166f048
JA
279static void
280discard_saved_var (sv)
281 SAVED_VAR *sv;
282{
283 if (sv->size != sizeof (int))
284 free (sv->desired_setting);
285 free (sv);
286}
726f6388
JA
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. */
292static void
293restore_variable (sv)
294 SAVED_VAR *sv;
295{
ccc6cda3 296 if (sv->size != sizeof (int))
726f6388 297 {
d166f048 298 FASTCOPY ((char *)sv->desired_setting, (char *)sv->variable, sv->size);
726f6388
JA
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 (). */
312void
313unwind_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;
ccc6cda3 321 if (size != sizeof (int))
726f6388
JA
322 {
323 s->desired_setting = (char *)xmalloc (size);
28ef6c31 324 FASTCOPY (value, (char *)s->desired_setting, size);
726f6388
JA
325 }
326 else
327 s->desired_setting = value;
328 s->size = size;
329 add_unwind_protect ((Function *)restore_variable, (char *)s);
330}