]> git.ipfire.org Git - thirdparty/bash.git/blob - unwind_prot.c
Imported from ../bash-2.0.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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22 /* **************************************************************** */
23 /* */
24 /* Unwind Protection Scheme for Bash */
25 /* */
26 /* **************************************************************** */
27 #include "config.h"
28
29 #include "bashtypes.h"
30 #if defined (HAVE_UNISTD_H)
31 # include <unistd.h>
32 #endif
33
34 #include "command.h"
35 #include "general.h"
36 #include "unwind_prot.h"
37 #include "quit.h"
38 #include "sig.h"
39
40 /* If CLEANUP is null, then ARG contains a tag to throw back to. */
41 typedef struct _uwp {
42 struct _uwp *next;
43 Function *cleanup;
44 char *arg;
45 } UNWIND_ELT;
46
47 static void
48 unwind_frame_discard_internal (), unwind_frame_run_internal (),
49 add_unwind_protect_internal (), remove_unwind_protect_internal (),
50 run_unwind_protects_internal (), without_interrupts ();
51
52 static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
53
54 extern int interrupt_immediately;
55
56 /* Run a function without interrupts. This relies on the fact that the
57 FUNCTION cannot change the value of interrupt_immediately. (I.e., does
58 not call QUIT (). */
59 static void
60 without_interrupts (function, arg1, arg2)
61 VFunction *function;
62 char *arg1, *arg2;
63 {
64 int old_interrupt_immediately;
65
66 old_interrupt_immediately = interrupt_immediately;
67 interrupt_immediately = 0;
68
69 (*function)(arg1, arg2);
70
71 interrupt_immediately = old_interrupt_immediately;
72 }
73
74 /* Start the beginning of a region. */
75 void
76 begin_unwind_frame (tag)
77 char *tag;
78 {
79 add_unwind_protect ((Function *)NULL, tag);
80 }
81
82 /* Discard the unwind protects back to TAG. */
83 void
84 discard_unwind_frame (tag)
85 char *tag;
86 {
87 if (unwind_protect_list)
88 without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
89 }
90
91 /* Run the unwind protects back to TAG. */
92 void
93 run_unwind_frame (tag)
94 char *tag;
95 {
96 if (unwind_protect_list)
97 without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
98 }
99
100 /* Add the function CLEANUP with ARG to the list of unwindable things. */
101 void
102 add_unwind_protect (cleanup, arg)
103 Function *cleanup;
104 char *arg;
105 {
106 without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
107 }
108
109 /* Remove the top unwind protect from the list. */
110 void
111 remove_unwind_protect ()
112 {
113 if (unwind_protect_list)
114 without_interrupts
115 (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
116 }
117
118 /* Run the list of cleanup functions in unwind_protect_list. */
119 void
120 run_unwind_protects ()
121 {
122 if (unwind_protect_list)
123 without_interrupts
124 (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
125 }
126
127 /* **************************************************************** */
128 /* */
129 /* The Actual Functions */
130 /* */
131 /* **************************************************************** */
132
133 static void
134 add_unwind_protect_internal (cleanup, arg)
135 Function *cleanup;
136 char *arg;
137 {
138 UNWIND_ELT *elt;
139
140 elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT));
141 elt->cleanup = cleanup;
142 elt->arg = arg;
143 elt->next = unwind_protect_list;
144 unwind_protect_list = elt;
145 }
146
147 static void
148 remove_unwind_protect_internal ()
149 {
150 UNWIND_ELT *elt = unwind_protect_list;
151
152 if (elt)
153 {
154 unwind_protect_list = unwind_protect_list->next;
155 free (elt);
156 }
157 }
158
159 static void
160 run_unwind_protects_internal ()
161 {
162 UNWIND_ELT *t, *elt = unwind_protect_list;
163
164 while (elt)
165 {
166 /* This function can be run at strange times, like when unwinding
167 the entire world of unwind protects. Thus, we may come across
168 an element which is simply a label for a catch frame. Don't call
169 the non-existant function. */
170 if (elt->cleanup)
171 (*(elt->cleanup)) (elt->arg);
172
173 t = elt;
174 elt = elt->next;
175 free (t);
176 }
177 unwind_protect_list = elt;
178 }
179
180 static void
181 unwind_frame_discard_internal (tag)
182 char *tag;
183 {
184 UNWIND_ELT *elt;
185
186 while (elt = unwind_protect_list)
187 {
188 unwind_protect_list = unwind_protect_list->next;
189 if (!elt->cleanup && (STREQ (elt->arg, tag)))
190 {
191 free (elt);
192 break;
193 }
194 else
195 free (elt);
196 }
197 }
198
199 static void
200 unwind_frame_run_internal (tag)
201 char *tag;
202 {
203 UNWIND_ELT *elt;
204
205 while (elt = unwind_protect_list)
206 {
207 unwind_protect_list = elt->next;
208
209 /* If tag, then compare. */
210 if (!elt->cleanup)
211 {
212 if (STREQ (elt->arg, tag))
213 {
214 free (elt);
215 break;
216 }
217 free (elt);
218 continue;
219 }
220 else
221 {
222 (*(elt->cleanup)) (elt->arg);
223 free (elt);
224 }
225 }
226 }
227
228 /* Structure describing a saved variable and the value to restore it to. */
229 typedef struct {
230 int *variable;
231 char *desired_setting;
232 int size;
233 } SAVED_VAR;
234
235 /* Restore the value of a variable, based on the contents of SV. If
236 sv->size is greater than sizeof (int), sv->desired_setting points to
237 a block of memory SIZE bytes long holding the value, rather than the
238 value itself. This block of memory is copied back into the variable. */
239 static void
240 restore_variable (sv)
241 SAVED_VAR *sv;
242 {
243 if (sv->size != sizeof (int))
244 {
245 bcopy ((char *)sv->desired_setting, (char *)sv->variable, sv->size);
246 free (sv->desired_setting);
247 }
248 else
249 *(sv->variable) = (int)sv->desired_setting;
250
251 free (sv);
252 }
253
254 /* Save the value of a variable so it will be restored when unwind-protects
255 are run. VAR is a pointer to the variable. VALUE is the value to be
256 saved. SIZE is the size in bytes of VALUE. If SIZE is bigger than what
257 can be saved in an int, memory will be allocated and the value saved
258 into that using bcopy (). */
259 void
260 unwind_protect_var (var, value, size)
261 int *var;
262 char *value;
263 int size;
264 {
265 SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR));
266
267 s->variable = var;
268 if (size != sizeof (int))
269 {
270 s->desired_setting = (char *)xmalloc (size);
271 bcopy (value, (char *)s->desired_setting, size);
272 }
273 else
274 s->desired_setting = value;
275 s->size = size;
276 add_unwind_protect ((Function *)restore_variable, (char *)s);
277 }