]> git.ipfire.org Git - thirdparty/bash.git/blame - unwind_prot.c
Imported from ../bash-3.2.48.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
7117c2d2 4/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
726f6388
JA
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
f73dda09
JA
36#if STDC_HEADERS
37# include <stddef.h>
38#endif
39
40#ifndef offsetof
41# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
42#endif
43
726f6388
JA
44#include "command.h"
45#include "general.h"
46#include "unwind_prot.h"
47#include "quit.h"
ccc6cda3 48#include "sig.h"
726f6388 49
f73dda09 50/* Structure describing a saved variable and the value to restore it to. */
d166f048 51typedef struct {
f73dda09 52 char *variable;
d166f048 53 int size;
f73dda09 54 char desired_setting[1]; /* actual size is `size' */
d166f048
JA
55} SAVED_VAR;
56
f73dda09
JA
57/* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to.
58 If HEAD.CLEANUP is restore_variable, then SV.V contains the saved
59 variable. Otherwise, call HEAD.CLEANUP (ARG.V) to clean up. */
60typedef union uwp {
61 struct uwp_head {
62 union uwp *next;
63 Function *cleanup;
64 } head;
65 struct {
66 struct uwp_head uwp_head;
67 char *v;
68 } arg;
69 struct {
70 struct uwp_head uwp_head;
71 SAVED_VAR v;
72 } sv;
73} UNWIND_ELT;
74
7117c2d2 75
f73dda09
JA
76static void without_interrupts __P((VFunction *, char *, char *));
77static void unwind_frame_discard_internal __P((char *, char *));
78static void unwind_frame_run_internal __P((char *, char *));
79static void add_unwind_protect_internal __P((Function *, char *));
80static void remove_unwind_protect_internal __P((char *, char *));
81static void run_unwind_protects_internal __P((char *, char *));
82static void clear_unwind_protects_internal __P((char *, char *));
83static inline void restore_variable __P((SAVED_VAR *));
84static void unwind_protect_mem_internal __P((char *, char *));
726f6388
JA
85
86static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
87
7117c2d2
JA
88#define uwpalloc(elt) (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT))
89#define uwpfree(elt) free(elt)
726f6388
JA
90
91/* Run a function without interrupts. This relies on the fact that the
92 FUNCTION cannot change the value of interrupt_immediately. (I.e., does
93 not call QUIT (). */
94static void
95without_interrupts (function, arg1, arg2)
96 VFunction *function;
97 char *arg1, *arg2;
98{
99 int old_interrupt_immediately;
100
101 old_interrupt_immediately = interrupt_immediately;
102 interrupt_immediately = 0;
103
104 (*function)(arg1, arg2);
105
106 interrupt_immediately = old_interrupt_immediately;
107}
108
109/* Start the beginning of a region. */
110void
111begin_unwind_frame (tag)
112 char *tag;
113{
114 add_unwind_protect ((Function *)NULL, tag);
115}
116
117/* Discard the unwind protects back to TAG. */
118void
119discard_unwind_frame (tag)
120 char *tag;
121{
122 if (unwind_protect_list)
123 without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
124}
125
126/* Run the unwind protects back to TAG. */
127void
128run_unwind_frame (tag)
129 char *tag;
130{
131 if (unwind_protect_list)
132 without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
133}
134
135/* Add the function CLEANUP with ARG to the list of unwindable things. */
136void
137add_unwind_protect (cleanup, arg)
138 Function *cleanup;
139 char *arg;
140{
141 without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
142}
143
144/* Remove the top unwind protect from the list. */
145void
146remove_unwind_protect ()
147{
148 if (unwind_protect_list)
149 without_interrupts
150 (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
151}
152
153/* Run the list of cleanup functions in unwind_protect_list. */
154void
155run_unwind_protects ()
156{
157 if (unwind_protect_list)
158 without_interrupts
159 (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
160}
161
28ef6c31
JA
162/* Erase the unwind-protect list. If flags is 1, free the elements. */
163void
164clear_unwind_protect_list (flags)
165 int flags;
166{
f73dda09
JA
167 char *flag;
168
28ef6c31 169 if (unwind_protect_list)
f73dda09
JA
170 {
171 flag = flags ? "" : (char *)NULL;
172 without_interrupts
173 (clear_unwind_protects_internal, flag, (char *)NULL);
174 }
28ef6c31
JA
175}
176
726f6388
JA
177/* **************************************************************** */
178/* */
28ef6c31 179/* The Actual Functions */
726f6388
JA
180/* */
181/* **************************************************************** */
182
183static void
184add_unwind_protect_internal (cleanup, arg)
185 Function *cleanup;
186 char *arg;
187{
188 UNWIND_ELT *elt;
189
7117c2d2 190 uwpalloc (elt);
f73dda09
JA
191 elt->head.next = unwind_protect_list;
192 elt->head.cleanup = cleanup;
193 elt->arg.v = arg;
726f6388
JA
194 unwind_protect_list = elt;
195}
196
197static void
28ef6c31
JA
198remove_unwind_protect_internal (ignore1, ignore2)
199 char *ignore1, *ignore2;
726f6388 200{
d166f048 201 UNWIND_ELT *elt;
726f6388 202
d166f048 203 elt = unwind_protect_list;
726f6388
JA
204 if (elt)
205 {
f73dda09 206 unwind_protect_list = unwind_protect_list->head.next;
7117c2d2 207 uwpfree (elt);
726f6388
JA
208 }
209}
210
211static void
28ef6c31
JA
212run_unwind_protects_internal (ignore1, ignore2)
213 char *ignore1, *ignore2;
726f6388 214{
f73dda09 215 unwind_frame_run_internal ((char *) NULL, (char *) NULL);
726f6388
JA
216}
217
218static void
28ef6c31
JA
219clear_unwind_protects_internal (flag, ignore)
220 char *flag, *ignore;
221{
f73dda09 222 if (flag)
28ef6c31
JA
223 {
224 while (unwind_protect_list)
225 remove_unwind_protect_internal ((char *)NULL, (char *)NULL);
226 }
227 unwind_protect_list = (UNWIND_ELT *)NULL;
228}
229
230static void
231unwind_frame_discard_internal (tag, ignore)
232 char *tag, *ignore;
726f6388
JA
233{
234 UNWIND_ELT *elt;
235
236 while (elt = unwind_protect_list)
237 {
f73dda09
JA
238 unwind_protect_list = unwind_protect_list->head.next;
239 if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag)))
726f6388 240 {
7117c2d2 241 uwpfree (elt);
726f6388
JA
242 break;
243 }
244 else
7117c2d2 245 uwpfree (elt);
726f6388
JA
246 }
247}
248
f73dda09
JA
249/* Restore the value of a variable, based on the contents of SV.
250 sv->desired_setting is a block of memory SIZE bytes long holding the
251 value itself. This block of memory is copied back into the variable. */
252static inline void
253restore_variable (sv)
254 SAVED_VAR *sv;
255{
256 FASTCOPY (sv->desired_setting, sv->variable, sv->size);
257}
258
726f6388 259static void
28ef6c31
JA
260unwind_frame_run_internal (tag, ignore)
261 char *tag, *ignore;
726f6388
JA
262{
263 UNWIND_ELT *elt;
264
265 while (elt = unwind_protect_list)
266 {
f73dda09 267 unwind_protect_list = elt->head.next;
726f6388
JA
268
269 /* If tag, then compare. */
f73dda09 270 if (!elt->head.cleanup)
726f6388 271 {
f73dda09 272 if (tag && STREQ (elt->arg.v, tag))
726f6388 273 {
7117c2d2 274 uwpfree (elt);
726f6388
JA
275 break;
276 }
726f6388
JA
277 }
278 else
279 {
f73dda09
JA
280 if (elt->head.cleanup == (Function *) restore_variable)
281 restore_variable (&elt->sv.v);
282 else
283 (*(elt->head.cleanup)) (elt->arg.v);
726f6388 284 }
726f6388 285
7117c2d2 286 uwpfree (elt);
f73dda09 287 }
d166f048 288}
726f6388 289
726f6388 290static void
f73dda09
JA
291unwind_protect_mem_internal (var, psize)
292 char *var;
293 char *psize;
726f6388 294{
f73dda09
JA
295 int size, allocated;
296 UNWIND_ELT *elt;
726f6388 297
f73dda09
JA
298 size = *(int *) psize;
299 allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]);
300 elt = (UNWIND_ELT *)xmalloc (allocated);
301 elt->head.next = unwind_protect_list;
302 elt->head.cleanup = (Function *) restore_variable;
303 elt->sv.v.variable = var;
304 elt->sv.v.size = size;
305 FASTCOPY (var, elt->sv.v.desired_setting, size);
306 unwind_protect_list = elt;
726f6388
JA
307}
308
309/* Save the value of a variable so it will be restored when unwind-protects
f73dda09
JA
310 are run. VAR is a pointer to the variable. SIZE is the size in
311 bytes of VAR. */
726f6388 312void
f73dda09
JA
313unwind_protect_mem (var, size)
314 char *var;
726f6388
JA
315 int size;
316{
f73dda09 317 without_interrupts (unwind_protect_mem_internal, var, (char *) &size);
726f6388 318}