changeset 6625:5d02dfacfc9e

[project @ 2007-05-16 08:49:47 by dbateman]
author dbateman
date Wed, 16 May 2007 08:49:48 +0000
parents 0d69a50fc5a9
children af16354ea09c
files src/ChangeLog src/load-path.cc src/load-path.h src/load-save.cc src/ls-mat5.cc src/ls-mat5.h src/ov-fcn-handle.cc src/ov-fcn-handle.h src/ov-fcn-inline.cc src/ov-fcn-inline.h
diffstat 10 files changed, 1341 insertions(+), 108 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Tue May 15 20:17:27 2007 +0000
+++ b/src/ChangeLog	Wed May 16 08:49:48 2007 +0000
@@ -1,3 +1,48 @@
+2007-05-16  David Bateman  <dbateman@free.fr>
+
+	* load_pathc.cc (std::string octave_system_path (void)): New
+        function.
+        * load-path.h (std::string octave_system_path (void)): Declare it.
+
+        * load-save.cc (static load_save_format get_file_format
+        (std::istream&, const std::string&)): Add filename argument, and
+        pass it to read_mat5_binary_header. Use new format throughout file.
+        (Fload): Don't allow gzip of matlab v7 files as the files
+        themselves include compression.
+
+        * ls-mat5.cc (arrayclsstype:MAT_FILE_WORKSPACE_CLASS): New class
+        type.
+        (read_mat5_binary_element): Workspaces, don't have dimensions, so
+        don't read them. Implement read of matlab objects, but only use
+        them for inline functions. Implement reading of function and
+        workspace classes.
+        (read_mat5_binary_header): Add filename argument. Read sub-system
+        specific data block given as an offset in bytes 117 to 124.
+        (save_mat5_binary_element): Include saving of inline functions.
+
+        * ls-mat5.h (read_mat5_binary_header): Include filename.
+
+        * ov-fcn-handle.cc (octave_fcn_handle_save_ascii,
+        octave_fcn_handle::load_ascii, octave_fcn_handle::save_binary, 
+        octave_fcn_handle::load_binary, octave_fcn_handle::save_hdf5, 
+        octave_fcn_handle::load_hdf5): Save and reload the local symbol
+        table of the user function associated with anonymous function
+        handles. Save and load the absolute path and the exec_prefix for
+        normal function handles and use then to find equivalent functions
+        between different installations of Octave. Attempt to maintain
+        backward and forward compatibility.
+        (Ffunctions): Additional outputs, including the workspace of
+        anonymous functions, and more compatiable outputs.
+
+        * ov-fcn-handle.h (user_function_value): Expose the user function
+        value of a function handle.
+
+        * ov-fcn-inline.cc (Octave_map octave_fcn_inline::map_value
+        (void) const): Return a structure compatiable with matlab's class
+        implementation of inline functions.
+
+        * ov-fcn-inline.h (map_value): Declare it.
+
 2007-05-14  Bob Weigel  <rweigel@gmu.edu>
 
 	* DLD-FUNCTIONS/svd.cc: Doc fix.
--- a/src/load-path.cc	Tue May 15 20:17:27 2007 +0000
+++ b/src/load-path.cc	Wed May 16 08:49:48 2007 +0000
@@ -50,6 +50,12 @@
 
 static std::string Vsystem_path;
 
+std::string
+octave_system_path (void)
+{
+  return Vsystem_path;
+}
+
 void
 load_path::dir_info::update (void)
 {
--- a/src/load-path.h	Tue May 15 20:17:27 2007 +0000
+++ b/src/load-path.h	Wed May 16 08:49:48 2007 +0000
@@ -341,6 +341,8 @@
 extern void execute_pkg_add (const std::string& dir);
 extern void execute_pkg_del (const std::string& dir);
 
+extern std::string octave_system_path (void);
+
 #endif
 
 /*
--- a/src/load-save.cc	Tue May 15 20:17:27 2007 +0000
+++ b/src/load-save.cc	Wed May 16 08:49:48 2007 +0000
@@ -348,7 +348,7 @@
 #endif
 
 static load_save_format
-get_file_format (std::istream& file)
+get_file_format (std::istream& file, const std::string& filename)
 {
   load_save_format retval = LS_UNKNOWN;
 
@@ -374,7 +374,7 @@
 	  file.clear ();
 	  file.seekg (0, std::ios::beg);
 
-	  err = read_mat5_binary_file_header (file, swap, true);
+	  err = read_mat5_binary_file_header (file, swap, true, filename);
 
 	  if (! err)
   	    {
@@ -415,7 +415,7 @@
       
   if (file)
     {
-      retval = get_file_format (file);
+      retval = get_file_format (file, orig_fname);
       file.close ();
 
 #ifdef HAVE_ZLIB
@@ -426,7 +426,7 @@
 
 	  if (gzfile)
 	    {
-	      retval = get_file_format (gzfile);
+	      retval = get_file_format (gzfile, orig_fname);
 	      gzfile.close ();
 	    }
 	}
@@ -925,7 +925,7 @@
 		  else if (format == LS_MAT5_BINARY 
 			   || format == LS_MAT7_BINARY)
 		    {
-		      if (read_mat5_binary_file_header (file, swap, false) < 0)
+		      if (read_mat5_binary_file_header (file, swap, false, orig_fname) < 0)
 			{
 			  if (file) file.close ();
 			  return retval;
@@ -959,7 +959,7 @@
 		  else if (format == LS_MAT5_BINARY 
 			   || format == LS_MAT7_BINARY)
 		    {
-		      if (read_mat5_binary_file_header (file, swap, false) < 0)
+		      if (read_mat5_binary_file_header (file, swap, false, orig_fname) < 0)
 			{
 			  if (file) file.close ();
 			  return retval;
@@ -1400,6 +1400,10 @@
   
       std::ios::openmode mode = std::ios::out;
 
+      // Matlab v7 files are always compressed
+      if (format == LS_MAT7_BINARY)
+	use_zlib = false;
+
       if (format == LS_BINARY
 #ifdef HAVE_HDF5
 	  || format == LS_HDF5
@@ -1667,6 +1671,10 @@
 
       std::ios::openmode mode = std::ios::out;
 
+      // Matlab v7 files are always compressed
+      if (format == LS_MAT7_BINARY)
+	use_zlib = false;
+
       if (format == LS_BINARY
 #ifdef HAVE_HDF5
 	  || format == LS_HDF5
--- a/src/ls-mat5.cc	Tue May 15 20:17:27 2007 +0000
+++ b/src/ls-mat5.cc	Wed May 16 08:49:48 2007 +0000
@@ -48,15 +48,18 @@
 #include "oct-time.h"
 #include "quit.h"
 #include "str-vec.h"
+#include "file-stat.h"
 
 #include "Cell.h"
 #include "defun.h"
 #include "error.h"
 #include "gripes.h"
 #include "load-save.h"
+#include "load-path.h"
 #include "oct-obj.h"
 #include "oct-map.h"
 #include "ov-cell.h"
+#include "ov-fcn-inline.h"
 #include "pager.h"
 #include "pt-exp.h"
 #include "symtab.h"
@@ -70,12 +73,19 @@
 #include "ls-utils.h"
 #include "ls-mat5.h"
 
+#include "parse.h"
+#include "defaults.h"
+
 #ifdef HAVE_ZLIB
 #include <zlib.h>
 #endif
 
 #define PAD(l) (((l) > 0 && (l) <= 4) ? 4 : (((l)+7)/8)*8)
 
+
+// The subsystem data block
+static octave_value subsys_ov;
+
 // FIXME -- the following enum values should be the same as the
 // mxClassID values in mexproto.h, but it seems they have also changed
 // over time.  What is the correct way to handle this and maintain
@@ -100,7 +110,8 @@
     MAT_FILE_UINT32_CLASS,		// 32 bit unsigned integer
     MAT_FILE_INT64_CLASS,		// 64 bit signed integer
     MAT_FILE_UINT64_CLASS,		// 64 bit unsigned integer
-    MAT_FILE_FUNCTION_CLASS            // Function handle
+    MAT_FILE_FUNCTION_CLASS,            // Function handle
+    MAT_FILE_WORKSPACE_CLASS		// Workspace (undocumented)
   };
 
 // Read COUNT elements of data from IS in the format specified by TYPE,
@@ -397,6 +408,8 @@
 
   oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown;
   int32_t type = 0;
+  std::string classname;
+  bool isclass = false;
   bool imag;
   bool logicalvar;
   enum arrayclasstype arrayclass;
@@ -407,7 +420,7 @@
   int32_t element_length;
   std::streampos pos;
   int16_t number;
-  number = *(int16_t *)"\x00\x01";
+  number = *(reinterpret_cast<const int16_t *>("\x00\x01"));
 
   global = false;
 
@@ -469,6 +482,7 @@
 
   if (type != miMATRIX)
     {
+      pos = is.tellg ();
       error ("load: invalid element type = %d", type);
       goto early_read_error;
     }
@@ -496,27 +510,35 @@
   read_int (is, swap, nzmax);	// max number of non-zero in sparse
   
   // dimensions array subelement
-  {
-    int32_t dim_len;
+  if (arrayclass != MAT_FILE_WORKSPACE_CLASS)
+    {
+      int32_t dim_len;
 
-    if (read_mat5_tag (is, swap, type, dim_len) || type != miINT32)
-      {
-	error ("load: invalid dimensions array subelement");
-	goto early_read_error;
-      }
+      if (read_mat5_tag (is, swap, type, dim_len) || type != miINT32)
+	{
+	  error ("load: invalid dimensions array subelement");
+	  goto early_read_error;
+	}
 
-    int ndims = dim_len / 4;
-    dims.resize (ndims);
-    for (int i = 0; i < ndims; i++)
-      {
-	int32_t n;
-	read_int (is, swap, n);
-	dims(i) = n;
-      }
+      int ndims = dim_len / 4;
+      dims.resize (ndims);
+      for (int i = 0; i < ndims; i++)
+	{
+	  int32_t n;
+	  read_int (is, swap, n);
+	  dims(i) = n;
+	}
 
-    std::streampos tmp_pos = is.tellg ();
-    is.seekg (tmp_pos + static_cast<std::streamoff> (PAD (dim_len) - dim_len));
-  }
+      std::streampos tmp_pos = is.tellg ();
+      is.seekg (tmp_pos + static_cast<std::streamoff> (PAD (dim_len) - dim_len));
+    }
+  else
+    {
+      // Why did mathworks decide to not have dims for a workspace!!!
+      dims.resize(2);
+      dims(0) = 1;
+      dims(1) = 1;
+    }
 
   if (read_mat5_tag (is, swap, type, len) || type != miINT8)
     {
@@ -571,10 +593,6 @@
       }
       break;
 
-    case MAT_FILE_OBJECT_CLASS:
-      warning ("load: objects are not implemented");
-      goto skip_ahead;
-
     case MAT_FILE_SPARSE_CLASS:
 #if SIZEOF_INT != SIZEOF_OCTAVE_IDX_TYPE
       warning ("load: sparse objects are not implemented");
@@ -707,13 +725,310 @@
 	else
 	  tc = sm;
       }
+#endif
       break;
-#endif
 
     case MAT_FILE_FUNCTION_CLASS:
-      warning ("load: function handles are not implemented");
-      goto skip_ahead;
+      {
+	octave_value tc2;
+	std::string nm
+	  = read_mat5_binary_element (is, filename, swap, global, tc2);
+
+	if (! is || error_state)
+	  goto data_read_error;
+
+	// Octave can handle both "/" and "\" as a directry seperator
+	// and so can ignore the seperator field of m0. I think the
+	// sentinel field is also save to ignore.
+	Octave_map m0 = tc2.map_value();
+	Octave_map m1 = m0.contents("function_handle")(0).map_value();
+	std::string ftype = m1.contents("type")(0).string_value();
+	std::string fname = m1.contents("function")(0).string_value();
+	std::string fpath = m1.contents("file")(0).string_value();
+
+	if (ftype == "simple" || ftype == "scopedfunction")
+	  {
+	    if (fpath.length() == 0)
+	      // We have a builtin function
+	      tc = make_fcn_handle (fname);
+	    else
+	      {
+		std::string mroot = 
+		  m0.contents("matlabroot")(0).string_value();
+
+		if ((fpath.length () >= mroot.length ()) &&
+		    fpath.substr(0, mroot.length()) == mroot &&
+		    OCTAVE_EXEC_PREFIX != mroot)
+		  {
+		    // If fpath starts with matlabroot, and matlabroot
+		    // doesn't equal octave_config_info ("exec_prefix")
+		    // then the function points to a version of Octave
+		    // or Matlab other than the running version. In that
+		    // case we replace with the same function in the
+		    // running version of Octave?
+		    
+		    // First check if just replacing matlabroot is enough
+		    std::string str = OCTAVE_EXEC_PREFIX + 
+		      fpath.substr (mroot.length ());		    
+		    file_stat fs (str);
+
+		    if (fs.exists ())
+		      {
+			symbol_record *sr = fbi_sym_tab->lookup (str, true);
+		    
+			if (sr)
+			  {
+			    load_fcn_from_file (sr, false);
+
+			    tc = octave_value (new octave_fcn_handle 
+					       (sr->def (), fname));
+
+			    // The next two lines are needed to force the 
+			    // definition of the function back to the one 
+			    // that is on the user path.
+			    sr = fbi_sym_tab->lookup (fname, true);
+
+			    load_fcn_from_file (sr, false);
+			  }
+		      }
+		    else
+		      {
+			// Next just search for it anywhere in the
+			// system path
+			string_vector names(3);
+			names(0) = fname + ".oct";
+			names(1) = fname + ".mex";
+			names(2) = fname + ".m";
+
+			dir_path p (octave_system_path ());
+
+			str = octave_env::make_absolute 
+			  (p.find_first_of (names), octave_env::getcwd ());
+
+			symbol_record *sr = fbi_sym_tab->lookup (str, true);
+
+			if (sr)
+			  {
+			    load_fcn_from_file (sr, false);
+
+			    tc = octave_value (new octave_fcn_handle 
+					       (sr->def (), fname));
+
+			    // The next two lines are needed to force the 
+			    // definition of the function back to the one 
+			    // that is on the user path.
+			    sr = fbi_sym_tab->lookup (fname, true);
+
+			    load_fcn_from_file (sr, false);
+			  }
+			else
+			  {
+			    warning ("load: can't find the file %s", 
+				     fpath.c_str());
+			    goto skip_ahead;
+			  }
+		      }
+		  }
+		else
+		  {
+		    symbol_record *sr = fbi_sym_tab->lookup (fpath, true);
+
+		    if (sr)
+		      {
+			load_fcn_from_file (sr, false);
+
+			tc = octave_value (new octave_fcn_handle (sr->def (), 
+								  fname));
+
+			sr = fbi_sym_tab->lookup (fname, true);
+
+			load_fcn_from_file (sr, false);
+		      }
+		    else
+		      {
+			warning ("load: can't find the file %s", 
+				 fpath.c_str());
+			goto skip_ahead;
+		      }
+		  }
+	      }
+	  }
+	else if (ftype == "nested")
+	  {
+	    warning ("load: can't load nested function");
+	    goto skip_ahead;
+	  }
+	else if (ftype == "anonymous")
+	  {
+	    Octave_map m2 = m1.contents("workspace")(0).map_value();
+	    uint32NDArray MCOS = m2.contents("MCOS")(0).uint32_array_value();
+	    octave_idx_type off = static_cast<octave_idx_type>(double (MCOS (4)));
+	    m2 = subsys_ov.map_value();
+	    m2 = m2.contents("MCOS")(0).map_value();
+	    tc2 = m2.contents("MCOS")(0).cell_value()(1 + off).cell_value()(1);
+	    m2 = tc2.map_value();
+	    symbol_table *local_sym_tab = 0;
+	    if (m2.length() > 0)
+	      {
+		octave_value tmp;
 
+		local_sym_tab = new symbol_table (((m2.length() + 1) & ~1), 
+						  "LOCAL");
+	      
+		for (Octave_map::iterator p0 = m2.begin() ; 
+		     p0 != m2.end(); p0++)
+		  {
+		    std::string key = m2.key(p0);
+		    octave_value val = m2.contents(p0)(0);
+
+		    symbol_record *sr = local_sym_tab->lookup (key, true);
+
+		    if (sr)
+		      sr->define (val);
+		    else
+		      {
+			error ("load: failed to load anonymous function handle");
+			goto skip_ahead;
+		      }
+                  }
+	      }
+	    
+	    unwind_protect::begin_frame ("anon_mat5_load");
+	    unwind_protect_ptr (curr_sym_tab);
+
+	    if (local_sym_tab)
+	      curr_sym_tab = local_sym_tab;
+
+	    int parse_status;
+	    octave_value anon_fcn_handle = 
+	      eval_string (fname.substr (4), true, parse_status);
+
+	    if (parse_status == 0)
+	      {
+		octave_fcn_handle *fh = 
+		  anon_fcn_handle.fcn_handle_value ();
+		if (fh)
+		  tc = new octave_fcn_handle (fh->fcn_val(), "@<anonymous>");
+		else
+		  {
+		    error ("load: failed to load anonymous function handle");
+		    goto skip_ahead;
+		  }
+	      }
+	    else
+	      {
+		error ("load: failed to load anonymous function handle");
+		goto skip_ahead;
+	      }
+
+	    unwind_protect::run_frame ("anon_mat5_load");
+
+	    if (local_sym_tab)
+	      delete local_sym_tab;	    
+	  }
+	else
+	  {
+	    error ("load: invalid function handle type");
+	    goto skip_ahead;
+	  }
+      }
+      break;
+
+    case MAT_FILE_WORKSPACE_CLASS:
+      {
+	Octave_map m (dim_vector (1, 1));
+	int n_fields = 2;
+	string_vector field (n_fields);
+
+	for (int i = 0; i < n_fields; i++)
+	  {
+	    int32_t fn_type;
+	    int32_t fn_len;
+	    if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT8)
+	      {
+		error ("load: invalid field name subelement");
+		goto data_read_error;
+	      }
+
+	    OCTAVE_LOCAL_BUFFER (char, elname, fn_len + 1);
+
+	    std::streampos tmp_pos = is.tellg ();
+
+	    if (fn_len)
+	      {
+		if (! is.read (elname, fn_len))
+		  goto data_read_error;
+
+		is.seekg (tmp_pos + 
+			  static_cast<std::streamoff> (PAD (fn_len)));
+	      }
+
+	    elname[fn_len] = '\0';
+
+	    field(i) = elname;
+	  }
+
+	std::vector<Cell> elt (n_fields);
+
+	for (octave_idx_type i = 0; i < n_fields; i++)
+	  elt[i] = Cell (dims);
+
+	octave_idx_type n = dims.numel ();
+
+	// fields subelements
+	for (octave_idx_type j = 0; j < n; j++)
+	  {
+	    for (octave_idx_type i = 0; i < n_fields; i++)
+	      {
+		if (field(i) == "MCOS")
+		  {
+		    octave_value fieldtc;
+		    read_mat5_binary_element (is, filename, swap, global,
+					      fieldtc); 
+		    if (! is || error_state)
+		      goto data_read_error;
+
+		    elt[i](j) = fieldtc;
+		  }
+		else
+		  elt[i](j) = octave_value ();
+	      }
+	  }
+
+	for (octave_idx_type i = 0; i < n_fields; i++)
+	  m.assign (field (i), elt[i]);
+	tc = m;
+      }
+      break;
+
+    case MAT_FILE_OBJECT_CLASS:
+      {
+	isclass = true;
+
+	if (read_mat5_tag (is, swap, type, len) || type != miINT8)
+	  {
+	    error ("load: invalid class name");
+	    goto skip_ahead;
+	  }
+
+	{
+	  OCTAVE_LOCAL_BUFFER (char, name, len+1);
+
+	  std::streampos tmp_pos = is.tellg ();
+
+	  if (len)
+	    {
+	      if (! is.read (name, len ))
+		goto data_read_error;
+	
+	      is.seekg (tmp_pos + static_cast<std::streamoff> (PAD (len)));
+	    }
+
+	  name[len] = '\0';
+	  classname = name;
+	}
+      }
+      // Fall-through
     case MAT_FILE_STRUCT_CLASS:
       {
 	Octave_map m (dim_vector (1, 1));
@@ -784,7 +1099,24 @@
 	      }
 	  }
 
-	tc = m;
+	if (isclass)
+	  {
+	    if (classname == "inline")
+	      {
+		// inline is not an object in Octave but rather an
+		// overload of a function handle. Special case.
+		tc =  
+		  new octave_fcn_inline (m.contents("expr")(0).string_value(),
+					 m.contents("args")(0).string_value());
+	      }
+	    else
+	      {
+		warning ("load: objects are not implemented");
+		goto skip_ahead;
+	      }
+	  }
+	else
+	  tc = m;
       }
       break;
 
@@ -975,9 +1307,14 @@
 }
 
 int
-read_mat5_binary_file_header (std::istream& is, bool& swap, bool quiet)
+read_mat5_binary_file_header (std::istream& is, bool& swap, bool quiet, 
+			      const std::string& filename)
 {
   int16_t version=0, magic=0;
+  uint64_t subsys_offset;
+
+  is.seekg (116, std::ios::beg);
+  is.read (reinterpret_cast<char *> (&subsys_offset), 8);
 
   is.seekg (124, std::ios::beg);
   is.read (reinterpret_cast<char *> (&version), 2);
@@ -1001,6 +1338,48 @@
     warning ("load: found version %d binary MAT file, "
 	     "but only prepared for version 1", version);
 
+  if (swap)
+    swap_bytes<8> (&subsys_offset, 1);
+
+  if (subsys_offset != 0x2020202020202020ULL && subsys_offset != 0ULL)
+    {
+      // Read the subsystem data block
+      is.seekg (subsys_offset, std::ios::beg);
+
+      octave_value tc;
+      bool global;
+      read_mat5_binary_element (is, filename, swap, global, tc);
+
+      if (!is || error_state)
+	return -1;
+
+      if (tc.is_uint8_type ())
+	{
+	  const uint8NDArray itmp = tc.uint8_array_value();
+	  octave_idx_type ilen = itmp.nelem ();
+
+	  // Why should I have to initialize outbuf as just overwrite
+	  std::string outbuf (ilen - 7, ' ');
+
+	  // FIXME -- find a way to avoid casting away const here
+	  char *ctmp = const_cast<char *> (outbuf.c_str ());
+	  for (octave_idx_type j = 8; j < ilen; j++)
+	    ctmp [j - 8] = itmp (j);
+
+	  std::istringstream fh_ws (outbuf);
+
+	  read_mat5_binary_element (fh_ws, filename, swap, global, subsys_ov);
+
+	  if (error_state)
+	    return -1;
+	}
+      else
+	return -1;
+
+      // Reposition to just after the header
+      is.seekg (128, std::ios::beg);
+    }
+
   return 0;
 }
 
@@ -1415,12 +1794,16 @@
       ret += save_mat5_array_length (m.fortran_vec (), m.nelem (),
 				     save_as_floats);
     }
-  else if (tc.is_map ()) 
+  else if (tc.is_map () || tc.is_inline_function ()) 
     {
       int fieldcnt = 0;
       const Octave_map m = tc.map_value ();
       int nel = m.numel ();
 
+      if (tc.is_inline_function ())
+	// length of "inline" is 6
+	ret += 8 + PAD (6 > max_namelen ? max_namelen : 6);
+
       for (Octave_map::const_iterator i = m.begin (); i != m.end (); i++)
 	fieldcnt++;
 
@@ -1559,6 +1942,8 @@
     flags |= MAT_FILE_STRUCT_CLASS;
   else if (tc.is_cell ())
     flags |= MAT_FILE_CELL_CLASS;
+  else if (tc.is_inline_function ())
+    flags |= MAT_FILE_OBJECT_CLASS;
   else
     {
       gripe_wrong_type_arg ("save", tc, false);
@@ -1746,12 +2131,28 @@
       write_mat5_array (os, ::real (m_cmplx), save_as_floats);
       write_mat5_array (os, ::imag (m_cmplx), save_as_floats);
     }
-  else if (tc.is_map ()) 
+  else if (tc.is_map () || tc.is_inline_function()) 
     {
+      const Octave_map m = tc.map_value ();
+      if (tc.is_inline_function ())
+	{
+	  std::string classname = "inline";
+	  int namelen = classname.length ();
+
+	  if (namelen > max_namelen)
+	    namelen = max_namelen; // only 31 or 63 char names permitted
+
+	  int paddedlength = PAD (namelen);
+
+	  write_mat5_tag (os, miINT8, namelen);
+	  OCTAVE_LOCAL_BUFFER (char, paddedname, paddedlength);
+	  memset (paddedname, 0, paddedlength);
+	  strncpy (paddedname, classname.c_str (), namelen);
+	  os.write (paddedname, paddedlength);
+	}
+
       // an Octave structure */
       // recursively write each element of the structure
-      const Octave_map m = tc.map_value ();
-
       {
 	char buf[64];
 	int32_t maxfieldnamelength = max_namelen + 1;
--- a/src/ls-mat5.h	Tue May 15 20:17:27 2007 +0000
+++ b/src/ls-mat5.h	Wed May 16 08:49:48 2007 +0000
@@ -48,7 +48,8 @@
 
 extern int
 read_mat5_binary_file_header (std::istream& is, bool& swap,
-			      bool quiet = false);
+			      bool quiet = false,
+			      const std::string& filename = std::string());
 extern std::string
 read_mat5_binary_element (std::istream& is, const std::string& filename,
 			  bool swap, bool& global, octave_value& tc);
--- a/src/ov-fcn-handle.cc	Tue May 15 20:17:27 2007 +0000
+++ b/src/ov-fcn-handle.cc	Wed May 16 08:49:48 2007 +0000
@@ -46,9 +46,15 @@
 #include "pt-assign.h"
 #include "variables.h"
 #include "parse.h"
+#include "unwind-prot.h"
+#include "defaults.h"
+#include "file-stat.h"
+#include "load-path.h"
+#include "oct-env.h"
 
 #include "byte-swap.h"
 #include "ls-oct-ascii.h"
+#include "ls-oct-binary.h"
 #include "ls-hdf5.h"
 #include "ls-utils.h"
 
@@ -144,14 +150,159 @@
 }
 
 bool
-octave_fcn_handle::save_ascii (std::ostream& os, bool&)
+octave_fcn_handle::set_fcn (const std::string &octaveroot, 
+			    const std::string& fpath)
 {
-  os << nm << "\n";
+  bool success = true;
+
+  if (octaveroot.length () != 0 && 
+      fpath.length () >= octaveroot.length () &&
+      fpath.substr (0, octaveroot.length ()) == octaveroot &&
+      OCTAVE_EXEC_PREFIX != octaveroot)
+    {
+      // First check if just replacing matlabroot is enough
+      std::string str = OCTAVE_EXEC_PREFIX + 
+	fpath.substr (octaveroot.length ());		    
+      file_stat fs (str);
+
+      if (fs.exists ())
+	{
+	  symbol_record *sr = fbi_sym_tab->lookup (str, true);
+		    
+	  if (sr)
+	    {
+	      load_fcn_from_file (sr, false);
+
+	      fcn = octave_value (new octave_fcn_handle (sr->def (), nm));
+
+	      // The next two lines are needed to force the 
+	      // definition of the function back to the one 
+	      // that is on the user path.
+	      sr = fbi_sym_tab->lookup (nm, true);
+
+	      load_fcn_from_file (sr, false);
+
+	    }
+	  else
+	    {
+	      error ("function handle points to non-existent function");
+	      success = false;
+	    }
+	}
+      else
+	{
+	  // Next just search for it anywhere in the system path
+	  string_vector names(3);
+	  names(0) = nm + ".oct";
+	  names(1) = nm + ".mex";
+	  names(2) = nm + ".m";
+
+	  dir_path p (octave_system_path ());
+
+	  str = octave_env::make_absolute 
+	    (p.find_first_of (names), octave_env::getcwd ());
+
+	  symbol_record *sr = fbi_sym_tab->lookup (str, true);
+
+	  if (sr)
+	    {
+	      load_fcn_from_file (sr, false);
 
+	      fcn = octave_value (new octave_fcn_handle (sr->def (), nm));
+
+	      // The next two lines are needed to force the 
+	      // definition of the function back to the one 
+	      // that is on the user path.
+	      sr = fbi_sym_tab->lookup (nm, true);
+
+	      load_fcn_from_file (sr, false);
+	    }
+	  else
+	    {
+	      error ("function handle points to non-existent function");
+	      success = false;
+	    }
+	}
+    }
+  else
+    {
+      if (fpath.length () > 0)
+	{
+	  symbol_record *sr = fbi_sym_tab->lookup (fpath, true);
+
+	  if (sr)
+	    {
+	      load_fcn_from_file (sr, false);
+
+	      fcn = octave_value (new octave_fcn_handle (sr->def (), nm));
+
+	      sr = fbi_sym_tab->lookup (nm, true);
+
+	      load_fcn_from_file (sr, false);
+	    }
+	  else
+	    {
+	      error ("function handle points to non-existent function");
+	      success = false;
+	    }
+	}
+      else
+	{
+	  fcn = lookup_function (nm);
+	  if (! fcn.is_function ())
+	    {
+	      error ("function handle points to non-existent function");
+	      success = false;
+	    }
+	}
+    }
+
+  return success;
+}
+
+bool
+octave_fcn_handle::save_ascii (std::ostream& os, bool& infnan_warned)
+{
   if (nm == "@<anonymous>")
     {
+      os << nm << "\n";
+
       print_raw (os, true);
       os << "\n";
+
+      if (fcn.is_undefined())
+	return false;
+
+      octave_user_function *f = fcn.user_function_value ();
+
+      Array<symbol_record *> vars = f->sym_tab()->symbol_list();
+      octave_idx_type varlen = vars.length();
+
+      // Exclude undefined values like __retval__
+      for (octave_idx_type i = 0; i < vars.length(); i++)
+	{
+	  if (! vars(i)->is_defined ())
+	    varlen--;
+	}
+
+      if (varlen > 0)
+	{
+	  os << "# length: " << varlen << "\n";
+
+	  for (octave_idx_type i = 0; i < vars.length(); i++)
+	    {
+	      if (vars(i)->is_defined () &&
+		  ! save_ascii_data (os, vars(i)->def(), vars(i)->name(), 
+				     infnan_warned, false, 0))
+		return os;
+	    }
+	}
+    }
+  else
+    {
+      os << "# octaveroot: " << OCTAVE_EXEC_PREFIX << "\n";
+      os << "# path: " << user_function_value ()-> fcn_file_name () << "\n";
+      os << nm << "\n";
     }
 
   return true;
@@ -160,10 +311,28 @@
 bool
 octave_fcn_handle::load_ascii (std::istream& is)
 {
+  bool success = true;
+
+  std::streampos pos = is.tellg ();
+  std::string octaveroot = extract_keyword (is, "octaveroot", true);
+  if (octaveroot.length() == 0)
+    {
+      is.seekg (pos);
+      is.clear ();
+    }
+  pos = is.tellg ();
+  std::string fpath = extract_keyword (is, "path", true);
+  if (fpath.length() == 0)
+    {
+      is.seekg (pos);
+      is.clear ();
+    }
+
   is >> nm;
 
   if (nm == "@<anonymous>")
     {
+      octave_idx_type len = 0;
       char c;
       std::ostringstream buf;
 
@@ -187,56 +356,186 @@
 	    }
 	}
 
-      int parse_status;
-      octave_value anon_fcn_handle = eval_string (buf.str (), true,
-						  parse_status);
+      pos = is.tellg ();
+      symbol_table *local_sym_tab = 0;
 
-      if (parse_status == 0)
+      if (extract_keyword (is, "length", len, true) && len >= 0)
 	{
-	  octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
-	  if (fh)
-	    fcn = fh->fcn;
-	  else
-	    return false;
+	  if (len > 0)
+	    {
+	      octave_idx_type nlen = len;
+	      if (nlen % 2)
+		nlen++;
+	      
+	      local_sym_tab = new symbol_table (((nlen + 1) & ~1) , "LOCAL");
+	      
+	      for (octave_idx_type i = 0; i < len; i++)
+		{
+		  octave_value t2;
+		  bool dummy;
+
+		  std::string name
+		    = read_ascii_data (is, std::string (), dummy, t2, i);
+
+		  if (!is)
+		    {
+		      error ("load: failed to load anonymous function handle");
+		      break;
+		    }
+
+		  symbol_record *sr = local_sym_tab->lookup (name, true);
+
+		  if (sr)
+		    sr->define (t2);
+		  else
+		    {
+		      error ("load: failed to load anonymous function handle");
+		      success = false;
+		      break;
+		    }
+		}
+	    }
 	}
       else
-	return false;
+	{
+	  is.seekg (pos);
+	  is.clear ();
+	}
+
+      if (is && success)
+	{
+	  unwind_protect::begin_frame ("anon_ascii_load");
+	  unwind_protect_ptr (curr_sym_tab);
+
+	  if (local_sym_tab)
+	    curr_sym_tab = local_sym_tab;
+
+	  int parse_status;
+	  octave_value anon_fcn_handle = 
+	    eval_string (buf.str (), true, parse_status);
+
+	  if (parse_status == 0)
+	    {
+	      octave_fcn_handle *fh = 
+		anon_fcn_handle.fcn_handle_value ();
+	      if (fh)
+		fcn = fh->fcn;
+	      else
+		success = false;
+	    }
+	  else
+	    success = false;
+
+	  unwind_protect::run_frame ("anon_ascii_load");
+	}
+      else
+	success = false;
+
+      if (local_sym_tab)
+	delete local_sym_tab;
     }
   else
-    {
-      fcn = lookup_function (nm);
-      if (! fcn.is_function ())
-	{
-	  error ("function handle points to non-existent function");
-	  return false;
-	}
-    }
+    success = set_fcn (octaveroot, fpath);
 
-  return true;
+  return success;
 }
 
+/* 
+
+%!test
+%! a = 2;
+%! f = @(x) a + x;
+%! g = @(x) 2 * x;
+%! h = @log2;
+%! f2 = f;
+%! g2 = g;
+%! h2 = h;
+%! nm = tmpnam();
+%! unwind_protect
+%!   save ("-text", nm, "f2", "g2", "h2");
+%!   clear f2 g2 h2
+%!   load (nm);
+%!   assert (f(2),f2(2));
+%!   assert (g(2),g2(2));
+%!   assert (g(3),g2(3));
+%!   unlink (nm);
+%!   save ("-text", nm, "f2", "g2", "h2");
+%! unwind_protect_cleanup
+%!   unlink (nm);
+%! end_unwind_protect
+
+*/
+
 bool
-octave_fcn_handle::save_binary (std::ostream& os, bool&)
+octave_fcn_handle::save_binary (std::ostream& os, bool& save_as_floats)
 {
-  int32_t tmp = nm.length ();
-  os.write (reinterpret_cast<char *> (&tmp), 4);
-  os.write (nm.c_str (), nm.length ());
   if (nm == "@<anonymous>")
     {
+      std::ostringstream nmbuf;
+
+      if (fcn.is_undefined())
+	return false;
+
+      octave_user_function *f = fcn.user_function_value ();
+
+      Array<symbol_record *> vars = f->sym_tab()->symbol_list();
+      octave_idx_type varlen = vars.length();
+
+      // Exclude undefined values like __retval__
+      for (octave_idx_type i = 0; i < vars.length(); i++)
+	{
+	  if (! vars(i)->is_defined ())
+	    varlen--;
+	}
+
+      if (varlen > 0)
+	nmbuf << nm << " " << varlen;
+      else
+	nmbuf << nm;
+
+      std::string buf_str = nmbuf.str();
+      int32_t tmp = buf_str.length ();
+      os.write (reinterpret_cast<char *> (&tmp), 4);
+      os.write (buf_str.c_str (), buf_str.length ());
+
       std::ostringstream buf;
       print_raw (buf, true);
       std::string stmp = buf.str ();
       tmp = stmp.length ();
       os.write (reinterpret_cast<char *> (&tmp), 4);
       os.write (stmp.c_str (), stmp.length ());
+
+      if (varlen > 0)
+	{
+	  for (octave_idx_type i = 0; i < vars.length(); i++)
+	    {
+	      if (vars(i)->is_defined () &&
+		  ! save_binary_data (os, vars(i)->def(), vars(i)->name(), 
+				      "", 0, save_as_floats))
+		return os;
+	    }
+	}
+    }
+  else
+    {
+      std::ostringstream nmbuf;
+
+      nmbuf << nm << "\n" << OCTAVE_EXEC_PREFIX << "\n" 
+	    << user_function_value ()-> fcn_file_name () ;
+
+      std::string buf_str = nmbuf.str ();
+      int32_t tmp = buf_str.length ();
+      os.write (reinterpret_cast<char *> (&tmp), 4);
+      os.write (buf_str.c_str (), buf_str.length ());
     }
   return true;
 }
 
 bool
 octave_fcn_handle::load_binary (std::istream& is, bool swap,
-				oct_mach_info::float_format)
+				oct_mach_info::float_format fmt)
 {
+  bool success = true;
   int32_t tmp;
   if (! is.read (reinterpret_cast<char *> (&tmp), 4))
     return false;
@@ -250,8 +549,17 @@
   if (! is)
     return false;
 
-  if (nm == "@<anonymous>")
+  if (nm.length() >= 12 && nm.substr (0, 12) == "@<anonymous>")
     {
+      octave_idx_type len = 0;
+
+      if (nm.length() > 12)
+	{
+	  std::istringstream nm_is (nm.substr(12));
+	  nm_is >> len;
+	  nm = nm.substr(0,12);
+	}
+
       if (! is.read (reinterpret_cast<char *> (&tmp), 4))
 	return false;
       if (swap)
@@ -260,36 +568,126 @@
       OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
       is.read (ctmp2, tmp);
 
-      int parse_status;
-      octave_value anon_fcn_handle = eval_string (ctmp2, true, parse_status);
-
-      if (parse_status == 0)
+      symbol_table *local_sym_tab = 0;
+      if (len > 0)
 	{
-	  octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
-	  if (fh)
-	    fcn = fh->fcn;
+	  octave_idx_type nlen = len;
+	  if (nlen % 2)
+	    nlen++;
+	      
+	  local_sym_tab = new symbol_table (nlen, "LOCAL");
+	      
+	  for (octave_idx_type i = 0; i < len; i++)
+	    {
+	      octave_value t2;
+	      bool dummy;
+	      std::string doc;
+
+	      std::string name = 
+		read_binary_data (is, swap, fmt, std::string (), 
+				  dummy, t2, doc);
+
+	      if (!is)
+		{
+		  error ("load: failed to load anonymous function handle");
+		  break;
+		}
+
+	      symbol_record *sr = local_sym_tab->lookup (name, true);
+
+	      if (sr)
+		{
+		  sr->define (t2);
+		  sr->document (doc);
+		}
+	      else
+		{
+		  error ("load: failed to load anonymous function handle");
+		  success = false;
+		  break;
+		}
+	    }
+	}
+
+      if (is && success)
+	{
+	  unwind_protect::begin_frame ("anon_binary_load");
+	  unwind_protect_ptr (curr_sym_tab);
+
+	  if (local_sym_tab)
+	    curr_sym_tab = local_sym_tab;
+
+	  int parse_status;
+	  octave_value anon_fcn_handle = 
+	    eval_string (ctmp2, true, parse_status);
+
+	  if (parse_status == 0)
+	    {
+	      octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
+	      if (fh)
+		fcn = fh->fcn;
+	      else
+		success = false;
+	    }
 	  else
-	    return false;
+	    success = false;
+
+	  unwind_protect::run_frame ("anon_binary_load");
 	}
-      else
-	return false;
+
+      if (local_sym_tab)
+	delete local_sym_tab;
     }
   else
     {
-      fcn = lookup_function (nm);
-      if (! fcn.is_function ())
+      std::string octaveroot;
+      std::string fpath;
+
+      if (nm.find_first_of ("\n") != NPOS)
 	{
-	  error ("function handle points to non-existent function");
-	  return false;
+	  size_t pos1 = nm.find_first_of ("\n");
+	  size_t pos2 = nm.find_first_of ("\n", pos1 + 1);
+	  octaveroot = nm.substr (pos1 + 1, pos2 - pos1 - 1);
+	  fpath = nm.substr (pos2 + 1);
+	  nm = nm.substr (0, pos1);
 	}
-    }
-  return true;
+
+      success = set_fcn (octaveroot, fpath);
+     }
+ 
+ return success;
 }
 
+/* 
+
+%!test
+%! a = 2;
+%! f = @(x) a + x;
+%! g = @(x) 2 * x;
+%! h = @log2;
+%! f2 = f;
+%! g2 = g;
+%! h2 = h;
+%! nm = tmpnam();
+%! unwind_protect
+%!   save ("-binary", nm, "f2", "g2", "h2");
+%!   clear f2 g2 h2
+%!   load (nm);
+%!   assert (f(2),f2(2));
+%!   assert (g(2),g2(2));
+%!   assert (g(3),g2(3));
+%!   unlink (nm);
+%!   save ("-binary", nm, "f2", "g2", "h2");
+%! unwind_protect_cleanup
+%!   unlink (nm);
+%! end_unwind_protect
+
+*/
+
 #if defined (HAVE_HDF5)
 bool
 octave_fcn_handle::save_hdf5 (hid_t loc_id, const char *name,
-			      bool /* save_as_floats */)
+			      bool save_as_floats)
 {
   hid_t group_hid = -1;
   group_hid = H5Gcreate (loc_id, name, 0);
@@ -355,6 +753,117 @@
 	}
 
       H5Dclose (data_hid);
+
+      octave_user_function *f = fcn.user_function_value ();
+      Array<symbol_record *> vars = f->sym_tab()->symbol_list();
+      octave_idx_type varlen = vars.length();
+
+      // Exclude undefined values like __retval__
+      for (octave_idx_type i = 0; i < vars.length(); i++)
+	{
+	  if (! vars(i)->is_defined ())
+	    varlen--;
+	}
+
+      if (varlen > 0)
+	{
+	  hid_t as_id = H5Screate (H5S_SCALAR);
+
+	  if (as_id >= 0)
+	    {
+	      hid_t a_id = H5Acreate (group_hid, "SYMBOL_TABLE",
+				      H5T_NATIVE_IDX, as_id, H5P_DEFAULT);
+
+	      if (a_id >= 0)
+		{
+		  retval = (H5Awrite (a_id, H5T_NATIVE_IDX, &varlen) >= 0);
+
+		  H5Aclose (a_id);
+		}
+	      else
+		retval = false;
+
+	      H5Sclose (as_id);
+	    }
+	  else
+	    retval = false;
+
+	  data_hid = H5Gcreate (group_hid, "symbol table", 0);
+	  if (data_hid < 0) 
+	    {
+	      H5Sclose (space_hid);
+	      H5Tclose (type_hid);
+	      H5Gclose (group_hid);
+	      return false;
+	    }
+
+	  for (octave_idx_type i = 0; i < vars.length(); i++)
+	    {
+	      if (vars(i)->is_defined () &&
+		  ! add_hdf5_data (data_hid, vars(i)->def(), vars(i)->name(), 
+				   "", false, save_as_floats))
+		break;
+	    }
+	  H5Gclose (data_hid);
+	}
+    }
+  else
+    {
+      std::string octaveroot = OCTAVE_EXEC_PREFIX;
+      std::string fpath = user_function_value ()-> fcn_file_name ();
+
+      H5Sclose (space_hid);
+      hdims[0] = 1;
+      hdims[1] = octaveroot.length ();
+      space_hid = H5Screate_simple (0 , hdims, 0);
+      if (space_hid < 0)
+	{
+	  H5Tclose (type_hid);
+	  H5Gclose (group_hid);
+	  return false;
+	}
+
+      H5Tclose (type_hid);
+      type_hid = H5Tcopy (H5T_C_S1);
+      H5Tset_size (type_hid, octaveroot.length () + 1);
+
+      hid_t a_id = H5Acreate (group_hid, "OCTAVEROOT",
+			      type_hid, space_hid, H5P_DEFAULT);
+
+      if (a_id >= 0)
+	{
+	  retval = (H5Awrite (a_id, type_hid, octaveroot.c_str ()) >= 0);
+
+	  H5Aclose (a_id);
+	}
+      else
+	retval = false;
+
+      H5Sclose (space_hid);
+      hdims[0] = 1;
+      hdims[1] = fpath.length ();
+      space_hid = H5Screate_simple (0 , hdims, 0);
+      if (space_hid < 0)
+	{
+	  H5Tclose (type_hid);
+	  H5Gclose (group_hid);
+	  return false;
+	}
+
+      H5Tclose (type_hid);
+      type_hid = H5Tcopy (H5T_C_S1);
+      H5Tset_size (type_hid, fpath.length () + 1);
+
+      a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid, H5P_DEFAULT);
+
+      if (a_id >= 0)
+	{
+	  retval = (H5Awrite (a_id, type_hid, fpath.c_str ()) >= 0);
+
+	  H5Aclose (a_id);
+	}
+      else
+	retval = false;
     }
 
   H5Sclose (space_hid);
@@ -366,11 +875,12 @@
 
 bool
 octave_fcn_handle::load_hdf5 (hid_t loc_id, const char *name,
-			      bool /* have_h5giterate_bug */)
+			      bool have_h5giterate_bug)
 {
   hid_t group_hid, data_hid, space_hid, type_hid, type_class_hid, st_id;
   hsize_t rank;
   int slen;
+  bool success = true;
 
   group_hid = H5Gopen (loc_id, name);
   if (group_hid < 0 ) return false;
@@ -490,34 +1000,220 @@
 	  return false;
 	}
       H5Dclose (data_hid);
-      H5Tclose (st_id);
+
+      symbol_table *local_sym_tab = 0;
+      octave_idx_type len = 0;
+
+      // we have to pull some shenanigans here to make sure
+      // HDF5 doesn't print out all sorts of error messages if we
+      // call H5Aopen for a non-existing attribute
+
+      H5E_auto_t err_func;
+      void *err_func_data;
 
-      int parse_status;
-      octave_value anon_fcn_handle = eval_string (fcn_tmp, true, parse_status);
+      // turn off error reporting temporarily, but save the error
+      // reporting function:
+      H5Eget_auto (&err_func, &err_func_data);
+      H5Eset_auto (0, 0);
+
+      hid_t attr_id = H5Aopen_name (group_hid, "SYMBOL_TABLE");
 
-      if (parse_status == 0)
+      if (attr_id >= 0)
+	{
+	  if (H5Aread (attr_id, H5T_NATIVE_IDX, &len) < 0)
+	    success = false;
+
+	  H5Aclose (attr_id);
+	}
+
+      // restore error reporting:
+      H5Eset_auto (err_func, err_func_data);
+
+      if (len > 0 && success)
 	{
-	  octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
-	  if (fh)
-	    fcn = fh->fcn;
+	  octave_idx_type nlen = len;
+	  if (nlen % 2)
+	    nlen++;
+	      
+	  local_sym_tab = new symbol_table (nlen, "LOCAL");
+	      
+#ifdef HAVE_H5GGET_NUM_OBJS
+	  hsize_t num_obj = 0;
+	  data_hid = H5Gopen (group_hid, "symbol table"); 
+	  H5Gget_num_objs (data_hid, &num_obj);
+	  H5Gclose (data_hid);
+
+	  if (num_obj != static_cast<hsize_t>(len))
+	    {
+	      error ("load: failed to load anonymous function handle");
+	      success = false;
+	    }
+#endif
+
+	  if (! error_state)
+	    {
+	      hdf5_callback_data dsub;
+	      int current_item = 0;
+	      for (octave_idx_type i = 0; i < len; i++)
+		{
+		  if (H5Giterate (group_hid, "symbol table", &current_item,
+				  hdf5_read_next_data, &dsub) <= 0)
+		    {
+		      error ("load: failed to load anonymous function handle");
+		      success = false;
+		      break;
+		    }
+
+		  if (have_h5giterate_bug)
+		    current_item++;  // H5Giterate returns last index processed
+
+		  symbol_record *sr = local_sym_tab->lookup (dsub.name, true);
+
+		  if (sr)
+		    sr->define (dsub.tc);
+		  else
+		    {
+		      error ("load: failed to load anonymous function handle");
+		      success = false;
+		      break;
+		    }
+		}
+	    }
+	}
+
+      H5Tclose (st_id);
+      H5Gclose (group_hid);
+
+      if (success)
+	{
+	  unwind_protect::begin_frame ("anon_hdf5_load");
+	  unwind_protect_ptr (curr_sym_tab);
+
+	  if (local_sym_tab)
+	    curr_sym_tab = local_sym_tab;
+
+	  int parse_status;
+	  octave_value anon_fcn_handle = 
+	    eval_string (fcn_tmp, true, parse_status);
+
+	  if (parse_status == 0)
+	    {
+	      octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
+	      if (fh)
+		fcn = fh->fcn;
+	      else
+		success = false;
+	    }
 	  else
-	    return false;
+	    success = false;
+
+	  unwind_protect::run_frame ("anon_hdf5_load");
 	}
-      else
-	return false;
+
+      if (local_sym_tab)
+	delete local_sym_tab;
     }
   else
     {
-      fcn = lookup_function (nm);
-      if (! fcn.is_function ())
+      std::string octaveroot;
+      std::string fpath;
+
+      // we have to pull some shenanigans here to make sure
+      // HDF5 doesn't print out all sorts of error messages if we
+      // call H5Aopen for a non-existing attribute
+
+      H5E_auto_t err_func;
+      void *err_func_data;
+
+      // turn off error reporting temporarily, but save the error
+      // reporting function:
+      H5Eget_auto (&err_func, &err_func_data);
+      H5Eset_auto (0, 0);
+
+      hid_t attr_id = H5Aopen_name (group_hid, "OCTAVEROOT");
+      if (attr_id >= 0)
 	{
-	  error ("function handle points to non-existent function");
-	  return false;
+	  type_hid = H5Aget_type (attr_id);
+	  type_class_hid = H5Tget_class (type_hid);
+
+	  if (type_class_hid != H5T_STRING)
+	    success = false;
+	  else
+	    {
+	      slen = H5Tget_size (type_hid);
+	      st_id = H5Tcopy (H5T_C_S1);
+	      H5Tset_size (st_id, slen);
+	      OCTAVE_LOCAL_BUFFER (char, root_tmp, slen);
+
+	      if (H5Aread (attr_id, st_id, root_tmp) < 0)
+		success = false;
+	      else
+		octaveroot = root_tmp;
+	    }
+
+	  H5Aclose (attr_id);
 	}
+
+      attr_id = H5Aopen_name (group_hid, "FILE");
+      if (attr_id >= 0)
+	{
+	  type_hid = H5Aget_type (attr_id);
+	  type_class_hid = H5Tget_class (type_hid);
+
+	  if (type_class_hid != H5T_STRING)
+	    success = false;
+	  else
+	    {
+	      slen = H5Tget_size (type_hid);
+	      st_id = H5Tcopy (H5T_C_S1);
+	      H5Tset_size (st_id, slen);
+	      OCTAVE_LOCAL_BUFFER (char, path_tmp, slen);
+
+	      if (H5Aread (attr_id, st_id, path_tmp) < 0)
+		success = false;
+	      else
+		fpath = path_tmp;
+	    }
+
+	  H5Aclose (attr_id);
+	}
+
+      // restore error reporting:
+      H5Eset_auto (err_func, err_func_data);
+
+      success = (success ? set_fcn (octaveroot, fpath) : success);
     }
 
-  return true;
+  return success;
 }
+
+/* 
+
+%!test
+%! if (!isempty(findstr(octave_config_info ("DEFS"),"HAVE_HDF5")))
+%!   a = 2;
+%!   f = @(x) a + x;
+%!   g = @(x) 2 * x;
+%!   h = @log2;
+%!   f2 = f;
+%!   g2 = g;
+%!   h2 = h;
+%!   nm = tmpnam();
+%!   unwind_protect
+%!     save ("-hdf5", nm, "f2", "g2", "h2");
+%!     clear f2 g2 h2
+%!     load (nm);
+%!     assert (f(2),f2(2));
+%!     assert (g(2),g2(2));
+%!     assert (g(3),g2(3));
+%!     unlink (nm);
+%!     save ("-hdf5", nm, "f2", "g2", "h2");
+%!   unwind_protect_cleanup
+%!     unlink (nm);
+%!   end_unwind_protect
+%! endif
+
+*/
 #endif
 
 void
@@ -657,23 +1353,70 @@
 
 	      std::string fh_nm = fh->fcn_name ();
 
-	      m.assign ("function", fh_nm);
+	      if (fh_nm == "@<anonymous>")
+		{
+		  std::ostringstream buf;
+		  fh->print_raw (buf);
+		  m.assign ("function", buf.str ());
+
+		  m.assign ("type", "anonymous");
+		}
+	      else
+		{
+		  m.assign ("function", fh_nm);
 
-	      if (fcn->is_nested_function ())
-		m.assign ("type", "subfunction");
-	      else
-		m.assign ("type", "simple");
+		  if (fcn->is_nested_function ())
+		    {
+		      m.assign ("type", "subfunction");
+		      Cell parentage (dim_vector (1, 2));
+		      parentage.elem(0) = fh_nm;
+		      parentage.elem(1) = fcn->parent_fcn_name ();
+		      m.assign ("parentage", parentage); 
+		    }
+		  else
+		    m.assign ("type", "simple");
+		}
 
 	      std::string nm = fcn->fcn_file_name ();
 
 	      if (nm.empty ())
 		{
 		  if (fh_nm == "@<anonymous>")
-		    m.assign ("file", "none");
+		    {
+		      m.assign ("file", "");
+
+		      octave_user_function *fu = fh->user_function_value ();
+		      Array <symbol_record *> vars = 
+			fu->sym_tab ()->symbol_list ();
+		      octave_idx_type varlen = vars.length ();
+
+		      // Exclude undefined values like __retval__
+		      for (int i = 0; i < vars.length (); i++)
+			{
+			  if (! vars (i)->is_defined ())
+			    varlen--;
+			}
+
+		      if (varlen > 0)
+			{
+			  Octave_map ws;
+			  for (octave_idx_type i = 0; i < vars.length (); i++)
+			    {
+			      if (vars (i)->is_defined ())
+				ws.assign (vars (i)->name (), 
+					   vars (i)->def ());
+			    }
+
+			  m.assign ("workspace", ws);
+			}
+		    }
 		  else if (fcn->is_user_function ())
-		    m.assign ("file", "command-line function");
+		    {
+		      octave_user_function *fu = fh->user_function_value ();
+		      m.assign ("file", fu->fcn_file_name ());
+		    }
 		  else
-		    m.assign ("file", "built-in function");
+		    m.assign ("file", "");
 		}
 	      else
 		m.assign ("file", nm);
--- a/src/ov-fcn-handle.h	Tue May 15 20:17:27 2007 +0000
+++ b/src/ov-fcn-handle.h	Wed May 16 08:49:48 2007 +0000
@@ -78,6 +78,9 @@
   octave_function *function_value (bool = false)
     { return fcn.function_value (); }
 
+  octave_user_function *user_function_value (bool = false)
+    { return fcn.user_function_value (); }
+
   octave_fcn_handle *fcn_handle_value (bool = false) { return this; }
 
   octave_value fcn_val (void) const { return fcn; }
@@ -105,6 +108,8 @@
 
 private:
 
+  bool set_fcn (const std::string &octaveroot, const std::string& fpath);
+
   DECLARE_OCTAVE_ALLOCATOR
 
   DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
--- a/src/ov-fcn-inline.cc	Tue May 15 20:17:27 2007 +0000
+++ b/src/ov-fcn-inline.cc	Wed May 16 08:49:48 2007 +0000
@@ -89,6 +89,26 @@
     error ("inline: unable to define function");
 }
 
+// This function is supplied to allow a Matlab style class structure
+// to be returned..
+Octave_map
+octave_fcn_inline::map_value (void) const
+{
+  Octave_map m;
+  string_vector args = fcn_arg_names ();
+  m.assign ("version", octave_value (1.0));
+  m.assign ("isEmpty", octave_value (0.0));
+  m.assign ("expr", octave_value (fcn_text ()));
+  m.assign ("numArgs", octave_value (args.length ()));
+  m.assign ("args", octave_value (args));
+  std::ostringstream buf;
+  for (int i = 0; i < args.length (); i++)
+    buf << args(i) << " = INLINE_INPUTS_{" << i + 1 << "}; ";
+  m.assign ("inputExpr", octave_value (buf.str ()));
+
+  return m;
+}
+
 bool
 octave_fcn_inline::save_ascii (std::ostream& os, bool&)
 {
--- a/src/ov-fcn-inline.h	Tue May 15 20:17:27 2007 +0000
+++ b/src/ov-fcn-inline.h	Wed May 16 08:49:48 2007 +0000
@@ -65,6 +65,8 @@
 
   octave_value convert_to_str_internal (bool, bool, char) const;
 
+  Octave_map map_value (void) const;
+
   bool save_ascii (std::ostream& os, bool& infnan_warned);
 
   bool load_ascii (std::istream& is);