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