]>
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 | ||
58 | static void unwind_frame_discard_internal (), unwind_frame_run_internal (); | |
59 | static void add_unwind_protect_internal (), remove_unwind_protect_internal (); | |
60 | static void run_unwind_protects_internal (), without_interrupts (); | |
61 | ||
62 | static void restore_variable (); | |
63 | static void discard_saved_var (); | |
726f6388 JA |
64 | |
65 | static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL; | |
66 | ||
67 | extern 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 (). */ | |
72 | static void | |
73 | without_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. */ | |
88 | void | |
89 | begin_unwind_frame (tag) | |
90 | char *tag; | |
91 | { | |
92 | add_unwind_protect ((Function *)NULL, tag); | |
93 | } | |
94 | ||
95 | /* Discard the unwind protects back to TAG. */ | |
96 | void | |
97 | discard_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. */ | |
105 | void | |
106 | run_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. */ | |
114 | void | |
115 | add_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. */ | |
123 | void | |
124 | remove_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. */ | |
132 | void | |
133 | run_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 | ||
146 | static void | |
147 | add_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 | ||
160 | static void | |
161 | remove_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 | ||
175 | static void | |
176 | run_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 | ||
196 | static void | |
197 | unwind_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 | ||
220 | static void | |
221 | unwind_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 |
249 | static void |
250 | discard_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. */ | |
262 | static void | |
263 | restore_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 (). */ | |
282 | void | |
283 | unwind_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 | } |