GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
ov-usr-fcn.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2013 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <sstream>
28 
29 #include "str-vec.h"
30 
31 #include <defaults.h>
32 #include "Cell.h"
33 #include "builtins.h"
34 #include "defun.h"
35 #include "error.h"
36 #include "gripes.h"
37 #include "input.h"
38 #include "oct-obj.h"
39 #include "ov-usr-fcn.h"
40 #include "ov.h"
41 #include "pager.h"
42 #include "pt-eval.h"
43 #include "pt-jit.h"
44 #include "pt-jump.h"
45 #include "pt-misc.h"
46 #include "pt-pr-code.h"
47 #include "pt-stmt.h"
48 #include "pt-walk.h"
49 #include "symtab.h"
50 #include "toplev.h"
51 #include "unwind-prot.h"
52 #include "utils.h"
53 #include "parse.h"
54 #include "profiler.h"
55 #include "variables.h"
56 #include "ov-fcn-handle.h"
57 
58 // Whether to optimize subsasgn method calls.
59 static bool Voptimize_subsasgn_calls = true;
60 
61 // The character to fill with when creating string arrays.
62 extern char Vstring_fill_char; // see pt-mat.cc
63 
64 std::map<std::string, octave_value>
66 {
67  return std::map<std::string, octave_value> ();
68 }
69 
70 // User defined scripts.
71 
73 
75  "user-defined script",
76  "user-defined script");
77 
79  : octave_user_code (), cmd_list (0), file_name (),
80  t_parsed (static_cast<time_t> (0)),
81  t_checked (static_cast<time_t> (0)),
82  call_depth (-1)
83 { }
84 
86  const std::string& nm,
87  tree_statement_list *cmds,
88  const std::string& ds)
89  : octave_user_code (nm, ds), cmd_list (cmds), file_name (fnm),
90  t_parsed (static_cast<time_t> (0)),
91  t_checked (static_cast<time_t> (0)),
92  call_depth (-1)
93 {
94  if (cmd_list)
96 }
97 
99  const std::string& nm,
100  const std::string& ds)
101  : octave_user_code (nm, ds), cmd_list (0), file_name (fnm),
102  t_parsed (static_cast<time_t> (0)),
103  t_checked (static_cast<time_t> (0)),
104  call_depth (-1)
105 { }
106 
108 {
109  if (cmd_list)
111 
112  delete cmd_list;
113 }
114 
116 octave_user_script::subsref (const std::string&,
117  const std::list<octave_value_list>&, int)
118 {
119  octave_value_list retval;
120 
121  ::error ("invalid use of script %s in index expression", file_name.c_str ());
122 
123  return retval;
124 }
125 
128  const octave_value_list& args)
129 {
130  octave_value_list retval;
131 
132  unwind_protect frame;
133 
134  if (! error_state)
135  {
136  if (args.length () == 0 && nargout == 0)
137  {
138  if (cmd_list)
139  {
140  frame.protect_var (call_depth);
141  call_depth++;
142 
144  {
146 
148 
151 
155 
158 
161 
162  if (error_state)
164  }
165  else
166  ::error ("max_recursion_depth exceeded");
167  }
168  }
169  else
170  error ("invalid call to script %s", file_name.c_str ());
171  }
172 
173  return retval;
174 }
175 
176 void
178 {
179  tw.visit_octave_user_script (*this);
180 }
181 
182 // User defined functions.
183 
185 
187  "user-defined function",
188  "user-defined function");
189 
190 // Ugh. This really needs to be simplified (code/data?
191 // extrinsic/intrinsic state?).
192 
196  : octave_user_code (std::string (), std::string ()),
197  param_list (pl), ret_list (rl), cmd_list (cl),
198  lead_comm (), trail_comm (), file_name (),
199  location_line (0), location_column (0),
200  parent_name (), t_parsed (static_cast<time_t> (0)),
201  t_checked (static_cast<time_t> (0)),
202  system_fcn_file (false), call_depth (-1),
203  num_named_args (param_list ? param_list->length () : 0),
204  subfunction (false), inline_function (false),
205  anonymous_function (false), nested_function (false),
206  class_constructor (false), class_method (false),
207  parent_scope (-1), local_scope (sid),
208  curr_unwind_protect_frame (0)
209 #ifdef HAVE_LLVM
210  , jit_info (0)
211 #endif
212 {
213  if (cmd_list)
214  cmd_list->mark_as_function_body ();
215 
216  if (local_scope >= 0)
217  symbol_table::set_curr_fcn (this, local_scope);
218 }
219 
221 {
222  if (cmd_list)
224 
225  delete param_list;
226  delete ret_list;
227  delete cmd_list;
228  delete lead_comm;
229  delete trail_comm;
230 
231 #ifdef HAVE_LLVM
232  delete jit_info;
233 #endif
234 
235  // FIXME: this is really playing with fire.
237 }
238 
241 {
242  ret_list = t;
243 
244  return this;
245 }
246 
247 void
249 {
250  file_name = nm;
251 }
252 
253 // If there is no explicit end statement at the end of the function,
254 // relocate the no_op that was generated for the end of file condition
255 // to appear on the next line after the last statement in the file, or
256 // the next line after the function keyword if there are no statements.
257 // More precisely, the new location should probably be on the next line
258 // after the end of the parameter list, but we aren't tracking that
259 // information (yet).
260 
261 void
263 {
264  if (cmd_list && ! cmd_list->empty ())
265  {
266  tree_statement *last_stmt = cmd_list->back ();
267 
268  if (last_stmt && last_stmt->is_end_of_fcn_or_script ()
269  && last_stmt->is_end_of_file ())
270  {
272  next_to_last_elt = cmd_list->rbegin ();
273 
274  next_to_last_elt++;
275 
276  int new_eof_line;
277  int new_eof_col;
278 
279  if (next_to_last_elt == cmd_list->rend ())
280  {
281  new_eof_line = beginning_line ();
282  new_eof_col = beginning_column ();
283  }
284  else
285  {
286  tree_statement *next_to_last_stmt = *next_to_last_elt;
287 
288  new_eof_line = next_to_last_stmt->line ();
289  new_eof_col = next_to_last_stmt->column ();
290  }
291 
292  last_stmt->set_location (new_eof_line + 1, new_eof_col);
293  }
294  }
295 }
296 
297 void
299 {
300  std::map<std::string, octave_value> fcns = subfunctions ();
301 
302  if (! fcns.empty ())
303  {
304  for (std::map<std::string, octave_value>::iterator p = fcns.begin ();
305  p != fcns.end (); p++)
306  {
307  octave_user_function *f = (p->second).user_function_value ();
308 
309  if (f)
311  }
312  }
313 
315 }
316 
317 std::string
319 {
320  std::ostringstream result;
321 
322  if (is_inline_function ())
323  result << "inline@" << fcn_file_name ()
324  << ":" << location_line << ":" << location_column;
325  else if (is_anonymous_function ())
326  result << "anonymous@" << fcn_file_name ()
327  << ":" << location_line << ":" << location_column;
328  else if (is_subfunction ())
329  result << parent_fcn_name () << ">" << name ();
330  else
331  result << name ();
332 
333  return result.str ();
334 }
335 
336 void
338 {
339  if (! file_name.empty ())
340  {
341  // We really should stash the whole path to the file we found,
342  // when we looked it up, to avoid possible race conditions...
343  // FIXME
344  //
345  // We probably also don't need to get the library directory
346  // every time, but since this function is only called when the
347  // function file is parsed, it probably doesn't matter that
348  // much.
349 
350  std::string ff_name = fcn_file_in_path (file_name);
351 
352  if (Vfcn_file_dir == ff_name.substr (0, Vfcn_file_dir.length ()))
353  system_fcn_file = true;
354  }
355  else
356  system_fcn_file = false;
357 }
358 
359 bool
361 {
362  return (param_list && param_list->takes_varargs ());
363 }
364 
365 bool
367 {
368  return (ret_list && ret_list->takes_varargs ());
369 }
370 
371 void
373 {
375 }
376 
377 void
379 {
381 }
382 
383 std::map<std::string, octave_value>
385 {
387 }
388 
389 bool
391 {
392  return ! subfcn_names.empty ();
393 }
394 
395 void
397  (const std::list<std::string>& names)
398 {
399  subfcn_names = names;
400 }
401 
404 {
405  octave_value_list retval;
406 
407  octave_idx_type n = args.length () - num_named_args;
408 
409  if (n > 0)
410  retval = args.slice (num_named_args, n);
411 
412  return retval;
413 }
414 
417  const std::list<octave_value_list>& idx,
418  int nargout)
419 {
420  return octave_user_function::subsref (type, idx, nargout, 0);
421 }
422 
425  const std::list<octave_value_list>& idx,
426  int nargout,
427  const std::list<octave_lvalue>* lvalue_list)
428 {
429  octave_value_list retval;
430 
431  switch (type[0])
432  {
433  case '(':
434  {
435  int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout;
436 
437  retval = do_multi_index_op (tmp_nargout, idx.front (),
438  idx.size () == 1 ? lvalue_list : 0);
439  }
440  break;
441 
442  case '{':
443  case '.':
444  {
445  std::string nm = type_name ();
446  error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
447  }
448  break;
449 
450  default:
451  panic_impossible ();
452  }
453 
454  // FIXME: perhaps there should be an
455  // octave_value_list::next_subsref member function? See also
456  // octave_builtin::subsref.
457 
458  if (idx.size () > 1)
459  retval = retval(0).next_subsref (nargout, type, idx);
460 
461  return retval;
462 }
463 
466  const octave_value_list& args)
467 {
468  return do_multi_index_op (nargout, args, 0);
469 }
470 
473  const octave_value_list& args,
474  const std::list<octave_lvalue>* lvalue_list)
475 {
476  octave_value_list retval;
477 
478  if (error_state)
479  return retval;
480 
481  if (! cmd_list)
482  return retval;
483 
484 #ifdef HAVE_LLVM
485  if (is_special_expr ()
486  && tree_jit::execute (*this, args, retval))
487  return retval;
488 #endif
489 
490  int nargin = args.length ();
491 
492  unwind_protect frame;
493 
494  frame.protect_var (call_depth);
495  call_depth++;
496 
498  {
499  ::error ("max_recursion_depth exceeded");
500  return retval;
501  }
502 
503  // Save old and set current symbol table context, for
504  // eval_undefined_error().
505 
506  int context = active_context ();
507 
508  octave_call_stack::push (this, local_scope, context);
510 
511  if (call_depth > 0 && ! is_anonymous_function ())
512  {
514 
516  }
517 
518  string_vector arg_names = args.name_tags ();
519 
520  if (param_list && ! param_list->varargs_only ())
521  {
523  if (error_state)
524  return retval;
525  }
526 
527  // Force parameter list to be undefined when this function exits.
528  // Doing so decrements the reference counts on the values of local
529  // variables that are also named function parameters.
530 
531  if (param_list)
533 
534  // Force return list to be undefined when this function exits.
535  // Doing so decrements the reference counts on the values of local
536  // variables that are also named values returned by this function.
537 
538  if (ret_list)
540 
541  if (call_depth == 0)
542  {
543  // Force symbols to be undefined again when this function
544  // exits.
545  //
546  // This cleanup function is added to the unwind_protect stack
547  // after the calls to clear the parameter lists so that local
548  // variables will be cleared before the parameter lists are
549  // cleared. That way, any function parameters that have been
550  // declared global will be unmarked as global before they are
551  // undefined by the clear_param_list cleanup function.
552 
554  }
555 
556  bind_automatic_vars (arg_names, nargin, nargout, all_va_args (args),
557  lvalue_list);
558 
560 
561  bool echo_commands = (Vecho_executing_commands & ECHO_FUNCTIONS);
562 
563  if (echo_commands)
565 
566  // Set pointer to the current unwind_protect frame to allow
567  // certain builtins register simple cleanup in a very optimized manner.
568  // This is *not* intended as a general-purpose on-cleanup mechanism,
570  curr_unwind_protect_frame = &frame;
571 
572  // Evaluate the commands that make up the function.
573 
576 
578 
579  if (is_special_expr ())
580  {
581  tree_expression *expr = special_expr ();
582 
583  if (expr)
584  retval = (lvalue_list
585  ? expr->rvalue (nargout, lvalue_list)
586  : expr->rvalue (nargout));
587  }
588  else
590 
592 
593  if (echo_commands)
595 
598 
601 
602  if (error_state)
603  {
605  return retval;
606  }
607 
608  // Copy return values out.
609 
610  if (ret_list && ! is_special_expr ())
611  {
613 
614  Cell varargout;
615 
616  if (ret_list->takes_varargs ())
617  {
618  octave_value varargout_varval = symbol_table::varval ("varargout");
619 
620  if (varargout_varval.is_defined ())
621  {
622  varargout = varargout_varval.cell_value ();
623 
624  if (error_state)
625  error ("expecting varargout to be a cell array object");
626  }
627  }
628 
629  if (! error_state)
630  retval = ret_list->convert_to_const_vector (nargout, varargout);
631  }
632 
633  return retval;
634 }
635 
636 void
638 {
639  tw.visit_octave_user_function (*this);
640 }
641 
644 {
645  assert (is_special_expr ());
646  assert (cmd_list->length () == 1);
647 
648  tree_statement *stmt = cmd_list->front ();
649  return stmt->expression ();
650 }
651 
652 bool
654 {
655  bool retval = false;
657  && param_list->length () > 0 && ! param_list->varargs_only ()
658  && ret_list->length () == 1 && ! ret_list->takes_varargs ())
659  {
660  tree_identifier *par1 = param_list->front ()->ident ();
661  tree_identifier *ret1 = ret_list->front ()->ident ();
662  retval = par1->name () == ret1->name ();
663  }
664 
665  return retval;
666 }
667 
668 #if 0
669 void
670 octave_user_function::print_symtab_info (std::ostream& os) const
671 {
673 }
674 #endif
675 
676 void
678 {
680 
682 }
683 
684 void
686 {
688 
690 }
691 
692 void
694  (const string_vector& arg_names, int nargin, int nargout,
695  const octave_value_list& va_args,
696  const std::list<octave_lvalue> *lvalue_list)
697 {
698  if (! arg_names.empty ())
699  {
700  // It is better to save this in the hidden variable .argn. and
701  // then use that in the inputname function instead of using argn,
702  // which might be redefined in a function. Keep the old argn name
703  // for backward compatibility of functions that use it directly.
704 
706  charMatrix (arg_names, Vstring_fill_char));
707  symbol_table::force_assign (".argn.", Cell (arg_names));
708 
709  symbol_table::mark_hidden (".argn.");
710 
712  symbol_table::mark_automatic (".argn.");
713  }
714 
715  symbol_table::force_assign (".nargin.", nargin);
716  symbol_table::force_assign (".nargout.", nargout);
717 
718  symbol_table::mark_hidden (".nargin.");
719  symbol_table::mark_hidden (".nargout.");
720 
721  symbol_table::mark_automatic (".nargin.");
722  symbol_table::mark_automatic (".nargout.");
723 
724  symbol_table::assign (".saved_warning_states.");
725 
726  symbol_table::mark_automatic (".saved_warning_states.");
727  symbol_table::mark_automatic (".saved_warning_states.");
728 
729  if (takes_varargs ())
730  symbol_table::assign ("varargin", va_args.cell_value ());
731 
732  // Force .ignored. variable to be undefined by default.
733  symbol_table::assign (".ignored.");
734 
735  if (lvalue_list)
736  {
737  octave_idx_type nbh = 0;
738  for (std::list<octave_lvalue>::const_iterator p = lvalue_list->begin ();
739  p != lvalue_list->end (); p++)
740  nbh += p->is_black_hole ();
741 
742  if (nbh > 0)
743  {
744  // Only assign the hidden variable if black holes actually present.
745  Matrix bh (1, nbh);
746  octave_idx_type k = 0, l = 0;
747  for (std::list<octave_lvalue>::const_iterator
748  p = lvalue_list->begin (); p != lvalue_list->end (); p++)
749  {
750  if (p->is_black_hole ())
751  bh(l++) = k+1;
752  k += p->numel ();
753  }
754 
755  symbol_table::assign (".ignored.", bh);
756  }
757  }
758 
759  symbol_table::mark_hidden (".ignored.");
760  symbol_table::mark_automatic (".ignored.");
761 }
762 
763 void
765 {
766  octave_value val = symbol_table::varval (".saved_warning_states.");
767 
768  if (val.is_defined ())
769  {
770  // Don't use the usual approach of attempting to extract a value
771  // and then checking error_state since this code might be
772  // executing when error_state is already set. But do fail
773  // spectacularly if .saved_warning_states. is not an octave_map
774  // (or octave_scalar_map) object.
775 
776  if (! val.is_map ())
777  panic_impossible ();
778 
779  octave_map m = val.map_value ();
780 
781  Cell ids = m.contents ("identifier");
782  Cell states = m.contents ("state");
783 
784  for (octave_idx_type i = 0; i < m.numel (); i++)
785  Fwarning (ovl (states(i), ids(i)));
786  }
787 }
788 
789 DEFUN (nargin, args, ,
790  "-*- texinfo -*-\n\
791 @deftypefn {Built-in Function} {} nargin ()\n\
792 @deftypefnx {Built-in Function} {} nargin (@var{fcn})\n\
793 Within a function, return the number of arguments passed to the function.\n\
794 At the top level, return the number of command line arguments passed to\n\
795 Octave.\n\
796 \n\
797 If called with the optional argument @var{fcn}, a function name or handle,\n\
798 return the declared number of arguments that the function can accept.\n\
799 If the last argument is @var{varargin} the returned value is negative.\n\
800 This feature does not work on builtin functions.\n\
801 @seealso{nargout, varargin, isargout, varargout, nthargout}\n\
802 @end deftypefn")
803 {
804  octave_value retval;
805 
806  int nargin = args.length ();
807 
808  if (nargin == 1)
809  {
810  octave_value func = args(0);
811 
812  if (func.is_string ())
813  {
814  std::string name = func.string_value ();
815  func = symbol_table::find_function (name);
816  if (func.is_undefined ())
817  error ("nargout: invalid function name: %s", name.c_str ());
818  }
819 
820  octave_function *fcn_val = func.function_value ();
821  if (fcn_val)
822  {
823  octave_user_function *fcn = fcn_val->user_function_value (true);
824 
825  if (fcn)
826  {
827  tree_parameter_list *param_list = fcn->parameter_list ();
828 
829  retval = param_list ? param_list->length () : 0;
830  if (fcn->takes_varargs ())
831  retval = -1 - retval;
832  }
833  else
834  {
835  // Matlab gives up for histc,
836  // so maybe it's ok that that we give up somtimes too?
837  error ("nargin: nargin information not available for builtin functions");
838  }
839  }
840  else
841  error ("nargin: FCN must be a string or function handle");
842  }
843  else if (nargin == 0)
844  {
845  retval = symbol_table::varval (".nargin.");
846 
847  if (retval.is_undefined ())
848  retval = 0;
849  }
850  else
851  print_usage ();
852 
853  return retval;
854 }
855 
856 DEFUN (nargout, args, ,
857  "-*- texinfo -*-\n\
858 @deftypefn {Built-in Function} {} nargout ()\n\
859 @deftypefnx {Built-in Function} {} nargout (@var{fcn})\n\
860 Within a function, return the number of values the caller expects to\n\
861 receive. If called with the optional argument @var{fcn}, a function\n\
862 name or handle, return the number of declared output values that the\n\
863 function can produce. If the final output argument is @var{varargout}\n\
864 the returned value is negative.\n\
865 \n\
866 For example,\n\
867 \n\
868 @example\n\
869 f ()\n\
870 @end example\n\
871 \n\
872 @noindent\n\
873 will cause @code{nargout} to return 0 inside the function @code{f} and\n\
874 \n\
875 @example\n\
876 [s, t] = f ()\n\
877 @end example\n\
878 \n\
879 @noindent\n\
880 will cause @code{nargout} to return 2 inside the function\n\
881 @code{f}.\n\
882 \n\
883 In the second usage,\n\
884 \n\
885 @example\n\
886 nargout (@@histc) \% or nargout (\"histc\")\n\
887 @end example\n\
888 \n\
889 @noindent\n\
890 will return 2, because @code{histc} has two outputs, whereas\n\
891 \n\
892 @example\n\
893 nargout (@@deal)\n\
894 @end example\n\
895 \n\
896 @noindent\n\
897 will return -1, because @code{deal} has a variable number of outputs.\n\
898 \n\
899 At the top level, @code{nargout} with no argument is undefined.\n\
900 @code{nargout} does not work on builtin functions.\n\
901 @code{nargout} returns -1 for all anonymous functions.\n\
902 @seealso{nargin, varargin, isargout, varargout, nthargout}\n\
903 @end deftypefn")
904 {
905  octave_value retval;
906 
907  int nargin = args.length ();
908 
909  if (nargin == 1)
910  {
911  octave_value func = args(0);
912 
913  if (func.is_string ())
914  {
915  std::string name = func.string_value ();
916  func = symbol_table::find_function (name);
917  if (func.is_undefined ())
918  error ("nargout: invalid function name: %s", name.c_str ());
919  }
920 
921  if (func.is_inline_function ())
922  {
923  retval = 1;
924  return retval;
925  }
926 
927  if (func.is_function_handle ())
928  {
929  octave_fcn_handle *fh = func.fcn_handle_value ();
930  std::string fh_nm = fh->fcn_name ();
931 
932  if (fh_nm == octave_fcn_handle::anonymous)
933  {
934  retval = -1;
935  return retval;
936  }
937  }
938 
939  octave_function *fcn_val = func.function_value ();
940  if (fcn_val)
941  {
942  octave_user_function *fcn = fcn_val->user_function_value (true);
943 
944  if (fcn)
945  {
946  tree_parameter_list *ret_list = fcn->return_list ();
947 
948  retval = ret_list ? ret_list->length () : 0;
949 
950  if (fcn->takes_var_return ())
951  retval = -1 - retval;
952  }
953  else
954  {
955  // JWE said this information is not available (2011-03-10)
956  // without making intrusive changes to Octave.
957  // Matlab gives up for histc,
958  // so maybe it's ok that we give up somtimes too?
959  error ("nargout: nargout information not available for builtin functions.");
960  }
961  }
962  else
963  error ("nargout: FCN must be a string or function handle");
964  }
965  else if (nargin == 0)
966  {
968  {
969  retval = symbol_table::varval (".nargout.");
970 
971  if (retval.is_undefined ())
972  retval = 0;
973  }
974  else
975  error ("nargout: invalid call at top level");
976  }
977  else
978  print_usage ();
979 
980  return retval;
981 }
982 
983 DEFUN (optimize_subsasgn_calls, args, nargout,
984  "-*- texinfo -*-\n\
985 @deftypefn {Built-in Function} {@var{val} =} optimize_subsasgn_calls ()\n\
986 @deftypefnx {Built-in Function} {@var{old_val} =} optimize_subsasgn_calls (@var{new_val})\n\
987 @deftypefnx {Built-in Function} {} optimize_subsasgn_calls (@var{new_val}, \"local\")\n\
988 Query or set the internal flag for subsasgn method call optimizations.\n\
989 If true, Octave will attempt to eliminate the redundant copying when calling\n\
990 subsasgn method of a user-defined class.\n\
991 \n\
992 When called from inside a function with the @qcode{\"local\"} option, the\n\
993 variable is changed locally for the function and any subroutines it calls. \n\
994 The original variable value is restored when exiting the function.\n\
995 @end deftypefn")
996 {
997  return SET_INTERNAL_VARIABLE (optimize_subsasgn_calls);
998 }
999 
1000 static bool val_in_table (const Matrix& table, double val)
1001 {
1002  if (table.is_empty ())
1003  return false;
1004 
1005  octave_idx_type i = table.lookup (val, ASCENDING);
1006  return (i > 0 && table(i-1) == val);
1007 }
1008 
1009 static bool isargout1 (int nargout, const Matrix& ignored, double k)
1010 {
1011  if (k != xround (k) || k <= 0)
1012  {
1013  error ("isargout: K must be a positive integer");
1014  return false;
1015  }
1016  else
1017  return (k == 1 || k <= nargout) && ! val_in_table (ignored, k);
1018 }
1019 
1020 DEFUN (isargout, args, ,
1021  "-*- texinfo -*-\n\
1022 @deftypefn {Built-in Function} {} isargout (@var{k})\n\
1023 Within a function, return a logical value indicating whether the argument\n\
1024 @var{k} will be assigned on output to a variable. If the result is false,\n\
1025 the argument has been ignored during the function call through the use of\n\
1026 the tilde (~) special output argument. Functions can use @code{isargout} to\n\
1027 avoid performing unnecessary calculations for outputs which are unwanted.\n\
1028 \n\
1029 If @var{k} is outside the range @code{1:max (nargout)}, the function returns\n\
1030 false. @var{k} can also be an array, in which case the function works\n\
1031 element-by-element and a logical array is returned. At the top level,\n\
1032 @code{isargout} returns an error.\n\
1033 @seealso{nargout, nargin, varargin, varargout, nthargout}\n\
1034 @end deftypefn")
1035 {
1036  octave_value retval;
1037 
1038  int nargin = args.length ();
1039 
1040  if (nargin == 1)
1041  {
1042  if (! symbol_table::at_top_level ())
1043  {
1044  int nargout1 = symbol_table::varval (".nargout.").int_value ();
1045  if (error_state)
1046  {
1047  error ("isargout: internal error");
1048  return retval;
1049  }
1050 
1051  Matrix ignored;
1052  octave_value tmp = symbol_table::varval (".ignored.");
1053  if (tmp.is_defined ())
1054  ignored = tmp.matrix_value ();
1055 
1056  if (args(0).is_scalar_type ())
1057  {
1058  double k = args(0).double_value ();
1059  if (! error_state)
1060  retval = isargout1 (nargout1, ignored, k);
1061  }
1062  else if (args(0).is_numeric_type ())
1063  {
1064  const NDArray ka = args(0).array_value ();
1065  if (! error_state)
1066  {
1067  boolNDArray r (ka.dims ());
1068  for (octave_idx_type i = 0;
1069  i < ka.numel () && ! error_state;
1070  i++)
1071  r(i) = isargout1 (nargout1, ignored, ka(i));
1072 
1073  retval = r;
1074  }
1075  }
1076  else
1077  gripe_wrong_type_arg ("isargout", args(0));
1078  }
1079  else
1080  error ("isargout: invalid call at top level");
1081  }
1082  else
1083  print_usage ();
1084 
1085  return retval;
1086 }
1087 
1088 /*
1089 %!function [x, y] = try_isargout ()
1090 %! if (isargout (1))
1091 %! if (isargout (2))
1092 %! x = 1; y = 2;
1093 %! else
1094 %! x = -1;
1095 %! endif
1096 %! else
1097 %! if (isargout (2))
1098 %! y = -2;
1099 %! else
1100 %! error ("no outputs requested");
1101 %! endif
1102 %! endif
1103 %!endfunction
1104 %!
1105 %!test
1106 %! [x, y] = try_isargout ();
1107 %! assert ([x, y], [1, 2]);
1108 %!
1109 %!test
1110 %! [x, ~] = try_isargout ();
1111 %! assert (x, -1);
1112 %!
1113 %!test
1114 %! [~, y] = try_isargout ();
1115 %! assert (y, -2);
1116 %!
1117 %!error [~, ~] = try_isargout ();
1118 %!
1119 %% Check to see that isargout isn't sticky:
1120 %!test
1121 %! [x, y] = try_isargout ();
1122 %! assert ([x, y], [1, 2]);
1123 %!
1124 %% It should work without ():
1125 %!test
1126 %! [~, y] = try_isargout;
1127 %! assert (y, -2);
1128 %!
1129 %% It should work in function handles, anonymous functions, and cell
1130 %% arrays of handles or anonymous functions.
1131 %!test
1132 %! fh = @try_isargout;
1133 %! af = @() try_isargout;
1134 %! c = {fh, af};
1135 %! [~, y] = fh ();
1136 %! assert (y, -2);
1137 %! [~, y] = af ();
1138 %! assert (y, -2);
1139 %! [~, y] = c{1}();
1140 %! assert (y, -2);
1141 %! [~, y] = c{2}();
1142 %! assert (y, -2);
1143 */