changeset 4791:62f2fb593455

[project @ 2004-02-20 18:02:59 by jwe]
author jwe
date Fri, 20 Feb 2004 18:02:59 +0000
parents 91a84c9bdadb
children d2038299c683
files liboctave/ChangeLog liboctave/Range.cc src/ChangeLog src/load-save.cc src/load-save.h src/ov-base-scalar.h src/ov-base.h src/ov-bool-mat.h src/ov-cell.cc src/ov-cell.h src/ov-ch-mat.h src/ov-cx-mat.h src/ov-list.cc src/ov-list.h src/ov-range.h src/ov-re-mat.h src/ov-streamoff.h src/ov-struct.cc src/ov-struct.h src/ov.cc src/ov.h src/pr-output.cc src/sighandlers.cc
diffstat 23 files changed, 370 insertions(+), 100 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/ChangeLog	Thu Feb 19 20:15:18 2004 +0000
+++ b/liboctave/ChangeLog	Fri Feb 20 18:02:59 2004 +0000
@@ -1,3 +1,9 @@
+2004-02-20  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* Range.cc (Range::matrix_value, Range::min, Range::max):
+	Don't compute values beyond the limits of the range.
+	(operator << (std::ostream&, const Range&)): Likewise.
+
 2004-02-18  John W. Eaton  <jwe@bevo.che.wisc.edu>
 
 	* oct-fftw.cc (octave_fftw_planner::create_plan):
--- a/liboctave/Range.cc	Thu Feb 19 20:15:18 2004 +0000
+++ b/liboctave/Range.cc	Fri Feb 20 18:02:59 2004 +0000
@@ -61,7 +61,17 @@
       double b = rng_base;
       double increment = rng_inc;
       for (int i = 0; i < rng_nelem; i++)
-	retval.elem (0, i) = b + i * increment;
+	retval(i) = b + i * increment;
+
+      // On some machines (x86 with extended precision floating point
+      // arithmetic, for example) it is possible that we can overshoot
+      // the limit by approximately the machine precision even though
+      // we were very careful in our calculation of the number of
+      // elements.
+
+      if ((rng_inc > 0 && retval(rng_nelem-1) > rng_limit)
+	  || (rng_inc < 0 && retval(rng_nelem-1) < rng_limit))
+	retval(rng_nelem-1) = rng_limit;
     }
 
   return retval;
@@ -78,7 +88,15 @@
       if (rng_inc > 0)
 	retval = rng_base;
       else
-	retval = rng_base + (rng_nelem - 1) * rng_inc;
+	{
+	  retval = rng_base + (rng_nelem - 1) * rng_inc;
+
+	  // See the note in the matrix_value method above.
+
+	  if (retval < rng_limit)
+	    retval = rng_limit;
+	}
+
     }
   return retval;
 }
@@ -90,7 +108,14 @@
   if (rng_nelem > 0)
     {
       if (rng_inc > 0)
-	retval = rng_base + (rng_nelem - 1) * rng_inc;
+	{
+	  retval = rng_base + (rng_nelem - 1) * rng_inc;
+
+	  // See the note in the matrix_value method above.
+
+	  if (retval > rng_limit)
+	    retval = rng_limit;
+	}
       else
 	retval = rng_base;
     }
@@ -125,10 +150,13 @@
   double increment = a.inc ();
   int num_elem = a.nelem ();
 
-  for (int i = 0; i < num_elem; i++)
+  for (int i = 0; i < num_elem-1; i++)
     os << b + i * increment << " ";
 
-  os << "\n";
+  // Prevent overshoot.  See comment in the matrix_value method
+  // above.
+
+  os << (increment > 0 ? a.max () : a.min ()) << "\n";
 
   return os;
 }
--- a/src/ChangeLog	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ChangeLog	Fri Feb 20 18:02:59 2004 +0000
@@ -1,5 +1,50 @@
+2004-02-20  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* pr-output.cc (octave_print_internal (std::ostream&, const
+	Range&, bool, int)): Don't print values beyond the limits of the
+	range.
+
+	* sighandlers.cc (sigint_handler): Print message after two
+	consecutive interrupts, dump core after three or more.
+
+	* load-save.cc (dump_octave_core): Handle core size limit.
+	Rename from save_user_variables.  Change all callers.
+	(Fload, dump_octave_core, Fsave): Open HDF5 fils in binary mode.
+	(do_save): Extract switch over file types to separate function.
+
+	* load-save.cc (Voctave_core_file_limit): New variable.
+	(octave_core_file_limit): New function.
+	(symbols_of_load_save): Add DEFVAR for octave_core_file_limit.
+
+	* load-save.cc (Voctave_core_file_name): New variable.
+	(octave_core_file_name): New function.
+	(symbols_of_load_save): Add DEFVAR for octave_core_file_name.
+
+	* load-save.cc (Voctave_core_file_format):
+	Rename from Voctave_core_format.
+	(octave_core_file_format): Rename from octave_core_format.
+	(symbols_of_load_save): Fix DEFVAR to match.
+
 2004-02-19  John W. Eaton  <jwe@bevo.che.wisc.edu>
 
+	* ov.cc (Fsizeof): New function.
+
+	* ov.h (octave_value::byte_size): New function.
+	* ov-base.h (octave_base_value::byte_size): New function.
+	* ov-base-scalar.h (octave_base_scalar::byte_size): New function.
+	* ov-bool-mat.h (octave_bool_matrix::byte_size): New function.
+	* ov-ch-mat.h (octave_char_matrix::byte_size): New function.
+	* ov-cx-mat.h (octave_complex_matrix::byte_size): New function.
+	* ov-re-mat.h (octave_matrix::byte_size): New function.
+	* ov-range.h (octave_range::byte_size): New function.
+	* ov-cell.cc (octave_cell::byte_size): New function.
+	* ov-cell.h: Provide decl.
+	* ov-struct.cc (octave_struct::byte_size): New function.
+	* ov-struct.h: Provide decl.
+	* ov-streamoff.h (octave_streamoff::byte_size): New function.
+	* ov-list.cc (octave_list::byte_size): New function.
+	* ov-list.h: Provide decl.
+
 	* xpow.cc (elem_xpow (const Matrix&, double)):
 	Convert both operands to Complex if any element of A is negative.
 	(elem_xpow (const NDArray&, double)): Likewise.
--- a/src/load-save.cc	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/load-save.cc	Fri Feb 20 18:02:59 2004 +0000
@@ -83,13 +83,20 @@
 // Write octave-core file if Octave crashes or is killed by a signal.
 static bool Vcrash_dumps_octave_core;
 
+// The maximum amount of memory (in kilobytes) that we will attempt to
+// write to the Octave core file.
+static double Voctave_core_file_limit;
+
+// The name of the Octave core file.
+static std::string Voctave_core_file_name;
+
 // The default output format.  May be one of "binary", "text",
 // "mat-binary", or "hdf5".
 static std::string Vdefault_save_format;
 
-// The output format for octave-core files.  May be one of "binary",
+// The output format for Octave core files.  May be one of "binary",
 // "text", "mat-binary", or "hdf5".
-static std::string Voctave_core_format;
+static std::string Voctave_core_file_format;
 
 // The format string for the comment line at the top of text-format
 // save files.  Passed to strftime.  Should begin with `#' and contain
@@ -738,9 +745,13 @@
 	  i++;
 
 	  std::ios::openmode mode = std::ios::in;
-	  if (format == LS_BINARY ||
-	      format == LS_MAT_BINARY ||
-	      format == LS_MAT5_BINARY)
+
+	  if (format == LS_BINARY
+#ifdef HAVE_HDF5
+	      || format == LS_HDF5
+#endif
+	      || format == LS_MAT_BINARY
+	      || format == LS_MAT5_BINARY)
 	    mode |= std::ios::binary;
 
 	  std::ifstream file (fname.c_str (), mode);
@@ -818,27 +829,12 @@
   return false;
 }
 
-// Save the info from sr on stream os in the format specified by fmt.
-
-void
-do_save (std::ostream& os, symbol_record *sr, load_save_format fmt,
-	 int save_as_floats, bool& infnan_warned)
+static void
+do_save (std::ostream& os, const octave_value& tc,
+	 const std::string& name, const std::string& help,
+	 int global, load_save_format fmt, bool save_as_floats,
+	 bool& infnan_warned)
 {
-  if (! sr->is_variable ())
-    {
-      error ("save: can only save variables, not functions");
-      return;
-    }
-
-  std::string name = sr->name ();
-  std::string help = sr->help ();
-  int global = sr->is_linked_to_global ();
-
-  octave_value tc = sr->def ();
-
-  if (tc.is_undefined ())
-    return;
-
   switch (fmt)
     {
     case LS_ASCII:
@@ -869,13 +865,39 @@
     }
 }
 
+// Save the info from SR on stream OS in the format specified by FMT.
+
+void
+do_save (std::ostream& os, symbol_record *sr, load_save_format fmt,
+	 bool save_as_floats, bool& infnan_warned)
+{
+  if (! sr->is_variable ())
+    {
+      error ("save: can only save variables, not functions");
+      return;
+    }
+
+  octave_value tc = sr->def ();
+
+  if (tc.is_defined ())
+    {
+      std::string name = sr->name ();
+      std::string help = sr->help ();
+
+      int global = sr->is_linked_to_global ();
+
+      do_save (os, tc, name, help, global, fmt, save_as_floats,
+	       infnan_warned);
+    }
+}
+
 // Save variables with names matching PATTERN on stream OS in the
 // format specified by FMT.  If SAVE_BUILTINS is TRUE, also save
 // builtin variables with names that match PATTERN.
 
 static int
 save_vars (std::ostream& os, const std::string& pattern, bool save_builtins,
-	   load_save_format fmt, int save_as_floats)
+	   load_save_format fmt, bool save_as_floats)
 {
   Array<symbol_record *> vars = curr_sym_tab->glob
     (pattern, symbol_record::USER_VARIABLE, SYMTAB_ALL_SCOPES);
@@ -886,7 +908,7 @@
 
   for (int i = 0; i < saved; i++)
     {
-      do_save (os, vars (i), fmt, save_as_floats, infnan_warned);
+      do_save (os, vars(i), fmt, save_as_floats, infnan_warned);
 
       if (error_state)
 	break;
@@ -903,7 +925,7 @@
 
       for (int i = 0; i < count; i++)
 	{
-	  do_save (os, vars (i), fmt, save_as_floats, infnan_warned);
+	  do_save (os, vars(i), fmt, save_as_floats, infnan_warned);
 
 	  if (error_state)
 	    break;
@@ -1039,23 +1061,79 @@
 }
 
 void
-save_user_variables (void)
+dump_octave_core (std::ostream& os, const char *fname, load_save_format fmt)
+{
+  write_header (os, fmt);
+
+  Array<symbol_record *> vars = curr_sym_tab->glob
+    ("*", symbol_record::USER_VARIABLE, SYMTAB_ALL_SCOPES);
+
+  int num_to_save = vars.length ();
+
+  bool infnan_warned = false;
+
+  double save_mem_size = 0;
+
+  for (int i = 0; i < num_to_save; i++)
+    {
+      symbol_record *sr = vars(i);
+
+      if (sr->is_variable ())
+	{
+	  octave_value tc = sr->def ();
+
+	  if (tc.is_defined ())
+	    {
+	      double tc_size = tc.byte_size () / 1024;
+
+	      // XXX FIXME XXX -- maybe we should try to throw out hte
+	      // largest first...
+
+	      if (Voctave_core_file_limit < 0
+		  || save_mem_size + tc_size < Voctave_core_file_limit)
+		{
+		  save_mem_size += tc_size;
+
+		  std::string name = sr->name ();
+		  std::string help = sr->help ();
+
+		  int global = sr->is_linked_to_global ();
+
+		  do_save (os, tc, name, help, global, fmt, false,
+			   infnan_warned);
+
+		  if (error_state)
+		    break;
+		}
+	    }
+	}
+    }
+
+  message (0, "save to `%s' complete", fname);
+}
+
+void
+dump_octave_core (void)
 {
   if (Vcrash_dumps_octave_core)
     {
       // XXX FIXME XXX -- should choose better file name?
 
-      const char *fname = "octave-core";
+      const char *fname = Voctave_core_file_name.c_str ();
 
       message (0, "attempting to save variables to `%s'...", fname);
 
       load_save_format format
-	= get_save_format (Voctave_core_format, LS_BINARY);
+	= get_save_format (Voctave_core_file_format, LS_BINARY);
 
       std::ios::openmode mode = std::ios::out|std::ios::trunc;
-      if (format == LS_BINARY ||
-	  format == LS_MAT_BINARY ||
-	  format == LS_MAT5_BINARY)
+
+      if (format == LS_BINARY
+#ifdef HAVE_HDF5
+	  || format == LS_HDF5
+#endif
+	  || format == LS_MAT_BINARY
+	  || format == LS_MAT5_BINARY)
 	mode |= std::ios::binary;
 
 #ifdef HAVE_HDF5
@@ -1065,10 +1143,7 @@
 
 	  if (file.file_id >= 0)
 	    {
-	      save_vars (string_vector (), 0, 0, file,
-			 false, format, false, true);
-
-	      message (0, "save to `%s' complete", fname);
+	      dump_octave_core (file, fname, format);
 
 	      file.close ();
 	    }
@@ -1084,9 +1159,8 @@
 	  
 	  if (file)
 	    {
-	      save_vars (string_vector (), 0, 0, file,
-			 false, format, false, true);
-	      message (0, "save to `%s' complete", fname);
+	      dump_octave_core (file, fname, format);
+
 	      file.close ();
 	    }
 	  else
@@ -1295,9 +1369,13 @@
       i++;
 
       std::ios::openmode mode = std::ios::out;
-      if (format == LS_BINARY ||
-	  format == LS_MAT_BINARY ||
-	  format == LS_MAT5_BINARY)
+
+      if (format == LS_BINARY
+#ifdef HAVE_HDF5
+	  || format == LS_HDF5
+#endif
+	  || format == LS_MAT_BINARY
+	  || format == LS_MAT5_BINARY)
 	mode |= std::ios::binary;
 
       mode |= append ? std::ios::ate : std::ios::trunc;
@@ -1374,19 +1452,53 @@
 }
 
 static int
-octave_core_format (void)
+octave_core_file_limit (void)
+{
+  double val;
+
+  if (builtin_real_scalar_variable ("octave_core_file_limit", val))
+    {
+      Voctave_core_file_limit = val;
+      return 0;
+    }
+  else
+    gripe_invalid_value_specified ("octave_core_file_limit");
+
+  return -1;
+}
+
+static int
+octave_core_file_name (void)
 {
   int status = 0;
 
-  std::string s = builtin_string_variable ("octave_core_format");
+  std::string s = builtin_string_variable ("octave_core_file_name");
 
   if (s.empty ())
     {
-      gripe_invalid_value_specified ("octave_core_format");
+      gripe_invalid_value_specified ("octave_core_file_name");
       status = -1;
     }
   else
-    Voctave_core_format = s;
+    Voctave_core_file_name = s;
+
+  return status;
+}
+
+static int
+octave_core_file_format (void)
+{
+  int status = 0;
+
+  std::string s = builtin_string_variable ("octave_core_file_format");
+
+  if (s.empty ())
+    {
+      gripe_invalid_value_specified ("octave_core_file_format");
+      status = -1;
+    }
+  else
+    Voctave_core_file_format = s;
 
   return status;
 }
@@ -1430,6 +1542,7 @@
 If this variable is set to a nonzero value, Octave tries to save all\n\
 current variables the the file \"octave-core\" if it crashes or receives a\n\
 hangup, terminate or similar signal.  The default value is 1.\n\
+@seealso{octave_core_file_limit, octave_core_file_name, and octave_core_file_format}\n\
 @end defvr");
 
   DEFVAR (default_save_format, "ascii", default_save_format,
@@ -1439,18 +1552,38 @@
 It should have one of the following values: @code{\"ascii\"},\n\
 @code{\"binary\"}, @code{float-binary}, or @code{\"mat-binary\"}.  The\n\
 initial default save format is Octave's text format.\n\
-@seealso{octave_core_format}\n\
+@end defvr");
+
+  DEFVAR (octave_core_file_limit, -1.0, octave_core_file_limit,
+    "-*- texinfo -*-\n\
+@defvr {Built-in Variable} octave_core_file_limit\n\
+The maximum amount of memory (in kilobytes) of the top-level workspace\n\
+that Octave will attempt to write when saving data to the\n\
+@var{octave_core_file_name}.  If @var{octave_core_file_format} is a\n\
+binary format, then @var{octave_core_file_limit} will be approximately\n\
+the maximum size of the file.  If a text file format is used, then the\n\
+file could be much larger than the limit.\n\
+The default value is -1 (unlimited)\n\
+@seealso{crash_dumps_octave_core, octave_core_file_name, and octave_core_file_format}\n\
 @end defvr");
 
-  DEFVAR (octave_core_format, "binary", octave_core_format,
+  DEFVAR (octave_core_file_name, "octave-core", octave_core_file_name,
     "-*- texinfo -*-\n\
-@defvr {Built-in Variable} octave_core_format\n\
+@defvr {Built-in Variable} octave_core_file_name\n\
+The name of the file used for saving data from the top-level workspace\n\
+when Octave aborts.  The default value is @code{\"octave-core\"}\n\
+@seealso{crash_dumps_octave_core, octave_core_file_name, and octave_core_file_format}\n\
+@end defvr");
+
+  DEFVAR (octave_core_file_format, "binary", octave_core_file_format,
+    "-*- texinfo -*-\n\
+@defvr {Built-in Variable} octave_core_file_format\n\
 If Octave aborts, it attempts to save the contents of the top-level\n\
 workspace in a file using this format.  The value of\n\
-@code{octave_core_format} should have one of the following values:\n\
+@code{octave_core_file_format} should have one of the following values:\n\
 @code{\"ascii\"}, @code{\"binary\"}, @code{float-binary}, or\n\
 @code{\"mat-binary\"}.  The default value is Octave's binary format.\n\
-@seealso{default_save_format}\n\
+@seealso{crash_dumps_octave_core, octave_core_file_name, and octave_core_file_limit}\n\
 @end defvr");
 
   DEFVAR (save_header_format_string, default_save_header_format (),
--- a/src/load-save.h	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/load-save.h	Fri Feb 20 18:02:59 2004 +0000
@@ -50,8 +50,7 @@
 save_three_d (std::ostream& os, const octave_value& t,
 	      bool parametric = false);
 
-extern void
-save_user_variables (void);
+extern void dump_octave_core (void);
 
 extern int
 read_binary_file_header (std::istream& is, bool& swap,
@@ -66,7 +65,7 @@
 
 extern void
 do_save (std::ostream& os, symbol_record *sr, load_save_format fmt,
-	 int save_as_floats, bool& infnan_warned);
+	 bool save_as_floats, bool& infnan_warned);
 
 extern void
 write_header (std::ostream& os, load_save_format format);
--- a/src/ov-base-scalar.h	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-base-scalar.h	Fri Feb 20 18:02:59 2004 +0000
@@ -81,6 +81,8 @@
 
   dim_vector dims (void) const { static dim_vector dv (1, 1); return dv; }
 
+  size_t byte_size (void) const { return sizeof (ST); }
+
   octave_value all (int = 0) const { return (scalar != 0.0); }
 
   octave_value any (int = 0) const { return (scalar != 0.0); }
--- a/src/ov-base.h	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-base.h	Fri Feb 20 18:02:59 2004 +0000
@@ -96,6 +96,8 @@
 
   dim_vector dims (void) const { return dim_vector (-1, -1); }
 
+  size_t byte_size (void) const { return 0; }
+
   octave_value reshape (const dim_vector&) const;
 
   octave_value permute (const Array<int>& vec, bool = false) const;
--- a/src/ov-bool-mat.h	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-bool-mat.h	Fri Feb 20 18:02:59 2004 +0000
@@ -78,6 +78,8 @@
 
   idx_vector index_vector (void) const { return idx_vector (matrix); }
 
+  size_t byte_size (void) const { return numel () * sizeof (bool); }
+
   bool is_bool_matrix (void) const { return true; }
 
   bool is_bool_type (void) const { return true; }
--- a/src/ov-cell.cc	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-cell.cc	Fri Feb 20 18:02:59 2004 +0000
@@ -241,6 +241,17 @@
     octave_base_matrix<Cell>::assign (idx, Cell (rhs));
 }
 
+size_t
+octave_cell::byte_size (void) const
+{
+  size_t retval = 0;
+
+  for (int i = 0; i < numel (); i++)
+    retval += matrix(i).byte_size ();
+
+  return retval;
+}
+
 octave_value_list
 octave_cell::list_value (void) const
 {
--- a/src/ov-cell.h	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-cell.h	Fri Feb 20 18:02:59 2004 +0000
@@ -87,6 +87,8 @@
 			 const std::list<octave_value_list>& idx,
 			 const octave_value& rhs);
 
+  size_t byte_size (void) const;
+
   bool is_matrix_type (void) const { return false; }
 
   bool is_numeric_type (void) const { return false; }
--- a/src/ov-ch-mat.h	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-ch-mat.h	Fri Feb 20 18:02:59 2004 +0000
@@ -83,6 +83,8 @@
   octave_value *clone (void) const { return new octave_char_matrix (*this); }
   octave_value *empty_clone (void) const { return new octave_char_matrix (); }
 
+  size_t byte_size (void) const { return numel () * sizeof (char); }
+
   bool is_char_matrix (void) const { return true; }
   bool is_real_matrix (void) const { return true; }
 
--- a/src/ov-cx-mat.h	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-cx-mat.h	Fri Feb 20 18:02:59 2004 +0000
@@ -85,6 +85,8 @@
 
   void assign (const octave_value_list& idx, const NDArray& rhs);
 
+  size_t byte_size (void) const { return numel () * sizeof (Complex); }
+
   bool is_complex_matrix (void) const { return true; }
 
   bool is_complex_type (void) const { return true; }
--- a/src/ov-list.cc	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-list.cc	Fri Feb 20 18:02:59 2004 +0000
@@ -241,6 +241,17 @@
     error ("lists may only be indexed by a single scalar");
 }
 
+size_t
+octave_list::byte_size (void) const
+{
+  size_t retval = 0;
+
+  for (int i = 0; i < numel (); i++)
+    retval += data(i).byte_size ();
+
+  return retval;
+}
+
 octave_value_list
 octave_list::list_value (void) const
 {
--- a/src/ov-list.h	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-list.h	Fri Feb 20 18:02:59 2004 +0000
@@ -86,6 +86,8 @@
 
   dim_vector dims (void) const { return dim_vector (1, data.length ()); }
 
+  size_t byte_size (void) const;
+
   bool is_defined (void) const { return true; }
 
   bool is_constant (void) const { return true; }
--- a/src/ov-range.h	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-range.h	Fri Feb 20 18:02:59 2004 +0000
@@ -108,6 +108,8 @@
       return dim_vector (n > 0, n);
     }
 
+  size_t byte_size (void) const { 3 * sizeof (double); }
+
   octave_value reshape (const dim_vector& new_dims) const
     { return NDArray (matrix_value().reshape (new_dims)); }
 
--- a/src/ov-re-mat.h	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-re-mat.h	Fri Feb 20 18:02:59 2004 +0000
@@ -84,6 +84,8 @@
 
   idx_vector index_vector (void) const { return idx_vector (matrix); }
 
+  size_t byte_size (void) const { return numel () * sizeof (double); }
+
   bool is_real_matrix (void) const { return true; }
 
   bool is_real_type (void) const { return true; }
--- a/src/ov-streamoff.h	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-streamoff.h	Fri Feb 20 18:02:59 2004 +0000
@@ -63,6 +63,8 @@
   octave_value *clone (void) const { return new octave_streamoff (*this); }
   octave_value *empty_clone (void) const { return new octave_streamoff (); }
 
+  size_t byte_size (void) const { return numel () * sizeof (std::streamoff); }
+
   bool is_defined (void) const { return true; }
 
   bool is_streamoff (void) const { return true; }
--- a/src/ov-struct.cc	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-struct.cc	Fri Feb 20 18:02:59 2004 +0000
@@ -353,6 +353,25 @@
   return retval;
 }
 
+size_t
+octave_struct::byte_size (void) const
+{
+  // Neglect the size of the fieldnames.
+
+  size_t retval = 0;
+
+  for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++)
+    {
+      std::string key = map.key (p);
+
+      octave_value val = octave_value (map.contents (p));
+
+      retval += val.byte_size ();
+    }
+
+  return retval;
+}
+
 void
 octave_struct::print (std::ostream& os, bool) const
 {
--- a/src/ov-struct.h	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov-struct.h	Fri Feb 20 18:02:59 2004 +0000
@@ -88,6 +88,8 @@
 
   dim_vector dims (void) const { return map.dims (); }
 
+  size_t byte_size (void) const;
+
   octave_value reshape (const dim_vector& new_dims) const
     { return map.reshape (new_dims); }
 
--- a/src/ov.cc	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov.cc	Fri Feb 20 18:02:59 2004 +0000
@@ -1916,6 +1916,22 @@
   octave_streamoff::register_type ();
 }
 
+DEFUN (sizeof, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} sizeof (@var{val})\n\
+Return the size of @var{val} in bytes\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  if (args.length () == 1)
+    retval = args(0).byte_size ();
+  else
+    print_usage ("sizeof");
+
+  return retval;
+}
+
 static int
 warn_fortran_indexing (void)
 {
--- a/src/ov.h	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/ov.h	Fri Feb 20 18:02:59 2004 +0000
@@ -338,6 +338,9 @@
 
   int numel (void) const;
 
+  virtual size_t byte_size (void) const
+    { return rep->byte_size (); }
+
   virtual octave_value reshape (const dim_vector& dv) const
     { return rep->reshape (dv); }
 
--- a/src/pr-output.cc	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/pr-output.cc	Fri Feb 20 18:02:59 2004 +0000
@@ -1874,6 +1874,15 @@
 
 		  double val = base + i * increment;
 
+		  if (i == num_elem - 1)
+		    {
+		      // See the comments in Range::matrix_value.
+
+		      if ((increment > 0 && val > limit)
+			  || (increment < 0 && val < limit))
+			val = limit;
+		    }
+
 		  os << "  ";
 
 		  pr_float (os, val, fw, scale);
--- a/src/sighandlers.cc	Thu Feb 19 20:15:18 2004 +0000
+++ b/src/sighandlers.cc	Fri Feb 20 18:02:59 2004 +0000
@@ -115,7 +115,7 @@
       std::cerr << "panic: " << sig_name << " -- stopping myself...\n";
 
       if (save_vars)
-	save_user_variables ();
+	dump_octave_core ();
 
       if (sig_number < 0)
 	exit (1);
@@ -259,7 +259,7 @@
     case SIGHUP:
       {
 	if (Vsighup_dumps_octave_core)
-	  save_user_variables ();
+	  dump_octave_core ();
       }
       break;
 #endif
@@ -268,7 +268,7 @@
     case SIGTERM:
       {
 	if (Vsigterm_dumps_octave_core)
-	  save_user_variables ();
+	  dump_octave_core ();
       }
       break;
 #endif
@@ -336,43 +336,11 @@
 	{
 	  octave_interrupt_state++;
 
-	  if (interactive)
-	    {
-	      if (octave_interrupt_state > 3)
-		{
-		  // XXX FIXME XXX -- might want to attempt to flush
-		  // any pending input first...
-
-		  std::cerr << "abort [y/N]? ";
-
-		  int c = octave_kbhit ();
-
-		  std::cerr << static_cast<char> (c) << std::endl;
-
-		  if (c == 'y' || c == 'Y')
-		    {
-		      std::cerr << "save top-level workspace [y/N]? ";
-
-		      c = octave_kbhit ();
+	  if (interactive && octave_interrupt_state == 2)
+	    std::cerr << "Press Control-C again to abort." << std::endl;
 
-		      std::cerr << static_cast<char> (c) << std::endl;
-
-		      my_friendly_exit (sys_siglist[sig], sig,
-					(c == 'y' || c == 'Y'));
-		    }
-		  else
-		    {
-		      // We will still eventually interrupt and jump to
-		      // the top level even if no additional interrupts
-		      // happen, but we will have to wait until it is
-		      // safe to do so.  It will take 3 more
-		      // consecutive interrupts before we offer to
-		      // abort again.
-
-		      octave_interrupt_state = 1;
-		    }
-		}
-	    }
+	  if (octave_interrupt_state >= 3)
+	    my_friendly_exit (sys_siglist[sig], sig, true);
 	}
     }