Imported from ../bash-1.14.7.tar.gz.
[platform/upstream/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 "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. */
36 typedef struct _uwp {
37   struct _uwp *next;
38   Function *cleanup;
39   char *arg;
40 } UNWIND_ELT;
41
42 static 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
47 static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
48
49 extern 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 (). */
54 static void
55 without_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. */
70 void
71 begin_unwind_frame (tag)
72      char *tag;
73 {
74   add_unwind_protect ((Function *)NULL, tag);
75 }
76
77 /* Discard the unwind protects back to TAG. */
78 void
79 discard_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. */
87 void
88 run_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. */
96 void
97 add_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. */
105 void
106 remove_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. */
114 void
115 run_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
128 static void
129 add_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
142 static void
143 remove_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
154 static void
155 run_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
175 static void
176 unwind_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
194 static void
195 unwind_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. */
224 typedef 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. */
234 static void
235 restore_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 (). */
254 void
255 unwind_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 }