Mercurial > hg > octave-lyh
diff src/ls-mat5.cc @ 6625:5d02dfacfc9e
[project @ 2007-05-16 08:49:47 by dbateman]
author | dbateman |
---|---|
date | Wed, 16 May 2007 08:49:48 +0000 |
parents | 0fcce0872e02 |
children | af16354ea09c |
line wrap: on
line diff
--- a/src/ls-mat5.cc +++ b/src/ls-mat5.cc @@ -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;