changeset 4687:e95c86d48732

[project @ 2004-01-06 21:53:34 by jwe]
author jwe
date Tue, 06 Jan 2004 21:53:34 +0000
parents c7ae43dfdea4
children eaa2caaa35d6
files liboctave/CNDArray.cc liboctave/CNDArray.h liboctave/ChangeLog liboctave/dNDArray.cc liboctave/dNDArray.h src/ChangeLog src/load-save.cc src/load-save.h src/ls-hdf5.cc src/ls-hdf5.h src/ls-oct-ascii.cc src/ls-oct-ascii.h src/ls-oct-binary.cc 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-cell.cc src/ov-cell.h src/ov-complex.cc src/ov-complex.h src/ov-cx-mat.cc src/ov-cx-mat.h src/ov-list.cc src/ov-list.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-typeinfo.cc src/ov.h
diffstat 39 files changed, 3855 insertions(+), 1531 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/CNDArray.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/liboctave/CNDArray.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -29,10 +29,13 @@
 #include <config.h>
 #endif
 
+#include <cfloat>
+
 #include "Array-util.h"
 #include "CNDArray.h"
 #include "mx-base.h"
 #include "lo-ieee.h"
+#include "lo-mappers.h"
 
 // XXX FIXME XXX -- could we use a templated mixed-type copy function
 // here?
@@ -73,6 +76,114 @@
 
 // XXX FIXME XXX -- this is not quite the right thing.
 
+bool
+ComplexNDArray::any_element_is_inf_or_nan (void) const
+{
+  int nel = nelem ();
+
+  for (int i = 0; i < nel; i++)
+    {
+      Complex val = elem (i);
+      if (xisinf (val) || xisnan (val))
+	return true;
+    }
+  return false;
+}
+
+// Return true if no elements have imaginary components.
+
+bool
+ComplexNDArray::all_elements_are_real (void) const
+{
+  int nel = nelem ();
+
+  for (int i = 0; i < nel; i++)
+    {
+      double ip = imag (elem (i));
+
+      if (ip != 0.0 || lo_ieee_signbit (ip))
+	return false;
+    }
+
+  return true;
+}
+
+// Return nonzero if any element of CM has a non-integer real or
+// imaginary part.  Also extract the largest and smallest (real or
+// imaginary) values and return them in MAX_VAL and MIN_VAL. 
+
+bool
+ComplexNDArray::all_integers (double& max_val, double& min_val) const
+{
+  int nel = nelem ();
+
+  if (nel > 0)
+    {
+      Complex val = elem (0);
+
+      double r_val = real (val);
+      double i_val = imag (val);
+      
+      max_val = r_val;
+      min_val = r_val;
+
+      if (i_val > max_val)
+	max_val = i_val;
+
+      if (i_val < max_val)
+	min_val = i_val;
+    }
+  else
+    return false;
+
+  for (int i = 0; i < nel; i++)
+    {
+      Complex val = elem (i);
+
+      double r_val = real (val);
+      double i_val = imag (val);
+
+      if (r_val > max_val)
+	max_val = r_val;
+
+      if (i_val > max_val)
+	max_val = i_val;
+
+      if (r_val < min_val)
+	min_val = r_val;
+
+      if (i_val < min_val)
+	min_val = i_val;
+
+      if (D_NINT (r_val) != r_val || D_NINT (i_val) != i_val)
+	return false;
+    }
+
+  return true;
+}
+
+bool
+ComplexNDArray::too_large_for_float (void) const
+{
+  int nel = nelem ();
+
+  for (int i = 0; i < nel; i++)
+    {
+      Complex val = elem (i);
+
+      double r_val = real (val);
+      double i_val = imag (val);
+
+      if (r_val > FLT_MAX
+	  || i_val > FLT_MAX
+	  || r_val < FLT_MIN
+	  || i_val < FLT_MIN)
+	return true;
+    }
+
+  return false;
+}
+
 boolNDArray
 ComplexNDArray::all (int dim) const
 {
@@ -175,6 +286,47 @@
   return ::compute_index (ra_idx, dimensions);
 }
 
+
+// This contains no information on the array structure !!!
+std::ostream&
+operator << (std::ostream& os, const ComplexNDArray& a)
+{
+  int nel = a.nelem ();
+
+  for (int i = 0; i < nel; i++)
+    {
+      os << " ";
+      octave_write_complex (os, a.elem (i));
+      os << "\n";
+    }
+  return os;
+}
+
+std::istream&
+operator >> (std::istream& is, ComplexNDArray& a)
+{
+  int nel = a.nelem ();
+
+  if (nel < 1 )
+    is.clear (std::ios::badbit);
+  else
+    {
+      Complex tmp;
+      for (int i = 0; i < nel; i++)
+	  {
+	    tmp = octave_read_complex (is);
+	    if (is)
+	      a.elem (i) = tmp;
+	    else
+	      goto done;
+	  }
+    }
+
+ done:
+
+  return is;
+}
+
 NDS_CMP_OPS(ComplexNDArray, real, Complex, real)
 NDS_BOOL_OPS(ComplexNDArray, Complex, 0.0)
 
--- a/liboctave/CNDArray.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/liboctave/CNDArray.h	Tue Jan 06 21:53:34 2004 +0000
@@ -74,6 +74,11 @@
 
   // XXX FIXME XXX -- this is not quite the right thing.
 
+  bool any_element_is_inf_or_nan (void) const;
+  bool all_elements_are_real (void) const;
+  bool all_integers (double& max_val, double& min_val) const;
+  bool too_large_for_float (void) const;
+
   boolNDArray all (int dim = -1) const;
   boolNDArray any (int dim = -1) const;
 
@@ -98,8 +103,8 @@
 
   // i/o
 
-  // friend std::ostream& operator << (std::ostream& os, const NDArray& a);
-  // friend std::istream& operator >> (std::istream& is, NDArray& a);
+  friend std::ostream& operator << (std::ostream& os, const ComplexNDArray& a);
+  friend std::istream& operator >> (std::istream& is, ComplexNDArray& a);
 
   static Complex resize_fill_value (void) { return Complex (0.0, 0.0); }
 
--- a/liboctave/ChangeLog	Tue Jan 06 19:31:57 2004 +0000
+++ b/liboctave/ChangeLog	Tue Jan 06 21:53:34 2004 +0000
@@ -1,3 +1,14 @@
+2004-01-06  David Bateman  <dbateman@free.fr>
+
+ 	* CNDArray.cc (ComplexNDArray::any_element_is_inf_or_nan, 
+ 	ComplexNDArray::all_elements_are_real, ComplexNDArray::all_integers,
+ 	ComplexNDArray::too_large_for_float): New functions
+ 
+ 	* CNDArray.cc (operator <<, operator >>): New IO operators.
+ 	* CNDArray.h: Provide decls.
+ 	* dNDArray.cc (operator <<, operator >>): New IO operators.
+ 	* dNDArray.h: Provide decls.
+
 2003-12-10  John W. Eaton  <jwe@bevo.che.wisc.edu>
 
 	* mx-ops: Delete bnda x bnda, b x bnda, and bnda x b ops since
--- a/liboctave/dNDArray.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/liboctave/dNDArray.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -286,6 +286,46 @@
   return ::compute_index (ra_idx, dimensions);
 }
 
+// This contains no information on the array structure !!!
+std::ostream&
+operator << (std::ostream& os, const NDArray& a)
+{
+  int nel = a.nelem ();
+
+  for (int i = 0; i < nel; i++)
+    {
+      os << " ";
+      octave_write_double (os, a.elem (i));
+      os << "\n";
+    }
+  return os;
+}
+
+std::istream&
+operator >> (std::istream& is, NDArray& a)
+{
+  int nel = a.nelem ();
+
+  if (nel < 1 )
+    is.clear (std::ios::badbit);
+  else
+    {
+      double tmp;
+      for (int i = 0; i < nel; i++)
+	  {
+	    tmp = octave_read_double (is);
+	    if (is)
+	      a.elem (i) = tmp;
+	    else
+	      goto done;
+	  }
+    }
+
+ done:
+
+  return is;
+}
+
 NDS_CMP_OPS(NDArray, , double, )
 NDS_BOOL_OPS(NDArray, double, 0.0)
 
--- a/liboctave/dNDArray.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/liboctave/dNDArray.h	Tue Jan 06 21:53:34 2004 +0000
@@ -105,8 +105,8 @@
 
   // i/o
 
-  // friend std::ostream& operator << (std::ostream& os, const NDArray& a);
-  // friend std::istream& operator >> (std::istream& is, NDArray& a);
+  friend std::ostream& operator << (std::ostream& os, const NDArray& a);
+  friend std::istream& operator >> (std::istream& is, NDArray& a);
 
   static double resize_fill_value (void) { return 0; }
 
--- a/src/ChangeLog	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ChangeLog	Tue Jan 06 21:53:34 2004 +0000
@@ -1,3 +1,101 @@
+2004-01-06  David Bateman  <dbateman@free.fr>
+
+	* ls-hdf5.cc: Fix handle of old versus new format files.
+
+ 	* ls-oct-binary.cc: Split the load/save functionality into the types
+ 	themselves.  Backward compatibility maintained.
+	
+ 	* ov-struct.cc (save_binary, load_binary):
+ 	* ov-str-mat.cc (save_binary, load_binary):
+ 	* ov-scalar.cc (save_binary, load_binary):
+ 	* ov-re-mat.cc (save_binary, load_binary):
+ 	* ov-range.cc (save_binary, load_binary):
+ 	* ov-list.cc (save_binary, load_binary):
+ 	* ov-cx-mat.cc (save_binary, load_binary):
+ 	* ov-complex.cc (save_binary, load_binary):
+ 	* ov-cell.cc (save_binary, load_binary):
+ 	* ov-bool.cc (save_binary, load_binary):
+ 	* ov-bool-mat.cc (save_binary, load_binary):
+	New functions for loading and saving structures in octave binary
+	format.
+
+ 	* ov-str-mat.h (save_binary, load_binary):
+ 	* ov-scalar.h (save_binary, load_binary):
+ 	* ov-re-mat.h (save_binary, load_binary):
+ 	* ov-range.h (save_binary, load_binary):
+ 	* ov-list.h (save_binary, load_binary):
+ 	* ov-cx-mat.h (save_binary, load_binary):
+ 	* ov-complex.h (save_binary, load_binary):
+ 	* ov-cell.h (save_binary, load_binary):
+ 	* ov-bool.h (save_binary, load_binary):
+ 	* ov-bool-mat.h (save_binary, load_binary):
+ 	* ov-struct.h (save_binary, load_binary):
+	Provide decls.
+
+ 	* ov.h (save_binary, load_binary): New virtual functions.
+
+ 	* ov-base.cc (save_binary, load_binary): New functions, for fallbacks
+ 	with error message.
+ 	* ov-base.h: Provide decls.
+
+ 	* load-save.cc: Remove "-import" flag and make it the default.
+ 	* load-save.h: Likewise.
+
+ 	* ls-oct-ascii.cc: Split the load/save functionality into the types
+ 	themselves. Save "string" variables with the name "string" rather than
+ 	string array. Backward compatiability maintained in ov-cs-mat.cc.
+ 	Include new version of extract_keyword that halts if the next value is
+ 	invalid rather that searching for the next valid value.
+ 
+ 	* ls-oct-ascii.h: Extract_keyword header updated.
+	Include definition of OCT_RBV and CELL_ELT_TAG, since they are now
+	used elsewhere.
+ 
+ 	* ls-hdf5.cc: Split load/save functionality into the types themselves.
+ 	The hdf5 format is changed so that each object is a group with a
+ 	dataset "type" being a string with the octave_value type and the
+ 	dataset or group "value" containing the value of the data, struct, etc.
+ 	This allows extensibility. Backward compatibility is maintained. The
+ 	"import" flag is now assumed to always be true and has been removed.
+  
+ 	* ov-struct.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): 
+ 	* ov-str-mat.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): 
+ 	* ov-scalar.cc (save_ascii, load_ascii, save_hdf5, load_hdf5):
+	* ov-re-mat.cc (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-range.cc (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-list.cc (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-cx-mat.cc (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-complex.cc (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-cell.cc (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-bool.cc (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-bool-mat.cc (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	New functions for loading and saving structures in octave ascii
+	and hdf5 formatted files.
+
+ 	* ov-struct.h (save_ascii, load_ascii, save_hdf5, load_hdf5): 
+ 	* ov-str-mat.h (save_ascii, load_ascii, save_hdf5, load_hdf5): 
+ 	* ov-scalar.h (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-re-mat.h (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-range.h (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-list.h (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-cx-mat.h (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-complex.h (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-cell.h (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-bool.h (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	* ov-bool-mat.h (save_ascii, load_ascii, save_hdf5, load_hdf5):
+ 	Provide decls.
+ 
+ 	* ov-typeinfo.cc (octave_value_typeinfo::do_lookup_type): Include
+ 	make_unique so that the stored type value is not used for all loaded
+ 	variables.
+ 
+ 	* ov.h: (save_ascii, load_ascii, save_hdf5 and load_hdf5):
+	New virtual functions.
+ 	
+  	* ov-base.cc (save_ascii, load_ascii, save_hdf5, load_hdf5):
+	New functions, for fallbacks with error message.
+	* ov-base.h: Provide decls.
+
 2003-12-22  John W. Eaton  <jwe@bevo.che.wisc.edu>
 
 	* ov-cx-mat.cc (octave_complex_matrix::assign): RHS arg is N-d.
--- a/src/load-save.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/load-save.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -375,7 +375,7 @@
 octave_value
 do_load (std::istream& stream, const std::string& orig_fname, bool force,
 	 load_save_format format, oct_mach_info::float_format flt_fmt,
-	 bool list_only, bool swap, bool verbose, bool import,
+	 bool list_only, bool swap, bool verbose,
 	 const string_vector& argv, int argv_idx, int argc, int nargout)
 {
   octave_value retval;
@@ -415,8 +415,7 @@
 
 #ifdef HAVE_HDF5
 	case LS_HDF5:
-	  name = read_hdf5_data (stream, orig_fname,
-				 global, tc, doc, import);
+	  name = read_hdf5_data (stream, orig_fname, global, tc, doc);
 	  break;
 #endif /* HAVE_HDF5 */
 
@@ -586,19 +585,15 @@
 (HDF5 is a free, portable binary format developed by the National\n\
 Center for Supercomputing Applications at the University of Illinois.)\n\
 Note that Octave can read HDF5 files not created by itself, but may\n\
-skip some datasets in formats that it cannot support.  In particular,\n\
-it will skip datasets of data types that it does not recognize, with\n\
-dimensionality > 2, or with names that aren't valid Octave identifiers\n\
-See, however, the @samp{-import} option to ameliorate this somewhat.\n"
+skip some datasets in formats that it cannot support.\n"
 
 HAVE_HDF5_HELP_STRING
 
 "\n\
 @item -import\n\
-Make a stronger attempt to import foreign datasets.  Currently, this means\n\
-that for HDF5 files, invalid characters in names are converted to @samp{_},\n\
-and datasets with dimensionality > 2 are imported as lists of matrices (or\n\
-lists of lists of matrices, or ...).\n\
+The @samp{-import} is acceptted but ignored for backward compatiability.\n\
+Octave can now support multi-dimensional HDF data and automatically modifies\n\
+variable names if they are invalid Octave identifiers.\n\
 \n\
 @end table\n\
 @end deffn")
@@ -621,7 +616,6 @@
   bool force = false;
   bool list_only = false;
   bool verbose = false;
-  bool import = false;
 
   int i;
   for (i = 1; i < argc; i++)
@@ -665,7 +659,7 @@
 	}
       else if (argv[i] == "-import" || argv[i] == "-i")
 	{
-	  import = true;
+	  warning ("load: -import ignored");
 	}
       else
 	break;
@@ -700,7 +694,7 @@
 	  // can't fix this using std::cin only.
 
 	  retval = do_load (std::cin, orig_fname, force, format, flt_fmt,
-			    list_only, swap, verbose, import, argv, i, argc,
+			    list_only, swap, verbose, argv, i, argc,
 			    nargout);
 	}
       else
@@ -724,7 +718,7 @@
 	    {
 	      retval = do_load (hdf5_file, orig_fname, force, format,
 				flt_fmt, list_only, swap, verbose,
-				import, argv, i, argc, nargout);
+				argv, i, argc, nargout);
 
 	      hdf5_file.close ();
 	    }
@@ -768,7 +762,7 @@
 		}
 
 	      retval = do_load (file, orig_fname, force, format,
-				flt_fmt, list_only, swap, verbose, import,
+				flt_fmt, list_only, swap, verbose,
 				argv, i, argc, nargout);
 	      file.close ();
 	    }
@@ -1270,7 +1264,7 @@
 
 #ifdef HAVE_HDF5
       if (format == LS_HDF5)
-        error ("load: cannot write HDF5 format to stdout");
+        error ("save: cannot write HDF5 format to stdout");
       else
 #endif /* HAVE_HDF5 */
 	// don't insert any commands here!  the brace below must go
@@ -1310,11 +1304,12 @@
 	{
 	  hdf5_ofstream hdf5_file (fname.c_str ());
 
-	  if (hdf5_file.file_id >= 0) {
-	    save_vars (argv, i, argc, hdf5_file, save_builtins, format,
-		       save_as_floats, true);
+	  if (hdf5_file.file_id >= 0)
+	    {
+	      save_vars (argv, i, argc, hdf5_file, save_builtins, format,
+			 save_as_floats, true);
 
-	    hdf5_file.close ();
+	      hdf5_file.close ();
 	  }
 	else
 	  {
--- a/src/load-save.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/load-save.h	Tue Jan 06 21:53:34 2004 +0000
@@ -61,7 +61,7 @@
 extern octave_value
 do_load (std::istream& stream, const std::string& orig_fname, bool force,
 	 load_save_format format, oct_mach_info::float_format flt_fmt,
-	 bool list_only, bool swap, bool verbose, bool import,
+	 bool list_only, bool swap, bool verbose,
 	 const string_vector& argv, int argv_idx, int argc, int nargout);
 
 extern void
--- a/src/ls-hdf5.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ls-hdf5.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -73,9 +73,6 @@
 #include "ls-utils.h"
 #include "ls-hdf5.h"
 
-// this is only used for HDF5 import
-// try to convert s into a valid identifier, replacing invalid chars with "_":
-
 static std::string
 make_valid_identifier (const std::string& nm)
 {
@@ -98,25 +95,6 @@
   return retval;
 }
 
-static bool
-ident_is_all_digits (const std::string& id)
-{
-  bool retval = true;
-
-  size_t len = 0;
-
-  for (size_t i = 0; i < len; i++)
-    {
-      if (! isdigit (id[i]))
-	{
-	  retval = false;
-	  break;
-	}
-    }
-
-  return retval;
-}
-
 // Define this to 1 if/when HDF5 supports automatic conversion between
 // integer and floating-point binary data:
 #define HAVE_HDF5_INT2FLOAT_CONVERSIONS 0
@@ -148,110 +126,6 @@
   return true;
 }
 
-// Import a multidimensional (rank >= 3) dataset whose id is data_id, into tc.
-// This works by calling itself recursively, building up lists of lists
-//  of lists ... of 2d matrices.  rank and dims are the rank and dimensions
-//  of the dataset.  type_id is the datatype to read into.  If it is
-//  H5T_NATIVE_DOUBLE, we are reading a real matrix.  Otherwise, type_id
-//  is assumed to be a complex type for reading a complex matrix.
-//
-//  Upon entry, we should have curdim = rank - 1, start = an array
-//  of length rank = all zeros, and count = an array of length rank =
-//  all ones except for the first two dimensions which equal the corresponding
-//  entries in dims[]. 
-//
-//  Note that we process the dimensions in reverse order, reflecting
-//  the fact that Octave is uses column-major (Fortran-order) data while
-//  HDF5 is row-major.  This means that the HDF5 file is read
-//  non-contiguously, but on the other hand means that for a 3d array
-//  we get a list of xy-plane slices, which seems nice.  We could change
-//  this behavior without much trouble; what is the best thing to do?
-//
-//  Returns a positive value upon success.
-
-static herr_t
-hdf5_import_multidim (hid_t data_id, hid_t space_id, hsize_t rank,
-		      const hsize_t *dims, hsize_t curdim,
-		      hssize_t *start, const hsize_t *count,
-		      hid_t type_id, octave_value &tc)
-{
-  herr_t retval = 1;
-
-  if (rank < 3 || curdim < 1 || curdim >= rank)
-    return -1;
-
-  if (curdim == 1)
-    {
-      // import 2d dataset for 1st 2 dims directly as a matrix
-      int nr, nc;    // rows and columns
-      nc = dims[0];  // octave uses column-major & HDF5 uses row-major
-      nr = dims[1];
-
-      hid_t mem_space_id = H5Screate_simple (2, dims, 0);
-
-      if (mem_space_id < 0)
-	return -1;
-
-      if (H5Sselect_all (mem_space_id) < 0)
-	return -1;
-    
-      if (H5Sselect_hyperslab (space_id, H5S_SELECT_SET,
-			       start, 0, count, 0) < 0)
-	{
-	  H5Sclose (mem_space_id);
-	  return -1;
-	}
-    
-      if (type_id == H5T_NATIVE_DOUBLE)
-	{
-	  // real matrix
-	  Matrix m (nr, nc);
-	  double *re = m.fortran_vec ();
-	  if (H5Dread (data_id, type_id, mem_space_id, space_id,
-		       H5P_DEFAULT, (void *) re) < 0)
-	    retval = -1;  // error
-	  else
-	    tc = m;
-	}
-      else
-	{
-	  // assume that we are using complex numbers
-	  // complex matrix
-	  ComplexMatrix m (nr, nc);
-	  Complex *reim = m.fortran_vec ();
-	  if (H5Dread (data_id, type_id, mem_space_id, space_id,
-		       H5P_DEFAULT, (void *) X_CAST (double *, reim)) < 0)
-	    retval = -1;  // error
-	  else
-	    tc = m;
-	}
-    
-      H5Sclose (mem_space_id);
-
-    }
-  else
-    {
-      octave_value_list lst;
-
-      for (hsize_t i = 0; i < dims[curdim]; ++i)
-	{
-	  octave_value slice;
-	  start[curdim] = i;
-	  retval = hdf5_import_multidim (data_id, space_id, rank,
-					 dims, curdim-1, start, count,
-					 type_id, slice);
-	  if (retval < 0)
-	    break;
-	  lst.append (slice);
-	}
-
-      if (retval > 0)
-	tc = octave_value (lst);
-    }
-
-  return retval;
-}
-
 // Return true if loc_id has the attribute named attr_name, and false
 // otherwise.
 
@@ -288,13 +162,13 @@
   return retval;
 }
 
-// The following two subroutines create HDF5 representations of the way
-// we will store Octave complex and range types (pairs and triplets of
-// floating-point numbers, respectively).  NUM_TYPE is the HDF5 numeric
-// type to use for storage (e.g. H5T_NATIVE_DOUBLE to save as 'double').
-// Note that any necessary conversions are handled automatically by HDF5.
+// The following subroutines creates an HDF5 representations of the way
+// we will store Octave complex types (pairs of floating-point numbers).
+// NUM_TYPE is the HDF5 numeric type to use for storage (e.g. 
+// H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary 
+// conversions are handled automatically by HDF5.
 
-static hid_t
+hid_t
 hdf5_make_complex_type (hid_t num_type)
 {
   hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 2);
@@ -305,52 +179,6 @@
   return type_id;
 }
 
-static hid_t
-hdf5_make_range_type (hid_t num_type)
-{
-  hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 3);
-
-  H5Tinsert (type_id, "base", 0 * sizeof (double), num_type);
-  H5Tinsert (type_id, "limit", 1 * sizeof (double), num_type);
-  H5Tinsert (type_id, "increment", 2 * sizeof (double), num_type);
-
-  return type_id;
-}
-
-// Callback data structure for passing data to hdf5_read_next_data, below.
-
-struct
-hdf5_callback_data
-{
-  hdf5_callback_data (void)
-    : name (), global (false), tc (), doc (),
-      complex_type (hdf5_make_complex_type (H5T_NATIVE_DOUBLE)),
-      range_type (hdf5_make_range_type (H5T_NATIVE_DOUBLE)),
-      import (false) { }
-
-  // the following fields are set by hdf5_read_data on successful return:
-
-  // the name of the variable
-  std::string name;
-
-  // whether it is global
-  bool global;
-
-  // the value of the variable, in Octave form
-  octave_value tc;
-
-  // a documentation string (NULL if none)
-  std::string doc;
-
-  // the following fields are input to hdf5_read_data:
-
-  // HDF5 rep's of complex and range type
-  hid_t complex_type, range_type;
-
-  // whether to try extra hard to import "foreign" data
-  bool import;
-};
-
 // This variable, set in read_hdf5_data(), tells whether we are using
 // a version of HDF5 with a buggy H5Giterate (i.e. which neglects to
 // increment the index parameter to the next unread item).
@@ -366,10 +194,12 @@
 // -1 on error, and 0 to tell H5Giterate to continue on to the next item
 // (e.g. if NAME was a data type we don't recognize).
 
-static herr_t
+herr_t
 hdf5_read_next_data (hid_t group_id, const char *name, void *dv)
 {
   hdf5_callback_data *d = static_cast <hdf5_callback_data *> (dv);
+  hid_t type_id = -1, type_class_id = -1, data_id = -1, subgroup_id = -1,
+    space_id = -1;
 
   H5G_stat_t info;
   herr_t retval = 0;
@@ -380,7 +210,7 @@
   // Allow identifiers as all digits so we can load lists saved by
   // earlier versions of Octave.
 
-  if (! ident_valid && (d->import || ident_is_all_digits (vname)))
+  if (! ident_valid )
     {
       // fix the identifier, replacing invalid chars with underscores
       vname = make_valid_identifier (vname);
@@ -391,297 +221,9 @@
 
   H5Gget_objinfo (group_id, name, 1, &info);
 
-  if (info.type == H5G_DATASET && ident_valid)
+  if (info.type == H5G_GROUP && ident_valid)
     {
-      retval = 1;
-
-      hid_t data_id = H5Dopen (group_id, name);
-
-      if (data_id < 0)
-	{
-	  retval = data_id;
-
-	  goto done;
-	}
-
-      hid_t type_id = H5Dget_type (data_id);
-
-      hid_t type_class_id = H5Tget_class (type_id);
-
-#if HAVE_HDF5_INT2FLOAT_CONVERSIONS
-      if (type_class_id == H5T_INTEGER || type_class_id == H5T_FLOAT)
-	{
-#else
-      // hdf5 doesn't (yet) support automatic float/integer conversions
-      if (type_class_id == H5T_FLOAT)
-	{
-#endif
-	  // read real matrix or scalar variable
-
-	  hid_t space_id = H5Dget_space (data_id);
-
-	  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
-
-	  if (rank == 0)
-	    {
-	      // real scalar:
-	      double dtmp;
-	      if (H5Dread (data_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, 
-			   H5P_DEFAULT, (void *) &dtmp) < 0)
-		retval = -1;  // error
-	      else
-		d->tc = dtmp;
-	    }
-	  else if (rank > 0 && rank <= 2)
-	    {
-	      // real matrix
-	      OCTAVE_LOCAL_BUFFER (hsize_t, dims, rank);
-	      OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
-
-	      H5Sget_simple_extent_dims (space_id, dims, maxdims);
-
-	      int nr, nc;  // rows and columns
-	      // octave uses column-major & HDF5 uses row-major
-	      nc = dims[0];
-	      nr = rank > 1 ? dims[1] : 1;
-	      Matrix m (nr, nc);
-	      double *re = m.fortran_vec ();
-	      if (H5Dread (data_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, 
-			   H5P_DEFAULT, (void *) re) < 0)
-		retval = -1;  // error
-	      else
-		d->tc = m;
-	    }
-	  else if (rank >= 3 && d->import)
-	    {
-	      OCTAVE_LOCAL_BUFFER (hsize_t, dims, rank);
-	      OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
-
-	      H5Sget_simple_extent_dims (space_id, dims, maxdims);
-
-	      OCTAVE_LOCAL_BUFFER (hssize_t, start, rank);
-	      OCTAVE_LOCAL_BUFFER (hsize_t, count, rank);
-
-	      for (hsize_t i = 0; i < rank; ++i)
-		{
-		  start[i] = 0;
-		  count[i] = 1;
-		}
-	      count[0] = dims[0];
-	      count[1] = dims[1];
-	      retval = hdf5_import_multidim (data_id, space_id,
-					     rank, dims, rank-1,
-					     start, count,
-					     H5T_NATIVE_DOUBLE, d->tc);
-	    }
-	  else
-	    {
-	      warning ("load: can't read %d-dim. hdf5 dataset %s",
-		       rank, name);
-	      retval = 0;  // skip; we can't read 3+ dimensional datasets
-	    }
-
-	  H5Sclose (space_id);
-	}
-      else if (type_class_id == H5T_STRING)
-	{
-	  // read string variable
-	  hid_t space_id = H5Dget_space (data_id);
-	  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
-
-	  if (rank == 0)
-	    {
-	      // a single string:
-	      int slen = H5Tget_size (type_id);
-	      if (slen < 0)
-		retval = -1;  // error
-	      else
-		{
-		  OCTAVE_LOCAL_BUFFER (char, s, slen);
-		  // create datatype for (null-terminated) string
-		  // to read into:
-		  hid_t st_id = H5Tcopy (H5T_C_S1);
-		  H5Tset_size (st_id, slen);
-		  if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, 
-			       H5P_DEFAULT, (void *) s) < 0)
-		    {
-		      retval = -1;  // error
-		    }
-		  else
-		    d->tc = s;
-
-		  H5Tclose (st_id);
-		}
-	    }
-	  else if (rank == 1)
-	    {
-	      // string vector
-	      hsize_t elements, maxdim;
-	      H5Sget_simple_extent_dims (space_id, &elements, &maxdim);
-	      int slen = H5Tget_size (type_id);
-	      if (slen < 0)
-		retval = -1;  // error
-	      else
-		{
-		  // hdf5 string arrays store strings of all the
-		  // same physical length (I think), which is
-		  // slightly wasteful, but oh well.
-
-		  OCTAVE_LOCAL_BUFFER (char, s, elements * slen);
-
-		  // create datatype for (null-terminated) string
-		  // to read into:
-		  hid_t st_id = H5Tcopy (H5T_C_S1);
-		  H5Tset_size (st_id, slen);
-
-		  if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, 
-			       H5P_DEFAULT, (void *) s) < 0)
-		    retval = -1;  // error
-		  else
-		    {
-		      charMatrix chm (elements, slen - 1);
-		      for (hsize_t i = 0; i < elements; ++i)
-			{
-			  chm.insert (s + i*slen, i, 0);
-			}
-		      d->tc = octave_value (chm, true);
-		    }
-
-		  H5Tclose (st_id);
-		}
-	    }
-	  else
-	    {
-	      warning ("load: can't read %d-dim. hdf5 string vector %s",
-		       rank, name); 
-	      // skip; we can't read higher-dimensional string vectors
-	      retval = 0;
-	    }
-	}
-      else if (type_class_id == H5T_COMPOUND)
-	{
-	  // check for complex or range data:
-
-	  if (hdf5_types_compatible (type_id, d->complex_type))
-	    {
-	      // read complex matrix or scalar variable
-
-	      hid_t space_id = H5Dget_space (data_id);
-	      hsize_t rank = H5Sget_simple_extent_ndims (space_id);
-
-	      if (rank == 0)
-		{
-		  // complex scalar:
-		  Complex ctmp;
-		  if (H5Dread (data_id, d->complex_type, H5S_ALL,
-			       H5S_ALL, H5P_DEFAULT,
-			       (void *) X_CAST (double *, &ctmp)) < 0)
-		    retval = -1;  // error
-		  else
-		    d->tc = ctmp;
-		}
-	      else if (rank > 0 && rank <= 2)
-		{
-		  // complex matrix
-		  OCTAVE_LOCAL_BUFFER (hsize_t, dims, rank);
-		  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
-		  H5Sget_simple_extent_dims (space_id, dims, maxdims);
-		  int nr, nc;  // rows and columns
-		  // octave uses column-major & HDF5 uses row-major
-		  nc = dims[0];
-		  nr = rank > 1 ? dims[1] : 1;
-		  ComplexMatrix m (nr, nc);
-		  Complex *reim = m.fortran_vec ();
-		  if (H5Dread (data_id, d->complex_type, H5S_ALL,
-			       H5S_ALL, H5P_DEFAULT,
-			       (void *) X_CAST (double *, reim)) < 0)
-		    retval = -1;  // error
-		  else
-		    d->tc = m;
-		}
-	      else if (rank >= 3 && d->import)
-		{
-		  OCTAVE_LOCAL_BUFFER (hsize_t, dims, rank);
-		  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
-		  H5Sget_simple_extent_dims (space_id, dims, maxdims);
-		  OCTAVE_LOCAL_BUFFER (hssize_t, start, rank);
-		  OCTAVE_LOCAL_BUFFER (hsize_t, count, rank);
-		  for (hsize_t i = 0; i < rank; ++i)
-		    {
-		      start[i] = 0;
-		      count[i] = 1;
-		    }
-		  count[0] = dims[0];
-		  count[1] = dims[1];
-		  retval = hdf5_import_multidim (data_id, space_id,
-						 rank, dims, rank-1,
-						 start, count,
-						 d->complex_type,
-						 d->tc);
-		}
-	      else
-		{
-		  warning ("load: can't read %d-dim. hdf5 dataset %s",
-			   rank, name);
-		  // skip; we can't read 3+ dimensional datasets
-		  retval = 0;
-		}
-	      H5Sclose (space_id);
-	    }
-	  else if (hdf5_types_compatible (type_id, d->range_type))
-	    {
-	      // read range variable:
-	      hid_t space_id = H5Dget_space (data_id);
-	      hsize_t rank = H5Sget_simple_extent_ndims (space_id);
-
-	      if (rank == 0)
-		{
-		  double rangevals[3];
-		  if (H5Dread (data_id, d->range_type, H5S_ALL, H5S_ALL, 
-			       H5P_DEFAULT, (void *) rangevals) < 0)
-		    retval = -1;  // error
-		  else
-		    {
-		      Range r (rangevals[0], rangevals[1], rangevals[2]);
-		      d->tc = r;
-		    }
-		}
-	      else
-		{
-		  warning ("load: can't read range array `%s' in hdf5 file",
-			   name);
-		  // skip; we can't read arrays of range variables
-		  retval = 0;
-		}
-
-	      H5Sclose (space_id);
-	    }
-	  else
-	    {
-	      warning ("load: can't read `%s' (unknown compound datatype)",
-		       name);
-	      retval = 0; // unknown datatype; skip.
-	    }
-	}
-      else
-	{
-	  warning ("load: can't read `%s' (unknown datatype)", name);
-	  retval = 0; // unknown datatype; skip
-	}
-
-      H5Tclose (type_id);
-
-      // check for OCTAVE_GLOBAL attribute:
-      d->global = hdf5_check_attr (data_id, "OCTAVE_GLOBAL");
-
-      H5Dclose (data_id);
-    }
-  else if (info.type == H5G_GROUP && ident_valid)
-    {
-      // read in group as a list or a structure
-      retval = 1;
-
-      hid_t subgroup_id = H5Gopen (group_id, name);
+      subgroup_id = H5Gopen (group_id, name);
 
       if (subgroup_id < 0)
 	{
@@ -689,56 +231,153 @@
 	  goto done;
 	}
 
-      // an HDF5 group is treated as an octave structure by
-      // default (since that preserves name information), and an
-      // octave list otherwise.
-
-      bool is_list = hdf5_check_attr (subgroup_id, "OCTAVE_LIST");
-
-      hdf5_callback_data dsub;
-
-      dsub.complex_type = d->complex_type;
-      dsub.range_type = d->range_type;
-      dsub.import = d->import;
+      if (hdf5_check_attr (subgroup_id, "OCTAVE_NEW_FORMAT"))
+	{
+	  data_id = H5Dopen (subgroup_id, "type");
 
-      herr_t retval2;
-      octave_value_list lst;
-      Octave_map m;
-      int current_item = 0;
-      while ((retval2 = H5Giterate (group_id, name, &current_item,
-				    hdf5_read_next_data, &dsub)) > 0)
-	{
-	  if (is_list)
-	    lst.append (dsub.tc);
-	  else
+	  if (data_id < 0)
 	    {
-	      octave_value ov = dsub.tc;
-
-	      if (ov.is_list ())
-		m.assign (dsub.name, octave_value (ov.list_value ()));
-	      else
-		m.assign (dsub.name, ov);
+	      retval = data_id;
+	      goto done;
 	    }
 
-	  if (have_h5giterate_bug)
-	    current_item++;  // H5Giterate returned the last index processed
+	  type_id = H5Dget_type (data_id);
+
+	  type_class_id = H5Tget_class (type_id);
+
+	  if (type_class_id != H5T_STRING)
+	    goto done;
+	  
+	  space_id = H5Dget_space (data_id);
+	  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
+
+	  if (rank != 0)
+	    goto done;
+
+	  int slen = H5Tget_size (type_id);
+	  if (slen < 0)
+	    goto done;
+
+	  OCTAVE_LOCAL_BUFFER (char, typ, slen);
+
+	  // create datatype for (null-terminated) string to read into:
+	  hid_t st_id = H5Tcopy (H5T_C_S1);
+	  H5Tset_size (st_id, slen);
+
+	  if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, 
+		       (void *) typ) < 0)
+	    goto done;
+
+	  H5Tclose (st_id);
+	  H5Dclose (data_id);
+
+	  d->tc = octave_value_typeinfo::lookup_type (typ);
+
+	  retval = (d->tc.load_hdf5 (subgroup_id, "value", 
+		have_h5giterate_bug) ? 1 : -1);
+
+	  // check for OCTAVE_GLOBAL attribute:
+	  d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL");
+
+	  H5Gclose (subgroup_id);
 	}
-
-      if (retval2 < 0)
-	retval = retval2;
       else
 	{
-	  d->global = hdf5_check_attr (group_id, "OCTAVE_GLOBAL");
+	  // an HDF5 group is treated as an octave structure by
+	  // default (since that preserves name information), and an
+	  // octave list otherwise.
+
+	  if (hdf5_check_attr (subgroup_id, "OCTAVE_LIST"))
+	    d->tc = octave_value_typeinfo::lookup_type ("list");
+	  else
+	    d->tc = octave_value_typeinfo::lookup_type ("cell");
+	  
+	  // check for OCTAVE_GLOBAL attribute:
+	  d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL");
+
+	  H5Gclose (subgroup_id);
 
-	  if (is_list)
-	    d->tc = octave_value (lst);
-	  else
-	    d->tc = m;
+	  retval = (d->tc.load_hdf5 (group_id, name, have_h5giterate_bug) 
+		    ? 1 : -1);
+	}
+
+    }
+  else if (info.type == H5G_DATASET && ident_valid)
+    {
+      // For backwards compatiability.
+      data_id = H5Dopen (group_id, name);
+
+      if (data_id < 0)
+	{
+	  retval = data_id;
+	  goto done;
 	}
 
-      H5Gclose (subgroup_id);
+      type_id = H5Dget_type (data_id);
+      
+      type_class_id = H5Tget_class (type_id);
+
+#if HAVE_HDF5_INT2FLOAT_CONVERSIONS
+      if (type_class_id == H5T_INTEGER || type_class_id == H5T_FLOAT)
+#else
+      // hdf5 doesn't (yet) support automatic float/integer conversions
+      if (type_class_id == H5T_FLOAT)
+#endif
+	{
+	  space_id = H5Dget_space (data_id);
+
+	  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
+	  
+	  if (rank == 0)
+	    d->tc = octave_value_typeinfo::lookup_type ("scalar");
+	  else
+	    d->tc = octave_value_typeinfo::lookup_type ("matrix");
+
+	  H5Sclose (space_id);
+	}
+      else if (type_class_id == H5T_STRING)
+	d->tc = octave_value_typeinfo::lookup_type ("string");
+      else if (type_class_id == H5T_COMPOUND)
+	{
+	  hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
+
+	  if (hdf5_types_compatible (type_id, complex_type))
+	    {
+	      // read complex matrix or scalar variable
+	      space_id = H5Dget_space (data_id);
+	      hsize_t rank = H5Sget_simple_extent_ndims (space_id);
+		  
+	      if (rank == 0)
+		d->tc = octave_value_typeinfo::lookup_type ("complex scalar");
+	      else
+		d->tc = octave_value_typeinfo::lookup_type ("complex matrix");
+
+	      H5Sclose (space_id);
+	    }
+	  else
+	    // Assume that if its not complex its a range. If its not
+	    // it'll be rejected later in the range code
+	    d->tc = octave_value_typeinfo::lookup_type ("range");
+
+	  H5Tclose (complex_type);
+	}
+      else
+	{
+	  warning ("load: can't read `%s' (unknown datatype)", name);
+	  retval = 0; // unknown datatype; skip
+	}
+      
+      // check for OCTAVE_GLOBAL attribute:
+      d->global = hdf5_check_attr (data_id, "OCTAVE_GLOBAL");
+
+      H5Tclose (type_id);
+      H5Dclose (data_id);
+
+      retval = (d->tc.load_hdf5 (group_id, name, have_h5giterate_bug) 
+		? 1 : -1);
     }
-  else if (! ident_valid)
+
+  if (!ident_valid)
     {
       // should we attempt to handle invalid identifiers by converting
       // bad characters to '_', say?
@@ -747,10 +386,9 @@
     }
 
  done:
-
   if (retval < 0)
     error ("load: error while reading hdf5 item %s", name);
-
+  
   if (retval > 0)
     {
       // get documentation string, if any:
@@ -764,7 +402,7 @@
 	}
       else if (vname != name)
 	{
-	  // the name was changed by import; store the original name
+	  // the name was changed; store the original name
 	  // as the documentation string:
 	  d->doc = name;
 	}
@@ -780,13 +418,10 @@
 // an hdf5_ifstream.  Return the variable value in tc, its doc string
 // in doc, and whether it is global in global.  The return value is
 // the name of the variable, or NULL if none were found or there was
-// and error.  If import is true, we try extra hard to import "foreign"
-// datasets (not created by Octave), although we usually do a reasonable
-// job anyway.  (c.f. load -import documentation.)
+// and error.
 std::string
-read_hdf5_data (std::istream& is,
-		const std::string& /* filename */, bool& global,
-		octave_value& tc, std::string& doc, bool import)
+read_hdf5_data (std::istream& is, const std::string& /* filename */, 
+		bool& global, octave_value& tc, std::string& doc)
 {
   std::string retval;
 
@@ -795,8 +430,6 @@
   hdf5_ifstream& hs = (hdf5_ifstream&) is;
   hdf5_callback_data d;
 
-  d.import = import;
-
   // Versions of HDF5 prior to 1.2.2 had a bug in H5Giterate where it
   // would return the index of the last item processed instead of the
   // next item to be processed, forcing us to increment the index manually.
@@ -835,9 +468,6 @@
       // hdf5_read_next_data already printed one, probably.
     }
 
-  H5Tclose (d.complex_type);
-  H5Tclose (d.range_type);
-
   if (! d.name.empty ())
     retval = d.name;
 
@@ -877,7 +507,6 @@
   return retval;
 }
 
-
 // save_type_to_hdf5 is not currently used, since hdf5 doesn't yet support
 // automatic float<->integer conversions:
 
@@ -885,7 +514,7 @@
 
 // return the HDF5 type id corresponding to the Octave save_type
 
-static hid_t
+hid_t
 save_type_to_hdf5 (save_type st)
 {
   switch (st)
@@ -923,297 +552,68 @@
 // successful.  This function calls itself recursively for lists
 // (stored as HDF5 groups).
 
-static bool
+bool
 add_hdf5_data (hid_t loc_id, const octave_value& tc,
 	       const std::string& name, const std::string& doc,
 	       bool mark_as_global, bool save_as_floats)
 {
   hsize_t dims[3];
-  hid_t type_id = -1, space_id = -1, data_id = -1;
-  bool data_is_group = 0;
-  bool retval = 0;
-
-  if (tc.is_string ())
-    {
-      int nr = tc.rows ();
-      charMatrix chm = tc.char_matrix_value ();
-      int nc = chm.cols ();
-
-      // create datatype for (null-terminated) string to write from:
-      type_id = H5Tcopy (H5T_C_S1); H5Tset_size (type_id, nc + 1);
-      if (type_id < 0)
-	goto error_cleanup;
-
-      dims[0] = nr;
-      space_id = H5Screate_simple (nr > 0 ? 1 : 0, dims, (hsize_t*) 0);
-      if (space_id < 0)
-	goto error_cleanup;
-
-      data_id = H5Dcreate (loc_id, name.c_str (), 
-			   type_id, space_id, H5P_DEFAULT);
-      if (data_id < 0)
-	goto error_cleanup;
-
-      OCTAVE_LOCAL_BUFFER (char, s, nr * (nc + 1));
-
-      for (int i = 0; i < nr; ++i)
-	{
-	  std::string tstr = chm.row_as_string (i);
-	  strcpy (s + i * (nc+1), tstr.c_str ());
-	}
-
-      if (H5Dwrite (data_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT,
-		    (void*) s) < 0) {
-	goto error_cleanup;
-      }
-    }
-  else if (tc.is_range ())
-    {
-      space_id = H5Screate_simple (0, dims, (hsize_t*) 0);
-      if (space_id < 0)
-	goto error_cleanup;
-
-      type_id = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
-      if (type_id < 0)
-	goto error_cleanup;
-
-      data_id = H5Dcreate (loc_id, name.c_str (), 
-			   type_id, space_id, H5P_DEFAULT);
-      if (data_id < 0)
-	goto error_cleanup;
-    
-      Range r = tc.range_value ();
-      double range_vals[3];
-      range_vals[0] = r.base ();
-      range_vals[1] = r.limit ();
-      range_vals[2] = r.inc ();
+  hid_t type_id = -1, space_id = -1, data_id = -1, data_type_id = -1;
+  bool retval = false;
+  octave_value val = tc;
+  std::string t = tc.type_name();
 
-      if (H5Dwrite (data_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT,
-		    (void*) range_vals) < 0)
-	goto error_cleanup;
-    }
-  else if (tc.is_real_scalar ())
-    {
-      space_id = H5Screate_simple (0, dims, (hsize_t*) 0);
-      if (space_id < 0) goto error_cleanup;
-
-      data_id = H5Dcreate (loc_id, name.c_str (), 
-			   H5T_NATIVE_DOUBLE, space_id, H5P_DEFAULT);
-      if (data_id < 0)
-	goto error_cleanup;
-
-      double tmp = tc.double_value ();
-      if (H5Dwrite (data_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
-		    H5P_DEFAULT, (void*) &tmp) < 0)
-	goto error_cleanup;
-    }
-  else if (tc.is_real_matrix ())
-    {
-      Matrix m = tc.matrix_value ();
-      dims[1] = m.rows ();    // Octave uses column-major, while
-      dims[0] = m.columns (); // HDF5 uses row-major ordering
-
-      space_id = H5Screate_simple (dims[1] > 1 ?2:1, dims, (hsize_t*) 0);
-      if (space_id < 0)
-	goto error_cleanup;
-
-      hid_t save_type_id = H5T_NATIVE_DOUBLE;
-
-      if (save_as_floats)
-	{
-	  if (m.too_large_for_float ())
-	    {
-	      warning ("save: some values too large to save as floats --");
-	      warning ("save: saving as doubles instead");
-	    }
-	  else
-	    save_type_id = H5T_NATIVE_FLOAT;
-	}
-#if HAVE_HDF5_INT2FLOAT_CONVERSIONS
-      // hdf5 currently doesn't support float/integer conversions
-      else
-	{
-	  double max_val, min_val;
-
-	  if (m.all_integers (max_val, min_val))
-	    save_type_id
-	      = save_type_to_hdf5 (get_save_type (max_val, min_val));
-	}
-#endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */
-
-      data_id = H5Dcreate (loc_id, name.c_str (), 
-			   save_type_id, space_id, H5P_DEFAULT);
-      if (data_id < 0)
-	goto error_cleanup;
-    
-      double *mtmp = m.fortran_vec ();
-      if (H5Dwrite (data_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
-		    H5P_DEFAULT, (void*) mtmp) < 0)
-	goto error_cleanup;
-    }
-  else if (tc.is_complex_scalar ())
-    {
-      space_id = H5Screate_simple (0, dims, (hsize_t*) 0);
-      if (space_id < 0)
-	goto error_cleanup;
+  data_id = H5Gcreate (loc_id, name.c_str (), 0);
+  if (data_id < 0)
+    goto error_cleanup;
 
-      type_id = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
-      if (type_id < 0)
-	goto error_cleanup;
-
-      data_id = H5Dcreate (loc_id, name.c_str (), 
-			   type_id, space_id, H5P_DEFAULT);
-      if (data_id < 0)
-	goto error_cleanup;
-
-      Complex tmp = tc.complex_value ();
-      if (H5Dwrite (data_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT,
-		    (void*) X_CAST (double*, &tmp)) < 0)
-	goto error_cleanup;
-    }
-  else if (tc.is_complex_matrix ())
-    {
-      ComplexMatrix m = tc.complex_matrix_value ();
-
-      dims[1] = m.rows ();    // Octave uses column-major, while
-      dims[0] = m.columns (); // HDF5 uses row-major ordering
-
-      space_id = H5Screate_simple (dims[1] > 1 ?2:1, dims, (hsize_t*) 0);
-      if (space_id < 0)
-	goto error_cleanup;
-
-      hid_t save_type_id = H5T_NATIVE_DOUBLE;
-
-      if (save_as_floats)
-	{
-	  if (m.too_large_for_float ())
-	    {
-	      warning ("save: some values too large to save as floats --");
-	      warning ("save: saving as doubles instead");
-	    }
-	  else
-	    save_type_id = H5T_NATIVE_FLOAT;
-	}
-#if HAVE_HDF5_INT2FLOAT_CONVERSIONS
-      // hdf5 currently doesn't support float/integer conversions
-      else
-	{
-	  double max_val, min_val;
-
-	  if (m.all_integers (max_val, min_val))
-	    save_type_id
-	      = save_type_to_hdf5 (get_save_type (max_val, min_val));
-	}
-#endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */
-
-      type_id = hdf5_make_complex_type (save_type_id);
-      if (type_id < 0) goto error_cleanup;
-
-      data_id = H5Dcreate (loc_id, name.c_str (), 
-			   type_id, space_id, H5P_DEFAULT);
-      if (data_id < 0)
-	goto error_cleanup;
-    
-      hid_t complex_type_id = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
-      if (complex_type_id < 0)
-	goto error_cleanup;
+  // attach the type of the variable
+  type_id = H5Tcopy (H5T_C_S1); H5Tset_size (type_id, t.length () + 1);
+  if (type_id < 0)
+    goto error_cleanup;
 
-      Complex *mtmp = m.fortran_vec ();
-      if (H5Dwrite (data_id, complex_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT,
-		    (void*) X_CAST (double *, mtmp)) < 0)
-	{
-	  H5Tclose (complex_type_id);
-	  goto error_cleanup;
-	}
-
-      H5Tclose (complex_type_id);
-    }
-  else if (tc.is_list ())
-    {
-      data_id = H5Gcreate (loc_id, name.c_str (), 0);
-      if (data_id < 0)
-	goto error_cleanup;
-
-      data_is_group = 1;
-
-      // recursively add each element of the list to this group
-      octave_value_list lst = tc.list_value ();
-
-      for (int i = 0; i < lst.length (); ++i)
-	{
-	  // should we use lst.name_tags () to label the elements?
-	  char s[20];
-	  sprintf (s, "_%d", i);
-	  bool retval2 = add_hdf5_data (data_id, lst (i), s, "",
-					false, save_as_floats);
-	  if (! retval2)
-	    goto error_cleanup;
-	}
+  dims[0] = 0;
+  space_id = H5Screate_simple (0 , dims, (hsize_t*) 0);
+  if (space_id < 0)
+    goto error_cleanup;
 
-      // mark with an attribute "OCTAVE_LIST" with value 1
-      // to distinguish from structures (also stored as HDF5 groups):
-      if (hdf5_add_attr (data_id, "OCTAVE_LIST") < 0)
-	goto error_cleanup;
-    }
-  else if (tc.is_map ())
-    {
-      // an Octave structure
-      data_id = H5Gcreate (loc_id, name.c_str (), 0);
-      if (data_id < 0)
-	goto error_cleanup;
-
-      data_is_group = 1;
+  data_type_id = H5Dcreate (data_id, "type",  type_id, space_id, H5P_DEFAULT);
+  if (data_type_id < 0 || H5Dwrite (data_type_id, type_id, H5S_ALL, H5S_ALL, 
+				    H5P_DEFAULT, (void*) t.c_str ()) < 0)
+    goto error_cleanup;
 
-      // recursively add each element of the structure to this group
-      const Octave_map m = tc.map_value ();
-      Octave_map::const_iterator i = m.begin ();
-      while (i != m.end ())
-	{
-	  // XXX FIXME XXX -- if the length of the structure array is
-	  // 1, should we really create a list object?
-	  bool retval2 = add_hdf5_data (data_id, octave_value (m.contents (i)),
-					m.key (i), "", false, save_as_floats);
-	  if (! retval2)
-	    goto error_cleanup;
-
-	  i++;
-	}
-    }
-  else
-    {
-      gripe_wrong_type_arg ("save", tc, false);
-      goto error_cleanup;
-    }
+  // Now call the real function to save the variable
+  retval = val.save_hdf5 (data_id, "value", save_as_floats);
 
   // attach doc string as comment:
-  if (doc.length () > 0
+  if (retval && doc.length () > 0
       && H5Gset_comment (loc_id, name.c_str (), doc.c_str ()) < 0)
-    goto error_cleanup;
-
-  retval = 1;
+    retval = false;
 
   // if it's global, add an attribute "OCTAVE_GLOBAL" with value 1
-  if (mark_as_global)
+  if (retval && mark_as_global)
     retval = hdf5_add_attr (data_id, "OCTAVE_GLOBAL") >= 0;
 
+  // We are saving in the new variable format, so mark it
+  if (retval)
+    retval = hdf5_add_attr (data_id, "OCTAVE_NEW_FORMAT") >= 0;
+
  error_cleanup:
 
-  if (! retval)
-    error ("save: error while writing `%s' to hdf5 file", name.c_str ());
+  if (data_type_id >= 0)
+    H5Dclose (data_type_id);
 
-  if (data_id >= 0)
-    {
-      if (data_is_group)
-	H5Gclose (data_id);
-      else
-	H5Dclose (data_id);
-    }
+  if (type_id >= 0)
+    H5Tclose (type_id);
 
   if (space_id >= 0)
     H5Sclose (space_id);
 
-  if (type_id >= 0)
-    H5Tclose (type_id);
+  if (data_id >= 0)
+    H5Gclose (data_id);
+
+  if (! retval)
+    error ("save: error while writing `%s' to hdf5 file", name.c_str ());
 
   return retval;
 }
--- a/src/ls-hdf5.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ls-hdf5.h	Tue Jan 06 21:53:34 2004 +0000
@@ -109,10 +109,51 @@
     { hdf5_fstreambase::open (name, mode, prot); }
 };
 
+// Callback data structure for passing data to hdf5_read_next_data, below.
+
+struct
+hdf5_callback_data
+{
+  hdf5_callback_data (void)
+    : name (), global (false), tc (), doc () { }
+
+  // the following fields are set by hdf5_read_data on successful return:
+
+  // the name of the variable
+  std::string name;
+
+  // whether it is global
+  bool global;
+
+  // the value of the variable, in Octave form
+  octave_value tc;
+
+  // a documentation string (NULL if none)
+  std::string doc;
+};
+
+#if HAVE_HDF5_INT2FLOAT_CONVERSIONS
+extern hid_t
+save_type_to_hdf5 (save_type st)
+#endif
+
+extern hid_t
+hdf5_make_complex_type (hid_t num_type);
+
+extern bool
+hdf5_types_compatible (hid_t t1, hid_t t2);
+
+extern herr_t
+hdf5_read_next_data (hid_t group_id, const char *name, void *dv);
+
+extern bool
+add_hdf5_data (hid_t loc_id, const octave_value& tc,
+	       const std::string& name, const std::string& doc,
+	       bool mark_as_global, bool save_as_floats);
+
 extern std::string
-read_hdf5_data (std::istream& is,
-		const std::string& filename, bool& global,
-		octave_value& tc, std::string& doc, bool import);
+read_hdf5_data (std::istream& is,  const std::string& filename, bool& global,
+		octave_value& tc, std::string& doc);
 
 extern bool
 save_hdf5_data (std::ostream& os, const octave_value& tc,
--- a/src/ls-oct-ascii.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ls-oct-ascii.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -26,7 +26,6 @@
 #include <config.h>
 #endif
 
-#include <cfloat>
 #include <cstring>
 #include <cctype>
 
@@ -71,27 +70,8 @@
 // The number of decimal digits to use when writing ascii data.
 static int Vsave_precision;
 
-#define CELL_ELT_TAG "<cell-element>"
-
-// Used when converting Inf to something that gnuplot can read.
-
-#ifndef OCT_RBV
-#define OCT_RBV DBL_MAX / 100.0
-#endif
-
 // Functions for reading ascii data.
 
-static void
-ascii_save_type (std::ostream& os, const char *type, bool mark_as_global)
-{
-  if (mark_as_global)
-    os << "# type: global ";
-  else
-    os << "# type: ";
-
-  os << type << "\n";
-}
-
 static Matrix
 strip_infnan (const Matrix& m)
 {
@@ -123,69 +103,6 @@
   return retval;
 }
 
-static ComplexMatrix
-strip_infnan (const ComplexMatrix& m)
-{
-  int nr = m.rows ();
-  int nc = m.columns ();
-
-  ComplexMatrix retval (nr, nc);
-
-  int k = 0;
-  for (int i = 0; i < nr; i++)
-    {
-      for (int j = 0; j < nc; j++)
-	{
-	  Complex c = m (i, j);
-	  if (xisnan (c))
-	    goto next_row;
-	  else
-	    {
-	      double re = real (c);
-	      double im = imag (c);
-
-	      re = xisinf (re) ? (re > 0 ? OCT_RBV : -OCT_RBV) : re;
-	      im = xisinf (im) ? (im > 0 ? OCT_RBV : -OCT_RBV) : im;
-
-	      retval (k, j) = Complex (re, im);
-	    }
-	}
-      k++;
-
-    next_row:
-      continue;
-    }
-
-  if (k > 0)
-    retval.resize (k, nc);
-
-  return retval;
-}
-
-// Skip white space and comments on stream IS.
-
-static void
-skip_comments (std::istream& is)
-{
-  char c = '\0';
-  while (is.get (c))
-    {
-      if (c == ' ' || c == '\t' || c == '\n')
-	; // Skip whitespace on way to beginning of next line.
-      else
-	break;
-    }
-
-  for (;;)
-    {
-      if (is && (c == '%' || c == '#'))
-	while (is.get (c) && c != '\n')
-	  ; // Skip to beginning of next line, ignoring everything.
-      else
-	break;
-    }
-}
-
 // Extract a KEYWORD and its value from stream IS, returning the
 // associated value in a new string.
 //
@@ -194,7 +111,7 @@
 //  [%#][ \t]*keyword[ \t]*:[ \t]*string-value[ \t]*\n
 
 std::string
-extract_keyword (std::istream& is, const char *keyword)
+extract_keyword (std::istream& is, const char *keyword, const bool next_only)
 {
   std::string retval;
 
@@ -236,6 +153,8 @@
 	      OSSTREAM_FREEZE (value);
 	      break;
 	    }
+	  else if (next_only)
+	    break;
 	}
     }
 
@@ -267,8 +186,9 @@
 //
 //  [%#][ \t]*keyword[ \t]*int-value.*\n
 
-static bool
-extract_keyword (std::istream& is, const char *keyword, int& value)
+bool
+extract_keyword (std::istream& is, const char *keyword, int& value, 
+		 const bool next_only)
 {
   bool status = false;
   value = 0;
@@ -308,6 +228,8 @@
 		; // Skip to beginning of next line;
 	      break;
 	    }
+	  else if (next_only)
+	    break;
 	}
     }
   return status;
@@ -317,6 +239,9 @@
 // place it in TC, returning the name of the variable.  If the value
 // is tagged as global in the file, return TRUE in GLOBAL.
 //
+// Each type supplies its own function to load the data, and so this
+// function is extensible.
+//
 // FILENAME is used for error messages.
 //
 // The data is expected to be in the following format:
@@ -334,7 +259,7 @@
 // # type: <type>
 // # <info>
 //
-// Where:
+// Where, for the built in types are:
 //
 //  <name> : a valid identifier
 //
@@ -345,21 +270,25 @@
 //             | complex scalar
 //             | matrix
 //             | complex matrix
+//             | bool
+//             | bool matrix
 //             | string
 //             | range
-//             | string array
 //
 //  <info> : <matrix info>
 //         | <string info>
-//         | <string array info>
 //
 //  <matrix info> : # rows: <integer>
 //                : # columns: <integer>
 //
-//  <string info> : # length: <integer>
+//  <string info> : # elements: <integer>
+//                : # length: <integer> (once before each string)
 //
-//  <string array info> : # elements: <integer>
-//                      : # length: <integer> (once before each string)
+//  For backward compatibility the type "string array" is treated as a
+// "string" type. Also "string" can have a single element with no elements
+// line such that
+//
+//  <string info> : # length: <integer>
 //
 // Formatted ASCII data follows the header.
 //
@@ -375,7 +304,7 @@
 // Example:
 //
 //  # name: foo
-//  # type: string array
+//  # type: string
 //  # elements: 5
 //  # length: 4
 //  this
@@ -389,7 +318,8 @@
 //  array
 //
 // XXX FIXME XXX -- this format is fairly rigid, and doesn't allow for
-// arbitrary comments, etc.  Someone should fix that.
+// arbitrary comments.  Someone should fix that. It does allow arbitrary
+// types however.
 
 // Ugh.  The signature of the compare method is not standard in older
 // versions of the GNU libstdc++.  Do this instead:
@@ -442,196 +372,13 @@
       else
 	typ = tag;
 
-      if (SUBSTRING_COMPARE_EQ (typ, 0, 6, "scalar"))
-	{
-	  double tmp = octave_read_double (is);
-	  if (is)
-	    tc = tmp;
-	  else
-	    error ("load: failed to load scalar constant");
-	}
-      else if (SUBSTRING_COMPARE_EQ (typ, 0, 6, "matrix"))
-	{
-	  int nr = 0;
-	  int nc = 0;
-
-	  if (extract_keyword (is, "rows", nr) && nr >= 0
-	      && extract_keyword (is, "columns", nc) && nc >= 0)
-	    {
-	      if (nr > 0 && nc > 0)
-		{
-		  Matrix tmp (nr, nc);
-		  is >> tmp;
-		  if (is)
-		    tc = tmp;
-		  else
-		    error ("load: failed to load matrix constant");
-		}
-	      else if (nr == 0 || nc == 0)
-		tc = Matrix (nr, nc);
-	      else
-		panic_impossible ();
-	    }
-	  else
-	    error ("load: failed to extract number of rows and columns");
-	}
-      else if (SUBSTRING_COMPARE_EQ (typ, 0, 4, "cell"))
-	{
-	  int nr = 0;
-	  int nc = 0;
-
-	  if (extract_keyword (is, "rows",    nr) && nr >= 0
-	      && extract_keyword (is, "columns", nc) && nc >= 0)
-	    {
-	      if (nr > 0 && nc > 0)
-		{
-		  Cell tmp (nr, nc);
-
-		  for (int j = 0; j < nc; j++)
-		    {
-		      for (int i = 0; i < nr; i++)
-			{
-			  octave_value t2;
-
-			  // recurse to read cell elements
-			  std::string nm
-			    = read_ascii_data (is, filename, global, t2, count);
-
-			  if (nm == CELL_ELT_TAG)
-			    {
-			      if (is)
-				tmp.elem (i, j) = t2;
-			    }
-			  else
-			    {
-			      error ("load: cell array element had unexpected name");
-			      goto cell_read_error;
-			    }
-			}
-		    }
-
-		cell_read_error:
+      // Special case for backward compatiablity. A small bit of cruft
+      if (SUBSTRING_COMPARE_EQ (typ, 0, 12, "string array"))
+	tc = octave_value (charMatrix (), true);
+      else
+	tc = octave_value_typeinfo::lookup_type (typ);
 
-		  if (is)
-		    tc = tmp;
-		  else
-		    error ("load: failed to load cell element");
-		}
-	      else if (nr == 0 || nc == 0)
-		tc = Cell (nr, nc);
-	      else
-		panic_impossible ();
-	    }
-	  else
-	    error ("load: failed to extract number of rows and columns for cell array");
-	}
-      else if (SUBSTRING_COMPARE_EQ (typ, 0, 14, "complex scalar"))
-	{
-	  Complex tmp = octave_read_complex (is);
-	  if (is)
-	    tc = tmp;
-	  else
-	    error ("load: failed to load complex scalar constant");
-	}
-      else if (SUBSTRING_COMPARE_EQ (typ, 0, 14, "complex matrix"))
-	{
-	  int nr = 0;
-	  int nc = 0;
-
-	  if (extract_keyword (is, "rows", nr) && nr > 0
-	      && extract_keyword (is, "columns", nc) && nc > 0)
-	    {
-	      ComplexMatrix tmp (nr, nc);
-	      is >> tmp;
-	      if (is)
-		tc = tmp;
-	      else
-		error ("load: failed to load complex matrix constant");
-	    }
-	  else
-	    error ("load: failed to extract number of rows and columns");
-	}
-      else if (SUBSTRING_COMPARE_EQ (typ, 0, 12, "string array"))
-	{
-	  int elements;
-	  if (extract_keyword (is, "elements", elements) && elements >= 0)
-	    {
-	      // XXX FIXME XXX -- need to be able to get max length
-	      // before doing anything.
-
-	      charMatrix chm (elements, 0);
-	      int max_len = 0;
-	      for (int i = 0; i < elements; i++)
-		{
-		  int len;
-		  if (extract_keyword (is, "length", len) && len >= 0)
-		    {
-		      OCTAVE_LOCAL_BUFFER (char, tmp, len+1);
-
-		      if (len > 0 && ! is.read (X_CAST (char *, tmp), len))
-			{
-			  error ("load: failed to load string constant");
-			  break;
-			}
-		      else
-			{
-			  tmp [len] = '\0';
-			  if (len > max_len)
-			    {
-			      max_len = len;
-			      chm.resize (elements, max_len, 0);
-			    }
-			  chm.insert (tmp, i, 0);
-			}
-		    }
-		  else
-		    error ("load: failed to extract string length for element %d", i+1);
-		}
-
-	      if (! error_state)
-		tc = octave_value (chm, true);
-	    }
-	  else
-	    error ("load: failed to extract number of string elements");
-	}
-      else if (SUBSTRING_COMPARE_EQ (typ, 0, 6, "string"))
-	{
-	  int len;
-	  if (extract_keyword (is, "length", len) && len >= 0)
-	    {
-	      OCTAVE_LOCAL_BUFFER (char, tmp, len+1);
-
-	      if (len > 0 && ! is.read (X_CAST (char *, tmp), len))
-		{
-		  error ("load: failed to load string constant");
-		}
-	      else
-		{
-		  tmp [len] = '\0';
-
-		  if (is)
-		    tc = tmp;
-		  else
-		    error ("load: failed to load string constant");
-		}
-	    }
-	  else
-	    error ("load: failed to extract string length");
-	}
-      else if (SUBSTRING_COMPARE_EQ (typ, 0, 5, "range"))
-	{
-	  // # base, limit, range comment added by save ().
-
-	  skip_comments (is);
-	  Range tmp;
-	  is >> tmp;
-	  if (is)
-	    tc = tmp;
-	  else
-	    error ("load: failed to load range constant");
-	}
-      else
-	error ("load: unknown constant type `%s'", tag.c_str ());
+      tc.load_ascii (is);
     }
   else
     error ("load: failed to extract keyword specifying value type");
@@ -679,186 +426,12 @@
 
   octave_value val = val_arg;
 
-  if (val.is_range ())
-    {
-      Range r = val.range_value ();
-      double base = r.base ();
-      double limit = r.limit ();
-      double inc = r.inc ();
-      if (! (NINT (base) == base
-	     && NINT (limit) == limit
-	     && NINT (inc) == inc))
-	val = val.matrix_value ();
-    }	
-
-  if (val.is_string ())
-    {
-      ascii_save_type (os, "string array", mark_as_global);
-      charMatrix chm = val.char_matrix_value ();
-      int elements = chm.rows ();
-      os << "# elements: " << elements << "\n";
-      for (int i = 0; i < elements; i++)
-	{
-	  unsigned len = chm.cols ();
-	  os << "# length: " << len << "\n";
-	  std::string tstr = chm.row_as_string (i, false, true);
-	  const char *tmp = tstr.data ();
-	  if (tstr.length () > len)
-	    panic_impossible ();
-	  os.write (X_CAST (char *, tmp), len);
-	  os << "\n";
-	}
-    }
-  else if (val.is_range ())
-    {
-      ascii_save_type (os, "range", mark_as_global);
-      Range tmp = val.range_value ();
-      os << "# base, limit, increment\n";
-      octave_write_double (os, tmp.base ());
-      os << " ";
-      octave_write_double (os, tmp.limit ());
-      os << " ";
-      octave_write_double (os, tmp.inc ());
-      os << "\n";
-    }
-  else if (val.is_real_scalar ())
-    {
-      ascii_save_type (os, "scalar", mark_as_global);
-
-      double d = val.double_value ();
-
-      if (strip_nan_and_inf)
-	{
-	  if (xisnan (d))
-	    {
-	      error ("only value to plot is NaN");
-	      success = false;
-	    }
-	  else
-	    {
-	      d = xisinf (d) ? (d > 0 ? OCT_RBV : -OCT_RBV) : d;
-	      octave_write_double (os, d);
-	      os << "\n";
-	    }
-	}
-      else
-	{
-	  if (! infnan_warned && (xisnan (d) || xisinf (d)))
-	    {
-	      warning ("save: Inf or NaN values may not be reloadable");
-	      infnan_warned = true;
-	    }
-
-	  octave_write_double (os, d);
-	  os << "\n";
-	}
-    }
-  else if (val.is_real_matrix ())
-    {
-      ascii_save_type (os, "matrix", mark_as_global);
-
-      os << "# rows: " << val.rows () << "\n"
-	 << "# columns: " << val.columns () << "\n";
-
-      Matrix tmp = val.matrix_value ();
+  if (mark_as_global)
+    os << "# type: global " << val.type_name () << "\n";
+  else
+    os << "# type: " << val.type_name() << "\n";
 
-      if (strip_nan_and_inf)
-	tmp = strip_infnan (tmp);
-      else if (! infnan_warned && tmp.any_element_is_inf_or_nan ())
-	{
-	  warning ("save: Inf or NaN values may not be reloadable");
-	  infnan_warned = true;
-	}
-
-      os << tmp;
-    }
-  else if (val.is_cell ())
-    {
-      ascii_save_type (os, "cell", mark_as_global);
-
-      os << "# rows: " << val.rows () << "\n"
-	 << "# columns: " << val.columns () << "\n";
-
-      Cell tmp = val.cell_value ();
-      
-      for (int j = 0; j < tmp.cols (); j++)
-	{
-	  for (int i = 0; i < tmp.rows (); i++)
-	    {
-	      octave_value o_val = tmp.elem (i, j);
-
-	      // Recurse to print sub-value.
-	      bool b = save_ascii_data (os, o_val, CELL_ELT_TAG,
-					infnan_warned, strip_nan_and_inf,
-					mark_as_global, 0);
-
-	      if (! b)
-		return os;
-	    }
-
-	  os << "\n";
-	}
-    }
-  else if (val.is_complex_scalar ())
-    {
-      ascii_save_type (os, "complex scalar", mark_as_global);
-
-      Complex c = val.complex_value ();
-
-      if (strip_nan_and_inf)
-	{
-	  if (xisnan (c))
-	    {
-	      error ("only value to plot is NaN");
-	      success = false;
-	    }
-	  else
-	    {
-	      double re = real (c);
-	      double im = imag (c);
-
-	      re = xisinf (re) ? (re > 0 ? OCT_RBV : -OCT_RBV) : re;
-	      im = xisinf (im) ? (im > 0 ? OCT_RBV : -OCT_RBV) : im;
-
-	      c = Complex (re, im);
-
-	      octave_write_complex (os, c);
-	      os << "\n";
-	    }
-	}
-      else
-	{
-	  if (! infnan_warned && (xisnan (c) || xisinf (c)))
-	    {
-	      warning ("save: Inf or NaN values may not be reloadable");
-	      infnan_warned = true;
-	    }
-
-	  octave_write_complex (os, c);
-	  os << "\n";
-	}
-    }
-  else if (val.is_complex_matrix ())
-    {
-      ascii_save_type (os, "complex matrix", mark_as_global);
-
-      os << "# rows: " << val.rows () << "\n"
-	 << "# columns: " << val.columns () << "\n";
-
-      ComplexMatrix tmp = val.complex_matrix_value ();
-
-      if (strip_nan_and_inf)
-	tmp = strip_infnan (tmp);
-      else if (! infnan_warned && tmp.any_element_is_inf_or_nan ())
-	{
-	  warning ("save: Inf or NaN values may not be reloadable");
-	  infnan_warned = true;
-	}
-
-      os << tmp;
-    }
-  else
-    gripe_wrong_type_arg ("save", val, false);
+  success = val . save_ascii(os, infnan_warned, strip_nan_and_inf);
 
   os.precision (old_precision);
 
--- a/src/ls-oct-ascii.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ls-oct-ascii.h	Tue Jan 06 21:53:34 2004 +0000
@@ -23,8 +23,24 @@
 #if !defined (octave_ls_oct_ascii_h)
 #define octave_ls_oct_ascii_h 1
 
+#include <cfloat>
+
+// Flag for cell elements
+#define CELL_ELT_TAG "<cell-element>"
+
+// Used when converting Inf to something that gnuplot can read.
+
+#ifndef OCT_RBV
+#define OCT_RBV DBL_MAX / 100.0
+#endif
+
 extern std::string
-extract_keyword (std::istream& is, const char *keyword);
+extract_keyword (std::istream& is, const char *keyword, 
+		 const bool next_only = false);
+
+extern  bool
+extract_keyword (std::istream& is, const char *keyword, int& value,
+		 const bool next_only = false);
 
 extern std::string
 read_ascii_data (std::istream& is, const std::string& filename, bool& global,
--- a/src/ls-oct-binary.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ls-oct-binary.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -99,43 +99,37 @@
 //
 //   global flag          integer             1
 //
-//   data type            integer             1
+//   data type            char                1
 //
-//   data (one of):
-//
-//     scalar:
-//       data             real                8
+// In general "data type" is 255, and in that case the next arguments
+// in the data set are
 //
-//     complex scalar:
-//       data             complex            16
+//   object               type            bytes
+//   ------               ----            -----
+//   type_length          integer             4
 //
-//     matrix:
-//       rows             integer             4
-//       columns          integer             4
-//       data             real            r*c*8
+//   type                 string    type_length
+//
+// The string "type" is then used with octave_value_typeinfo::lookup_type
+// to create an octave_value of the correct type. The specific load/save
+// function is then called.
 //
-//     complex matrix:
-//       rows             integer             4
-//       columns          integer             4
-//       data             complex        r*c*16
-//
-//     string:
-//       length           int                 4
-//       data             string         length
+// For backward compatiablity "data type" can also be a value between 1
+// and 7, where this defines a hardcoded octave_value of the type
 //
-//     range:
-//       base             real                8
-//       limit            real                8
-//       increment        real                8
+//   data type                  octave_value
+//   ---------                  ------------
+//   1                          scalar
+//   2                          matrix
+//   3                          complex scalar
+//   4                          complex matrix
+//   5                          string   (old style storage)
+//   6                          range
+//   7                          string
 //
-//     string array
-//       elements         int                 4
-//
-//       for each element:
-//         length         int                 4
-//         data           string         length
-//
-// FILENAME is used for error messages.
+// Except for "data type" equal 5 that requires special treatment, these
+// old style "data type" value also cause the specific load/save functions
+// to be called. FILENAME is used for error messages.
 
 std::string
 read_binary_data (std::istream& is, bool swap,
@@ -191,82 +185,30 @@
   if (! is.read (X_CAST (char *, &tmp), 1))
     goto data_read_error;
 
+  // All cases except 255 kept for backwards compatibility
   switch (tmp)
     {
     case 1:
-      {
-	if (! is.read (X_CAST (char *, &tmp), 1))
-	  goto data_read_error;
-	double dtmp;
-	read_doubles (is, &dtmp, X_CAST (save_type, tmp), 1, swap, fmt);
-	if (error_state || ! is)
-	  goto data_read_error;
-	tc = dtmp;
-      }
+      tc = octave_value_typeinfo::lookup_type ("scalar");
       break;
 
     case 2:
-      {
-	FOUR_BYTE_INT nr, nc;
-	if (! is.read (X_CAST (char *, &nr), 4))
-	  goto data_read_error;
-	if (swap)
-	  swap_4_bytes (X_CAST (char *, &nr));
-	if (! is.read (X_CAST (char *, &nc), 4))
-	  goto data_read_error;
-	if (swap)
-	  swap_4_bytes (X_CAST (char *, &nc));
-	if (! is.read (X_CAST (char *, &tmp), 1))
-	  goto data_read_error;
-	Matrix m (nr, nc);
-	double *re = m.fortran_vec ();
-	int len = nr * nc;
-	read_doubles (is, re, X_CAST (save_type, tmp), len, swap, fmt);
-	if (error_state || ! is)
-	  goto data_read_error;
-	tc = m;
-      }
+      tc = octave_value_typeinfo::lookup_type ("matrix");
       break;
 
     case 3:
-      {
-	if (! is.read (X_CAST (char *, &tmp), 1))
-	  goto data_read_error;
-	Complex ctmp;
-	read_doubles (is, X_CAST (double *, &ctmp),
-		      X_CAST (save_type, tmp), 2, swap, fmt);
-	if (error_state || ! is)
-	  goto data_read_error;
-	tc = ctmp;
-      }
+      tc = octave_value_typeinfo::lookup_type ("complex scalar");
       break;
 
     case 4:
-      {
-	FOUR_BYTE_INT nr, nc;
-	if (! is.read (X_CAST (char *, &nr), 4))
-	  goto data_read_error;
-	if (swap)
-	  swap_4_bytes (X_CAST (char *, &nr));
-	if (! is.read (X_CAST (char *, &nc), 4))
-	  goto data_read_error;
-	if (swap)
-	  swap_4_bytes (X_CAST (char *, &nc));
-	if (! is.read (X_CAST (char *, &tmp), 1))
-	  goto data_read_error;
-	ComplexMatrix m (nr, nc);
-	Complex *im = m.fortran_vec ();
-	int len = nr * nc;
-	read_doubles (is, X_CAST (double *, im),
-		      X_CAST (save_type, tmp), 2*len, swap, fmt);
-	if (error_state || ! is)
-	  goto data_read_error;
-	tc = m;
-      }
+      tc = octave_value_typeinfo::lookup_type ("complex matrix");
       break;
 
     case 5:
       {
+	// XXX FIXME XXXX
+	// This is cruft, since its for a save type that is old. Maybe
+	// this is taking backward compatability too far!!
 	FOUR_BYTE_INT len;
 	if (! is.read (X_CAST (char *, &len), 4))
 	  goto data_read_error;
@@ -277,66 +219,45 @@
 	  goto data_read_error;
 	s[len] = '\0';
 	tc = s;
+
+	// Early return, since don't want rest of this function
+	return retval;
       }
       break;
 
     case 6:
-      {
-	if (! is.read (X_CAST (char *, &tmp), 1))
-	  goto data_read_error;
-	double bas, lim, inc;
-	if (! is.read (X_CAST (char *, &bas), 8))
-	  goto data_read_error;
-	if (swap)
-	  swap_8_bytes (X_CAST (char *, &bas));
-	if (! is.read (X_CAST (char *, &lim), 8))
-	  goto data_read_error;
-	if (swap)
-	  swap_8_bytes (X_CAST (char *, &lim));
-	if (! is.read (X_CAST (char *, &inc), 8))
-	  goto data_read_error;
-	if (swap)
-	  swap_8_bytes (X_CAST (char *, &inc));
-	Range r (bas, lim, inc);
-	tc = r;
-      }
+      tc = octave_value_typeinfo::lookup_type ("range");
       break;
 
     case 7:
+      tc = octave_value_typeinfo::lookup_type ("string");
+      break;
+
+    case 255:
       {
-	FOUR_BYTE_INT elements;
-	if (! is.read (X_CAST (char *, &elements), 4))
+	// Read the saved variable type
+	FOUR_BYTE_INT len;
+	if (! is.read (X_CAST (char *, &len), 4))
 	  goto data_read_error;
 	if (swap)
-	  swap_4_bytes (X_CAST (char *, &elements));
-	charMatrix chm (elements, 0);
-	int max_len = 0;
-	for (int i = 0; i < elements; i++)
-	  {
-	    FOUR_BYTE_INT len;
-	    if (! is.read (X_CAST (char *, &len), 4))
-	      goto data_read_error;
-	    if (swap)
-	      swap_4_bytes (X_CAST (char *, &len));
-	    OCTAVE_LOCAL_BUFFER (char, btmp, len+1);
-	    if (! is.read (X_CAST (char *, btmp), len))
-	      goto data_read_error;
-	    if (len > max_len)
-	      {
-		max_len = len;
-		chm.resize (elements, max_len, 0);
-	      }
-	    btmp [len] = '\0';
-	    chm.insert (btmp, i, 0);
-	  }
-	tc = octave_value (chm, true);
+	  swap_4_bytes (X_CAST (char *, &len));
+	OCTAVE_LOCAL_BUFFER (char, s, len+1);
+	if (! is.read (X_CAST (char *, s), len))
+	  goto data_read_error;
+	s[len] = '\0';
+	std::string typ = s;
+	tc = octave_value_typeinfo::lookup_type (typ);
       }
       break;
-
     default:
+      goto data_read_error;
+      break;
+    }
+  
+  if (!tc.load_binary (is, swap, fmt))
+    {
     data_read_error:
       error ("load: trouble reading binary file `%s'", filename.c_str ());
-      break;
     }
 
   return retval;
@@ -366,118 +287,24 @@
   tmp = mark_as_global;
   os.write (X_CAST (char *, &tmp), 1);
 
-  if (tc.is_string ())
-    {
-      tmp = 7;
-      os.write (X_CAST (char *, &tmp), 1);
-      FOUR_BYTE_INT nr = tc.rows ();
-      os.write (X_CAST (char *, &nr), 4);
-      charMatrix chm = tc.char_matrix_value ();
-      for (int i = 0; i < nr; i++)
-	{
-	  FOUR_BYTE_INT len = chm.cols ();
-	  os.write (X_CAST (char *, &len), 4);
-	  std::string tstr = chm.row_as_string (i);
-	  const char *btmp = tstr.data ();
-	  os.write (X_CAST (char *, btmp), len);
-	}
-    }
-  else if (tc.is_range ())
-    {
-      tmp = 6;
-      os.write (X_CAST (char *, &tmp), 1);
-      tmp = (char) LS_DOUBLE;
-      os.write (X_CAST (char *, &tmp), 1);
-      Range r = tc.range_value ();
-      double bas = r.base ();
-      double lim = r.limit ();
-      double inc = r.inc ();
-      os.write (X_CAST (char *, &bas), 8);
-      os.write (X_CAST (char *, &lim), 8);
-      os.write (X_CAST (char *, &inc), 8);
-    }
-  else if (tc.is_real_scalar ())
-    {
-      tmp = 1;
-      os.write (X_CAST (char *, &tmp), 1);
-      tmp = (char) LS_DOUBLE;
-      os.write (X_CAST (char *, &tmp), 1);
-      double dtmp = tc.double_value ();
-      os.write (X_CAST (char *, &dtmp), 8);
-    }
-  else if (tc.is_real_matrix ())
-    {
-      tmp = 2;
-      os.write (X_CAST (char *, &tmp), 1);
-      Matrix m = tc.matrix_value ();
-      FOUR_BYTE_INT nr = m.rows ();
-      FOUR_BYTE_INT nc = m.columns ();
-      os.write (X_CAST (char *, &nr), 4);
-      os.write (X_CAST (char *, &nc), 4);
-      int len = nr * nc;
-      save_type st = LS_DOUBLE;
-      if (save_as_floats)
-	{
-	  if (m.too_large_for_float ())
-	    {
-	      warning ("save: some values too large to save as floats --");
-	      warning ("save: saving as doubles instead");
-	    }
-	  else
-	    st = LS_FLOAT;
-	}
-      else if (len > 8192) // XXX FIXME XXX -- make this configurable.
-	{
-	  double max_val, min_val;
-	  if (m.all_integers (max_val, min_val))
-	    st = get_save_type (max_val, min_val);
-	}
-      const double *mtmp = m.data ();
-      write_doubles (os, mtmp, st, len);
-    }
-  else if (tc.is_complex_scalar ())
-    {
-      tmp = 3;
-      os.write (X_CAST (char *, &tmp), 1);
-      tmp = (char) LS_DOUBLE;
-      os.write (X_CAST (char *, &tmp), 1);
-      Complex ctmp = tc.complex_value ();
-      os.write (X_CAST (char *, &ctmp), 16);
-    }
-  else if (tc.is_complex_matrix ())
-    {
-      tmp = 4;
-      os.write (X_CAST (char *, &tmp), 1);
-      ComplexMatrix m = tc.complex_matrix_value ();
-      FOUR_BYTE_INT nr = m.rows ();
-      FOUR_BYTE_INT nc = m.columns ();
-      os.write (X_CAST (char *, &nr), 4);
-      os.write (X_CAST (char *, &nc), 4);
-      int len = nr * nc;
-      save_type st = LS_DOUBLE;
-      if (save_as_floats)
-	{
-	  if (m.too_large_for_float ())
-	    {
-	      warning ("save: some values too large to save as floats --");
-	      warning ("save: saving as doubles instead");
-	    }
-	  else
-	    st = LS_FLOAT;
-	}
-      else if (len > 4096) // XXX FIXME XXX -- make this configurable.
-	{
-	  double max_val, min_val;
-	  if (m.all_integers (max_val, min_val))
-	    st = get_save_type (max_val, min_val);
-	}
-      const Complex *mtmp = m.data ();
-      write_doubles (os, X_CAST (const double *, mtmp), st, 2*len);
-    }
-  else
-    gripe_wrong_type_arg ("save", tc, false);
+  // 255 flags the new binary format
+  tmp = 255;
+  os.write (X_CAST (char *, &tmp), 1);
 
-  return os;
+  // Write the string corresponding to the octave_value type
+  std::string typ = tc.type_name ();
+  FOUR_BYTE_INT len = typ.length ();
+  os.write (X_CAST (char *, &len), 4);
+  const char *btmp = typ.data ();
+  os.write (X_CAST (char *, btmp), len);
+      
+  // The octave_value of tc is const. Make a copy...
+  octave_value val = tc;
+
+  // Call specific save function
+  bool success = val.save_binary (os, save_as_floats);
+
+  return (os && success);
 }
 
 /*
--- a/src/ov-base.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-base.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -521,6 +521,53 @@
   return retval;
 }
 
+bool 
+octave_base_value::save_ascii (std::ostream&, bool&, bool)
+{
+  gripe_wrong_type_arg ("octave_base_value::save_ascii()", type_name ());
+  return false;
+}
+
+bool 
+octave_base_value::load_ascii (std::istream&)
+{
+  gripe_wrong_type_arg ("octave_base_value::load_ascii()", type_name ());
+  return false;
+}
+
+bool 
+octave_base_value::save_binary (std::ostream&, bool&)
+{
+  gripe_wrong_type_arg ("octave_base_value::save_binary()", type_name ());
+  return false;
+}
+
+bool 
+octave_base_value::load_binary (std::istream&, bool,
+				oct_mach_info::float_format)
+{
+  gripe_wrong_type_arg ("octave_base_value::load_binary()", type_name ());
+  return false;
+}
+
+#if defined (HAVE_HDF5)
+bool
+octave_base_value::save_hdf5 (hid_t, const char *, bool)
+{
+  gripe_wrong_type_arg ("octave_base_value::save_binary()", type_name ());
+
+  return false;
+}
+
+bool 
+octave_base_value::load_hdf5 (hid_t, const char *, bool)
+{
+  gripe_wrong_type_arg ("octave_base_value::load_binary()", type_name ());
+
+  return false;
+}
+#endif
+
 CONVDECLX (matrix_conv)
 {
   return new octave_matrix ();
--- a/src/ov-base.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-base.h	Tue Jan 06 21:53:34 2004 +0000
@@ -252,6 +252,22 @@
 
   void print_info (std::ostream& os, const std::string& prefix) const;
 
+  bool save_ascii (std::ostream& os, bool& infnan_warned,
+			   bool strip_nan_and_inf);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool& save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, 
+		    oct_mach_info::float_format fmt);
+
+#if defined (HAVE_HDF5)
+  bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
+#endif
+
 private:
 
   DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
--- a/src/ov-bool-mat.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-bool-mat.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -44,6 +44,11 @@
 #include "ov-re-mat.h"
 #include "pr-output.h"
 
+#include "byte-swap.h"
+#include "ls-oct-ascii.h"
+#include "ls-hdf5.h"
+#include "ls-utils.h"
+
 template class octave_base_matrix<boolNDArray>;
 
 DEFINE_OCTAVE_ALLOCATOR (octave_bool_matrix);
@@ -148,6 +153,289 @@
 			 current_print_indent_level ());
 }
 
+bool 
+octave_bool_matrix::save_ascii (std::ostream& os, bool& /* infnan_warned */,
+				bool /* strip_nan_and_inf */)
+{
+  dim_vector d = dims ();
+  if (d.length () > 2)
+    {
+      NDArray tmp = array_value ();
+      os << "# ndims: " << d.length () << "\n";
+
+      for (int i=0; i < d.length (); i++)
+	os << " " << d (i);
+
+      os << "\n" << tmp;
+    }
+  else
+    {
+      // Keep this case, rather than use generic code above for backward 
+      // compatiability. Makes load_ascii much more complex!!
+      os << "# rows: " << rows () << "\n"
+	 << "# columns: " << columns () << "\n";
+
+      Matrix tmp = matrix_value ();
+
+      os << tmp;
+    }
+
+  return true;
+}
+
+bool 
+octave_bool_matrix::load_ascii (std::istream& is)
+{
+  int mdims = 0;
+  bool success = true;
+  std::streampos pos = is.tellg ();
+
+  if (extract_keyword (is, "ndims", mdims, true))
+    {
+      if (mdims >= 0)
+	{
+	  dim_vector dv;
+	  dv.resize (mdims);
+
+	  for (int i = 0; i < mdims; i++)
+	    is >> dv(i);
+
+	  NDArray tmp(dv);
+	  is >> tmp;
+
+	  if (!is) 
+	    {
+	      error ("load: failed to load matrix constant");
+	      success = false;
+	    }
+
+	  boolNDArray btmp (dv);
+	  for (int i = 0; i < btmp.nelem (); i++)
+	      btmp.elem (i) = (tmp.elem (i) != 0.);
+	  
+	  matrix = btmp;
+	}
+      else
+	{
+	  error ("load: failed to extract number of rows and columns");
+	  success = false;
+	}
+    }
+  else
+    {
+      int nr = 0;
+      int nc = 0;
+
+      // re-read the same line again
+      is.clear ();
+      is.seekg (pos);
+
+      if (extract_keyword (is, "rows", nr) && nr >= 0
+	  && extract_keyword (is, "columns", nc) && nc >= 0)
+	{
+	  if (nr > 0 && nc > 0)
+	    {
+	      Matrix tmp (nr, nc);
+	      is >> tmp;
+	      if (!is) 
+		{
+		  error ("load: failed to load matrix constant");
+		  success = false;
+		}
+
+	      boolMatrix btmp (nr,nc);
+	      for (int j = 0; j < nc; j++)
+		for (int i = 0; i < nr; i++)
+		  btmp.elem (i,j) = (tmp.elem (i, j) != 0.);
+	      
+	      matrix = btmp;
+	    }
+	  else if (nr == 0 || nc == 0)
+	    matrix = boolMatrix (nr, nc);
+	  else
+	    panic_impossible ();
+	}
+      else 
+	{
+	  error ("load: failed to extract number of rows and columns");
+	  success = false;
+	}
+    }
+
+  return success;
+}
+
+bool 
+octave_bool_matrix::save_binary (std::ostream& os, bool& /* save_as_floats */)
+{
+
+  dim_vector d = dims ();
+  if (d.length() < 1)
+    return false;
+
+  // Use negative value for ndims to differentiate with old format!!
+  FOUR_BYTE_INT tmp = - d.length();
+  os.write (X_CAST (char *, &tmp), 4);
+  for (int i=0; i < d.length (); i++)
+    {
+      tmp = d(i);
+      os.write (X_CAST (char *, &tmp), 4);
+    }
+
+  boolNDArray m = bool_array_value ();
+  bool *mtmp = m.fortran_vec ();
+  int nel = m.nelem ();
+  OCTAVE_LOCAL_BUFFER (char, htmp, nel);
+
+  for (int i = 0; i < nel; i++)
+    htmp[i] = (mtmp[i] ? 1 : 0);
+
+  os.write (htmp, nel);
+
+  return true;
+}
+
+bool 
+octave_bool_matrix::load_binary (std::istream& is, bool swap,
+				 oct_mach_info::float_format /* fmt */)
+{
+  FOUR_BYTE_INT mdims;
+  if (! is.read (X_CAST (char *, &mdims), 4))
+    return false;
+  if (swap)
+    swap_4_bytes (X_CAST (char *, &mdims));
+  if (mdims >= 0)
+    return false;
+
+  // mdims is negative for consistency with other matrices, where it is
+  // negative to allow the positive value to be used for rows/cols for
+  // backward compatibility
+  mdims = - mdims;
+  FOUR_BYTE_INT di;
+  dim_vector dv;
+  dv.resize (mdims);
+
+  for (int i = 0; i < mdims; i++)
+    {
+      if (! is.read (X_CAST (char *, &di), 4))
+	return false;
+      if (swap)
+	swap_4_bytes (X_CAST (char *, &di));
+      dv(i) = di;
+    }
+  
+  int nel = dv.numel ();
+  OCTAVE_LOCAL_BUFFER (char, htmp, nel);
+  if (! is.read (htmp, nel))
+    return false;
+  boolNDArray m(dv);
+  bool *mtmp = m.fortran_vec ();
+  for (int i = 0; i < nel; i++)
+    mtmp[i] = (htmp[i] ? 1 : 0);
+  matrix = m;
+
+  return true;
+}
+
+#if defined (HAVE_HDF5)
+bool
+octave_bool_matrix::save_hdf5 (hid_t loc_id, const char *name,
+			       bool /* save_as_floats */)
+{
+  dim_vector d = dims ();
+  hsize_t hdims[d.length () > 2 ? d.length () : 3];
+  hid_t space_hid = -1, data_hid = -1;
+  int rank = ( (d (0) == 1) && (d.length () == 2) ? 1 : d.length ());
+  bool retval = true;
+
+  boolNDArray m = bool_array_value ();
+
+  // Octave uses column-major, while HDF5 uses row-major ordering
+  for (int i = 0, j = d.length() - 1; i < d.length (); i++, j--)
+    hdims[i] = d (j);
+
+  space_hid = H5Screate_simple (rank, hdims, (hsize_t*) 0);
+  if (space_hid < 0) return false;
+
+  data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_HBOOL, space_hid, 
+			H5P_DEFAULT);
+  if (data_hid < 0)
+    {
+      H5Sclose (space_hid);
+      return false;
+    }
+
+  int nel = m.nelem ();
+  bool *mtmp = m.fortran_vec ();
+  hbool_t htmp[nel];
+  
+  for (int i = 0; i < nel; i++)
+    htmp[i] = mtmp[i];
+
+  retval = H5Dwrite (data_hid, H5T_NATIVE_HBOOL, H5S_ALL, H5S_ALL,
+		     H5P_DEFAULT, (void*) htmp) >= 0;
+
+  H5Dclose (data_hid);
+  H5Sclose (space_hid);
+  return retval;
+}
+
+bool
+octave_bool_matrix::load_hdf5 (hid_t loc_id, const char *name,
+			       bool /* have_h5giterate_bug */)
+{
+  bool retval = false;
+  hid_t data_hid = H5Dopen (loc_id, name);
+  hid_t space_id = H5Dget_space (data_hid);
+
+  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
+  
+  if (rank < 1)
+    {
+      H5Dclose (data_hid);
+      return false;
+    }
+
+  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
+  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
+
+  H5Sget_simple_extent_dims (space_id, hdims, maxdims);
+
+  dim_vector dv;
+
+  // Octave uses column-major, while HDF5 uses row-major ordering
+  if (rank == 1)
+    {
+      dv.resize (2);
+      dv(0) = 1;
+      dv(1) = hdims[0];
+    }
+  else
+    {
+      dv.resize (rank);
+      for (int i = 0, j = rank - 1; i < (int)rank; i++, j--)
+	dv(j) = hdims[i];
+    }
+
+  int nel = dv.numel ();
+  hbool_t htmp[nel];
+  if (H5Dread (data_hid, H5T_NATIVE_HBOOL, H5S_ALL, H5S_ALL, 
+	       H5P_DEFAULT, (void *) htmp) >= 0) 
+    {
+      retval = true;
+
+      boolNDArray btmp (dv);
+      for (int i = 0; i < nel; i++)
+	  btmp.elem (i) = htmp[i];
+
+      matrix = btmp;
+    }
+
+  H5Dclose (data_hid);
+  return retval;
+}
+#endif
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-bool-mat.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-bool-mat.h	Tue Jan 06 21:53:34 2004 +0000
@@ -115,6 +115,22 @@
 
   void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
+  bool save_ascii (std::ostream& os, bool& infnan_warned,
+		 bool strip_nan_and_inf);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool& save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, 
+		    oct_mach_info::float_format fmt);
+
+#if defined (HAVE_HDF5)
+  bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
+#endif
+
 protected:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-bool.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-bool.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -43,6 +43,9 @@
 #include "ov-scalar.h"
 #include "pr-output.h"
 
+#include "ls-oct-ascii.h"
+#include "ls-hdf5.h"
+
 template class octave_base_scalar<bool>;
 
 DEFINE_OCTAVE_ALLOCATOR (octave_bool);
@@ -112,6 +115,110 @@
   return octave_value (s);
 }
 
+bool 
+octave_bool::save_ascii (std::ostream& os, bool& /* infnan_warned */,
+			 bool /* strip_nan_and_inf */)
+{
+  double d = double_value ();
+
+  octave_write_double (os, d);
+  os << "\n";
+
+  return true;
+}
+
+bool 
+octave_bool::load_ascii (std::istream& is)
+{
+  scalar = (octave_read_double (is) != 0.);
+
+  if (!is)
+    {
+      error ("load: failed to load scalar constant");
+      return false;
+    }
+
+  return true;
+}
+
+bool 
+octave_bool::save_binary (std::ostream& os, bool& /* save_as_floats */)
+{
+  char tmp = (scalar ? 1 : 0);
+  os.write (X_CAST (char *, &tmp), 1);
+
+  return true;
+}
+
+bool 
+octave_bool::load_binary (std::istream& is, bool /* swap */,
+			  oct_mach_info::float_format /* fmt */)
+{
+  char tmp;
+  if (! is.read (X_CAST (char *, &tmp), 1))
+    return false;
+  scalar = (tmp ? 1 : 0);
+  return true;
+}
+
+#if defined (HAVE_HDF5)
+bool
+octave_bool::save_hdf5 (hid_t loc_id, const char *name,
+			bool /* save_as_floats */)
+{
+  hsize_t dimens[3];
+  hid_t space_hid = -1, data_hid = -1;
+  bool retval = true;
+
+  space_hid = H5Screate_simple (0, dimens, (hsize_t*) 0);
+  if (space_hid < 0) return false;
+
+  data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_DOUBLE, space_hid, 
+			H5P_DEFAULT);
+  if (data_hid < 0) 
+    {
+      H5Sclose (space_hid);
+      return false;
+    }
+
+  double tmp = double_value ();
+  retval = H5Dwrite (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
+		     H5P_DEFAULT, (void*) &tmp) >= 0;
+
+  H5Dclose (data_hid);
+  H5Sclose (space_hid);
+  return retval;
+}
+
+bool
+octave_bool::load_hdf5 (hid_t loc_id, const char *name,
+			bool /* have_h5giterate_bug */)
+{
+  hid_t data_hid = H5Dopen (loc_id, name);
+  hid_t space_id = H5Dget_space (data_hid);
+
+  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
+
+  if (rank != 0)
+    { 
+      H5Dclose (data_hid);
+      return false;
+    }
+
+  double dtmp;
+  if (H5Dread (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, 
+	       H5P_DEFAULT, (void *) &dtmp) < 0)
+    { 
+      H5Dclose (data_hid);
+      return false;
+    }
+
+  scalar = (dtmp != 0.);
+  H5Dclose (data_hid);
+  return true;
+}
+#endif
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-bool.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-bool.h	Tue Jan 06 21:53:34 2004 +0000
@@ -110,6 +110,22 @@
 
   octave_value convert_to_str_internal (bool pad, bool force) const;
 
+  bool save_ascii (std::ostream& os, bool& infnan_warned,
+		 bool strip_nan_and_inf);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool& save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, 
+		    oct_mach_info::float_format fmt);
+
+#if defined (HAVE_HDF5)
+  bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
+#endif
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-cell.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-cell.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -45,6 +45,12 @@
 #include "ov-re-mat.h"
 #include "ov-scalar.h"
 
+#include "byte-swap.h"
+#include "ls-oct-ascii.h"
+#include "ls-oct-binary.h"
+#include "ls-hdf5.h"
+#include "ls-utils.h"
+
 template class octave_base_matrix<Cell>;
 
 DEFINE_OCTAVE_ALLOCATOR (octave_cell);
@@ -395,6 +401,455 @@
     }
 }
 
+#define CELL_ELT_TAG "<cell-element>"
+
+bool 
+octave_cell::save_ascii (std::ostream& os, bool& infnan_warned, 
+			       bool strip_nan_and_inf)
+{
+  dim_vector d = dims ();
+  if (d.length () > 2)
+    {
+      os << "# ndims: " << d.length () << "\n";
+      
+      for (int i=0; i < d.length (); i++)
+	os << " " << d (i);
+      os << "\n";
+
+      Cell tmp = cell_value ();
+      
+      for (int i = 0; i < d.numel (); i++)
+	{
+	  octave_value o_val = tmp.elem (i);
+
+	  // Recurse to print sub-value.
+	  bool b = save_ascii_data (os, o_val, CELL_ELT_TAG, infnan_warned, 
+				    strip_nan_and_inf, 0, 0);
+	      
+	  if (! b)
+	    return os;
+	}
+    }
+  else
+    {
+      // Keep this case, rather than use generic code above for backward 
+      // compatiability. Makes load_ascii much more complex!!
+      os << "# rows: " << rows () << "\n"
+	 << "# columns: " << columns () << "\n";
+
+      Cell tmp = cell_value ();
+      
+      for (int j = 0; j < tmp.cols (); j++)
+	{
+	  for (int i = 0; i < tmp.rows (); i++)
+	    {
+	      octave_value o_val = tmp.elem (i, j);
+
+	      // Recurse to print sub-value.
+	      bool b = save_ascii_data (os, o_val, CELL_ELT_TAG, 
+					infnan_warned, 
+					strip_nan_and_inf, 0, 0);
+	      
+	      if (! b)
+		return os;
+	    }
+	  
+	  os << "\n";
+	}
+    }
+
+  return true;
+}
+
+bool 
+octave_cell::load_ascii (std::istream& is)
+{
+  int mdims = 0;
+  bool success = true;
+  std::streampos pos = is.tellg ();
+
+  if (extract_keyword (is, "ndims", mdims, true))
+    {
+      if (mdims >= 0)
+	{
+	  dim_vector dv;
+	  dv.resize (mdims);
+
+	  for (int i = 0; i < mdims; i++)
+	    is >> dv(i);
+
+	  Cell tmp(dv);
+
+	  for (int i = 0; i < dv.numel (); i++)
+	    {
+	      octave_value t2;
+	      bool dummy;
+
+	      // recurse to read cell elements
+	      std::string nm = read_ascii_data (is, std::string (), 
+						dummy, t2, count);
+
+	      if (nm == CELL_ELT_TAG)
+		{
+		  if (is)
+		    tmp.elem (i) = t2;
+		}
+	      else
+		{
+		  error ("load: cell array element had unexpected name");
+		  success = false;
+		  break;
+		}
+	    }
+
+	  if (is)
+	    matrix = tmp;
+	  else
+	    {
+	      error ("load: failed to load matrix constant");
+	      success = false;
+	    }
+	}
+      else
+	{
+	  error ("load: failed to extract number of rows and columns");
+	  success = false;
+	}
+      
+    }
+  else
+    {
+      int nr = 0;
+      int nc = 0;
+
+      // re-read the same line again
+      is.clear ();
+      is.seekg (pos);
+
+      if (extract_keyword (is, "rows", nr) && nr >= 0
+	  && extract_keyword (is, "columns", nc) && nc >= 0)
+	{
+	  if (nr > 0 && nc > 0)
+	    {
+	      Cell tmp (nr, nc);
+
+	      for (int j = 0; j < nc; j++)
+		{
+		  for (int i = 0; i < nr; i++)
+		    {
+		      octave_value t2;
+		      bool dummy;
+
+		      // recurse to read cell elements
+		      std::string nm = read_ascii_data (is, std::string (), 
+							dummy, t2, count);
+
+		      if (nm == CELL_ELT_TAG)
+			{
+			  if (is)
+			    tmp.elem (i, j) = t2;
+			}
+		      else
+			{
+			  error ("load: cell array element had unexpected name");
+			  success = false;
+			  goto cell_read_error;
+			}
+		    }
+		}
+	      
+	    cell_read_error:
+
+	      if (is) 
+		matrix = tmp;
+	      else
+		{
+		  error ("load: failed to load cell element");
+		  success = false;
+		}
+	    }
+	  else if (nr == 0 || nc == 0)
+	    matrix = Cell (nr, nc);
+	  else
+	    panic_impossible ();
+	}
+      else {
+	error ("load: failed to extract number of rows and columns for cell array");
+	success = false;
+      }
+    }
+
+  return success;
+}
+
+bool 
+octave_cell::save_binary (std::ostream& os, bool& save_as_floats)
+{
+  dim_vector d = dims ();
+  if (d.length () < 1)
+    return false;
+
+  // Use negative value for ndims
+  FOUR_BYTE_INT di = - d.length();
+  os.write (X_CAST (char *, &di), 4);
+  for (int i=0; i < d.length (); i++)
+    {
+      di = d(i);
+      os.write (X_CAST (char *, &di), 4);
+    }
+  
+  Cell tmp = cell_value ();
+      
+  for (int i = 0; i < d.numel (); i++)
+    {
+      octave_value o_val = tmp.elem (i);
+
+      // Recurse to print sub-value.
+      bool b = save_binary_data (os, o_val, CELL_ELT_TAG, "", 0, 
+				 save_as_floats);
+	      
+      if (! b)
+	return false;
+    }
+  
+  return true;
+}
+
+bool 
+octave_cell::load_binary (std::istream& is, bool swap,
+				 oct_mach_info::float_format fmt)
+{
+  bool success = true;
+  FOUR_BYTE_INT mdims;
+  if (! is.read (X_CAST (char *, &mdims), 4))
+    return false;
+  if (swap)
+    swap_4_bytes (X_CAST (char *, &mdims));
+  if (mdims >= 0)
+    return false;
+
+  mdims = -mdims;
+  FOUR_BYTE_INT di;
+  dim_vector dv;
+  dv.resize (mdims);
+
+  for (int i = 0; i < mdims; i++)
+    {
+      if (! is.read (X_CAST (char *, &di), 4))
+	return false;
+      if (swap)
+	swap_4_bytes (X_CAST (char *, &di));
+      dv(i) = di;
+    }
+  
+  int nel = dv.numel ();
+  Cell tmp(dv);
+
+  for (int i = 0; i < nel; i++)
+    {
+      octave_value t2;
+      bool dummy;
+      std::string doc;
+
+      // recurse to read cell elements
+      std::string nm = read_binary_data (is, swap, fmt, std::string (), 
+					 dummy, t2, doc);
+
+      if (nm == CELL_ELT_TAG)
+	{
+	  if (is)
+	    tmp.elem (i) = t2;
+	}
+      else
+	{
+	  error ("load: cell array element had unexpected name");
+	  success = false;
+	  break;
+	}
+    }
+
+  if (is)
+    matrix = tmp;
+  else
+    {
+      error ("load: failed to load matrix constant");
+      success = false;
+    }
+
+  return success;
+}
+
+#if defined (HAVE_HDF5)
+bool
+octave_cell::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
+{
+  hsize_t dimens[3];
+  hid_t space_hid = -1, data_hid = -1, size_hid = -1;
+
+  data_hid = H5Gcreate (loc_id, name, 0);
+  if (data_hid < 0) return false;
+
+  // Have to save rows/columns since can't have a dataset of groups....
+  space_hid = H5Screate_simple (0, dimens, (hsize_t*) 0);
+  if (space_hid < 0) 
+    {
+      H5Gclose (data_hid);
+      return false;
+    }
+
+  size_hid = H5Dcreate (data_hid, "rows", H5T_NATIVE_INT, space_hid, 
+			H5P_DEFAULT);
+  if (size_hid < 0) 
+    {
+      H5Sclose (space_hid);
+      H5Gclose (data_hid);
+      return false;
+    }
+
+  int rc = rows();
+  if (! H5Dwrite (size_hid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
+		  H5P_DEFAULT, (void*) &rc) < 0)
+    {
+      H5Dclose (size_hid);
+      H5Sclose (space_hid);
+      H5Gclose (data_hid);
+      return false;
+    }
+  H5Dclose (size_hid);
+
+  size_hid = H5Dcreate (data_hid, "columns", H5T_NATIVE_INT, space_hid, 
+			H5P_DEFAULT);
+  if (size_hid < 0) 
+    {
+      H5Sclose (space_hid);
+      H5Gclose (data_hid);
+      return false;
+    }
+
+  rc = columns();
+  if (! H5Dwrite (size_hid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
+		  H5P_DEFAULT, (void*) &rc) < 0)
+    {
+      H5Dclose (size_hid);
+      H5Sclose (space_hid);
+      H5Gclose (data_hid);
+      return false;
+    }
+  H5Dclose (size_hid);
+  H5Sclose (space_hid);
+
+  // recursively add each element of the cell to this group
+  Cell tmp = cell_value ();
+  
+  for (int j = 0; j < tmp.cols (); j++)
+    {
+      for (int i = 0; i < tmp.rows (); i++)
+	{
+	  char s[20];
+	  sprintf (s, "_%d", (i + j * tmp.rows ()));
+
+	  if (! add_hdf5_data(data_hid, tmp.elem (i, j), s, "", false,
+			      save_as_floats))
+	    {
+	      H5Gclose (data_hid);
+	      return false;
+	    }
+	}
+    }
+
+  H5Gclose (data_hid);
+  return true;
+}
+
+bool
+octave_cell::load_hdf5 (hid_t loc_id, const char *name,
+			bool have_h5giterate_bug)
+{
+  bool retval = false;
+  hid_t group_id = H5Gopen (loc_id, name);
+
+  if (group_id < 0)
+    return false;
+
+  hid_t data_hid = H5Dopen (group_id, "rows");
+  hid_t space_hid = H5Dget_space (data_hid);
+  hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
+  if (rank != 0) 
+    {
+      H5Dclose(data_hid);
+      H5Gclose(group_id);
+      return false;
+    }
+
+  int nr;
+  if (H5Dread (data_hid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, 
+	       H5P_DEFAULT, (void *) &nr) < 0)
+    {
+      H5Dclose(data_hid);
+      H5Gclose(group_id);
+      return false;
+    }
+  H5Dclose (data_hid);
+
+  data_hid = H5Dopen (group_id, "columns");
+  space_hid = H5Dget_space (data_hid);
+  rank = H5Sget_simple_extent_ndims (space_hid);
+  if (rank != 0)
+    {
+      H5Dclose(data_hid);
+      H5Gclose(group_id);
+      return false;
+    }
+
+  int nc;
+  if (H5Dread (data_hid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, 
+	       H5P_DEFAULT, (void *) &nc) < 0)
+    {
+      H5Dclose(data_hid);
+      H5Gclose(group_id);
+      return false;
+    }
+  H5Dclose (data_hid);
+  H5Gclose (group_id);
+
+  hdf5_callback_data dsub;
+
+  herr_t retval2 = -1;
+  Cell m (nr, nc);
+  int current_item = 0;
+  if (have_h5giterate_bug)
+    current_item = 2;   // Skip row/columns items in group
+
+  for (int j = 0; j < nc; j++)
+    {
+      for (int i = 0; i < nr; i++)
+	{
+	  retval2 = H5Giterate (loc_id, name, &current_item,
+				hdf5_read_next_data, &dsub);
+	  if (retval2 <= 0)
+	    break;
+
+	  octave_value ov = dsub.tc;
+	  m.elem (i, j) = ov;
+
+	  if (have_h5giterate_bug)
+	    current_item++;  // H5Giterate returned the last index processed
+
+	}
+      if (retval2 <= 0)
+	break;
+    }
+
+  if (retval2 >= 0)
+    {
+      matrix = m;
+      retval = true;
+    }
+  
+  return retval;
+}
+#endif
+
 DEFUN (iscell, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} iscell (@var{x})\n\
--- a/src/ov-cell.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-cell.h	Tue Jan 06 21:53:34 2004 +0000
@@ -110,6 +110,23 @@
 
   void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
+
+  bool save_ascii (std::ostream& os, bool& infnan_warned,
+		 bool strip_nan_and_inf);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool& save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, 
+		    oct_mach_info::float_format fmt);
+
+#if defined (HAVE_HDF5)
+  bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
+#endif
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-complex.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-complex.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -43,6 +43,9 @@
 #include "gripes.h"
 #include "pr-output.h"
 
+#include "ls-oct-ascii.h"
+#include "ls-hdf5.h"
+
 template class octave_base_scalar<Complex>;
 
 DEFINE_OCTAVE_ALLOCATOR (octave_complex);
@@ -146,6 +149,173 @@
   return ComplexNDArray (dim_vector (1, 1), scalar);
 }
 
+bool 
+octave_complex::save_ascii (std::ostream& os, bool& infnan_warned, 
+			    bool strip_nan_and_inf)
+{
+  Complex c = complex_value ();
+
+  if (strip_nan_and_inf)
+    {
+      if (xisnan (c))
+	{
+	  error ("only value to plot is NaN");
+	  return false;
+	}
+      else
+	{
+	  double re = real (c);
+	  double im = imag (c);
+
+	  re = xisinf (re) ? (re > 0 ? OCT_RBV : -OCT_RBV) : re;
+	  im = xisinf (im) ? (im > 0 ? OCT_RBV : -OCT_RBV) : im;
+
+	  c = Complex (re, im);
+
+	  octave_write_complex (os, c);
+	  os << "\n";
+	}
+    }
+  else
+    {
+      if (! infnan_warned && (xisnan (c) || xisinf (c)))
+	{
+	  warning ("save: Inf or NaN values may not be reloadable");
+	  infnan_warned = true;
+	}
+      
+      octave_write_complex (os, c);
+      os << "\n";
+    }
+
+  return true;
+}
+
+bool 
+octave_complex::load_ascii (std::istream& is)
+{
+  scalar = octave_read_complex (is);
+
+  if (!is) 
+    {
+      error ("load: failed to load complex scalar constant");
+      return false;
+    }
+
+  return true;
+}
+
+
+bool 
+octave_complex::save_binary (std::ostream& os, bool& /* save_as_floats */)
+{
+  char tmp = (char) LS_DOUBLE;
+  os.write (X_CAST (char *, &tmp), 1);
+  Complex ctmp = complex_value ();
+  os.write (X_CAST (char *, &ctmp), 16);
+
+  return true;
+}
+
+bool 
+octave_complex::load_binary (std::istream& is, bool swap,
+			     oct_mach_info::float_format fmt)
+{
+  char tmp;
+  if (! is.read (X_CAST (char *, &tmp), 1))
+    return false;
+
+  Complex ctmp;
+  read_doubles (is, X_CAST (double *, &ctmp), X_CAST (save_type, tmp), 2, 
+		swap, fmt);
+  if (error_state || ! is)
+    return false;
+
+  scalar = ctmp;
+  return true;
+}
+
+#if defined (HAVE_HDF5)
+bool
+octave_complex::save_hdf5 (hid_t loc_id, const char *name,
+			   bool /* save_as_floats */)
+{
+  hsize_t dimens[3];
+  hid_t space_hid = -1, type_hid = -1, data_hid = -1;
+  bool retval = true;
+
+  space_hid = H5Screate_simple (0, dimens, (hsize_t*) 0);
+  if (space_hid < 0) return false;
+
+  type_hid = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
+  if (type_hid < 0) 
+    {
+      H5Sclose (space_hid);
+      return false;
+    }
+
+  data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, H5P_DEFAULT);
+  if (data_hid < 0) 
+    {
+      H5Sclose (space_hid);
+      H5Tclose (type_hid);
+      return false;
+    }
+
+  Complex tmp = complex_value ();
+  retval = H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT, 
+		     (void*) X_CAST (double*, &tmp)) >= 0;
+
+  H5Dclose (data_hid);
+  H5Tclose (type_hid);
+  H5Sclose (space_hid);
+  return retval;
+}
+
+bool
+octave_complex::load_hdf5 (hid_t loc_id, const char *name,
+			   bool /* have_h5giterate_bug */)
+{
+  bool retval = false;
+  hid_t data_hid = H5Dopen (loc_id, name);
+  hid_t type_hid = H5Dget_type (data_hid);
+
+  hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
+
+  if (! hdf5_types_compatible (type_hid, complex_type))
+    {
+      H5Tclose(complex_type);
+      H5Dclose (data_hid);
+      return false;
+    }
+
+  hid_t space_id = H5Dget_space (data_hid);
+  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
+
+  if (rank != 0) 
+    {
+      H5Tclose(complex_type);
+      H5Sclose (space_id);
+      H5Dclose (data_hid);
+      return false;
+    }
+
+  // complex scalar:
+  Complex ctmp;
+  if (H5Dread (data_hid, complex_type, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+	       (void *) X_CAST (double *, &ctmp)) >= 0)
+    {
+      retval = true;
+      scalar = ctmp;
+    }
+
+  H5Tclose(complex_type);
+  H5Sclose (space_id);
+  H5Dclose (data_hid);
+  return retval;
+}
+#endif
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-complex.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-complex.h	Tue Jan 06 21:53:34 2004 +0000
@@ -98,6 +98,22 @@
 
   void decrement (void) { scalar -= 1.0; }
 
+  bool save_ascii (std::ostream& os, bool& infnan_warned,
+		 bool strip_nan_and_inf);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool& save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, 
+		    oct_mach_info::float_format fmt);
+
+#if defined (HAVE_HDF5)
+  bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
+#endif
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-cx-mat.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-cx-mat.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -45,6 +45,11 @@
 #include "ov-scalar.h"
 #include "pr-output.h"
 
+#include "byte-swap.h"
+#include "ls-oct-ascii.h"
+#include "ls-hdf5.h"
+#include "ls-utils.h"
+
 template class octave_base_matrix<ComplexNDArray>;
 
 DEFINE_OCTAVE_ALLOCATOR (octave_complex_matrix);
@@ -172,6 +177,413 @@
   return matrix.matrix_value ();
 }
 
+static ComplexMatrix
+strip_infnan (const ComplexMatrix& m)
+{
+  int nr = m.rows ();
+  int nc = m.columns ();
+
+  ComplexMatrix retval (nr, nc);
+
+  int k = 0;
+  for (int i = 0; i < nr; i++)
+    {
+      for (int j = 0; j < nc; j++)
+	{
+	  Complex c = m (i, j);
+	  if (xisnan (c))
+	    goto next_row;
+	  else
+	    {
+	      double re = real (c);
+	      double im = imag (c);
+
+	      re = xisinf (re) ? (re > 0 ? OCT_RBV : -OCT_RBV) : re;
+	      im = xisinf (im) ? (im > 0 ? OCT_RBV : -OCT_RBV) : im;
+
+	      retval (k, j) = Complex (re, im);
+	    }
+	}
+      k++;
+
+    next_row:
+      continue;
+    }
+
+  if (k > 0)
+    retval.resize (k, nc);
+
+  return retval;
+}
+
+bool 
+octave_complex_matrix::save_ascii (std::ostream& os, bool& infnan_warned, 
+			       bool strip_nan_and_inf)
+{
+  dim_vector d = dims ();
+  if (d.length () > 2)
+    {
+      ComplexNDArray tmp = complex_array_value ();
+
+      if (strip_nan_and_inf)
+	{
+	  warning ("save: Can not strip Inf or NaN values");
+	  warning ("save: Inf or NaN values may not be reloadable");
+	  infnan_warned = true;
+	}
+      else if (! infnan_warned && tmp.any_element_is_inf_or_nan ())
+	{
+	  warning ("save: Inf or NaN values may not be reloadable");
+	  infnan_warned = true;
+	}
+
+      os << "# ndims: " << d.length () << "\n";
+
+      for (int i=0; i < d.length (); i++)
+	os << " " << d (i);
+
+      os << "\n" << tmp;
+    }
+  else
+    {
+      // Keep this case, rather than use generic code above for backward 
+      // compatiability. Makes load_ascii much more complex!!
+      os << "# rows: " << rows () << "\n"
+	 << "# columns: " << columns () << "\n";
+
+      ComplexMatrix tmp = complex_matrix_value ();
+
+      if (strip_nan_and_inf)
+	tmp = strip_infnan (tmp);
+      else if (! infnan_warned && tmp.any_element_is_inf_or_nan ())
+	{
+	  warning ("save: Inf or NaN values may not be reloadable");
+	  infnan_warned = true;
+	}
+
+      os << tmp;
+    }
+
+  return true;
+}
+
+bool 
+octave_complex_matrix::load_ascii (std::istream& is)
+{
+  int mdims = 0;
+  bool success = true;
+  std::streampos pos = is.tellg ();
+
+  if (extract_keyword (is, "ndims", mdims, true))
+    {
+      if (mdims >= 0)
+	{
+	  dim_vector dv;
+	  dv.resize (mdims);
+
+	  for (int i = 0; i < mdims; i++)
+	    is >> dv(i);
+
+	  ComplexNDArray tmp(dv);
+	  is >> tmp;
+
+	  if (!is) 
+	    {
+	      error ("load: failed to load matrix constant");
+	      success = false;
+	    }
+	  matrix = tmp;
+	}
+      else
+	{
+	  error ("load: failed to extract number of rows and columns");
+	  success = false;
+	}
+    }
+  else
+    {
+      int nr = 0;
+      int nc = 0;
+
+      // re-read the same line again
+      is.clear ();
+      is.seekg (pos);
+
+      if (extract_keyword (is, "rows", nr) && nr >= 0
+	  && extract_keyword (is, "columns", nc) && nc >= 0)
+	{
+	  if (nr > 0 && nc > 0)
+	    {
+	      ComplexMatrix tmp (nr, nc);
+	      is >> tmp;
+	      if (!is) 
+		{
+		  error ("load: failed to load matrix constant");
+		  success = false;
+		}
+	      matrix = tmp;
+	    }
+	  else if (nr == 0 || nc == 0)
+	    matrix = ComplexMatrix (nr, nc);
+	  else
+	    panic_impossible ();
+	}
+      else 
+	{
+	  error ("load: failed to extract number of rows and columns");
+	  success = false;
+	}
+    }
+
+  return success;
+}
+
+bool 
+octave_complex_matrix::save_binary (std::ostream& os, bool& save_as_floats)
+{
+  dim_vector d = dims ();
+  if (d.length() < 1)
+    return false;
+
+  // Use negative value for ndims to differentiate with old format!!
+  FOUR_BYTE_INT tmp = - d.length();
+  os.write (X_CAST (char *, &tmp), 4);
+  for (int i=0; i < d.length (); i++)
+    {
+      tmp = d(i);
+      os.write (X_CAST (char *, &tmp), 4);
+    }
+
+  ComplexNDArray m = complex_array_value ();
+  save_type st = LS_DOUBLE;
+  if (save_as_floats)
+    {
+      if (m.too_large_for_float ())
+	{
+	  warning ("save: some values too large to save as floats --");
+	  warning ("save: saving as doubles instead");
+	}
+      else
+	st = LS_FLOAT;
+    }
+  else if (d.numel () > 4096) // XXX FIXME XXX -- make this configurable.
+    {
+      double max_val, min_val;
+      if (m.all_integers (max_val, min_val))
+	st = get_save_type (max_val, min_val);
+    }
+
+
+  const Complex *mtmp = m.data ();
+  write_doubles (os, X_CAST (const double *, mtmp), st, 2 * d.numel ());
+
+  return true;
+}
+
+bool 
+octave_complex_matrix::load_binary (std::istream& is, bool swap,
+				 oct_mach_info::float_format fmt)
+{
+  char tmp;
+  FOUR_BYTE_INT mdims;
+  if (! is.read (X_CAST (char *, &mdims), 4))
+    return false;
+  if (swap)
+    swap_4_bytes (X_CAST (char *, &mdims));
+  if (mdims < 0)
+    {
+      mdims = - mdims;
+      FOUR_BYTE_INT di;
+      dim_vector dv;
+      dv.resize (mdims);
+
+      for (int i = 0; i < mdims; i++)
+	{
+	  if (! is.read (X_CAST (char *, &di), 4))
+	    return false;
+	  if (swap)
+	    swap_4_bytes (X_CAST (char *, &di));
+	  dv(i) = di;
+	}
+
+      if (! is.read (X_CAST (char *, &tmp), 1))
+	return false;
+
+      ComplexNDArray m(dv);
+      Complex *im = m.fortran_vec ();
+      read_doubles (is, X_CAST (double *, im), X_CAST (save_type, tmp), 
+		    2 * dv.numel (), swap, fmt);
+      if (error_state || ! is)
+	return false;
+      matrix = m;
+    }
+  else
+    {
+      FOUR_BYTE_INT nr, nc;
+      nr = mdims;
+      if (! is.read (X_CAST (char *, &nc), 4))
+	return false;
+      if (swap)
+	swap_4_bytes (X_CAST (char *, &nc));
+      if (! is.read (X_CAST (char *, &tmp), 1))
+	return false;
+      ComplexMatrix m (nr, nc);
+      Complex *im = m.fortran_vec ();
+      int len = nr * nc;
+      read_doubles (is, X_CAST (double *, im),
+		    X_CAST (save_type, tmp), 2*len, swap, fmt);
+      if (error_state || ! is)
+	return false;
+      matrix = m;
+    }
+  return true;
+}
+
+#if defined (HAVE_HDF5)
+bool
+octave_complex_matrix::save_hdf5 (hid_t loc_id, const char *name,
+				  bool save_as_floats)
+{
+  dim_vector d = dims ();
+  hsize_t hdims[d.length () > 2 ? d.length () : 3];
+  hid_t space_hid = -1, type_hid = -1, data_hid = -1;
+  int rank = ( (d (0) == 1) && (d.length () == 2) ? 1 : d.length ());
+  bool retval = true;
+  ComplexNDArray m = complex_array_value ();
+
+  // Octave uses column-major, while HDF5 uses row-major ordering
+  for (int i = 0, j = d.length() - 1; i < d.length (); i++, j--)
+    hdims[i] = d (j);
+
+  space_hid = H5Screate_simple (rank, hdims, (hsize_t*) 0);
+  if (space_hid < 0) return false;
+
+  hid_t save_type_hid = H5T_NATIVE_DOUBLE;
+
+  if (save_as_floats)
+    {
+      if (m.too_large_for_float ())
+	{
+	  warning ("save: some values too large to save as floats --");
+	  warning ("save: saving as doubles instead");
+	}
+      else
+	save_type_hid = H5T_NATIVE_FLOAT;
+    }
+#if HAVE_HDF5_INT2FLOAT_CONVERSIONS
+  // hdf5 currently doesn't support float/integer conversions
+  else
+    {
+      double max_val, min_val;
+      
+      if (m.all_integers (max_val, min_val))
+	save_type_hid
+	  = save_type_to_hdf5 (get_save_type (max_val, min_val));
+    }
+#endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */
+
+  type_hid = hdf5_make_complex_type (save_type_hid);
+  if (type_hid < 0)
+    {
+      H5Sclose (space_hid);
+      return false;
+    }
+
+  data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, H5P_DEFAULT);
+  if (data_hid < 0)
+    {
+      H5Sclose (space_hid);
+      H5Tclose (type_hid);
+      return false;
+    }
+
+  hid_t complex_type_hid = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
+  if (complex_type_hid < 0) retval = false;
+
+  if (retval)
+    {
+      Complex *mtmp = m.fortran_vec ();
+      if (H5Dwrite (data_hid, complex_type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+		    (void*) X_CAST (double *, mtmp)) < 0)
+	{
+	  H5Tclose (complex_type_hid);
+	  retval = false;
+	}
+    }
+
+  H5Tclose (complex_type_hid);
+  H5Dclose (data_hid);
+  H5Tclose (type_hid);
+  H5Sclose (space_hid);
+  return retval;
+}
+
+bool 
+octave_complex_matrix::load_hdf5 (hid_t loc_id, const char *name,
+				  bool /* have_h5giterate_bug */)
+{
+  bool retval = false;
+  hid_t data_hid = H5Dopen (loc_id, name);
+  hid_t type_hid = H5Dget_type (data_hid);
+
+  hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
+
+  if (! hdf5_types_compatible (type_hid, complex_type))
+    {
+      H5Tclose(complex_type);
+      H5Dclose (data_hid);
+      return false;
+    }
+
+  hid_t space_id = H5Dget_space (data_hid);
+
+  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
+  
+  if (rank < 1)
+    {
+      H5Tclose(complex_type);
+      H5Sclose (space_id);
+      H5Dclose (data_hid);
+      return false;
+    }
+
+  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
+  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
+
+  H5Sget_simple_extent_dims (space_id, hdims, maxdims);
+
+  dim_vector dv;
+
+  // Octave uses column-major, while HDF5 uses row-major ordering
+  if (rank == 1)
+    {
+      dv.resize (2);
+      dv(0) = 1;
+      dv(1) = hdims[0];
+    }
+  else
+    {
+      dv.resize (rank);
+      for (int i = 0, j = rank - 1; i < (int)rank; i++, j--)
+	dv(j) = hdims[i];
+    }
+
+  ComplexNDArray m (dv);
+  Complex *reim = m.fortran_vec ();
+  if (H5Dread (data_hid, complex_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, 
+	       (void *) X_CAST (double *, reim)) >= 0) 
+    {
+      retval = true;
+      matrix = m;
+    }
+
+  H5Tclose(complex_type);
+  H5Sclose (space_id);
+  H5Dclose (data_hid);
+  return retval;
+}
+#endif
+
 void
 octave_complex_matrix::print_raw (std::ostream& os,
 				  bool pr_as_read_syntax) const
--- a/src/ov-cx-mat.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-cx-mat.h	Tue Jan 06 21:53:34 2004 +0000
@@ -108,6 +108,22 @@
 
   void decrement (void) { matrix -= Complex (1.0); }
 
+  bool save_ascii (std::ostream& os, bool& infnan_warned,
+		 bool strip_nan_and_inf);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool& save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, 
+		    oct_mach_info::float_format fmt);
+
+#if defined (HAVE_HDF5)
+  bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
+#endif
+
   void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
 private:
--- a/src/ov-list.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-list.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -39,6 +39,12 @@
 #include "ov-list.h"
 #include "unwind-prot.h"
 
+#include "byte-swap.h"
+#include "ls-oct-ascii.h"
+#include "ls-oct-binary.h"
+#include "ls-hdf5.h"
+#include "ls-utils.h"
+
 DEFINE_OCTAVE_ALLOCATOR (octave_list);
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_list, "list", "list");
@@ -495,6 +501,204 @@
   return retval;
 }
 
+bool 
+octave_list::save_ascii (std::ostream& os, bool& infnan_warned, 
+			   bool strip_nan_and_inf)
+{
+  octave_value_list lst = list_value ();
+  os << "# length: " << lst.length () << "\n";
+
+  for (int i = 0; i < lst.length (); ++i)
+    {
+      // should we use lst.name_tags () to label the elements?
+      char s[20];
+      sprintf (s, "_%d", i);
+      bool b = save_ascii_data (os, lst (i), s, infnan_warned, 
+				strip_nan_and_inf, 0, 0);
+      
+      if (! b)
+	return false;
+    }
+
+  return true;
+}
+
+bool 
+octave_list::load_ascii (std::istream& is)
+{
+  int len = 0;
+  bool success = true;
+
+  if (extract_keyword (is, "length", len) && len >= 0)
+    {
+      if (len > 0)
+	{
+	  octave_value_list lst;
+
+	  for (int j = 0; j < len; j++)
+	    {
+	      octave_value t2;
+	      bool dummy;
+
+	      // recurse to read list elements
+	      std::string nm
+		= read_ascii_data (is, std::string (), dummy, t2, count);
+
+	      if (!is)
+		break;
+
+	      lst.append (t2);
+	    }
+
+	  if (is) 
+	    data = lst;
+	  else
+	    {
+	      error ("load: failed to load list");
+	      success = false;
+	    }
+	}
+      else if (len == 0 )
+	data = Cell (0, 0);
+      else
+	panic_impossible ();
+    }
+  else {
+    error ("load: failed to extract number of elements in list");
+    success = false;
+  }
+
+  return success;
+}
+
+bool 
+octave_list::save_binary (std::ostream& os, bool& save_as_floats)
+{
+  octave_value_list lst = list_value ();
+
+  FOUR_BYTE_INT len = lst.length();
+  os.write (X_CAST (char *, &len), 4);
+  
+  for (int i = 0; i < lst.length (); i++)
+    {
+      // should we use lst.name_tags () to label the elements?
+      char s[20];
+      sprintf (s, "_%d", i);
+
+      // Recurse to print sub-value.
+      bool b = save_binary_data (os, lst(i), s, "", 0, save_as_floats);
+	      
+      if (! b)
+	return false;
+    }
+  
+  return true;
+}
+
+bool 
+octave_list::load_binary (std::istream& is, bool swap,
+				 oct_mach_info::float_format fmt)
+{
+  FOUR_BYTE_INT len;
+  if (! is.read (X_CAST (char *, &len), 4))
+    return false;
+  if (swap)
+    swap_4_bytes (X_CAST (char *, &len));
+
+  if (len > 0)
+    {
+      octave_value_list lst;
+
+      for (int i = 0; i < len; i++)
+	{
+	  octave_value t2;
+	  bool dummy;
+	  std::string doc;
+	  
+	  // recurse to read list elements
+	  std::string nm = read_binary_data (is, swap, fmt, std::string (), 
+					     dummy, t2, doc);
+	  
+	  if (!is)
+	    return false;
+	  
+	  lst.append(t2);
+	}
+
+      if (is)
+	data = lst;
+      else
+	{
+	  error ("load: failed to load list");
+	  return false;
+	}
+
+    }
+  else if (len == 0 )
+    data = Cell (0, 0);
+  else
+    return false;
+  
+  return true;
+}
+
+#if defined (HAVE_HDF5)
+bool
+octave_list::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
+{
+  hid_t data_hid = -1;
+
+  data_hid = H5Gcreate (loc_id, name, 0);
+  if (data_hid < 0) return false;
+
+  // recursively add each element of the list to this group
+  octave_value_list lst = list_value ();
+
+  for (int i = 0; i < lst.length (); ++i)
+    {
+      // should we use lst.name_tags () to label the elements?
+      char s[20];
+      sprintf (s, "_%d", i);
+      bool retval2 = add_hdf5_data (data_hid, lst (i), s, "",
+				    false, save_as_floats);
+      if (! retval2)
+	break;
+    }
+
+  H5Gclose (data_hid);
+  return true;
+}
+
+bool
+octave_list::load_hdf5 (hid_t loc_id,  const char *name,
+			bool have_h5giterate_bug)
+{
+  bool retval = false;
+
+  hdf5_callback_data dsub;
+
+  herr_t retval2;
+  octave_value_list lst;
+  int current_item = 0;
+  while ((retval2 = H5Giterate (loc_id, name, &current_item,
+				hdf5_read_next_data, &dsub)) > 0)
+    {
+      lst.append (dsub.tc);
+
+      if (have_h5giterate_bug)
+	current_item++;  // H5Giterate returned the last index processed
+    }
+
+  if (retval2 >= 0)
+    {
+      data = lst;
+      retval = true;
+    }
+  
+  return retval;
+}
+#endif
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-list.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-list.h	Tue Jan 06 21:53:34 2004 +0000
@@ -100,6 +100,22 @@
 
   bool print_name_tag (std::ostream& os, const std::string& name) const;
 
+  bool save_ascii (std::ostream& os, bool& infnan_warned,
+		 bool strip_nan_and_inf);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool& save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, 
+		    oct_mach_info::float_format fmt);
+
+#if defined (HAVE_HDF5)
+  bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
+#endif
+
 protected:
 
   // The list of Octave values.
--- a/src/ov-range.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-range.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -41,6 +41,10 @@
 #include "ov-scalar.h"
 #include "pr-output.h"
 
+#include "byte-swap.h"
+#include "ls-hdf5.h"
+#include "ls-utils.h"
+
 DEFINE_OCTAVE_ALLOCATOR (octave_range);
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_range, "range", "double");
@@ -250,6 +254,213 @@
   return retval;
 }
 
+// Skip white space and comments on stream IS.
+
+static void
+skip_comments (std::istream& is)
+{
+  char c = '\0';
+  while (is.get (c))
+    {
+      if (c == ' ' || c == '\t' || c == '\n')
+	; // Skip whitespace on way to beginning of next line.
+      else
+	break;
+    }
+
+  for (;;)
+    {
+      if (is && (c == '%' || c == '#'))
+	while (is.get (c) && c != '\n')
+	  ; // Skip to beginning of next line, ignoring everything.
+      else
+	break;
+    }
+}
+
+bool 
+octave_range::save_ascii (std::ostream& os, bool& /* infnan_warned */,
+			  bool /* strip_nan_and_inf */)
+{
+  Range r = range_value ();
+  double base = r.base ();
+  double limit = r.limit ();
+  double inc = r.inc ();
+
+  os << "# base, limit, increment\n";
+  octave_write_double (os, base);
+  os << " ";
+  octave_write_double (os, limit);
+  os << " ";
+  octave_write_double (os, inc);
+  os << "\n";
+
+  return true;
+}
+
+bool 
+octave_range::load_ascii (std::istream& is)
+{
+  // # base, limit, range comment added by save ().
+  skip_comments (is);
+
+  is >> range;
+
+  if (!is)
+    {
+      error ("load: failed to load range constant");
+      return false;
+    }
+
+  return true;
+}
+
+bool 
+octave_range::save_binary (std::ostream& os, bool& /* save_as_floats */)
+{
+  char tmp = (char) LS_DOUBLE;
+  os.write (X_CAST (char *, &tmp), 1);
+  Range r = range_value ();
+  double bas = r.base ();
+  double lim = r.limit ();
+  double inc = r.inc ();
+  os.write (X_CAST (char *, &bas), 8);
+  os.write (X_CAST (char *, &lim), 8);
+  os.write (X_CAST (char *, &inc), 8);
+
+  return true;
+}
+
+bool 
+octave_range::load_binary (std::istream& is, bool swap,
+			   oct_mach_info::float_format /* fmt */)
+{
+  char tmp;
+  if (! is.read (X_CAST (char *, &tmp), 1))
+    return false;
+  double bas, lim, inc;
+  if (! is.read (X_CAST (char *, &bas), 8))
+    return false;
+  if (swap)
+    swap_8_bytes (X_CAST (char *, &bas));
+  if (! is.read (X_CAST (char *, &lim), 8))
+    return false;
+  if (swap)
+    swap_8_bytes (X_CAST (char *, &lim));
+  if (! is.read (X_CAST (char *, &inc), 8))
+    return false;
+  if (swap)
+    swap_8_bytes (X_CAST (char *, &inc));
+  Range r (bas, lim, inc);
+  range = r;
+  return true;
+}
+
+#if defined (HAVE_HDF5)
+// The following subroutines creates an HDF5 representation of the way
+// we will store Octave range types (triplets of floating-point numbers). 
+// NUM_TYPE is the HDF5 numeric type to use for storage (e.g. 
+// H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary 
+// conversions are handled automatically by HDF5.
+
+static hid_t
+hdf5_make_range_type (hid_t num_type)
+{
+  hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 3);
+
+  H5Tinsert (type_id, "base", 0 * sizeof (double), num_type);
+  H5Tinsert (type_id, "limit", 1 * sizeof (double), num_type);
+  H5Tinsert (type_id, "increment", 2 * sizeof (double), num_type);
+
+  return type_id;
+}
+
+bool
+octave_range::save_hdf5 (hid_t loc_id, const char *name,
+			 bool /* save_as_floats */)
+{
+  hsize_t dims[3];
+  hid_t space_hid = -1, type_hid = -1, data_hid = -1;
+  bool retval = true;
+
+  space_hid = H5Screate_simple (0, dims, (hsize_t*) 0);
+  if (space_hid < 0) return false;
+
+  type_hid = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
+  if (type_hid < 0) 
+    {
+      H5Sclose (space_hid);
+      return false;
+    }
+
+  data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, H5P_DEFAULT);
+  if (data_hid < 0) 
+    {
+      H5Sclose (space_hid);
+      H5Tclose (type_hid);
+      return false;
+    }
+  
+  Range r = range_value ();
+  double range_vals[3];
+  range_vals[0] = r.base ();
+  range_vals[1] = r.limit ();
+  range_vals[2] = r.inc ();
+
+  retval = H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+		     (void*) range_vals) >= 0;
+
+  H5Dclose (data_hid);
+  H5Tclose (type_hid);
+  H5Sclose (space_hid);
+  return retval;
+}
+
+bool 
+octave_range::load_hdf5 (hid_t loc_id, const char *name,
+			 bool /* have_h5giterate_bug */)
+{
+  bool retval = false;
+  hid_t data_hid = H5Dopen (loc_id, name);
+  hid_t type_hid = H5Dget_type (data_hid);
+
+  hid_t range_type = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
+
+  if (! hdf5_types_compatible (type_hid, range_type))
+    {
+      H5Tclose(range_type);
+      H5Dclose (data_hid);
+      return false;
+    }
+
+  hid_t space_hid = H5Dget_space (data_hid);
+  hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
+
+  if (rank != 0)
+    {
+      H5Tclose(range_type);
+      H5Sclose (space_hid);
+      H5Dclose (data_hid);
+      return false;
+    }
+
+  double rangevals[3];
+  if (H5Dread (data_hid, range_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, 
+	       (void *) rangevals) >= 0)
+    {
+      retval = true;
+      Range r (rangevals[0], rangevals[1], rangevals[2]);
+      range = r;
+    }
+
+  H5Tclose(range_type);
+  H5Sclose (space_hid);
+  H5Dclose (data_hid);
+  return retval;
+
+}
+#endif
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-range.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-range.h	Tue Jan 06 21:53:34 2004 +0000
@@ -171,6 +171,22 @@
 
   bool print_name_tag (std::ostream& os, const std::string& name) const;
 
+  bool save_ascii (std::ostream& os, bool& infnan_warned,
+		 bool strip_nan_and_inf);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool& save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, 
+		    oct_mach_info::float_format fmt);
+
+#if defined (HAVE_HDF5)
+  bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
+#endif
+
 private:
 
   Range range;
--- a/src/ov-re-mat.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-re-mat.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -49,6 +49,10 @@
 #include "pr-output.h"
 #include "variables.h"
 
+#include "byte-swap.h"
+#include "ls-oct-ascii.h"
+#include "ls-utils.h"
+
 #if ! defined (UCHAR_MAX)
 #define UCHAR_MAX 255
 #endif
@@ -226,6 +230,371 @@
   return retval;
 }
 
+static Matrix
+strip_infnan (const Matrix& m)
+{
+  int nr = m.rows ();
+  int nc = m.columns ();
+
+  Matrix retval (nr, nc);
+
+  int k = 0;
+  for (int i = 0; i < nr; i++)
+    {
+      for (int j = 0; j < nc; j++)
+	{
+	  double d = m (i, j);
+	  if (xisnan (d))
+	    goto next_row;
+	  else
+	    retval (k, j) = xisinf (d) ? (d > 0 ? OCT_RBV : -OCT_RBV) : d;
+	}
+      k++;
+
+    next_row:
+      continue;
+    }
+
+  if (k > 0)
+    retval.resize (k, nc);
+
+  return retval;
+}
+
+bool 
+octave_matrix::save_ascii (std::ostream& os, bool& infnan_warned, 
+			       bool strip_nan_and_inf)
+{
+  dim_vector d = dims ();
+  if (d.length () > 2)
+    {
+      NDArray tmp = array_value ();
+
+      if (strip_nan_and_inf)
+	{
+	  warning ("save: Can not strip Inf or NaN values");
+	  warning ("save: Inf or NaN values may not be reloadable");
+	  infnan_warned = true;
+	}
+      else if (! infnan_warned && tmp.any_element_is_inf_or_nan ())
+	{
+	  warning ("save: Inf or NaN values may not be reloadable");
+	  infnan_warned = true;
+	}
+
+      os << "# ndims: " << d.length () << "\n";
+
+      for (int i=0; i < d.length (); i++)
+	os << " " << d (i);
+
+      os << "\n" << tmp;
+    }
+  else
+    {
+      // Keep this case, rather than use generic code above for backward 
+      // compatiability. Makes load_ascii much more complex!!
+      os << "# rows: " << rows () << "\n"
+	 << "# columns: " << columns () << "\n";
+
+      Matrix tmp = matrix_value ();
+
+      if (strip_nan_and_inf)
+	tmp = strip_infnan (tmp);
+      else if (! infnan_warned && tmp.any_element_is_inf_or_nan ())
+	{
+	  warning ("save: Inf or NaN values may not be reloadable");
+	  infnan_warned = true;
+	}
+
+      os << tmp;
+    }
+
+  return true;
+}
+
+bool 
+octave_matrix::load_ascii (std::istream& is)
+{
+  int mdims = 0;
+  bool success = true;
+  std::streampos pos = is.tellg ();
+
+  if (extract_keyword (is, "ndims", mdims, true))
+    {
+      if (mdims >= 0)
+	{
+	  dim_vector dv;
+	  dv.resize (mdims);
+
+	  for (int i = 0; i < mdims; i++)
+	    is >> dv(i);
+
+	  NDArray tmp(dv);
+	  is >> tmp;
+
+	  if (!is) 
+	    {
+	      error ("load: failed to load matrix constant");
+	      success = false;
+	    }
+	  matrix = tmp;
+	}
+      else
+	{
+	  error ("load: failed to extract number of rows and columns");
+	  success = false;
+	}
+    }
+  else
+    {
+      int nr = 0;
+      int nc = 0;
+
+      // re-read the same line again
+      is.clear ();
+      is.seekg (pos);
+
+      if (extract_keyword (is, "rows", nr) && nr >= 0
+	  && extract_keyword (is, "columns", nc) && nc >= 0)
+	{
+	  if (nr > 0 && nc > 0)
+	    {
+	      Matrix tmp (nr, nc);
+	      is >> tmp;
+	      if (is)
+		matrix = tmp;
+	      else
+		{
+		  error ("load: failed to load matrix constant");
+		  success = false;
+		}
+	    }
+	  else if (nr == 0 || nc == 0)
+	    matrix = Matrix (nr, nc);
+	  else
+	    panic_impossible ();
+	}
+      else 
+	{
+	  error ("load: failed to extract number of rows and columns");
+	  success = false;
+	}
+    }
+
+  return success;
+}
+
+bool 
+octave_matrix::save_binary (std::ostream& os, bool& save_as_floats)
+{
+
+  dim_vector d = dims ();
+  if (d.length() < 1)
+    return false;
+
+  // Use negative value for ndims to differentiate with old format!!
+  FOUR_BYTE_INT tmp = - d.length();
+  os.write (X_CAST (char *, &tmp), 4);
+  for (int i=0; i < d.length (); i++)
+    {
+      tmp = d(i);
+      os.write (X_CAST (char *, &tmp), 4);
+    }
+
+  NDArray m = array_value ();
+  save_type st = LS_DOUBLE;
+  if (save_as_floats)
+    {
+      if (m.too_large_for_float ())
+	{
+	  warning ("save: some values too large to save as floats --");
+	  warning ("save: saving as doubles instead");
+	}
+      else
+	st = LS_FLOAT;
+    }
+  else if (d.numel () > 8192) // XXX FIXME XXX -- make this configurable.
+    {
+      double max_val, min_val;
+      if (m.all_integers (max_val, min_val))
+	st = get_save_type (max_val, min_val);
+    }
+
+  const double *mtmp = m.data ();
+  write_doubles (os, mtmp, st, d.numel ());
+
+  return true;
+}
+
+bool 
+octave_matrix::load_binary (std::istream& is, bool swap,
+				 oct_mach_info::float_format fmt)
+{
+  char tmp;
+  FOUR_BYTE_INT mdims;
+  if (! is.read (X_CAST (char *, &mdims), 4))
+    return false;
+  if (swap)
+    swap_4_bytes (X_CAST (char *, &mdims));
+  if (mdims < 0)
+    {
+      mdims = - mdims;
+      FOUR_BYTE_INT di;
+      dim_vector dv;
+      dv.resize (mdims);
+
+      for (int i = 0; i < mdims; i++)
+	{
+	  if (! is.read (X_CAST (char *, &di), 4))
+	    return false;
+	  if (swap)
+	    swap_4_bytes (X_CAST (char *, &di));
+	  dv(i) = di;
+	}
+
+      if (! is.read (X_CAST (char *, &tmp), 1))
+	return false;
+
+      NDArray m(dv);
+      double *re = m.fortran_vec ();
+      read_doubles (is, re, X_CAST (save_type, tmp), dv.numel (), swap, fmt);
+      if (error_state || ! is)
+	return false;
+      matrix = m;
+    }
+  else
+    {
+      FOUR_BYTE_INT nr, nc;
+      nr = mdims;
+      if (! is.read (X_CAST (char *, &nc), 4))
+	return false;
+      if (swap)
+	swap_4_bytes (X_CAST (char *, &nc));
+      if (! is.read (X_CAST (char *, &tmp), 1))
+	return false;
+      Matrix m (nr, nc);
+      double *re = m.fortran_vec ();
+      int len = nr * nc;
+      read_doubles (is, re, X_CAST (save_type, tmp), len, swap, fmt);
+      if (error_state || ! is)
+	return false;
+      matrix = m;
+    }
+  return true;
+}
+
+#if defined (HAVE_HDF5)
+bool
+octave_matrix::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
+{
+  dim_vector d = dims ();
+  hsize_t hdims[d.length () > 2 ? d.length () : 3];
+  hid_t space_hid = -1, data_hid = -1;
+  int rank = ( (d (0) == 1) && (d.length () == 2) ? 1 : d.length ());
+  bool retval = true;
+  NDArray m = array_value ();
+
+  // Octave uses column-major, while HDF5 uses row-major ordering
+  for (int i = 0, j = d.length() - 1; i < d.length (); i++, j--)
+    hdims[i] = d (j);
+
+  space_hid = H5Screate_simple (rank, hdims, (hsize_t*) 0);
+  if (space_hid < 0) return false;
+
+  hid_t save_type_hid = H5T_NATIVE_DOUBLE;
+
+  if (save_as_floats)
+    {
+      if (m.too_large_for_float ())
+	{
+	  warning ("save: some values too large to save as floats --");
+	  warning ("save: saving as doubles instead");
+	}
+      else
+	save_type_hid = H5T_NATIVE_FLOAT;
+    }
+#if HAVE_HDF5_INT2FLOAT_CONVERSIONS
+  // hdf5 currently doesn't support float/integer conversions
+  else
+    {
+      double max_val, min_val;
+
+      if (m.all_integers (max_val, min_val))
+	save_type_hid
+	  = save_type_to_hdf5 (get_save_type (max_val, min_val));
+    }
+#endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */
+  
+  data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid, 
+			H5P_DEFAULT);
+  if (data_hid < 0)
+    {
+      H5Sclose (space_hid);
+      return false;
+    }
+
+  double *mtmp = m.fortran_vec ();
+  retval = H5Dwrite (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
+		     H5P_DEFAULT, (void*) mtmp) >= 0;
+
+  H5Dclose (data_hid);
+  H5Sclose (space_hid);
+  return retval;
+}
+
+bool
+octave_matrix::load_hdf5 (hid_t loc_id, const char *name,
+			  bool /* have_h5giterate_bug */)
+{
+  bool retval = false;
+  hid_t data_hid = H5Dopen (loc_id, name);
+  hid_t space_id = H5Dget_space (data_hid);
+
+  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
+  
+  if (rank < 1)
+    {
+      H5Sclose (space_id);
+      H5Dclose (data_hid);
+      return false;
+    }
+
+  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
+  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
+
+  H5Sget_simple_extent_dims (space_id, hdims, maxdims);
+
+  dim_vector dv;
+
+  // Octave uses column-major, while HDF5 uses row-major ordering
+  if (rank == 1)
+    {
+      dv.resize (2);
+      dv(0) = 1;
+      dv(1) = hdims[0];
+    }
+  else
+    {
+      dv.resize (rank);
+      for (int i = 0, j = rank - 1; i < (int)rank; i++, j--)
+	dv(j) = hdims[i];
+    }
+
+  NDArray m (dv);
+  double *re = m.fortran_vec ();
+  if (H5Dread (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, 
+	       H5P_DEFAULT, (void *) re) >= 0) 
+    {
+      retval = true;
+      matrix = m;
+    }
+
+  H5Sclose (space_id);
+  H5Dclose (data_hid);
+  return retval;
+}
+#endif
+
 void
 octave_matrix::print_raw (std::ostream& os,
 			  bool pr_as_read_syntax) const
--- a/src/ov-re-mat.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-re-mat.h	Tue Jan 06 21:53:34 2004 +0000
@@ -113,6 +113,22 @@
 
   void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
+  bool save_ascii (std::ostream& os, bool& infnan_warned,
+		 bool strip_nan_and_inf);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool& save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, 
+		    oct_mach_info::float_format fmt);
+
+#if defined (HAVE_HDF5)
+  bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
+#endif
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-scalar.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-scalar.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -43,6 +43,9 @@
 #include "xdiv.h"
 #include "xpow.h"
 
+#include "ls-oct-ascii.h"
+#include "ls-hdf5.h"
+
 template class octave_base_scalar<double>;
 
 DEFINE_OCTAVE_ALLOCATOR (octave_scalar);
@@ -115,6 +118,140 @@
   return retval;
 }
 
+bool 
+octave_scalar::save_ascii (std::ostream& os, bool& infnan_warned, 
+			   bool strip_nan_and_inf)
+{
+  double d = double_value ();
+
+  if (strip_nan_and_inf)
+    {
+      if (xisnan (d))
+	{
+	  error ("only value to plot is NaN");
+	  return false;
+	}
+      else
+	{
+	  d = xisinf (d) ? (d > 0 ? OCT_RBV : -OCT_RBV) : d;
+	  octave_write_double (os, d);
+	  os << "\n";
+	}
+    }
+  else
+    {
+      if (! infnan_warned && (xisnan (d) || xisinf (d)))
+	{
+	  warning ("save: Inf or NaN values may not be reloadable");
+	  infnan_warned = true;
+	}
+
+      octave_write_double (os, d);
+      os << "\n";
+    }
+
+  return true;
+}
+
+bool 
+octave_scalar::load_ascii (std::istream& is)
+{
+  scalar = octave_read_double (is);
+  if (!is)
+    {
+      error ("load: failed to load scalar constant");
+      return false;
+    }
+
+  return true;
+}
+
+bool 
+octave_scalar::save_binary (std::ostream& os, bool& /* save_as_floats */)
+{
+  char tmp = (char) LS_DOUBLE;
+  os.write (X_CAST (char *, &tmp), 1);
+  double dtmp = double_value ();
+  os.write (X_CAST (char *, &dtmp), 8);
+
+  return true;
+}
+
+bool 
+octave_scalar::load_binary (std::istream& is, bool swap,
+				 oct_mach_info::float_format fmt)
+{
+  char tmp;
+  if (! is.read (X_CAST (char *, &tmp), 1))
+    return false;
+
+  double dtmp;
+  read_doubles (is, &dtmp, X_CAST (save_type, tmp), 1, swap, fmt);
+  if (error_state || ! is)
+    return false;
+
+  scalar = dtmp;
+  return true;
+}
+
+#if defined (HAVE_HDF5)
+bool
+octave_scalar::save_hdf5 (hid_t loc_id, const char *name,
+			  bool /* save_as_floats */)
+{
+  hsize_t dimens[3];
+  hid_t space_hid = -1, data_hid = -1;
+  bool retval = true;
+
+  space_hid = H5Screate_simple (0, dimens, (hsize_t*) 0);
+  if (space_hid < 0) return false;
+
+  data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_DOUBLE, space_hid, 
+			H5P_DEFAULT);
+  if (data_hid < 0) 
+    {
+      H5Sclose (space_hid);
+      return false;
+    }
+
+  double tmp = double_value ();
+  retval = H5Dwrite (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
+		     H5P_DEFAULT, (void*) &tmp) >= 0;
+
+  H5Dclose (data_hid);
+  H5Sclose (space_hid);
+  return retval;
+}
+
+bool
+octave_scalar::load_hdf5 (hid_t loc_id, const char *name,
+			  bool /* have_h5giterate_bug */)
+{
+  hid_t data_hid = H5Dopen (loc_id, name);
+  hid_t space_id = H5Dget_space (data_hid);
+
+  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
+
+  if (rank != 0)
+    { 
+      H5Dclose (data_hid);
+      return false;
+    }
+
+  double dtmp;
+  if (H5Dread (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, 
+	       H5P_DEFAULT, (void *) &dtmp) < 0)
+    { 
+      H5Dclose (data_hid);
+      return false;
+    }
+
+  scalar = dtmp;
+  H5Dclose (data_hid);
+  return true;
+}
+#endif
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-scalar.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-scalar.h	Tue Jan 06 21:53:34 2004 +0000
@@ -108,6 +108,22 @@
 
   void decrement (void) { --scalar; }
 
+  bool save_ascii (std::ostream& os, bool& infnan_warned,
+		 bool strip_nan_and_inf);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool& save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, 
+		    oct_mach_info::float_format fmt);
+
+#if defined (HAVE_HDF5)
+  bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
+#endif
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-str-mat.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-str-mat.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -41,6 +41,11 @@
 #include "pr-output.h"
 #include "pt-mat.h"
 
+#include "byte-swap.h"
+#include "ls-oct-ascii.h"
+#include "ls-hdf5.h"
+#include "ls-utils.h"
+
 DEFINE_OCTAVE_ALLOCATOR (octave_char_matrix_str);
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_char_matrix_str, "string", "char");
@@ -229,6 +234,330 @@
 			 current_print_indent_level (), true);
 }
 
+bool 
+octave_char_matrix_str::save_ascii (std::ostream& os,
+				    bool& /* infnan_warned */, 
+				    bool /* strip_nan_and_inf */)
+{
+  charMatrix chm = char_matrix_value ();
+  int elements = chm.rows ();
+  os << "# elements: " << elements << "\n";
+  for (int i = 0; i < elements; i++)
+    {
+      unsigned len = chm.cols ();
+      os << "# length: " << len << "\n";
+      std::string tstr = chm.row_as_string (i, false, true);
+      const char *tmp = tstr.data ();
+      if (tstr.length () > len)
+	panic_impossible ();
+      os.write (X_CAST (char *, tmp), len);
+      os << "\n";
+    }
+
+  return true;
+}
+
+bool 
+octave_char_matrix_str::load_ascii (std::istream& is)
+{
+  int elements;
+  bool success = true;
+  std::streampos pos = is.tellg ();
+
+  if (extract_keyword (is, "elements", elements, true))
+    {
+
+      if (elements >= 0)
+	{
+	  // XXX FIXME XXX -- need to be able to get max length
+	  // before doing anything.
+
+	  charMatrix chm (elements, 0);
+	  int max_len = 0;
+	  for (int i = 0; i < elements; i++)
+	    {
+	      int len;
+	      if (extract_keyword (is, "length", len) && len >= 0)
+		{
+		  OCTAVE_LOCAL_BUFFER (char, tmp, len+1);
+		  
+		  if (len > 0 && ! is.read (X_CAST (char *, tmp), len))
+		    {
+		      error ("load: failed to load string constant");
+		      success = false;
+		      break;
+		    }
+		  else
+		    {
+		      tmp [len] = '\0';
+		      if (len > max_len)
+			{
+			  max_len = len;
+			  chm.resize (elements, max_len, 0);
+			}
+		      chm.insert (tmp, i, 0);
+		    }
+		}
+	      else
+		{
+		  error ("load: failed to extract string length for element %d", 
+			 i+1);
+		  success = false;
+		}
+	    }
+	  
+	  if (! error_state)
+	    matrix = chm;
+	  
+	}
+      else
+	{
+	  error ("load: failed to extract number of string elements");
+	  success = false;
+	}
+    }
+  else
+    {
+      // re-read the same line again
+      is.clear ();
+      is.seekg (pos);
+
+      int len;
+      
+      if (extract_keyword (is, "length", len) && len >= 0)
+	{
+	  // This is cruft for backward compatiability, but relatively harmless.
+
+	  OCTAVE_LOCAL_BUFFER (char, tmp, len+1);
+
+	  if (len > 0 && ! is.read (X_CAST (char *, tmp), len))
+	    {
+	      error ("load: failed to load string constant");
+	    }
+	  else
+	    {
+	      tmp [len] = '\0';
+
+	      if (is)
+		matrix = charMatrix (tmp);
+	      else
+		error ("load: failed to load string constant");
+	    }
+	}
+    }
+
+  return success;
+}
+
+bool 
+octave_char_matrix_str::save_binary (std::ostream& os,
+				     bool& /* save_as_floats */)
+{
+  FOUR_BYTE_INT nr = rows ();
+  os.write (X_CAST (char *, &nr), 4);
+  charMatrix chm = char_matrix_value ();
+  for (int i = 0; i < nr; i++)
+    {
+      FOUR_BYTE_INT len = chm.cols ();
+      os.write (X_CAST (char *, &len), 4);
+      std::string tstr = chm.row_as_string (i);
+      const char *btmp = tstr.data ();
+      os.write (X_CAST (char *, btmp), len);
+    }
+  return true;
+}
+
+bool 
+octave_char_matrix_str::load_binary (std::istream& is, bool swap,
+				     oct_mach_info::float_format /* fmt */)
+{
+  FOUR_BYTE_INT elements;
+  if (! is.read (X_CAST (char *, &elements), 4))
+    return false;
+  if (swap)
+    swap_4_bytes (X_CAST (char *, &elements));
+  charMatrix chm (elements, 0);
+  int max_len = 0;
+  for (int i = 0; i < elements; i++)
+    {
+      FOUR_BYTE_INT len;
+      if (! is.read (X_CAST (char *, &len), 4))
+	return false;
+      if (swap)
+	swap_4_bytes (X_CAST (char *, &len));
+      OCTAVE_LOCAL_BUFFER (char, btmp, len+1);
+      if (! is.read (X_CAST (char *, btmp), len))
+	return false;
+      if (len > max_len)
+	{
+	  max_len = len;
+	  chm.resize (elements, max_len, 0);
+	}
+      btmp [len] = '\0';
+      chm.insert (btmp, i, 0);
+    }
+
+  matrix = chm;
+  return true;
+}
+
+#if defined (HAVE_HDF5)
+bool
+octave_char_matrix_str::save_hdf5 (hid_t loc_id, const char *name,
+				   bool /* save_as_floats */)
+{
+  hsize_t dimens[3];
+  hid_t space_hid = -1, type_hid = -1, data_hid = -1;
+  bool retval = true;
+
+  int nr = rows ();
+  charMatrix chm = char_matrix_value ();
+  int nc = chm.cols ();
+
+  // create datatype for (null-terminated) string to write from:
+  type_hid = H5Tcopy (H5T_C_S1); H5Tset_size (type_hid, nc + 1);
+  if (type_hid < 0) return false;
+
+  dimens[0] = nr;
+  space_hid = H5Screate_simple (nr > 0 ? 1 : 0, dimens, (hsize_t*) 0);
+  if (space_hid < 0)
+    {
+      H5Tclose (type_hid);
+      return false;
+    }
+
+  data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, H5P_DEFAULT);
+  if (data_hid < 0)
+    {
+      H5Sclose (space_hid);
+      H5Tclose (type_hid);
+      return false;
+    }
+
+  OCTAVE_LOCAL_BUFFER (char, s, nr * (nc + 1));
+
+  for (int i = 0; i < nr; ++i)
+    {
+      std::string tstr = chm.row_as_string (i);
+      strcpy (s + i * (nc+1), tstr.c_str ());
+    }
+
+  retval = H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+		     (void*) s) >= 0;
+
+  H5Dclose (data_hid);
+  H5Tclose (type_hid);
+  H5Sclose (space_hid);
+  return retval;
+}
+
+bool 
+octave_char_matrix_str::load_hdf5 (hid_t loc_id, const char *name,
+				   bool /* have_h5giterate_bug */)
+{
+  hid_t data_hid = H5Dopen (loc_id, name);
+  hid_t space_hid = H5Dget_space (data_hid);
+  hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
+  hid_t type_hid = H5Dget_type (data_hid);
+
+  if (rank == 0)
+    {
+      // a single string:
+      int slen = H5Tget_size (type_hid);
+      if (slen < 0)
+	{
+	  H5Tclose (type_hid);
+	  H5Sclose (space_hid);
+	  H5Dclose (data_hid);
+	  return false;
+	}
+      else
+	{
+	  OCTAVE_LOCAL_BUFFER (char, s, slen);
+	  // create datatype for (null-terminated) string
+	  // to read into:
+	  hid_t st_id = H5Tcopy (H5T_C_S1);
+	  H5Tset_size (st_id, slen);
+	  if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, 
+		       H5P_DEFAULT, (void *) s) < 0)
+	    {
+	      H5Tclose (st_id);
+	      H5Tclose (type_hid);
+	      H5Sclose (space_hid);
+	      H5Dclose (data_hid);
+	      return false;
+	    }
+
+	  matrix = charMatrix (s);
+	  
+	  H5Tclose (st_id);
+	  H5Tclose (type_hid);
+	  H5Sclose (space_hid);
+	  H5Dclose (data_hid);
+	  return true;
+	}
+    }
+  else if (rank == 1)
+    {
+      // string vector
+      hsize_t elements, maxdim;
+      H5Sget_simple_extent_dims (space_hid, &elements, &maxdim);
+      int slen = H5Tget_size (type_hid);
+      if (slen < 0)
+	{
+	  H5Tclose (type_hid);
+	  H5Sclose (space_hid);
+	  H5Dclose (data_hid);
+	  return false;
+	}
+      else
+	{
+	  // hdf5 string arrays store strings of all the
+	  // same physical length (I think), which is
+	  // slightly wasteful, but oh well.
+	  
+	  OCTAVE_LOCAL_BUFFER (char, s, elements * slen);
+
+	  // create datatype for (null-terminated) string
+	  // to read into:
+	  hid_t st_id = H5Tcopy (H5T_C_S1);
+	  H5Tset_size (st_id, slen);
+
+	  if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, 
+		       H5P_DEFAULT, (void *) s) < 0)
+	    {
+	      H5Tclose (st_id);
+	      H5Tclose (type_hid);
+	      H5Sclose (space_hid);
+	      H5Dclose (data_hid);
+	      return false;
+	    }
+
+	  charMatrix chm (elements, slen - 1);
+	  for (hsize_t i = 0; i < elements; ++i)
+	    {
+	      chm.insert (s + i*slen, i, 0);
+	    }
+
+	  matrix = chm;
+
+	  H5Tclose (st_id);
+	  H5Tclose (type_hid);
+	  H5Sclose (space_hid);
+	  H5Dclose (data_hid);
+	  return true;
+	}
+    }
+  else
+    {
+      H5Tclose (type_hid);
+      H5Sclose (space_hid);
+      H5Dclose (data_hid);
+      return false;
+    }
+}
+#endif
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-str-mat.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-str-mat.h	Tue Jan 06 21:53:34 2004 +0000
@@ -124,6 +124,22 @@
 
   void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
+  bool save_ascii (std::ostream& os, bool& infnan_warned,
+		 bool strip_nan_and_inf);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool& save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, 
+		    oct_mach_info::float_format fmt);
+
+#if defined (HAVE_HDF5)
+  bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
+#endif
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-struct.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-struct.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -40,6 +40,12 @@
 #include "unwind-prot.h"
 #include "variables.h"
 
+#include "byte-swap.h"
+#include "ls-oct-ascii.h"
+#include "ls-oct-binary.h"
+#include "ls-hdf5.h"
+#include "ls-utils.h"
+
 DEFINE_OCTAVE_ALLOCATOR(octave_struct);
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct", "struct");
@@ -527,6 +533,214 @@
   return retval;
 }
 
+bool 
+octave_struct::save_ascii (std::ostream& os, bool& infnan_warned, 
+			   bool strip_nan_and_inf)
+{
+  Octave_map m = map_value ();
+  os << "# length: " << m.length () << "\n";
+
+  Octave_map::iterator i = m.begin ();
+  while (i != m.end ())
+    {
+      Cell val = map.contents (i);
+      octave_value tmp = (map.numel () == 1) ? val(0) : 
+	octave_value (val, true);
+
+      bool b = save_ascii_data (os, tmp, m.key (i), infnan_warned, 
+				strip_nan_and_inf, 0, 0);
+      
+      if (! b)
+	return os;
+
+      i++;
+    }
+
+  return true;
+}
+
+bool 
+octave_struct::load_ascii (std::istream& is)
+{
+  int len = 0;
+  bool success = true;
+
+  if (extract_keyword (is, "length", len) && len >= 0)
+    {
+      if (len > 0)
+	{
+	  Octave_map m (map);
+
+	  for (int j = 0; j < len; j++)
+	    {
+	      octave_value t2;
+	      bool dummy;
+
+	      // recurse to read cell elements
+	      std::string nm
+		= read_ascii_data (is, std::string (), dummy, t2, count);
+
+	      if (!is)
+		break;
+
+	      m.assign (nm, t2);
+	    }
+
+	  if (is) 
+	    map = m;
+	  else
+	    {
+	      error ("load: failed to load structure");
+	      success = false;
+	    }
+	}
+      else if (len == 0 )
+	map = Octave_map ();
+      else
+	panic_impossible ();
+    }
+  else {
+    error ("load: failed to extract number of elements in structure");
+    success = false;
+  }
+
+  return success;
+}
+
+bool 
+octave_struct::save_binary (std::ostream& os, bool& save_as_floats)
+{
+  Octave_map m = map_value ();
+
+  FOUR_BYTE_INT len = m.length();
+  os.write (X_CAST (char *, &len), 4);
+  
+  Octave_map::iterator i = m.begin ();
+  while (i != m.end ())
+    {
+      Cell val = map.contents (i);
+      octave_value tmp = (map.numel () == 1) ? val(0) : 
+	octave_value (val, true);
+
+      bool b = save_binary_data (os, tmp, m.key (i), "", 0, save_as_floats);
+      
+      if (! b)
+	return os;
+
+      i++;
+    }
+
+  return true;
+}
+
+bool 
+octave_struct::load_binary (std::istream& is, bool swap,
+				 oct_mach_info::float_format fmt)
+{
+  bool success = true;
+  FOUR_BYTE_INT len;
+  if (! is.read (X_CAST (char *, &len), 4))
+    return false;
+  if (swap)
+    swap_4_bytes (X_CAST (char *, &len));
+
+  if (len > 0)
+    {
+      Octave_map m (map);
+
+      for (int j = 0; j < len; j++)
+	{
+	  octave_value t2;
+	  bool dummy;
+	  std::string doc;
+
+	  // recurse to read cell elements
+	  std::string nm = read_binary_data (is, swap, fmt, std::string (), 
+					     dummy, t2, doc);
+
+	  if (!is)
+	    break;
+
+	  m.assign (nm, t2);
+	}
+
+      if (is) 
+	map = m;
+      else
+	{
+	  error ("load: failed to load structure");
+	  success = false;
+	}
+    }
+  else if (len == 0 )
+    map = Octave_map ();
+  else
+    panic_impossible ();
+
+  return success;
+}
+
+#if defined (HAVE_HDF5)
+bool
+octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
+{
+  hid_t data_hid = -1;
+
+  data_hid = H5Gcreate (loc_id, name, 0);
+  if (data_hid < 0) return false;
+
+  // recursively add each element of the structure to this group
+  Octave_map m = map_value ();
+  Octave_map::iterator i = m.begin ();
+  while (i != m.end ())
+    {
+      Cell val = map.contents (i);
+      octave_value tmp = (map.numel () == 1) ? val(0) : 
+	octave_value (val, true);
+
+      bool retval2 = add_hdf5_data (data_hid, tmp, m.key (i), "", false, 
+				    save_as_floats);
+
+      if (! retval2)
+	break;
+
+      i++;
+    }
+
+  H5Gclose (data_hid);
+  return true;
+}
+
+bool 
+octave_struct::load_hdf5 (hid_t loc_id, const char *name,
+			  bool have_h5giterate_bug)
+{
+  bool retval = false;
+
+  hdf5_callback_data dsub;
+
+  herr_t retval2;
+  Octave_map m;
+  int current_item = 0;
+  while ((retval2 = H5Giterate (loc_id, name, &current_item,
+				hdf5_read_next_data, &dsub)) > 0)
+    {
+      m.assign (dsub.name, dsub.tc);
+
+      if (have_h5giterate_bug)
+	current_item++;  // H5Giterate returned the last index processed
+    }
+
+  if (retval2 >= 0)
+    {
+      map = m;
+      retval = true;
+    }
+  
+  return retval;
+}
+#endif
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-struct.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-struct.h	Tue Jan 06 21:53:34 2004 +0000
@@ -107,6 +107,22 @@
 
   bool print_name_tag (std::ostream& os, const std::string& name) const;
 
+  bool save_ascii (std::ostream& os, bool& infnan_warned,
+		 bool strip_nan_and_inf);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool& save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, 
+		    oct_mach_info::float_format fmt);
+
+#if defined (HAVE_HDF5)
+  bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
+#endif
+
 private:
 
   // The associative array used to manage the structure data.
--- a/src/ov-typeinfo.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov-typeinfo.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -148,6 +148,9 @@
     ? instance->do_register_widening_op (t, t_result, f) : false;
 }
 
+// XXX FIXME XXX -- we should also store all class names and provide a
+// way to list them (calling class with nargin == 0?).
+
 int
 octave_value_typeinfo::do_register_type (const std::string& t_name,
 					 const std::string& c_name,
@@ -339,6 +342,7 @@
       if (nm == types(i))
 	{
 	  retval = vals(i);
+	  retval.make_unique ();
 	  break;
 	}
     }
--- a/src/ov.h	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ov.h	Tue Jan 06 21:53:34 2004 +0000
@@ -33,6 +33,9 @@
 #include <string>
 #include <list>
 
+#if defined (HAVE_HDF5)
+#include <hdf5.h>
+#endif
 
 #include "Range.h"
 #include "idx-vector.h"
@@ -642,6 +645,29 @@
   virtual void print_info (std::ostream& os,
 			   const std::string& prefix = std::string ()) const;
 
+  virtual bool save_ascii (std::ostream& os, bool& infnan_warned,
+			   bool strip_nan_and_inf) 
+    { return rep->save_ascii (os, infnan_warned, strip_nan_and_inf); }
+
+  virtual bool load_ascii (std::istream& is)
+    { return rep->load_ascii (is); }
+
+  virtual bool save_binary (std::ostream& os, bool& save_as_floats)
+    { return rep->save_binary (os, save_as_floats); }
+
+  virtual bool load_binary (std::istream& is, bool swap,
+			    oct_mach_info::float_format fmt)
+    { return rep->load_binary (is, swap, fmt); }
+
+#if defined (HAVE_HDF5)
+  virtual bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
+    { return rep->save_hdf5 (loc_id, name, save_as_floats); }
+
+  virtual bool load_hdf5 (hid_t loc_id, const char *name,
+			  bool have_h5giterate_bug)
+    { return rep->load_hdf5 (loc_id, name, have_h5giterate_bug); }
+#endif
+
 protected:
 
   octave_value (const octave_xvalue&) : rep (0) { }