ov-fcn-handle.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2003-2012 John W. Eaton
00004 Copyright (C) 2009 VZLU Prague, a.s.
00005 Copyright (C) 2010 Jaroslav Hajek
00006 
00007 This file is part of Octave.
00008 
00009 Octave is free software; you can redistribute it and/or modify it
00010 under the terms of the GNU General Public License as published by the
00011 Free Software Foundation; either version 3 of the License, or (at your
00012 option) any later version.
00013 
00014 Octave is distributed in the hope that it will be useful, but WITHOUT
00015 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00017 for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with Octave; see the file COPYING.  If not, see
00021 <http://www.gnu.org/licenses/>.
00022 
00023 */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #include <config.h>
00027 #endif
00028 
00029 #include <iostream>
00030 #include <sstream>
00031 #include <vector>
00032 
00033 #include "file-ops.h"
00034 #include "oct-locbuf.h"
00035 
00036 #include "defun.h"
00037 #include "error.h"
00038 #include "gripes.h"
00039 #include "input.h"
00040 #include "oct-map.h"
00041 #include "ov-base.h"
00042 #include "ov-fcn-handle.h"
00043 #include "ov-usr-fcn.h"
00044 #include "pr-output.h"
00045 #include "pt-pr-code.h"
00046 #include "pt-misc.h"
00047 #include "pt-stmt.h"
00048 #include "pt-cmd.h"
00049 #include "pt-exp.h"
00050 #include "pt-assign.h"
00051 #include "pt-arg-list.h"
00052 #include "variables.h"
00053 #include "parse.h"
00054 #include "unwind-prot.h"
00055 #include "defaults.h"
00056 #include "file-stat.h"
00057 #include "load-path.h"
00058 #include "oct-env.h"
00059 
00060 #include "byte-swap.h"
00061 #include "ls-ascii-helper.h"
00062 #include "ls-hdf5.h"
00063 #include "ls-oct-ascii.h"
00064 #include "ls-oct-binary.h"
00065 #include "ls-utils.h"
00066 
00067 DEFINE_OCTAVE_ALLOCATOR (octave_fcn_handle);
00068 
00069 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_fcn_handle,
00070                                      "function handle",
00071                                      "function_handle");
00072 
00073 const std::string octave_fcn_handle::anonymous ("@<anonymous>");
00074 
00075 octave_fcn_handle::octave_fcn_handle (const octave_value& f,
00076                                       const std::string& n)
00077   : fcn (f), nm (n), has_overloads (false)
00078 {
00079   octave_user_function *uf = fcn.user_function_value (true);
00080 
00081   if (uf && nm != anonymous)
00082     symbol_table::cache_name (uf->scope (), nm);
00083 }
00084 
00085 octave_value_list
00086 octave_fcn_handle::subsref (const std::string& type,
00087                             const std::list<octave_value_list>& idx,
00088                             int nargout)
00089 {
00090   return octave_fcn_handle::subsref (type, idx, nargout, 0);
00091 }
00092 
00093 octave_value_list
00094 octave_fcn_handle::subsref (const std::string& type,
00095                             const std::list<octave_value_list>& idx,
00096                             int nargout, const std::list<octave_lvalue>* lvalue_list)
00097 {
00098   octave_value_list retval;
00099 
00100   switch (type[0])
00101     {
00102     case '(':
00103       {
00104         int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout;
00105 
00106         retval = do_multi_index_op (tmp_nargout, idx.front (),
00107                                     idx.size () == 1 ? lvalue_list : 0);
00108       }
00109       break;
00110 
00111     case '{':
00112     case '.':
00113       {
00114         std::string tnm = type_name ();
00115         error ("%s cannot be indexed with %c", tnm.c_str (), type[0]);
00116       }
00117       break;
00118 
00119     default:
00120       panic_impossible ();
00121     }
00122 
00123   // FIXME -- perhaps there should be an
00124   // octave_value_list::next_subsref member function?  See also
00125   // octave_builtin::subsref.
00126 
00127   if (idx.size () > 1)
00128     retval = retval(0).next_subsref (nargout, type, idx);
00129 
00130   return retval;
00131 }
00132 
00133 octave_value_list
00134 octave_fcn_handle::do_multi_index_op (int nargout,
00135                                       const octave_value_list& args)
00136 {
00137   return do_multi_index_op (nargout, args, 0);
00138 }
00139 
00140 octave_value_list
00141 octave_fcn_handle::do_multi_index_op (int nargout,
00142                                       const octave_value_list& args,
00143                                       const std::list<octave_lvalue>* lvalue_list)
00144 {
00145   octave_value_list retval;
00146 
00147   out_of_date_check (fcn, std::string (), false);
00148 
00149   if (has_overloads)
00150     {
00151       // Possibly overloaded function.
00152       octave_value ov_fcn;
00153 
00154       // Compute dispatch type.
00155       builtin_type_t btyp;
00156       std::string dispatch_type = get_dispatch_type (args, btyp);
00157 
00158       // Retrieve overload.
00159       if (btyp != btyp_unknown)
00160         {
00161           out_of_date_check (builtin_overloads[btyp], dispatch_type, false);
00162           ov_fcn = builtin_overloads[btyp];
00163         }
00164       else
00165         {
00166           str_ov_map::iterator it = overloads.find (dispatch_type);
00167 
00168           if (it == overloads.end ())
00169             {
00170               // Try parent classes too.
00171 
00172               std::list<std::string> plist
00173                 = symbol_table::parent_classes (dispatch_type);
00174 
00175               std::list<std::string>::const_iterator pit = plist.begin ();
00176 
00177               while (pit != plist.end ())
00178                 {
00179                   std::string pname = *pit;
00180 
00181                   std::string fnm = fcn_name ();
00182 
00183                   octave_value ftmp = symbol_table::find_method (fnm, pname);
00184 
00185                   if (ftmp.is_defined ())
00186                     {
00187                       set_overload (pname, ftmp);
00188 
00189                       out_of_date_check (ftmp, pname, false);
00190                       ov_fcn = ftmp;
00191 
00192                       break;
00193                     }
00194 
00195                   pit++;
00196                 }
00197             }
00198           else
00199             {
00200               out_of_date_check (it->second, dispatch_type, false);
00201               ov_fcn = it->second;
00202             }
00203         }
00204 
00205       if (ov_fcn.is_defined ())
00206         retval = ov_fcn.do_multi_index_op (nargout, args, lvalue_list);
00207       else if (fcn.is_defined ())
00208         retval = fcn.do_multi_index_op (nargout, args, lvalue_list);
00209       else
00210         error ("%s: no method for class %s", nm.c_str (), dispatch_type.c_str ());
00211     }
00212   else
00213     {
00214       // Non-overloaded function (anonymous, subfunction, private function).
00215       if (fcn.is_defined ())
00216         retval = fcn.do_multi_index_op (nargout, args, lvalue_list);
00217       else
00218         error ("%s: no longer valid function handle", nm.c_str ());
00219     }
00220 
00221   return retval;
00222 }
00223 
00224 bool
00225 octave_fcn_handle::is_equal_to (const octave_fcn_handle& h) const
00226 {
00227   bool retval = fcn.is_copy_of (h.fcn) && (has_overloads == h.has_overloads);
00228   retval = retval && (overloads.size () == h.overloads.size ());
00229 
00230   if (retval && has_overloads)
00231     {
00232       for (int i = 0; i < btyp_num_types && retval; i++)
00233         retval = builtin_overloads[i].is_copy_of (h.builtin_overloads[i]);
00234 
00235       str_ov_map::const_iterator iter = overloads.begin (), hiter = h.overloads.begin ();
00236       for (; iter != overloads.end () && retval; iter++, hiter++)
00237         retval = (iter->first == hiter->first) && (iter->second.is_copy_of (hiter->second));
00238     }
00239 
00240   return retval;
00241 }
00242 
00243 bool
00244 octave_fcn_handle::set_fcn (const std::string &octaveroot,
00245                             const std::string& fpath)
00246 {
00247   bool success = true;
00248 
00249   if (octaveroot.length () != 0
00250       && fpath.length () >= octaveroot.length ()
00251       && fpath.substr (0, octaveroot.length ()) == octaveroot
00252       && OCTAVE_EXEC_PREFIX != octaveroot)
00253     {
00254       // First check if just replacing matlabroot is enough
00255       std::string str = OCTAVE_EXEC_PREFIX +
00256         fpath.substr (octaveroot.length ());
00257       file_stat fs (str);
00258 
00259       if (fs.exists ())
00260         {
00261           size_t xpos = str.find_last_of (file_ops::dir_sep_chars ());
00262 
00263           std::string dir_name = str.substr (0, xpos);
00264 
00265           octave_function *xfcn
00266             = load_fcn_from_file (str, dir_name, "", nm);
00267 
00268           if (xfcn)
00269             {
00270               octave_value tmp (xfcn);
00271 
00272               fcn = octave_value (new octave_fcn_handle (tmp, nm));
00273             }
00274           else
00275             {
00276               error ("function handle points to non-existent function");
00277               success = false;
00278             }
00279         }
00280       else
00281         {
00282           // Next just search for it anywhere in the system path
00283           string_vector names(3);
00284           names(0) = nm + ".oct";
00285           names(1) = nm + ".mex";
00286           names(2) = nm + ".m";
00287 
00288           dir_path p (load_path::system_path ());
00289 
00290           str = octave_env::make_absolute (p.find_first_of (names));
00291 
00292           size_t xpos = str.find_last_of (file_ops::dir_sep_chars ());
00293 
00294           std::string dir_name = str.substr (0, xpos);
00295 
00296           octave_function *xfcn = load_fcn_from_file (str, dir_name, "", nm);
00297 
00298           if (xfcn)
00299             {
00300               octave_value tmp (xfcn);
00301 
00302               fcn = octave_value (new octave_fcn_handle (tmp, nm));
00303             }
00304           else
00305             {
00306               error ("function handle points to non-existent function");
00307               success = false;
00308             }
00309         }
00310     }
00311   else
00312     {
00313       if (fpath.length () > 0)
00314         {
00315           size_t xpos = fpath.find_last_of (file_ops::dir_sep_chars ());
00316 
00317           std::string dir_name = fpath.substr (0, xpos);
00318 
00319           octave_function *xfcn = load_fcn_from_file (fpath, dir_name, "", nm);
00320 
00321           if (xfcn)
00322             {
00323               octave_value tmp (xfcn);
00324 
00325               fcn = octave_value (new octave_fcn_handle (tmp, nm));
00326             }
00327           else
00328             {
00329               error ("function handle points to non-existent function");
00330               success = false;
00331             }
00332         }
00333       else
00334         {
00335           fcn = symbol_table::find_function (nm);
00336 
00337           if (! fcn.is_function ())
00338             {
00339               error ("function handle points to non-existent function");
00340               success = false;
00341             }
00342         }
00343     }
00344 
00345   return success;
00346 }
00347 
00348 bool
00349 octave_fcn_handle::save_ascii (std::ostream& os)
00350 {
00351   if (nm == anonymous)
00352     {
00353       os << nm << "\n";
00354 
00355       print_raw (os, true);
00356       os << "\n";
00357 
00358       if (fcn.is_undefined ())
00359         return false;
00360 
00361       octave_user_function *f = fcn.user_function_value ();
00362 
00363       std::list<symbol_table::symbol_record> vars
00364         = symbol_table::all_variables (f->scope (), 0);
00365 
00366       size_t varlen = vars.size ();
00367 
00368       if (varlen > 0)
00369         {
00370           os << "# length: " << varlen << "\n";
00371 
00372           for (std::list<symbol_table::symbol_record>::const_iterator p = vars.begin ();
00373                p != vars.end (); p++)
00374             {
00375               if (! save_ascii_data (os, p->varval (), p->name (), false, 0))
00376                 return os;
00377             }
00378         }
00379     }
00380   else
00381     {
00382       octave_function *f = function_value ();
00383       std::string fnm = f ? f->fcn_file_name () : std::string ();
00384 
00385       os << "# octaveroot: " << OCTAVE_EXEC_PREFIX << "\n";
00386       if (! fnm.empty ())
00387         os << "# path: " << fnm << "\n";
00388       os << nm << "\n";
00389     }
00390 
00391   return true;
00392 }
00393 
00394 bool
00395 octave_fcn_handle::load_ascii (std::istream& is)
00396 {
00397   bool success = true;
00398 
00399   std::streampos pos = is.tellg ();
00400   std::string octaveroot = extract_keyword (is, "octaveroot", true);
00401   if (octaveroot.length() == 0)
00402     {
00403       is.seekg (pos);
00404       is.clear ();
00405     }
00406   pos = is.tellg ();
00407   std::string fpath = extract_keyword (is, "path", true);
00408   if (fpath.length() == 0)
00409     {
00410       is.seekg (pos);
00411       is.clear ();
00412     }
00413 
00414   is >> nm;
00415 
00416   if (nm == anonymous)
00417     {
00418       skip_preceeding_newline (is);
00419 
00420       std::string buf;
00421 
00422       if (is)
00423         {
00424 
00425           // Get a line of text whitespace characters included, leaving
00426           // newline in the stream.
00427           buf = read_until_newline (is, true);
00428 
00429         }
00430 
00431       pos = is.tellg ();
00432 
00433       unwind_protect_safe frame;
00434 
00435       // Set up temporary scope to use for evaluating the text that
00436       // defines the anonymous function.
00437 
00438       symbol_table::scope_id local_scope = symbol_table::alloc_scope ();
00439       frame.add_fcn (symbol_table::erase_scope, local_scope);
00440 
00441       symbol_table::set_scope (local_scope);
00442 
00443       octave_call_stack::push (local_scope, 0);
00444       frame.add_fcn (octave_call_stack::pop);
00445 
00446       octave_idx_type len = 0;
00447 
00448       if (extract_keyword (is, "length", len, true) && len >= 0)
00449         {
00450           if (len > 0)
00451             {
00452               for (octave_idx_type i = 0; i < len; i++)
00453                 {
00454                   octave_value t2;
00455                   bool dummy;
00456 
00457                   std::string name
00458                     = read_ascii_data (is, std::string (), dummy, t2, i);
00459 
00460                   if (!is)
00461                     {
00462                       error ("load: failed to load anonymous function handle");
00463                       break;
00464                     }
00465 
00466                   symbol_table::varref (name, local_scope, 0) = t2;
00467                 }
00468             }
00469         }
00470       else
00471         {
00472           is.seekg (pos);
00473           is.clear ();
00474         }
00475 
00476       if (is && success)
00477         {
00478           int parse_status;
00479           octave_value anon_fcn_handle =
00480             eval_string (buf, true, parse_status);
00481 
00482           if (parse_status == 0)
00483             {
00484               octave_fcn_handle *fh =
00485                 anon_fcn_handle.fcn_handle_value ();
00486 
00487               if (fh)
00488                 {
00489                   fcn = fh->fcn;
00490 
00491                   octave_user_function *uf = fcn.user_function_value (true);
00492 
00493                   if (uf)
00494                     symbol_table::cache_name (uf->scope (), nm);
00495                 }
00496               else
00497                 success = false;
00498             }
00499           else
00500             success = false;
00501         }
00502       else
00503         success = false;
00504     }
00505   else
00506     success = set_fcn (octaveroot, fpath);
00507 
00508   return success;
00509 }
00510 
00511 bool
00512 octave_fcn_handle::save_binary (std::ostream& os, bool& save_as_floats)
00513 {
00514   if (nm == anonymous)
00515     {
00516       std::ostringstream nmbuf;
00517 
00518       if (fcn.is_undefined ())
00519         return false;
00520 
00521       octave_user_function *f = fcn.user_function_value ();
00522 
00523       std::list<symbol_table::symbol_record> vars
00524         = symbol_table::all_variables (f->scope (), 0);
00525 
00526       size_t varlen = vars.size ();
00527 
00528       if (varlen > 0)
00529         nmbuf << nm << " " << varlen;
00530       else
00531         nmbuf << nm;
00532 
00533       std::string buf_str = nmbuf.str();
00534       int32_t tmp = buf_str.length ();
00535       os.write (reinterpret_cast<char *> (&tmp), 4);
00536       os.write (buf_str.c_str (), buf_str.length ());
00537 
00538       std::ostringstream buf;
00539       print_raw (buf, true);
00540       std::string stmp = buf.str ();
00541       tmp = stmp.length ();
00542       os.write (reinterpret_cast<char *> (&tmp), 4);
00543       os.write (stmp.c_str (), stmp.length ());
00544 
00545       if (varlen > 0)
00546         {
00547           for (std::list<symbol_table::symbol_record>::const_iterator p = vars.begin ();
00548                p != vars.end (); p++)
00549             {
00550               if (! save_binary_data (os, p->varval (), p->name (),
00551                                       "", 0, save_as_floats))
00552                 return os;
00553             }
00554         }
00555     }
00556   else
00557     {
00558       std::ostringstream nmbuf;
00559 
00560       octave_function *f = function_value ();
00561       std::string fnm = f ? f->fcn_file_name () : std::string ();
00562 
00563       nmbuf << nm << "\n" << OCTAVE_EXEC_PREFIX << "\n" << fnm;
00564 
00565       std::string buf_str = nmbuf.str ();
00566       int32_t tmp = buf_str.length ();
00567       os.write (reinterpret_cast<char *> (&tmp), 4);
00568       os.write (buf_str.c_str (), buf_str.length ());
00569     }
00570 
00571   return true;
00572 }
00573 
00574 bool
00575 octave_fcn_handle::load_binary (std::istream& is, bool swap,
00576                                 oct_mach_info::float_format fmt)
00577 {
00578   bool success = true;
00579 
00580   int32_t tmp;
00581   if (! is.read (reinterpret_cast<char *> (&tmp), 4))
00582     return false;
00583   if (swap)
00584     swap_bytes<4> (&tmp);
00585 
00586   OCTAVE_LOCAL_BUFFER (char, ctmp1, tmp+1);
00587   // is.get (ctmp1, tmp+1, 0); caused is.eof () to be true though
00588   // effectively not reading over file end
00589   is.read (ctmp1, tmp);
00590   ctmp1[tmp] = 0;
00591   nm = std::string (ctmp1);
00592 
00593   if (! is)
00594     return false;
00595 
00596   size_t anl = anonymous.length ();
00597 
00598   if (nm.length() >= anl && nm.substr (0, anl) == anonymous)
00599     {
00600       octave_idx_type len = 0;
00601 
00602       if (nm.length() > anl)
00603         {
00604           std::istringstream nm_is (nm.substr (anl));
00605           nm_is >> len;
00606           nm = nm.substr (0, anl);
00607         }
00608 
00609       if (! is.read (reinterpret_cast<char *> (&tmp), 4))
00610         return false;
00611       if (swap)
00612         swap_bytes<4> (&tmp);
00613 
00614       OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
00615       // is.get (ctmp2, tmp+1, 0); caused is.eof () to be true though
00616       // effectively not reading over file end
00617       is.read (ctmp2, tmp);
00618       ctmp2[tmp] = 0;
00619 
00620       unwind_protect_safe frame;
00621 
00622       // Set up temporary scope to use for evaluating the text that
00623       // defines the anonymous function.
00624 
00625       symbol_table::scope_id local_scope = symbol_table::alloc_scope ();
00626       frame.add_fcn (symbol_table::erase_scope, local_scope);
00627 
00628       symbol_table::set_scope (local_scope);
00629 
00630       octave_call_stack::push (local_scope, 0);
00631       frame.add_fcn (octave_call_stack::pop);
00632 
00633       if (len > 0)
00634         {
00635           for (octave_idx_type i = 0; i < len; i++)
00636             {
00637               octave_value t2;
00638               bool dummy;
00639               std::string doc;
00640 
00641               std::string name =
00642                 read_binary_data (is, swap, fmt, std::string (),
00643                                   dummy, t2, doc);
00644 
00645               if (!is)
00646                 {
00647                   error ("load: failed to load anonymous function handle");
00648                   break;
00649                 }
00650 
00651               symbol_table::varref (name, local_scope) = t2;
00652             }
00653         }
00654 
00655       if (is && success)
00656         {
00657           int parse_status;
00658           octave_value anon_fcn_handle =
00659             eval_string (ctmp2, true, parse_status);
00660 
00661           if (parse_status == 0)
00662             {
00663               octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
00664 
00665               if (fh)
00666                 {
00667                   fcn = fh->fcn;
00668 
00669                   octave_user_function *uf = fcn.user_function_value (true);
00670 
00671                   if (uf)
00672                     symbol_table::cache_name (uf->scope (), nm);
00673                 }
00674               else
00675                 success = false;
00676             }
00677           else
00678             success = false;
00679         }
00680     }
00681   else
00682     {
00683       std::string octaveroot;
00684       std::string fpath;
00685 
00686       if (nm.find_first_of ("\n") != std::string::npos)
00687         {
00688           size_t pos1 = nm.find_first_of ("\n");
00689           size_t pos2 = nm.find_first_of ("\n", pos1 + 1);
00690           octaveroot = nm.substr (pos1 + 1, pos2 - pos1 - 1);
00691           fpath = nm.substr (pos2 + 1);
00692           nm = nm.substr (0, pos1);
00693         }
00694 
00695       success = set_fcn (octaveroot, fpath);
00696      }
00697 
00698   return success;
00699 }
00700 
00701 #if defined (HAVE_HDF5)
00702 bool
00703 octave_fcn_handle::save_hdf5 (hid_t loc_id, const char *name,
00704                               bool save_as_floats)
00705 {
00706   bool retval = true;
00707 
00708   hid_t group_hid = -1;
00709 #if HAVE_HDF5_18
00710   group_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00711 #else
00712   group_hid = H5Gcreate (loc_id, name, 0);
00713 #endif
00714   if (group_hid < 0)
00715     return false;
00716 
00717   hid_t space_hid = -1, data_hid = -1, type_hid = -1;;
00718 
00719   // attach the type of the variable
00720   type_hid = H5Tcopy (H5T_C_S1);
00721   H5Tset_size (type_hid, nm.length () + 1);
00722   if (type_hid < 0)
00723     {
00724       H5Gclose (group_hid);
00725       return false;
00726     }
00727 
00728   OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
00729   hdims[0] = 0;
00730   hdims[1] = 0;
00731   space_hid = H5Screate_simple (0 , hdims, 0);
00732   if (space_hid < 0)
00733     {
00734       H5Tclose (type_hid);
00735       H5Gclose (group_hid);
00736       return false;
00737     }
00738 #if HAVE_HDF5_18
00739   data_hid = H5Dcreate (group_hid, "nm",  type_hid, space_hid,
00740                         H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00741 #else
00742   data_hid = H5Dcreate (group_hid, "nm",  type_hid, space_hid, H5P_DEFAULT);
00743 #endif
00744   if (data_hid < 0 || H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL,
00745                                 H5P_DEFAULT, nm.c_str ()) < 0)
00746     {
00747       H5Sclose (space_hid);
00748       H5Tclose (type_hid);
00749       H5Gclose (group_hid);
00750       return false;
00751     }
00752   H5Dclose (data_hid);
00753 
00754   if (nm == anonymous)
00755     {
00756       std::ostringstream buf;
00757       print_raw (buf, true);
00758       std::string stmp = buf.str ();
00759 
00760       // attach the type of the variable
00761       H5Tset_size (type_hid, stmp.length () + 1);
00762       if (type_hid < 0)
00763         {
00764           H5Sclose (space_hid);
00765           H5Gclose (group_hid);
00766           return false;
00767         }
00768 
00769 #if HAVE_HDF5_18
00770       data_hid = H5Dcreate (group_hid, "fcn",  type_hid, space_hid,
00771                             H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00772 #else
00773       data_hid = H5Dcreate (group_hid, "fcn",  type_hid, space_hid,
00774                             H5P_DEFAULT);
00775 #endif
00776       if (data_hid < 0 || H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL,
00777                                     H5P_DEFAULT, stmp.c_str ()) < 0)
00778         {
00779           H5Sclose (space_hid);
00780           H5Tclose (type_hid);
00781           H5Gclose (group_hid);
00782           return false;
00783         }
00784 
00785       H5Dclose (data_hid);
00786 
00787       octave_user_function *f = fcn.user_function_value ();
00788 
00789       std::list<symbol_table::symbol_record> vars
00790         = symbol_table::all_variables (f->scope (), 0);
00791 
00792       size_t varlen = vars.size ();
00793 
00794       if (varlen > 0)
00795         {
00796           hid_t as_id = H5Screate (H5S_SCALAR);
00797 
00798           if (as_id >= 0)
00799             {
00800 #if HAVE_HDF5_18
00801               hid_t a_id = H5Acreate (group_hid, "SYMBOL_TABLE",
00802                                       H5T_NATIVE_IDX, as_id,
00803                                       H5P_DEFAULT, H5P_DEFAULT);
00804 
00805 #else
00806               hid_t a_id = H5Acreate (group_hid, "SYMBOL_TABLE",
00807                                       H5T_NATIVE_IDX, as_id, H5P_DEFAULT);
00808 #endif
00809 
00810               if (a_id >= 0)
00811                 {
00812                   retval = (H5Awrite (a_id, H5T_NATIVE_IDX, &varlen) >= 0);
00813 
00814                   H5Aclose (a_id);
00815                 }
00816               else
00817                 retval = false;
00818 
00819               H5Sclose (as_id);
00820             }
00821           else
00822             retval = false;
00823 #if HAVE_HDF5_18
00824           data_hid = H5Gcreate (group_hid, "symbol table", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00825 #else
00826           data_hid = H5Gcreate (group_hid, "symbol table", 0);
00827 #endif
00828           if (data_hid < 0)
00829             {
00830               H5Sclose (space_hid);
00831               H5Tclose (type_hid);
00832               H5Gclose (group_hid);
00833               return false;
00834             }
00835 
00836           for (std::list<symbol_table::symbol_record>::const_iterator p = vars.begin ();
00837                p != vars.end (); p++)
00838             {
00839               if (! add_hdf5_data (data_hid, p->varval (), p->name (),
00840                                    "", false, save_as_floats))
00841                 break;
00842             }
00843           H5Gclose (data_hid);
00844         }
00845     }
00846   else
00847     {
00848       std::string octaveroot = OCTAVE_EXEC_PREFIX;
00849 
00850       octave_function *f = function_value ();
00851       std::string fpath = f ? f->fcn_file_name () : std::string ();
00852 
00853       H5Sclose (space_hid);
00854       hdims[0] = 1;
00855       hdims[1] = octaveroot.length ();
00856       space_hid = H5Screate_simple (0 , hdims, 0);
00857       if (space_hid < 0)
00858         {
00859           H5Tclose (type_hid);
00860           H5Gclose (group_hid);
00861           return false;
00862         }
00863 
00864       H5Tclose (type_hid);
00865       type_hid = H5Tcopy (H5T_C_S1);
00866       H5Tset_size (type_hid, octaveroot.length () + 1);
00867 #if HAVE_HDF5_18
00868       hid_t a_id = H5Acreate (group_hid, "OCTAVEROOT",
00869                               type_hid, space_hid, H5P_DEFAULT, H5P_DEFAULT);
00870 #else
00871       hid_t a_id = H5Acreate (group_hid, "OCTAVEROOT",
00872                               type_hid, space_hid, H5P_DEFAULT);
00873 #endif
00874 
00875       if (a_id >= 0)
00876         {
00877           retval = (H5Awrite (a_id, type_hid, octaveroot.c_str ()) >= 0);
00878 
00879           H5Aclose (a_id);
00880         }
00881       else
00882         {
00883           H5Sclose (space_hid);
00884           H5Tclose (type_hid);
00885           H5Gclose (group_hid);
00886           return false;
00887         }
00888 
00889       H5Sclose (space_hid);
00890       hdims[0] = 1;
00891       hdims[1] = fpath.length ();
00892       space_hid = H5Screate_simple (0 , hdims, 0);
00893       if (space_hid < 0)
00894         {
00895           H5Tclose (type_hid);
00896           H5Gclose (group_hid);
00897           return false;
00898         }
00899 
00900       H5Tclose (type_hid);
00901       type_hid = H5Tcopy (H5T_C_S1);
00902       H5Tset_size (type_hid, fpath.length () + 1);
00903 
00904 #if HAVE_HDF5_18
00905       a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid,
00906                         H5P_DEFAULT, H5P_DEFAULT);
00907 #else
00908       a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid, H5P_DEFAULT);
00909 #endif
00910 
00911       if (a_id >= 0)
00912         {
00913           retval = (H5Awrite (a_id, type_hid, fpath.c_str ()) >= 0);
00914 
00915           H5Aclose (a_id);
00916         }
00917       else
00918         retval = false;
00919     }
00920 
00921   H5Sclose (space_hid);
00922   H5Tclose (type_hid);
00923   H5Gclose (group_hid);
00924 
00925   return retval;
00926 }
00927 
00928 bool
00929 octave_fcn_handle::load_hdf5 (hid_t loc_id, const char *name)
00930 {
00931   bool success = true;
00932 
00933   hid_t group_hid, data_hid, space_hid, type_hid, type_class_hid, st_id;
00934   hsize_t rank;
00935   int slen;
00936 
00937 #if HAVE_HDF5_18
00938   group_hid = H5Gopen (loc_id, name, H5P_DEFAULT);
00939 #else
00940   group_hid = H5Gopen (loc_id, name);
00941 #endif
00942   if (group_hid < 0)
00943     return false;
00944 
00945 #if HAVE_HDF5_18
00946   data_hid = H5Dopen (group_hid, "nm", H5P_DEFAULT);
00947 #else
00948   data_hid = H5Dopen (group_hid, "nm");
00949 #endif
00950 
00951   if (data_hid < 0)
00952     {
00953       H5Gclose (group_hid);
00954       return false;
00955     }
00956 
00957   type_hid = H5Dget_type (data_hid);
00958   type_class_hid = H5Tget_class (type_hid);
00959 
00960   if (type_class_hid != H5T_STRING)
00961     {
00962       H5Tclose (type_hid);
00963       H5Dclose (data_hid);
00964       H5Gclose (group_hid);
00965       return false;
00966     }
00967 
00968   space_hid = H5Dget_space (data_hid);
00969   rank = H5Sget_simple_extent_ndims (space_hid);
00970 
00971   if (rank != 0)
00972     {
00973       H5Sclose (space_hid);
00974       H5Tclose (type_hid);
00975       H5Dclose (data_hid);
00976       H5Gclose (group_hid);
00977       return false;
00978     }
00979 
00980   slen = H5Tget_size (type_hid);
00981   if (slen < 0)
00982     {
00983       H5Sclose (space_hid);
00984       H5Tclose (type_hid);
00985       H5Dclose (data_hid);
00986       H5Gclose (group_hid);
00987       return false;
00988     }
00989 
00990   OCTAVE_LOCAL_BUFFER (char, nm_tmp, slen);
00991 
00992   // create datatype for (null-terminated) string to read into:
00993   st_id = H5Tcopy (H5T_C_S1);
00994   H5Tset_size (st_id, slen);
00995 
00996   if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, nm_tmp) < 0)
00997     {
00998       H5Tclose (st_id);
00999       H5Sclose (space_hid);
01000       H5Tclose (type_hid);
01001       H5Dclose (data_hid);
01002       H5Gclose (group_hid);
01003       return false;
01004     }
01005   H5Tclose (st_id);
01006   H5Dclose (data_hid);
01007   nm = nm_tmp;
01008 
01009   if (nm == anonymous)
01010     {
01011 #if HAVE_HDF5_18
01012       data_hid = H5Dopen (group_hid, "fcn", H5P_DEFAULT);
01013 #else
01014       data_hid = H5Dopen (group_hid, "fcn");
01015 #endif
01016 
01017       if (data_hid < 0)
01018         {
01019           H5Sclose (space_hid);
01020           H5Tclose (type_hid);
01021           H5Gclose (group_hid);
01022           return false;
01023         }
01024 
01025       H5Tclose (type_hid);
01026       type_hid = H5Dget_type (data_hid);
01027       type_class_hid = H5Tget_class (type_hid);
01028 
01029       if (type_class_hid != H5T_STRING)
01030         {
01031           H5Sclose (space_hid);
01032           H5Tclose (type_hid);
01033           H5Dclose (data_hid);
01034           H5Gclose (group_hid);
01035           return false;
01036         }
01037 
01038       H5Sclose (space_hid);
01039       space_hid = H5Dget_space (data_hid);
01040       rank = H5Sget_simple_extent_ndims (space_hid);
01041 
01042       if (rank != 0)
01043         {
01044           H5Sclose (space_hid);
01045           H5Tclose (type_hid);
01046           H5Dclose (data_hid);
01047           H5Gclose (group_hid);
01048           return false;
01049         }
01050 
01051       slen = H5Tget_size (type_hid);
01052       if (slen < 0)
01053         {
01054           H5Sclose (space_hid);
01055           H5Tclose (type_hid);
01056           H5Dclose (data_hid);
01057           H5Gclose (group_hid);
01058           return false;
01059         }
01060 
01061       OCTAVE_LOCAL_BUFFER (char, fcn_tmp, slen);
01062 
01063       // create datatype for (null-terminated) string to read into:
01064       st_id = H5Tcopy (H5T_C_S1);
01065       H5Tset_size (st_id, slen);
01066 
01067       if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, fcn_tmp) < 0)
01068         {
01069           H5Tclose (st_id);
01070           H5Sclose (space_hid);
01071           H5Tclose (type_hid);
01072           H5Dclose (data_hid);
01073           H5Gclose (group_hid);
01074           return false;
01075         }
01076       H5Tclose (st_id);
01077       H5Dclose (data_hid);
01078 
01079       octave_idx_type len = 0;
01080 
01081       // we have to pull some shenanigans here to make sure
01082       // HDF5 doesn't print out all sorts of error messages if we
01083       // call H5Aopen for a non-existing attribute
01084 
01085       H5E_auto_t err_func;
01086       void *err_func_data;
01087 
01088       // turn off error reporting temporarily, but save the error
01089       // reporting function:
01090 #if HAVE_HDF5_18
01091       H5Eget_auto (H5E_DEFAULT, &err_func, &err_func_data);
01092       H5Eset_auto (H5E_DEFAULT, 0, 0);
01093 #else
01094       H5Eget_auto (&err_func, &err_func_data);
01095       H5Eset_auto (0, 0);
01096 #endif
01097 
01098       hid_t attr_id = H5Aopen_name (group_hid, "SYMBOL_TABLE");
01099 
01100       if (attr_id >= 0)
01101         {
01102           if (H5Aread (attr_id, H5T_NATIVE_IDX, &len) < 0)
01103             success = false;
01104 
01105           H5Aclose (attr_id);
01106         }
01107 
01108       // restore error reporting:
01109 #if HAVE_HDF5_18
01110       H5Eset_auto (H5E_DEFAULT, err_func, err_func_data);
01111 #else
01112       H5Eset_auto (err_func, err_func_data);
01113 #endif
01114 
01115       unwind_protect_safe frame;
01116 
01117       // Set up temporary scope to use for evaluating the text that
01118       // defines the anonymous function.
01119 
01120       symbol_table::scope_id local_scope = symbol_table::alloc_scope ();
01121       frame.add_fcn (symbol_table::erase_scope, local_scope);
01122 
01123       symbol_table::set_scope (local_scope);
01124 
01125       octave_call_stack::push (local_scope, 0);
01126       frame.add_fcn (octave_call_stack::pop);
01127 
01128       if (len > 0 && success)
01129         {
01130           hsize_t num_obj = 0;
01131 #if HAVE_HDF5_18
01132           data_hid = H5Gopen (group_hid, "symbol table", H5P_DEFAULT);
01133 #else
01134           data_hid = H5Gopen (group_hid, "symbol table");
01135 #endif
01136           H5Gget_num_objs (data_hid, &num_obj);
01137           H5Gclose (data_hid);
01138 
01139           if (num_obj != static_cast<hsize_t>(len))
01140             {
01141               error ("load: failed to load anonymous function handle");
01142               success = false;
01143             }
01144 
01145           if (! error_state)
01146             {
01147               hdf5_callback_data dsub;
01148               int current_item = 0;
01149               for (octave_idx_type i = 0; i < len; i++)
01150                 {
01151                   if (H5Giterate (group_hid, "symbol table", &current_item,
01152                                   hdf5_read_next_data, &dsub) <= 0)
01153                     {
01154                       error ("load: failed to load anonymous function handle");
01155                       success = false;
01156                       break;
01157                     }
01158 
01159                   symbol_table::varref (dsub.name, local_scope) = dsub.tc;
01160                 }
01161             }
01162         }
01163 
01164       if (success)
01165         {
01166           int parse_status;
01167           octave_value anon_fcn_handle =
01168             eval_string (fcn_tmp, true, parse_status);
01169 
01170           if (parse_status == 0)
01171             {
01172               octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
01173 
01174               if (fh)
01175                 {
01176                   fcn = fh->fcn;
01177 
01178                   octave_user_function *uf = fcn.user_function_value (true);
01179 
01180                   if (uf)
01181                     symbol_table::cache_name (uf->scope (), nm);
01182                 }
01183               else
01184                 success = false;
01185             }
01186           else
01187             success = false;
01188         }
01189 
01190       frame.run ();
01191     }
01192   else
01193     {
01194       std::string octaveroot;
01195       std::string fpath;
01196 
01197       // we have to pull some shenanigans here to make sure
01198       // HDF5 doesn't print out all sorts of error messages if we
01199       // call H5Aopen for a non-existing attribute
01200 
01201       H5E_auto_t err_func;
01202       void *err_func_data;
01203 
01204       // turn off error reporting temporarily, but save the error
01205       // reporting function:
01206 #if HAVE_HDF5_18
01207       H5Eget_auto (H5E_DEFAULT, &err_func, &err_func_data);
01208       H5Eset_auto (H5E_DEFAULT, 0, 0);
01209 #else
01210       H5Eget_auto (&err_func, &err_func_data);
01211       H5Eset_auto (0, 0);
01212 #endif
01213 
01214       hid_t attr_id = H5Aopen_name (group_hid, "OCTAVEROOT");
01215       if (attr_id >= 0)
01216         {
01217           H5Tclose (type_hid);
01218           type_hid = H5Aget_type (attr_id);
01219           type_class_hid = H5Tget_class (type_hid);
01220 
01221           if (type_class_hid != H5T_STRING)
01222             success = false;
01223           else
01224             {
01225               slen = H5Tget_size (type_hid);
01226               st_id = H5Tcopy (H5T_C_S1);
01227               H5Tset_size (st_id, slen);
01228               OCTAVE_LOCAL_BUFFER (char, root_tmp, slen);
01229 
01230               if (H5Aread (attr_id, st_id, root_tmp) < 0)
01231                 success = false;
01232               else
01233                 octaveroot = root_tmp;
01234 
01235               H5Tclose (st_id);
01236             }
01237 
01238           H5Aclose (attr_id);
01239         }
01240 
01241       if (success)
01242         {
01243           attr_id = H5Aopen_name (group_hid, "FILE");
01244           if (attr_id >= 0)
01245             {
01246               H5Tclose (type_hid);
01247               type_hid = H5Aget_type (attr_id);
01248               type_class_hid = H5Tget_class (type_hid);
01249 
01250               if (type_class_hid != H5T_STRING)
01251                 success = false;
01252               else
01253                 {
01254                   slen = H5Tget_size (type_hid);
01255                   st_id = H5Tcopy (H5T_C_S1);
01256                   H5Tset_size (st_id, slen);
01257                   OCTAVE_LOCAL_BUFFER (char, path_tmp, slen);
01258 
01259                   if (H5Aread (attr_id, st_id, path_tmp) < 0)
01260                     success = false;
01261                   else
01262                     fpath = path_tmp;
01263 
01264                   H5Tclose (st_id);
01265                 }
01266 
01267               H5Aclose (attr_id);
01268             }
01269         }
01270 
01271       // restore error reporting:
01272 #if HAVE_HDF5_18
01273       H5Eset_auto (H5E_DEFAULT, err_func, err_func_data);
01274 #else
01275       H5Eset_auto (err_func, err_func_data);
01276 #endif
01277 
01278       success = (success ? set_fcn (octaveroot, fpath) : success);
01279     }
01280 
01281   H5Tclose (type_hid);
01282   H5Sclose (space_hid);
01283   H5Gclose (group_hid);
01284 
01285   return success;
01286 }
01287 
01288 #endif
01289 
01290 /*
01291 
01292 %!test
01293 %! a = 2;
01294 %! f = @(x) a + x;
01295 %! g = @(x) 2 * x;
01296 %! hm = @version;
01297 %! hdld = @svd;
01298 %! hbi = @log2;
01299 %! f2 = f;
01300 %! g2 = g;
01301 %! hm2 = hm;
01302 %! hdld2 = hdld;
01303 %! hbi2 = hbi;
01304 %! modes = {"-text", "-binary"};
01305 %! if (!isempty(findstr(octave_config_info ("DEFS"),"HAVE_HDF5")))
01306 %!   modes(end+1) = "-hdf5";
01307 %! endif
01308 %! for i = 1:numel (modes)
01309 %!   mode = modes{i};
01310 %!   nm = tmpnam();
01311 %!   unwind_protect
01312 %!     save (mode, nm, "f2", "g2", "hm2", "hdld2", "hbi2");
01313 %!     clear f2 g2 hm2 hdld2 hbi2
01314 %!     load (nm);
01315 %!     assert (f(2),f2(2));
01316 %!     assert (g(2),g2(2));
01317 %!     assert (g(3),g2(3));
01318 %!     unlink (nm);
01319 %!     save (mode, nm, "f2", "g2", "hm2", "hdld2", "hbi2");
01320 %!   unwind_protect_cleanup
01321 %!     unlink (nm);
01322 %!   end_unwind_protect
01323 %! endfor
01324 
01325 */
01326 
01327 void
01328 octave_fcn_handle::print (std::ostream& os, bool pr_as_read_syntax) const
01329 {
01330   print_raw (os, pr_as_read_syntax);
01331   newline (os);
01332 }
01333 
01334 void
01335 octave_fcn_handle::print_raw (std::ostream& os, bool pr_as_read_syntax) const
01336 {
01337   bool printed = false;
01338 
01339   if (nm == anonymous)
01340     {
01341       tree_print_code tpc (os);
01342 
01343       // FCN is const because this member function is, so we can't
01344       // use it to call user_function_value, so we make a copy first.
01345 
01346       octave_value ftmp = fcn;
01347 
01348       octave_user_function *f = ftmp.user_function_value ();
01349 
01350       if (f)
01351         {
01352           tree_parameter_list *p = f->parameter_list ();
01353 
01354           os << "@(";
01355 
01356           if (p)
01357             p->accept (tpc);
01358 
01359           os << ") ";
01360 
01361           tpc.print_fcn_handle_body (f->body ());
01362 
01363           printed = true;
01364         }
01365     }
01366 
01367   if (! printed)
01368     octave_print_internal (os, "@" + nm, pr_as_read_syntax,
01369                            current_print_indent_level ());
01370 }
01371 
01372 octave_value
01373 make_fcn_handle (const std::string& nm, bool local_funcs)
01374 {
01375   octave_value retval;
01376 
01377   // Bow to the god of compatibility.
01378 
01379   // FIXME -- it seems ugly to put this here, but there is no single
01380   // function in the parser that converts from the operator name to
01381   // the corresponding function name.  At least try to do it without N
01382   // string compares.
01383 
01384   std::string tnm = nm;
01385 
01386   size_t len = nm.length ();
01387 
01388   if (len == 3 && nm == ".**")
01389     tnm = "power";
01390   else if (len == 2)
01391     {
01392       if (nm[0] == '.')
01393         {
01394           switch (nm[1])
01395             {
01396             case '\'':
01397               tnm = "transpose";
01398               break;
01399 
01400             case '+':
01401               tnm = "plus";
01402               break;
01403 
01404             case '-':
01405               tnm = "minus";
01406               break;
01407 
01408             case '*':
01409               tnm = "times";
01410               break;
01411 
01412             case '/':
01413               tnm = "rdivide";
01414               break;
01415 
01416             case '^':
01417               tnm = "power";
01418               break;
01419 
01420             case '\\':
01421               tnm = "ldivide";
01422               break;
01423             }
01424         }
01425       else if (nm[1] == '=')
01426         {
01427           switch (nm[0])
01428             {
01429             case '<':
01430               tnm = "le";
01431               break;
01432 
01433             case '=':
01434               tnm = "eq";
01435               break;
01436 
01437             case '>':
01438               tnm = "ge";
01439               break;
01440 
01441             case '~':
01442             case '!':
01443               tnm = "ne";
01444               break;
01445             }
01446         }
01447       else if (nm == "**")
01448         tnm = "mpower";
01449     }
01450   else if (len == 1)
01451     {
01452       switch (nm[0])
01453         {
01454         case '~':
01455         case '!':
01456           tnm = "not";
01457           break;
01458 
01459         case '\'':
01460           tnm = "ctranspose";
01461           break;
01462 
01463         case '+':
01464           tnm = "plus";
01465           break;
01466 
01467         case '-':
01468           tnm = "minus";
01469           break;
01470 
01471         case '*':
01472           tnm = "mtimes";
01473           break;
01474 
01475         case '/':
01476           tnm = "mrdivide";
01477           break;
01478 
01479         case '^':
01480           tnm = "mpower";
01481           break;
01482 
01483         case '\\':
01484           tnm = "mldivide";
01485           break;
01486 
01487         case '<':
01488           tnm = "lt";
01489           break;
01490 
01491         case '>':
01492           tnm = "gt";
01493           break;
01494 
01495         case '&':
01496           tnm = "and";
01497           break;
01498 
01499         case '|':
01500           tnm = "or";
01501           break;
01502         }
01503     }
01504 
01505   octave_value f = symbol_table::find_function (tnm, octave_value_list (),
01506                                                 local_funcs);
01507 
01508   octave_function *fptr = f.function_value (true);
01509 
01510   // Here we are just looking to see if FCN is a method or constructor
01511   // for any class.
01512   if (local_funcs && fptr
01513       && (fptr->is_subfunction () || fptr->is_private_function ()
01514           || fptr->is_class_constructor ()))
01515     {
01516       // Locally visible function.
01517       retval = octave_value (new octave_fcn_handle (f, tnm));
01518     }
01519   else
01520     {
01521       // Globally visible (or no match yet). Query overloads.
01522       std::list<std::string> classes = load_path::overloads (tnm);
01523       bool any_match = fptr != 0 || classes.size () > 0;
01524       if (! any_match)
01525         {
01526           // No match found, try updating load_path and query classes again.
01527           load_path::update ();
01528           classes = load_path::overloads (tnm);
01529           any_match = classes.size () > 0;
01530         }
01531 
01532       if (any_match)
01533         {
01534           octave_fcn_handle *fh = new octave_fcn_handle (f, tnm);
01535           retval = fh;
01536 
01537           for (std::list<std::string>::iterator iter = classes.begin ();
01538                iter != classes.end (); iter++)
01539             {
01540               std::string class_name = *iter;
01541               octave_value fmeth = symbol_table::find_method (tnm, class_name);
01542 
01543               bool is_builtin = false;
01544               for (int i = 0; i < btyp_num_types; i++)
01545                 {
01546                   // FIXME: Too slow? Maybe binary lookup?
01547                   if (class_name == btyp_class_name[i])
01548                     {
01549                       is_builtin = true;
01550                       fh->set_overload (static_cast<builtin_type_t> (i), fmeth);
01551                     }
01552                 }
01553 
01554               if (! is_builtin)
01555                 fh->set_overload (class_name, fmeth);
01556             }
01557         }
01558       else
01559         error ("@%s: no function and no method found", tnm.c_str ());
01560     }
01561 
01562   return retval;
01563 }
01564 
01565 /*
01566 %!test
01567 %! x = {".**", "power";
01568 %!      ".'", "transpose";
01569 %!      ".+", "plus";
01570 %!      ".-", "minus";
01571 %!      ".*", "times";
01572 %!      "./", "rdivide";
01573 %!      ".^", "power";
01574 %!      ".\\", "ldivide";
01575 %!      "<=", "le";
01576 %!      "==", "eq";
01577 %!      ">=", "ge";
01578 %!      "~=", "ne";
01579 %!      "!=", "ne";
01580 %!      "**", "mpower";
01581 %!      "~", "not";
01582 %!      "!", "not";
01583 %!      "\'", "ctranspose";
01584 %!      "+", "plus";
01585 %!      "-", "minus";
01586 %!      "*", "mtimes";
01587 %!      "/", "mrdivide";
01588 %!      "^", "mpower";
01589 %!      "\\", "mldivide";
01590 %!      "<", "lt";
01591 %!      ">", "gt";
01592 %!      "&", "and";
01593 %!      "|", "or"};
01594 %! for i = 1:rows (x)
01595 %!   assert (functions (str2func (x{i,1})).function, x{i,2})
01596 %! endfor
01597 */
01598 
01599 DEFUN (functions, args, ,
01600   "-*- texinfo -*-\n\
01601 @deftypefn {Built-in Function} {} functions (@var{fcn_handle})\n\
01602 Return a struct containing information about the function handle\n\
01603 @var{fcn_handle}.\n\
01604 @end deftypefn")
01605 {
01606   octave_value retval;
01607 
01608   if (args.length () == 1)
01609     {
01610       octave_fcn_handle *fh = args(0).fcn_handle_value ();
01611 
01612       if (! error_state)
01613         {
01614           octave_function *fcn = fh ? fh->function_value () : 0;
01615 
01616           if (fcn)
01617             {
01618               octave_scalar_map m;
01619 
01620               std::string fh_nm = fh->fcn_name ();
01621 
01622               if (fh_nm == octave_fcn_handle::anonymous)
01623                 {
01624                   std::ostringstream buf;
01625                   fh->print_raw (buf);
01626                   m.setfield ("function", buf.str ());
01627 
01628                   m.setfield ("type", "anonymous");
01629                 }
01630               else
01631                 {
01632                   m.setfield ("function", fh_nm);
01633 
01634                   if (fcn->is_subfunction ())
01635                     {
01636                       m.setfield ("type", "subfunction");
01637                       Cell parentage (dim_vector (1, 2));
01638                       parentage.elem(0) = fh_nm;
01639                       parentage.elem(1) = fcn->parent_fcn_name ();
01640                       m.setfield ("parentage", octave_value (parentage));
01641                     }
01642                   else if (fcn->is_private_function ())
01643                     m.setfield ("type", "private");
01644                   else if (fh->is_overloaded ())
01645                     m.setfield ("type", "overloaded");
01646                   else
01647                     m.setfield ("type", "simple");
01648                 }
01649 
01650               std::string nm = fcn->fcn_file_name ();
01651 
01652               if (fh_nm == octave_fcn_handle::anonymous)
01653                 {
01654                   m.setfield ("file", nm);
01655 
01656                   octave_user_function *fu = fh->user_function_value ();
01657 
01658                   std::list<symbol_table::symbol_record> vars
01659                     = symbol_table::all_variables (fu->scope (), 0);
01660 
01661                   size_t varlen = vars.size ();
01662 
01663                   if (varlen > 0)
01664                     {
01665                       octave_scalar_map ws;
01666                       for (std::list<symbol_table::symbol_record>::const_iterator p = vars.begin ();
01667                            p != vars.end (); p++)
01668                         {
01669                           ws.assign (p->name (), p->varval (0));
01670                         }
01671 
01672                       m.setfield ("workspace", ws);
01673                     }
01674                 }
01675               else if (fcn->is_user_function () || fcn->is_user_script ())
01676                 {
01677                   octave_function *fu = fh->function_value ();
01678                   m.setfield ("file", fu->fcn_file_name ());
01679                 }
01680               else
01681                 m.setfield ("file", "");
01682 
01683               retval = m;
01684             }
01685           else
01686             error ("functions: FCN_HANDLE is not a valid function handle object");
01687         }
01688       else
01689         error ("functions: FCN_HANDLE argument must be a function handle object");
01690     }
01691   else
01692     print_usage ();
01693 
01694   return retval;
01695 }
01696 
01697 DEFUN (func2str, args, ,
01698   "-*- texinfo -*-\n\
01699 @deftypefn {Built-in Function} {} func2str (@var{fcn_handle})\n\
01700 Return a string containing the name of the function referenced by\n\
01701 the function handle @var{fcn_handle}.\n\
01702 @end deftypefn")
01703 {
01704   octave_value retval;
01705 
01706   if (args.length () == 1)
01707     {
01708       octave_fcn_handle *fh = args(0).fcn_handle_value ();
01709 
01710       if (! error_state && fh)
01711         {
01712           std::string fh_nm = fh->fcn_name ();
01713 
01714           if (fh_nm == octave_fcn_handle::anonymous)
01715             {
01716               std::ostringstream buf;
01717 
01718               fh->print_raw (buf);
01719 
01720               retval = buf.str ();
01721             }
01722           else
01723             retval = fh_nm;
01724         }
01725       else
01726         error ("func2str: FCN_HANDLE must be a valid function handle");
01727     }
01728   else
01729     print_usage ();
01730 
01731   return retval;
01732 }
01733 
01734 DEFUN (str2func, args, ,
01735   "-*- texinfo -*-\n\
01736 @deftypefn  {Built-in Function} {} str2func (@var{fcn_name})\n\
01737 @deftypefnx {Built-in Function} {} str2func (@var{fcn_name}, \"global\")\n\
01738 Return a function handle constructed from the string @var{fcn_name}.\n\
01739 If the optional \"global\" argument is passed, locally visible functions\n\
01740 are ignored in the lookup.\n\
01741 @end deftypefn")
01742 {
01743   octave_value retval;
01744   int nargin = args.length ();
01745 
01746   if (nargin == 1 || nargin == 2)
01747     {
01748       std::string nm = args(0).string_value ();
01749 
01750       if (! error_state)
01751         retval = make_fcn_handle (nm, nargin != 2);
01752       else
01753         error ("str2func: FCN_NAME must be a string");
01754     }
01755   else
01756     print_usage ();
01757 
01758   return retval;
01759 }
01760 
01761 /*
01762 
01763 %!function y = __testrecursionfunc (f, x, n)
01764 %!  if (nargin < 3)
01765 %!    n = 0;
01766 %!  endif
01767 %!  if (n > 2)
01768 %!    y = f (x);
01769 %!  else
01770 %!    n++;
01771 %!    y = __testrecursionfunc (@(x) f(2*x), x, n);
01772 %!  endif
01773 %!endfunction
01774 %!
01775 %!assert (__testrecursionfunc (@(x) x, 1), 8)
01776 
01777 */
01778 
01779 DEFUN (is_function_handle, args, ,
01780   "-*- texinfo -*-\n\
01781 @deftypefn {Built-in Function} {} is_function_handle (@var{x})\n\
01782 Return true if @var{x} is a function handle.\n\
01783 @seealso{isa, typeinfo, class}\n\
01784 @end deftypefn")
01785 {
01786   octave_value retval;
01787 
01788   int nargin = args.length ();
01789 
01790   if (nargin == 1)
01791     retval = args(0).is_function_handle ();
01792   else
01793     print_usage ();
01794 
01795   return retval;
01796 }
01797 
01798 /*
01799 %!shared fh
01800 %! fh = @(x) x;
01801 
01802 %!assert (is_function_handle (fh))
01803 %!assert (! is_function_handle ({fh}))
01804 %!assert (! is_function_handle (1))
01805 %!error is_function_handle ();
01806 %!error is_function_handle (1, 2);
01807 
01808 */
01809 
01810 
01811 octave_fcn_binder::octave_fcn_binder (const octave_value& f,
01812                                       const octave_value& root,
01813                                       const octave_value_list& templ,
01814                                       const std::vector<int>& mask,
01815                                       int exp_nargin)
01816 : octave_fcn_handle (f), root_handle (root), arg_template (templ),
01817   arg_mask (mask), expected_nargin (exp_nargin)
01818 {
01819 }
01820 
01821 octave_fcn_handle *
01822 octave_fcn_binder::maybe_binder (const octave_value& f)
01823 {
01824   octave_fcn_handle *retval = 0;
01825 
01826   octave_user_function *usr_fcn = f.user_function_value (false);
01827   tree_parameter_list *param_list = usr_fcn ? usr_fcn->parameter_list () : 0;
01828 
01829   // Verify that the body is a single expression (always true in theory).
01830 
01831   tree_statement_list *cmd_list = usr_fcn ? usr_fcn->body () : 0;
01832   tree_expression *body_expr = (cmd_list->length () == 1
01833                                 ? cmd_list->front ()->expression () : 0);
01834 
01835 
01836   if (body_expr && body_expr->is_index_expression ()
01837       && ! (param_list && param_list->takes_varargs ()))
01838     {
01839       // It's an index expression.
01840       tree_index_expression *idx_expr = dynamic_cast<tree_index_expression *> (body_expr);
01841       tree_expression *head_expr = idx_expr->expression ();
01842       std::list<tree_argument_list *> arg_lists = idx_expr->arg_lists ();
01843       std::string type_tags = idx_expr->type_tags ();
01844 
01845       if (type_tags.length () == 1 && type_tags[0] == '('
01846           && head_expr->is_identifier ())
01847         {
01848           assert (arg_lists.size () == 1);
01849 
01850           // It's a single index expression: a(x,y,....)
01851           tree_identifier *head_id = dynamic_cast<tree_identifier *> (head_expr);
01852           tree_argument_list *arg_list = arg_lists.front ();
01853 
01854           // Build a map of input params to their position.
01855           std::map<std::string, int> arginmap;
01856           int npar = 0;
01857 
01858           if (param_list)
01859             {
01860               for (tree_parameter_list::iterator it = param_list->begin ();
01861                    it != param_list->end (); ++it, ++npar)
01862                 {
01863                   tree_decl_elt *elt = *it;
01864                   tree_identifier *id = elt ? elt->ident () : 0;
01865                   if (id && ! id->is_black_hole ())
01866                      arginmap[id->name ()] = npar;
01867                 }
01868             }
01869 
01870           if (arg_list && arg_list->length () > 0)
01871             {
01872               bool bad = false;
01873               int nargs = arg_list->length ();
01874               octave_value_list arg_template (nargs);
01875               std::vector<int> arg_mask (nargs);
01876 
01877               // Verify that each argument is either a named param, a constant, or a defined identifier.
01878               int iarg = 0;
01879               for (tree_argument_list::iterator it = arg_list->begin ();
01880                    it != arg_list->end (); ++it, ++iarg)
01881                 {
01882                   tree_expression *elt = *it;
01883                   if (elt && elt->is_constant ())
01884                     {
01885                       arg_template(iarg) = elt->rvalue1 ();
01886                       arg_mask[iarg] = -1;
01887                     }
01888                   else if (elt && elt->is_identifier ())
01889                     {
01890                       tree_identifier *elt_id = dynamic_cast<tree_identifier *> (elt);
01891                       if (arginmap.find (elt_id->name ()) != arginmap.end ())
01892                         {
01893                           arg_mask[iarg] = arginmap[elt_id->name ()];
01894                         }
01895                       else if (elt_id->is_defined ())
01896                         {
01897                           arg_template(iarg) = elt_id->rvalue1 ();
01898                           arg_mask[iarg] = -1;
01899                         }
01900                       else
01901                         {
01902                           bad = true;
01903                           break;
01904                         }
01905                     }
01906                   else
01907                     {
01908                       bad = true;
01909                       break;
01910                     }
01911                 }
01912 
01913               octave_value root_val;
01914 
01915               if (! bad)
01916                 {
01917                   // If the head is a value, use it as root.
01918                   if (head_id->is_defined ())
01919                      root_val = head_id->rvalue1 ();
01920                   else
01921                     {
01922                       // It's a name.
01923                       std::string head_name = head_id->name ();
01924                       // Function handles can't handle legacy dispatch, so
01925                       // we make sure it's not defined.
01926                       if (symbol_table::get_dispatch (head_name).size () > 0)
01927                          bad = true;
01928                       else
01929                         {
01930                           // Simulate try/catch.
01931                           unwind_protect frame;
01932                           interpreter_try (frame);
01933 
01934                           root_val = make_fcn_handle (head_name);
01935                           if (error_state)
01936                              bad = true;
01937                         }
01938                     }
01939                 }
01940 
01941               if (! bad)
01942                 {
01943                   // Stash proper name tags.
01944                   std::list<string_vector> arg_names = idx_expr->arg_names ();
01945                   assert (arg_names.size () == 1);
01946                   arg_template.stash_name_tags (arg_names.front ());
01947 
01948                   retval = new octave_fcn_binder (f, root_val, arg_template,
01949                                                   arg_mask, npar);
01950                 }
01951             }
01952         }
01953     }
01954 
01955   if (! retval)
01956      retval = new octave_fcn_handle (f, octave_fcn_handle::anonymous);
01957 
01958   return retval;
01959 }
01960 
01961 octave_value_list
01962 octave_fcn_binder::do_multi_index_op (int nargout,
01963                                       const octave_value_list& args)
01964 {
01965   return do_multi_index_op (nargout, args, 0);
01966 }
01967 
01968 octave_value_list
01969 octave_fcn_binder::do_multi_index_op (int nargout,
01970                                       const octave_value_list& args,
01971                                       const std::list<octave_lvalue>* lvalue_list)
01972 {
01973   octave_value_list retval;
01974 
01975   if (args.length () == expected_nargin)
01976     {
01977       for (int i = 0; i < arg_template.length (); i++)
01978         {
01979           int j = arg_mask[i];
01980           if (j >= 0)
01981              arg_template(i) = args(j); // May force a copy...
01982         }
01983 
01984       // Make a shallow copy of arg_template, to ensure consistency throughout the following
01985       // call even if we happen to get back here.
01986       octave_value_list tmp (arg_template);
01987       retval = root_handle.do_multi_index_op (nargout, tmp, lvalue_list);
01988     }
01989   else
01990      retval = octave_fcn_handle::do_multi_index_op (nargout, args, lvalue_list);
01991 
01992   return retval;
01993 }
01994 
01995 /*
01996 %!function r = __f (g, i)
01997 %!  r = g(i);
01998 %!endfunction
01999 %!test
02000 %! x = [1,2;3,4];
02001 %! assert (__f (@(i) x(:,i), 1), [1;3]);
02002 */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines