* Makefile.in: Regenerated.
[bpt/guile.git] / libguile / backtrace.c
index aec7c16..292bdf9 100644 (file)
@@ -1,5 +1,5 @@
 /* Printing of backtraces and error messages
- * Copyright (C) 1996 Mikael Djurfeldt
+ * Copyright (C) 1996,1997,1998 Free Software Foundation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -13,7 +13,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this software; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
  *
  * As a special exception, the Free Software Foundation gives permission
  * for additional uses of the text contained in its release of GUILE.
@@ -40,8 +41,7 @@
  * If you do not wish that, delete this exception notice.
  *
  * The author can be reached at djurfeldt@nada.kth.se
- * Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN
- */
+ * Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN */
 
 #include <stdio.h>
 #include "_scm.h"
@@ -50,6 +50,8 @@
 #include "genio.h"
 #include "struct.h"
 #include "strports.h"
+#include "throw.h"
+#include "fluids.h"
 
 #include "backtrace.h"
 
@@ -66,6 +68,8 @@
           return SCM_BOOL_F;
 #endif
 
+SCM scm_the_last_stack_fluid;
+
 static void display_header SCM_P ((SCM source, SCM port));
 static void
 display_header (source, port)
@@ -78,14 +82,18 @@ display_header (source, port)
   if (SCM_NIMP (fname) && SCM_STRINGP (fname))
     {
       scm_prin1 (fname, port, 0);
-      scm_gen_putc (':', port);
-      scm_prin1 (scm_source_property (source, scm_i_line), port, 0);
-      scm_gen_putc (':', port);
-      scm_prin1 (scm_source_property (source, scm_i_column), port, 0);
+      scm_putc (':', port);
+      scm_intprint (SCM_INUM (scm_source_property (source, scm_i_line)) + 1,
+                   10,
+                   port);
+      scm_putc (':', port);
+      scm_intprint (SCM_INUM (scm_source_property (source, scm_i_column)) + 1,
+                   10,
+                   port);
     }
   else
-    scm_gen_puts (scm_regular_string, "ERROR", port);
-  scm_gen_puts (scm_regular_string, ": ", port);
+    scm_puts ("ERROR", port);
+  scm_puts (": ", port);
 }
 
 
@@ -99,14 +107,16 @@ scm_display_error_message (message, args, port)
   char *start;
   char *p;
   
-  if (!SCM_STRINGP (message) || SCM_IMP (args) || !scm_list_p (args))
+  if (SCM_IMP (message) || !SCM_ROSTRINGP (message) || SCM_IMP (args)
+      || !scm_list_p (args))
     {
       scm_prin1 (message, port, 0);
-      scm_gen_putc ('\n', port);
+      scm_putc ('\n', port);
       return;
     }
 
-  start = SCM_CHARS (message);
+  SCM_COERCE_SUBSTR (message);
+  start = SCM_ROCHARS (message);
   for (p = start; *p != '\0'; ++p)
     if (*p == '%')
       {
@@ -121,13 +131,13 @@ scm_display_error_message (message, args, port)
        else
          continue;
 
-       scm_gen_write (scm_regular_string, start, p - start - 1, port);
+       scm_lfwrite (start, p - start - 1, port);
        scm_prin1 (SCM_CAR (args), port, writingp);
        args = SCM_CDR (args);
        start = p + 1;
       }
-  scm_gen_write (scm_regular_string, start, p - start, port);
-  scm_gen_putc ('\n', port);
+  scm_lfwrite (start, p - start, port);
+  scm_putc ('\n', port);
 }
 
 static void display_expression SCM_P ((SCM frame, SCM pname, SCM source, SCM port));
@@ -149,63 +159,118 @@ display_expression (frame, pname, source, port)
       if (SCM_NIMP (frame)
          && SCM_FRAMEP (frame)
          && SCM_FRAME_EVAL_ARGS_P (frame))
-       scm_gen_puts (scm_regular_string, "While evaluating arguments to ", port);
+       scm_puts ("While evaluating arguments to ", port);
       else
-       scm_gen_puts (scm_regular_string, "In procedure ", port);
+       scm_puts ("In procedure ", port);
       scm_iprin1 (pname, port, pstate);
       if (SCM_NIMP (source) && SCM_MEMOIZEDP (source))
        {
-         scm_gen_puts (scm_regular_string, " in expression ", port);
+         scm_puts (" in expression ", port);
          pstate->writingp = 1;
          scm_iprin1 (scm_unmemoize (source), port, pstate);
        }
     }
   else if (SCM_NIMP (source))
     {
-      scm_gen_puts (scm_regular_string, "In expression ", port);
+      scm_puts ("In expression ", port);
       pstate->writingp = 1;
       scm_iprin1 (scm_unmemoize (source), port, pstate);
     }
-  scm_gen_puts (scm_regular_string, ":\n", port);
+  scm_puts (":\n", port);
   scm_free_print_state (print_state);
 }
 
-SCM_PROC(s_display_error, "display-error", 6, 0, 0, scm_display_error);
-SCM
-scm_display_error (stack, port, subr, message, args, rest)
-     SCM stack;
-     SCM port;
-     SCM subr;
-     SCM message;
-     SCM args;
-     SCM rest;
+struct display_error_args {
+  SCM stack;
+  SCM port;
+  SCM subr;
+  SCM message;
+  SCM args;
+  SCM rest;
+};
+
+static SCM
+display_error_body (struct display_error_args *a)
 {
   SCM current_frame = SCM_BOOL_F;
   SCM source = SCM_BOOL_F;
   SCM pname = SCM_BOOL_F;
+  SCM prev_frame = SCM_BOOL_F;
+
   if (SCM_DEBUGGINGP
-      && SCM_NIMP (stack)
-      && SCM_STACKP (stack)
-      && SCM_STACK_LENGTH (stack) > 0)
+      && SCM_NIMP (a->stack)
+      && SCM_STACKP (a->stack)
+      && SCM_STACK_LENGTH (a->stack) > 0)
     {
-      current_frame = scm_stack_ref (stack, SCM_INUM0);
+      current_frame = scm_stack_ref (a->stack, SCM_INUM0);
       source = SCM_FRAME_SOURCE (current_frame);
-      if (!(SCM_NIMP (source) && SCM_MEMOIZEDP (source)))
-       source = SCM_FRAME_SOURCE (SCM_FRAME_PREV (current_frame));
+      prev_frame = SCM_FRAME_PREV (current_frame);
+      if (!(SCM_NIMP (source) && SCM_MEMOIZEDP (source))
+         && prev_frame != SCM_BOOL_F)
+       source = SCM_FRAME_SOURCE (prev_frame);
       if (SCM_FRAME_PROC_P (current_frame)
          && scm_procedure_p (SCM_FRAME_PROC (current_frame)) == SCM_BOOL_T)
        pname = scm_procedure_name (SCM_FRAME_PROC (current_frame));
     }
   if (!(SCM_NIMP (pname) && SCM_ROSTRINGP (pname)))
-    pname = subr;
-  if ((SCM_NIMP (source) && SCM_MEMOIZEDP (source))
-      || (SCM_NIMP (pname) && SCM_ROSTRINGP (pname)))
+    pname = a->subr;
+  if ((SCM_NIMP (pname) && SCM_ROSTRINGP (pname))
+      || (SCM_NIMP (source) && SCM_MEMOIZEDP (source)))
     {
-      display_header (source, port);
-      display_expression (current_frame, pname, source, port);
+      display_header (source, a->port);
+      display_expression (current_frame, pname, source, a->port);
     }
-  display_header (source, port);
-  scm_display_error_message (message, args, port);
+  display_header (source, a->port);
+  scm_display_error_message (a->message, a->args, a->port);
+  return SCM_UNSPECIFIED;
+}
+
+struct display_error_handler_data {
+  char *mode;
+  SCM port;
+};
+
+/* This is the exception handler for error reporting routines.
+   Note that it is very important that this handler *doesn't* try to
+   print more than the error tag, since the error very probably is
+   caused by an erroneous print call-back routine.  If we would
+   tru to print all objects, we would enter an infinite loop. */
+static SCM
+display_error_handler (struct display_error_handler_data *data,
+                      SCM tag, SCM args)
+{
+  SCM print_state = scm_make_print_state ();
+  scm_puts ("\nException during displaying of ", data->port);
+  scm_puts (data->mode, data->port);
+  scm_puts (": ", data->port);
+  scm_iprin1 (tag, data->port, SCM_PRINT_STATE (print_state));
+  scm_putc ('\n', data->port);
+  return SCM_UNSPECIFIED;
+}
+
+SCM_PROC(s_display_error, "display-error", 6, 0, 0, scm_display_error);
+SCM
+scm_display_error (stack, port, subr, message, args, rest)
+     SCM stack;
+     SCM port;
+     SCM subr;
+     SCM message;
+     SCM args;
+     SCM rest;
+{
+  struct display_error_args a;
+  struct display_error_handler_data data;
+  a.stack = stack;
+  a.port  = port;
+  a.subr  = subr;
+  a.message = message;
+  a.args  = args;
+  a.rest  = rest;
+  data.mode = "error";
+  data.port = port;
+  scm_internal_catch (SCM_BOOL_T,
+                     (scm_catch_body_t) display_error_body, &a,
+                     (scm_catch_handler_t) display_error_handler, &data);
   return SCM_UNSPECIFIED;
 }
 
@@ -217,7 +282,7 @@ indent (n, port)
 {
   int i;
   for (i = 0; i < n; ++i)
-    scm_gen_putc (' ', port);
+    scm_putc (' ', port);
 }
 
 static void display_frame_expr SCM_P ((char *hdr, SCM exp, char *tlr, int indentation, SCM sport, SCM port, scm_print_state *pstate));
@@ -231,16 +296,65 @@ display_frame_expr (hdr, exp, tlr, indentation, sport, port, pstate)
      SCM port;
      scm_print_state *pstate;
 {
-  pstate->level = 2;
-  pstate->length = 3;
   if (SCM_NIMP (exp) && SCM_CONSP (exp))
     {
       scm_iprlist (hdr, exp, tlr[0], port, pstate);
-      scm_gen_puts (scm_regular_string, &tlr[1], port);
+      scm_puts (&tlr[1], port);
     }
   else
     scm_iprin1 (exp, port, pstate);
-  scm_gen_putc ('\n', port);
+  scm_putc ('\n', port);
+}
+
+static void display_application SCM_P ((SCM frame, int indentation, SCM sport, SCM port, scm_print_state *pstate));
+static void
+display_application (frame, indentation, sport, port, pstate)
+     SCM frame;
+     int indentation;
+     SCM sport;
+     SCM port;
+     scm_print_state *pstate;
+{
+  SCM proc = SCM_FRAME_PROC (frame);
+  SCM name = (SCM_NFALSEP (scm_procedure_p (proc))
+             ? scm_procedure_name (proc)
+             : SCM_BOOL_F);
+  display_frame_expr ("[",
+                     scm_cons (SCM_NFALSEP (name) ? name : proc,
+                               SCM_FRAME_ARGS (frame)),
+                     SCM_FRAME_EVAL_ARGS_P (frame) ? " ..." : "]",
+                     indentation,
+                     sport,
+                     port,
+                     pstate);
+}
+
+SCM_PROC(s_display_application, "display-application", 1, 1, 0, scm_display_application);
+
+SCM
+scm_display_application (SCM frame, SCM port)
+{
+  if (SCM_UNBNDP (port))
+    port = scm_cur_outp;
+  if (SCM_FRAME_PROC_P (frame))
+    /* Display an application. */
+    {
+      SCM print_state;
+      scm_print_state *pstate;
+      
+      /* Create a print state for printing of frames. */
+      print_state = scm_make_print_state ();
+      pstate = SCM_PRINT_STATE (print_state);
+      pstate->writingp = 1;
+      pstate->fancyp = 1;
+      pstate->level = 2;
+      pstate->length = 9;
+      
+      display_application (frame, 0, SCM_BOOL_F, port, pstate); /*fixme*/
+      return SCM_BOOL_T;
+    }
+  else
+    return SCM_BOOL_F;
 }
 
 static void display_frame SCM_P ((SCM frame, int nfield, int indentation, SCM sport, SCM port, scm_print_state *pstate));
@@ -259,7 +373,7 @@ display_frame (frame, nfield, indentation, sport, port, pstate)
   if (!SCM_BACKWARDS_P && SCM_FRAME_OVERFLOW_P (frame))
     {
       indent (nfield + 1 + indentation, port);
-      scm_gen_puts (scm_regular_string, "...\n", port);
+      scm_puts ("...\n", port);
     }
 
   /* Check size of frame number. */
@@ -273,36 +387,26 @@ display_frame (frame, nfield, indentation, sport, port, pstate)
   scm_iprin1 (SCM_MAKINUM (n), port, pstate);
 
   /* Real frame marker */
-  scm_gen_putc (SCM_FRAME_REAL_P (frame) ? '*' : ' ', port);
+  scm_putc (SCM_FRAME_REAL_P (frame) ? '*' : ' ', port);
 
   /* Indentation. */
   indent (indentation, port);
 
   if (SCM_FRAME_PROC_P (frame))
     /* Display an application. */
-    {
-      SCM proc = SCM_FRAME_PROC (frame);
-      SCM name = (SCM_NFALSEP (scm_procedure_p (proc))
-                 ? scm_procedure_name (proc)
-                 : SCM_BOOL_F);
-      display_frame_expr ("[",
-                         scm_cons (SCM_NFALSEP (name) ? name : proc,
-                                   SCM_FRAME_ARGS (frame)),
-                         SCM_FRAME_EVAL_ARGS_P (frame) ? " ..." : "]",
-                         nfield + 1 + indentation,
-                         sport,
-                         port,
-                         pstate);
-    }
+    display_application (frame, nfield + 1 + indentation, sport, port, pstate);
   else
     /* Display a special form. */
     {
       SCM source = SCM_FRAME_SOURCE (frame);
-      SCM copy = scm_source_property (source, scm_i_copy);
+      SCM copy = (SCM_NIMP (source) && SCM_CONSP (source) 
+                 ? scm_source_property (source, scm_i_copy)
+                 : SCM_BOOL_F);
+      SCM umcopy = (SCM_NIMP (source) && SCM_MEMOIZEDP (source)
+                   ? scm_unmemoize (source)
+                   : SCM_BOOL_F);
       display_frame_expr ("(",
-                         SCM_NIMP (copy) && SCM_CONSP (copy)
-                         ? copy
-                         : scm_unmemoize (source),
+                         SCM_NIMP (copy) && SCM_CONSP (copy) ? copy : umcopy,
                          ")",
                          nfield + 1 + indentation,
                          sport,
@@ -314,37 +418,43 @@ display_frame (frame, nfield, indentation, sport, port, pstate)
   if (SCM_BACKWARDS_P && SCM_FRAME_OVERFLOW_P (frame))
     {
       indent (nfield + 1 + indentation, port);
-      scm_gen_puts (scm_regular_string, "...\n", port);
+      scm_puts ("...\n", port);
     }
 }
 
+struct display_backtrace_args {
+  SCM stack;
+  SCM port;
+  SCM first;
+  SCM depth;
+};
+
 SCM_PROC(s_display_backtrace, "display-backtrace", 2, 2, 0, scm_display_backtrace);
-SCM
-scm_display_backtrace (stack, port, first, depth)
-     SCM stack;
-     SCM port;
-     SCM first;
-     SCM depth;
+
+static SCM
+display_backtrace_body (struct display_backtrace_args *a)
 {
   int n_frames, beg, end, n, i, j;
   int nfield, indent_p, indentation;
   SCM frame, sport, print_state;
   scm_print_state *pstate;
 
+  a->port = SCM_COERCE_OUTPORT (a->port);
+
   /* Argument checking and extraction. */
-  SCM_ASSERT (SCM_NIMP (stack) && SCM_STACKP (stack),
-             stack,
+  SCM_ASSERT (SCM_NIMP (a->stack) && SCM_STACKP (a->stack),
+             a->stack,
              SCM_ARG1,
              s_display_backtrace);
-  SCM_ASSERT (SCM_NIMP (port) && SCM_OPOUTPORTP (port),
-             port,
+  SCM_ASSERT (SCM_NIMP (a->port) && SCM_OPOUTPORTP (a->port),
+             a->port,
              SCM_ARG2,
              s_display_backtrace);
-  n_frames = SCM_INUM (scm_stack_length (stack));
-  n = SCM_INUMP (depth) ? SCM_INUM (depth) : SCM_BACKTRACE_DEPTH;
+  n_frames = SCM_INUM (scm_stack_length (a->stack));
+  n = SCM_INUMP (a->depth) ? SCM_INUM (a->depth) : SCM_BACKTRACE_DEPTH;
   if (SCM_BACKWARDS_P)
     {
-      beg = SCM_INUMP (first) ? SCM_INUM (first) : 0;
+      beg = SCM_INUMP (a->first) ? SCM_INUM (a->first) : 0;
       end = beg + n - 1;
       if (end >= n_frames)
        end = n_frames - 1;
@@ -352,9 +462,9 @@ scm_display_backtrace (stack, port, first, depth)
     }
   else
     {
-      if (SCM_INUMP (first))
+      if (SCM_INUMP (a->first))
        {
-         beg = SCM_INUM (first);
+         beg = SCM_INUM (a->first);
          end = beg - n + 1;
          if (end < 0)
            end = 0;
@@ -368,8 +478,8 @@ scm_display_backtrace (stack, port, first, depth)
        }
       n = beg - end + 1;
     }
-  SCM_ASSERT (beg >= 0 && beg < n_frames, first, SCM_ARG3, s_display_backtrace);
-  SCM_ASSERT (n > 0, depth, SCM_ARG4, s_display_backtrace);
+  SCM_ASSERT (beg >= 0 && beg < n_frames, a->first, SCM_ARG3, s_display_backtrace);
+  SCM_ASSERT (n > 0, a->depth, SCM_ARG4, s_display_backtrace);
 
   /* Create a string port used for adaptation of printing parameters. */
   sport = scm_mkstrport (SCM_INUM0,
@@ -382,6 +492,8 @@ scm_display_backtrace (stack, port, first, depth)
   pstate = SCM_PRINT_STATE (print_state);
   pstate->writingp = 1;
   pstate->fancyp = 1;
+  pstate->level = 2;
+  pstate->length = 3;
 
   /* First find out if it's reasonable to do indentation. */
   if (SCM_BACKWARDS_P)
@@ -389,7 +501,7 @@ scm_display_backtrace (stack, port, first, depth)
   else
     {
       indent_p = 1;
-      frame = scm_stack_ref (stack, SCM_MAKINUM (beg));
+      frame = scm_stack_ref (a->stack, SCM_MAKINUM (beg));
       for (i = 0, j = 0; i < n; ++i)
        {
          if (SCM_FRAME_REAL_P (frame))
@@ -406,37 +518,59 @@ scm_display_backtrace (stack, port, first, depth)
     }
   
   /* Determine size of frame number field. */
-  j = SCM_FRAME_NUMBER (scm_stack_ref (stack, SCM_MAKINUM (end)));
+  j = SCM_FRAME_NUMBER (scm_stack_ref (a->stack, SCM_MAKINUM (end)));
   for (i = 0; j > 0; ++i) j /= 10;
   nfield = i ? i : 1;
   
-  scm_gen_puts (scm_regular_string, "Backtrace:\n", port);
+  scm_puts ("Backtrace:\n", a->port);
 
   /* Print frames. */
-  frame = scm_stack_ref (stack, SCM_MAKINUM (beg));
+  frame = scm_stack_ref (a->stack, SCM_MAKINUM (beg));
   indentation = 1;
-  display_frame (frame, nfield, indentation, sport, port, pstate);
+  display_frame (frame, nfield, indentation, sport, a->port, pstate);
   for (i = 1; i < n; ++i)
     {
       if (indent_p && SCM_FRAME_EVAL_ARGS_P (frame))
        ++indentation;
       frame = SCM_BACKWARDS_P ? SCM_FRAME_PREV (frame) : SCM_FRAME_NEXT (frame);
-      display_frame (frame, nfield, indentation, sport, port, pstate);
+      display_frame (frame, nfield, indentation, sport, a->port, pstate);
     }
-  
+
   return SCM_UNSPECIFIED;
 }
 
-SCM_GLOBAL (scm_has_shown_backtrace_hint_p_var, "has-shown-backtrace-hint?");
+SCM
+scm_display_backtrace (stack, port, first, depth)
+     SCM stack;
+     SCM port;
+     SCM first;
+     SCM depth;
+{
+  struct display_backtrace_args a;
+  struct display_error_handler_data data;
+  a.stack = stack;
+  a.port  = port;
+  a.first = first;
+  a.depth = depth;
+  data.mode = "backtrace";
+  data.port = port;
+  scm_internal_catch (SCM_BOOL_T,
+                     (scm_catch_body_t) display_backtrace_body, &a,
+                     (scm_catch_handler_t) display_error_handler, &data);
+  return SCM_UNSPECIFIED;
+}
+
+SCM_VCELL (scm_has_shown_backtrace_hint_p_var, "has-shown-backtrace-hint?");
 
 SCM_PROC(s_backtrace, "backtrace", 0, 0, 0, scm_backtrace);
 SCM
 scm_backtrace ()
 {
-  if (SCM_NFALSEP (SCM_CDR (scm_the_last_stack_var)))
+  SCM the_last_stack = scm_fluid_ref (SCM_CDR (scm_the_last_stack_fluid));
+  if (SCM_NFALSEP (the_last_stack))
     {
       scm_newline (scm_cur_outp);
-      scm_display_backtrace (SCM_CDR (scm_the_last_stack_var),
+      scm_display_backtrace (the_last_stack,
                             scm_cur_outp,
                             SCM_UNDEFINED,
                             SCM_UNDEFINED);
@@ -444,18 +578,16 @@ scm_backtrace ()
       if (SCM_FALSEP (SCM_CDR (scm_has_shown_backtrace_hint_p_var))
          && !SCM_BACKTRACE_P)
        {
-         scm_gen_puts (scm_regular_string,
-                       "Type \"(debug-enable 'backtrace)\" if you would like a backtrace
-automatically if an error occurs in the future.\n",
-                       scm_cur_outp);
+         scm_puts ("Type \"(debug-enable 'backtrace)\" if you would like "
+                   "a backtrace\n"
+                   "automatically if an error occurs in the future.\n",
+                   scm_cur_outp);
          SCM_SETCDR (scm_has_shown_backtrace_hint_p_var, SCM_BOOL_T);
        }
     }
   else
     {
-      scm_gen_puts (scm_regular_string,
-                   "No backtrace available.\n",
-                   scm_cur_outp);
+      scm_puts ("No backtrace available.\n", scm_cur_outp);
     }
   return SCM_UNSPECIFIED;
 }
@@ -465,7 +597,8 @@ automatically if an error occurs in the future.\n",
 void
 scm_init_backtrace ()
 {
-  scm_the_last_stack_var = scm_sysintern ("the-last-stack", SCM_BOOL_F);
+  SCM f = scm_make_fluid ();
+  scm_the_last_stack_fluid = scm_sysintern ("the-last-stack", f);
 
 #include "backtrace.x"
 }