GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ov-usr-fcn.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-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 <sstream>
31 
32 #include "file-info.h"
33 #include "file-ops.h"
34 #include "file-stat.h"
35 #include "str-vec.h"
36 
37 #include "builtin-defun-decls.h"
38 #include "defaults.h"
39 #include "Cell.h"
40 #include "defun.h"
41 #include "error.h"
42 #include "errwarn.h"
43 #include "input.h"
44 #include "ovl.h"
45 #include "ov-usr-fcn.h"
46 #include "ov.h"
47 #include "pager.h"
48 #include "pt-eval.h"
49 #include "pt-jump.h"
50 #include "pt-misc.h"
51 #include "pt-pr-code.h"
52 #include "pt-stmt.h"
53 #include "pt-walk.h"
54 #include "symtab.h"
55 #include "interpreter-private.h"
56 #include "interpreter.h"
57 #include "unwind-prot.h"
58 #include "utils.h"
59 #include "parse.h"
60 #include "profiler.h"
61 #include "variables.h"
62 #include "ov-fcn-handle.h"
63 
64 // Whether to optimize subsasgn method calls.
65 static bool Voptimize_subsasgn_calls = true;
66 
68 {
69  // This function is no longer valid, so remove the pointer to it from
70  // the corresponding scope.
71  // FIXME: would it be better to use shared/weak pointers for this job
72  // instead of storing a bare pointer in the scope object?
73  m_scope.set_user_code (nullptr);
74 
75  // FIXME: shouldn't this happen automatically when deleting cmd_list?
76  if (m_cmd_list)
77  {
78  octave::event_manager& evmgr = octave::__get_event_manager__ ();
79 
80  m_cmd_list->remove_all_breakpoints (evmgr, m_file_name);
81  }
82 
83  delete m_cmd_list;
84  delete m_file_info;
85 }
86 
87 void
89 {
90  m_file_info = new octave::file_info (m_file_name);
91 
92  octave::sys::file_stat fs (m_file_name);
93 
94  if (fs && (fs.mtime () > time_parsed ()))
95  warning ("function file '%s' changed since it was parsed",
96  m_file_name.c_str ());
97 }
98 
99 std::string
101 {
102  if (! m_file_info)
103  get_file_info ();
104 
105  return m_file_info->get_line (line);
106 }
107 
108 std::deque<std::string>
109 octave_user_code::get_code_lines (std::size_t line, std::size_t num_lines)
110 {
111  if (! m_file_info)
112  get_file_info ();
113 
114  return m_file_info->get_lines (line, num_lines);
115 }
116 
117 void
119  const octave::sys::time& timestamp)
120 {
121  delete m_file_info;
122 
123  if (timestamp > time_parsed ())
124  warning ("help text for function is newer than function");
125 
126  m_file_info = new octave::file_info (text, timestamp);
127 }
128 
129 std::map<std::string, octave_value>
131 {
132  return std::map<std::string, octave_value> ();
133 }
134 
137 {
138  std::map<std::string, octave_value> m
139  = {{ "scope_info", m_scope ? m_scope.dump () : "0x0" },
140  { "m_file_name", m_file_name },
141  { "time_parsed", m_t_parsed },
142  { "time_checked", m_t_checked }
143  };
144 
145  return octave_value (m);
146 }
147 
148 
149 // User defined scripts.
150 
152  "user-defined script",
153  "user-defined script");
154 
156  : octave_user_code ()
157 { }
158 
160 (const std::string& fnm, const std::string& nm,
161  const octave::symbol_scope& scope, octave::tree_statement_list *cmds,
162  const std::string& ds)
163  : octave_user_code (fnm, nm, scope, cmds, ds)
164 {
165  if (m_cmd_list)
166  m_cmd_list->mark_as_script_body ();
167 }
168 
170 (const std::string& fnm, const std::string& nm,
171  const octave::symbol_scope& scope, const std::string& ds)
172  : octave_user_code (fnm, nm, scope, nullptr, ds)
173 { }
174 
175 // We must overload the call method so that we call the proper
176 // push_stack_frame method, which is overloaded for pointers to
177 // octave_function, octave_user_function, and octave_user_script
178 // objects.
179 
181 octave_user_script::call (octave::tree_evaluator& tw, int nargout,
182  const octave_value_list& args)
183 {
184  tw.push_stack_frame (this);
185 
186  octave::unwind_action act ([&tw] () { tw.pop_stack_frame (); });
187 
188  return execute (tw, nargout, args);
189 }
190 
192 octave_user_script::execute (octave::tree_evaluator& tw, int nargout,
193  const octave_value_list& args)
194 {
195  return tw.execute_user_script (*this, nargout, args);
196 }
197 
198 void
199 octave_user_script::accept (octave::tree_walker& tw)
200 {
201  tw.visit_octave_user_script (*this);
202 }
203 
204 // User defined functions.
205 
207  "user-defined function",
208  "user-defined function");
209 
210 // Ugh. This really needs to be simplified (code/data?
211 // extrinsic/intrinsic state?).
212 
214 (const octave::symbol_scope& scope, octave::tree_parameter_list *pl,
215  octave::tree_parameter_list *rl, octave::tree_statement_list *cl)
216  : octave_user_code ("", "", scope, cl, ""),
217  m_param_list (pl), m_ret_list (rl),
218  m_lead_comm (), m_trail_comm (),
219  m_location_line (0), m_location_column (0),
220  m_system_fcn_file (false),
221  m_num_named_args (m_param_list ? m_param_list->length () : 0),
222  m_subfunction (false), m_inline_function (false),
223  m_anonymous_function (false), m_nested_function (false),
224  m_class_constructor (none), m_class_method (none)
225 {
226  if (m_cmd_list)
227  m_cmd_list->mark_as_function_body ();
228 }
229 
231 {
232  delete m_param_list;
233  delete m_ret_list;
234  delete m_lead_comm;
235  delete m_trail_comm;
236 }
237 
239 octave_user_function::define_ret_list (octave::tree_parameter_list *t)
240 {
241  m_ret_list = t;
242 
243  return this;
244 }
245 
246 // If there is no explicit end statement at the end of the function,
247 // relocate the no_op that was generated for the end of file condition
248 // to appear on the next line after the last statement in the file, or
249 // the next line after the function keyword if there are no statements.
250 // More precisely, the new location should probably be on the next line
251 // after the end of the parameter list, but we aren't tracking that
252 // information (yet).
253 
254 void
255 octave_user_function::maybe_relocate_end_internal ()
256 {
257  if (m_cmd_list && ! m_cmd_list->empty ())
258  {
259  octave::tree_statement *last_stmt = m_cmd_list->back ();
260 
261  if (last_stmt && last_stmt->is_end_of_fcn_or_script ()
262  && last_stmt->is_end_of_file ())
263  {
264  octave::tree_statement_list::reverse_iterator
265  next_to_last_elt = m_cmd_list->rbegin ();
266 
267  next_to_last_elt++;
268 
269  int new_eof_line;
270  int new_eof_col;
271 
272  if (next_to_last_elt == m_cmd_list->rend ())
273  {
274  new_eof_line = beginning_line ();
275  new_eof_col = beginning_column ();
276  }
277  else
278  {
279  octave::tree_statement *next_to_last_stmt = *next_to_last_elt;
280 
281  new_eof_line = next_to_last_stmt->line ();
282  new_eof_col = next_to_last_stmt->column ();
283  }
284 
285  last_stmt->set_location (new_eof_line + 1, new_eof_col);
286  }
287  }
288 }
289 
290 void
292 {
293  std::map<std::string, octave_value> fcns = subfunctions ();
294 
295  if (! fcns.empty ())
296  {
297  for (auto& nm_fnval : fcns)
298  {
299  octave_user_function *f = nm_fnval.second.user_function_value ();
300 
301  if (f)
302  f->maybe_relocate_end_internal ();
303  }
304  }
305 
306  maybe_relocate_end_internal ();
307 }
308 
309 void
310 octave_user_function::stash_parent_fcn_scope (const octave::symbol_scope& ps)
311 {
312  m_scope.set_parent (ps);
313 }
314 
315 std::string
317 {
318  std::ostringstream result;
319 
320  if (is_anonymous_function ())
321  result << "anonymous@" << fcn_file_name ()
322  << ':' << m_location_line << ':' << m_location_column;
323  else if (is_subfunction ())
324  result << parent_fcn_name () << '>' << name ();
325  else if (is_class_method ())
326  result << '@' << dispatch_class () << '/' << name ();
328  result << '@' << name ();
329  else if (is_inline_function ())
330  result << "inline@" << fcn_file_name ()
331  << ':' << m_location_line << ':' << m_location_column;
332  else
333  result << name ();
334 
335  return result.str ();
336 }
337 
338 void
340 {
341  if (! m_file_name.empty ())
342  {
343  // We really should stash the whole path to the file we found,
344  // when we looked it up, to avoid possible race conditions...
345  // FIXME
346  //
347  // We probably also don't need to get the library directory
348  // every time, but since this function is only called when the
349  // function file is parsed, it probably doesn't matter that
350  // much.
351 
352  std::string ff_name = octave::fcn_file_in_path (m_file_name);
353 
354  static const std::string canonical_fcn_file_dir
357  static const std::string fcn_file_dir
358  = canonical_fcn_file_dir.empty () ? octave::config::fcn_file_dir ()
359  : canonical_fcn_file_dir;
360 
361  if (fcn_file_dir == ff_name.substr (0, fcn_file_dir.length ()))
362  m_system_fcn_file = true;
363  }
364  else
365  m_system_fcn_file = false;
366 }
367 
368 void
370 {
371  m_scope.erase_subfunctions ();
372 }
373 
374 bool
376 {
377  return (m_param_list && m_param_list->takes_varargs ());
378 }
379 
380 bool
382 {
383  return (m_ret_list && m_ret_list->takes_varargs ());
384 }
385 
386 void
388 {
389  m_scope.mark_subfunctions_in_scope_as_private (cname);
390 
392 }
393 
394 void
396 {
397  m_scope.lock_subfunctions ();
398 }
399 
400 void
402 {
403  m_scope.unlock_subfunctions ();
404 }
405 
406 std::map<std::string, octave_value>
408 {
409  return m_scope.subfunctions ();
410 }
411 
412 // Find definition of final subfunction in list of subfcns:
413 //
414 // sub1>sub2>...>subN
415 
417 octave_user_function::find_subfunction (const std::string& subfcns_arg) const
418 {
419  std::string subfcns = subfcns_arg;
420 
421  std::string first_fcn = subfcns;
422 
423  std::size_t pos = subfcns.find ('>');
424 
425  if (pos == std::string::npos)
426  subfcns = "";
427  else
428  {
429  first_fcn = subfcns.substr (0, pos-1);
430  subfcns = subfcns.substr (pos+1);
431  }
432 
433  octave_value ov_fcn = m_scope.find_subfunction (first_fcn);
434 
435  if (subfcns.empty ())
436  return ov_fcn;
437 
438  octave_user_function *fcn = ov_fcn.user_function_value ();
439 
440  return fcn->find_subfunction (subfcns);
441 }
442 
443 bool
445 {
446  return m_scope.has_subfunctions ();
447 }
448 
449 void
450 octave_user_function::stash_subfunction_names (const std::list<std::string>& names)
451 {
452  m_scope.stash_subfunction_names (names);
453 }
454 
455 std::list<std::string>
457 {
458  return m_scope.subfunction_names ();
459 }
460 
463 {
464  octave_value_list retval;
465 
466  octave_idx_type n = args.length () - m_num_named_args;
467 
468  if (n > 0)
469  retval = args.slice (m_num_named_args, n);
470 
471  return retval;
472 }
473 
474 // We must overload the call method so that we call the proper
475 // push_stack_frame method, which is overloaded for pointers to
476 // octave_function, octave_user_function, and octave_user_script
477 // objects.
478 
480 octave_user_function::call (octave::tree_evaluator& tw, int nargout,
481  const octave_value_list& args)
482 {
483  tw.push_stack_frame (this);
484 
485  octave::unwind_action act ([&tw] () { tw.pop_stack_frame (); });
486 
487  return execute (tw, nargout, args);
488 }
489 
491 octave_user_function::execute (octave::tree_evaluator& tw, int nargout,
492  const octave_value_list& args)
493 {
494  return tw.execute_user_function (*this, nargout, args);
495 }
496 
497 void
498 octave_user_function::accept (octave::tree_walker& tw)
499 {
500  tw.visit_octave_user_function (*this);
501 }
502 
503 octave::tree_expression *
505 {
507  panic_if (m_cmd_list->length () != 1);
508 
509  octave::tree_statement *stmt = m_cmd_list->front ();
510  return stmt->expression ();
511 }
512 
513 bool
515 {
516  bool retval = false;
517  if (Voptimize_subsasgn_calls
518  && m_param_list && m_ret_list
519  && m_param_list->length () > 0 && ! m_param_list->varargs_only ()
520  && m_ret_list->length () == 1 && ! m_ret_list->takes_varargs ())
521  {
522  octave::tree_identifier *par1 = m_param_list->front ()->ident ();
523  octave::tree_identifier *ret1 = m_ret_list->front ()->ident ();
524  retval = par1->name () == ret1->name ();
525  }
526 
527  return retval;
528 }
529 
530 std::string
531 octave_user_function::ctor_type_str () const
532 {
533  std::string retval;
534 
535  switch (m_class_constructor)
536  {
537  case none:
538  retval = "none";
539  break;
540 
541  case legacy:
542  retval = "legacy";
543  break;
544 
545  case classdef:
546  retval = "classdef";
547  break;
548 
549  default:
550  retval = "unrecognized enum value";
551  break;
552  }
553 
554  return retval;
555 }
556 
557 std::string
558 octave_user_function::method_type_str () const
559 {
560  std::string retval;
561 
562  switch (m_class_method)
563  {
564  case none:
565  retval = "none";
566  break;
567 
568  case legacy:
569  retval = "legacy";
570  break;
571 
572  case classdef:
573  retval = "classdef";
574  break;
575 
576  default:
577  retval = "unrecognized enum value";
578  break;
579  }
580 
581  return retval;
582 }
583 
586 {
587  std::map<std::string, octave_value> m
588  = {{ "user_code", octave_user_code::dump () },
589  { "line", m_location_line },
590  { "col", m_location_column },
591  { "end_line", m_end_location_line },
592  { "end_col", m_end_location_column },
593  { "system_fcn_file", m_system_fcn_file },
594  { "num_named_args", m_num_named_args },
595  { "subfunction", m_subfunction },
596  { "inline_function", m_inline_function },
597  { "anonymous_function", m_anonymous_function },
598  { "nested_function", m_nested_function },
599  { "ctor_type", ctor_type_str () },
600  { "class_method", m_class_method }
601  };
602 
603  return octave_value (m);
604 }
605 
606 void
607 octave_user_function::print_code_function_header (const std::string& prefix)
608 {
609  octave::tree_print_code tpc (octave_stdout, prefix);
610 
611  tpc.visit_octave_user_function_header (*this);
612 }
613 
614 void
615 octave_user_function::print_code_function_trailer (const std::string& prefix)
616 {
617  octave::tree_print_code tpc (octave_stdout, prefix);
618 
619  tpc.visit_octave_user_function_trailer (*this);
620 }
621 
622 void
624 {
625  octave::interpreter& interp = octave::__get_interpreter__ ();
626 
627  octave::tree_evaluator& tw = interp.get_evaluator ();
628 
629  octave_value val
630  = tw.get_auto_fcn_var (octave::stack_frame::SAVED_WARNING_STATES);
631 
632  if (val.is_defined ())
633  {
634  // Fail spectacularly if SAVED_WARNING_STATES is not an
635  // octave_map (or octave_scalar_map) object.
636 
637  if (! val.isstruct ())
638  panic_impossible ();
639 
640  octave_map m = val.map_value ();
641 
642  Cell ids = m.contents ("identifier");
643  Cell states = m.contents ("state");
644 
645  for (octave_idx_type i = 0; i < m.numel (); i++)
646  Fwarning (interp, ovl (states(i), ids(i)));
647  }
648 }
649 
651 
652 DEFMETHOD (nargin, interp, args, ,
653  doc: /* -*- texinfo -*-
654 @deftypefn {} {@var{n} =} nargin ()
655 @deftypefnx {} {@var{n} =} nargin (@var{fcn})
656 Report the number of input arguments to a function.
657 
658 Called from within a function, return the number of arguments passed to the
659 function. At the top level, return the number of command line arguments
660 passed to Octave.
661 
662 If called with the optional argument @var{fcn}---a function name or
663 handle---return the declared number of arguments that the function can
664 accept.
665 
666 If the last argument to @var{fcn} is @var{varargin} the returned value is
667 negative. For example, the function @code{union} for sets is declared as
668 
669 @example
670 @group
671 function [y, ia, ib] = union (a, b, varargin)
672 
673 and
674 
675 nargin ("union")
676 @result{} -3
677 @end group
678 @end example
679 
680 Programming Note: @code{nargin} does not work on compiled functions
681 (@file{.oct} files) such as built-in or dynamically loaded functions.
682 @seealso{nargout, narginchk, varargin, inputname}
683 @end deftypefn */)
684 {
685  int nargin = args.length ();
686 
687  if (nargin > 1)
688  print_usage ();
689 
690  octave_value retval;
691 
692  if (nargin == 1)
693  {
694  octave_value fcn = args(0);
695 
696  if (fcn.is_string ())
697  {
698  symbol_table& symtab = interp.get_symbol_table ();
699 
700  std::string name = fcn.string_value ();
701  fcn = symtab.find_function (name);
702  if (fcn.is_undefined ())
703  error ("nargin: invalid function name: %s", name.c_str ());
704  }
705 
706  octave_function *fcn_val = fcn.function_value (true);
707  if (! fcn_val)
708  error ("nargin: FCN must be a string or function handle");
709 
710  octave_user_function *ufcn = fcn_val->user_function_value (true);
711 
712  if (! ufcn)
713  {
714  // Matlab gives up for histc, so maybe it's ok that we
715  // give up sometimes too?
716 
717  std::string type = fcn_val->type_name ();
718  error ("nargin: number of input arguments unavailable for %s objects",
719  type.c_str ());
720  }
721 
722  tree_parameter_list *m_param_list = ufcn->parameter_list ();
723 
724  retval = (m_param_list ? m_param_list->length () : 0);
725  if (ufcn->takes_varargs ())
726  retval = -1 - retval;
727  }
728  else
729  {
730  tree_evaluator& tw = interp.get_evaluator ();
731 
733 
734  if (retval.is_undefined ())
735  retval = 0;
736  }
737 
738  return retval;
739 }
740 
741 DEFMETHOD (nargout, interp, args, ,
742  doc: /* -*- texinfo -*-
743 @deftypefn {} {@var{n} =} nargout ()
744 @deftypefnx {} {@var{n} =} nargout (@var{fcn})
745 Report the number of output arguments from a function.
746 
747 Called from within a function, return the number of values the caller
748 expects to receive. At the top level, @code{nargout} with no argument is
749 undefined and will produce an error.
750 
751 If called with the optional argument @var{fcn}---a function name or
752 handle---return the number of declared output values that the function can
753 produce.
754 
755 If the final output argument is @var{varargout} the returned value is
756 negative.
757 
758 For example,
759 
760 @example
761 f ()
762 @end example
763 
764 @noindent
765 will cause @code{nargout} to return 0 inside the function @code{f} and
766 
767 @example
768 [s, t] = f ()
769 @end example
770 
771 @noindent
772 will cause @code{nargout} to return 2 inside the function @code{f}.
773 
774 In the second usage,
775 
776 @example
777 nargout (@@histc) # or nargout ("histc") using a string input
778 @end example
779 
780 @noindent
781 will return 2, because @code{histc} has two outputs, whereas
782 
783 @example
784 nargout (@@imread)
785 @end example
786 
787 @noindent
788 will return -2, because @code{imread} has two outputs and the second is
789 @var{varargout}.
790 
791 Programming Note. @code{nargout} does not work for built-in functions and
792 returns -1 for all anonymous functions.
793 @seealso{nargin, varargout, isargout, nthargout}
794 @end deftypefn */)
795 {
796  int nargin = args.length ();
797 
798  if (nargin > 1)
799  print_usage ();
800 
801  octave_value retval;
802 
803  if (nargin == 1)
804  {
805  octave_value fcn = args(0);
806 
807  if (fcn.is_string ())
808  {
809  symbol_table& symtab = interp.get_symbol_table ();
810 
811  std::string name = fcn.string_value ();
812  fcn = symtab.find_function (name);
813  if (fcn.is_undefined ())
814  error ("nargout: invalid function name: %s", name.c_str ());
815  }
816 
817  if (fcn.is_inline_function ())
818  return ovl (1);
819 
820  if (fcn.is_function_handle ())
821  {
822  octave_fcn_handle *fh = fcn.fcn_handle_value ();
823 
824  if (fh->is_anonymous ())
825  return ovl (-1);
826  }
827 
828  octave_function *fcn_val = fcn.function_value (true);
829  if (! fcn_val)
830  error ("nargout: FCN must be a string or function handle");
831 
832  octave_user_function *ufcn = fcn_val->user_function_value (true);
833 
834  if (! ufcn)
835  {
836  // Matlab gives up for histc, so maybe it's ok that we
837  // give up sometimes too?
838 
839  std::string type = fcn_val->type_name ();
840  error ("nargout: number of output arguments unavailable for %s objects",
841  type.c_str ());
842  }
843 
844  tree_parameter_list *m_ret_list = ufcn->return_list ();
845 
846  retval = (m_ret_list ? m_ret_list->length () : 0);
847 
848  if (ufcn->takes_var_return ())
849  retval = -1 - retval;
850  }
851  else
852  {
853  if (interp.at_top_level ())
854  error ("nargout: invalid call at top level");
855 
856  tree_evaluator& tw = interp.get_evaluator ();
857 
859 
860  if (retval.is_undefined ())
861  retval = 0;
862  }
863 
864  return retval;
865 }
866 
867 DEFUN (optimize_subsasgn_calls, args, nargout,
868  doc: /* -*- texinfo -*-
869 @deftypefn {} {@var{val} =} optimize_subsasgn_calls ()
870 @deftypefnx {} {@var{old_val} =} optimize_subsasgn_calls (@var{new_val})
871 @deftypefnx {} {@var{old_val} =} optimize_subsasgn_calls (@var{new_val}, "local")
872 Query or set the internal flag for @code{subsasgn} method call
873 optimizations.
874 
875 If true, Octave will attempt to eliminate the redundant copying when calling
876 the @code{subsasgn} method of a user-defined class.
877 
878 When called from inside a function with the @qcode{"local"} option, the
879 variable is changed locally for the function and any subroutines it calls.
880 The original variable value is restored when exiting the function.
881 @seealso{subsasgn}
882 @end deftypefn */)
883 {
884  return set_internal_variable (Voptimize_subsasgn_calls, args, nargout,
885  "optimize_subsasgn_calls");
886 }
887 
888 static bool
889 val_in_table (const Matrix& table, double val)
890 {
891  if (table.isempty ())
892  return false;
893 
894  octave_idx_type i = table.lookup (val, ASCENDING);
895  return (i > 0 && table(i-1) == val);
896 }
897 
898 static bool
899 isargout1 (int nargout, const Matrix& ignored, double k)
900 {
901  if (k != math::fix (k) || k <= 0)
902  error ("isargout: K must be a positive integer");
903 
904  return (k == 1 || k <= nargout) && ! val_in_table (ignored, k);
905 }
906 
907 DEFMETHOD (isargout, interp, args, ,
908  doc: /* -*- texinfo -*-
909 @deftypefn {} {@var{tf} =} isargout (@var{k})
910 Within a function, return a logical value indicating whether the argument
911 @var{k} will be assigned to a variable on output.
912 
913 If the result is false, the argument has been ignored during the function
914 call through the use of the tilde (~) special output argument. Functions
915 can use @code{isargout} to avoid performing unnecessary calculations for
916 outputs which are unwanted.
917 
918 If @var{k} is outside the range @code{1:max (nargout)}, the function returns
919 false. @var{k} can also be an array, in which case the function works
920 element-by-element and a logical array is returned. At the top level,
921 @code{isargout} returns an error.
922 @seealso{nargout, varargout, nthargout}
923 @end deftypefn */)
924 {
925  if (args.length () != 1)
926  print_usage ();
927 
928  if (interp.at_top_level ())
929  error ("isargout: invalid call at top level");
930 
931  tree_evaluator& tw = interp.get_evaluator ();
932 
933  octave_value tmp;
934 
935  int nargout1 = 0;
937  if (tmp.is_defined ())
938  nargout1 = tmp.int_value ();
939 
940  Matrix ignored;
942  if (tmp.is_defined ())
943  ignored = tmp.matrix_value ();
944 
945  if (args(0).is_scalar_type ())
946  {
947  double k = args(0).double_value ();
948 
949  return ovl (isargout1 (nargout1, ignored, k));
950  }
951  else if (args(0).isnumeric ())
952  {
953  const NDArray ka = args(0).array_value ();
954 
955  boolNDArray r (ka.dims ());
956  for (octave_idx_type i = 0; i < ka.numel (); i++)
957  r(i) = isargout1 (nargout1, ignored, ka(i));
958 
959  return ovl (r);
960  }
961  else
962  err_wrong_type_arg ("isargout", args(0));
963 
964  return ovl ();
965 }
966 
967 /*
968 %!function [x, y] = try_isargout ()
969 %! if (isargout (1))
970 %! if (isargout (2))
971 %! x = 1; y = 2;
972 %! else
973 %! x = -1;
974 %! endif
975 %! else
976 %! if (isargout (2))
977 %! y = -2;
978 %! else
979 %! error ("no outputs requested");
980 %! endif
981 %! endif
982 %!endfunction
983 %!
984 %!function [a, b] = try_isargout2 (x, y)
985 %! a = y;
986 %! b = {isargout(1), isargout(2), x};
987 %!endfunction
988 %!
989 %!test
990 %! [x, y] = try_isargout ();
991 %! assert ([x, y], [1, 2]);
992 %!
993 %!test
994 %! [x, ~] = try_isargout ();
995 %! assert (x, -1);
996 %!
997 %!test
998 %! [~, y] = try_isargout ();
999 %! assert (y, -2);
1000 %!
1001 %!error [~, ~] = try_isargout ()
1002 %!
1003 ## Check to see that isargout isn't sticky:
1004 %!test
1005 %! [x, y] = try_isargout ();
1006 %! assert ([x, y], [1, 2]);
1007 %!
1008 ## It should work without ():
1009 %!test
1010 %! [~, y] = try_isargout;
1011 %! assert (y, -2);
1012 %!
1013 ## It should work in function handles,
1014 %!test
1015 %! fh = @try_isargout;
1016 %! [~, y] = fh ();
1017 %! assert (y, -2);
1018 %!
1019 ## anonymous functions,
1020 %!test
1021 %! af = @() try_isargout;
1022 %! [~, y] = af ();
1023 %! assert (y, -2);
1024 %!
1025 ## and cell arrays of handles or anonymous functions.
1026 %!test
1027 %! fh = @try_isargout;
1028 %! af = @() try_isargout;
1029 %! c = {fh, af};
1030 %! [~, y] = c{1}();
1031 %! assert (y, -2);
1032 %!test
1033 %! fh = @try_isargout;
1034 %! af = @() try_isargout;
1035 %! c = {fh, af};
1036 %! [~, y] = c{2}();
1037 %! assert (y, -2);
1038 %!
1039 ## Nesting, anyone?
1040 %!test
1041 %! [~, b] = try_isargout2 (try_isargout, rand);
1042 %! assert (b, {0, 1, -1});
1043 %!test
1044 %! [~, b] = try_isargout2 ({try_isargout, try_isargout}, rand);
1045 %! assert (b, {0, 1, {-1, -1}});
1046 */
1047 
1048 OCTAVE_END_NAMESPACE(octave)
octave_value_list Fwarning(octave::interpreter &, const octave_value_list &=octave_value_list(), int=0)
bool isempty() const
Size of the specified dimension.
Definition: Array.h:651
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:503
octave_idx_type lookup(const T &value, sortmode mode=UNSORTED) const
Do a binary lookup in a sorted array.
Definition: Array-base.cc:2158
octave_idx_type numel() const
Number of elements in the array.
Definition: Array.h:414
Definition: Cell.h:43
Definition: dMatrix.h:42
std::size_t length() const
Definition: base-list.h:53
virtual octave_user_function * user_function_value(bool silent=false)
Definition: ov-base.cc:949
virtual std::string type_name() const
Definition: ov-base.h:954
friend class octave_value
Definition: ov-base.h:269
bool is_anonymous() const
std::string dispatch_class() const
Definition: ov-fcn.h:148
bool is_class_method(const std::string &cname="") const
Definition: ov-fcn.h:115
bool is_class_constructor(const std::string &cname="") const
Definition: ov-fcn.h:110
virtual void mark_as_private_function(const std::string &cname="")
Definition: ov-fcn.h:155
std::string name() const
Definition: ov-fcn.h:206
std::string get_code_line(std::size_t line)
Definition: ov-usr-fcn.cc:100
std::string m_file_name
Definition: ov-usr-fcn.h:130
octave::sys::time m_t_checked
Definition: ov-usr-fcn.h:137
std::string fcn_file_name() const
Definition: ov-usr-fcn.h:105
octave_value dump() const
Definition: ov-usr-fcn.cc:136
std::deque< std::string > get_code_lines(std::size_t line, std::size_t num_lines)
Definition: ov-usr-fcn.cc:109
virtual std::map< std::string, octave_value > subfunctions() const
Definition: ov-usr-fcn.cc:130
octave::tree_statement_list * m_cmd_list
Definition: ov-usr-fcn.h:144
octave::sys::time m_t_parsed
Definition: ov-usr-fcn.h:133
octave::file_info * m_file_info
Definition: ov-usr-fcn.h:141
void cache_function_text(const std::string &text, const octave::sys::time &timestamp)
Definition: ov-usr-fcn.cc:118
octave::symbol_scope m_scope
Definition: ov-usr-fcn.h:127
void get_file_info()
Definition: ov-usr-fcn.cc:88
octave::sys::time time_parsed() const
Definition: ov-usr-fcn.h:107
std::list< std::string > subfunction_names() const
Definition: ov-usr-fcn.cc:456
octave_value_list call(octave::tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition: ov-usr-fcn.cc:480
bool is_inline_function() const
Definition: ov-usr-fcn.h:309
bool takes_varargs() const
Definition: ov-usr-fcn.cc:375
bool is_special_expr() const
Definition: ov-usr-fcn.h:328
void stash_parent_fcn_scope(const octave::symbol_scope &ps)
Definition: ov-usr-fcn.cc:310
void mark_as_system_fcn_file()
Definition: ov-usr-fcn.cc:339
octave_user_function * define_ret_list(octave::tree_parameter_list *t)
Definition: ov-usr-fcn.cc:239
std::string profiler_name() const
Definition: ov-usr-fcn.cc:316
octave_value_list all_va_args(const octave_value_list &args)
Definition: ov-usr-fcn.cc:462
void stash_subfunction_names(const std::list< std::string > &names)
Definition: ov-usr-fcn.cc:450
bool is_classdef_constructor(const std::string &cname="") const
Definition: ov-usr-fcn.h:349
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::tree_expression * special_expr()
Definition: ov-usr-fcn.cc:504
octave::tree_parameter_list * parameter_list()
Definition: ov-usr-fcn.h:384
bool subsasgn_optimization_ok()
Definition: ov-usr-fcn.cc:514
void mark_as_private_function(const std::string &cname="")
Definition: ov-usr-fcn.cc:387
int beginning_column() const
Definition: ov-usr-fcn.h:233
std::string parent_fcn_name() const
Definition: ov-usr-fcn.h:254
bool is_anonymous_function() const
Definition: ov-usr-fcn.h:313
void accept(octave::tree_walker &tw)
Definition: ov-usr-fcn.cc:498
void restore_warning_states()
Definition: ov-usr-fcn.cc:623
int beginning_line() const
Definition: ov-usr-fcn.h:232
octave_value find_subfunction(const std::string &subfuns) const
Definition: ov-usr-fcn.cc:417
bool is_subfunction() const
Definition: ov-usr-fcn.h:305
bool has_subfunctions() const
Definition: ov-usr-fcn.cc:444
std::map< std::string, octave_value > subfunctions() const
Definition: ov-usr-fcn.cc:407
octave::tree_parameter_list * return_list()
Definition: ov-usr-fcn.h:386
bool takes_var_return() const
Definition: ov-usr-fcn.cc:381
octave_user_function(const octave::symbol_scope &scope=octave::symbol_scope::anonymous(), octave::tree_parameter_list *pl=nullptr, octave::tree_parameter_list *rl=nullptr, octave::tree_statement_list *cl=nullptr)
Definition: ov-usr-fcn.cc:214
octave_value dump() const
Definition: ov-usr-fcn.cc:585
void accept(octave::tree_walker &tw)
Definition: ov-usr-fcn.cc:199
octave_value_list call(octave::tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition: ov-usr-fcn.cc:181
octave_value_list execute(octave::tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition: ov-usr-fcn.cc:192
octave_value_list slice(octave_idx_type offset, octave_idx_type len, bool tags=false) const
Definition: ovl.h:131
octave_idx_type length() const
Definition: ovl.h:113
bool is_function_handle() const
Definition: ov.h:768
bool is_undefined() const
Definition: ov.h:595
bool is_inline_function() const
Definition: ov.h:774
octave_user_function * user_function_value(bool silent=false) const
int int_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:812
bool is_string() const
Definition: ov.h:637
bool is_defined() const
Definition: ov.h:592
octave_function * function_value(bool silent=false) const
octave_map map_value() const
octave_fcn_handle * fcn_handle_value(bool silent=false) const
std::string string_value(bool force=false) const
Definition: ov.h:974
bool isstruct() const
Definition: ov.h:649
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:853
octave_value find_function(const std::string &name, const symbol_scope &search_scope=symbol_scope::invalid())
Definition: symtab.cc:254
octave_value get_auto_fcn_var(stack_frame::auto_var_type avt) const
Definition: pt-eval.cc:2213
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
std::string fcn_file_dir()
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() 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
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:166
event_manager & __get_event_manager__()
interpreter & __get_interpreter__()
double fix(double x)
Definition: lo-mappers.h:118
F77_RET_T const F77_DBLE const F77_DBLE * f
T octave_idx_type m
Definition: mx-inlines.cc:781
octave_idx_type n
Definition: mx-inlines.cc:761
T * r
Definition: mx-inlines.cc:781
std::string fcn_file_dir()
Definition: defaults.cc:345
std::string canonicalize_file_name(const std::string &name)
Definition: file-ops.cc:798
std::string fcn_file_in_path(const std::string &name)
Definition: utils.cc:749
octave_value set_internal_variable(bool &var, const octave_value_list &args, int nargout, const char *nm)
Definition: variables.cc:583
@ ASCENDING
Definition: oct-sort.h:97
#define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)
Definition: ov-base.h:235
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:219
#define octave_stdout
Definition: pager.h:309