/* Printing of backtraces and error messages
- * Copyright (C) 1996,1997,1998,1999,2000,2001, 2003, 2004, 2006, 2009 Free Software Foundation
+ * Copyright (C) 1996,1997,1998,1999,2000,2001, 2003, 2004, 2006, 2009, 2010, 2011 Free Software Foundation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
#include <stdio.h>
#include <ctype.h>
-#include <assert.h>
#include "libguile/_scm.h"
#include <io.h>
#endif
+#include "libguile/deprecation.h"
#include "libguile/stacks.h"
#include "libguile/srcprop.h"
#include "libguile/struct.h"
#include "libguile/frames.h"
#include "libguile/validate.h"
-#include "libguile/lang.h"
#include "libguile/backtrace.h"
#include "libguile/filesys.h"
#include "libguile/private-options.h"
* Note that these functions shouldn't generate errors themselves.
*/
+static SCM
+boot_print_exception (SCM port, SCM frame, SCM key, SCM args)
+#define FUNC_NAME "boot-print-exception"
+{
+ scm_puts ("Throw to key ", port);
+ scm_write (key, port);
+ scm_puts (" with args ", port);
+ scm_write (args, port);
+ return SCM_UNSPECIFIED;
+}
+#undef FUNC_NAME
+
+SCM
+scm_print_exception (SCM port, SCM frame, SCM key, SCM args)
+#define FUNC_NAME "print-exception"
+{
+ static SCM print_exception = SCM_BOOL_F;
+
+ SCM_VALIDATE_OPOUTPORT (1, port);
+ if (scm_is_true (frame))
+ SCM_VALIDATE_FRAME (2, frame);
+ SCM_VALIDATE_SYMBOL (3, key);
+ SCM_VALIDATE_LIST (4, args);
+
+ if (scm_is_false (print_exception))
+ print_exception =
+ scm_module_variable (scm_the_root_module (),
+ scm_from_latin1_symbol ("print-exception"));
+
+ return scm_call_4 (scm_variable_ref (print_exception),
+ port, frame, key, args);
+}
+#undef FUNC_NAME
+
+
+\f
+
/* Print parameters for error messages. */
#define DISPLAY_ERROR_MESSAGE_MAX_LEVEL 7
if (!(_cond)) \
return SCM_BOOL_F;
-SCM scm_the_last_stack_fluid_var;
-
-static void
-display_header (SCM source, SCM port)
-{
- scm_puts ("ERROR", port);
- scm_puts (": ", port);
-}
-
-
-struct display_error_message_data {
- SCM message;
- SCM args;
- SCM port;
- scm_print_state *pstate;
- int old_fancyp;
- int old_level;
- int old_length;
-};
-
-static SCM
-display_error_message (struct display_error_message_data *d)
-{
- if (scm_is_string (d->message) && scm_is_true (scm_list_p (d->args)))
- scm_simple_format (d->port, d->message, d->args);
- else
- scm_display (d->message, d->port);
- scm_newline (d->port);
- return SCM_UNSPECIFIED;
-}
-
-static void
-before_display_error_message (struct display_error_message_data *d)
-{
- scm_print_state *pstate = d->pstate;
- d->old_fancyp = pstate->fancyp;
- d->old_level = pstate->level;
- d->old_length = pstate->length;
- pstate->fancyp = 1;
- pstate->level = DISPLAY_ERROR_MESSAGE_MAX_LEVEL;
- pstate->length = DISPLAY_ERROR_MESSAGE_MAX_LENGTH;
-}
-
-static void
-after_display_error_message (struct display_error_message_data *d)
-{
- scm_print_state *pstate = d->pstate;
- pstate->fancyp = d->old_fancyp;
- pstate->level = d->old_level;
- pstate->length = d->old_length;
-}
void
scm_display_error_message (SCM message, SCM args, SCM port)
{
- struct display_error_message_data d;
- SCM print_state;
- scm_print_state *pstate;
-
- port = scm_i_port_with_print_state (port, SCM_UNDEFINED);
- print_state = SCM_PORT_WITH_PS_PS (port);
- pstate = SCM_PRINT_STATE (print_state);
-
- d.message = message;
- d.args = args;
- d.port = port;
- d.pstate = pstate;
- scm_internal_dynamic_wind ((scm_t_guard) before_display_error_message,
- (scm_t_inner) display_error_message,
- (scm_t_guard) after_display_error_message,
- &d,
- &d);
-}
-
-static void
-display_expression (SCM frame, SCM pname, SCM source, SCM port)
-{
- SCM print_state = scm_make_print_state ();
- scm_print_state *pstate = SCM_PRINT_STATE (print_state);
- pstate->writingp = 0;
- pstate->fancyp = 1;
- pstate->level = DISPLAY_EXPRESSION_MAX_LEVEL;
- pstate->length = DISPLAY_EXPRESSION_MAX_LENGTH;
- if (scm_is_symbol (pname) || scm_is_string (pname))
- {
- scm_puts ("In procedure ", port);
- scm_iprin1 (pname, port, pstate);
- }
- scm_puts (":\n", port);
- scm_free_print_state (print_state);
-}
-
-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 = a->subr;
-
- if (scm_is_symbol (pname) || scm_is_string (pname))
- {
- display_header (source, a->port);
- display_expression (current_frame, pname, source, a->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
- try 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_UNUSED)
-{
- 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_print_exception (port, SCM_BOOL_F, scm_misc_error_key,
+ scm_list_3 (SCM_BOOL_F, message, args));
}
* code should rather use the function scm_display_error.
*/
void
-scm_i_display_error (SCM stack, SCM port, SCM subr, SCM message, SCM args, SCM rest)
+scm_i_display_error (SCM frame, 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_t_catch_body) display_error_body, &a,
- (scm_t_catch_handler) display_error_handler, &data);
+ scm_print_exception (port, frame, scm_misc_error_key,
+ scm_list_3 (subr, message, args));
}
SCM_DEFINE (scm_display_error, "display-error", 6, 0, 0,
- (SCM stack, SCM port, SCM subr, SCM message, SCM args, SCM rest),
+ (SCM frame, SCM port, SCM subr, SCM message, SCM args, SCM rest),
"Display an error message to the output port @var{port}.\n"
- "@var{stack} is the saved stack for the error, @var{subr} is\n"
+ "@var{frame} is the frame in which the error occurred, @var{subr} is\n"
"the name of the procedure in which the error occurred and\n"
"@var{message} is the actual error message, which may contain\n"
"formatting instructions. These will format the arguments in\n"
{
SCM_VALIDATE_OUTPUT_PORT (2, port);
- scm_i_display_error (stack, port, subr, message, args, rest);
+#if SCM_ENABLE_DEPRECATED
+ if (SCM_STACKP (frame))
+ {
+ scm_c_issue_deprecation_warning
+ ("Passing a stack as the first argument to `scm_display_error' is "
+ "deprecated. Pass a frame instead.");
+ if (SCM_STACK_LENGTH (frame))
+ frame = scm_stack_ref (frame, SCM_INUM0);
+ else
+ frame = SCM_BOOL_F;
+ }
+#endif
+
+ scm_i_display_error (frame, port, subr, message, args, rest);
return SCM_UNSPECIFIED;
}
scm_print_state *pstate;
/* Create a string port used for adaptation of printing parameters. */
- sport = scm_mkstrport (SCM_INUM0,
- scm_make_string (scm_from_int (240),
- SCM_UNDEFINED),
+ sport = scm_mkstrport (SCM_INUM0, SCM_BOOL_F,
SCM_OPN | SCM_WRTNG,
FUNC_NAME);
#define FUNC_NAME "display_backtrace_body"
{
int n_frames, beg, end, n, i, j;
- int nfield, indent_p, indentation;
+ int nfield, indentation;
SCM frame, sport, print_state;
SCM last_file;
scm_print_state *pstate;
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,
- scm_make_string (scm_from_int (240), SCM_UNDEFINED),
+ sport = scm_mkstrport (SCM_INUM0, SCM_BOOL_F,
SCM_OPN | SCM_WRTNG,
FUNC_NAME);
pstate->fancyp = 1;
pstate->highlight_objects = a->highlight_objects;
- /* First find out if it's reasonable to do indentation. */
- indent_p = 0;
-
/* Determine size of frame number field. */
j = end;
for (i = 0; j > 0; ++i) j /= 10;
}
#undef FUNC_NAME
+static SCM
+error_during_backtrace (void *data, SCM tag, SCM throw_args)
+{
+ SCM port = PTR2SCM (data);
+
+ scm_puts ("Exception thrown while printing backtrace:\n", port);
+ scm_print_exception (port, SCM_BOOL_F, tag, throw_args);
+
+ return SCM_UNSPECIFIED;
+}
+
+
SCM_DEFINE (scm_display_backtrace_with_highlights, "display-backtrace", 2, 3, 0,
(SCM stack, SCM port, SCM first, SCM depth, SCM highlights),
"Display a backtrace to the output port @var{port}. @var{stack}\n"
#define FUNC_NAME s_scm_display_backtrace_with_highlights
{
struct display_backtrace_args a;
- struct display_error_handler_data data;
a.stack = stack;
a.port = port;
a.first = first;
a.highlight_objects = SCM_EOL;
else
a.highlight_objects = highlights;
- data.mode = "backtrace";
- data.port = port;
+
scm_internal_catch (SCM_BOOL_T,
(scm_t_catch_body) display_backtrace_body, &a,
- (scm_t_catch_handler) display_error_handler, &data);
+ (scm_t_catch_handler) error_during_backtrace, SCM2PTR (port));
+
return SCM_UNSPECIFIED;
}
#undef FUNC_NAME
SCM_DEFINE (scm_backtrace_with_highlights, "backtrace", 0, 1, 0,
(SCM highlights),
- "Display a backtrace of the stack saved by the last error\n"
- "to the current output port. If @var{highlights} is given\n"
- "it should be a list; the elements of this list will be\n"
- "highlighted wherever they appear in the backtrace.")
+ "Display a backtrace of the current stack to the current\n"
+ "output port. If @var{highlights} is given, it should be\n"
+ "a list; the elements of this list will be highlighted\n"
+ "wherever they appear in the backtrace.")
#define FUNC_NAME s_scm_backtrace_with_highlights
{
SCM port = scm_current_output_port ();
- SCM the_last_stack =
- scm_fluid_ref (SCM_VARIABLE_REF (scm_the_last_stack_fluid_var));
-
+ SCM stack = scm_make_stack (SCM_BOOL_T, SCM_EOL);
+
if (SCM_UNBNDP (highlights))
highlights = SCM_EOL;
- if (scm_is_true (the_last_stack))
- {
- scm_newline (port);
- scm_puts ("Backtrace:\n", port);
- scm_display_backtrace_with_highlights (the_last_stack,
- port,
- SCM_BOOL_F,
- SCM_BOOL_F,
- highlights);
- scm_newline (port);
- if (scm_is_false (SCM_VARIABLE_REF (scm_has_shown_backtrace_hint_p_var))
- && !SCM_BACKTRACE_P)
- {
- scm_puts ("Type \"(debug-enable 'backtrace)\" if you would like "
- "a backtrace\n"
- "automatically if an error occurs in the future.\n",
- port);
- SCM_VARIABLE_SET (scm_has_shown_backtrace_hint_p_var, SCM_BOOL_T);
- }
- }
- else
- {
- scm_puts ("No backtrace available.\n", port);
- }
+ scm_newline (port);
+ scm_puts ("Backtrace:\n", port);
+ scm_display_backtrace_with_highlights (stack, port, SCM_BOOL_F, SCM_BOOL_F,
+ highlights);
+ scm_newline (port);
+
return SCM_UNSPECIFIED;
}
#undef FUNC_NAME
void
scm_init_backtrace ()
{
- SCM f = scm_make_fluid ();
- scm_the_last_stack_fluid_var = scm_c_define ("the-last-stack", f);
-
+ scm_c_define_gsubr ("print-exception", 4, 0, 0, boot_print_exception);
#include "libguile/backtrace.x"
}