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