summaryrefslogtreecommitdiff
path: root/unwind_prot.c
diff options
context:
space:
mode:
authorJari Aalto <jari.aalto@cante.net>1996-08-26 18:22:31 +0000
committerJari Aalto <jari.aalto@cante.net>2009-09-12 16:46:49 +0000
commit726f63884db0132f01745f1fb4465e6621088ccf (patch)
tree6c2f7765a890a97e0e513cb539df43283a8f7c4d /unwind_prot.c
downloadbash-726f63884db0132f01745f1fb4465e6621088ccf.tar.gz
Imported from ../bash-1.14.7.tar.gz.
Diffstat (limited to 'unwind_prot.c')
-rw-r--r--unwind_prot.c272
1 files changed, 272 insertions, 0 deletions
diff --git a/unwind_prot.c b/unwind_prot.c
new file mode 100644
index 00000000..d9399d7d
--- /dev/null
+++ b/unwind_prot.c
@@ -0,0 +1,272 @@
+/* I can't stand it anymore! Please can't we just write the
+ whole Unix system in lisp or something? */
+
+/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
+
+This file is part of GNU Bash, the Bourne Again SHell.
+
+Bash is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* **************************************************************** */
+/* */
+/* Unwind Protection Scheme for Bash */
+/* */
+/* **************************************************************** */
+#include "bashtypes.h"
+#include <signal.h>
+#include "config.h"
+#include "command.h"
+#include "general.h"
+#include "unwind_prot.h"
+#include "quit.h"
+
+/* If CLEANUP is null, then ARG contains a tag to throw back to. */
+typedef struct _uwp {
+ struct _uwp *next;
+ Function *cleanup;
+ char *arg;
+} UNWIND_ELT;
+
+static void
+ unwind_frame_discard_internal (), unwind_frame_run_internal (),
+ add_unwind_protect_internal (), remove_unwind_protect_internal (),
+ run_unwind_protects_internal (), without_interrupts ();
+
+static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
+
+extern int interrupt_immediately;
+
+/* Run a function without interrupts. This relies on the fact that the
+ FUNCTION cannot change the value of interrupt_immediately. (I.e., does
+ not call QUIT (). */
+static void
+without_interrupts (function, arg1, arg2)
+ VFunction *function;
+ char *arg1, *arg2;
+{
+ int old_interrupt_immediately;
+
+ old_interrupt_immediately = interrupt_immediately;
+ interrupt_immediately = 0;
+
+ (*function)(arg1, arg2);
+
+ interrupt_immediately = old_interrupt_immediately;
+}
+
+/* Start the beginning of a region. */
+void
+begin_unwind_frame (tag)
+ char *tag;
+{
+ add_unwind_protect ((Function *)NULL, tag);
+}
+
+/* Discard the unwind protects back to TAG. */
+void
+discard_unwind_frame (tag)
+ char *tag;
+{
+ if (unwind_protect_list)
+ without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
+}
+
+/* Run the unwind protects back to TAG. */
+void
+run_unwind_frame (tag)
+ char *tag;
+{
+ if (unwind_protect_list)
+ without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
+}
+
+/* Add the function CLEANUP with ARG to the list of unwindable things. */
+void
+add_unwind_protect (cleanup, arg)
+ Function *cleanup;
+ char *arg;
+{
+ without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
+}
+
+/* Remove the top unwind protect from the list. */
+void
+remove_unwind_protect ()
+{
+ if (unwind_protect_list)
+ without_interrupts
+ (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
+}
+
+/* Run the list of cleanup functions in unwind_protect_list. */
+void
+run_unwind_protects ()
+{
+ if (unwind_protect_list)
+ without_interrupts
+ (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
+}
+
+/* **************************************************************** */
+/* */
+/* The Actual Functions */
+/* */
+/* **************************************************************** */
+
+static void
+add_unwind_protect_internal (cleanup, arg)
+ Function *cleanup;
+ char *arg;
+{
+ UNWIND_ELT *elt;
+
+ elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT));
+ elt->cleanup = cleanup;
+ elt->arg = arg;
+ elt->next = unwind_protect_list;
+ unwind_protect_list = elt;
+}
+
+static void
+remove_unwind_protect_internal ()
+{
+ UNWIND_ELT *elt = unwind_protect_list;
+
+ if (elt)
+ {
+ unwind_protect_list = unwind_protect_list->next;
+ free (elt);
+ }
+}
+
+static void
+run_unwind_protects_internal ()
+{
+ UNWIND_ELT *t, *elt = unwind_protect_list;
+
+ while (elt)
+ {
+ /* This function can be run at strange times, like when unwinding
+ the entire world of unwind protects. Thus, we may come across
+ an element which is simply a label for a catch frame. Don't call
+ the non-existant function. */
+ if (elt->cleanup)
+ (*(elt->cleanup)) (elt->arg);
+
+ t = elt;
+ elt = elt->next;
+ free (t);
+ }
+ unwind_protect_list = elt;
+}
+
+static void
+unwind_frame_discard_internal (tag)
+ char *tag;
+{
+ UNWIND_ELT *elt;
+
+ while (elt = unwind_protect_list)
+ {
+ unwind_protect_list = unwind_protect_list->next;
+ if (!elt->cleanup && (STREQ (elt->arg, tag)))
+ {
+ free (elt);
+ break;
+ }
+ else
+ free (elt);
+ }
+}
+
+static void
+unwind_frame_run_internal (tag)
+ char *tag;
+{
+ UNWIND_ELT *elt;
+
+ while (elt = unwind_protect_list)
+ {
+ unwind_protect_list = elt->next;
+
+ /* If tag, then compare. */
+ if (!elt->cleanup)
+ {
+ if (STREQ (elt->arg, tag))
+ {
+ free (elt);
+ break;
+ }
+ free (elt);
+ continue;
+ }
+ else
+ {
+ (*(elt->cleanup)) (elt->arg);
+ free (elt);
+ }
+ }
+}
+
+/* Structure describing a saved variable and the value to restore it to. */
+typedef struct {
+ int *variable;
+ char *desired_setting;
+ int size;
+} SAVED_VAR;
+
+/* Restore the value of a variable, based on the contents of SV. If
+ sv->size is greater than sizeof (int), sv->desired_setting points to
+ a block of memory SIZE bytes long holding the value, rather than the
+ value itself. This block of memory is copied back into the variable. */
+static void
+restore_variable (sv)
+ SAVED_VAR *sv;
+{
+ if (sv->size > sizeof (int))
+ {
+ bcopy ((char *)sv->desired_setting, (char *)sv->variable, sv->size);
+ free (sv->desired_setting);
+ }
+ else
+ *(sv->variable) = (int)sv->desired_setting;
+
+ free (sv);
+}
+
+/* Save the value of a variable so it will be restored when unwind-protects
+ are run. VAR is a pointer to the variable. VALUE is the value to be
+ saved. SIZE is the size in bytes of VALUE. If SIZE is bigger than what
+ can be saved in an int, memory will be allocated and the value saved
+ into that using bcopy (). */
+void
+unwind_protect_var (var, value, size)
+ int *var;
+ char *value;
+ int size;
+{
+ SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR));
+
+ s->variable = var;
+ if (size > sizeof (int))
+ {
+ s->desired_setting = (char *)xmalloc (size);
+ bcopy (value, (char *)s->desired_setting, size);
+ }
+ else
+ s->desired_setting = value;
+ s->size = size;
+ add_unwind_protect ((Function *)restore_variable, (char *)s);
+}