]> git.ipfire.org Git - thirdparty/bash.git/blame - unwind_prot.c
Imported from ../bash-2.04.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
58static void unwind_frame_discard_internal (), unwind_frame_run_internal ();
59static void add_unwind_protect_internal (), remove_unwind_protect_internal ();
60static void run_unwind_protects_internal (), without_interrupts ();
61
62static void restore_variable ();
63static void discard_saved_var ();
726f6388
JA
64
65static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
66
67extern int interrupt_immediately;
68
69/* Run a function without interrupts. This relies on the fact that the
70 FUNCTION cannot change the value of interrupt_immediately. (I.e., does
71 not call QUIT (). */
72static void
73without_interrupts (function, arg1, arg2)
74 VFunction *function;
75 char *arg1, *arg2;
76{
77 int old_interrupt_immediately;
78
79 old_interrupt_immediately = interrupt_immediately;
80 interrupt_immediately = 0;
81
82 (*function)(arg1, arg2);
83
84 interrupt_immediately = old_interrupt_immediately;
85}
86
87/* Start the beginning of a region. */
88void
89begin_unwind_frame (tag)
90 char *tag;
91{
92 add_unwind_protect ((Function *)NULL, tag);
93}
94
95/* Discard the unwind protects back to TAG. */
96void
97discard_unwind_frame (tag)
98 char *tag;
99{
100 if (unwind_protect_list)
101 without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
102}
103
104/* Run the unwind protects back to TAG. */
105void
106run_unwind_frame (tag)
107 char *tag;
108{
109 if (unwind_protect_list)
110 without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
111}
112
113/* Add the function CLEANUP with ARG to the list of unwindable things. */
114void
115add_unwind_protect (cleanup, arg)
116 Function *cleanup;
117 char *arg;
118{
119 without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
120}
121
122/* Remove the top unwind protect from the list. */
123void
124remove_unwind_protect ()
125{
126 if (unwind_protect_list)
127 without_interrupts
128 (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
129}
130
131/* Run the list of cleanup functions in unwind_protect_list. */
132void
133run_unwind_protects ()
134{
135 if (unwind_protect_list)
136 without_interrupts
137 (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
138}
139
140/* **************************************************************** */
141/* */
142/* The Actual Functions */
143/* */
144/* **************************************************************** */
145
146static void
147add_unwind_protect_internal (cleanup, arg)
148 Function *cleanup;
149 char *arg;
150{
151 UNWIND_ELT *elt;
152
153 elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT));
154 elt->cleanup = cleanup;
155 elt->arg = arg;
156 elt->next = unwind_protect_list;
157 unwind_protect_list = elt;
158}
159
160static void
161remove_unwind_protect_internal ()
162{
d166f048 163 UNWIND_ELT *elt;
726f6388 164
d166f048 165 elt = unwind_protect_list;
726f6388
JA
166 if (elt)
167 {
168 unwind_protect_list = unwind_protect_list->next;
d166f048
JA
169 if (elt->cleanup && elt->cleanup == (Function *)restore_variable)
170 discard_saved_var ((SAVED_VAR *)elt->arg);
726f6388
JA
171 free (elt);
172 }
173}
174
175static void
176run_unwind_protects_internal ()
177{
178 UNWIND_ELT *t, *elt = unwind_protect_list;
179
180 while (elt)
181 {
182 /* This function can be run at strange times, like when unwinding
d166f048 183 the entire world of unwind protects. Thus, we may come across
726f6388
JA
184 an element which is simply a label for a catch frame. Don't call
185 the non-existant function. */
186 if (elt->cleanup)
187 (*(elt->cleanup)) (elt->arg);
188
189 t = elt;
190 elt = elt->next;
191 free (t);
192 }
193 unwind_protect_list = elt;
194}
195
196static void
197unwind_frame_discard_internal (tag)
198 char *tag;
199{
200 UNWIND_ELT *elt;
201
202 while (elt = unwind_protect_list)
203 {
204 unwind_protect_list = unwind_protect_list->next;
d166f048 205 if (elt->cleanup == 0 && (STREQ (elt->arg, tag)))
726f6388
JA
206 {
207 free (elt);
208 break;
209 }
d166f048
JA
210 else if (elt->cleanup && elt->cleanup == (Function *)restore_variable)
211 {
212 discard_saved_var ((SAVED_VAR *)elt->arg);
213 free (elt);
214 }
726f6388
JA
215 else
216 free (elt);
217 }
218}
219
220static void
221unwind_frame_run_internal (tag)
222 char *tag;
223{
224 UNWIND_ELT *elt;
225
226 while (elt = unwind_protect_list)
227 {
228 unwind_protect_list = elt->next;
229
230 /* If tag, then compare. */
231 if (!elt->cleanup)
232 {
233 if (STREQ (elt->arg, tag))
234 {
235 free (elt);
236 break;
237 }
238 free (elt);
239 continue;
240 }
241 else
242 {
243 (*(elt->cleanup)) (elt->arg);
244 free (elt);
245 }
246 }
247}
248
d166f048
JA
249static void
250discard_saved_var (sv)
251 SAVED_VAR *sv;
252{
253 if (sv->size != sizeof (int))
254 free (sv->desired_setting);
255 free (sv);
256}
726f6388
JA
257
258/* Restore the value of a variable, based on the contents of SV. If
259 sv->size is greater than sizeof (int), sv->desired_setting points to
260 a block of memory SIZE bytes long holding the value, rather than the
261 value itself. This block of memory is copied back into the variable. */
262static void
263restore_variable (sv)
264 SAVED_VAR *sv;
265{
ccc6cda3 266 if (sv->size != sizeof (int))
726f6388 267 {
d166f048 268 FASTCOPY ((char *)sv->desired_setting, (char *)sv->variable, sv->size);
726f6388
JA
269 free (sv->desired_setting);
270 }
271 else
272 *(sv->variable) = (int)sv->desired_setting;
273
274 free (sv);
275}
276
277/* Save the value of a variable so it will be restored when unwind-protects
278 are run. VAR is a pointer to the variable. VALUE is the value to be
279 saved. SIZE is the size in bytes of VALUE. If SIZE is bigger than what
280 can be saved in an int, memory will be allocated and the value saved
281 into that using bcopy (). */
282void
283unwind_protect_var (var, value, size)
284 int *var;
285 char *value;
286 int size;
287{
288 SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR));
289
290 s->variable = var;
ccc6cda3 291 if (size != sizeof (int))
726f6388 292 {
d166f048
JA
293 /* There is a problem here when VALUE is 0. This tries to copy the
294 first SIZE bytes starting at memory location 0 into
295 s->desired_setting. There is no guarantee that these bytes are
296 0, or make a valid null pointer. We can try to bzero the space,
297 or just save it as 0 (or (void *)0). If we do the latter, make
298 sure restore_variable is changed to understand it. */
726f6388 299 s->desired_setting = (char *)xmalloc (size);
d166f048
JA
300 if (value == 0)
301 bzero ((char *)s->desired_setting, size);
302 else
303 FASTCOPY (value, (char *)s->desired_setting, size);
726f6388
JA
304 }
305 else
306 s->desired_setting = value;
307 s->size = size;
308 add_unwind_protect ((Function *)restore_variable, (char *)s);
309}