changeset 3219:30770ba4457a

[project @ 1998-11-13 03:44:31 by jwe]
author jwe
date Fri, 13 Nov 1998 03:44:36 +0000
parents 2c91af0db179
children 3deb1105fbc1
files ChangeLog doc/interpreter/matrix.texi emacs/otags libcruft/ChangeLog libcruft/Makefile.in liboctave/ChangeLog liboctave/cmd-edit.cc liboctave/cmd-edit.h liboctave/dMatrix.cc liboctave/oct-alloc.h src/ChangeLog src/Makefile.in src/input.cc src/oct-obj.cc src/oct-obj.h src/ov-base-mat.cc src/ov-base-mat.h src/ov-base.cc src/ov-base.h src/ov-bool-mat.cc src/ov-bool-mat.h src/ov-bool.cc src/ov-bool.h src/ov-builtin.cc src/ov-builtin.h src/ov-ch-mat.cc src/ov-ch-mat.h src/ov-colon.cc src/ov-colon.h src/ov-complex.cc src/ov-complex.h src/ov-cx-mat.cc src/ov-cx-mat.h src/ov-fcn.cc src/ov-fcn.h src/ov-file.cc src/ov-file.h src/ov-list.cc src/ov-list.h src/ov-mapper.cc src/ov-mapper.h src/ov-range.cc src/ov-range.h src/ov-re-mat.cc src/ov-re-mat.h src/ov-scalar.cc src/ov-scalar.h src/ov-str-mat.cc src/ov-str-mat.h src/ov-struct.cc src/ov-struct.h src/ov-usr-fcn.cc src/ov-usr-fcn.h src/ov-va-args.cc src/ov-va-args.h src/ov.cc src/ov.h src/version.h
diffstat 58 files changed, 580 insertions(+), 831 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Thu Nov 12 10:42:25 1998  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* emacs/otags: New script from Mario Storti
+	<mstorti@minerva.unl.edu.ar>.
+	* emacs/Makefile.in: Add it to the list of files to distribute and
+	install.
+
+Wed Nov 11 17:26:26 1998  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* configure.in (AC_OUTPUT): Add libcruft/amos/Makefile.
+	Delete libcruft/specfun/Makefile.
+
 Mon Nov  9 08:53:03 1998  John W. Eaton  <jwe@bevo.che.wisc.edu>
 
 	* Makeconf.in (LIBGLOB): Add a place for substitution to occur.
--- a/doc/interpreter/matrix.texi
+++ b/doc/interpreter/matrix.texi
@@ -68,7 +68,7 @@
 @end example
 
 @noindent
-tests a random 5 by 5 matrix to see if all of it's elements are less
+tests a random 5 by 5 matrix to see if all of its elements are less
 than 0.9.
 
 Note that in conditional contexts (like the test clause of @code{if} and
--- a/emacs/otags
+++ b/emacs/otags
@@ -17,6 +17,8 @@
 # a line by yourself of the form `###key <script-name>' if you want to
 # jump to it.  :-(
 
+# Author: Mario Storti <mstorti@minerva.unl.edu.ar>
+
 etags --lang=none \
       --regex='/[ \t]*function.*=[ \t]*\([^ \t]*\)[ \t]*(/\1/' \
       --regex='/###key \(.*\)/\1/' \
--- a/libcruft/ChangeLog
+++ b/libcruft/ChangeLog
@@ -1,3 +1,9 @@
+Wed Nov 11 17:27:35 1998  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* Makefile.in (CRUFT_DIRS): Add amos.  Delete specfun.
+	* specfun: Delete directory.
+	* amos: New directory
+
 Thu Oct 15 00:43:13 1998  John W. Eaton  <jwe@bevo.che.wisc.edu>
 
 	* ranlib: Update to newer version of randlib.
--- a/libcruft/Makefile.in
+++ b/libcruft/Makefile.in
@@ -24,8 +24,8 @@
 # generate a new configure script in the top-level directory (edit
 # configure.in and run autoconf).
 
-CRUFT_DIRS = blas dassl fftpack lapack linpack minpack misc odepack \
-	ordered-qz quadpack ranlib slatec-err slatec-fn specfun villad
+CRUFT_DIRS = amos blas dassl fftpack lapack linpack minpack misc odepack \
+	ordered-qz quadpack ranlib slatec-err slatec-fn villad
 
 SUBDIRS = $(CRUFT_DIRS)
 
--- a/liboctave/ChangeLog
+++ b/liboctave/ChangeLog
@@ -1,5 +1,16 @@
+Thu Nov 12 17:44:15 1998  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* cmd-edit.h (command_editor::readline): Add new variation that
+	allows EOF information to be passed back to caller.
+
+	* dMatrix.cc (Matrix::read): Do the right thing for EOF when
+	amount of data to read is unspecified.
+
 Tue Nov 10 07:53:15 1998  John W. Eaton  <jwe@bevo.che.wisc.edu>
 
+	* oct-alloc.h (DECLARE_OCTAVE_ALLOCATOR): New macro.
+	(DEFINE_OCTAVE_ALLOCATOR): Ditto.
+
 	* byte-swap.h (swap_bytes, swap_2_bytes, swap_4_bytes, swap_8_bytes): 
 	Add volatile qualifier to void* arg.
 	Cast volatile void* arg to volatile char*.
--- a/liboctave/cmd-edit.cc
+++ b/liboctave/cmd-edit.cc
@@ -74,7 +74,7 @@
 
   void do_set_name (const string& n);
 
-  string do_readline (const string& prompt);
+  string do_readline (const string& prompt, bool& eof);
 
   void do_set_input_stream (FILE *f);
 
@@ -176,10 +176,12 @@
 }
 
 string
-gnu_readline::do_readline (const string& prompt)
+gnu_readline::do_readline (const string& prompt, bool& eof)
 {
   string retval;
 
+  eof = false;
+
   char *line = ::readline (prompt.c_str ());
 
   if (line)
@@ -188,6 +190,8 @@
 
       free (line);
     }
+  else
+    eof = true;
 
   return retval;
 }
@@ -419,7 +423,7 @@
 
   ~default_command_editor (void) { }
 
-  string do_readline (const string& prompt);
+  string do_readline (const string& prompt, bool& eof);
 
   void do_set_input_stream (FILE *f);
 
@@ -441,8 +445,10 @@
 };
 
 string
-default_command_editor::do_readline (const string& prompt)
+default_command_editor::do_readline (const string& prompt, bool& eof)
 {
+  eof = false;
+
   fprintf (output_stream, prompt.c_str ());
   fflush (output_stream);
 
@@ -524,8 +530,16 @@
 string
 command_editor::readline (const string& prompt)
 {
+  bool eof;
+
+  return readline (prompt, eof);
+}
+
+string
+command_editor::readline (const string& prompt, bool& eof)
+{
   return (instance_ok ())
-    ? instance->do_readline (prompt) : string ();
+    ? instance->do_readline (prompt, eof) : string ();
 }
 
 void
--- a/liboctave/cmd-edit.h
+++ b/liboctave/cmd-edit.h
@@ -47,6 +47,8 @@
 
   static string readline (const string& prompt);
 
+  static string readline (const string& prompt, bool& eof);
+
   static void set_input_stream (FILE *f);
 
   static FILE *get_input_stream (void);
@@ -120,7 +122,14 @@
 
   virtual void do_set_name (const string&) { }
 
-  virtual string do_readline (const string&) = 0;
+  string do_readline (const string& prompt)
+    {
+      bool eof;
+
+      return do_readline (prompt, eof);
+    }
+
+  virtual string do_readline (const string&, bool&) = 0;
 
   virtual void do_set_input_stream (FILE *) = 0;
 
--- a/liboctave/dMatrix.cc
+++ b/liboctave/dMatrix.cc
@@ -2617,7 +2617,7 @@
 		  if (ok && skip != 0)
 		    is.seekg (skip, ios::cur);
 
-		  if (! ok)
+		  if (! ok || is.eof ())
 		    {
 		      if (is.eof ())
 			{
--- a/liboctave/oct-alloc.h
+++ b/liboctave/oct-alloc.h
@@ -59,6 +59,19 @@
   bool grow (void);
 };
 
+#define DECLARE_OCTAVE_ALLOCATOR \
+  public: \
+    void *operator new (size_t size) { return allocator.alloc (size); } \
+    void operator delete (void *p, size_t size) { allocator.free (p, size); } \
+  private: \
+    static octave_allocator allocator;
+
+#define DEFINE_OCTAVE_ALLOCATOR(t) \
+  octave_allocator t::allocator (sizeof (t))
+
+#define DEFINE_OCTAVE_ALLOCATOR2(t, s) \
+  octave_allocator t::allocator (sizeof (t), s)
+
 #endif
 
 /*
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,74 @@
+Thu Nov 12 11:13:24 1998  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* input.cc (gnu_readline): Check for EOF from command_editor::readline.
+
+	* ov-str-mat.h, ov-str-mat.cc (class octave_char_matrix_str):
+	Get common functions via new derivation scheme.
+	
+	* ov-bool-mat.h, ov-bool-mat.cc (class octave_bool_matrix):
+	Derive from octave_base_matrix and get common functions via derivation.
+	* ov-ch-mat.h, ov-ch-mat.cc (class octave_char_matrix): Ditto.
+	* ov-cx-mat.h, ov-cx-mat.cc (class octave_complex_matrix): Ditto.
+	* ov-re-mat.h, ov-re-mat.cc (class octave_real_matrix): Ditto.
+
+	* ov-base-mat.h, ov-base-mat.cc (class octave_base_matrix): New
+	files  for new class definition.  Put common matrix data type
+	stuff here.
+
+	* ov-list.cc (Fnth): New function.
+
+	* ov-list.cc (octave_list::do_index_op): Allow more complex indexing.
+
+	* oct-obj.cc (octave_value_list::index): New function.
+	(octave_value_list::octve_value_list (Array<octave_value>)):
+	New private constructor.
+
+	* ov-list.cc (Fsplice): Fix docstring to match.
+	* oct-obj.cc (octave_value_list::splice): Allow special case
+	splice (x, length(x)+1, 0, y) to be equivalent to append (x, y).
+
+	* ov-list.cc (Fappend): If an arg is a list, concatenate the lists
+	instead of appending arg as a single element.
+
+Wed Nov 11 14:07:27 1998  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* load-save.cc (get_mat_data_input_line): New function.
+	(get_lines_and_columns): Use it here.
+	(read_mat_ascii_data): And here and do our own reading instead of
+	using Matrix::operator<<.
+
+Tue Nov 10 16:12:25 1998  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* parse.y (make_constant): Initialize retval to 0.
+
+	* toplev.h (clean_up_and_exit (void)): Delete declaration.
+	* toplev.cc (do_octave_atexit): Move guts of clean_up_for_exit
+	here, but ensure that the actions are only executed once.
+	* octave.cc (main): Don't register cleanup_tmp_files with atexit.
+
+	* ov.h, ov.cc (class octave_value): Use DECLARE_OCTAVE_ALLOCATOR
+	and DEFINE_OCTAVE_ALLOCATOR for uniform declaration and definition
+	of allocator functions.  Use DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
+	and DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA for uniform declaration
+	and definition of type id functions and data.
+	* ov-usr-fcn.h, ov-usr-fcn.cc (class octave_user_function): Ditto.
+	* ov-scalar.h, ov-scalar.cc (class octave_scalar): Ditto.
+	* ov-re-mat.h ov-re-mat.cc (class octave_matrix): Ditto.
+	* ov-range.h, ov-range.cc (class octave_range): Ditto.
+	* ov-mapper.h, ov-mapper.cc (class octave_mapper): Ditto.
+	* ov-list.h, ov-list.cc (class octave_list): Ditto.
+	* ov-file.h, ov-file.cc (class octave_file): Ditto.
+	* ov-fcn.h, ov-fcn.cc (class octave_function): Ditto.
+	* ov-cx-mat.h, ov-cx-mat.cc (class octave_complex_matrix): Ditto.
+	* ov-complex.h, ov-complex.cc (class octave_complex): Ditto.
+	* ov-ch-mat.h, ov-ch-mat.cc (octave_char_matrix): Ditto.
+	* ov-builtin.h, ov-builtin.cc (class octave_builtin): Ditto.
+	* ov-bool.h, ov-bool.cc (class octave_bool): Ditto.
+	* ov-bool-mat.h, ov-bool-mat.cc (octave_bool_matrix): Ditto.
+
+	* ov.h (DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA): New macro.
+	(DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA): Ditto.
+
 Mon Nov  9 16:12:37 1998  John W. Eaton  <jwe@bevo.che.wisc.edu>
 
 	* pr-output.cc (octave_print_internal): Reorder default args for
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -66,7 +66,7 @@
 
 OV_INCLUDES := ov-re-mat.h ov-cx-mat.h ov-ch-mat.h \
 	ov-list.h ov-struct.h ov-scalar.h ov-range.h \
-	ov-complex.h ov-va-args.h ov-colon.h ov-base.h \
+	ov-complex.h ov-va-args.h ov-colon.h ov-base.h ov-base-mat.h \
 	ov-str-mat.h ov-bool-mat.h ov-bool.h ov-file.h ov.h \
 	ov-fcn.h ov-builtin.h ov-mapper.h ov-usr-fcn.h ov-typeinfo.h
 
@@ -104,7 +104,7 @@
 
 OP_SRC := $(addprefix OPERATORS/, $(OP_XSRC))
 
-OV_SRC := ov-base.cc ov-ch-mat.cc ov-list.cc ov-re-mat.cc \
+OV_SRC := ov-base.cc ov-base-mat.cc ov-ch-mat.cc ov-list.cc ov-re-mat.cc \
 	ov-cx-mat.cc ov-range.cc ov-scalar.cc ov-complex.cc \
 	ov-str-mat.cc ov-struct.cc ov-va-args.cc ov-colon.cc \
 	ov-bool-mat.cc ov-bool.cc ov-file.cc ov.cc ov-fcn.cc \
--- a/src/input.cc
+++ b/src/input.cc
@@ -165,9 +165,11 @@
 
   if (line_editing || force_readline)
     {
-      retval = command_editor::readline (s);
+      bool eof;
 
-      if (retval.empty ())
+      retval = command_editor::readline (s, eof);
+
+      if (! eof && retval.empty ())
 	retval = "\n";
     }
   else
--- a/src/oct-obj.cc
+++ b/src/oct-obj.cc
@@ -103,8 +103,11 @@
 
   if (offset < 0 || offset >= len)
     {
-      error ("octave_value_list::splice: invalid OFFSET");
-      return retval;
+      if (! (rep_length == 0 && offset == len))
+	{
+	  error ("octave_value_list::splice: invalid OFFSET");
+	  return retval;
+	}
     }
 
   if (rep_length < 0 || rep_length + offset > len)
@@ -133,6 +136,12 @@
   return retval;
 }
 
+octave_value_list
+octave_value_list::index (idx_vector& i) const
+{
+  return octave_value_list (data.index (i));
+}
+
 bool
 octave_value_list::all_strings_p (void) const
 {
--- a/src/oct-obj.h
+++ b/src/oct-obj.h
@@ -136,6 +136,8 @@
   octave_value_list splice (int offset, int length,
 			    const octave_value_list& lst) const;
 
+  octave_value_list index (idx_vector& i) const;
+
   bool all_strings_p (void) const;
 
   string_vector make_argv (const string&) const;
@@ -170,6 +172,9 @@
 
   octave_value_list (int n);
 
+  octave_value_list (const Array<octave_value>& d)
+    : data (d) { }
+
   void maybe_resize (int n)
     {
       if (n >= length ())
new file mode 100644
--- /dev/null
+++ b/src/ov-base-mat.cc
@@ -0,0 +1,87 @@
+/*
+
+Copyright (C) 1996, 1997 John W. Eaton
+
+This file is part of Octave.
+
+Octave 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 2, or (at your option) any
+later version.
+
+Octave 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 Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if defined (__GNUG__)
+#pragma implementation
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <iostream.h>
+
+#include "ov-base.h"
+#include "ov-base-mat.h"
+
+template <class MT>
+bool
+octave_base_matrix<MT>::print_as_scalar (void) const
+{
+  int nr = rows ();
+  int nc = columns ();
+
+  return (nr == 1 && nc == 1 || (nr == 0 || nc == 0));
+}
+
+template <class MT>
+void
+octave_base_matrix<MT>::print (ostream& os, bool pr_as_read_syntax) const
+{
+  print_raw (os, pr_as_read_syntax);
+  newline (os);
+}
+
+template <class MT>
+void
+octave_base_matrix<MT>::print_raw (ostream& os, bool pr_as_read_syntax) const
+{
+  octave_print_internal (os, matrix, pr_as_read_syntax,
+			 current_print_indent_level ());
+}
+
+template <class MT>
+bool
+octave_base_matrix<MT>::print_name_tag (ostream& os, const string& name) const
+{
+  bool retval = false;
+
+  indent (os);
+
+  if (print_as_scalar ())
+    os << name << " = ";
+  else
+    {
+      os << name << " =";
+      newline (os);
+      newline (os);
+      retval = true;
+    }
+
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/ov-base-mat.h
@@ -0,0 +1,102 @@
+/*
+
+Copyright (C) 1998 John W. Eaton
+
+This file is part of Octave.
+
+Octave 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 2, or (at your option) any
+later version.
+
+Octave 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 Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#if !defined (octave_base_matrix_h)
+#define octave_base_matrix_h 1
+
+#if defined (__GNUG__)
+#pragma interface
+#endif
+
+#include <cstdlib>
+
+#include <string>
+
+class ostream;
+
+#include "mx-base.h"
+#include "str-vec.h"
+
+#include "error.h"
+#include "ov-base.h"
+#include "ov-typeinfo.h"
+
+class Octave_map;
+class octave_value_list;
+
+class tree_walker;
+
+// Real matrix values.
+
+template <class MT> class
+octave_base_matrix : public octave_base_value
+{
+public:
+
+  octave_base_matrix (void)
+    : octave_base_value () { }
+
+  octave_base_matrix (const MT& m)
+    : octave_base_value (), matrix (m) { }
+
+  octave_base_matrix (const octave_base_matrix& m)
+    : octave_base_value (), matrix (m.matrix) { }
+
+  ~octave_base_matrix (void) { }
+
+  octave_value *clone (void) { return new octave_base_matrix (*this); }
+
+  int rows (void) const { return matrix.rows (); }
+  int columns (void) const { return matrix.columns (); }
+
+  int length (void) const
+  {
+    int r = rows ();
+    int c = columns ();
+
+    return r > c ? r : c;
+  }
+
+  bool is_defined (void) const { return true; }
+
+  bool is_constant (void) const { return true; }
+
+  virtual bool print_as_scalar (void) const;
+
+  void print (ostream& os, bool pr_as_read_syntax = false) const;
+
+  void print_raw (ostream& os, bool pr_as_read_syntax = false) const;
+
+  bool print_name_tag (ostream& os, const string& name) const;
+
+protected:
+
+  MT matrix;
+};
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
--- a/src/ov-base.cc
+++ b/src/ov-base.cc
@@ -48,9 +48,7 @@
 #include "ov-list.h"
 #include "variables.h"
 
-int octave_base_value::t_id = -1;
-
-const string octave_base_value::t_name ("<unknown type>");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_base_value, "<unknown type>");
 
 octave_value
 octave_base_value::do_index_op (const octave_value_list&)
--- a/src/ov-base.h
+++ b/src/ov-base.h
@@ -84,11 +84,11 @@
 
   octave_lvalue struct_elt_ref (octave_value *parent, const string& nm);
 
-  int rows (void) const { reteurn -1; }
+  int rows (void) const { return -1; }
 
-  int columns (void) const { reteurn -1; }
+  int columns (void) const { return -1; }
 
-  int length (void) const { reteurn -1; }
+  int length (void) const { return -1; }
 
   bool is_defined (void) const { return false; }
 
@@ -197,22 +197,9 @@
 
   bool print_name_tag (ostream& os, const string& name) const;
 
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
-  // Type id of base value objects, set by register_type().
-  static int t_id;
-
-  // Type name of base value objects, defined in ov-base.cc.
-  static const string t_name;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
 #endif
--- a/src/ov-bool-mat.cc
+++ b/src/ov-bool-mat.cc
@@ -36,19 +36,19 @@
 #include "gripes.h"
 #include "oct-obj.h"
 #include "ops.h"
+#include "ov-base.h"
+#include "ov-base-mat.h"
+#include "ov-base-mat.cc"
 #include "ov-bool.h"
 #include "ov-bool-mat.h"
 #include "ov-re-mat.h"
 #include "pr-output.h"
 
-octave_allocator
-octave_bool_matrix::allocator (sizeof (octave_bool_matrix));
+template class octave_base_matrix<boolMatrix>;
 
-int
-octave_bool_matrix::t_id (-1);
+DEFINE_OCTAVE_ALLOCATOR (octave_bool_matrix);
 
-const string
-octave_bool_matrix::t_name ("bool matrix");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_bool_matrix, "bool matrix");
 
 static octave_value *
 default_numeric_conversion_function (const octave_value& a)
@@ -212,44 +212,6 @@
   return retval;
 }
 
-void
-octave_bool_matrix::print (ostream& os, bool pr_as_read_syntax) const
-{
-  print_raw (os, pr_as_read_syntax);
-  newline (os);
-}
-
-void
-octave_bool_matrix::print_raw (ostream& os, bool pr_as_read_syntax) const
-{
-  Matrix tmp (matrix);
-  octave_print_internal (os, tmp, pr_as_read_syntax,
-			 current_print_indent_level ());
-}
-
-bool
-octave_bool_matrix::print_name_tag (ostream& os, const string& name) const
-{
-  bool retval = false;
-
-  int nr = rows ();
-  int nc = columns ();
-
-  indent (os);
-
-  if (nr == 1 && nc == 1 || (nr == 0 || nc == 0))
-    os << name << " = ";
-  else
-    {
-      os << name << " =";
-      newline (os);
-      newline (os);
-      retval = true;
-    }
-
-  return retval;
-}
-
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-bool-mat.h
+++ b/src/ov-bool-mat.h
@@ -38,6 +38,7 @@
 
 #include "error.h"
 #include "ov-base.h"
+#include "ov-base-mat.h"
 #include "ov-typeinfo.h"
 
 class Octave_map;
@@ -48,29 +49,23 @@
 // Character matrix values.
 
 class
-octave_bool_matrix : public octave_base_value
+octave_bool_matrix : public octave_base_matrix<boolMatrix>
 {
 public:
 
   octave_bool_matrix (void)
-    : octave_base_value () { }
+    : octave_base_matrix () { }
 
   octave_bool_matrix (const boolMatrix& bm)
-    : octave_base_value (), matrix (bm) { }
+    : octave_base_matrix (bm) { }
 
   octave_bool_matrix (const octave_bool_matrix& bm)
-    : octave_base_value (), matrix (bm.matrix) { }
+    : octave_base_matrix (bm) { }
 
   ~octave_bool_matrix (void) { }
 
   octave_value *clone (void) { return new octave_bool_matrix (*this); }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   type_conv_fcn numeric_conversion_function (void) const;
 
   octave_value *try_narrowing_conversion (void);
@@ -81,21 +76,6 @@
 
   idx_vector index_vector (void) const { return idx_vector (matrix); }
 
-  int rows (void) const { return matrix.rows (); }
-  int columns (void) const { return matrix.columns (); }
-
-  int length (void) const
-  {
-    int r = rows ();
-    int c = columns ();
-
-    return r > c ? r : c;
-  }
-
-  bool is_defined (void) const { return true; }
-
-  bool is_constant (void) const { return true; }
-
   bool is_bool_matrix (void) const { return true; }
 
   octave_value all (void) const { return matrix.all (); }
@@ -133,32 +113,11 @@
   octave_value convert_to_str (void) const
     { return octave_value (matrix); }
 
-  void print (ostream& os, bool pr_as_read_syntax = false) const;
-
-  void print_raw (ostream& os, bool pr_as_read_syntax = false) const;
-
-  bool print_name_tag (ostream& os, const string& name) const;
-
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 protected:
 
-  boolMatrix matrix;
-
-  static octave_allocator allocator;
+  DECLARE_OCTAVE_ALLOCATOR
 
-  // Type id of bool matrix objects, set by register_type().
-  static int t_id;
-
-  // Type name of bool matrix objects, defined in ov-bool-mat.cc.
-  static const string t_name;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
 #endif
--- a/src/ov-bool.cc
+++ b/src/ov-bool.cc
@@ -40,14 +40,9 @@
 #include "ov-scalar.h"
 #include "pr-output.h"
 
-octave_allocator
-octave_bool::allocator (sizeof (octave_bool));
+DEFINE_OCTAVE_ALLOCATOR (octave_bool);
 
-int
-octave_bool::t_id (-1);
-
-const string
-octave_bool::t_name ("bool");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_bool, "bool");
 
 static octave_value *
 default_numeric_conversion_function (const octave_value& a)
--- a/src/ov-bool.h
+++ b/src/ov-bool.h
@@ -66,12 +66,6 @@
 
   octave_value *clone (void) { return new octave_bool (*this); }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   type_conv_fcn numeric_conversion_function (void) const;
 
   octave_value do_index_op (const octave_value_list& idx);
@@ -131,28 +125,14 @@
 
   bool print_name_tag (ostream& os, const string& name) const;
 
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
   // The value of this scalar.
   bool scalar;
 
-  // For custom memory management.
-  static octave_allocator allocator;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 
-  // Type id of bool objects, set by register_type().
-  static int t_id;
-
-  // Type name of bool objects, defined in ov-bool.cc.
-  static const string t_name;
+  DECLARE_OCTAVE_ALLOCATOR
 };
 
 #endif
--- a/src/ov-builtin.cc
+++ b/src/ov-builtin.cc
@@ -33,14 +33,9 @@
 #include "ov-builtin.h"
 #include "ov.h"
 
-octave_allocator
-octave_builtin::allocator (sizeof (octave_builtin));
+DEFINE_OCTAVE_ALLOCATOR (octave_builtin);
 
-int
-octave_builtin::t_id (-1);
-
-const string
-octave_builtin::t_name ("built-in function");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_builtin, "built-in function");
 
 // Are any of the arguments `:'?
 
--- a/src/ov-builtin.h
+++ b/src/ov-builtin.h
@@ -50,25 +50,10 @@
 
   ~octave_builtin (void) { }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   octave_function *function_value (bool) { return this; }
 
   octave_value_list do_index_op (int nargout, const octave_value_list& args);
 
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
   octave_builtin (void);
@@ -78,14 +63,9 @@
   // A pointer to the actual function.
   fcn f;
 
-  // For custom memory management.
-  static octave_allocator allocator;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 
-  // Type id of list objects, set by register_type().
-  static int t_id;
-
-  // Type name of list objects, defined in ov-list.cc.
-  static const string t_name;
+  DECLARE_OCTAVE_ALLOCATOR
 };
 
 #endif
--- a/src/ov-ch-mat.cc
+++ b/src/ov-ch-mat.cc
@@ -33,18 +33,18 @@
 #include "lo-ieee.h"
 #include "mx-base.h"
 
+#include "ov-base.h"
+#include "ov-base-mat.h"
+#include "ov-base-mat.cc"
 #include "ov-ch-mat.h"
 #include "gripes.h"
 #include "pr-output.h"
 
-octave_allocator
-octave_char_matrix::allocator (sizeof (octave_char_matrix));
+template class octave_base_matrix<charMatrix>;
 
-int
-octave_char_matrix::t_id (-1);
+DEFINE_OCTAVE_ALLOCATOR (octave_char_matrix);
 
-const string
-octave_char_matrix::t_name ("char matrix");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_char_matrix, "char matrix");
 
 bool
 octave_char_matrix::valid_as_scalar_index (void) const
@@ -114,43 +114,6 @@
   return retval;
 }
 
-void
-octave_char_matrix::print (ostream& os, bool pr_as_read_syntax) const
-{
-  print_raw (os, pr_as_read_syntax);
-  newline (os);
-}
-
-void
-octave_char_matrix::print_raw (ostream& os, bool pr_as_read_syntax) const
-{
-  octave_print_internal (os, matrix, pr_as_read_syntax, false,
-			 current_print_indent_level ());
-}
-
-bool
-octave_char_matrix::print_name_tag (ostream& os, const string& name) const
-{
-  bool retval = false;
-
-  int nr = rows ();
-  int nc = columns ();
-
-  indent (os);
-
-  if (nr == 1 && nc == 1 || (nr == 0 || nc == 0))
-    os << name << " = ";
-  else
-    {
-      os << name << " =";
-      newline (os);
-      newline (os);
-      retval = true;
-    }
-
-  return retval;
-}
-
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-ch-mat.h
+++ b/src/ov-ch-mat.h
@@ -39,6 +39,7 @@
 
 #include "error.h"
 #include "ov-base.h"
+#include "ov-base-mat.h"
 #include "ov-typeinfo.h"
 
 class Octave_map;
@@ -49,56 +50,35 @@
 // Character matrix values.
 
 class
-octave_char_matrix : public octave_base_value
+octave_char_matrix : public octave_base_matrix<charMatrix>
 {
 public:
 
   octave_char_matrix (void)
-    : octave_base_value () { }
+    : octave_base_matrix<charMatrix> () { }
 
   octave_char_matrix (const charMatrix& chm, bool = false)
-    : octave_base_value (), matrix (chm) { }
+    : octave_base_matrix<charMatrix> (chm) { }
 
   octave_char_matrix (char c)
-    : octave_base_value (), matrix (c) { }
+    : octave_base_matrix<charMatrix> (c) { }
 
   octave_char_matrix (const char *s)
-    : octave_base_value (), matrix (s) { }
+    : octave_base_matrix<charMatrix> (s) { }
 
   octave_char_matrix (const string& s)
-    : octave_base_value (), matrix (s) { }
+    : octave_base_matrix<charMatrix> (s) { }
 
   octave_char_matrix (const string_vector& s)
-    : octave_base_value (), matrix (s) { }
+    : octave_base_matrix<charMatrix> (s) { }
 
   octave_char_matrix (const octave_char_matrix& chm)
-    : octave_base_value (), matrix (chm.matrix) { }
+    : octave_base_matrix<charMatrix> (chm) { }
 
   ~octave_char_matrix (void) { }
 
   octave_value *clone (void) { return new octave_char_matrix (*this); }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
-  int rows (void) const { return matrix.rows (); }
-  int columns (void) const { return matrix.columns (); }
-
-  int length (void) const
-  {
-    int r = rows ();
-    int c = columns ();
-
-    return r > c ? r : c;
-  }
-
-  bool is_constant (void) const { return true; }
-
-  bool is_defined (void) const { return true; }
-
   bool is_char_matrix (void) const { return true; }
   bool is_real_matrix (void) const { return true; }
 
@@ -134,32 +114,11 @@
   octave_value convert_to_str (void) const
     { return octave_value (matrix, true); }
 
-  void print (ostream& os, bool pr_as_read_syntax = false) const;
-
-  void print_raw (ostream& os, bool pr_as_read_syntax = false) const;
-
-  bool print_name_tag (ostream& os, const string& name) const;
-
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 protected:
 
-  charMatrix matrix;
-
-  static octave_allocator allocator;
+  DECLARE_OCTAVE_ALLOCATOR
 
-  // Type id of character matrix objects, set by register_type().
-  static int t_id;
-
-  // Type name of character matrix objects, defined in ov-ch-mat.cc.
-  static const string t_name;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
 #endif
--- a/src/ov-colon.cc
+++ b/src/ov-colon.cc
@@ -34,9 +34,7 @@
 #include "pr-output.h"
 #include "ov-colon.h"
 
-int octave_magic_colon::t_id = -1;
-
-const string octave_magic_colon::t_name ("magic-colon");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_magic_colon, "magic-colon");
 
 void
 octave_magic_colon::print (ostream& os, bool) const
--- a/src/ov-colon.h
+++ b/src/ov-colon.h
@@ -74,22 +74,9 @@
 
   void print_raw (ostream& os, bool pr_as_read_syntax = false) const;
 
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
-  // Type id of magic colon objects, set by register_type().
-  static int t_id;
-
-  // Type name of magic colon objects, defined in ov-colon.cc.
-  static const string t_name;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
 #endif
--- a/src/ov-complex.cc
+++ b/src/ov-complex.cc
@@ -40,14 +40,9 @@
 #include "gripes.h"
 #include "pr-output.h"
 
-octave_allocator
-octave_complex::allocator (sizeof (octave_complex));
+DEFINE_OCTAVE_ALLOCATOR (octave_complex);
 
-int
-octave_complex::t_id (-1);
-
-const string
-octave_complex::t_name ("complex scalar");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_complex, "complex scalar");
 
 octave_value *
 octave_complex::try_narrowing_conversion (void)
--- a/src/ov-complex.h
+++ b/src/ov-complex.h
@@ -66,12 +66,6 @@
 
   octave_value *clone (void) { return new octave_complex (*this); }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   octave_value *try_narrowing_conversion (void);
 
   octave_value do_index_op (const octave_value_list& idx);
@@ -131,26 +125,13 @@
 
   bool print_name_tag (ostream& os, const string& name) const;
 
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
   Complex scalar;
 
-  static octave_allocator allocator;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 
-  // Type id of complex scalar objects, set in register_type().
-  static int t_id;
-
-  // Type name of complex scalar objects, defined in ov-complex.cc.
-  static const string t_name;
+  DECLARE_OCTAVE_ALLOCATOR
 };
 
 #endif
--- a/src/ov-cx-mat.cc
+++ b/src/ov-cx-mat.cc
@@ -36,32 +36,34 @@
 #include "gripes.h"
 #include "oct-obj.h"
 #include "ops.h"
+#include "ov-base.h"
+#include "ov-base-mat.h"
+#include "ov-base-mat.cc"
 #include "ov-complex.h"
 #include "ov-cx-mat.h"
 #include "ov-re-mat.h"
 #include "ov-scalar.h"
 #include "pr-output.h"
 
-octave_allocator
-octave_complex_matrix::allocator (sizeof (octave_complex_matrix));
+template class octave_base_matrix<ComplexMatrix>;
 
-int
-octave_complex_matrix::t_id (-1);
+DEFINE_OCTAVE_ALLOCATOR (octave_complex_matrix);
 
-const string
-octave_complex_matrix::t_name ("complex matrix");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_complex_matrix, "complex matrix");
 
 octave_complex_matrix::octave_complex_matrix (const ComplexRowVector& v,
 					      int pcv)
-  : octave_base_value (),
-    matrix ((pcv < 0 && Vprefer_column_vectors) || pcv
-	    ? ComplexMatrix (v.transpose ()) : ComplexMatrix (v)) { }
+  : octave_base_matrix<ComplexMatrix> (((pcv < 0 && Vprefer_column_vectors)
+					|| pcv)
+				       ? ComplexMatrix (v.transpose ())
+				       : ComplexMatrix (v)) { }
 
 octave_complex_matrix::octave_complex_matrix (const ComplexColumnVector& v,
 					      int pcv)
-  : octave_base_value (),
-    matrix ((pcv < 0 && Vprefer_column_vectors) || pcv
-	    ? ComplexMatrix (v) : ComplexMatrix (v.transpose ())) { }
+  : octave_base_matrix<ComplexMatrix> (((pcv < 0 && Vprefer_column_vectors)
+					|| pcv)
+				       ? ComplexMatrix (v)
+				       : ComplexMatrix (v.transpose ())) { }
 
 octave_value *
 octave_complex_matrix::try_narrowing_conversion (void)
@@ -310,43 +312,6 @@
   return matrix;
 }
 
-void
-octave_complex_matrix::print (ostream& os, bool pr_as_read_syntax) const
-{
-  print_raw (os, pr_as_read_syntax);
-  newline (os);
-}
-
-void
-octave_complex_matrix::print_raw (ostream& os, bool pr_as_read_syntax) const
-{
-  octave_print_internal (os, matrix, pr_as_read_syntax,
-			 current_print_indent_level ());
-}
-
-bool
-octave_complex_matrix::print_name_tag (ostream& os, const string& name) const
-{
-  bool retval = false;
-
-  int nr = rows ();
-  int nc = columns ();
-
-  indent (os);
-
-  if (nr == 1 && nc == 1 || (nr == 0 || nc == 0))
-    os << name << " = ";
-  else
-    {
-      os << name << " =";
-      newline (os);
-      newline (os);
-      retval = true;
-    }
-
-  return retval;
-}
-
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-cx-mat.h
+++ b/src/ov-cx-mat.h
@@ -39,6 +39,7 @@
 
 #include "error.h"
 #include "ov-base.h"
+#include "ov-base-mat.h"
 #include "ov-typeinfo.h"
 
 class Octave_map;
@@ -49,36 +50,30 @@
 // Complex matrix values.
 
 class
-octave_complex_matrix : public octave_base_value
+octave_complex_matrix : public octave_base_matrix<ComplexMatrix>
 {
 public:
 
   octave_complex_matrix (void)
-    : octave_base_value () { }
+    : octave_base_matrix<ComplexMatrix> () { }
 
   octave_complex_matrix (const ComplexMatrix& m)
-    : octave_base_value (), matrix (m) { }
+    : octave_base_matrix<ComplexMatrix> (m) { }
 
   octave_complex_matrix (const ComplexDiagMatrix& d)
-    : octave_base_value (), matrix (d) { }
+    : octave_base_matrix<ComplexMatrix> (d) { }
 
   octave_complex_matrix (const ComplexRowVector& v, int pcv = -1);
 
   octave_complex_matrix (const ComplexColumnVector& v, int pcv = -1);
 
   octave_complex_matrix (const octave_complex_matrix& cm)
-    : octave_base_value (), matrix (cm.matrix) { }
+    : octave_base_matrix<ComplexMatrix> (cm) { }
 
   ~octave_complex_matrix (void) { }
 
   octave_value *clone (void) { return new octave_complex_matrix (*this); }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   octave_value *try_narrowing_conversion (void);
 
   octave_value do_index_op (const octave_value_list& idx);
@@ -87,21 +82,6 @@
 
   void assign (const octave_value_list& idx, const Matrix& rhs);
 
-  int rows (void) const { return matrix.rows (); }
-  int columns (void) const { return matrix.columns (); }
-
-  int length (void) const
-  {
-    int r = rows ();
-    int c = columns ();
-
-    return r > c ? r : c;
-  }
-
-  bool is_defined (void) const { return true; }
-
-  bool is_constant (void) const { return true; }
-
   bool is_complex_matrix (void) const { return true; }
 
   octave_value all (void) const { return matrix.all (); }
@@ -135,32 +115,11 @@
 
   void decrement (void) { matrix -= Complex (1.0); }
 
-  void print (ostream& os, bool pr_as_read_syntax = false) const;
-
-  void print_raw (ostream& os, bool pr_as_read_syntax = false) const;
-
-  bool print_name_tag (ostream& os, const string& name) const;
-
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
-  ComplexMatrix matrix;
-
-  static octave_allocator allocator;
+  DECLARE_OCTAVE_ALLOCATOR
 
-  // Type id of complex matrix objects, set by register_type().
-  static int t_id;
-
-  // Type name of complex matrix objects, defined in ov-cx-mat.cc.
-  static const string t_name;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
 #endif
--- a/src/ov-fcn.cc
+++ b/src/ov-fcn.cc
@@ -31,8 +31,7 @@
 #include "error.h"
 #include "ov-fcn.h"
 
-octave_allocator
-octave_function::allocator (sizeof (octave_function));
+DEFINE_OCTAVE_ALLOCATOR (octave_function);
 
 octave_function *
 octave_function::clone (void)
--- a/src/ov-fcn.h
+++ b/src/ov-fcn.h
@@ -53,12 +53,6 @@
 
   octave_function *clone (void);
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   bool is_defined (void) const { return true; }
 
   bool is_function (void) const { return true; }
@@ -94,8 +88,7 @@
   // The help text for this function.
   string doc;
 
-  // For custom memory management.
-  static octave_allocator allocator;
+  DECLARE_OCTAVE_ALLOCATOR
 };
 
 #endif
--- a/src/ov-file.cc
+++ b/src/ov-file.cc
@@ -36,14 +36,9 @@
 #include "ov-scalar.h"
 #include "unwind-prot.h"
 
-octave_allocator
-octave_file::allocator (sizeof (octave_file));
+DEFINE_OCTAVE_ALLOCATOR (octave_file);
 
-int
-octave_file::t_id (-1);
-
-const string
-octave_file::t_name ("file");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_file, "file");
 
 static octave_value *
 default_numeric_conversion_function (const octave_value& a)
--- a/src/ov-file.h
+++ b/src/ov-file.h
@@ -62,12 +62,6 @@
 
   octave_value *clone (void) { return new octave_file (*this); }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   type_conv_fcn numeric_conversion_function (void) const;
 
   double double_value (bool) const { return static_cast<double> (number); }
@@ -88,15 +82,6 @@
 
   bool print_name_tag (ostream& os, const string& name) const;
 
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
   // The stream object.
@@ -105,14 +90,9 @@
   // The number of the beast.
   int number;
 
-  // For custom memory management.
-  static octave_allocator allocator;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 
-  // Type id of list objects, set by register_type().
-  static int t_id;
-
-  // Type name of list objects, defined in ov-list.cc.
-  static const string t_name;
+  DECLARE_OCTAVE_ALLOCATOR
 };
 
 #endif
--- a/src/ov-list.cc
+++ b/src/ov-list.cc
@@ -38,14 +38,9 @@
 #include "ov-list.h"
 #include "unwind-prot.h"
 
-octave_allocator
-octave_list::allocator (sizeof (octave_list));
+DEFINE_OCTAVE_ALLOCATOR (octave_list);
 
-int
-octave_list::t_id (-1);
-
-const string
-octave_list::t_name ("list");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_list, "list");
 
 octave_value
 octave_list::do_index_op (const octave_value_list& idx)
@@ -54,19 +49,9 @@
 
   if (idx.length () == 1)
     {
-      int i = idx(0).int_value (true);
-
-      if (! error_state)
-	{
-	  int n = lst.length ();
+      idx_vector i = idx (0).index_vector ();
 
-	  if (i > 0 && i <= n)
-	    retval = lst(i-1);
-	  else
-	    error ("list index = %d out of range", i);
-	}
-      else
-	error ("list index must be an integer");
+      retval = octave_value_list (lst.index (i));
     }
   else
     error ("lists may only be indexed by a single scalar");
@@ -166,10 +151,53 @@
   return octave_value (args);
 }
 
+DEFUN (nth, args, ,
+  "nth (LIST, N)\n\
+\n\
+Return the N-th element of LIST.")
+{
+  octave_value retval;
+
+  if (args.length () == 2)
+    {
+      octave_value_list lst = args(0).list_value ();
+
+      if (! error_state)
+	{
+	  int n = args(1).int_value (true);
+
+	  if (! error_state)
+	    {
+	      if (n > 0 && n <= lst.length ())
+		retval = lst(n-1);
+	      else
+		error ("nth: index = %d out of range", n);
+	    }
+	  else
+	    error ("nth: second argument must be an integer");
+	}
+      else
+	error ("nth: first argument must be a list");
+    }
+  else
+    print_usage ("nth");
+
+  return retval;
+}
+
 DEFUN (append, args, ,
-  "append (LIST, ARGS)\n\
+  "append (LIST, ARG, ...)\n\
+\n\
+Return a new list created by appending each ARG to LIST.  If any of\n\
+the arguments to be appended is a list, its elements are appended\n\
+individually.  For example,\n\
 \n\
-Return a new list created by appending ARGS to LIST")
+  x = list (1, 2);\n\
+  y = list (3, 4);\n\
+  append (x, y);\n\
+\n\
+results in the list containing the four elements (1 2 3 4), not a list\n\
+containing the three elements (1 2 (3 4))")
 {
   octave_value retval;
 
@@ -182,7 +210,14 @@
       if (! error_state)
 	{
 	  for (int i = 1; i < nargin; i++)
-	    tmp.append (args(i));
+	    {
+	      octave_value ov = args(i);
+
+	      if (ov.is_list ())
+		tmp.append (ov.list_value ());
+	      else
+		tmp.append (ov);
+	    }
 
 	  retval = tmp;
 	}
@@ -223,7 +258,9 @@
 \n\
 Replace LENGTH elements of LIST_1 beginning at OFFSET with the\n\
 contents of LIST_2 (if any).  If LENGTH is omitted, all elements\n\
-from OFFSET to the end of LIST_1 are replaced.")
+from OFFSET to the end of LIST_1 are replaced.  As a special case, if\n\
+OFFSET is one greater than the length of LIST_1 and LENGTH is 0,\n\
+splice is equivalent to append (LIST_1, LIST_2)")
 {
   octave_value retval;
 
--- a/src/ov-list.h
+++ b/src/ov-list.h
@@ -64,12 +64,6 @@
 
   octave_value *clone (void) { return new octave_list (*this); }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   octave_value do_index_op (const octave_value_list& idx);
 
   void assign (const octave_value_list& idx, const octave_value& rhs);
@@ -90,28 +84,14 @@
 
   bool print_name_tag (ostream& os, const string& name) const;
 
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
   // The list of Octave values.
   octave_value_list lst;
 
-  // For custom memory management.
-  static octave_allocator allocator;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 
-  // Type id of list objects, set by register_type().
-  static int t_id;
-
-  // Type name of list objects, defined in ov-list.cc.
-  static const string t_name;
+  DECLARE_OCTAVE_ALLOCATOR
 };
 
 #endif
--- a/src/ov-mapper.cc
+++ b/src/ov-mapper.cc
@@ -34,14 +34,10 @@
 #include "ov-mapper.h"
 #include "ov.h"
 
-octave_allocator
-octave_mapper::allocator (sizeof (octave_mapper));
+DEFINE_OCTAVE_ALLOCATOR (octave_mapper);
 
-int
-octave_mapper::t_id (-1);
-
-const string
-octave_mapper::t_name ("built-in mapper function");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_mapper,
+				     "built-in mapper function");
 
 static bool
 any_element_less_than (const Matrix& a, double val)
--- a/src/ov-mapper.h
+++ b/src/ov-mapper.h
@@ -57,25 +57,10 @@
 
   ~octave_mapper (void) { }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   octave_function *function_value (bool) { return this; }
 
   octave_value_list do_index_op (int nargout, const octave_value_list& args);
 
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
   octave_mapper (void);
@@ -110,14 +95,9 @@
 
   int flag;
 
-  // For custom memory management.
-  static octave_allocator allocator;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 
-  // Type id of list objects, set by register_type().
-  static int t_id;
-
-  // Type name of list objects, defined in ov-list.cc.
-  static const string t_name;
+  DECLARE_OCTAVE_ALLOCATOR
 };
 
 #endif
--- a/src/ov-range.cc
+++ b/src/ov-range.cc
@@ -40,14 +40,9 @@
 #include "ov-scalar.h"
 #include "pr-output.h"
 
-octave_allocator
-octave_range::allocator (sizeof (octave_range));
+DEFINE_OCTAVE_ALLOCATOR (octave_range);
 
-int
-octave_range::t_id (-1);
-
-const string
-octave_range::t_name ("range");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_range, "range");
 
 static octave_value *
 default_numeric_conversion_function (const octave_value& a)
--- a/src/ov-range.h
+++ b/src/ov-range.h
@@ -81,12 +81,6 @@
 
   octave_value *clone (void) { return new octave_range (*this); }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   type_conv_fcn numeric_conversion_function (void) const;
 
   octave_value *try_narrowing_conversion (void);
@@ -152,26 +146,13 @@
 
   bool print_name_tag (ostream& os, const string& name) const;
 
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
   Range range;
 
-  static octave_allocator allocator;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 
-  // Type id of range objects, set by register_type ().
-  static int t_id;
-
-  // Type name of scalar objects, defined in ov-range.cc.
-  static const string t_name;
+  DECLARE_OCTAVE_ALLOCATOR
 };
 
 #endif
--- a/src/ov-re-mat.cc
+++ b/src/ov-re-mat.cc
@@ -38,29 +38,27 @@
 #include "oct-obj.h"
 #include "oct-lvalue.h"
 #include "ops.h"
+#include "ov-base.h"
+#include "ov-base-mat.h"
+#include "ov-base-mat.cc"
 #include "ov-scalar.h"
 #include "ov-re-mat.h"
 #include "pr-output.h"
 #include "variables.h"
 
-octave_allocator
-octave_matrix::allocator (sizeof (octave_matrix));
+template class octave_base_matrix<Matrix>;
 
-int
-octave_matrix::t_id (-1);
+DEFINE_OCTAVE_ALLOCATOR (octave_matrix);
 
-const string
-octave_matrix::t_name ("matrix");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_matrix, "matrix");
 
 octave_matrix::octave_matrix (const RowVector& v, int pcv)
-  : octave_base_value (),
-    matrix ((pcv < 0 && Vprefer_column_vectors) || pcv
-	    ? Matrix (v.transpose ()) : Matrix (v)) { }
+  : octave_base_matrix<Matrix> ((pcv < 0 && Vprefer_column_vectors) || pcv
+				? Matrix (v.transpose ()) : Matrix (v)) { }
 
 octave_matrix::octave_matrix (const ColumnVector& v, int pcv)
-  : octave_base_value (),
-    matrix ((pcv < 0 && Vprefer_column_vectors) || pcv
-	    ? Matrix (v) : Matrix (v.transpose ())) { }
+  : octave_base_matrix<Matrix> ((pcv < 0 && Vprefer_column_vectors) || pcv
+			       ? Matrix (v) : Matrix (v.transpose ())) { }
 
 octave_value *
 octave_matrix::try_narrowing_conversion (void)
@@ -370,43 +368,6 @@
   return retval;
 }
 
-void
-octave_matrix::print (ostream& os, bool pr_as_read_syntax) const
-{
-  print_raw (os, pr_as_read_syntax);
-  newline (os);
-}
-
-void
-octave_matrix::print_raw (ostream& os, bool pr_as_read_syntax) const
-{
-  octave_print_internal (os, matrix, pr_as_read_syntax,
-			 current_print_indent_level ());
-}
-
-bool
-octave_matrix::print_name_tag (ostream& os, const string& name) const
-{
-  bool retval = false;
-
-  int nr = rows ();
-  int nc = columns ();
-
-  indent (os);
-
-  if (nr == 1 && nc == 1 || (nr == 0 || nc == 0))
-    os << name << " = ";
-  else
-    {
-      os << name << " =";
-      newline (os);
-      newline (os);
-      retval = true;
-    }
-
-  return retval;
-}
-
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-re-mat.h
+++ b/src/ov-re-mat.h
@@ -39,6 +39,7 @@
 
 #include "error.h"
 #include "ov-base.h"
+#include "ov-base-mat.h"
 #include "ov-typeinfo.h"
 
 class Octave_map;
@@ -49,36 +50,30 @@
 // Real matrix values.
 
 class
-octave_matrix : public octave_base_value
+octave_matrix : public octave_base_matrix<Matrix>
 {
 public:
 
   octave_matrix (void)
-    : octave_base_value () { }
+    : octave_base_matrix<Matrix> () { }
 
   octave_matrix (const Matrix& m)
-    : octave_base_value (), matrix (m) { }
+    : octave_base_matrix<Matrix> (m) { }
 
   octave_matrix (const DiagMatrix& d)
-    : octave_base_value (), matrix (d) { }
+    : octave_base_matrix<Matrix> (d) { }
 
   octave_matrix (const RowVector& v, int pcv = -1);
 
   octave_matrix (const ColumnVector& v, int pcv = -1);
 
   octave_matrix (const octave_matrix& m)
-    : octave_base_value (), matrix (m.matrix) { }
+    : octave_base_matrix<Matrix> (m) { }
 
   ~octave_matrix (void) { }
 
   octave_value *clone (void) { return new octave_matrix (*this); }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   octave_value *try_narrowing_conversion (void);
 
   octave_value do_index_op (const octave_value_list& idx);
@@ -102,21 +97,6 @@
 
   octave_lvalue struct_elt_ref (octave_value *parent, const string& nm);
 
-  int rows (void) const { return matrix.rows (); }
-  int columns (void) const { return matrix.columns (); }
-
-  int length (void) const
-  {
-    int r = rows ();
-    int c = columns ();
-
-    return r > c ? r : c;
-  }
-
-  bool is_defined (void) const { return true; }
-
-  bool is_constant (void) const { return true; }
-
   bool is_real_matrix (void) const { return true; }
 
   octave_value all (void) const { return matrix.all (); }
@@ -152,32 +132,11 @@
 
   octave_value convert_to_str (void) const;
 
-  void print (ostream& os, bool pr_as_read_syntax = false) const;
-
-  void print_raw (ostream& os, bool pr_as_read_syntax = false) const;
-
-  bool print_name_tag (ostream& os, const string& name) const;
-
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
-  Matrix matrix;
-
-  static octave_allocator allocator;
+  DECLARE_OCTAVE_ALLOCATOR
 
-  // Type id of matrix objects, set by register_type ().
-  static int t_id;
-
-  // Type name of matrix objects, defined in ov-re-mat.cc.
-  static const string t_name;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
 #endif
--- a/src/ov-scalar.cc
+++ b/src/ov-scalar.cc
@@ -40,14 +40,9 @@
 #include "xdiv.h"
 #include "xpow.h"
 
-octave_allocator
-octave_scalar::allocator (sizeof (octave_scalar));
+DEFINE_OCTAVE_ALLOCATOR (octave_scalar);
 
-int
-octave_scalar::t_id (-1);
-
-const string
-octave_scalar::t_name ("scalar");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_scalar, "scalar");
 
 static inline bool
 valid_scalar_indices (const octave_value_list& args)
--- a/src/ov-scalar.h
+++ b/src/ov-scalar.h
@@ -67,12 +67,6 @@
 
   octave_value *clone (void) { return new octave_scalar (*this); }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   octave_value do_index_op (const octave_value_list& idx);
 
   idx_vector index_vector (void) const { return idx_vector (scalar); }
@@ -127,28 +121,14 @@
 
   bool print_name_tag (ostream& os, const string& name) const;
 
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
   // The value of this scalar.
   double scalar;
 
-  // For custom memory management.
-  static octave_allocator allocator;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 
-  // Type id of scalar objects, set by register_type().
-  static int t_id;
-
-  // Type name of scalar objects, defined in ov-scalar.cc.
-  static const string t_name;
+  DECLARE_OCTAVE_ALLOCATOR
 };
 
 #endif
--- a/src/ov-str-mat.cc
+++ b/src/ov-str-mat.cc
@@ -40,11 +40,9 @@
 #include "gripes.h"
 #include "pr-output.h"
 
-int
-octave_char_matrix_str::t_id (-1);
+DEFINE_OCTAVE_ALLOCATOR (octave_char_matrix_str);
 
-const string
-octave_char_matrix_str::t_name ("string");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_char_matrix_str, "string");
 
 static octave_value *
 default_numeric_conversion_function (const octave_value& a)
@@ -198,38 +196,10 @@
 }
 
 void
-octave_char_matrix_str::print (ostream& os, bool pr_as_read_syntax) const
-{
-  // indent (os);
-  print_raw (os, pr_as_read_syntax);
-  newline (os);
-}
-
-void
 octave_char_matrix_str::print_raw (ostream& os, bool pr_as_read_syntax) const
 {
-  octave_print_internal (os, matrix, pr_as_read_syntax, true,
-			 current_print_indent_level ());
-}
-
-bool
-octave_char_matrix_str::print_name_tag (ostream& os, const string& name) const
-{
-  bool retval = false;
-
-  indent (os);
-
-  if (rows () <= 1)
-    os << name << " = ";
-  else
-    {
-      os << name << " =";
-      newline (os);
-      newline (os);
-      retval = true;
-    }
-
-  return retval;
+  octave_print_internal (os, matrix, pr_as_read_syntax,
+			 current_print_indent_level (), true);
 }
 
 /*
--- a/src/ov-str-mat.h
+++ b/src/ov-str-mat.h
@@ -103,28 +103,15 @@
 
   string string_value (void) const;
 
-  void print (ostream& os, bool pr_as_read_syntax = false) const;
+  bool print_as_scalar (void) const { return (rows () <= 1); }
 
   void print_raw (ostream& os, bool pr_as_read_syntax = false) const;
 
-  bool print_name_tag (ostream& os, const string& name) const;
-
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
-  // Type id of char_matrix_str objects, set by register_type().
-  static int t_id;
+  DECLARE_OCTAVE_ALLOCATOR
 
-  // Type name of char_matrix_strXX objects, defined in ov-str-mat.cc.
-  static const string t_name;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
 #endif
--- a/src/ov-struct.cc
+++ b/src/ov-struct.cc
@@ -36,14 +36,9 @@
 #include "unwind-prot.h"
 #include "variables.h"
 
-octave_allocator
-octave_struct::allocator (sizeof (octave_struct));
+DEFINE_OCTAVE_ALLOCATOR(octave_struct);
 
-int
-octave_struct::t_id (-1);
-
-const string
-octave_struct::t_name ("struct");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct");
 
 octave_value
 octave_struct::do_struct_elt_index_op (const string& nm,
--- a/src/ov-struct.h
+++ b/src/ov-struct.h
@@ -67,12 +67,6 @@
 
   octave_value *clone (void) { return new octave_struct (*this); }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   octave_value
   do_struct_elt_index_op (const string& nm, const octave_value_list& idx,
 			  bool silent);
@@ -95,28 +89,14 @@
 
   bool print_name_tag (ostream& os, const string& name) const;
 
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
   // The associative array used to manage the structure data.
   Octave_map map;
 
-  // For custom memory management.
-  static octave_allocator allocator;
+  DECLARE_OCTAVE_ALLOCATOR
 
-  // Type id of struct objects, set by register_type().
-  static int t_id;
-
-  // Type name of struct objects, defined in ov-struct.cc.
-  static const string t_name;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
 #endif
--- a/src/ov-usr-fcn.cc
+++ b/src/ov-usr-fcn.cc
@@ -62,14 +62,10 @@
 
 // User defined functions.
 
-octave_allocator
-octave_user_function::allocator (sizeof (octave_user_function));
+DEFINE_OCTAVE_ALLOCATOR (octave_user_function);
 
-int
-octave_user_function::t_id (-1);
-
-const string
-octave_user_function::t_name ("user-defined function");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_user_function,
+				     "user-defined function");
 
 // Ugh.  This really needs to be simplified (code/data?
 // extrinsic/intrinsic state?).
--- a/src/ov-usr-fcn.h
+++ b/src/ov-usr-fcn.h
@@ -59,12 +59,6 @@
 
   ~octave_user_function (void);
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   octave_function *function_value (bool) { return this; }
 
   octave_user_function *define_param_list (tree_parameter_list *t);
@@ -129,15 +123,6 @@
 
   void accept (tree_walker& tw);
 
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
   octave_user_function (void);
@@ -206,15 +191,6 @@
   // The symbol record for nargout in the local symbol table.
   symbol_record *nargout_sr;
 
-  // For custom memory management.
-  static octave_allocator allocator;
-
-  // Type id of list objects, set by register_type().
-  static int t_id;
-
-  // Type name of list objects, defined in ov-list.cc.
-  static const string t_name;
-
   void print_code_function_header (void);
 
   void print_code_function_trailer (void);
@@ -223,6 +199,10 @@
 
   void bind_automatic_vars (const string_vector& arg_names, int nargin,
 			    int nargout);
+
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
+
+  DECLARE_OCTAVE_ALLOCATOR
 };
 
 #endif
--- a/src/ov-va-args.cc
+++ b/src/ov-va-args.cc
@@ -34,9 +34,7 @@
 #include "pr-output.h"
 #include "ov-va-args.h"
 
-int octave_all_va_args::t_id = -1;
-
-const string octave_all_va_args::t_name ("va-arg");
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_all_va_args, "va-arg");
 
 void
 octave_all_va_args::print (ostream& os, bool) const
--- a/src/ov-va-args.h
+++ b/src/ov-va-args.h
@@ -66,22 +66,9 @@
 
   void print_raw (ostream& os, bool pr_as_read_syntax = false) const;
 
-  int type_id (void) const { return t_id; }
-
-  string type_name (void) const { return t_name; }
-
-  static int static_type_id (void) { return t_id; }
-
-  static void register_type (void)
-    { t_id = octave_value_typeinfo::register_type (t_name); }
-
 private:
 
-  // Type id of all_va_arg objects, set by register_type().
-  static int t_id;
-
-  // Type name of all_va_arg objects, defined in ov-va-args.cc.
-  static const string t_name;
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
 #endif
--- a/src/ov.cc
+++ b/src/ov.cc
@@ -64,8 +64,7 @@
 
 // We are likely to have a lot of octave_value objects to allocate, so
 // make the grow_size large.
-octave_allocator
-octave_value::allocator (sizeof (octave_value), 1024);
+DEFINE_OCTAVE_ALLOCATOR2(octave_value, 1024);
 
 // If TRUE, allow assignments like
 //
--- a/src/ov.h
+++ b/src/ov.h
@@ -206,12 +206,6 @@
 	}
     }
 
-  void *operator new (size_t size)
-    { return allocator.alloc (size); }
-
-  void operator delete (void *p, size_t size)
-    { allocator.free (p, size); }
-
   // Simple assignment.
 
   octave_value& operator = (const octave_value& a)
@@ -505,8 +499,6 @@
 
 private:
 
-  static octave_allocator allocator;
-
   union
     {
       octave_value *rep;      // The real representation.
@@ -532,6 +524,8 @@
 
   void simple_assign (assign_op orig_op, const octave_value_list& idx,
 		      const octave_value& rhs);
+
+  DECLARE_OCTAVE_ALLOCATOR
 };
 
 #define OV_UNOP_FN(name) \
@@ -607,6 +601,24 @@
 
 OV_BINOP_FN (struct_ref)
 
+// T_ID is the type id of struct objects, set by register_type().
+// T_NAME is the type name of struct objects.
+#define DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA \
+  public: \
+    int type_id (void) const { return t_id; } \
+    string type_name (void) const { return t_name; } \
+    static int static_type_id (void) { return t_id; } \
+    static void register_type (void) \
+      { t_id = octave_value_typeinfo::register_type (t_name); } \
+ \
+  private: \
+    static int t_id; \
+    static const string t_name;
+
+#define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n) \
+  int t::t_id (-1); \
+  const string t::t_name (n)
+
 // If TRUE, allow assignments like
 //
 //   octave> A(1) = 3; A(2) = 5
--- a/src/version.h
+++ b/src/version.h
@@ -23,7 +23,7 @@
 #if !defined (octave_version_h)
 #define octave_version_h 1
 
-#define OCTAVE_VERSION "2.1.9"
+#define OCTAVE_VERSION "2.1.10"
 
 #define OCTAVE_COPYRIGHT \
   "Copyright (C) 1996, 1997, 1998 John W. Eaton."
@@ -37,7 +37,15 @@
 
 #define OCTAVE_STARTUP_MESSAGE \
   OCTAVE_NAME_VERSION_AND_COPYRIGHT "\n\
-For details, type `warranty'."
+For details, type `warranty'.\n\
+\n\
+*** This is a development version of Octave.  Development releases\n\
+*** are provided for people who want to help test, debug, and improve\n\
+*** Octave.\n\
+***\n\
+*** If you want a stable, well-tested version of Octave, you should be\n\
+*** using one of the stable releases (when this development release\n\
+*** was made, the latest stable version was 2.0.13)."
 
 #endif