]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | |
bb70624e | 10 | Software Foundation; either version 2, or (at your option) any later |
726f6388 JA |
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 | |
bb70624e | 20 | Foundation, 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. */ | |
43 | typedef 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. */ | |
52 | typedef struct { | |
53 | int *variable; | |
54 | char *desired_setting; | |
55 | int size; | |
56 | } SAVED_VAR; | |
57 | ||
28ef6c31 JA |
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 (); | |
d166f048 JA |
65 | static void restore_variable (); |
66 | static void discard_saved_var (); | |
726f6388 JA |
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 | ||
28ef6c31 JA |
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 | ||
726f6388 JA |
153 | /* **************************************************************** */ |
154 | /* */ | |
28ef6c31 | 155 | /* The Actual Functions */ |
726f6388 JA |
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 | |
28ef6c31 JA |
174 | remove_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 | ||
189 | static void | |
28ef6c31 JA |
190 | run_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 | ||
211 | static void | |
28ef6c31 JA |
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; | |
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 | ||
250 | static void | |
28ef6c31 JA |
251 | unwind_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 |
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 | } | |
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. */ | |
292 | static void | |
293 | restore_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 (). */ | |
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; | |
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 | } |