octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: saveing/loading symbol table of annymous functions


From: David Bateman
Subject: Re: saveing/loading symbol table of annymous functions
Date: Mon, 14 May 2007 14:45:14 +0200
User-agent: Thunderbird 1.5.0.7 (X11/20060921)

David Bateman wrote:
>
> No its missing the header of 116 bytes plus an additional 8 bytes for
> what is called the subsystem data offset and starts with the endianness,
> version number in hex of "0001 494d 0000 0000". One thing I just noticed
> is that the 117 to 124 are different in a file containing an anonymous
> function handle. The file anon2.mat above has "e003 0000 0000 0000",
> whereas a normal file just has 8 spaces (0x20).
> 
> Page 1-7 of matfile_format.pdf from the mathworks site states
> 
> <quote>
> Header Subsystem Data Offset Field
> Bytes 117 through 124 of the header contain an offset to
> subsystem-specific data in the MAT-file. All zeros or all spaces in this
> field indicate that there is no subsystem-specific data stored in the file.
> </quote>
> 
> Funnily the offset 0x3e0 points to the data block containing
> function_handle_workspace which is the embedded matfile....
> 
> What I wonder now is if this offset is needed to find the block to
> convert. As at the moment to make my life easy my test files all only
> have a single saved function handle, I now wonder what will happen to
> the file format if it contains multiple variables.. I'll check
> 
> In any case the current Octave code ignores bytes 117 to 124 of the
> header of matfiles as well.
> 

In fact the function handle workspace doesn't follow the function
handles class 17 block. Rather the header has an offset into the file
where the sub-system workspace is located and all function handle
workspaces have a field MCOS that is a signature and an offset into the
sub-system workspace for the workspace of each of the individual
function handle workspace. There are still some things I don't
understand in the file format for function handles, but I think I have
the loading of function handles working correctly for matlab files. I
think I'd like to see this included in octave and get a little bit of
feedback on issues people have to try and better understand the format
to allow saving to work.

The attached patch also includes a load/save for the octave file formats
for function handles that respects the path to system files, saves the
anonymous handles workspace, includes load/save in mat-file format for
inline functions and updates the Ffunctions function to print the
workspace and be a bit more compatible.

Regards
David


Index: src/load-path.cc
===================================================================
RCS file: /usr/local/cvsroot/octave/src/load-path.cc,v
retrieving revision 1.14
diff -c -r1.14 load-path.cc
*** src/load-path.cc    27 Feb 2007 19:43:36 -0000      1.14
--- src/load-path.cc    14 May 2007 12:34:40 -0000
***************
*** 50,55 ****
--- 50,61 ----
  
  static std::string Vsystem_path;
  
+ std::string
+ octave_system_path (void)
+ {
+   return Vsystem_path;
+ }
+ 
  void
  load_path::dir_info::update (void)
  {
Index: src/load-path.h
===================================================================
RCS file: /usr/local/cvsroot/octave/src/load-path.h,v
retrieving revision 1.6
diff -c -r1.6 load-path.h
*** src/load-path.h     27 Feb 2007 19:43:36 -0000      1.6
--- src/load-path.h     14 May 2007 12:34:40 -0000
***************
*** 341,346 ****
--- 341,348 ----
  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
  
  /*
Index: src/load-save.cc
===================================================================
RCS file: /usr/local/cvsroot/octave/src/load-save.cc,v
retrieving revision 1.221
diff -c -r1.221 load-save.cc
*** src/load-save.cc    26 Apr 2007 15:41:29 -0000      1.221
--- src/load-save.cc    14 May 2007 12:34:41 -0000
***************
*** 348,354 ****
  #endif
  
  static load_save_format
! get_file_format (std::istream& file)
  {
    load_save_format retval = LS_UNKNOWN;
  
--- 348,354 ----
  #endif
  
  static load_save_format
! get_file_format (std::istream& file, const std::string& filename)
  {
    load_save_format retval = LS_UNKNOWN;
  
***************
*** 374,380 ****
          file.clear ();
          file.seekg (0, std::ios::beg);
  
!         err = read_mat5_binary_file_header (file, swap, true);
  
          if (! err)
            {
--- 374,380 ----
          file.clear ();
          file.seekg (0, std::ios::beg);
  
!         err = read_mat5_binary_file_header (file, swap, true, filename);
  
          if (! err)
            {
***************
*** 415,421 ****
        
    if (file)
      {
!       retval = get_file_format (file);
        file.close ();
  
  #ifdef HAVE_ZLIB
--- 415,421 ----
        
    if (file)
      {
!       retval = get_file_format (file, orig_fname);
        file.close ();
  
  #ifdef HAVE_ZLIB
***************
*** 426,432 ****
  
          if (gzfile)
            {
!             retval = get_file_format (gzfile);
              gzfile.close ();
            }
        }
--- 426,432 ----
  
          if (gzfile)
            {
!             retval = get_file_format (gzfile, orig_fname);
              gzfile.close ();
            }
        }
***************
*** 925,931 ****
                  else if (format == LS_MAT5_BINARY 
                           || format == LS_MAT7_BINARY)
                    {
!                     if (read_mat5_binary_file_header (file, swap, false) < 0)
                        {
                          if (file) file.close ();
                          return retval;
--- 925,931 ----
                  else if (format == LS_MAT5_BINARY 
                           || format == LS_MAT7_BINARY)
                    {
!                     if (read_mat5_binary_file_header (file, swap, false, 
orig_fname) < 0)
                        {
                          if (file) file.close ();
                          return retval;
***************
*** 959,965 ****
                  else if (format == LS_MAT5_BINARY 
                           || format == LS_MAT7_BINARY)
                    {
!                     if (read_mat5_binary_file_header (file, swap, false) < 0)
                        {
                          if (file) file.close ();
                          return retval;
--- 959,965 ----
                  else if (format == LS_MAT5_BINARY 
                           || format == LS_MAT7_BINARY)
                    {
!                     if (read_mat5_binary_file_header (file, swap, false, 
orig_fname) < 0)
                        {
                          if (file) file.close ();
                          return retval;
***************
*** 1400,1405 ****
--- 1400,1409 ----
    
        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,1672 ****
--- 1671,1680 ----
  
        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
Index: src/ls-mat5.cc
===================================================================
RCS file: /usr/local/cvsroot/octave/src/ls-mat5.cc,v
retrieving revision 1.39
diff -c -r1.39 ls-mat5.cc
*** src/ls-mat5.cc      10 Feb 2007 02:10:21 -0000      1.39
--- src/ls-mat5.cc      14 May 2007 12:34:41 -0000
***************
*** 48,62 ****
--- 48,65 ----
  #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,81 ****
--- 73,91 ----
  #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,106 ****
      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
    };
  
  // Read COUNT elements of data from IS in the format specified by TYPE,
--- 110,117 ----
      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_WORKSPACE_CLASS          // Workspace (undocumented)
    };
  
  // Read COUNT elements of data from IS in the format specified by TYPE,
***************
*** 397,402 ****
--- 408,415 ----
  
    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,413 ****
    int32_t element_length;
    std::streampos pos;
    int16_t number;
!   number = *(int16_t *)"\x00\x01";
  
    global = false;
  
--- 420,426 ----
    int32_t element_length;
    std::streampos pos;
    int16_t number;
!   number = *(reinterpret_cast<const int16_t *>("\x00\x01"));
  
    global = false;
  
***************
*** 469,474 ****
--- 482,488 ----
  
    if (type != miMATRIX)
      {
+       pos = is.tellg ();
        error ("load: invalid element type = %d", type);
        goto early_read_error;
      }
***************
*** 496,522 ****
    read_int (is, swap, nzmax); // max number of non-zero in sparse
    
    // dimensions array subelement
!   {
!     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;
!       }
  
!     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));
!   }
  
    if (read_mat5_tag (is, swap, type, len) || type != miINT8)
      {
--- 510,544 ----
    read_int (is, swap, nzmax); // max number of non-zero in sparse
    
    // dimensions array subelement
!   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;
!       }
  
!       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));
!     }
!   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,580 ****
        }
        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");
--- 593,598 ----
***************
*** 707,719 ****
        else
          tc = sm;
        }
-       break;
  #endif
  
      case MAT_FILE_FUNCTION_CLASS:
!       warning ("load: function handles are not implemented");
!       goto skip_ahead;
  
      case MAT_FILE_STRUCT_CLASS:
        {
        Octave_map m (dim_vector (1, 1));
--- 725,1034 ----
        else
          tc = sm;
        }
  #endif
+       break;
  
      case MAT_FILE_FUNCTION_CLASS:
!       {
!       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,790 ****
              }
          }
  
!       tc = m;
        }
        break;
  
--- 1099,1122 ----
              }
          }
  
!       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,983 ****
  }
  
  int
! read_mat5_binary_file_header (std::istream& is, bool& swap, bool quiet)
  {
    int16_t version=0, magic=0;
  
    is.seekg (124, std::ios::beg);
    is.read (reinterpret_cast<char *> (&version), 2);
--- 1307,1320 ----
  }
  
  int
! 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,1006 ****
--- 1338,1385 ----
      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,1426 ****
        ret += save_mat5_array_length (m.fortran_vec (), m.nelem (),
                                     save_as_floats);
      }
!   else if (tc.is_map ()) 
      {
        int fieldcnt = 0;
        const Octave_map m = tc.map_value ();
        int nel = m.numel ();
  
        for (Octave_map::const_iterator i = m.begin (); i != m.end (); i++)
        fieldcnt++;
  
--- 1794,1809 ----
        ret += save_mat5_array_length (m.fortran_vec (), m.nelem (),
                                     save_as_floats);
      }
!   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,1564 ****
--- 1942,1949 ----
      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,1757 ****
        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 ()) 
      {
-       // 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;
--- 2131,2158 ----
        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 () || 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
        {
        char buf[64];
        int32_t maxfieldnamelength = max_namelen + 1;
Index: src/ls-mat5.h
===================================================================
RCS file: /usr/local/cvsroot/octave/src/ls-mat5.h,v
retrieving revision 1.3
diff -c -r1.3 ls-mat5.h
*** src/ls-mat5.h       26 Apr 2005 19:24:33 -0000      1.3
--- src/ls-mat5.h       14 May 2007 12:34:41 -0000
***************
*** 48,54 ****
  
  extern int
  read_mat5_binary_file_header (std::istream& is, bool& swap,
!                             bool quiet = false);
  extern std::string
  read_mat5_binary_element (std::istream& is, const std::string& filename,
                          bool swap, bool& global, octave_value& tc);
--- 48,55 ----
  
  extern int
  read_mat5_binary_file_header (std::istream& is, bool& swap,
!                             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);
Index: src/ov-fcn-handle.cc
===================================================================
RCS file: /usr/local/cvsroot/octave/src/ov-fcn-handle.cc,v
retrieving revision 1.37
diff -c -r1.37 ov-fcn-handle.cc
*** src/ov-fcn-handle.cc        3 Apr 2007 19:39:12 -0000       1.37
--- src/ov-fcn-handle.cc        14 May 2007 12:34:41 -0000
***************
*** 46,54 ****
--- 46,60 ----
  #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,157 ****
  }
  
  bool
! octave_fcn_handle::save_ascii (std::ostream& os, bool&)
  {
!   os << nm << "\n";
  
    if (nm == "@<anonymous>")
      {
        print_raw (os, true);
        os << "\n";
      }
  
    return true;
--- 150,308 ----
  }
  
  bool
! octave_fcn_handle::set_fcn (const std::string &octaveroot, 
!                           const std::string& fpath)
  {
!   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,169 ****
--- 311,338 ----
  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,242 ****
            }
        }
  
!       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
!           return false;
        }
        else
-       return false;
-     }
-   else
-     {
-       fcn = lookup_function (nm);
-       if (! fcn.is_function ())
        {
!         error ("function handle points to non-existent function");
!         return false;
        }
      }
  
!   return true;
  }
  
  bool
! octave_fcn_handle::save_binary (std::ostream& os, bool&)
  {
-   int32_t tmp = nm.length ();
-   os.write (reinterpret_cast<char *> (&tmp), 4);
-   os.write (nm.c_str (), nm.length ());
    if (nm == "@<anonymous>")
      {
        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 ());
      }
    return true;
  }
  
  bool
  octave_fcn_handle::load_binary (std::istream& is, bool swap,
!                               oct_mach_info::float_format)
  {
    int32_t tmp;
    if (! is.read (reinterpret_cast<char *> (&tmp), 4))
      return false;
--- 356,541 ----
            }
        }
  
!       pos = is.tellg ();
!       symbol_table *local_sym_tab = 0;
  
!       if (extract_keyword (is, "length", len, true) && len >= 0)
        {
!         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
        {
!         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
+     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 ("-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 ("test.mat");
+ %!   save ("-text", nm, "f2", "g2", "h2");
+ %! unwind_protect_cleanup
+ %!   unlink (nm);
+ %! end_unwind_protect
+ 
+ */
+ 
  bool
! octave_fcn_handle::save_binary (std::ostream& os, bool& save_as_floats)
  {
    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 fmt)
  {
+   bool success = true;
    int32_t tmp;
    if (! is.read (reinterpret_cast<char *> (&tmp), 4))
      return false;
***************
*** 250,257 ****
    if (! is)
      return false;
  
!   if (nm == "@<anonymous>")
      {
        if (! is.read (reinterpret_cast<char *> (&tmp), 4))
        return false;
        if (swap)
--- 549,565 ----
    if (! is)
      return false;
  
!   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,295 ****
        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)
        {
!         octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
!         if (fh)
!           fcn = fh->fcn;
          else
!           return false;
        }
!       else
!       return false;
      }
    else
      {
!       fcn = lookup_function (nm);
!       if (! fcn.is_function ())
        {
!         error ("function handle points to non-existent function");
!         return false;
        }
!     }
!   return true;
  }
  
  #if defined (HAVE_HDF5)
  bool
  octave_fcn_handle::save_hdf5 (hid_t loc_id, const char *name,
!                             bool /* save_as_floats */)
  {
    hid_t group_hid = -1;
    group_hid = H5Gcreate (loc_id, name, 0);
--- 568,693 ----
        OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
        is.read (ctmp2, tmp);
  
!       symbol_table *local_sym_tab = 0;
!       if (len > 0)
!       {
!         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
!           success = false;
! 
!         unwind_protect::run_frame ("anon_binary_load");
        }
! 
!       if (local_sym_tab)
!       delete local_sym_tab;
      }
    else
      {
!       std::string octaveroot;
!       std::string fpath;
! 
!       if (nm.find_first_of ("\n") != NPOS)
        {
!         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);
        }
! 
!       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 ("test.mat");
+ %!   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)
  {
    hid_t group_hid = -1;
    group_hid = H5Gcreate (loc_id, name, 0);
***************
*** 355,360 ****
--- 753,869 ----
        }
  
        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,376 ****
  
  bool
  octave_fcn_handle::load_hdf5 (hid_t loc_id, const char *name,
!                             bool /* have_h5giterate_bug */)
  {
    hid_t group_hid, data_hid, space_hid, type_hid, type_class_hid, st_id;
    hsize_t rank;
    int slen;
  
    group_hid = H5Gopen (loc_id, name);
    if (group_hid < 0 ) return false;
--- 875,886 ----
  
  bool
  octave_fcn_handle::load_hdf5 (hid_t loc_id, const char *name,
!                             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,523 ****
          return false;
        }
        H5Dclose (data_hid);
-       H5Tclose (st_id);
  
!       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
!           return false;
        }
!       else
!       return false;
      }
    else
      {
!       fcn = lookup_function (nm);
!       if (! fcn.is_function ())
        {
!         error ("function handle points to non-existent function");
!         return false;
        }
      }
  
!   return true;
  }
  #endif
  
  void
--- 1000,1219 ----
          return false;
        }
        H5Dclose (data_hid);
  
!       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;
! 
!       // 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 (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_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
!           success = false;
! 
!         unwind_protect::run_frame ("anon_hdf5_load");
        }
! 
!       if (local_sym_tab)
!       delete local_sym_tab;
      }
    else
      {
!       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)
        {
!         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 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 ("test.mat");
+ %!     save ("-hdf5", nm, "f2", "g2", "h2");
+ %!   unwind_protect_cleanup
+ %!     unlink (nm);
+ %!   end_unwind_protect
+ %! endif
+ 
+ */
  #endif
  
  void
***************
*** 657,679 ****
  
              std::string fh_nm = fh->fcn_name ();
  
!             m.assign ("function", fh_nm);
  
!             if (fcn->is_nested_function ())
!               m.assign ("type", "subfunction");
              else
!               m.assign ("type", "simple");
  
              std::string nm = fcn->fcn_file_name ();
  
              if (nm.empty ())
                {
                  if (fh_nm == "@<anonymous>")
!                   m.assign ("file", "none");
                  else if (fcn->is_user_function ())
!                   m.assign ("file", "command-line function");
                  else
!                   m.assign ("file", "built-in function");
                }
              else
                m.assign ("file", nm);
--- 1353,1422 ----
  
              std::string fh_nm = fh->fcn_name ();
  
!             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");
!                     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", "");
! 
!                     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 ())
!                   {
!                     octave_user_function *fu = fh->user_function_value ();
!                     m.assign ("file", fu->fcn_file_name ());
!                   }
                  else
!                   m.assign ("file", "");
                }
              else
                m.assign ("file", nm);
Index: src/ov-fcn-handle.h
===================================================================
RCS file: /usr/local/cvsroot/octave/src/ov-fcn-handle.h,v
retrieving revision 1.22
diff -c -r1.22 ov-fcn-handle.h
*** src/ov-fcn-handle.h 23 Aug 2006 18:35:39 -0000      1.22
--- src/ov-fcn-handle.h 14 May 2007 12:34:41 -0000
***************
*** 78,83 ****
--- 78,86 ----
    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,110 ****
--- 108,115 ----
  
  private:
  
+   bool set_fcn (const std::string &octaveroot, const std::string& fpath);
+ 
    DECLARE_OCTAVE_ALLOCATOR
  
    DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
Index: src/ov-fcn-inline.cc
===================================================================
RCS file: /usr/local/cvsroot/octave/src/ov-fcn-inline.cc,v
retrieving revision 1.31
diff -c -r1.31 ov-fcn-inline.cc
*** src/ov-fcn-inline.cc        19 Apr 2007 21:47:41 -0000      1.31
--- src/ov-fcn-inline.cc        14 May 2007 12:34:41 -0000
***************
*** 89,94 ****
--- 89,114 ----
      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&)
  {
Index: src/ov-fcn-inline.h
===================================================================
RCS file: /usr/local/cvsroot/octave/src/ov-fcn-inline.h,v
retrieving revision 1.11
diff -c -r1.11 ov-fcn-inline.h
*** src/ov-fcn-inline.h 23 Aug 2006 18:35:39 -0000      1.11
--- src/ov-fcn-inline.h 14 May 2007 12:34:41 -0000
***************
*** 65,70 ****
--- 65,72 ----
  
    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);
2007-04-11  David Bateman  <address@hidden>

        * 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-mat.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.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]