update.
[chise/xemacs-chise.git-] / src / emacs.c
index fe1d119..e1208f2 100644 (file)
@@ -2,6 +2,7 @@
    Copyright (C) 1985, 1986, 1987, 1992, 1993, 1994
    Free Software Foundation, Inc.
    Copyright (C) 1995 Sun Microsystems, Inc.
    Copyright (C) 1985, 1986, 1987, 1992, 1993, 1994
    Free Software Foundation, Inc.
    Copyright (C) 1995 Sun Microsystems, Inc.
+   Copyright (C) 2000 Ben Wing.
 
 This file is part of XEmacs.
 
 
 This file is part of XEmacs.
 
@@ -22,6 +23,141 @@ Boston, MA 02111-1307, USA.  */
 
 /* Synched up with: Mule 2.0, FSF 19.28. */
 
 
 /* Synched up with: Mule 2.0, FSF 19.28. */
 
+/* Capsule summary of the various releases of Lucid Emacs/XEmacs and
+   FSF/GNU Emacs.  Provided here for use in cross-referencing version
+   releases and dates in comments, esp. in the authorship comments at
+   the beginning of each file.  More information about history can be
+   found in the beginning of the Internals Manual and in the About page.
+
+
+-- A time line for Lucid Emacs/XEmacs is
+
+version 19.0 shipped with Energize 1.0, April 1992.
+version 19.1 released June 4, 1992.
+version 19.2 released June 19, 1992.
+version 19.3 released September 9, 1992.
+version 19.4 released January 21, 1993.
+version 19.5 was a repackaging of 19.4 with a few bug fixes and
+  shipped with Energize 2.0.  Never released to the net.
+version 19.6 released April 9, 1993.
+version 19.7 was a repackaging of 19.6 with a few bug fixes and
+  shipped with Energize 2.1.  Never released to the net.
+version 19.8 released September 6, 1993.
+version 19.9 released January 12, 1994.
+version 19.10 released May 27, 1994.
+version 19.11 (first XEmacs) released September 13, 1994.
+version 19.12 released June 23, 1995.
+version 19.13 released September 1, 1995.
+version 19.14 released June 23, 1996.
+version 20.0 released February 9, 1997.
+version 19.15 released March 28, 1997.
+version 20.1 (not released to the net) April 15, 1997.
+version 20.2 released May 16, 1997.
+version 19.16 released October 31, 1997.
+version 20.3 (the first stable version of XEmacs 20.x) released
+  November 30, 1997.
+version 20.4 released February 28, 1998.
+
+
+-- A time line for GNU Emacs version 19 is
+
+version 19.7 (beta) (first beta release) released ??????; prob. late May 1993.
+version 19.8 (beta) released May 27, 1993.
+version 19.9 (beta) released May 27, 1993.
+version 19.10 (beta) released May 30, 1993.
+version 19.11 (beta) released June 1, 1993.
+version 19.12 (beta) released June 2, 1993.
+version 19.13 (beta) released June 8, 1993.
+version 19.14 (beta) released June 17, 1993.
+version 19.15 (beta) released June 19, 1993.
+version 19.16 (beta) released July 6, 1993.
+version 19.17 (beta) released late July, 1993.
+version 19.18 (beta) released August 9, 1993.
+version 19.19 (beta) released August 15, 1993.
+version 19.20 (beta) released November 17, 1993.
+version 19.21 (beta) released November 17, 1993.
+version 19.22 (beta) released November 28, 1993.
+version 19.23 (beta) released May 17, 1994.
+version 19.24 (beta) released May 16, 1994.
+version 19.25 (beta) released June 3, 1994.
+version 19.26 (beta) released September 11, 1994.
+version 19.27 (beta) released September 14, 1994.
+version 19.28 (first ``official'' release) released November 1, 1994.
+version 19.29 released June 21, 1995.
+version 19.30 released November 24, 1995.
+version 19.31 released May 25, 1996.
+version 19.32 released July 31, 1996.
+version 19.33 released August 11, 1996.
+version 19.34 released August 21, 1996.
+version 19.34b released September 6, 1996.
+
+
+-- A time line for GNU Emacs version 20 is
+
+version 20.1 released September 17, 1997.
+version 20.2 released September 20, 1997.
+version 20.3 released August 19, 1998.
+
+
+-- A time line for GNU Emacs version 18 and older is
+
+GNU Emacs version 15 (15.34) was released sometime in 1984 or 1985 and
+  shared some code with a version of Emacs written by James Gosling (the
+  same James Gosling who later created the Java language).
+GNU Emacs version 16 (first released version was 16.56) was released on
+  July 15, 1985.  All Gosling code was removed due to potential copyright
+  problems with the code.
+version 16.57: released on September 16, 1985.
+versions 16.58, 16.59: released on September 17, 1985.
+version 16.60: released on September 19, 1985.  These later version 16's
+  incorporated patches from the net, esp. for getting Emacs to work under
+  System V.
+version 17.36 (first official v17 release) released on December 20, 1985.
+  Included a TeX-able user manual.  First official unpatched version that
+   worked on vanilla System V machines.
+version 17.43 (second official v17 release) released on January 25, 1986.
+version 17.45 released on January 30, 1986.
+version 17.46 released on February 4, 1986.
+version 17.48 released on February 10, 1986.
+version 17.49 released on February 12, 1986.
+version 17.55 released on March 18, 1986.
+version 17.57 released on March 27, 1986.
+version 17.58 released on April 4, 1986.
+version 17.61 released on April 12, 1986.
+version 17.63 released on May 7, 1986.
+version 17.64 released on May 12, 1986.
+version 18.24 (a beta version) released on October 2, 1986.
+version 18.30 (a beta version) released on November 15, 1986.
+version 18.31 (a beta version) released on November 23, 1986.
+version 18.32 (a beta version) released on December 7, 1986.
+version 18.33 (a beta version) released on December 12, 1986.
+version 18.35 (a beta version) released on January 5, 1987.
+version 18.36 (a beta version) released on January 21, 1987.
+January 27, 1987: The Great Usenet Renaming.  net.emacs is now comp.emacs.
+version 18.37 (a beta version) released on February 12, 1987.
+version 18.38 (a beta version) released on March 3, 1987.
+version 18.39 (a beta version) released on March 14, 1987.
+version 18.40 (a beta version) released on March 18, 1987.
+version 18.41 (the first ``official'' release) released on March 22, 1987.
+version 18.45 released on June 2, 1987.
+version 18.46 released on June 9, 1987.
+version 18.47 released on June 18, 1987.
+version 18.48 released on September 3, 1987.
+version 18.49 released on September 18, 1987.
+version 18.50 released on February 13, 1988.
+version 18.51 released on May 7, 1988.
+version 18.52 released on September 1, 1988.
+version 18.53 released on February 24, 1989.
+version 18.54 released on April 26, 1989.
+version 18.55 released on August 23, 1989.  This is the earliest version
+  that is still available by FTP.
+version 18.56 released on January 17, 1991.
+version 18.57 released late January, 1991.
+version 18.58 released ?????.
+version 18.59 released October 31, 1992.
+
+*/
+
 /* Note: It is necessary to specify <config.h> and not "config.h" in
    order for the --srcdir type of compilation to work properly.
    Otherwise the config.h from the srcdir, rather than the one from
 /* Note: It is necessary to specify <config.h> and not "config.h" in
    order for the --srcdir type of compilation to work properly.
    Otherwise the config.h from the srcdir, rather than the one from
@@ -170,8 +306,10 @@ Lisp_Object Vconfigure_exec_prefix_directory, Vconfigure_prefix_directory;
    priority. */
 int emacs_priority;
 
    priority. */
 int emacs_priority;
 
-/* If non-zero a filter or a sentinel is running.  Tested to save the match
-   data on the first attempt to change it inside asynchronous code. */
+/* Some FSF junk with running_asynch_code, to preserve the match
+   data.  Not necessary because we don't call process filters
+   asynchronously (i.e. from within QUIT). */
+/* #### Delete this when merging the rest of my code */
 int running_asynch_code;
 
 /* If non-zero, a window-system was specified on the command line. */
 int running_asynch_code;
 
 /* If non-zero, a window-system was specified on the command line. */
@@ -241,11 +379,63 @@ Lisp_Object Qsave_buffers_kill_emacs;
 extern Lisp_Object Vlisp_EXEC_SUFFIXES;
 
 \f
 extern Lisp_Object Vlisp_EXEC_SUFFIXES;
 
 \f
-/* Signal code for the fatal signal that was received */
-static int fatal_error_code;
 
 
-/* Nonzero if handling a fatal error already */
-static int fatal_error_in_progress;
+/* Ben's capsule summary about expected and unexpected exits from XEmacs.
+
+   Expected exits occur when the user directs XEmacs to exit, for example
+   by pressing the close button on the only frame in XEmacs, or by typing
+   C-x C-c.  This runs `save-buffers-kill-emacs', which saves any necessary
+   buffers, and then exits using the primitive `kill-emacs'.
+
+   However, unexpected exits occur in a few different ways:
+
+     -- a memory access violation or other hardware-generated exception
+        occurs.  This is the worst possible problem to deal with, because
+        the fault can occur while XEmacs is in any state whatsoever, even
+        quite unstable ones.  As a result, we need to be *extremely* careful
+        what we do.
+     -- we are using one X display (or if we've used more, we've closed the
+        others already), and some hardware or other problem happens and
+        suddenly we've lost our connection to the display.  In this situation,
+       things are not so dire as in the last one; our code itself isn't
+       trashed, so we can continue execution as normal, after having set
+       things up so that we can exit at the appropriate time.  Our exit
+       still needs to be of the emergency nature; we have no displays, so
+       any attempts to use them will fail.  We simply want to auto-save
+       (the single most important thing to do during shut-down), do minimal
+       cleanup of stuff that has an independent existence outside of XEmacs,
+       and exit.
+
+       Currently, both unexpected exit scenarios described above set
+       preparing_for_armageddon to indicate that nonessential and possibly
+       dangerous things should not be done, specifically:
+
+       -- no garbage collection.
+       -- no hooks are run.
+       -- no messages of any sort from autosaving.
+       -- autosaving tries harder, ignoring certain failures.
+       -- existing frames are not deleted.
+
+       (Also, all places that set preparing_for_armageddon also
+       set dont_check_for_quit.  This happens separately because it's
+       also necessary to set other variables to make absolutely sure
+       no quitting happens.)
+
+       In the first scenario above (the access violation), we also set
+       fatal_error_in_progress.  This causes more things to not happen:
+
+       -- assertion failures do not abort.
+       -- printing code does not do code conversion or gettext when
+          printing to stdout/stderr.
+*/
+
+/* Nonzero if handling a fatal error already. */
+int fatal_error_in_progress;
+
+/* Non-nil means we're going down, so we better not run any hooks
+   or do other non-essential stuff. */
+int preparing_for_armageddon;
+
 
 static JMP_BUF run_temacs_catch;
 
 
 static JMP_BUF run_temacs_catch;
 
@@ -255,23 +445,54 @@ static char *run_temacs_args;
 static size_t run_temacs_argv_size;
 static size_t run_temacs_args_size;
 
 static size_t run_temacs_argv_size;
 static size_t run_temacs_args_size;
 
-static void shut_down_emacs (int sig, Lisp_Object stuff);
+static void shut_down_emacs (int sig, Lisp_Object stuff, int no_auto_save);
+
+static void
+ensure_no_quitting_from_now_on (void)
+{
+  /* make sure no quitting from now on!! */
+  dont_check_for_quit = 1;
+  Vinhibit_quit = Qt;
+  Vquit_flag = Qnil;
+}
 
 /* Handle bus errors, illegal instruction, etc. */
 SIGTYPE
 fatal_error_signal (int sig)
 {
 
 /* Handle bus errors, illegal instruction, etc. */
 SIGTYPE
 fatal_error_signal (int sig)
 {
-  fatal_error_code = sig;
-  signal (sig, SIG_DFL);
+  fatal_error_in_progress++;
+  preparing_for_armageddon = 1;
+
+  ensure_no_quitting_from_now_on ();
+
   /* Unblock the signal so that if the same signal gets sent in the
      code below, we avoid a deadlock. */
   /* Unblock the signal so that if the same signal gets sent in the
      code below, we avoid a deadlock. */
-  EMACS_UNBLOCK_SIGNAL (fatal_error_code);
+  EMACS_UNBLOCK_SIGNAL (sig);
+
+  /* Only try auto-saving first time through.  If we crash in auto-saving,
+     don't do it again. */
+  if (fatal_error_in_progress == 1)
+    {
+      Fdo_auto_save (Qt, Qnil); /* do this before anything hazardous */
+      /* Do this so that the variable has the same value of 2 regardless of
+        whether we made it through auto-saving correctly. */
+      fatal_error_in_progress++;
+    }
+  else if (fatal_error_in_progress == 2)
+    stderr_out ("WARNING: Unable to auto-save your files properly.\n"
+               "Some or all may in fact have been auto-saved.\n"
+               "\n");
+
+  /* Now, reset our signal handler, so the next time, we just die.
+     Don't do this before auto-saving. */
+  signal (sig, SIG_DFL);
 
 
+  /* Keep in mind that there's more than one signal that we can crash
+     on. */
   /* If fatal error occurs in code below, avoid infinite recursion.  */
   /* If fatal error occurs in code below, avoid infinite recursion.  */
-  if (! fatal_error_in_progress)
+  if (fatal_error_in_progress <= 2)
     {
     {
-      fatal_error_in_progress = dont_check_for_quit = 1;
-      shut_down_emacs (sig, Qnil);
+      shut_down_emacs (sig, Qnil, 1);
       stderr_out ("\nLisp backtrace follows:\n\n");
       Fbacktrace (Qexternal_debugging_output, Qt);
 # if 0 /* This is evil, rarely useful, and causes grief in some cases. */
       stderr_out ("\nLisp backtrace follows:\n\n");
       Fbacktrace (Qexternal_debugging_output, Qt);
 # if 0 /* This is evil, rarely useful, and causes grief in some cases. */
@@ -290,9 +511,62 @@ fatal_error_signal (int sig)
 # endif
     }
   /* Signal the same code; this time it will really be fatal. */
 # endif
     }
   /* Signal the same code; this time it will really be fatal. */
-  kill (getpid (), fatal_error_code);
+  kill (getpid (), sig);
   SIGRETURN;
 }
   SIGRETURN;
 }
+
+#ifdef _MSC_VER
+
+static DWORD
+mswindows_handle_hardware_exceptions (DWORD code)
+{
+  if (code != STATUS_ACCESS_VIOLATION && code != STATUS_ILLEGAL_INSTRUCTION
+      && code != STATUS_PRIVILEGED_INSTRUCTION
+      && code != STATUS_DATATYPE_MISALIGNMENT)
+    return EXCEPTION_CONTINUE_SEARCH;
+
+  /* I don't know if this filter is still wrapped in the outer __try, but
+     it doesn't hurt to have another one. --ben */
+  __try
+    {
+      fatal_error_in_progress++;
+      preparing_for_armageddon = 1;
+
+      ensure_no_quitting_from_now_on ();
+
+      /* Only try auto-saving first time through.  If we crash in auto-saving,
+        don't do it again. */
+      if (fatal_error_in_progress == 1)
+       {
+         Fdo_auto_save (Qt, Qnil); /* do this before anything hazardous */
+         /* Do this so that the variable has the same value of 2 regardless of
+            whether we made it through auto-saving correctly. */
+         fatal_error_in_progress++;
+       }
+      else if (fatal_error_in_progress == 2)
+       stderr_out ("WARNING: Unable to auto-save your files properly.\n"
+                   "Some or all may in fact have been auto-saved.\n"
+                   "\n");
+
+      /* If fatal error occurs in code below, avoid infinite recursion.  */
+      if (fatal_error_in_progress <= 2)
+       {
+         shut_down_emacs (-1, Qnil, 1);
+         stderr_out ("\nLisp backtrace follows:\n\n");
+         Fbacktrace (Qexternal_debugging_output, Qt);
+       }
+    }
+  /* VC++ documentation says that
+     GetExceptionCode() cannot be called inside the filter itself. */
+  __except (mswindows_handle_hardware_exceptions (GetExceptionCode ())) {}
+
+  /* pretend we didn't handle this, so that the debugger is invoked and/or
+     the normal GPF box appears. */
+  return EXCEPTION_CONTINUE_SEARCH;
+}
+
+#endif /* _MSC_VER */
+
 \f
 
 #ifdef SIGDANGER
 \f
 
 #ifdef SIGDANGER
@@ -1686,7 +1960,6 @@ main_1 (int argc, char **argv, char **envp, int restart)
 #endif
       reinit_vars_of_objects ();
       reinit_vars_of_print ();
 #endif
       reinit_vars_of_objects ();
       reinit_vars_of_print ();
-      reinit_vars_of_redisplay ();
       reinit_vars_of_search ();
       reinit_vars_of_undo ();
       reinit_vars_of_window ();
       reinit_vars_of_search ();
       reinit_vars_of_undo ();
       reinit_vars_of_window ();
@@ -2173,6 +2446,16 @@ Do not call this.  It will reinitialize your XEmacs.  You'll be sorry.
 int
 main (int argc, char **argv, char **envp)
 {
 int
 main (int argc, char **argv, char **envp)
 {
+
+#ifdef _MSC_VER
+  /* Under VC++, access violations and the like are not sent through
+     the standard signal() mechanism.  Rather, they need to be handled
+     using the Microsoft "structured exception handling" mechanism,
+     which vaguely resembles the C++ mechanisms. */
+  __try
+  {
+#endif
+
   int     volatile vol_argc = argc;
   char ** volatile vol_argv = argv;
   char ** volatile vol_envp = envp;
   int     volatile vol_argc = argc;
   char ** volatile vol_argv = argv;
   char ** volatile vol_envp = envp;
@@ -2290,6 +2573,14 @@ main (int argc, char **argv, char **envp)
   run_temacs_argc = -1;
 
   main_1 (vol_argc, vol_argv, vol_envp, restarted);
   run_temacs_argc = -1;
 
   main_1 (vol_argc, vol_argv, vol_envp, restarted);
+
+#ifdef _MSC_VER
+  }
+  /* VC++ documentation says that
+     GetExceptionCode() cannot be called inside the filter itself. */
+  __except (mswindows_handle_hardware_exceptions (GetExceptionCode ())) {}
+#endif
+
   return 0; /* unreached */
 }
 
   return 0; /* unreached */
 }
 
@@ -2334,9 +2625,7 @@ all of which are called before XEmacs is actually killed.
   if (!preparing_for_armageddon && !noninteractive)
     run_hook (Qkill_emacs_hook);
 
   if (!preparing_for_armageddon && !noninteractive)
     run_hook (Qkill_emacs_hook);
 
-  /* make sure no quitting from now on!! */
-  dont_check_for_quit = 1;
-  Vinhibit_quit = Qt;
+  ensure_no_quitting_from_now_on ();
 
   if (!preparing_for_armageddon)
     {
 
   if (!preparing_for_armageddon)
     {
@@ -2364,7 +2653,7 @@ all of which are called before XEmacs is actually killed.
 
   UNGCPRO;
 
 
   UNGCPRO;
 
-  shut_down_emacs (0, STRINGP (arg) ? arg : Qnil);
+  shut_down_emacs (0, STRINGP (arg) ? arg : Qnil, 0);
 
 #if defined(GNU_MALLOC)
   __free_hook =
 
 #if defined(GNU_MALLOC)
   __free_hook =
@@ -2387,45 +2676,54 @@ all of which are called before XEmacs is actually killed.
 
    If SIG is a signal number, print a message for it.
 
 
    If SIG is a signal number, print a message for it.
 
-   This is called by fatal signal handlers, X protocol error handlers,
-   and Fkill_emacs.  */
+   This is called by fatal signal handlers and Fkill_emacs.  It used to
+   be called by X protocol error handlers, but instead they now call
+   Fkill_emacs. */
 static void
 static void
-shut_down_emacs (int sig, Lisp_Object stuff)
+shut_down_emacs (int sig, Lisp_Object stuff, int no_auto_save)
 {
   /* This function can GC */
   /* Prevent running of hooks and other non-essential stuff
      from now on.  */
   preparing_for_armageddon = 1;
 
 {
   /* This function can GC */
   /* Prevent running of hooks and other non-essential stuff
      from now on.  */
   preparing_for_armageddon = 1;
 
-  /* In case frames or windows are screwed up, avoid assertion
-     failures here */
-  Vinhibit_quit = Qt;
+  ensure_no_quitting_from_now_on ();
 
 #ifdef QUANTIFY
   quantify_stop_recording_data ();
 #endif /* QUANTIFY */
 
 
 #ifdef QUANTIFY
   quantify_stop_recording_data ();
 #endif /* QUANTIFY */
 
-#if 0
   /* This is absolutely the most important thing to do, so make sure
      we do it now, before anything else.  We might have crashed and
      be in a weird inconsistent state, and potentially anything could
      set off another protection fault and cause us to bail out
      immediately. */
   /* This is absolutely the most important thing to do, so make sure
      we do it now, before anything else.  We might have crashed and
      be in a weird inconsistent state, and potentially anything could
      set off another protection fault and cause us to bail out
      immediately. */
-  /* I'm not removing the code entirely, yet.  We have run up against
+  /* Steve writes the following:
+
+     [[I'm not removing the code entirely, yet.  We have run up against
      a spate of problems in diagnosing crashes due to crashes within
      crashes.  It has very definitely been determined that code called
      during auto-saving cannot work if XEmacs crashed inside of GC.
      We already auto-save on an itimer so there cannot be too much
      unsaved stuff around, and if we get better crash reports we might
      a spate of problems in diagnosing crashes due to crashes within
      crashes.  It has very definitely been determined that code called
      during auto-saving cannot work if XEmacs crashed inside of GC.
      We already auto-save on an itimer so there cannot be too much
      unsaved stuff around, and if we get better crash reports we might
-     be able to get more problems fixed so I'm disabling this.  -slb */
-  Fdo_auto_save (Qt, Qnil); /* do this before anything hazardous */
-#endif
+     be able to get more problems fixed so I'm disabling this.  -slb]]
+
+     and DISABLES AUTO-SAVING ENTIRELY during crashes!  Way way bad idea.
+
+     Instead let's just be more intelligent about avoiding crashing
+     when possible, esp. nested crashes.
+  */
+  if (!no_auto_save)
+    Fdo_auto_save (Qt, Qnil); /* do this before anything hazardous */
 
   fflush (stdout);
   reset_all_consoles ();
   if (sig && sig != SIGTERM)
     {
 
   fflush (stdout);
   reset_all_consoles ();
   if (sig && sig != SIGTERM)
     {
-      stderr_out ("\nFatal error (%d).\n", sig);
+      if (sig == -1)
+       stderr_out ("\nFatal error.\n\n");
+      else
+       stderr_out ("\nFatal error (%d).\n\n", sig);
       stderr_out
        ("Your files have been auto-saved.\n"
         "Use `M-x recover-session' to recover them.\n"
       stderr_out
        ("Your files have been auto-saved.\n"
         "Use `M-x recover-session' to recover them.\n"
@@ -2444,6 +2742,7 @@ shut_down_emacs (int sig, Lisp_Object stuff)
 #endif
         "*MAKE SURE* to include the information in the command\n"
         "M-x describe-installation.\n"
 #endif
         "*MAKE SURE* to include the information in the command\n"
         "M-x describe-installation.\n"
+#ifndef _MSC_VER
         "\n"
         "If at all possible, *please* try to obtain a C stack backtrace;\n"
         "it will help us immensely in determining what went wrong.\n"
         "\n"
         "If at all possible, *please* try to obtain a C stack backtrace;\n"
         "it will help us immensely in determining what went wrong.\n"
@@ -2452,7 +2751,10 @@ shut_down_emacs (int sig, Lisp_Object stuff)
         "directory in which you started the editor, or maybe in your home\n"
         "directory), and type\n"
         "\n"
         "directory in which you started the editor, or maybe in your home\n"
         "directory), and type\n"
         "\n"
-        "  gdb ");
+        "  gdb "
+#endif
+        );
+#ifndef _MSC_VER
       {
        const char *name;
        char *dir = 0;
       {
        const char *name;
        char *dir = 0;
@@ -2479,6 +2781,7 @@ shut_down_emacs (int sig, Lisp_Object stuff)
         "(If you don't have GDB on your system, you might have DBX,\n"
         "or XDB, or SDB.  A similar procedure should work for all of\n"
         "these.  Ask your system administrator if you need more help.)\n");
         "(If you don't have GDB on your system, you might have DBX,\n"
         "or XDB, or SDB.  A similar procedure should work for all of\n"
         "these.  Ask your system administrator if you need more help.)\n");
+#endif /* _MSC_VER */
     }
 
   stuff_buffered_input (stuff);
     }
 
   stuff_buffered_input (stuff);
@@ -2742,17 +3045,75 @@ Non-nil return value means XEmacs is running without interactive terminal.
 #ifdef USE_ASSERTIONS
 /* This highly dubious kludge ... shut up Jamie, I'm tired of your slagging. */
 
 #ifdef USE_ASSERTIONS
 /* This highly dubious kludge ... shut up Jamie, I'm tired of your slagging. */
 
-DOESNT_RETURN
-assert_failed (const char *file, int line, const char *expr)
-{
-  stderr_out ("Fatal error: assertion failed, file %s, line %d, %s\n",
-             file, line, expr);
+static int in_assert_failed;
+static const char *assert_failed_file;
+static int assert_failed_line;
+static const char *assert_failed_expr;
+
+#ifdef fprintf
+#undef fprintf
+#endif
+
 #undef abort   /* avoid infinite #define loop... */
 #undef abort   /* avoid infinite #define loop... */
+
 #if defined (WINDOWSNT) && defined (DEBUG_XEMACS)
 #if defined (WINDOWSNT) && defined (DEBUG_XEMACS)
-  DebugBreak ();
-#elif !defined (ASSERTIONS_DONT_ABORT)
+#define enter_debugger() DebugBreak ()
+#else
+#define enter_debugger()
+#endif
+
+void
+assert_failed (const char *file, int line, const char *expr)
+{
+  /* If we're already crashing, let's not crash again.  This might be
+     critical to getting auto-saving working properly. */
+  if (fatal_error_in_progress)
+    return;
+
+  /* We are extremely paranoid so we sensibly deal with recursive
+     assertion failures. */
+  in_assert_failed++;
+
+  if (in_assert_failed >= 4)
+    _exit (-1);
+  else if (in_assert_failed == 3)
+    {
+      enter_debugger ();
+      _exit (-1);
+    }
+  else if (in_assert_failed == 2)
+    {
+      /* Not stderr_out(), which does additional things and may trigger
+        a recursive assertion failure.  fprintf was undeffed above, in
+        case it was encapsulated. */
+      fprintf (stderr,
+              "Fatal error: recursive assertion failure, "
+              "file %s, line %d, %s\n",
+              file, line, expr);
+      fprintf (stderr,
+              "Original assertion failure: file %s, line %d, %s\n",
+              assert_failed_file, assert_failed_line, assert_failed_expr);
+    }
+  else
+    {
+      assert_failed_file = file;
+      assert_failed_line = line;
+      assert_failed_expr = expr;
+      if (!initialized)
+       fprintf (stderr,
+                "Fatal error: assertion failed, file %s, line %d, %s\n",
+                file, line, expr);
+      else
+       stderr_out ("Fatal error: assertion failed, file %s, line %d, %s\n",
+                   file, line, expr);
+    }
+
+  enter_debugger ();
+#if !defined (ASSERTIONS_DONT_ABORT)
   abort ();
 #endif
   abort ();
 #endif
+  in_assert_failed = 0;
 }
 #endif /* USE_ASSERTIONS */
 
 }
 #endif /* USE_ASSERTIONS */
 
@@ -3176,19 +3537,6 @@ or were installed as packages, and are intended for XEmacs to use.
 */ );
   Vdata_directory_list = Qnil;
 
 */ );
   Vdata_directory_list = Qnil;
 
-#ifdef CLASH_DETECTION
-  DEFVAR_LISP ("configure-lock-directory", &Vconfigure_lock_directory /*
-For internal use by the build procedure only.
-configure's idea of what LOCK-DIRECTORY will be.
-*/ );
-#ifdef PATH_LOCK
-  Vconfigure_lock_directory = Ffile_name_as_directory
-    (build_string ((char *) PATH_LOCK));
-#else
-  Vconfigure_lock_directory = Qnil;
-#endif
-#endif /* CLASH_DETECTION */
-
   DEFVAR_LISP ("site-directory", &Vsite_directory /*
 *Directory of site-specific Lisp files that come with XEmacs.
 */ );
   DEFVAR_LISP ("site-directory", &Vsite_directory /*
 *Directory of site-specific Lisp files that come with XEmacs.
 */ );