]> git.ipfire.org Git - thirdparty/bash.git/blame - unwind_prot.c
Bash-5.2 patch 26: fix typo when specifying readline's custom color prefix
[thirdparty/bash.git] / unwind_prot.c
CommitLineData
3185942a
JA
1/* unwind_prot.c - a simple unwind-protect system for internal variables */
2
726f6388
JA
3/* I can't stand it anymore! Please can't we just write the
4 whole Unix system in lisp or something? */
5
74091dd4 6/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
726f6388 7
3185942a 8 This file is part of GNU Bash, the Bourne Again SHell.
726f6388 9
3185942a
JA
10 Bash is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
726f6388 14
3185942a
JA
15 Bash is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
726f6388 19
3185942a
JA
20 You should have received a copy of the GNU General Public License
21 along with Bash. If not, see <http://www.gnu.org/licenses/>.
22*/
726f6388
JA
23
24/* **************************************************************** */
25/* */
26/* Unwind Protection Scheme for Bash */
27/* */
28/* **************************************************************** */
726f6388 29#include "config.h"
ccc6cda3
JA
30
31#include "bashtypes.h"
d166f048
JA
32#include "bashansi.h"
33
ccc6cda3
JA
34#if defined (HAVE_UNISTD_H)
35# include <unistd.h>
36#endif
37
74091dd4 38#if defined (HAVE_STDDEF_H)
f73dda09
JA
39# include <stddef.h>
40#endif
41
42#ifndef offsetof
43# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
44#endif
45
726f6388
JA
46#include "command.h"
47#include "general.h"
48#include "unwind_prot.h"
ccc6cda3 49#include "sig.h"
ac50fbac 50#include "quit.h"
74091dd4 51#include "bashintl.h" /* for _() */
495aee44 52#include "error.h" /* for internal_warning */
a0c0a00f 53#include "ocache.h"
726f6388 54
f73dda09 55/* Structure describing a saved variable and the value to restore it to. */
d166f048 56typedef struct {
f73dda09 57 char *variable;
d166f048 58 int size;
f73dda09 59 char desired_setting[1]; /* actual size is `size' */
d166f048
JA
60} SAVED_VAR;
61
f73dda09
JA
62/* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to.
63 If HEAD.CLEANUP is restore_variable, then SV.V contains the saved
64 variable. Otherwise, call HEAD.CLEANUP (ARG.V) to clean up. */
65typedef union uwp {
66 struct uwp_head {
67 union uwp *next;
68 Function *cleanup;
69 } head;
70 struct {
71 struct uwp_head uwp_head;
72 char *v;
73 } arg;
74 struct {
75 struct uwp_head uwp_head;
76 SAVED_VAR v;
77 } sv;
78} UNWIND_ELT;
79
8868edaf
CR
80static void without_interrupts PARAMS((VFunction *, char *, char *));
81static void unwind_frame_discard_internal PARAMS((char *, char *));
82static void unwind_frame_run_internal PARAMS((char *, char *));
83static void add_unwind_protect_internal PARAMS((Function *, char *));
84static void remove_unwind_protect_internal PARAMS((char *, char *));
85static void run_unwind_protects_internal PARAMS((char *, char *));
86static void clear_unwind_protects_internal PARAMS((char *, char *));
87static inline void restore_variable PARAMS((SAVED_VAR *));
88static void unwind_protect_mem_internal PARAMS((char *, char *));
726f6388
JA
89
90static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
91
a0c0a00f
CR
92/* Allocating from a cache of unwind-protect elements */
93#define UWCACHESIZE 128
94
95sh_obj_cache_t uwcache = {0, 0, 0};
96
97#if 0
7117c2d2
JA
98#define uwpalloc(elt) (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT))
99#define uwpfree(elt) free(elt)
a0c0a00f
CR
100#else
101#define uwpalloc(elt) ocache_alloc (uwcache, UNWIND_ELT, elt)
102#define uwpfree(elt) ocache_free (uwcache, UNWIND_ELT, elt)
103#endif
104
105void
106uwp_init ()
107{
108 ocache_create (uwcache, UNWIND_ELT, UWCACHESIZE);
109}
726f6388
JA
110
111/* Run a function without interrupts. This relies on the fact that the
8868edaf 112 FUNCTION cannot call QUIT (). */
726f6388
JA
113static void
114without_interrupts (function, arg1, arg2)
115 VFunction *function;
116 char *arg1, *arg2;
117{
726f6388 118 (*function)(arg1, arg2);
726f6388
JA
119}
120
121/* Start the beginning of a region. */
122void
123begin_unwind_frame (tag)
124 char *tag;
125{
126 add_unwind_protect ((Function *)NULL, tag);
127}
128
129/* Discard the unwind protects back to TAG. */
130void
131discard_unwind_frame (tag)
132 char *tag;
133{
134 if (unwind_protect_list)
135 without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
136}
137
138/* Run the unwind protects back to TAG. */
139void
140run_unwind_frame (tag)
141 char *tag;
142{
143 if (unwind_protect_list)
144 without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
145}
146
147/* Add the function CLEANUP with ARG to the list of unwindable things. */
148void
149add_unwind_protect (cleanup, arg)
150 Function *cleanup;
151 char *arg;
152{
153 without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
154}
155
156/* Remove the top unwind protect from the list. */
157void
158remove_unwind_protect ()
159{
160 if (unwind_protect_list)
161 without_interrupts
162 (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
163}
164
165/* Run the list of cleanup functions in unwind_protect_list. */
166void
167run_unwind_protects ()
168{
169 if (unwind_protect_list)
170 without_interrupts
171 (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
172}
173
28ef6c31
JA
174/* Erase the unwind-protect list. If flags is 1, free the elements. */
175void
176clear_unwind_protect_list (flags)
177 int flags;
178{
f73dda09
JA
179 char *flag;
180
28ef6c31 181 if (unwind_protect_list)
f73dda09
JA
182 {
183 flag = flags ? "" : (char *)NULL;
184 without_interrupts
185 (clear_unwind_protects_internal, flag, (char *)NULL);
186 }
28ef6c31
JA
187}
188
3185942a
JA
189int
190have_unwind_protects ()
191{
192 return (unwind_protect_list != 0);
193}
194
a0c0a00f
CR
195int
196unwind_protect_tag_on_stack (tag)
197 const char *tag;
198{
199 UNWIND_ELT *elt;
200
201 elt = unwind_protect_list;
202 while (elt)
203 {
204 if (elt->head.cleanup == 0 && STREQ (elt->arg.v, tag))
205 return 1;
206 elt = elt->head.next;
207 }
208 return 0;
209}
210
726f6388
JA
211/* **************************************************************** */
212/* */
28ef6c31 213/* The Actual Functions */
726f6388
JA
214/* */
215/* **************************************************************** */
216
217static void
218add_unwind_protect_internal (cleanup, arg)
219 Function *cleanup;
220 char *arg;
221{
222 UNWIND_ELT *elt;
223
7117c2d2 224 uwpalloc (elt);
f73dda09
JA
225 elt->head.next = unwind_protect_list;
226 elt->head.cleanup = cleanup;
227 elt->arg.v = arg;
726f6388
JA
228 unwind_protect_list = elt;
229}
230
231static void
28ef6c31
JA
232remove_unwind_protect_internal (ignore1, ignore2)
233 char *ignore1, *ignore2;
726f6388 234{
d166f048 235 UNWIND_ELT *elt;
726f6388 236
d166f048 237 elt = unwind_protect_list;
726f6388
JA
238 if (elt)
239 {
f73dda09 240 unwind_protect_list = unwind_protect_list->head.next;
7117c2d2 241 uwpfree (elt);
726f6388
JA
242 }
243}
244
245static void
28ef6c31
JA
246run_unwind_protects_internal (ignore1, ignore2)
247 char *ignore1, *ignore2;
726f6388 248{
f73dda09 249 unwind_frame_run_internal ((char *) NULL, (char *) NULL);
726f6388
JA
250}
251
252static void
28ef6c31
JA
253clear_unwind_protects_internal (flag, ignore)
254 char *flag, *ignore;
255{
f73dda09 256 if (flag)
28ef6c31
JA
257 {
258 while (unwind_protect_list)
259 remove_unwind_protect_internal ((char *)NULL, (char *)NULL);
260 }
261 unwind_protect_list = (UNWIND_ELT *)NULL;
262}
263
264static void
265unwind_frame_discard_internal (tag, ignore)
266 char *tag, *ignore;
726f6388
JA
267{
268 UNWIND_ELT *elt;
495aee44 269 int found;
726f6388 270
495aee44 271 found = 0;
726f6388
JA
272 while (elt = unwind_protect_list)
273 {
f73dda09
JA
274 unwind_protect_list = unwind_protect_list->head.next;
275 if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag)))
726f6388 276 {
7117c2d2 277 uwpfree (elt);
495aee44 278 found = 1;
726f6388
JA
279 break;
280 }
281 else
7117c2d2 282 uwpfree (elt);
726f6388 283 }
495aee44
CR
284
285 if (found == 0)
74091dd4 286 internal_warning (_("unwind_frame_discard: %s: frame not found"), tag);
726f6388
JA
287}
288
f73dda09
JA
289/* Restore the value of a variable, based on the contents of SV.
290 sv->desired_setting is a block of memory SIZE bytes long holding the
291 value itself. This block of memory is copied back into the variable. */
292static inline void
293restore_variable (sv)
294 SAVED_VAR *sv;
295{
296 FASTCOPY (sv->desired_setting, sv->variable, sv->size);
297}
298
726f6388 299static void
28ef6c31
JA
300unwind_frame_run_internal (tag, ignore)
301 char *tag, *ignore;
726f6388
JA
302{
303 UNWIND_ELT *elt;
495aee44 304 int found;
726f6388 305
495aee44 306 found = 0;
726f6388
JA
307 while (elt = unwind_protect_list)
308 {
f73dda09 309 unwind_protect_list = elt->head.next;
726f6388
JA
310
311 /* If tag, then compare. */
495aee44 312 if (elt->head.cleanup == 0)
726f6388 313 {
f73dda09 314 if (tag && STREQ (elt->arg.v, tag))
726f6388 315 {
7117c2d2 316 uwpfree (elt);
495aee44 317 found = 1;
726f6388
JA
318 break;
319 }
726f6388
JA
320 }
321 else
322 {
f73dda09
JA
323 if (elt->head.cleanup == (Function *) restore_variable)
324 restore_variable (&elt->sv.v);
325 else
326 (*(elt->head.cleanup)) (elt->arg.v);
726f6388 327 }
726f6388 328
7117c2d2 329 uwpfree (elt);
f73dda09 330 }
495aee44 331 if (tag && found == 0)
74091dd4 332 internal_warning (_("unwind_frame_run: %s: frame not found"), tag);
d166f048 333}
726f6388 334
726f6388 335static void
f73dda09
JA
336unwind_protect_mem_internal (var, psize)
337 char *var;
338 char *psize;
726f6388 339{
f73dda09
JA
340 int size, allocated;
341 UNWIND_ELT *elt;
726f6388 342
f73dda09
JA
343 size = *(int *) psize;
344 allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]);
8868edaf
CR
345 if (allocated < sizeof (UNWIND_ELT))
346 allocated = sizeof (UNWIND_ELT);
f73dda09
JA
347 elt = (UNWIND_ELT *)xmalloc (allocated);
348 elt->head.next = unwind_protect_list;
349 elt->head.cleanup = (Function *) restore_variable;
350 elt->sv.v.variable = var;
351 elt->sv.v.size = size;
352 FASTCOPY (var, elt->sv.v.desired_setting, size);
353 unwind_protect_list = elt;
726f6388
JA
354}
355
356/* Save the value of a variable so it will be restored when unwind-protects
f73dda09
JA
357 are run. VAR is a pointer to the variable. SIZE is the size in
358 bytes of VAR. */
726f6388 359void
f73dda09
JA
360unwind_protect_mem (var, size)
361 char *var;
726f6388
JA
362 int size;
363{
f73dda09 364 without_interrupts (unwind_protect_mem_internal, var, (char *) &size);
726f6388 365}
495aee44
CR
366
367#if defined (DEBUG)
368#include <stdio.h>
369
370void
371print_unwind_protect_tags ()
372{
373 UNWIND_ELT *elt;
374
375 elt = unwind_protect_list;
376 while (elt)
377 {
495aee44
CR
378 if (elt->head.cleanup == 0)
379 fprintf(stderr, "tag: %s\n", elt->arg.v);
a0c0a00f 380 elt = elt->head.next;
495aee44
CR
381 }
382}
383#endif