GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ov-fcn-handle.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2003-2023 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <istream>
31 #include <list>
32 #include <ostream>
33 #include <sstream>
34 #include <string>
35 #include <vector>
36 
37 #include "file-ops.h"
38 #include "oct-locbuf.h"
39 
40 #include "defaults.h"
41 #include "defun.h"
42 #include "error.h"
43 #include "errwarn.h"
44 #include "file-stat.h"
45 #include "input.h"
46 #include "interpreter-private.h"
47 #include "interpreter.h"
48 #include "load-path.h"
49 #include "oct-env.h"
50 #include "oct-hdf5.h"
51 #include "oct-map.h"
52 #include "ov-base.h"
53 #include "ov-cell.h"
54 #include "ov-fcn-handle.h"
55 #include "ov-usr-fcn.h"
56 #include "parse.h"
57 #include "pr-output.h"
58 #include "pt-arg-list.h"
59 #include "pt-assign.h"
60 #include "pt-cmd.h"
61 #include "pt-eval.h"
62 #include "pt-exp.h"
63 #include "pt-idx.h"
64 #include "pt-misc.h"
65 #include "pt-pr-code.h"
66 #include "pt-stmt.h"
67 #include "stack-frame.h"
68 #include "syminfo.h"
69 #include "symscope.h"
70 #include "unwind-prot.h"
71 #include "variables.h"
72 
73 #include "byte-swap.h"
74 #include "ls-ascii-helper.h"
75 #include "ls-hdf5.h"
76 #include "ls-oct-text.h"
77 #include "ls-oct-binary.h"
78 #include "ls-utils.h"
79 
80 
82  "function handle",
83  "function_handle");
84 
85 const std::string octave_fcn_handle::anonymous ("@<anonymous>");
86 
88 
90 {
91 public:
92 
93  invalid_fcn_handle (void) : base_fcn_handle ("<invalid>") { }
94 
96 
97  ~invalid_fcn_handle (void) = default;
98 
99  invalid_fcn_handle * clone (void) const
100  {
101  return new invalid_fcn_handle (*this);
102  }
103 
104  std::string type (void) const { return "<invalid>"; }
105 
106  octave_value_list call (int nargout, const octave_value_list& args);
107 };
108 
109 // Create a handle to an unnamed internal function. There will be no
110 // way to save and reload it. See, for example, the F__fltk_check__
111 // function in __init_fltk__.cc.
112 
114 {
115 public:
116 
118  : base_fcn_handle ("<internal>"), m_fcn (fcn)
119  { }
120 
122 
123  ~internal_fcn_handle (void) = default;
124 
125  internal_fcn_handle * clone (void) const
126  {
127  return new internal_fcn_handle (*this);
128  }
129 
130  std::string type (void) const { return "<internal>"; }
131 
132  bool is_internal (void) const { return true; }
133 
134  octave_value_list call (int nargout, const octave_value_list& args);
135 
136  // FIXME: These must go away. They don't do the right thing for
137  // scoping or overloads.
139  {
140  return m_fcn.function_value ();
141  }
142 
144  {
145  return m_fcn.user_function_value ();
146  }
147 
148  octave_value fcn_val (void) { return m_fcn; }
149 
150  // Should be const.
151  octave_scalar_map info (void);
152 
153  friend bool is_equal_to (const internal_fcn_handle& fh1,
154  const internal_fcn_handle& fh2);
155 
156 private:
157 
159 };
160 
162 {
163 public:
164 
165  // FIXME: octaveroot is temporary information used when loading
166  // handles. Can we avoid using it in the constructor?
167 
168  simple_fcn_handle (const std::string& name = "",
169  const std::string& file = "",
170  const std::string& /*octaveroot*/ = "")
171  : base_fcn_handle (name, file), m_fcn ()
172  { }
173 
174  simple_fcn_handle (const octave_value& fcn, const std::string& name)
175  : base_fcn_handle (name), m_fcn (fcn)
176  {
177  if (m_fcn.is_defined ())
178  {
179  octave_function *oct_fcn = m_fcn.function_value ();
180 
181  if (oct_fcn)
182  m_file = oct_fcn->fcn_file_name ();
183  }
184  }
185 
187 
188  ~simple_fcn_handle (void) = default;
189 
190  simple_fcn_handle * clone (void) const
191  {
192  return new simple_fcn_handle (*this);
193  }
194 
195  std::string type (void) const { return "simple"; }
196 
197  bool is_simple (void) const { return true; }
198 
199  octave_value_list call (int nargout, const octave_value_list& args);
200 
201  // FIXME: These must go away. They don't do the right thing for
202  // scoping or overloads.
204 
206 
207  octave_value fcn_val (void);
208 
209  // Should be const.
210  octave_scalar_map info (void);
211 
212  bool save_ascii (std::ostream& os);
213 
214  bool load_ascii (std::istream& is);
215 
216  bool save_binary (std::ostream& os, bool save_as_floats);
217 
218  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
219 
220  bool save_hdf5 (octave_hdf5_id loc_hid, const char *name,
221  bool save_as_floats);
222 
223  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
224  octave_hdf5_id& type_hid);
225 
226  void print_raw (std::ostream& os, bool pr_as_read_syntax,
227  int current_print_indent_level) const;
228 
229  friend bool is_equal_to (const simple_fcn_handle& fh1,
230  const simple_fcn_handle& fh2);
231 
232 private:
233 
235 };
236 
238 {
239 public:
240 
241  // FIXME: octaveroot is temporary information used when loading
242  // handles. Can we avoid using it in the constructor?
243 
244  scoped_fcn_handle (const std::string& name = "",
245  const std::string& file = "",
246  const std::string& /*octaveroot*/ = "")
247  : base_fcn_handle (name, file)
248  { }
249 
250  scoped_fcn_handle (const octave_value& fcn, const std::string& name,
251  const std::list<std::string>& parentage);
252 
254 
255  ~scoped_fcn_handle (void) = default;
256 
257  scoped_fcn_handle * clone (void) const
258  {
259  return new scoped_fcn_handle (*this);
260  }
261 
262  std::string type (void) const { return "scopedfunction"; }
263 
264  bool is_scoped (void) const { return true; }
265 
266  octave_value_list call (int nargout, const octave_value_list& args);
267 
268  // FIXME: These must go away. They don't do the right thing for
269  // scoping or overloads.
271  {
272  return m_fcn.function_value ();
273  }
274 
276  {
277  return m_fcn.user_function_value ();
278  }
279 
280  octave_value fcn_val (void) { return m_fcn; }
281 
282  // Should be const.
283  octave_scalar_map info (void);
284 
285  bool save_ascii (std::ostream& os);
286 
287  bool load_ascii (std::istream& is);
288 
289  bool save_binary (std::ostream& os, bool save_as_floats);
290 
291  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
292 
293  bool save_hdf5 (octave_hdf5_id loc_id, const char *name,
294  bool save_as_floats);
295 
296  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
297  octave_hdf5_id& type_hid);
298 
299  void print_raw (std::ostream&, bool pr_as_read_syntax,
300  int current_print_indent_level) const;
301 
302  friend bool is_equal_to (const scoped_fcn_handle& fh1,
303  const scoped_fcn_handle& fh2);
304 
305 protected:
306 
307  void find_function (void);
308 
309  // The function we are handling.
311 
312  // List of parent function names. The first element is the name of
313  // m_fcn.
314  std::list<std::string> m_parentage;
315 };
316 
318 {
319 public:
320 
321  // FIXME: octaveroot is temporary information used when loading
322  // handles. Can we avoid using it in the constructor?
323 
324  base_nested_fcn_handle (const std::string& name = "",
325  const std::string& file = "",
326  const std::string& /*octaveroot*/ = "")
327  : base_fcn_handle (name, file)
328  { }
329 
330  base_nested_fcn_handle (const octave_value& fcn, const std::string& name)
331  : base_fcn_handle (name), m_fcn (fcn)
332  { }
333 
334  std::string type (void) const { return "nested"; }
335 
337 
338  bool is_nested (void) const { return true; }
339 
340  // FIXME: These must go away. They don't do the right thing for
341  // scoping or overloads.
343  {
344  return m_fcn.function_value ();
345  }
346 
348  {
349  return m_fcn.user_function_value ();
350  }
351 
352  octave_value fcn_val (void) { return m_fcn; }
353 
354  virtual octave_value workspace (void) const = 0;
355 
356  // Should be const.
357  octave_scalar_map info (void);
358 
359  bool save_ascii (std::ostream& os);
360 
361  bool load_ascii (std::istream& is);
362 
363  bool save_binary (std::ostream& os, bool save_as_floats);
364 
365  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
366 
367  bool save_hdf5 (octave_hdf5_id loc_id, const char *name,
368  bool save_as_floats);
369 
370  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
371  octave_hdf5_id& type_hid);
372 
373  void print_raw (std::ostream&, bool pr_as_read_syntax,
374  int current_print_indent_level) const;
375 
376 protected:
377 
378  // The function we are handling.
380 };
381 
383 {
384 public:
385 
386  // FIXME: octaveroot is temporary information used when loading
387  // handles. Can we avoid using it in the constructor?
388 
389  nested_fcn_handle (const std::string& name = "",
390  const std::string& file = "",
391  const std::string& octaveroot = "")
392  : base_nested_fcn_handle (name, file, octaveroot)
393  { }
394 
395  nested_fcn_handle (const octave_value& fcn, const std::string& name,
396  const std::shared_ptr<stack_frame>& stack_context)
398  {
399  if (m_stack_context)
400  m_stack_context->mark_closure_context ();
401  }
402 
404 
405  ~nested_fcn_handle (void) = default;
406 
408 
409  bool is_nested (const std::shared_ptr<stack_frame>& frame) const
410  {
411  return frame == m_stack_context;
412  }
413 
414  nested_fcn_handle * clone (void) const
415  {
416  return new nested_fcn_handle (*this);
417  }
418 
420 
421  octave_value_list call (int nargout, const octave_value_list& args);
422 
423  octave_value workspace (void) const;
424 
425  friend bool is_equal_to (const nested_fcn_handle& fh1,
426  const nested_fcn_handle& fh2);
427 
428  std::shared_ptr<stack_frame> stack_context (void) const
429  {
430  return m_stack_context;
431  }
432 
433 protected:
434 
435  // Pointer to closure stack frames.
436  std::shared_ptr<stack_frame> m_stack_context;
437 };
438 
440 {
441 public:
442 
444  : base_nested_fcn_handle (nfh), m_stack_context (nfh.stack_context ())
445  { }
446 
448 
449  ~weak_nested_fcn_handle (void) = default;
450 
452  {
453  return new weak_nested_fcn_handle (*this);
454  }
455 
456  bool is_weak_nested (void) const { return true; }
457 
458  octave_value_list call (int nargout, const octave_value_list& args);
459 
460  octave_value workspace (void) const;
461 
462  friend bool is_equal_to (const weak_nested_fcn_handle& fh1,
463  const weak_nested_fcn_handle& fh2);
464 
465 protected:
466 
467  // Pointer to closure stack frames.
468  std::weak_ptr<stack_frame> m_stack_context;
469 };
470 
472 {
473 public:
474 
475  // FIXME: octaveroot is temporary information used when loading
476  // handles. Can we avoid using it in the constructor?
477 
478  class_simple_fcn_handle (const std::string& name,
479  const std::string& file,
480  const std::string& /*octaveroot*/)
481  : base_fcn_handle (name, file)
482  { }
483 
484  // FIXME: is the method name supposed to be just the method name or
485  // also contain the object name?
486 
487  class_simple_fcn_handle (const std::string& class_nm,
488  const std::string& meth_nm);
489 
491  const std::string& class_nm,
492  const std::string& meth_nm);
493 
494  class_simple_fcn_handle (const octave_value& obj, const octave_value& fcn,
495  const std::string& class_nm,
496  const std::string& meth_nm);
497 
499 
500  ~class_simple_fcn_handle (void) = default;
501 
503  {
504  return new class_simple_fcn_handle (*this);
505  }
506 
507  std::string type (void) const { return "classsimple"; }
508 
509  bool is_class_simple (void) const { return true; }
510 
511  octave_value_list call (int nargout, const octave_value_list& args);
512 
513  // FIXME: These must go away. They don't do the right thing for
514  // scoping or overloads.
516  {
517  // FIXME: Shouldn't the lookup rules here match those used in the
518  // call method?
519 
520  if (m_fcn.is_defined ())
521  return m_fcn.function_value ();
522 
523  symbol_table& symtab = __get_symbol_table__ ();
524 
525  // FIXME: is caching the correct thing to do?
526  // Cache this value so that the pointer will be valid as long as the
527  // function handle object is valid.
528 
529  // FIXME: This should probably dispatch to the respective class method.
530  // But that breaks if a function handle is used in a class method with
531  // e.g. bsxfun with arguments of a different class (see bug #59661).
532  // m_fcn = symtab.find_method (m_name, m_dispatch_class);
534 
535  return m_fcn.is_defined () ? m_fcn.function_value () : nullptr;
536  }
537 
539  {
540  return m_fcn.user_function_value ();
541  }
542 
543  octave_value fcn_val (void) { return m_fcn; }
544 
545  // Should be const.
546  octave_scalar_map info (void);
547 
548  std::string dispatch_class (void) const { return m_dispatch_class; }
549 
550  bool save_ascii (std::ostream& os);
551 
552  bool load_ascii (std::istream& is);
553 
554  bool save_binary (std::ostream& os, bool save_as_floats);
555 
556  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
557 
558  bool save_hdf5 (octave_hdf5_id loc_id, const char *name,
559  bool save_as_floats);
560 
561  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
562  octave_hdf5_id& type_hid);
563 
564  void print_raw (std::ostream&, bool pr_as_read_syntax,
565  int current_print_indent_level) const;
566 
567  friend bool is_equal_to (const class_simple_fcn_handle& fh1,
568  const class_simple_fcn_handle& fh2);
569 
570 protected:
571 
572  // The object containing the method we are handing.
574 
575  // The method we are handling.
577 
578  // Name of the class that m_fcn belongs to.
579  std::string m_dispatch_class;
580 };
581 
582 // Handles to anonymous functions are similar to handles to nested
583 // functions. If they are created in a context that contains nested
584 // functions, then they store a link to the parent call stack frames
585 // that are active when they are created. These call stack frames
586 // (closure frames) provide access to variables needed by any nested
587 // functions that are called from the anonymous function. Anonymous
588 // functions also store a list of values from their parent scope
589 // corresponding to the symbols in the anonymous function. This list
590 // of values captures the variable values that are visible in the
591 // scope where they are created.
592 //
593 // Note that because handles to anonymous and nested functions capture
594 // call stack frames when they are created, they will cause deletion
595 // of the values in those frames to be deferred until the handles to
596 // the anonymous or nested functions are deleted.
597 //
598 // Would it be possible to avoid storing the closure frames for
599 // handles to anonymous functions if we can determine that the
600 // anonymous function has no unbound variables (or parameters, which
601 // could be handles to nested functions?) or if it is not created in a
602 // context that contains nested functions?
603 //
604 // Would it be possible to define anonymous functions as a special
605 // type of nested function object that also has an variable
606 // initialization list associated with it?
607 
609 {
610 public:
611 
612  static const std::string anonymous;
613 
614  // Setting NAME here is a bit of a kluge to cope with a bad choice
615  // made to append the number of local variables to the @<anonymous>
616  // tag in the binary file format. See also the save_binary and
617  // load_binary functions.
618 
619  base_anonymous_fcn_handle (const std::string& name = "")
620  : base_fcn_handle (name)
621  { }
622 
624  const stack_frame::local_vars_map& local_vars)
625  : base_fcn_handle (anonymous), m_fcn (fcn), m_local_vars (local_vars)
626  { }
627 
629 
630  ~base_anonymous_fcn_handle (void) = default;
631 
632  std::string type (void) const { return "anonymous"; }
633 
634  bool is_anonymous (void) const { return true; }
635 
636  // FIXME: These must go away. They don't do the right thing for
637  // scoping or overloads.
639  {
640  return m_fcn.function_value ();
641  }
642 
644  {
645  return m_fcn.user_function_value ();
646  }
647 
648  octave_value fcn_val (void) { return m_fcn; }
649 
650  virtual octave_value workspace (void) const = 0;
651 
652  // Should be const.
653  octave_scalar_map info (void);
654 
655  bool save_ascii (std::ostream& os);
656 
657  bool load_ascii (std::istream& is);
658 
659  bool save_binary (std::ostream& os, bool save_as_floats);
660 
661  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
662 
663  bool save_hdf5 (octave_hdf5_id loc_id, const char *name,
664  bool save_as_floats);
665 
666  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
667  octave_hdf5_id& type_hid);
668 
669  void print_raw (std::ostream&, bool pr_as_read_syntax,
670  int current_print_indent_level) const;
671 
672  // Anonymous function handles are printed without a newline.
673  bool print_as_scalar (void) const { return false; }
674 
675  bool parse (const std::string& fcn_text);
676 
677 protected:
678 
679  // The function we are handling.
681 
682  // List of captured variable values for anonymous fucntions.
684 };
685 
687 {
688 public:
689 
691 
692  // Setting NAME here is a bit of a kluge to cope with a bad choice
693  // made to append the number of local variables to the @<anonymous>
694  // tag in the binary file format. See also the save_binary and
695  // load_binary functions.
696 
697  anonymous_fcn_handle (const std::string& name = "")
699  { }
700 
702  const stack_frame::local_vars_map& local_vars,
703  const std::shared_ptr<stack_frame>& stack_context = std::shared_ptr<stack_frame> ());
704 
706 
707  ~anonymous_fcn_handle (void) = default;
708 
710  {
711  return new anonymous_fcn_handle (*this);
712  }
713 
715 
716  octave_value_list call (int nargout, const octave_value_list& args);
717 
718  octave_value workspace (void) const;
719 
720  friend bool is_equal_to (const anonymous_fcn_handle& fh1,
721  const anonymous_fcn_handle& fh2);
722 
723  std::shared_ptr<stack_frame> stack_context (void) const
724  {
725  return m_stack_context;
726  }
727 
728 protected:
729 
730  // Pointer to closure stack frames.
731  std::shared_ptr<stack_frame> m_stack_context;
732 };
733 
735 {
736 public:
737 
739 
741  : base_anonymous_fcn_handle (afh), m_stack_context (afh.stack_context ())
742  { }
743 
745 
746  ~weak_anonymous_fcn_handle (void) = default;
747 
749  {
750  return new weak_anonymous_fcn_handle (*this);
751  }
752 
753  bool is_weak_anonymous (void) const { return true; }
754 
755  octave_value_list call (int nargout, const octave_value_list& args);
756 
757  octave_value workspace (void) const;
758 
759  friend bool is_equal_to (const weak_anonymous_fcn_handle& fh1,
760  const weak_anonymous_fcn_handle& fh2);
761 
762 protected:
763 
764  // Pointer to closure stack frames.
765  std::weak_ptr<stack_frame> m_stack_context;
766 };
767 
768 extern bool is_equal_to (const anonymous_fcn_handle& fh1,
769  const anonymous_fcn_handle& fh2);
770 
771 static void err_invalid_fcn_handle (const std::string& name)
772 {
773  error ("invalid function handle, unable to find function for @%s",
774  name.c_str ());
775 }
776 
778 {
779  std::string type_str = type ();
780  error ("invalid conversion from %s handle to weak nestead handle",
781  type_str.c_str ());
782 }
783 
785 {
786  std::string type_str = type ();
787  error ("invalid conversion from %s handle to weak anonymous handle",
788  type_str.c_str ());
789 }
790 
792 base_fcn_handle::subsref (const std::string& type,
793  const std::list<octave_value_list>& idx,
794  int nargout)
795 {
796  octave_value_list retval;
797 
798  switch (type[0])
799  {
800  case '(':
801  {
802  int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout;
803 
804  retval = call (tmp_nargout, idx.front ());
805  }
806  break;
807 
808  case '{':
809  case '.':
810  error ("function handle cannot be indexed with %c", type[0]);
811 
812  default:
813  panic_impossible ();
814  }
815 
816  // FIXME: perhaps there should be an
817  // octave_value_list::next_subsref member function? See also
818  // octave_builtin::subsref.
819 
820  if (idx.size () > 1)
821  retval = retval(0).next_subsref (nargout, type, idx);
822 
823  return retval;
824 }
825 
827 base_fcn_handle::convert_to_str_internal (bool, bool, char type) const
828 {
829  std::ostringstream buf;
830  print_raw (buf, true, 0);
831  return octave_value (buf.str (), type);
832 }
833 
834 bool
836 {
837  unimplemented ("save", "text");
838 
839  return true;
840 }
841 
842 bool
844 {
845  unimplemented ("load", "text");
846 
847  return true;
848 }
849 
850 bool
851 base_fcn_handle::save_binary (std::ostream&, bool)
852 {
853  unimplemented ("save", "binary");
854 
855  return true;
856 }
857 
858 bool
860 {
861  unimplemented ("load", "binary");
862 
863  return true;
864 }
865 
866 bool
868 {
869  unimplemented ("save", "hdf5");
870 
871  return true;
872 }
873 
874 bool
876 {
877  unimplemented ("load", "hdf5");
878 
879  return true;
880 }
881 
882 void base_fcn_handle::warn_load (const char *file_type) const
883 {
884  std::string obj_type = type ();
885 
887  ("Octave:load-save-unavailable",
888  "%s: loading %s files not available in this version of Octave",
889  obj_type.c_str (), file_type);
890 }
891 
892 void base_fcn_handle::warn_save (const char *file_type) const
893 {
894  std::string obj_type = type ();
895 
897  ("Octave:load-save-unavailable",
898  "%s: saving %s files not available in this version of Octave",
899  obj_type.c_str (), file_type);
900 }
901 
902 void base_fcn_handle::unimplemented (const char *op, const char *fmt) const
903 {
904  std::string htype = type ();
905 
906  warning ("%s for %s handles with %s format is not implemented",
907  op, htype.c_str (), fmt);
908 }
909 
912 {
913  error ("invalid call to invalid function handle");
914 }
915 
918 {
919  interpreter& interp = __get_interpreter__ ();
920 
921  return interp.feval (m_fcn, args, nargout);
922 }
923 
925 {
927 
928  m.setfield ("function", fcn_name ());
929  m.setfield ("type", type ());
930  m.setfield ("file", "");
931 
932  return m;
933 }
934 
936  const internal_fcn_handle& fh2)
937 {
938  if (fh1.m_name == fh2.m_name
939  && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
940  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
941  else
942  return false;
943 }
944 
946 simple_fcn_handle::call (int nargout, const octave_value_list& args)
947 {
948  // FIXME: if m_name has a '.' in the name, lookup first component. If
949  // it is a classdef meta object, then build TYPE and IDX arguments and
950  // make a subsref call using them.
951 
952  interpreter& interp = __get_interpreter__ ();
953 
954  octave_value fcn_to_call;
955 
956  // The following code is similar to part of
957  // tree_evaluator::visit_index_expression but simpler because it
958  // handles a more restricted case.
959 
960  symbol_table& symtab = interp.get_symbol_table ();
961 
962  std::size_t pos = m_name.find ('.');
963 
964  if (pos != std::string::npos)
965  {
966  // FIXME: check to see which of these cases actually work in
967  // Octave and Matlab. For the last two, assume handle is
968  // created before object is defined as an object.
969  //
970  // We can have one of
971  //
972  // pkg-list . fcn (args)
973  // pkg-list . cls . meth (args)
974  // class-name . method (args)
975  // class-name . static-method (args)
976  // object . method (args)
977  // object . static-method (args)
978 
979  // Evaluate package elements until we find a function,
980  // classdef object, or classdef_meta object that is not a
981  // package. An object may only appear as the first element,
982  // then it must be followed directly by a function name.
983 
984  std::size_t beg = 0;
985  std::size_t end = pos;
986 
987  std::vector<std::string> idx_elts;
988 
989  while (true)
990  {
991  end = m_name.find ('.', beg);
992 
993  idx_elts.push_back (m_name.substr (beg, end-beg));
994 
995  if (end == std::string::npos)
996  break;
997 
998  beg = end+1;
999  }
1000 
1001  std::size_t n_elts = idx_elts.size ();
1002 
1003  bool have_object = false;
1004  octave_value partial_expr_val;
1005 
1006  // Lazy evaluation. The first element was not known to be defined
1007  // as an object in the scope where the handle was created. See if
1008  // there is a definition in the current scope.
1009 
1010  partial_expr_val = interp.varval (idx_elts[0]);
1011 
1012  if (partial_expr_val.is_defined ())
1013  {
1014  if (! partial_expr_val.is_classdef_object () || n_elts != 2)
1016 
1017  have_object = true;
1018  }
1019  else
1020  partial_expr_val = symtab.find_function (idx_elts[0], ovl ());
1021 
1022  std::string type;
1023  std::list<octave_value_list> arg_list;
1024 
1025  for (std::size_t i = 1; i < n_elts; i++)
1026  {
1027  if (partial_expr_val.is_package ())
1028  {
1029  if (have_object)
1031 
1032  type = ".";
1033  arg_list.push_back (ovl (idx_elts[i]));
1034 
1035  try
1036  {
1037  // Silently ignore extra output values.
1038 
1039  octave_value_list tmp_list
1040  = partial_expr_val.subsref (type, arg_list, 0);
1041 
1042  partial_expr_val
1043  = tmp_list.length () ? tmp_list(0) : octave_value ();
1044 
1045  if (partial_expr_val.is_cs_list ())
1047 
1048  arg_list.clear ();
1049  }
1050  catch (const index_exception&)
1051  {
1053  }
1054  }
1055  else if (have_object || partial_expr_val.is_classdef_meta ())
1056  {
1057  // Object or class name must be the next to the last
1058  // element (it was the previous one, so if this is the
1059  // final element, it should be a classdef method,
1060  // but we'll let the classdef or classdef_meta subsref
1061  // function sort that out.
1062 
1063  if (i != n_elts-1)
1065 
1066  type = ".(";
1067  arg_list.push_back (ovl (idx_elts[i]));
1068  arg_list.push_back (args);
1069 
1070  return partial_expr_val.subsref (type, arg_list, nargout);
1071  }
1072  else
1074  }
1075 
1076  // If we get here, we must have a function to call.
1077 
1078  if (! partial_expr_val.is_function ())
1080 
1081  fcn_to_call = partial_expr_val;
1082  }
1083  else
1084  {
1085  // No "." in the name.
1086 
1087  // Perform function lookup given current arguments. We'll need
1088  // to do this regardless of whether a function was found when
1089  // the handle was created.
1090 
1091  octave_value ov_fcn = symtab.find_function (m_name, args);
1092 
1093  if (m_fcn.is_defined ())
1094  {
1095  // A simple function was found when the handle was created.
1096  // Use that unless we find a class method to override it.
1097 
1098  fcn_to_call = m_fcn;
1099 
1100  if (ov_fcn.is_defined ())
1101  {
1102  octave_function *fcn = ov_fcn.function_value ();
1103 
1104  std::string dispatch_class = fcn->dispatch_class ();
1105 
1106  if (fcn->is_class_method ())
1107  {
1108  // Function found through lookup is a class method
1109  // so use it instead of the simple one found when
1110  // the handle was created.
1111 
1112  fcn_to_call = ov_fcn;
1113  }
1114  }
1115  }
1116  else
1117  {
1118  // There was no simple function found when the handle was
1119  // created so use the one found here (if any).
1120 
1121  fcn_to_call = ov_fcn;
1122  }
1123  }
1124 
1125  if (! fcn_to_call.is_defined ())
1127 
1128  return interp.feval (fcn_to_call, args, nargout);
1129 }
1130 
1132 {
1133  // FIXME: Shouldn't the lookup rules here match those used in the
1134  // call method?
1135 
1136  if (m_fcn.is_defined ())
1137  return m_fcn.function_value ();
1138 
1139  symbol_table& symtab = __get_symbol_table__ ();
1140 
1141  // FIXME: is caching the correct thing to do?
1142  // Cache this value so that the pointer will be valid as long as the
1143  // function handle object is valid.
1144 
1146 
1147  return m_fcn.is_defined () ? m_fcn.function_value () : nullptr;
1148 }
1149 
1151 {
1152  // FIXME: Shouldn't the lookup rules here match those used in the
1153  // call method?
1154 
1155  if (m_fcn.is_defined ())
1156  return m_fcn.user_function_value ();
1157 
1158  symbol_table& symtab = __get_symbol_table__ ();
1159 
1160  // FIXME: is caching the correct thing to do?
1161  // Cache this value so that the pointer will be valid as long as the
1162  // function handle object is valid.
1163 
1164  m_fcn = symtab.find_user_function (m_name);
1165 
1166  return m_fcn.is_defined () ? m_fcn.user_function_value () : nullptr;
1167 }
1168 
1170 {
1171  if (m_fcn.is_defined ())
1172  return m_fcn;
1173 
1174  symbol_table& symtab = __get_symbol_table__ ();
1175 
1176  // FIXME: is caching the correct thing to do?
1177  // Cache this value so that the pointer will be valid as long as the
1178  // function handle object is valid.
1179 
1180  m_fcn = symtab.find_user_function (m_name);
1181 
1182  return m_fcn;
1183 }
1184 
1186 {
1188 
1189  m.setfield ("function", fcn_name ());
1190  m.setfield ("type", type ());
1191  // When is FILE defined for simple function handles?
1192  m.setfield ("file", file ());
1193 
1194  return m;
1195 }
1196 
1197 bool simple_fcn_handle::save_ascii (std::ostream& os)
1198 {
1199  os << "# octaveroot: " << config::octave_exec_home () << "\n";
1200 
1201  std::string fnm = file ();
1202  if (! fnm.empty ())
1203  os << "# path: " << fnm << "\n";
1204 
1205  os << "# subtype: " << type () << "\n";
1206 
1207  os << m_name << "\n";
1208 
1209  return true;
1210 }
1211 
1212 bool simple_fcn_handle::load_ascii (std::istream& is)
1213 {
1214  // FIXME: If m_file is not empty, try to load the file and define
1215  // the function? Is it an error if that fails? Or should this job
1216  // always be deferred until the handle is used?
1217 
1218  return is.good ();
1219 }
1220 
1221 bool simple_fcn_handle::save_binary (std::ostream& os, bool)
1222 {
1223  std::ostringstream nmbuf;
1224 
1225  // When is FILE defined for simple function handles?
1226  std::string fnm;
1227 
1228  nmbuf << m_name << "@<simple>\n" << config::octave_exec_home ()
1229  << "\n" << fnm;
1230 
1231  std::string buf_str = nmbuf.str ();
1232  int32_t tmp = buf_str.length ();
1233  os.write (reinterpret_cast<char *> (&tmp), 4);
1234  os.write (buf_str.c_str (), buf_str.length ());
1235 
1236  return true;
1237 }
1238 
1239 bool simple_fcn_handle::load_binary (std::istream& is, bool,
1241 {
1242  return is.good ();
1243 }
1244 
1245 bool simple_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, const char *name,
1246  bool)
1247 {
1248 #if defined (HAVE_HDF5)
1249 
1250  bool retval = true;
1251 
1252  octave_hdf5_id group_hid = -1;
1253 #if defined (HAVE_HDF5_18)
1254  group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
1256 #else
1257  group_hid = H5Gcreate (loc_id, name, 0);
1258 #endif
1259  if (group_hid < 0)
1260  return false;
1261 
1262  octave_hdf5_id space_hid, data_hid, type_hid;
1263  space_hid = data_hid = type_hid = -1;
1264 
1265  // attach the type of the variable
1266  type_hid = H5Tcopy (H5T_C_S1);
1267  H5Tset_size (type_hid, m_name.length () + 1);
1268  if (type_hid < 0)
1269  {
1270  H5Gclose (group_hid);
1271  return false;
1272  }
1273 
1274  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
1275  hdims[0] = 0;
1276  hdims[1] = 0;
1277  space_hid = H5Screate_simple (0, hdims, nullptr);
1278  if (space_hid < 0)
1279  {
1280  H5Tclose (type_hid);
1281  H5Gclose (group_hid);
1282  return false;
1283  }
1284 #if defined (HAVE_HDF5_18)
1285  data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid,
1288 #else
1289  data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid,
1291 #endif
1292  if (data_hid < 0
1293  || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
1294  octave_H5P_DEFAULT, m_name.c_str ()) < 0)
1295  {
1296  H5Sclose (space_hid);
1297  H5Tclose (type_hid);
1298  H5Gclose (group_hid);
1299  return false;
1300  }
1301  H5Dclose (data_hid);
1302 
1303  std::string octaveroot = config::octave_exec_home ();
1304 
1305  // When is FILE defined for simple fucntion handles?
1306  std::string fpath;
1307 
1308  H5Sclose (space_hid);
1309  hdims[0] = 1;
1310  hdims[1] = octaveroot.length ();
1311  space_hid = H5Screate_simple (0, hdims, nullptr);
1312  if (space_hid < 0)
1313  {
1314  H5Tclose (type_hid);
1315  H5Gclose (group_hid);
1316  return false;
1317  }
1318 
1319  H5Tclose (type_hid);
1320  type_hid = H5Tcopy (H5T_C_S1);
1321  H5Tset_size (type_hid, octaveroot.length () + 1);
1322  octave_hdf5_id a_id;
1323 #if defined (HAVE_HDF5_18)
1324  a_id = H5Acreate (group_hid, "OCTAVEROOT", type_hid, space_hid,
1326 #else
1327  a_id = H5Acreate (group_hid, "OCTAVEROOT", type_hid, space_hid,
1329 #endif
1330 
1331  if (a_id >= 0)
1332  {
1333  retval = (H5Awrite (a_id, type_hid, octaveroot.c_str ()) >= 0);
1334 
1335  H5Aclose (a_id);
1336  }
1337  else
1338  {
1339  H5Sclose (space_hid);
1340  H5Tclose (type_hid);
1341  H5Gclose (group_hid);
1342  return false;
1343  }
1344 
1345  H5Sclose (space_hid);
1346  hdims[0] = 1;
1347  hdims[1] = fpath.length ();
1348  space_hid = H5Screate_simple (0, hdims, nullptr);
1349  if (space_hid < 0)
1350  {
1351  H5Tclose (type_hid);
1352  H5Gclose (group_hid);
1353  return false;
1354  }
1355 
1356  H5Tclose (type_hid);
1357  type_hid = H5Tcopy (H5T_C_S1);
1358  H5Tset_size (type_hid, fpath.length () + 1);
1359 
1360 #if defined (HAVE_HDF5_18)
1361  a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid,
1363 #else
1364  a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid,
1366 #endif
1367 
1368  if (a_id >= 0)
1369  {
1370  retval = (H5Awrite (a_id, type_hid, fpath.c_str ()) >= 0);
1371 
1372  H5Aclose (a_id);
1373  }
1374  else
1375  retval = false;
1376 
1377  H5Sclose (space_hid);
1378  H5Tclose (type_hid);
1379  H5Gclose (group_hid);
1380 
1381  return retval;
1382 
1383 #else
1384 
1385  octave_unused_parameter (loc_id);
1386  octave_unused_parameter (name);
1387 
1388  warn_save ("hdf5");
1389 
1390  return false;
1391 
1392 #endif
1393 }
1394 
1396  octave_hdf5_id& space_hid,
1397  octave_hdf5_id& type_hid)
1398 {
1399 #if defined (HAVE_HDF5)
1400 
1401  unimplemented ("load", "hdf5");
1402 
1403  octave_unused_parameter (group_hid);
1404  octave_unused_parameter (space_hid);
1405  octave_unused_parameter (type_hid);
1406 
1407  return true;
1408 
1409 #else
1410 
1411  octave_unused_parameter (group_hid);
1412  octave_unused_parameter (space_hid);
1413  octave_unused_parameter (type_hid);
1414 
1415  return false;
1416 
1417 #endif
1418 }
1419 
1420 void simple_fcn_handle::print_raw (std::ostream& os, bool pr_as_read_syntax,
1421  int current_print_indent_level) const
1422 {
1423  octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
1424  current_print_indent_level);
1425 }
1426 
1427 bool is_equal_to (const simple_fcn_handle& fh1, const simple_fcn_handle& fh2)
1428 {
1429  if (fh1.m_name == fh2.m_name)
1430  {
1431  if (fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
1432  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
1433 
1434  if (fh1.m_fcn.is_undefined () && fh2.m_fcn.is_undefined ())
1435  return true;
1436  }
1437 
1438  return false;
1439 }
1440 
1442  const std::string& name,
1443  const std::list<std::string>& parentage)
1444  : base_fcn_handle (name), m_fcn (fcn), m_parentage (parentage)
1445 {
1446  // FIXME: should it be an error if FCN is undefined?
1447 
1448  if (m_fcn.is_defined ())
1449  {
1450  octave_function *oct_fcn = m_fcn.function_value ();
1451 
1452  if (oct_fcn)
1453  m_file = oct_fcn->fcn_file_name ();
1454  }
1455 
1456  m_parentage.push_front (name);
1457 }
1458 
1460 scoped_fcn_handle::call (int nargout, const octave_value_list& args)
1461 {
1462  // FIXME: we aren't really using the scope yet. Hmm.
1463 
1464  interpreter& interp = __get_interpreter__ ();
1465 
1466  if (! m_fcn.is_defined ())
1467  {
1468  // Try to find it?
1469 
1470  find_function ();
1471  }
1472 
1473  if (! m_fcn.is_defined ())
1475 
1476  return interp.feval (m_fcn, args, nargout);
1477 }
1478 
1480 {
1482 
1483  m.setfield ("function", fcn_name ());
1484  m.setfield ("type", type ());
1485  m.setfield ("file", file ());
1486 
1487  m.setfield ("parentage", Cell (m_parentage));
1488 
1489  return m;
1490 }
1491 
1492 bool scoped_fcn_handle::save_ascii (std::ostream& os)
1493 {
1494  os << "# octaveroot: " << config::octave_exec_home () << "\n";
1495 
1496  std::string fnm = file ();
1497  if (! fnm.empty ())
1498  os << "# path: " << fnm << "\n";
1499 
1500  os << "# subtype: " << type () << "\n";
1501 
1502  os << m_name << "\n";
1503 
1504  octave_value tmp = Cell (m_parentage);
1505  tmp.save_ascii (os);
1506 
1507  return os.good ();
1508 }
1509 
1510 bool scoped_fcn_handle::load_ascii (std::istream& is)
1511 {
1512  octave_cell ov_cell;
1513  ov_cell.load_ascii (is);
1514 
1515  if (ov_cell.iscellstr ())
1516  {
1517  Array<std::string> cellstr_val = ov_cell.cellstr_value ();
1518 
1519  for (octave_idx_type i = 0; i < cellstr_val.numel (); i++)
1520  m_parentage.push_back (cellstr_val(i));
1521  }
1522 
1523  return is.good ();
1524 }
1525 
1526 bool scoped_fcn_handle::save_binary (std::ostream& os, bool save_as_floats)
1527 {
1528  std::ostringstream nmbuf;
1529 
1530  std::string fnm = file ();
1531 
1532  nmbuf << m_name << "@<scopedfunction>\n" << config::octave_exec_home ()
1533  << "\n" << fnm;
1534 
1535  std::string buf_str = nmbuf.str ();
1536  int32_t len = buf_str.length ();
1537  os.write (reinterpret_cast<char *> (&len), 4);
1538  os.write (buf_str.c_str (), buf_str.length ());
1539 
1540  octave_value tmp = Cell (m_parentage);
1541  tmp.save_binary (os, save_as_floats);
1542 
1543  return os.good ();
1544 }
1545 
1546 bool scoped_fcn_handle::load_binary (std::istream& is, bool swap,
1548 {
1549  octave_cell ov_cell;
1550  ov_cell.load_binary (is, swap, fmt);
1551 
1552  if (ov_cell.iscellstr ())
1553  {
1554  Array<std::string> cellstr_val = ov_cell.cellstr_value ();
1555 
1556  for (octave_idx_type i = 0; i < cellstr_val.numel (); i++)
1557  m_parentage.push_back (cellstr_val(i));
1558  }
1559 
1560  return is.good ();
1561 }
1562 
1563 bool scoped_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, const char *name,
1564  bool)
1565 {
1566 #if defined (HAVE_HDF5)
1567 
1568  unimplemented ("save", "hdf5");
1569 
1570  // FIXME: save parentage.
1571 
1572  octave_unused_parameter (loc_id);
1573  octave_unused_parameter (name);
1574 
1575  return true;
1576 
1577 #else
1578 
1579  octave_unused_parameter (loc_id);
1580  octave_unused_parameter (name);
1581 
1582  warn_save ("hdf5");
1583 
1584  return false;
1585 
1586 #endif
1587 }
1588 
1590  octave_hdf5_id& space_hid,
1591  octave_hdf5_id& type_hid)
1592 {
1593 #if defined (HAVE_HDF5)
1594 
1595  unimplemented ("load", "hdf5");
1596 
1597  // FIXME: load parentage.
1598 
1599  octave_unused_parameter (group_hid);
1600  octave_unused_parameter (space_hid);
1601  octave_unused_parameter (type_hid);
1602 
1603  return true;
1604 
1605 #else
1606 
1607  octave_unused_parameter (group_hid);
1608  octave_unused_parameter (space_hid);
1609  octave_unused_parameter (type_hid);
1610 
1611  return false;
1612 
1613 #endif
1614 }
1615 
1616 void scoped_fcn_handle::print_raw (std::ostream& os,
1617  bool pr_as_read_syntax,
1618  int current_print_indent_level) const
1619 {
1620  octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
1621  current_print_indent_level);
1622 }
1623 
1624 bool is_equal_to (const scoped_fcn_handle& fh1, const scoped_fcn_handle& fh2)
1625 {
1626  if (fh1.m_name == fh2.m_name
1627  && fh2.m_parentage == fh2.m_parentage
1628  && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
1629  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
1630  else
1631  return false;
1632 }
1633 
1635 {
1636  // Since a scoped function is not visible by itself, try to load the
1637  // file named in m_file then find and define the scoped function.
1638  // It is not an error if this fails. We can report later that the
1639  // handle is invalid.
1640 
1641  symbol_table& symtab = __get_symbol_table__ ();
1642 
1643  if (m_parentage.size () == 1)
1644  {
1645  std::string dir_name = sys::file_ops::dirname (m_file);
1646 
1647  std::size_t pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
1648 
1649  if (pos != std::string::npos)
1650  dir_name = dir_name.substr (0, pos);
1651  else if (dir_name == "private")
1652  dir_name = ".";
1653 
1654  std::string fcn_name = m_parentage.front ();
1655 
1656  // FIXME: Does dir_name need to be in the load path for this to work?
1657 
1658  m_fcn = symtab.find_private_function (dir_name, m_name);
1659 
1660  // FIXME: Verify that it is a private function?
1661  }
1662  else
1663  {
1664  std::string primary_parent_name = m_parentage.back ();
1665 
1666  octave_value ov_parent_fcn
1667  = symtab.find_user_function (primary_parent_name);
1668 
1669  if (ov_parent_fcn.is_defined ())
1670  {
1671  octave_user_function *fcn = ov_parent_fcn.user_function_value ();
1672 
1673  if (fcn)
1674  {
1675  std::string file_name = fcn->fcn_file_name ();
1676 
1677  std::string oct_home = config::octave_exec_home ();
1678 
1679  if (file_name.substr (0, oct_home.size ()) == oct_home)
1680  file_name = file_name.substr (oct_home.size ());
1681 
1682  octave_value subfcn = fcn->find_subfunction (m_name);
1683 
1684  if (subfcn.is_defined ())
1685  m_fcn = subfcn;
1686  }
1687  }
1688  }
1689 }
1690 
1692 {
1694 
1695  m.setfield ("function", fcn_name ());
1696  m.setfield ("type", type ());
1697  m.setfield ("file", "");
1698  m.setfield ("workspace", workspace ());
1699 
1700  return m;
1701 }
1702 
1703 // FIXME: For save, we need a way to save the (possibly shared)
1704 // workspace. For load, we need a way to load and link to the
1705 // (possibly shared) workspace that was saved.
1706 //
1707 // Since a nested function is not visible by itself, do we need to try
1708 // to load the file named in m_file then find and define the function?
1709 // Is it an error if that fails? Or should this job always be
1710 // deferred until the handle is used?
1711 
1712 bool base_nested_fcn_handle::save_ascii (std::ostream& os)
1713 {
1714  unimplemented ("save", "text");
1715 
1716  octave_unused_parameter (os);
1717 
1718  return true;
1719 }
1720 
1721 bool base_nested_fcn_handle::load_ascii (std::istream& is)
1722 {
1723  unimplemented ("load", "text");
1724 
1725  octave_unused_parameter (is);
1726 
1727  return true;
1728 }
1729 
1731  bool save_as_floats)
1732 {
1733  unimplemented ("save", "binary");
1734 
1735  octave_unused_parameter (os);
1736  octave_unused_parameter (save_as_floats);
1737 
1738  return true;
1739 }
1740 
1741 bool base_nested_fcn_handle::load_binary (std::istream& is, bool swap,
1743 {
1744  unimplemented ("load", "binary");
1745 
1746  octave_unused_parameter (is);
1747  octave_unused_parameter (swap);
1748  octave_unused_parameter (fmt);
1749 
1750  return true;
1751 }
1752 
1754  const char *name, bool)
1755 {
1756 #if defined (HAVE_HDF5)
1757 
1758  unimplemented ("save", "hdf5");
1759 
1760  octave_unused_parameter (loc_id);
1761  octave_unused_parameter (name);
1762 
1763  return true;
1764 
1765 #else
1766 
1767  octave_unused_parameter (loc_id);
1768  octave_unused_parameter (name);
1769 
1770  warn_save ("hdf5");
1771 
1772  return false;
1773 
1774 #endif
1775 }
1776 
1778  octave_hdf5_id& space_hid,
1779  octave_hdf5_id& type_hid)
1780 {
1781 #if defined (HAVE_HDF5)
1782 
1783  unimplemented ("load", "hdf5");
1784 
1785  octave_unused_parameter (group_hid);
1786  octave_unused_parameter (space_hid);
1787  octave_unused_parameter (type_hid);
1788 
1789  return true;
1790 
1791 #else
1792 
1793  octave_unused_parameter (group_hid);
1794  octave_unused_parameter (space_hid);
1795  octave_unused_parameter (type_hid);
1796 
1797  return false;
1798 
1799 #endif
1800 }
1801 
1802 void base_nested_fcn_handle::print_raw (std::ostream& os,
1803  bool pr_as_read_syntax,
1804  int current_print_indent_level) const
1805 {
1806  octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
1807  current_print_indent_level);
1808 }
1809 
1811 {
1812  return octave_value (new octave_fcn_handle
1813  (new weak_nested_fcn_handle (*this)));
1814 }
1815 
1817 nested_fcn_handle::call (int nargout, const octave_value_list& args)
1818 {
1820 
1822 
1823  tw.push_stack_frame (oct_usr_fcn, m_stack_context);
1824 
1825  unwind_action act ([&tw] () { tw.pop_stack_frame (); });
1826 
1827  return oct_usr_fcn->execute (tw, nargout, args);
1828 }
1829 
1831 {
1832  return m_stack_context->workspace ();
1833 }
1834 
1835 bool is_equal_to (const nested_fcn_handle& fh1, const nested_fcn_handle& fh2)
1836 {
1837  if (fh1.m_name == fh2.m_name
1838  && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
1839  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
1840  else
1841  return false;
1842 }
1843 
1846 {
1848 
1850 
1851  std::shared_ptr<stack_frame> frames = m_stack_context.lock ();
1852 
1853  tw.push_stack_frame (oct_usr_fcn, frames);
1854 
1855  unwind_action act ([&tw] () { tw.pop_stack_frame (); });
1856 
1857  return oct_usr_fcn->execute (tw, nargout, args);
1858 }
1859 
1861 {
1862  std::shared_ptr<stack_frame> frames = m_stack_context.lock ();
1863 
1864  return frames ? frames->workspace () : octave_value ();
1865 }
1866 
1868  const weak_nested_fcn_handle& fh2)
1869 {
1870  if (fh1.m_name == fh2.m_name
1871  && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
1872  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
1873  else
1874  return false;
1875 }
1876 
1878  const std::string& meth_nm)
1879  : base_fcn_handle (meth_nm), m_obj (), m_fcn (),
1880  m_dispatch_class (class_nm)
1881 { }
1882 
1884  const std::string& class_nm,
1885  const std::string& meth_nm)
1886  : base_fcn_handle (meth_nm), m_obj (), m_fcn (fcn),
1887  m_dispatch_class (class_nm)
1888 { }
1889 
1891  const octave_value& fcn,
1892  const std::string& class_nm,
1893  const std::string& meth_nm)
1894  : base_fcn_handle (meth_nm), m_obj (obj), m_fcn (fcn),
1895  m_dispatch_class (class_nm)
1896 { }
1897 
1900 {
1901  interpreter& interp = __get_interpreter__ ();
1902 
1903  if (m_obj.is_defined ())
1904  {
1905  octave_value_list tmp_args = args;
1906  tmp_args.prepend (m_obj);
1907 
1908  return interp.feval (m_fcn, tmp_args, nargout);
1909  }
1910 
1911  // FIXME: is this the best approach? Should we be saving current
1912  // dispatch class and restoring that value instead of
1913  // unconditionally setting it to "" when we return from this
1914  // function?
1915 
1916  tree_evaluator& tw = interp.get_evaluator ();
1917 
1918  unwind_action act ([&tw] () { tw.set_dispatch_class (""); });
1919 
1921 
1922  if (m_fcn.is_defined ())
1923  return interp.feval (m_fcn, args, nargout);
1924 
1925  return interp.feval (fcn_name (), args, nargout);
1926 }
1927 
1929 {
1931 
1932  m.setfield ("function", fcn_name ());
1933  m.setfield ("type", type ());
1934  m.setfield ("file", "");
1935  m.setfield ("class", dispatch_class ());
1936 
1937  return m;
1938 }
1939 
1940 // FIXME: Since a class method is not visible by itself, do we need to
1941 // try to load the file named in m_file then find and define the
1942 // function? Is it an error if that fails? Or should this job always
1943 // be deferred until the handle is used?
1944 
1946 {
1947  unimplemented ("save", "text");
1948 
1949  octave_unused_parameter (os);
1950 
1951  return true;
1952 }
1953 
1955 {
1956  unimplemented ("load", "text");
1957 
1958  octave_unused_parameter (is);
1959 
1960  return true;
1961 }
1962 
1964  bool save_as_floats)
1965 {
1966  unimplemented ("save", "binary");
1967 
1968  octave_unused_parameter (os);
1969  octave_unused_parameter (save_as_floats);
1970 
1971  return true;
1972 }
1973 
1974 bool class_simple_fcn_handle::load_binary (std::istream& is, bool swap,
1976 {
1977  unimplemented ("load", "binary");
1978 
1979  octave_unused_parameter (is);
1980  octave_unused_parameter (swap);
1981  octave_unused_parameter (fmt);
1982 
1983  return true;
1984 }
1985 
1987  const char *name, bool)
1988 {
1989 #if defined (HAVE_HDF5)
1990 
1991  unimplemented ("save", "hdf5");
1992 
1993  octave_unused_parameter (loc_id);
1994  octave_unused_parameter (name);
1995 
1996  return true;
1997 
1998 #else
1999 
2000  octave_unused_parameter (loc_id);
2001  octave_unused_parameter (name);
2002 
2003  warn_save ("hdf5");
2004 
2005  return false;
2006 
2007 #endif
2008 }
2009 
2011  octave_hdf5_id& space_hid,
2012  octave_hdf5_id& type_hid)
2013 {
2014 #if defined (HAVE_HDF5)
2015 
2016  unimplemented ("load", "hdf5");
2017 
2018  octave_unused_parameter (group_hid);
2019  octave_unused_parameter (space_hid);
2020  octave_unused_parameter (type_hid);
2021 
2022  return true;
2023 
2024 #else
2025 
2026  octave_unused_parameter (group_hid);
2027  octave_unused_parameter (space_hid);
2028  octave_unused_parameter (type_hid);
2029 
2030  return false;
2031 
2032 #endif
2033 }
2034 
2035 void class_simple_fcn_handle::print_raw (std::ostream& os,
2036  bool pr_as_read_syntax,
2037  int current_print_indent_level) const
2038 {
2039  octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
2040  current_print_indent_level);
2041 }
2042 
2044  const class_simple_fcn_handle& fh2)
2045 {
2046  // FIXME: Also need to check object values are equivalent?
2047 
2048  if (fh1.m_name == fh2.m_name
2049  && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
2050  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
2051  else
2052  return false;
2053 }
2054 
2055 const std::string base_anonymous_fcn_handle::anonymous ("@<anonymous>");
2056 
2058 {
2060 
2061  std::ostringstream buf;
2062  print_raw (buf, true, 0);
2063  m.setfield ("function", buf.str ());
2064 
2065  m.setfield ("type", type ());
2066  m.setfield ("file", "");
2067  m.setfield ("workspace", workspace ());
2068  m.setfield ("within_file_path", "");
2069 
2070  return m;
2071 }
2072 
2074 {
2075  // FIXME: can we ensure that m_fcn is always defined?
2076 
2077  if (m_fcn.is_undefined ())
2078  return false;
2079 
2080  os << m_name << "\n";
2081 
2082  print_raw (os, true, 0);
2083  os << "\n";
2084 
2085  std::size_t varlen = m_local_vars.size ();
2086 
2087  if (varlen > 0)
2088  {
2089  os << "# length: " << varlen << "\n";
2090 
2091  for (const auto& nm_val : m_local_vars)
2092  {
2093  if (! save_text_data (os, nm_val.second, nm_val.first, false, 0))
2094  return ! os.fail ();
2095  }
2096  }
2097 
2098  return true;
2099 }
2100 
2102 {
2104 
2105  std::string buf;
2106 
2107  if (is)
2108  {
2109  // Get a line of text whitespace characters included, leaving
2110  // newline in the stream.
2111 
2112  buf = octave::read_until_newline (is, true);
2113  }
2114 
2115  std::streampos pos = is.tellg ();
2116 
2117  // Set up temporary scope to use for evaluating the text that
2118  // defines the anonymous function.
2119 
2120  interpreter& interp = __get_interpreter__ ();
2121 
2122  tree_evaluator& tw = interp.get_evaluator ();
2123 
2124  tw.push_dummy_scope (buf);
2125  unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw);
2126 
2127  octave_idx_type len = 0;
2128 
2129  if (extract_keyword (is, "length", len, true) && len >= 0)
2130  {
2131  if (len > 0)
2132  {
2133  for (octave_idx_type i = 0; i < len; i++)
2134  {
2135  octave_value t2;
2136  bool dummy;
2137 
2138  std::string name = read_text_data (is, "", dummy, t2, i);
2139 
2140  if (! is)
2141  error ("load: failed to load anonymous function handle");
2142 
2143  m_local_vars[name] = t2;
2144  }
2145  }
2146  }
2147  else
2148  {
2149  is.seekg (pos);
2150  is.clear ();
2151  }
2152 
2153  if (is)
2154  return parse (buf);
2155 
2156  return false;
2157 }
2158 
2160  bool save_as_floats)
2161 {
2162  // FIXME: can we ensure that m_fcn is always defined?
2163 
2164  if (m_fcn.is_undefined ())
2165  return false;
2166 
2167  std::ostringstream nmbuf;
2168 
2169  std::size_t varlen = m_local_vars.size ();
2170 
2171  nmbuf << anonymous;
2172  if (varlen > 0)
2173  nmbuf << ' ' << varlen;
2174 
2175  std::string buf_str = nmbuf.str ();
2176  int32_t tmp = buf_str.length ();
2177  os.write (reinterpret_cast<char *> (&tmp), 4);
2178  os.write (buf_str.c_str (), buf_str.length ());
2179 
2180  std::ostringstream buf;
2181  print_raw (buf, true, 0);
2182  std::string stmp = buf.str ();
2183  tmp = stmp.length ();
2184  os.write (reinterpret_cast<char *> (&tmp), 4);
2185  os.write (stmp.c_str (), stmp.length ());
2186 
2187  if (varlen > 0)
2188  {
2189  for (const auto& nm_val : m_local_vars)
2190  {
2191  if (! save_binary_data (os, nm_val.second, nm_val.first,
2192  "", 0, save_as_floats))
2193  return ! os.fail ();
2194  }
2195  }
2196 
2197  return true;
2198 }
2199 
2200 bool base_anonymous_fcn_handle::load_binary (std::istream& is, bool swap,
2202 {
2203  // Read extra characters in m_name as the number of local variable
2204  // values in this anonymous function.
2205 
2206  octave_idx_type len = 0;
2207  std::size_t anl = anonymous.length ();
2208  if (m_name.length () > anl)
2209  {
2210  std::istringstream nm_is (m_name.substr (anl));
2211  nm_is >> len;
2212 
2213  // Anonymous functions don't have names. We just used this
2214  // string as temporary storage to pass the number of local
2215  // variable values.
2216 
2217  m_name = "";
2218  }
2219 
2220  int32_t tmp;
2221 
2222  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
2223  return false;
2224  if (swap)
2225  swap_bytes<4> (&tmp);
2226 
2227  OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
2228  // is.get (ctmp2, tmp+1, 0); caused is.eof () to be true though
2229  // effectively not reading over file end
2230  is.read (ctmp2, tmp);
2231  ctmp2[tmp] = 0;
2232 
2233  // Set up temporary scope to use for evaluating the text that
2234  // defines the anonymous function.
2235 
2236  interpreter& interp = __get_interpreter__ ();
2237 
2238  tree_evaluator& tw = interp.get_evaluator ();
2239 
2240  tw.push_dummy_scope (ctmp2);
2241  unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw);
2242 
2243  if (len > 0)
2244  {
2245  for (octave_idx_type i = 0; i < len; i++)
2246  {
2247  octave_value t2;
2248  bool dummy;
2249  std::string doc;
2250 
2251  std::string name
2252  = read_binary_data (is, swap, fmt, "", dummy, t2, doc);
2253 
2254  if (! is)
2255  error ("load: failed to load anonymous function handle");
2256 
2257  m_local_vars[name] = t2;
2258  }
2259  }
2260 
2261  if (is)
2262  return parse (ctmp2);
2263 
2264  return false;
2265 }
2266 
2268  const char *name,
2269  bool save_as_floats)
2270 {
2271 #if defined (HAVE_HDF5)
2272 
2273  bool retval = true;
2274 
2275  octave_hdf5_id group_hid = -1;
2276 #if defined (HAVE_HDF5_18)
2277  group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
2279 #else
2280  group_hid = H5Gcreate (loc_id, name, 0);
2281 #endif
2282  if (group_hid < 0)
2283  return false;
2284 
2285  octave_hdf5_id space_hid, data_hid, type_hid;
2286  space_hid = data_hid = type_hid = -1;
2287 
2288  // attach the type of the variable
2289  type_hid = H5Tcopy (H5T_C_S1);
2290  H5Tset_size (type_hid, m_name.length () + 1);
2291  if (type_hid < 0)
2292  {
2293  H5Gclose (group_hid);
2294  return false;
2295  }
2296 
2297  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
2298  hdims[0] = 0;
2299  hdims[1] = 0;
2300  space_hid = H5Screate_simple (0, hdims, nullptr);
2301  if (space_hid < 0)
2302  {
2303  H5Tclose (type_hid);
2304  H5Gclose (group_hid);
2305  return false;
2306  }
2307 #if defined (HAVE_HDF5_18)
2308  data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid,
2311 #else
2312  data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid,
2314 #endif
2315  if (data_hid < 0
2316  || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
2317  octave_H5P_DEFAULT, m_name.c_str ()) < 0)
2318  {
2319  H5Sclose (space_hid);
2320  H5Tclose (type_hid);
2321  H5Gclose (group_hid);
2322  return false;
2323  }
2324  H5Dclose (data_hid);
2325 
2326  std::ostringstream buf;
2327  print_raw (buf, true, 0);
2328  std::string stmp = buf.str ();
2329 
2330  // attach the type of the variable
2331  H5Tset_size (type_hid, stmp.length () + 1);
2332  if (type_hid < 0)
2333  {
2334  H5Sclose (space_hid);
2335  H5Gclose (group_hid);
2336  return false;
2337  }
2338 
2339 #if defined (HAVE_HDF5_18)
2340  data_hid = H5Dcreate (group_hid, "fcn", type_hid, space_hid,
2343 #else
2344  data_hid = H5Dcreate (group_hid, "fcn", type_hid, space_hid,
2346 #endif
2347  if (data_hid < 0
2348  || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
2349  octave_H5P_DEFAULT, stmp.c_str ()) < 0)
2350  {
2351  H5Sclose (space_hid);
2352  H5Tclose (type_hid);
2353  H5Gclose (group_hid);
2354  return false;
2355  }
2356 
2357  H5Dclose (data_hid);
2358 
2359  std::size_t varlen = m_local_vars.size ();
2360 
2361  if (varlen > 0)
2362  {
2363  octave_hdf5_id as_id = H5Screate (H5S_SCALAR);
2364 
2365  if (as_id >= 0)
2366  {
2367  octave_hdf5_id a_id;
2368 #if defined (HAVE_HDF5_18)
2369  a_id = H5Acreate (group_hid, "SYMBOL_TABLE", H5T_NATIVE_IDX, as_id,
2371 
2372 #else
2373  a_id = H5Acreate (group_hid, "SYMBOL_TABLE", H5T_NATIVE_IDX, as_id,
2375 #endif
2376 
2377  if (a_id >= 0)
2378  {
2379  retval = (H5Awrite (a_id, H5T_NATIVE_IDX, &varlen) >= 0);
2380 
2381  H5Aclose (a_id);
2382  }
2383  else
2384  retval = false;
2385 
2386  H5Sclose (as_id);
2387  }
2388  else
2389  retval = false;
2390 #if defined (HAVE_HDF5_18)
2391  data_hid = H5Gcreate (group_hid, "symbol table",
2394 #else
2395  data_hid = H5Gcreate (group_hid, "symbol table", 0);
2396 #endif
2397  if (data_hid < 0)
2398  {
2399  H5Sclose (space_hid);
2400  H5Tclose (type_hid);
2401  H5Gclose (group_hid);
2402  return false;
2403  }
2404 
2405  for (const auto& nm_val : m_local_vars)
2406  {
2407  if (! add_hdf5_data (data_hid, nm_val.second, nm_val.first,
2408  "", false, save_as_floats))
2409  break;
2410  }
2411 
2412  H5Gclose (data_hid);
2413  }
2414 
2415  H5Sclose (space_hid);
2416  H5Tclose (type_hid);
2417  H5Gclose (group_hid);
2418 
2419  return retval;
2420 
2421 #else
2422 
2423  octave_unused_parameter (loc_id);
2424  octave_unused_parameter (name);
2425  octave_unused_parameter (save_as_floats);
2426 
2427  warn_save ("hdf5");
2428 
2429  return false;
2430 
2431 #endif
2432 }
2433 
2435  octave_hdf5_id& space_hid,
2436  octave_hdf5_id& type_hid)
2437 {
2438 #if defined (HAVE_HDF5)
2439 
2440  bool success = true;
2441 
2442 #if defined (HAVE_HDF5_18)
2443  octave_hdf5_id data_hid = H5Dopen (group_hid, "fcn", octave_H5P_DEFAULT);
2444 #else
2445  octave_hdf5_id data_hid = H5Dopen (group_hid, "fcn");
2446 #endif
2447 
2448  if (data_hid < 0)
2449  {
2450  H5Sclose (space_hid);
2451  H5Tclose (type_hid);
2452  H5Gclose (group_hid);
2453  return false;
2454  }
2455 
2456  H5Tclose (type_hid);
2457  type_hid = H5Dget_type (data_hid);
2458  octave_hdf5_id type_class_hid = H5Tget_class (type_hid);
2459 
2460  if (type_class_hid != H5T_STRING)
2461  {
2462  H5Sclose (space_hid);
2463  H5Tclose (type_hid);
2464  H5Dclose (data_hid);
2465  H5Gclose (group_hid);
2466  return false;
2467  }
2468 
2469  H5Sclose (space_hid);
2470  space_hid = H5Dget_space (data_hid);
2471  hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
2472 
2473  if (rank != 0)
2474  {
2475  H5Sclose (space_hid);
2476  H5Tclose (type_hid);
2477  H5Dclose (data_hid);
2478  H5Gclose (group_hid);
2479  return false;
2480  }
2481 
2482  int slen = H5Tget_size (type_hid);
2483  if (slen < 0)
2484  {
2485  H5Sclose (space_hid);
2486  H5Tclose (type_hid);
2487  H5Dclose (data_hid);
2488  H5Gclose (group_hid);
2489  return false;
2490  }
2491 
2492  OCTAVE_LOCAL_BUFFER (char, fcn_tmp, slen);
2493 
2494  // create datatype for (null-terminated) string to read into:
2495  octave_hdf5_id st_id = H5Tcopy (H5T_C_S1);
2496  H5Tset_size (st_id, slen);
2497 
2498  if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL,
2499  octave_H5P_DEFAULT, fcn_tmp)
2500  < 0)
2501  {
2502  H5Tclose (st_id);
2503  H5Sclose (space_hid);
2504  H5Tclose (type_hid);
2505  H5Dclose (data_hid);
2506  H5Gclose (group_hid);
2507  return false;
2508  }
2509  H5Tclose (st_id);
2510  H5Dclose (data_hid);
2511 
2512  octave_idx_type len = 0;
2513 
2514  // we have to pull some shenanigans here to make sure
2515  // HDF5 doesn't print out all sorts of error messages if we
2516  // call H5Aopen for a non-existing attribute
2517 
2518  H5E_auto_t err_fcn;
2519  void *err_fcn_data;
2520 
2521  // turn off error reporting temporarily, but save the error
2522  // reporting function:
2523 #if defined (HAVE_HDF5_18)
2524  H5Eget_auto (octave_H5E_DEFAULT, &err_fcn, &err_fcn_data);
2525  H5Eset_auto (octave_H5E_DEFAULT, nullptr, nullptr);
2526 #else
2527  H5Eget_auto (&err_fcn, &err_fcn_data);
2528  H5Eset_auto (nullptr, nullptr);
2529 #endif
2530 
2531  octave_hdf5_id attr_id = H5Aopen_name (group_hid, "SYMBOL_TABLE");
2532 
2533  if (attr_id >= 0)
2534  {
2535  if (H5Aread (attr_id, H5T_NATIVE_IDX, &len) < 0)
2536  success = false;
2537 
2538  H5Aclose (attr_id);
2539  }
2540 
2541  // restore error reporting:
2542 #if defined (HAVE_HDF5_18)
2543  H5Eset_auto (octave_H5E_DEFAULT, err_fcn, err_fcn_data);
2544 #else
2545  H5Eset_auto (err_fcn, err_fcn_data);
2546 #endif
2547 
2548  // Set up temporary scope to use for evaluating the text that
2549  // defines the anonymous function.
2550 
2551  interpreter& interp = __get_interpreter__ ();
2552 
2553  tree_evaluator& tw = interp.get_evaluator ();
2554 
2555  tw.push_dummy_scope (fcn_tmp);
2556  unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw);
2557 
2558  if (len > 0 && success)
2559  {
2560  hsize_t num_obj = 0;
2561 #if defined (HAVE_HDF5_18)
2562  data_hid = H5Gopen (group_hid, "symbol table", octave_H5P_DEFAULT);
2563 #else
2564  data_hid = H5Gopen (group_hid, "symbol table");
2565 #endif
2566  H5Gget_num_objs (data_hid, &num_obj);
2567  H5Gclose (data_hid);
2568 
2569  if (num_obj != static_cast<hsize_t> (len))
2570  error ("load: failed to load anonymous function handle");
2571 
2572  hdf5_callback_data dsub;
2573  int current_item = 0;
2574  for (octave_idx_type i = 0; i < len; i++)
2575  {
2576  if (hdf5_h5g_iterate (group_hid, "symbol table", &current_item,
2577  &dsub) <= 0)
2578  error ("load: failed to load anonymous function handle");
2579 
2580  m_local_vars[dsub.name] = dsub.tc;
2581  }
2582  }
2583 
2584  if (success)
2585  return parse (fcn_tmp);
2586 
2587  return false;
2588 
2589 #else
2590 
2591  octave_unused_parameter (group_hid);
2592  octave_unused_parameter (space_hid);
2593  octave_unused_parameter (type_hid);
2594 
2595  return false;
2596 
2597 #endif
2598 }
2599 
2600 void base_anonymous_fcn_handle::print_raw (std::ostream& os, bool, int) const
2601 {
2602  tree_print_code tpc (os);
2603 
2605 
2606  if (! f)
2607  error ("invalid anonymous function handle");
2608 
2609  os << "@";
2610 
2611  // The parameter list should always be valid for anonymous
2612  // functions, so we should always call accept for it, and it will
2613  // print the parens for us.
2614 
2615  tree_parameter_list *p = f->parameter_list ();
2616 
2617  if (p)
2618  p->accept (tpc);
2619 
2620  os << " ";
2621 
2622  tree_statement_list *b = f->body ();
2623 
2624  panic_if (b->length () != 1);
2625 
2626  tree_statement *s = b->front ();
2627 
2628  if (! s)
2629  error ("invalid anonymous function handle");
2630 
2631  panic_unless (s->is_expression ());
2632 
2633  tree_expression *e = s->expression ();
2634 
2635  if (! e)
2636  error ("invalid anonymous function handle");
2637 
2638  tpc.print_fcn_handle_body (e);
2639 }
2640 
2641 bool base_anonymous_fcn_handle::parse (const std::string& fcn_text)
2642 {
2643  // FIXME: If evaluation of the string gives us an anonymous function
2644  // handle object, then why extract the function and create a new
2645  // anonymous function object? Why not just attach the workspace
2646  // values to the object returned by eval_string? This code is also is
2647  // duplicated in read_mat5_binary_element in ls-mat5.cc.
2648 
2649  interpreter& interp = __get_interpreter__ ();
2650 
2651  // Set up temporary scope to use for evaluating the text that defines
2652  // the anonymous function so that we don't pick up values of random
2653  // variables that might be in the current scope.
2654 
2655  tree_evaluator& tw = interp.get_evaluator ();
2656  tw.push_dummy_scope ("read_mat5_binary_element");
2657 
2658  unwind_action act ([&tw] () { tw.pop_scope (); });
2659 
2660  int parse_status;
2661  octave_value anonymous_fcn_hdl
2662  = interp.eval_string (fcn_text, true, parse_status);
2663 
2664  if (parse_status != 0)
2665  return false;
2666 
2667  octave_fcn_handle *fh = anonymous_fcn_hdl.fcn_handle_value ();
2668 
2669  if (! fh)
2670  return false;
2671 
2672  m_fcn = fh->fcn_val ();
2673 
2675 
2676  if (uf)
2677  {
2678  symbol_scope uf_scope = uf->scope ();
2679 
2680  if (uf_scope)
2681  uf_scope.cache_name (m_name);
2682  }
2683 
2684  return true;
2685 }
2686 
2688  const stack_frame::local_vars_map& local_vars,
2689  const std::shared_ptr<stack_frame>& stack_context)
2690  : base_anonymous_fcn_handle (fcn, local_vars),
2691  m_stack_context (stack_context)
2692 {
2693  if (m_stack_context)
2694  m_stack_context->mark_closure_context ();
2695 }
2696 
2698 {
2699  return octave_value (new octave_fcn_handle
2700  (new weak_anonymous_fcn_handle (*this)));
2701 }
2702 
2705 {
2707 
2709 
2710  tw.push_stack_frame (oct_usr_fcn, m_local_vars, m_stack_context);
2711 
2712  unwind_action act ([&tw] () { tw.pop_stack_frame (); });
2713 
2714  return oct_usr_fcn->execute (tw, nargout, args);
2715 }
2716 
2718 {
2719  octave_scalar_map local_vars_map;
2720 
2721  for (const auto& nm_val : m_local_vars)
2722  local_vars_map.assign (nm_val.first, nm_val.second);
2723 
2724  // FIXME: it would be more convenient if stack_frame::workspace
2725  // returned a Cell object directly instead of a Cell in an
2726  // octave_value object.
2727 
2728  Cell cell_frames;
2729 
2730  if (m_stack_context)
2731  {
2732  octave_value ov_frames = m_stack_context->workspace ();
2733  cell_frames = ov_frames.cell_value ();
2734  }
2735 
2736  octave_idx_type num_frames = cell_frames.numel ();
2737  // FIXME: It seems there should be a simple way to concatenate cells...
2738  Cell retval = Cell (num_frames+1, 1);
2739  retval(0) = m_local_vars;
2740  for (octave_idx_type i = 0; i < num_frames; i++)
2741  retval(i+1) = cell_frames(i);
2742 
2743  return retval;
2744 }
2745 
2747  const anonymous_fcn_handle& fh2)
2748 {
2749  if (fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
2750  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
2751  else
2752  return false;
2753 }
2754 
2757 {
2759 
2761 
2762  std::shared_ptr<stack_frame> frames = m_stack_context.lock ();
2763 
2764  tw.push_stack_frame (oct_usr_fcn, m_local_vars, frames);
2765 
2766  unwind_action act ([&tw] () { tw.pop_stack_frame (); });
2767 
2768  return oct_usr_fcn->execute (tw, nargout, args);
2769 }
2770 
2772 {
2773  octave_scalar_map local_vars_map;
2774 
2775  for (const auto& nm_val : m_local_vars)
2776  local_vars_map.assign (nm_val.first, nm_val.second);
2777 
2778  // FIXME: it would be more convenient if stack_frame::workspace
2779  // returned a Cell object directly instead of a Cell in an
2780  // octave_value object.
2781 
2782  std::shared_ptr<stack_frame> frames = m_stack_context.lock ();
2783 
2784  Cell cell_frames;
2785 
2786  if (frames)
2787  {
2788  octave_value ov_frames = frames->workspace ();
2789  cell_frames = ov_frames.cell_value ();
2790  }
2791 
2792  octave_idx_type num_frames = cell_frames.numel ();
2793 
2794  // FIXME: It seems there should be a simple way to concatenate
2795  // cells...
2796  Cell retval = Cell (num_frames+1, 1);
2797  retval(0) = m_local_vars;
2798  for (octave_idx_type i = 0; i < num_frames; i++)
2799  retval(i+1) = cell_frames(i);
2800 
2801  return retval;
2802 }
2803 
2805  const weak_anonymous_fcn_handle& fh2)
2806 {
2807  if (fh1.m_name == fh2.m_name
2808  && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
2809  return fh1.m_fcn.is_copy_of (fh2.m_fcn);
2810  else
2811  return false;
2812 }
2813 
2815 
2817  : octave_base_value (), m_rep (new octave::invalid_fcn_handle ())
2818 { }
2819 
2821  : octave_base_value (), m_rep (new octave::internal_fcn_handle (fcn))
2822 { }
2823 
2824 octave_fcn_handle::octave_fcn_handle (const std::string& name)
2825  : octave_base_value (), m_rep (new octave::simple_fcn_handle (name))
2826 { }
2827 
2829  const std::string& name)
2830  : octave_base_value (), m_rep (new octave::simple_fcn_handle (fcn, name))
2831 { }
2832 
2833 octave_fcn_handle::octave_fcn_handle (const std::string& class_nm,
2834  const std::string& meth_nm)
2835  : octave_base_value (),
2836  m_rep (new octave::class_simple_fcn_handle (class_nm, meth_nm))
2837 { }
2838 
2840  const std::string& class_nm,
2841  const std::string& meth_nm)
2842  : octave_base_value (),
2843  m_rep (new octave::class_simple_fcn_handle (fcn, class_nm, meth_nm))
2844 { }
2845 
2847  const octave_value& fcn,
2848  const std::string& class_nm,
2849  const std::string& meth_nm)
2850  : octave_base_value (),
2851  m_rep (new octave::class_simple_fcn_handle (obj, fcn, class_nm, meth_nm))
2852 { }
2853 
2855  const std::string& name,
2856  const std::list<std::string>& parentage)
2857  : octave_base_value (),
2858  m_rep (new octave::scoped_fcn_handle (fcn, name, parentage))
2859 { }
2860 
2862  const std::string& name,
2863  const std::shared_ptr<octave::stack_frame>& stack_context)
2864  : octave_base_value (),
2865  m_rep (new octave::nested_fcn_handle (fcn, name, stack_context))
2866 { }
2867 
2869  const octave::stack_frame::local_vars_map& local_vars,
2870  const std::shared_ptr<octave::stack_frame>& stack_context)
2871  : octave_base_value (),
2872  m_rep (new octave::anonymous_fcn_handle (fcn, local_vars, stack_context))
2873 { }
2874 
2875 octave_fcn_handle::octave_fcn_handle (octave::base_fcn_handle *rep)
2876  : octave_base_value (), m_rep (rep)
2877 { }
2878 
2880  : octave_base_value (fh)
2881 {
2882  m_rep.reset (fh.m_rep->clone ());
2883 }
2884 
2885 dim_vector
2887 {
2888  static dim_vector dv (1, 1);
2889  return dv;
2890 }
2891 
2892 bool
2894 {
2895  return m_rep->save_ascii (os);
2896 }
2897 
2898 bool
2900 {
2901  std::shared_ptr<octave::base_fcn_handle> new_rep;
2902 
2903  // Read enough to detect type then create new rep object and dispatch
2904  // to finish loading object.
2905 
2906  std::streampos pos = is.tellg ();
2907 
2908  std::string octaveroot = extract_keyword (is, "octaveroot", true);
2909  if (octaveroot.empty ())
2910  {
2911  is.seekg (pos);
2912  is.clear ();
2913  }
2914 
2915  pos = is.tellg ();
2916 
2917  std::string fpath = extract_keyword (is, "path", true);
2918  if (fpath.empty ())
2919  {
2920  is.seekg (pos);
2921  is.clear ();
2922  }
2923 
2924  if (! (octaveroot.empty () || fpath.empty ()))
2925  {
2926  std::size_t len = octaveroot.size ();
2927  if (octaveroot == fpath.substr (0, len))
2928  fpath = octave::config::octave_exec_home () + fpath.substr (len);
2929  }
2930 
2931  pos = is.tellg ();
2932 
2933  std::string subtype = extract_keyword (is, "subtype", true);
2934  if (subtype.empty ())
2935  {
2936  is.seekg (pos);
2937  is.clear ();
2938 
2939  // We have a legacy file that can contain either an anonymous
2940  // function or a simple function handle.
2941 
2942  std::string name;
2943  is >> name;
2944 
2945  if (name == anonymous)
2946  new_rep.reset (new octave::anonymous_fcn_handle ());
2947  else
2948  new_rep.reset (new octave::simple_fcn_handle (name, fpath, octaveroot));
2949  }
2950  else
2951  {
2952  // Load individual function handle types.
2953 
2954  if (subtype == "simple")
2955  {
2956  std::string name;
2957  is >> name;
2958 
2959  new_rep.reset (new octave::simple_fcn_handle (name, fpath,
2960  octaveroot));
2961  }
2962  else if (subtype == "scopedfunction")
2963  {
2964  std::string name;
2965  is >> name;
2966 
2967  new_rep.reset (new octave::scoped_fcn_handle (name, fpath,
2968  octaveroot));
2969  }
2970  else if (subtype == "anonymous")
2971  new_rep.reset (new octave::anonymous_fcn_handle ());
2972  else if (subtype == "nested")
2973  {
2974  std::string name;
2975  is >> name;
2976 
2977  new_rep.reset (new octave::nested_fcn_handle (name, fpath,
2978  octaveroot));
2979  }
2980  else if (subtype == "classsimple")
2981  {
2982  std::string name;
2983  is >> name;
2984 
2985  new_rep.reset (new octave::class_simple_fcn_handle (name, fpath,
2986  octaveroot));
2987  }
2988  }
2989 
2990  if (! new_rep)
2991  return false;
2992 
2993  if (! new_rep->load_ascii (is))
2994  return false;
2995 
2996  m_rep = new_rep;
2997 
2998  return true;
2999 }
3000 
3001 bool
3002 octave_fcn_handle::save_binary (std::ostream& os, bool save_as_floats)
3003 {
3004  return m_rep->save_binary (os, save_as_floats);
3005 }
3006 
3007 bool
3008 octave_fcn_handle::load_binary (std::istream& is, bool swap,
3010 {
3011  // Read enough to detect type then create new rep object and dispatch
3012  // to finish loading object.
3013 
3014  int32_t tmp;
3015  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
3016  return false;
3017  if (swap)
3018  swap_bytes<4> (&tmp);
3019 
3020  OCTAVE_LOCAL_BUFFER (char, ctmp1, tmp+1);
3021  // is.get (ctmp1, tmp+1, 0); caused is.eof () to be true though
3022  // effectively not reading over file end
3023  is.read (ctmp1, tmp);
3024  ctmp1[tmp] = 0;
3025  std::string name (ctmp1);
3026 
3027  if (! is)
3028  return false;
3029 
3030  std::shared_ptr<octave::base_fcn_handle> new_rep;
3031 
3032  std::size_t anl = anonymous.length ();
3033 
3034  if (name.length () >= anl && name.substr (0, anl) == anonymous)
3035  {
3036  // Even with extra info stored in the function name, anonymous
3037  // functions look the same. Note that NAME here may have the
3038  // number of local variables appended. We decode that inside the
3039  // load_binary function.
3040 
3041  new_rep.reset (new octave::anonymous_fcn_handle (name));
3042  }
3043  else
3044  {
3045  // Unpack extra info stored with the function name and load
3046  // individual function handle types.
3047  // FIXME: is there a better way?
3048 
3049  std::string octaveroot;
3050  std::string fpath;
3051  std::string subtype = "simple";
3052 
3053  if (name.find_first_of ('\n') != std::string::npos)
3054  {
3055  std::size_t pos1 = name.find_first_of ('\n');
3056  std::size_t pos2 = name.find_first_of ('\n', pos1 + 1);
3057  octaveroot = name.substr (pos1 + 1, pos2 - pos1 - 1);
3058  fpath = name.substr (pos2 + 1);
3059  name = name.substr (0, pos1);
3060  }
3061 
3062  std::size_t pos1 = name.find ('@');
3063  if (pos1 != std::string::npos)
3064  {
3065  if (name[pos1+1] == '<')
3066  {
3067  std::size_t pos2 = name.find ('>', pos1 + 2);
3068 
3069  if (pos2 != std::string::npos)
3070  subtype = name.substr (pos1 + 2, pos2 - pos1 - 2);
3071  }
3072 
3073  name = name.substr (0, pos1);
3074  }
3075 
3076  // Anonymous should have been handled above so it is not in the
3077  // following list.
3078 
3079  if (subtype == "simple")
3080  new_rep.reset (new octave::simple_fcn_handle (name, fpath, octaveroot));
3081  else if (subtype == "scopedfunction")
3082  new_rep.reset (new octave::scoped_fcn_handle (name, fpath, octaveroot));
3083  else if (subtype == "nested")
3084  new_rep.reset (new octave::nested_fcn_handle (name, fpath, octaveroot));
3085  else if (subtype == "classsimple")
3086  new_rep.reset (new octave::class_simple_fcn_handle (name, fpath,
3087  octaveroot));
3088  }
3089 
3090  if (! new_rep)
3091  return false;
3092 
3093  if (! new_rep->load_binary (is, swap, fmt))
3094  return false;
3095 
3096  m_rep = new_rep;
3097 
3098  return true;
3099 }
3100 
3101 bool
3103  bool save_as_floats)
3104 {
3105  return m_rep->save_hdf5 (loc_id, name, save_as_floats);
3106 }
3107 
3108 bool
3109 octave_fcn_handle::load_hdf5 (octave_hdf5_id loc_id, const char *name_arg)
3110 {
3111 #if defined (HAVE_HDF5)
3112 
3113 #if defined (HAVE_HDF5_18)
3114  octave_hdf5_id group_hid = H5Gopen (loc_id, name_arg, octave_H5P_DEFAULT);
3115 #else
3116  octave_hdf5_id group_hid = H5Gopen (loc_id, name_arg);
3117 #endif
3118  if (group_hid < 0)
3119  return false;
3120 
3121 #if defined (HAVE_HDF5_18)
3122  octave_hdf5_id data_hid = H5Dopen (group_hid, "nm", octave_H5P_DEFAULT);
3123 #else
3124  octave_hdf5_id data_hid = H5Dopen (group_hid, "nm");
3125 #endif
3126 
3127  if (data_hid < 0)
3128  {
3129  H5Gclose (group_hid);
3130  return false;
3131  }
3132 
3133  octave_hdf5_id type_hid = H5Dget_type (data_hid);
3134  octave_hdf5_id type_class_hid = H5Tget_class (type_hid);
3135 
3136  if (type_class_hid != H5T_STRING)
3137  {
3138  H5Tclose (type_hid);
3139  H5Dclose (data_hid);
3140  H5Gclose (group_hid);
3141  return false;
3142  }
3143 
3144  octave_hdf5_id space_hid = H5Dget_space (data_hid);
3145  hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
3146 
3147  if (rank != 0)
3148  {
3149  H5Sclose (space_hid);
3150  H5Tclose (type_hid);
3151  H5Dclose (data_hid);
3152  H5Gclose (group_hid);
3153  return false;
3154  }
3155 
3156  int slen = H5Tget_size (type_hid);
3157  if (slen < 0)
3158  {
3159  H5Sclose (space_hid);
3160  H5Tclose (type_hid);
3161  H5Dclose (data_hid);
3162  H5Gclose (group_hid);
3163  return false;
3164  }
3165 
3166  OCTAVE_LOCAL_BUFFER (char, nm_tmp, slen);
3167 
3168  // create datatype for (null-terminated) string to read into:
3169  octave_hdf5_id st_id = H5Tcopy (H5T_C_S1);
3170  H5Tset_size (st_id, slen);
3171 
3172  if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL,
3173  octave_H5P_DEFAULT, nm_tmp)
3174  < 0)
3175  {
3176  H5Tclose (st_id);
3177  H5Sclose (space_hid);
3178  H5Tclose (type_hid);
3179  H5Dclose (data_hid);
3180  H5Gclose (group_hid);
3181  return false;
3182  }
3183  H5Tclose (st_id);
3184  H5Dclose (data_hid);
3185 
3186  std::string name (nm_tmp);
3187 
3188  std::shared_ptr<octave::base_fcn_handle> new_rep;
3189 
3190  if (name == anonymous)
3191  {
3192  // Even with extra info stored in the function name, anonymous
3193  // functions look the same.
3194 
3195  new_rep.reset (new octave::anonymous_fcn_handle ());
3196  }
3197  else
3198  {
3199  // Unpack extra info stored with the function name and load
3200  // individual function handle types.
3201  // FIXME: is there a better way?
3202 
3203  std::string octaveroot;
3204  std::string fpath;
3205  std::string subtype = "simple";
3206 
3207  if (name.find_first_of ('\n') != std::string::npos)
3208  {
3209  std::size_t pos1 = name.find_first_of ('\n');
3210  std::size_t pos2 = name.find_first_of ('\n', pos1 + 1);
3211  octaveroot = name.substr (pos1 + 1, pos2 - pos1 - 1);
3212  fpath = name.substr (pos2 + 1);
3213  name = name.substr (0, pos1);
3214  }
3215 
3216  std::size_t pos1 = name.find ('@');
3217  if (pos1 != std::string::npos)
3218  {
3219  if (name[pos1+1] == '<')
3220  {
3221  std::size_t pos2 = name.find ('>', pos1 + 2);
3222 
3223  if (pos2 != std::string::npos)
3224  subtype = name.substr (pos1 + 2, pos2 - pos1 - 2);
3225  }
3226 
3227  name = name.substr (0, pos1);
3228  }
3229 
3230  // Anonymous should have been handled above so it is not in the
3231  // following list.
3232 
3233  if (subtype == "simple")
3234  new_rep.reset (new octave::simple_fcn_handle (name, fpath, octaveroot));
3235  else if (subtype == "scopedfunction")
3236  new_rep.reset (new octave::scoped_fcn_handle (name, fpath, octaveroot));
3237  else if (subtype == "nested")
3238  new_rep.reset (new octave::nested_fcn_handle (name, fpath, octaveroot));
3239  else if (subtype == "classsimple")
3240  new_rep.reset (new octave::class_simple_fcn_handle (name, fpath,
3241  octaveroot));
3242  }
3243 
3244  bool status = false;
3245 
3246  if (new_rep && new_rep->load_hdf5 (group_hid, space_hid, type_hid))
3247  {
3248  m_rep = new_rep;
3249  status = true;
3250  }
3251 
3252  // FIXME: manage these with an unwind_action object?
3253 
3254  H5Tclose (type_hid);
3255  H5Sclose (space_hid);
3256  H5Gclose (group_hid);
3257 
3258  return status;
3259 
3260 #else
3261 
3262  octave_unused_parameter (loc_id);
3263  octave_unused_parameter (name_arg);
3264 
3265  warn_load ("hdf5");
3266 
3267  return false;
3268 
3269 #endif
3270 }
3271 
3272 /*
3273 %!test <*33857>
3274 %! a = 2;
3275 %! f = @(x) a + x;
3276 %! g = @(x) 2 * x;
3277 %! hm = @version;
3278 %! hdld = @svd;
3279 %! hbi = @log2;
3280 %! f2 = f;
3281 %! g2 = g;
3282 %! hm2 = hm;
3283 %! hdld2 = hdld;
3284 %! hbi2 = hbi;
3285 %! modes = {"-text", "-binary"};
3286 %! if (isfield (__octave_config_info__, "HAVE_HDF5")
3287 %! && __octave_config_info__ ("HAVE_HDF5"))
3288 %! modes(end+1) = "-hdf5";
3289 %! endif
3290 %! for i = 1:numel (modes)
3291 %! mode = modes{i};
3292 %! nm = tempname ();
3293 %! unwind_protect
3294 %! f2 (1);
3295 %! save (mode, nm, "f2", "g2", "hm2", "hdld2", "hbi2");
3296 %! clear f2 g2 hm2 hdld2 hbi2
3297 %! load (nm);
3298 %! assert (f (2), f2 (2));
3299 %! assert (g (2), g2 (2));
3300 %! assert (g (3), g2 (3));
3301 %! unlink (nm);
3302 %! save (mode, nm, "f2", "g2", "hm2", "hdld2", "hbi2");
3303 %! unwind_protect_cleanup
3304 %! unlink (nm);
3305 %! end_unwind_protect
3306 %! endfor
3307 */
3308 
3309 /*
3310 %!function fcn_handle_save_recurse (n, mode, nm, f2, g2, hm2, hdld2, hbi2)
3311 %! if (n == 0)
3312 %! save (mode, nm, "f2", "g2", "hm2", "hdld2", "hbi2");
3313 %! else
3314 %! fcn_handle_save_recurse (n - 1, mode, nm, f2, g2, hm2, hdld2, hbi2);
3315 %! endif
3316 %!endfunction
3317 %!function [f2, g2, hm2, hdld2, hbi2] = fcn_handle_load_recurse (n, nm)
3318 %! if (n == 0)
3319 %! load (nm);
3320 %! else
3321 %! [f2, g2, hm2, hdld2, hbi2] = fcn_handle_load_recurse (n - 1, nm);
3322 %! endif
3323 %!endfunction
3324 
3325 %!test <*35876>
3326 %! a = 2;
3327 %! f = @(x) a + x;
3328 %! g = @(x) 2 * x;
3329 %! hm = @version;
3330 %! hdld = @svd;
3331 %! hbi = @log2;
3332 %! f2 = f;
3333 %! g2 = g;
3334 %! hm2 = hm;
3335 %! hdld2 = hdld;
3336 %! hbi2 = hbi;
3337 %! modes = {"-text", "-binary"};
3338 %! if (isfield (__octave_config_info__, "HAVE_HDF5")
3339 %! && __octave_config_info__ ("HAVE_HDF5"))
3340 %! modes(end+1) = "-hdf5";
3341 %! endif
3342 %! for i = 1:numel (modes)
3343 %! mode = modes{i};
3344 %! nm = tempname ();
3345 %! unwind_protect
3346 %! fcn_handle_save_recurse (2, mode, nm, f2, g2, hm2, hdld2, hbi2);
3347 %! clear f2 g2 hm2 hdld2 hbi2
3348 %! [f2, f2, hm2, hdld2, hbi2] = fcn_handle_load_recurse (2, nm);
3349 %! load (nm);
3350 %! assert (f (2), f2 (2));
3351 %! assert (g (2), g2 (2));
3352 %! assert (g (3), g2 (3));
3353 %! unlink (nm);
3354 %! fcn_handle_save_recurse (2, mode, nm, f2, g2, hm2, hdld2, hbi2);
3355 %! unwind_protect_cleanup
3356 %! unlink (nm);
3357 %! end_unwind_protect
3358 %! endfor
3359 */
3360 
3361 void
3362 octave_fcn_handle::print (std::ostream& os, bool pr_as_read_syntax)
3363 {
3364  print_raw (os, pr_as_read_syntax);
3365  newline (os);
3366 }
3367 
3368 void
3369 octave_fcn_handle::print_raw (std::ostream& os, bool pr_as_read_syntax) const
3370 {
3371  m_rep->print_raw (os, pr_as_read_syntax, current_print_indent_level ());
3372 }
3373 
3374 bool
3376 {
3377  // FIXME: Maybe there is a better way? Possibly by using typeid or
3378  // typeindex?
3379 
3380  // Don't include invalid_fcn_handle in the list of types to compare.
3381  // Consider them to be like NaN values so comparisons between any two
3382  // invalid handles are always false.
3383 
3384  if (fh1.is_internal () && fh2.is_internal ())
3385  return is_equal_to (*dynamic_cast<octave::internal_fcn_handle *> (fh1.get_rep ()),
3386  *dynamic_cast<octave::internal_fcn_handle *> (fh2.get_rep ()));
3387  else if (fh1.is_simple () && fh2.is_simple ())
3388  return is_equal_to (*dynamic_cast<octave::simple_fcn_handle *> (fh1.get_rep ()),
3389  *dynamic_cast<octave::simple_fcn_handle *> (fh2.get_rep ()));
3390  else if (fh1.is_scoped () && fh2.is_scoped ())
3391  return is_equal_to (*dynamic_cast<octave::scoped_fcn_handle *> (fh1.get_rep ()),
3392  *dynamic_cast<octave::scoped_fcn_handle *> (fh2.get_rep ()));
3393  else if (fh1.is_nested () && fh2.is_nested ())
3394  return is_equal_to (*dynamic_cast<octave::nested_fcn_handle *> (fh1.get_rep ()),
3395  *dynamic_cast<octave::nested_fcn_handle *> (fh2.get_rep ()));
3396  else if (fh1.is_class_simple () && fh2.is_class_simple ())
3397  return is_equal_to (*dynamic_cast<octave::class_simple_fcn_handle *> (fh1.get_rep ()),
3398  *dynamic_cast<octave::class_simple_fcn_handle *> (fh2.get_rep ()));
3399  else if (fh1.is_anonymous () && fh2.is_anonymous ())
3400  return is_equal_to (*dynamic_cast<octave::anonymous_fcn_handle *> (fh1.get_rep ()),
3401  *dynamic_cast<octave::anonymous_fcn_handle *> (fh2.get_rep ()));
3402  else
3403  return false;
3404 }
3405 
3407 
3408 DEFUN (functions, args, ,
3409  doc: /* -*- texinfo -*-
3410 @deftypefn {} {@var{s} =} functions (@var{fcn_handle})
3411 Return a structure containing information about the function handle
3412 @var{fcn_handle}.
3413 
3414 The structure @var{s} always contains these three fields:
3415 
3416 @table @asis
3417 @item function
3418 The function name. For an anonymous function (no name) this will be the
3419 actual function definition.
3420 
3421 @item type
3422 Type of the function.
3423 
3424 @table @asis
3425 @item anonymous
3426 The function is anonymous.
3427 
3428 @item private
3429 The function is private.
3430 
3431 @item overloaded
3432 The function overloads an existing function.
3433 
3434 @item simple
3435 The function is a built-in or m-file function.
3436 
3437 @item subfunction
3438 The function is a subfunction within an m-file.
3439 @end table
3440 
3441 @item nested
3442 The function is nested.
3443 
3444 @item file
3445 The m-file that will be called to perform the function. This field is empty
3446 for anonymous and built-in functions.
3447 @end table
3448 
3449 In addition, some function types may return more information in additional
3450 fields.
3451 
3452 @strong{Warning:} @code{functions} is provided for debugging purposes only.
3453 Its behavior may change in the future and programs should not depend on any
3454 particular output format.
3455 
3456 @seealso{func2str, str2func}
3457 @end deftypefn */)
3458 {
3459  if (args.length () != 1)
3460  print_usage ();
3461 
3462  octave_fcn_handle *fh = args(
3463  0).xfcn_handle_value ("functions: FCN_HANDLE argument must be a function handle object");
3464 
3465  return ovl (fh->info ());
3466 }
3467 
3468 DEFUN (func2str, args, ,
3469  doc: /* -*- texinfo -*-
3470 @deftypefn {} {@var{str} =} func2str (@var{fcn_handle})
3471 Return a string containing the name of the function referenced by the function
3472 handle @var{fcn_handle}.
3473 @seealso{str2func, functions}
3474 @end deftypefn */)
3475 {
3476  if (args.length () != 1)
3477  print_usage ();
3478 
3479  octave_fcn_handle *fh = args(
3480  0).xfcn_handle_value ("func2str: FCN_HANDLE argument must be a function handle object");
3481 
3482  if (! fh)
3483  error ("func2str: FCN_HANDLE must be a valid function handle");
3484 
3485  octave_value retval;
3486 
3487  std::string fh_nm = fh->fcn_name ();
3488 
3489  if (fh->is_anonymous ())
3490  {
3491  std::ostringstream buf;
3492 
3493  fh->print_raw (buf);
3494 
3495  retval = buf.str ();
3496  }
3497  else
3498  retval = fh_nm;
3499 
3500  return retval;
3501 }
3502 
3503 DEFMETHOD (str2func, interp, args, ,
3504  doc: /* -*- texinfo -*-
3505 @deftypefn {} {@var{hfcn} =} str2func (@var{str})
3506 Return a function handle constructed from the string @var{str}.
3507 
3508 The input may be the name of a function such as @qcode{"sin"} or a string
3509 defining a function such as @qcode{"@@(x) sin (x + pi)"}.
3510 
3511 Programming Note: In most cases it will be better to use anonymous function
3512 syntax and let the Octave parser create the function handle rather than use
3513 @code{str2func}. For example:
3514 
3515 @example
3516 @group
3517 hfcn = @@sin ;
3518 hfcn = @@(x) sin (x + pi) ;
3519 @end group
3520 @end example
3521 
3522 @seealso{func2str, functions}
3523 @end deftypefn */)
3524 {
3525  int nargin = args.length ();
3526 
3527  if (nargin < 1 || nargin > 2)
3528  print_usage ();
3529 
3530  std::string nm
3531  = args(0).xstring_value ("str2func: FCN_NAME must be a string");
3532 
3533  if (nm.empty ())
3534  error ("str2func: invalid function name");
3535 
3536  if (nm[0] == '@')
3537  {
3538  // Unlike the anonymous_fcn_handle::parse method, don't set up
3539  // temporary scope to use for evaluating the text that defines
3540  // the anonymous function. Here we want
3541  //
3542  // str2func ("@(args) expr")
3543  //
3544  // to behave the same as if
3545  //
3546  // @(args) expr
3547  //
3548  // were evaluated in the current scope.
3549 
3550  int parse_status;
3551  octave_value afh = interp.eval_string (nm, true, parse_status);
3552 
3553  if (parse_status == 0)
3554  return afh;
3555  }
3556  else
3557  {
3558  if (nargin == 2)
3559  warning_with_id ("Octave:str2func-global-argument",
3560  "str2func: second argument ignored");
3561 
3562  tree_evaluator& tw = interp.get_evaluator ();
3563 
3564  return tw.make_fcn_handle (nm);
3565  }
3566 
3567  return ovl ();
3568 }
3569 
3570 /*
3571 %!test
3572 %! f = str2func ("<");
3573 %! assert (class (f), "function_handle");
3574 %! assert (func2str (f), "lt");
3575 %! assert (f (1, 2), true);
3576 %! assert (f (2, 1), false);
3577 
3578 %!test
3579 %! f = str2func ("@(x) sin (x)");
3580 %! assert (func2str (f), "@(x) sin (x)");
3581 %! assert (f (0:3), sin (0:3));
3582 
3583 %!error <FCN_NAME must be a string> str2func ({"sin"})
3584 */
3585 
3586 /*
3587 %!function y = __testrecursionfcn (f, x, n)
3588 %! if (nargin < 3)
3589 %! n = 0;
3590 %! endif
3591 %! if (n > 2)
3592 %! y = f (x);
3593 %! else
3594 %! n++;
3595 %! y = __testrecursionfcn (@(x) f (2*x), x, n);
3596 %! endif
3597 %!endfunction
3598 %!
3599 %!assert (__testrecursionfcn (@(x) x, 1), 8)
3600 */
3601 
3602 DEFUN (is_function_handle, args, ,
3603  doc: /* -*- texinfo -*-
3604 @deftypefn {} {@var{tf} =} is_function_handle (@var{x})
3605 Return true if @var{x} is a function handle.
3606 @seealso{isa, typeinfo, class, functions}
3607 @end deftypefn */)
3608 {
3609  if (args.length () != 1)
3610  print_usage ();
3611 
3612  return ovl (args(0).is_function_handle ());
3613 }
3614 
3615 /*
3616 %!shared fh
3617 %! fh = @(x) x;
3618 
3619 %!assert (is_function_handle (fh))
3620 %!assert (! is_function_handle ({fh}))
3621 %!assert (! is_function_handle (1))
3622 
3623 %!error is_function_handle ()
3624 %!error is_function_handle (1, 2)
3625 */
3626 
3627 /*
3628 %!test
3629 %! f = @(t) eval ('2*t');
3630 %! assert (f (21), 42);
3631 */
3632 
3633 /*
3634 %!test <*58389>
3635 %! s = "x";
3636 %! a.(s) = [e, pi];
3637 %! f = @(x) a.(s)(x);
3638 %! assert (f(1), e);
3639 %! assert (f(2), pi);
3640 %! assert (f([2,1]), [pi, e]);
3641 */
3642 
3643 /*
3644 %!function r = __f (g, i)
3645 %! r = g(i);
3646 %!endfunction
3647 %!test
3648 %! x = [1,2;3,4];
3649 %! assert (__f (@(i) x(:,i), 1), [1;3]);
3650 */
3651 
OCTAVE_END_NAMESPACE(octave)
void swap_bytes< 4 >(void *ptr)
Definition: byte-swap.h:63
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:414
Definition: Cell.h:43
octave_value make_weak_anonymous_handle(void) const
anonymous_fcn_handle(const anonymous_fcn_handle &)=default
anonymous_fcn_handle * clone(void) const
octave_value workspace(void) const
friend bool is_equal_to(const anonymous_fcn_handle &fh1, const anonymous_fcn_handle &fh2)
std::shared_ptr< stack_frame > m_stack_context
std::shared_ptr< stack_frame > stack_context(void) const
octave_value_list call(int nargout, const octave_value_list &args)
anonymous_fcn_handle(const std::string &name="")
~anonymous_fcn_handle(void)=default
bool load_hdf5(octave_hdf5_id &group_hid, octave_hdf5_id &space_hid, octave_hdf5_id &type_hid)
void print_raw(std::ostream &, bool pr_as_read_syntax, int current_print_indent_level) const
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
bool load_ascii(std::istream &is)
bool save_ascii(std::ostream &os)
octave_scalar_map info(void)
std::string type(void) const
bool load_binary(std::istream &is, bool swap, mach_info::float_format fmt)
bool parse(const std::string &fcn_text)
octave_user_function * user_function_value(bool=false)
base_anonymous_fcn_handle(const octave_value &fcn, const stack_frame::local_vars_map &local_vars)
virtual octave_value workspace(void) const =0
octave_value fcn_val(void)
bool save_binary(std::ostream &os, bool save_as_floats)
stack_frame::local_vars_map m_local_vars
octave_function * function_value(bool=false)
static const std::string anonymous
base_anonymous_fcn_handle(const std::string &name="")
bool is_anonymous(void) const
bool print_as_scalar(void) const
base_anonymous_fcn_handle(const base_anonymous_fcn_handle &)=default
~base_anonymous_fcn_handle(void)=default
virtual bool save_binary(std::ostream &os, bool save_as_floats)
virtual bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
virtual octave_value make_weak_anonymous_handle(void) const
std::string m_name
void unimplemented(const char *op, const char *fmt) const
std::string fcn_name(void) const
Definition: ov-fcn-handle.h:92
virtual bool save_ascii(std::ostream &os)
virtual std::string type(void) const =0
void warn_save(const char *file_type) const
virtual bool load_binary(std::istream &is, bool swap, mach_info::float_format fmt)
virtual octave_value make_weak_nested_handle(void) const
virtual bool load_hdf5(octave_hdf5_id &group_hid, octave_hdf5_id &space_hid, octave_hdf5_id &type_hid)
virtual octave_value_list call(int nargout, const octave_value_list &args)=0
void warn_load(const char *file_type) const
virtual bool is_nested(void) const
Definition: ov-fcn-handle.h:73
virtual bool load_ascii(std::istream &is)
octave_value_list subsref(const std::string &type, const std::list< octave_value_list > &idx, int nargout)
std::string file(void) const
Definition: ov-fcn-handle.h:94
octave_value convert_to_str_internal(bool pad, bool force, char type) const
std::string m_file
virtual void print_raw(std::ostream &, bool, int) const
elt_type & front(void)
Definition: base-list.h:79
std::size_t length(void) const
Definition: base-list.h:53
void print_raw(std::ostream &, bool pr_as_read_syntax, int current_print_indent_level) const
octave_scalar_map info(void)
bool load_binary(std::istream &is, bool swap, mach_info::float_format fmt)
base_nested_fcn_handle(const std::string &name="", const std::string &file="", const std::string &="")
bool save_binary(std::ostream &os, bool save_as_floats)
octave_user_function * user_function_value(bool=false)
octave_function * function_value(bool=false)
std::string type(void) const
bool is_nested(void) const
bool save_ascii(std::ostream &os)
bool load_hdf5(octave_hdf5_id &group_hid, octave_hdf5_id &space_hid, octave_hdf5_id &type_hid)
base_nested_fcn_handle(const octave_value &fcn, const std::string &name)
virtual octave_value workspace(void) const =0
bool load_ascii(std::istream &is)
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
octave_value fcn_val(void)
octave_value_list call(int nargout, const octave_value_list &args)
octave_function * function_value(bool=false)
std::string type(void) const
friend bool is_equal_to(const class_simple_fcn_handle &fh1, const class_simple_fcn_handle &fh2)
bool is_class_simple(void) const
octave_user_function * user_function_value(bool=false)
bool load_binary(std::istream &is, bool swap, mach_info::float_format fmt)
std::string dispatch_class(void) const
~class_simple_fcn_handle(void)=default
bool save_binary(std::ostream &os, bool save_as_floats)
class_simple_fcn_handle * clone(void) const
class_simple_fcn_handle(const std::string &name, const std::string &file, const std::string &)
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
class_simple_fcn_handle(const class_simple_fcn_handle &)=default
void print_raw(std::ostream &, bool pr_as_read_syntax, int current_print_indent_level) const
octave_scalar_map info(void)
bool save_ascii(std::ostream &os)
bool load_hdf5(octave_hdf5_id &group_hid, octave_hdf5_id &space_hid, octave_hdf5_id &type_hid)
octave_value fcn_val(void)
bool load_ascii(std::istream &is)
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_value_list call(int nargout, const octave_value_list &args)
octave_user_function * user_function_value(bool=false)
octave_function * function_value(bool=false)
~internal_fcn_handle(void)=default
internal_fcn_handle(const octave_value &fcn)
bool is_internal(void) const
internal_fcn_handle(const internal_fcn_handle &)=default
octave_scalar_map info(void)
octave_value fcn_val(void)
internal_fcn_handle * clone(void) const
friend bool is_equal_to(const internal_fcn_handle &fh1, const internal_fcn_handle &fh2)
std::string type(void) const
octave_value varval(const std::string &name) const
tree_evaluator & get_evaluator(void)
octave_value_list eval_string(const std::string &eval_str, bool silent, int &parse_status, int nargout)
symbol_table & get_symbol_table(void)
Definition: interpreter.h:298
octave_value_list feval(const char *name, const octave_value_list &args=octave_value_list(), int nargout=0)
Evaluate an Octave function (built-in or interpreted) and return the list of result values.
~invalid_fcn_handle(void)=default
octave_value_list call(int nargout, const octave_value_list &args)
std::string type(void) const
invalid_fcn_handle(const invalid_fcn_handle &)=default
invalid_fcn_handle * clone(void) const
friend bool is_equal_to(const nested_fcn_handle &fh1, const nested_fcn_handle &fh2)
nested_fcn_handle(const std::string &name="", const std::string &file="", const std::string &octaveroot="")
nested_fcn_handle(const octave_value &fcn, const std::string &name, const std::shared_ptr< stack_frame > &stack_context)
bool is_nested(const std::shared_ptr< stack_frame > &frame) const
octave_value_list call(int nargout, const octave_value_list &args)
octave_value workspace(void) const
std::shared_ptr< stack_frame > stack_context(void) const
std::shared_ptr< stack_frame > m_stack_context
octave_value make_weak_nested_handle(void) const
nested_fcn_handle(const nested_fcn_handle &)=default
~nested_fcn_handle(void)=default
nested_fcn_handle * clone(void) const
int current_print_indent_level(void) const
Definition: ov-base.h:903
OCTINTERP_API void newline(std::ostream &os) const
Definition: ov-base.cc:1388
OCTINTERP_API void warn_load(const char *type) const
Definition: ov-base.cc:1157
bool load_ascii(std::istream &is)
Definition: ov-cell.cc:798
Array< std::string > cellstr_value(void) const
Definition: ov-cell.cc:636
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
Definition: ov-cell.cc:930
bool iscellstr(void) const
Definition: ov-cell.cc:431
static const std::string anonymous
std::string fcn_name(void) const
void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
octave_scalar_map info(void)
bool is_simple(void) const
std::shared_ptr< octave::base_fcn_handle > m_rep
bool load_hdf5(octave_hdf5_id loc_id, const char *name)
bool is_internal(void) const
bool load_ascii(std::istream &is)
bool is_class_simple(void) const
octave::base_fcn_handle * get_rep(void) const
octave_value fcn_val(void)
bool is_anonymous(void) const
dim_vector dims(void) const
bool is_scoped(void) const
bool save_binary(std::ostream &os, bool save_as_floats)
bool save_ascii(std::ostream &os)
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
bool is_nested(void) const
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
void print(std::ostream &os, bool pr_as_read_syntax=false)
std::string dispatch_class(void) const
Definition: ov-fcn.h:150
virtual std::string fcn_file_name(void) const
Definition: ov-fcn.h:79
bool is_class_method(const std::string &cname="") const
Definition: ov-fcn.h:117
void assign(const std::string &k, const octave_value &val)
Definition: oct-map.h:238
std::string fcn_file_name(void) const
Definition: ov-usr-fcn.h:107
octave::symbol_scope scope(void)
Definition: ov-usr-fcn.h:94
octave_value_list execute(octave::tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition: ov-usr-fcn.cc:492
octave_value find_subfunction(const std::string &subfuns) const
Definition: ov-usr-fcn.cc:418
octave_idx_type length(void) const
Definition: ovl.h:113
octave_value_list & prepend(const octave_value &val)
Definition: ovl.cc:80
bool is_function(void) const
Definition: ov.h:822
bool is_classdef_object(void) const
Definition: ov.h:700
bool is_package(void) const
Definition: ov.h:706
OCTINTERP_API octave_function * function_value(bool silent=false) const
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov.h:525
bool is_cs_list(void) const
Definition: ov.h:715
bool is_copy_of(const octave_value &val) const
Definition: ov.h:1485
bool save_binary(std::ostream &os, bool save_as_floats)
Definition: ov.h:1494
bool is_defined(void) const
Definition: ov.h:637
bool save_ascii(std::ostream &os)
Definition: ov.h:1490
Cell cell_value(void) const
bool is_classdef_meta(void) const
Definition: ov.h:697
OCTINTERP_API octave_user_function * user_function_value(bool silent=false) const
OCTINTERP_API octave_fcn_handle * fcn_handle_value(bool silent=false) const
bool is_undefined(void) const
Definition: ov.h:640
friend bool is_equal_to(const scoped_fcn_handle &fh1, const scoped_fcn_handle &fh2)
void find_function(void)
void print_raw(std::ostream &, bool pr_as_read_syntax, int current_print_indent_level) const
bool save_binary(std::ostream &os, bool save_as_floats)
scoped_fcn_handle(const scoped_fcn_handle &)=default
octave_function * function_value(bool=false)
octave_value m_fcn
~scoped_fcn_handle(void)=default
bool load_ascii(std::istream &is)
octave_value_list call(int nargout, const octave_value_list &args)
bool load_binary(std::istream &is, bool swap, mach_info::float_format fmt)
octave_user_function * user_function_value(bool=false)
octave_value fcn_val(void)
std::string type(void) const
bool load_hdf5(octave_hdf5_id &group_hid, octave_hdf5_id &space_hid, octave_hdf5_id &type_hid)
octave_scalar_map info(void)
scoped_fcn_handle(const std::string &name="", const std::string &file="", const std::string &="")
scoped_fcn_handle * clone(void) const
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
bool is_scoped(void) const
bool save_ascii(std::ostream &os)
std::list< std::string > m_parentage
friend bool is_equal_to(const simple_fcn_handle &fh1, const simple_fcn_handle &fh2)
std::string type(void) const
octave_function * function_value(bool)
bool is_simple(void) const
octave_user_function * user_function_value(bool)
simple_fcn_handle(const std::string &name="", const std::string &file="", const std::string &="")
simple_fcn_handle(const octave_value &fcn, const std::string &name)
void print_raw(std::ostream &os, bool pr_as_read_syntax, int current_print_indent_level) const
bool save_binary(std::ostream &os, bool save_as_floats)
bool save_hdf5(octave_hdf5_id loc_hid, const char *name, bool save_as_floats)
simple_fcn_handle * clone(void) const
octave_value m_fcn
octave_value fcn_val(void)
bool save_ascii(std::ostream &os)
bool load_binary(std::istream &is, bool swap, mach_info::float_format fmt)
bool load_hdf5(octave_hdf5_id &group_hid, octave_hdf5_id &space_hid, octave_hdf5_id &type_hid)
simple_fcn_handle(const simple_fcn_handle &)=default
octave_value_list call(int nargout, const octave_value_list &args)
bool load_ascii(std::istream &is)
octave_scalar_map info(void)
~simple_fcn_handle(void)=default
std::map< std::string, octave_value > local_vars_map
Definition: stack-frame.h:112
void cache_name(const std::string &name)
Definition: symscope.h:576
octave_value find_private_function(const std::string &dir_name, const std::string &name)
Definition: symtab.cc:99
octave_value find_function(const std::string &name, const symbol_scope &search_scope=symbol_scope())
Definition: symtab.cc:249
octave_value find_user_function(const std::string &name)
Definition: symtab.cc:288
void set_dispatch_class(const std::string &class_name)
Definition: pt-eval.cc:2554
void pop_stack_frame(void)
Definition: pt-eval.cc:2472
void push_dummy_scope(const std::string &name)
Definition: pt-eval.cc:2640
void pop_scope(void)
Definition: pt-eval.cc:2647
octave_value make_fcn_handle(const std::string &nm)
Definition: pt-eval.cc:1605
void push_stack_frame(const symbol_scope &scope)
Definition: pt-eval.cc:2444
void accept(tree_walker &tw)
Definition: pt-misc.h:102
void print_fcn_handle_body(tree_expression *)
Definition: pt-pr-code.cc:1191
bool is_expression(void) const
Definition: pt-stmt.h:80
tree_expression * expression(void)
Definition: pt-stmt.h:101
weak_anonymous_fcn_handle(const anonymous_fcn_handle &afh)
bool is_weak_anonymous(void) const
weak_anonymous_fcn_handle * clone(void) const
std::weak_ptr< stack_frame > m_stack_context
octave_value workspace(void) const
octave_value_list call(int nargout, const octave_value_list &args)
friend bool is_equal_to(const weak_anonymous_fcn_handle &fh1, const weak_anonymous_fcn_handle &fh2)
~weak_anonymous_fcn_handle(void)=default
weak_anonymous_fcn_handle(const weak_anonymous_fcn_handle &)=default
weak_nested_fcn_handle(const nested_fcn_handle &nfh)
std::weak_ptr< stack_frame > m_stack_context
octave_value workspace(void) const
bool is_weak_nested(void) const
friend bool is_equal_to(const weak_nested_fcn_handle &fh1, const weak_nested_fcn_handle &fh2)
weak_nested_fcn_handle(const weak_nested_fcn_handle &)=default
~weak_nested_fcn_handle(void)=default
weak_nested_fcn_handle * clone(void) const
octave_value_list call(int nargout, const octave_value_list &args)
const octave_hdf5_id octave_H5P_DEFAULT
const octave_hdf5_id octave_H5E_DEFAULT
const octave_hdf5_id octave_H5S_ALL
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
std::string octave_exec_home(void)
Definition: defaults.cc:164
OCTINTERP_API void print_usage(void)
Definition: defun-int.h:72
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition: defun.h:111
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void warning(const char *fmt,...)
Definition: error.cc:1054
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1069
void error(const char *fmt,...)
Definition: error.cc:979
void panic_unless(bool cond)
Definition: error.h:526
void panic_if(bool cond)
Definition: error.h:512
#define panic_impossible()
Definition: error.h:508
std::string dirname(const std::string &path)
Definition: file-ops.cc:360
interpreter & __get_interpreter__(void)
symbol_table & __get_symbol_table__(void)
tree_evaluator & __get_evaluator__(void)
F77_RET_T const F77_DBLE const F77_DBLE * f
std::string read_until_newline(std::istream &is, bool keep_newline)
void skip_preceeding_newline(std::istream &is)
octave_hdf5_err hdf5_h5g_iterate(octave_hdf5_id loc_id, const char *name, int *idx, void *operator_data)
Definition: ls-hdf5.cc:1059
bool add_hdf5_data(octave_hdf5_id loc_id, const octave_value &tc, const std::string &name, const std::string &doc, bool mark_global, bool save_as_floats)
Definition: ls-hdf5.cc:1406
std::string read_binary_data(std::istream &is, bool swap, octave::mach_info::float_format fmt, const std::string &filename, bool &global, octave_value &tc, std::string &doc)
bool save_binary_data(std::ostream &os, const octave_value &tc, const std::string &name, const std::string &doc, bool mark_global, bool save_as_floats)
std::string read_text_data(std::istream &is, const std::string &filename, bool &global, octave_value &tc, octave_idx_type count, const bool do_name_validation)
Definition: ls-oct-text.cc:286
std::string extract_keyword(std::istream &is, const char *keyword, const bool next_only)
Definition: ls-oct-text.cc:84
bool save_text_data(std::ostream &os, const octave_value &val_arg, const std::string &name, bool mark_global, int precision)
Definition: ls-oct-text.cc:361
float_format
Definition: mach-info.h:38
T octave_idx_type m
Definition: mx-inlines.cc:773
int64_t octave_hdf5_id
#define H5T_NATIVE_IDX
Definition: oct-hdf5.h:42
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
#define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)
Definition: ov-base.h:229
static void err_invalid_fcn_handle(const std::string &name)
bool is_equal_to(const anonymous_fcn_handle &fh1, const anonymous_fcn_handle &fh2)
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
void octave_print_internal(std::ostream &os, const float_display_format &fmt, bool d, bool pr_as_read_syntax)
Definition: pr-output.cc:1762
static std::string dir_sep_chars
Definition: shared-fcns.h:96
octave_value tc
Definition: ls-hdf5.h:116
std::string name
Definition: ls-hdf5.h:110
F77_RET_T len
Definition: xerbla.cc:61