GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
call-stack.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1995-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 "lo-regexp.h"
31 #include "str-vec.h"
32 
33 #include "builtin-defun-decls.h"
34 #include "call-stack.h"
35 #include "defun.h"
36 #include "interpreter.h"
37 #include "interpreter-private.h"
38 #include "oct-map.h"
39 #include "ov.h"
40 #include "ov-fcn-handle.h"
41 #include "ov-fcn.h"
42 #include "ov-usr-fcn.h"
43 #include "pager.h"
44 #include "stack-frame.h"
45 #include "syminfo.h"
46 #include "symrec.h"
47 #include "symscope.h"
48 #include "variables.h"
49 
51 
52 // Use static fields for the best efficiency.
53 // NOTE: C++0x will allow these two to be merged into one.
54 static const char *bt_fieldnames[] =
55 { "file", "name", "line", "column", nullptr };
56 
57 static const octave_fields bt_fields (bt_fieldnames);
58 
60  : m_evaluator (evaluator), m_cs (), m_curr_frame (0),
61  m_max_stack_depth (1024), m_global_values ()
62 {
63  push (symbol_scope ("top scope"));
64 }
65 
67 call_stack::current_function (bool skip_first) const
68 {
69  if (m_cs.empty ())
70  error ("current_function: call stack is empty");
71 
72  octave_function *fcn = nullptr;
73 
74  std::size_t idx = m_curr_frame;
75 
76  if (idx > 0 && skip_first)
77  --idx;
78 
79  while (true)
80  {
81  fcn = m_cs[idx]->function ();
82 
83  if (fcn || idx == 0)
84  break;
85 
86  --idx;
87  }
88 
89  return fcn;
90 }
91 
92 int
94 {
95  int retval = -1;
96 
97  if (! m_cs.empty ())
98  {
99  const std::shared_ptr<stack_frame> elt = m_cs[m_curr_frame];
100  retval = elt->line ();
101  }
102 
103  return retval;
104 }
105 
106 int
108 {
109  int retval = -1;
110 
111  if (! m_cs.empty ())
112  {
113  const std::shared_ptr<stack_frame> elt = m_cs[m_curr_frame];
114  retval = elt->column ();
115  }
116 
117  return retval;
118 }
119 
122 {
123  // Start at current frame.
124 
125  std::size_t xframe = find_current_user_frame ();
126 
127  if (xframe > 0)
128  {
129  const std::shared_ptr<stack_frame> elt = m_cs[xframe];
130 
131  octave_function *f = elt->function ();
132 
133  if (f && f->is_user_code ())
134  return dynamic_cast<octave_user_code *> (f);
135  }
136 
137  return nullptr;
138 }
139 
140 int
142 {
143  // Start at current frame.
144 
145  std::size_t xframe = find_current_user_frame ();
146 
147  if (xframe > 0)
148  {
149  const std::shared_ptr<stack_frame> elt = m_cs[xframe];
150 
151  octave_function *f = elt->function ();
152 
153  if (f && f->is_user_code ())
154  {
155  int line = elt->line ();
156 
157  if (line > 0)
158  return line;
159  }
160  }
161 
162  return -1;
163 }
164 
165 int
167 {
168  // Start at current frame.
169 
170  std::size_t xframe = find_current_user_frame ();
171 
172  if (xframe > 0)
173  {
174  const std::shared_ptr<stack_frame> elt = m_cs[xframe];
175 
176  octave_function *f = elt->function ();
177 
178  if (f && f->is_user_code ())
179  {
180  int column = elt->column ();
181 
182  if (column > 0)
183  return column;
184  }
185  }
186 
187  return -1;
188 }
189 
192 {
193  // Start at current frame.
194 
195  std::size_t xframe = find_current_user_frame ();
196 
197  if (xframe > 0)
198  {
199  const std::shared_ptr<stack_frame> elt = m_cs[xframe];
200 
201  octave_function *f = elt->function ();
202 
203  if (f && f->is_user_code ())
204  return elt->unwind_protect_frame ();
205  }
206 
207  return nullptr;
208 }
209 
212 {
213  octave_user_code *retval = nullptr;
214 
215  // This should never happen...
216  if (m_curr_frame == 0)
217  return retval;
218 
219  std::size_t i = m_curr_frame;
220 
221  while (i != 0)
222  {
223  const std::shared_ptr<stack_frame> elt = m_cs[i--];
224 
225  octave_function *f = elt->function ();
226 
227  if (f && f->is_user_code ())
228  {
229  retval = dynamic_cast<octave_user_code *> (f);
230  break;
231  }
232  }
233 
234  return retval;
235 }
236 
237 int
239 {
240  int retval = -1;
241 
242  // This should never happen...
243  if (m_curr_frame == 0)
244  return retval;
245 
246  std::size_t i = m_curr_frame;
247 
248  while (i != 0)
249  {
250  const std::shared_ptr<stack_frame> elt = m_cs[i--];
251 
252  octave_function *f = elt->function ();
253 
254  if (f && f->is_user_code ())
255  {
256  if (elt->line ())
257  {
258  retval = elt->line ();
259  break;
260  }
261  }
262  }
263 
264  return retval;
265 }
266 
267 int
269 {
270  int retval = -1;
271 
272  // This should never happen...
273  if (m_curr_frame == 0)
274  return retval;
275 
276  // Start looking with the caller of the calling debug function.
277  std::size_t i = m_curr_frame;
278 
279  while (i != 0)
280  {
281  const std::shared_ptr<stack_frame> elt = m_cs[i--];
282 
283  octave_function *f = elt->function ();
284 
285  if (f && f->is_user_code ())
286  {
287  if (elt->column ())
288  {
289  retval = elt->column ();
290  break;
291  }
292  }
293  }
294 
295  return retval;
296 }
297 
298 std::string
300 {
301  return m_cs[m_curr_frame]->get_dispatch_class ();
302 }
303 
304 void
305 call_stack::set_dispatch_class (const std::string& class_name)
306 {
307  m_cs[m_curr_frame]->set_dispatch_class (class_name);
308 }
309 
310 bool
311 call_stack::is_class_method_executing (std::string& dispatch_class) const
312 {
313  dispatch_class = "";
314 
316 
317  bool retval = (f && f->is_class_method ());
318 
319  if (retval)
320  dispatch_class = f->dispatch_class ();
321 
322  return retval;
323 }
324 
325 bool
326 call_stack::is_class_constructor_executing (std::string& dispatch_class) const
327 {
328  dispatch_class = "";
329 
331 
332  bool retval = (f && f->is_class_constructor ());
333 
334  if (retval)
335  dispatch_class = f->dispatch_class ();
336 
337  return retval;
338 }
339 
340 bool
342 {
343  bool retval = true;
344 
345  auto p = m_cs.cend ();
346 
347  while (p != m_cs.cbegin ())
348  {
349  const std::shared_ptr<stack_frame> elt = *(--p);
350 
351  octave_function *f = elt->function ();
352 
353  if (f && ! f->is_user_script ())
354  {
355  retval = false;
356  break;
357  }
358  }
359 
360  return retval;
361 }
362 
363 void call_stack::get_new_frame_index_and_links
364 (std::size_t& new_frame_idx, std::shared_ptr<stack_frame>& parent_link,
365  std::shared_ptr<stack_frame>& static_link) const
366 {
367  // FIXME: is there a better way?
368 
369  std::size_t prev_frame_idx = m_curr_frame;
370 
371  new_frame_idx = m_cs.size ();
372 
373  // m_max_stack_depth should never be less than zero.
374  if (new_frame_idx > static_cast<std::size_t> (m_max_stack_depth))
375  error ("max_stack_depth exceeded");
376 
377  // There can't be any links to previous frames if this is the first
378  // frame on the stack.
379 
380  if (new_frame_idx == 0)
381  return;
382 
383  parent_link = m_cs[prev_frame_idx];
384 
385  octave_function *t_fcn = parent_link->function ();
386 
387  static_link = (t_fcn
388  ? (t_fcn->is_user_code ()
389  ? parent_link : parent_link->static_link ())
390  : parent_link);
391 }
392 
393 void
395 {
396  std::size_t new_frame_idx;
397  std::shared_ptr<stack_frame> parent_link;
398  std::shared_ptr<stack_frame> static_link;
399 
400  get_new_frame_index_and_links (new_frame_idx, parent_link, static_link);
401 
402  std::shared_ptr<stack_frame>
403  new_frame (stack_frame::create (m_evaluator, scope, new_frame_idx,
404  parent_link, static_link));
405 
406  m_cs.push_back (new_frame);
407 
408  m_curr_frame = new_frame_idx;
409 }
410 
411 void
413  const std::shared_ptr<stack_frame>& closure_frames)
414 {
415  std::size_t new_frame_idx;
416  std::shared_ptr<stack_frame> parent_link;
417  std::shared_ptr<stack_frame> static_link;
418 
419  get_new_frame_index_and_links (new_frame_idx, parent_link, static_link);
420 
421  std::shared_ptr<stack_frame>
422  new_frame (stack_frame::create (m_evaluator, fcn, new_frame_idx,
423  parent_link, static_link,
424  closure_frames));
425 
426  m_cs.push_back (new_frame);
427 
428  m_curr_frame = new_frame_idx;
429 }
430 
431 void
433  const stack_frame::local_vars_map& local_vars,
434  const std::shared_ptr<stack_frame>& closure_frames)
435 {
436  std::size_t new_frame_idx;
437  std::shared_ptr<stack_frame> parent_link;
438  std::shared_ptr<stack_frame> static_link;
439 
440  get_new_frame_index_and_links (new_frame_idx, parent_link, static_link);
441 
442  std::shared_ptr<stack_frame>
443  new_frame (stack_frame::create (m_evaluator, fcn, new_frame_idx,
444  parent_link, static_link, local_vars,
445  closure_frames));
446 
447  m_cs.push_back (new_frame);
448 
449  m_curr_frame = new_frame_idx;
450 }
451 
452 void
454 {
455  std::size_t new_frame_idx;
456  std::shared_ptr<stack_frame> parent_link;
457  std::shared_ptr<stack_frame> static_link;
458 
459  get_new_frame_index_and_links (new_frame_idx, parent_link, static_link);
460 
461  std::shared_ptr<stack_frame>
462  new_frame (stack_frame::create (m_evaluator, script, new_frame_idx,
463  parent_link, static_link));
464 
465  m_cs.push_back (new_frame);
466 
467  m_curr_frame = new_frame_idx;
468 }
469 
470 void
472 {
473  std::size_t new_frame_idx;
474  std::shared_ptr<stack_frame> parent_link;
475  std::shared_ptr<stack_frame> static_link;
476 
477  get_new_frame_index_and_links (new_frame_idx, parent_link, static_link);
478 
479  std::shared_ptr<stack_frame>
480  new_frame (stack_frame::create (m_evaluator, fcn, new_frame_idx,
481  parent_link, static_link));
482 
483  m_cs.push_back (new_frame);
484 
485  m_curr_frame = new_frame_idx;
486 }
487 
488 bool
489 call_stack::goto_frame (std::size_t n, bool verbose)
490 {
491  bool retval = false;
492 
493  if (n < m_cs.size ())
494  {
495  retval = true;
496 
497  m_curr_frame = n;
498 
499  if (verbose)
500  {
501  const std::shared_ptr<stack_frame> elt = m_cs[n];
502 
503  elt->display_stopped_in_message (octave_stdout);
504  }
505  }
506 
507  return retval;
508 }
509 
510 std::size_t
512 {
513  std::size_t user_frame = m_curr_frame;
514 
515  std::shared_ptr<stack_frame> frm = m_cs[user_frame];
516 
517  if (! (frm->is_user_fcn_frame () || frm->is_user_script_frame ()
518  || frm->is_scope_frame ()))
519  {
520  frm = frm->static_link ();
521 
522  user_frame = frm->index ();
523  }
524 
525  return user_frame;
526 }
527 
528 std::shared_ptr<stack_frame>
530 {
531  std::size_t frame = find_current_user_frame ();
532 
533  return m_cs[frame];
534 }
535 
536 // Go to the Nth frame (up if N is negative or down if positive) in
537 // the call stack that corresponds to a script, function, or scope
538 // beginning with the frame indexed by START.
539 
540 std::size_t
541 call_stack::dbupdown (std::size_t start, int n, bool verbose)
542 {
543  if (start >= m_cs.size ())
544  error ("invalid stack frame");
545 
546  // Can't go up from here.
547 
548  if (start == 0 && n < 0)
549  {
550  if (verbose)
551  m_cs[start]->display_stopped_in_message (octave_stdout);
552 
553  return start;
554  }
555 
556  std::shared_ptr<stack_frame> frm = m_cs[start];
557 
558  if (! (frm && (frm->is_user_fcn_frame ()
559  || frm->is_user_script_frame ()
560  || frm->is_scope_frame ())))
561  error ("call_stack::dbupdown: invalid initial frame in call stack!");
562 
563  // Use index into the call stack to begin the search. At this point
564  // we iterate up or down using indexing instead of static links
565  // because ... FIXME: it's a bit complicated, but deserves
566  // explanation. May be easiest with some pictures of the call stack
567  // for an example or two.
568 
569  std::size_t xframe = frm->index ();
570 
571  if (n == 0)
572  {
573  if (verbose)
574  frm->display_stopped_in_message (octave_stdout);
575 
576  return xframe;
577  }
578 
579  int incr = 0;
580 
581  if (n < 0)
582  {
583  incr = -1;
584  n = -n;
585  }
586  else if (n > 0)
587  incr = 1;
588 
589  std::size_t last_good_frame = 0;
590 
591  while (true)
592  {
593  frm = m_cs[xframe];
594 
595  if (frm->is_user_fcn_frame () || frm->is_user_script_frame ()
596  || frm->is_scope_frame ())
597  {
598  last_good_frame = xframe;
599 
600  if (n == 0)
601  break;
602 
603  n--;
604  }
605 
606  xframe += incr;
607 
608  if (xframe == 0)
609  {
610  last_good_frame = 0;
611  break;
612  }
613 
614  if (xframe == m_cs.size ())
615  break;
616  }
617 
618  if (verbose)
619  m_cs[last_good_frame]->display_stopped_in_message (octave_stdout);
620 
621  return last_good_frame;
622 }
623 
624 // Like dbupdown above but find the starting frame automatically from
625 // the current frame. If the current frame is already a user
626 // function, script, or scope frame, use that. Otherwise, follow
627 // the static link for the current frame. If that is not a user
628 // function, script or scope frame then there is an error in the
629 // implementation.
630 
631 std::size_t
632 call_stack::dbupdown (int n, bool verbose)
633 {
634  std::size_t start = find_current_user_frame ();
635 
636  return dbupdown (start, n, verbose);
637 }
638 
639 // May be used to temporarily change the value ov m_curr_frame inside
640 // a function like evalin. If used in a function like dbup, the new
641 // value of m_curr_frame would be wiped out when dbup returns and the
642 // stack frame for dbup is popped.
643 
644 void
646 {
647  std::size_t start = find_current_user_frame ();
648 
649  std::shared_ptr<stack_frame> caller_frame = m_cs[start]->static_link ();
650 
651  // Allow evalin ('caller', ...) to work when called from the
652  // top-level prompt.
653 
654  m_curr_frame = caller_frame ? caller_frame->index () : 0;
655 }
656 
657 void
659 {
660  if (m_curr_frame > 0)
661  m_curr_frame = 0;
662 }
663 
664 std::list<std::shared_ptr<stack_frame>>
666 {
667  std::list<std::shared_ptr<stack_frame>> frames;
668 
669  // curr_frame is the index to the current frame in the overall call
670  // stack, which includes any compiled function frames and scope
671  // frames. The curr_user_frame value we set is the index into the
672  // subset of frames returned in the octave_map object.
673 
674  std::size_t curr_frame = find_current_user_frame ();
675 
676  // Don't include top-level stack frame in the list.
677 
678  for (std::size_t n = m_cs.size () - 1; n > 0; n--)
679  {
680  std::shared_ptr<stack_frame> frm = m_cs[n];
681 
682  if (frm->is_user_script_frame () || frm->is_user_fcn_frame ()
683  || frm->is_scope_frame ())
684  {
685  if (frm->index () == curr_frame)
686  curr_user_frame = frames.size ();
687 
688  frames.push_back (frm);
689  }
690 
691  if (n == 0)
692  break;
693  }
694 
695  return frames;
696 }
697 
698 std::list<std::shared_ptr<stack_frame>>
700 {
701  octave_idx_type curr_user_frame = -1;
702 
703  return backtrace_frames (curr_user_frame);
704 }
705 
706 std::list<frame_info>
708  bool print_subfn) const
709 {
710  std::list<std::shared_ptr<stack_frame>> frames
711  = backtrace_frames (curr_user_frame);
712 
713  std::list<frame_info> retval;
714 
715  for (const auto& frm : frames)
716  {
717  if (frm->is_user_script_frame () || frm->is_user_fcn_frame ()
718  || frm->is_scope_frame ())
719  {
720  retval.push_back (frame_info (frm->fcn_file_name (),
721  frm->fcn_name (print_subfn),
722  frm->line (), frm->column ()));
723  }
724  }
725 
726  return retval;
727 }
728 
729 std::list<frame_info>
731 {
732  octave_idx_type curr_user_frame = -1;
733 
734  return backtrace_info (curr_user_frame, true);
735 }
736 
739  bool print_subfn) const
740 {
741  std::list<std::shared_ptr<stack_frame>> frames
742  = backtrace_frames (curr_user_frame);
743 
744  std::size_t nframes = frames.size ();
745 
746  octave_map retval (dim_vector (nframes, 1), bt_fields);
747 
748  Cell& file = retval.contents (0);
749  Cell& name = retval.contents (1);
750  Cell& line = retval.contents (2);
751  Cell& column = retval.contents (3);
752 
753  octave_idx_type k = 0;
754 
755  for (const auto& frm : frames)
756  {
757  if (frm->is_user_script_frame () || frm->is_user_fcn_frame ()
758  || frm->is_scope_frame ())
759  {
760  file(k) = frm->fcn_file_name ();
761  name(k) = frm->fcn_name (print_subfn);
762  line(k) = frm->line ();
763  column(k) = frm->column ();
764 
765  k++;
766  }
767  }
768 
769  return retval;
770 }
771 
774 {
775  octave_idx_type curr_user_frame = -1;
776 
777  return backtrace (curr_user_frame, true);
778 }
779 
782 {
783  return octave_map (dim_vector (0, 1), bt_fields);
784 }
785 
786 void
788 {
789  // Never pop top scope.
790  // FIXME: is it possible for this case to happen?
791 
792  if (m_cs.size () > 1)
793  {
794  std::shared_ptr<stack_frame> elt = m_cs.back ();
795 
796  std::shared_ptr<stack_frame> caller = elt->parent_link ();
797 
798  m_curr_frame = caller->index ();
799 
800  if (elt->is_closure_context ())
801  elt->break_closure_cycles (elt);
802 
803  elt->clear_parent_static_link ();
804 
805  m_cs.pop_back ();
806  }
807 }
808 
809 std::shared_ptr<stack_frame>
811 {
812  if (!m_cs.empty ())
813  {
814  std::shared_ptr<stack_frame> elt = std::move (m_cs.back ());
815  m_cs.pop_back ();
816 
817  m_curr_frame = elt->parent_frame_index ();
818 
819  if (elt->is_closure_context ())
820  elt->break_closure_cycles (elt);
821 
822  elt->clear_parent_static_link ();
823 
824  return elt;
825  }
826 
827  return nullptr;
828 }
829 
830 void
832 {
833  while (! m_cs.empty ())
834  pop ();
835 }
836 
839 {
840  return m_cs[m_curr_frame]->all_variables ();
841 }
842 
843 std::list<std::string>
845 {
846  std::list<std::string> retval;
847 
848  for (const auto& nm_ov : m_global_values)
849  {
850  if (nm_ov.second.is_defined ())
851  retval.push_back (nm_ov.first);
852  }
853 
854  retval.sort ();
855 
856  return retval;
857 }
858 
859 std::list<std::string>
861 {
862  return m_cs[0]->variable_names ();
863 }
864 
865 std::list<std::string>
867 {
868  return m_cs[m_curr_frame]->variable_names ();
869 }
870 
871 void
872 call_stack::clear_global_variable (const std::string& name)
873 {
874  auto p = m_global_values.find (name);
875 
876  if (p != m_global_values.end ())
877  p->second = octave_value ();
878 }
879 
880 void
881 call_stack::clear_global_variable_pattern (const std::string& pattern)
882 {
883  symbol_match pat (pattern);
884 
885  for (auto& nm_ov : m_global_values)
886  {
887  if (pat.match (nm_ov.first))
888  nm_ov.second = octave_value ();
889  }
890 }
891 
892 void
893 call_stack::clear_global_variable_regexp (const std::string& pattern)
894 {
895  regexp pat (pattern);
896 
897  for (auto& nm_ov : m_global_values)
898  {
899  if (pat.is_match (nm_ov.first))
900  nm_ov.second = octave_value ();
901  }
902 }
903 
904 void
906 {
907  for (auto& nm_ov : m_global_values)
908  nm_ov.second = octave_value ();
909 }
910 
912 call_stack::glob_symbol_info (const std::string& pattern) const
913 {
914  return m_cs[m_curr_frame]->glob_symbol_info (pattern);
915 }
916 
918 call_stack::regexp_symbol_info (const std::string& pattern) const
919 {
920  return m_cs[m_curr_frame]->regexp_symbol_info (pattern);
921 }
922 
925 {
926  return m_cs[m_curr_frame]->get_symbol_info ();
927 }
928 
931 {
932  return m_cs[0]->get_symbol_info ();
933 }
934 
937  int nargout)
938 {
939  return set_internal_variable (m_max_stack_depth, args, nargout,
940  "max_stack_depth", 0);
941 }
942 
943 void
945 {
946  m_cs[m_curr_frame]->make_persistent (sym);
947 }
948 
949 void
951 {
952  m_cs[m_curr_frame]->make_global (sym);
953 }
954 
956 call_stack::global_varval (const std::string& name) const
957 {
958  auto p = m_global_values.find (name);
959 
960  return p == m_global_values.end () ? octave_value () : p->second;
961 }
962 
964 call_stack::global_varref (const std::string& name)
965 {
966  return m_global_values[name];
967 }
968 
970 call_stack::get_top_level_value (const std::string& name) const
971 {
972  return m_cs[0]->varval (name);
973 }
974 
975 void
976 call_stack::set_top_level_value (const std::string& name,
977  const octave_value& value)
978 {
979  m_cs[0]->assign (name, value);
980 }
981 
983 call_stack::do_who (int argc, const string_vector& argv,
984  bool return_list, bool verbose)
985 {
986  octave_value retval;
987 
988  std::string my_name = argv[0];
989 
990  std::string file_name;
991 
992  bool from_file = false;
993  bool global_only = false;
994  bool have_regexp = false;
995 
996  int i = 1;
997  while (i < argc)
998  {
999  if (argv[i] == "-file")
1000  {
1001  if (from_file)
1002  error ("%s: -file option may only be specified once",
1003  my_name.c_str ());
1004 
1005  from_file = true;
1006 
1007  if (i == argc - 1)
1008  error ("%s: -file argument must be followed by a filename",
1009  my_name.c_str ());
1010 
1011  file_name = argv[++i];
1012  }
1013  else if (argv[i] == "-regexp")
1014  {
1015  have_regexp = true;
1016  }
1017  else if (argv[i] == "global")
1018  global_only = true;
1019  else if (argv[i][0] == '-')
1020  warning ("%s: unrecognized option '%s'", my_name.c_str (),
1021  argv[i].c_str ());
1022  else
1023  break;
1024 
1025  i++;
1026  }
1027 
1028  int npatterns = argc - i;
1029  string_vector patterns;
1030  if (npatterns > 0)
1031  {
1032  patterns.resize (npatterns);
1033  for (int j = 0; j < npatterns; j++)
1034  patterns[j] = argv[i+j];
1035  }
1036  else
1037  {
1038  patterns.resize (1);
1039  patterns[0] = "*";
1040  }
1041 
1042  if (from_file)
1043  {
1044  // FIXME: This is an inefficient manner to implement this as the
1045  // variables are loaded in to a temporary context and then treated.
1046  // It would be better to refactor symbol_info_list to not store the
1047  // symbol records and then use it in load-save.cc (do_load) to
1048  // implement this option there so that the variables are never
1049  // stored at all.
1050 
1051  // Set up temporary scope.
1052 
1053  symbol_scope tmp_scope (file_name);
1054 
1055  push (tmp_scope);
1056 
1057  unwind_action restore_scope ([=] () { pop (); });
1058 
1059  interpreter& interp = m_evaluator.get_interpreter ();
1060 
1061  Fload (interp, ovl (file_name));
1062 
1063  std::string newmsg = "Variables in the file " + file_name + ":\n";
1064 
1065  if (global_only)
1066  return do_global_who_two (patterns, have_regexp, return_list,
1067  verbose, newmsg);
1068  else
1069  return do_who_two (patterns, have_regexp, return_list, verbose,
1070  newmsg);
1071  }
1072  else
1073  {
1074  if (global_only)
1075  return do_global_who_two (patterns, have_regexp, return_list,
1076  verbose);
1077  else
1078  return do_who_two (patterns, have_regexp, return_list, verbose);
1079  }
1080 }
1081 
1084  bool have_regexp, bool return_list,
1085  bool verbose, const std::string& msg)
1086 {
1087  return m_cs[m_curr_frame]->who (patterns, have_regexp, return_list,
1088  verbose, m_evaluator.whos_line_format (),
1089  msg);
1090 }
1091 
1094  bool have_regexp,
1095  bool return_list, bool verbose,
1096  const std::string& msg)
1097 {
1098  symbol_info_list symbol_stats;
1099  std::list<std::string> symbol_names;
1100 
1101  octave_idx_type npatterns = patterns.numel ();
1102 
1103  for (octave_idx_type j = 0; j < npatterns; j++)
1104  {
1105  std::string pattern = patterns[j];
1106 
1107  std::list<std::string> tmp;
1108 
1109  if (have_regexp)
1110  {
1111  regexp pat (pattern);
1112 
1113  for (auto& nm_ov : m_global_values)
1114  {
1115  if (pat.is_match (nm_ov.first))
1116  tmp.push_back (nm_ov.first);
1117  }
1118  }
1119  else
1120  {
1121  symbol_match pat (pattern);
1122 
1123  for (auto& nm_ov : m_global_values)
1124  {
1125  if (pat.match (nm_ov.first))
1126  tmp.push_back (nm_ov.first);
1127  }
1128  }
1129 
1130  for (const auto& nm : tmp)
1131  {
1132  octave_value value = m_global_values[nm];
1133 
1134  if (value.is_defined ())
1135  {
1136  if (verbose)
1137  {
1138  bool is_formal = false;
1139  bool is_global = true;
1140  bool is_persistent = false;
1141 
1142  symbol_info syminf (nm, value, is_formal, is_global,
1143  is_persistent);
1144 
1145  symbol_stats.append (syminf);
1146  }
1147  else
1148  symbol_names.push_back (nm);
1149  }
1150  }
1151  }
1152 
1153  if (return_list)
1154  {
1155  if (verbose)
1156  {
1157  std::string caller_fcn_name;
1158  octave_function *caller_fcn = caller_function ();
1159  if (caller_fcn)
1160  caller_fcn_name = caller_fcn->name ();
1161 
1162  return symbol_stats.map_value (caller_fcn_name, 1);
1163  }
1164  else
1165  return Cell (string_vector (symbol_names));
1166  }
1167  else if (! (symbol_stats.empty () && symbol_names.empty ()))
1168  {
1169  if (msg.empty ())
1170  octave_stdout << "Global variables:\n\n";
1171  else
1172  octave_stdout << msg;
1173 
1174  if (verbose)
1175  symbol_stats.display (octave_stdout,
1176  m_evaluator.whos_line_format ());
1177  else
1178  {
1179  string_vector names (symbol_names);
1180 
1182  }
1183 
1184  octave_stdout << "\n";
1185  }
1186 
1187  return octave_value ();
1188 }
1189 
1190 void
1192 {
1193  std::ostream& os = octave_stdout;
1194 
1195  std::size_t nframes = size ();
1196 
1197  for (std::size_t i = 0; i < nframes; i++)
1198  {
1199  m_cs[i]->display (false);
1200  if (i < nframes - 1)
1201  os << std::endl;
1202  }
1203 }
1204 
1205 void
1207  const octave_value& val)
1208 {
1209  m_cs[m_curr_frame]->set_auto_fcn_var (avt, val);
1210 }
1211 
1212 void
1214 {
1215  m_cs[m_curr_frame]->set_nargin (nargin);
1216 }
1217 
1218 void
1220 {
1221  m_cs[m_curr_frame]->set_nargout (nargout);
1222 }
1223 
1226 {
1227  return m_cs[m_curr_frame]->get_auto_fcn_var (avt);
1228 }
1229 
1230 DEFMETHOD (max_stack_depth, interp, args, nargout,
1231  doc: /* -*- texinfo -*-
1232 @deftypefn {} {@var{val} =} max_stack_depth ()
1233 @deftypefnx {} {@var{old_val} =} max_stack_depth (@var{new_val})
1234 @deftypefnx {} {@var{old_val} =} max_stack_depth (@var{new_val}, "local")
1235 Query or set the internal limit on the number of times a function may
1236 be called recursively.
1237 
1238 If the limit is exceeded, an error message is printed and control returns to
1239 the top level.
1240 
1241 When called from inside a function with the @qcode{"local"} option, the
1242 variable is changed locally for the function and any subroutines it calls.
1243 The original variable value is restored when exiting the function.
1244 
1245 @seealso{max_recursion_depth}
1246 @end deftypefn */)
1247 {
1248  tree_evaluator& tw = interp.get_evaluator ();
1249 
1250  return tw.max_stack_depth (args, nargout);
1251 }
1252 
1253 /*
1254 %!test
1255 %! orig_val = max_stack_depth ();
1256 %! old_val = max_stack_depth (2*orig_val);
1257 %! assert (orig_val, old_val);
1258 %! assert (max_stack_depth (), 2*orig_val);
1259 %! max_stack_depth (orig_val);
1260 %! assert (max_stack_depth (), orig_val);
1261 
1262 %!error max_stack_depth (1, 2)
1263 */
1264 
1265 DEFMETHOD (who, interp, args, nargout,
1266  doc: /* -*- texinfo -*-
1267 @deftypefn {} {} who
1268 @deftypefnx {} {} who pattern @dots{}
1269 @deftypefnx {} {} who option pattern @dots{}
1270 @deftypefnx {} {C =} who (@dots{})
1271 List currently defined variables matching the given patterns.
1272 
1273 Valid pattern syntax is the same as described for the @code{clear} command.
1274 If no patterns are supplied, all variables are listed.
1275 
1276 By default, only variables visible in the local scope are displayed.
1277 
1278 The following are valid options, but may not be combined.
1279 
1280 @table @code
1281 @item global
1282 List variables in the global scope rather than the current scope.
1283 
1284 @item -regexp
1285 The patterns are considered to be regular expressions when matching the
1286 variables to display. The same pattern syntax accepted by the @code{regexp}
1287 function is used.
1288 
1289 @item -file
1290 The next argument is treated as a filename. All variables found within the
1291 specified file are listed. No patterns are accepted when reading variables
1292 from a file.
1293 @end table
1294 
1295 If called as a function, return a cell array of defined variable names
1296 matching the given patterns.
1297 @seealso{whos, isglobal, isvarname, exist, regexp}
1298 @end deftypefn */)
1299 {
1300  int argc = args.length () + 1;
1301 
1302  string_vector argv = args.make_argv ("who");
1303 
1304  tree_evaluator& tw = interp.get_evaluator ();
1305 
1306  return tw.do_who (argc, argv, nargout == 1);
1307 }
1308 
1309 /*
1310 %!test
1311 %! avar = magic (4);
1312 %! ftmp = [tempname() ".mat"];
1313 %! save_default_options ("-binary", "local");
1314 %! unwind_protect
1315 %! save (ftmp, "avar");
1316 %! vars = whos ("-file", ftmp);
1317 %! assert (numel (vars), 1);
1318 %! assert (isstruct (vars));
1319 %! assert (vars.name, "avar");
1320 %! assert (vars.size, [4, 4]);
1321 %! assert (vars.class, "double");
1322 %! assert (vars.bytes, 128);
1323 %! unwind_protect_cleanup
1324 %! unlink (ftmp);
1325 %! end_unwind_protect
1326 */
1327 
1328 DEFMETHOD (whos, interp, args, nargout,
1329  doc: /* -*- texinfo -*-
1330 @deftypefn {} {} whos
1331 @deftypefnx {} {} whos pattern @dots{}
1332 @deftypefnx {} {} whos option pattern @dots{}
1333 @deftypefnx {} {S =} whos ("pattern", @dots{})
1334 Provide detailed information on currently defined variables matching the
1335 given patterns.
1336 
1337 Options and pattern syntax are the same as for the @code{who} command.
1338 
1339 Extended information about each variable is summarized in a table with the
1340 following default entries.
1341 
1342 @table @asis
1343 @item Attr
1344 Attributes of the listed variable. Possible attributes are:
1345 
1346 @table @asis
1347 @item blank
1348 Variable in local scope
1349 
1350 @item @code{c}
1351 Variable of complex type.
1352 
1353 @item @code{f}
1354 Formal parameter (function argument).
1355 
1356 @item @code{g}
1357 Variable with global scope.
1358 
1359 @item @code{p}
1360 Persistent variable.
1361 @end table
1362 
1363 @item Name
1364 The name of the variable.
1365 
1366 @item Size
1367 The logical size of the variable. A scalar is 1x1, a vector is
1368 @nospell{1xN} or @nospell{Nx1}, a 2-D matrix is @nospell{MxN}.
1369 
1370 @item Bytes
1371 The amount of memory currently used to store the variable.
1372 
1373 @item Class
1374 The class of the variable. Examples include double, single, char, uint16,
1375 cell, and struct.
1376 @end table
1377 
1378 The table can be customized to display more or less information through
1379 the function @code{whos_line_format}.
1380 
1381 If @code{whos} is called as a function, return a struct array of defined
1382 variable names matching the given patterns. Fields in the structure
1383 describing each variable are: name, size, bytes, class, global, sparse,
1384 complex, nesting, persistent.
1385 @seealso{who, whos_line_format}
1386 @end deftypefn */)
1387 {
1388  int argc = args.length () + 1;
1389 
1390  string_vector argv = args.make_argv ("whos");
1391 
1392  tree_evaluator& tw = interp.get_evaluator ();
1393 
1394  return tw.do_who (argc, argv, nargout == 1, true);
1395 }
1396 
1397 OCTAVE_END_NAMESPACE(octave)
octave_value_list Fload(octave::interpreter &, const octave_value_list &=octave_value_list(), int=0)
Definition: Cell.h:43
Cell column(octave_idx_type i) const
Definition: Cell.cc:303
void append(const elt_type &s)
Definition: base-list.h:92
bool empty() const
Definition: base-list.h:50
void set_dispatch_class(const std::string &class_name)
Definition: call-stack.cc:305
octave_function * caller_function() const
Definition: call-stack.h:76
octave_value do_who(int argc, const string_vector &argv, bool return_list, bool verbose=false)
Definition: call-stack.cc:983
octave_value get_top_level_value(const std::string &name) const
Definition: call-stack.cc:970
octave_value global_varval(const std::string &name) const
Definition: call-stack.cc:956
std::size_t find_current_user_frame() const
Definition: call-stack.cc:511
std::list< std::shared_ptr< stack_frame > > backtrace_frames() const
Definition: call-stack.cc:699
octave_value & global_varref(const std::string &name)
Definition: call-stack.cc:964
octave_value do_who_two(const string_vector &patterns, bool have_regexp, bool return_list, bool verbose, const std::string &msg="")
Definition: call-stack.cc:1083
void set_top_level_value(const std::string &name, const octave_value &value)
Definition: call-stack.cc:976
int current_user_code_column() const
Definition: call-stack.cc:166
int current_line() const
Definition: call-stack.cc:93
void display() const
Definition: call-stack.cc:1191
void pop()
Definition: call-stack.cc:787
octave_value get_auto_fcn_var(stack_frame::auto_var_type avt) const
Definition: call-stack.cc:1225
std::list< std::string > variable_names() const
Definition: call-stack.cc:866
symbol_info_list regexp_symbol_info(const std::string &pattern) const
Definition: call-stack.cc:918
void make_global(const symbol_record &sym)
Definition: call-stack.cc:950
std::shared_ptr< stack_frame > current_user_frame() const
Definition: call-stack.cc:529
std::size_t size() const
Definition: call-stack.h:89
std::shared_ptr< stack_frame > pop_return()
Definition: call-stack.cc:810
void clear_global_variables()
Definition: call-stack.cc:905
symbol_info_list glob_symbol_info(const std::string &pattern) const
Definition: call-stack.cc:912
bool is_class_method_executing(std::string &dispatch_class) const
Definition: call-stack.cc:311
bool goto_frame(std::size_t n=0, bool verbose=false)
Definition: call-stack.cc:489
int debug_user_code_column() const
Definition: call-stack.cc:268
void set_auto_fcn_var(stack_frame::auto_var_type avt, const octave_value &val)
Definition: call-stack.cc:1206
symbol_info_list get_symbol_info()
Definition: call-stack.cc:924
symbol_info_list top_scope_symbol_info() const
Definition: call-stack.cc:930
std::list< std::string > global_variable_names() const
Definition: call-stack.cc:844
bool is_class_constructor_executing(std::string &dispatch_class) const
Definition: call-stack.cc:326
void goto_caller_frame()
Definition: call-stack.cc:645
octave_map empty_backtrace() const
Definition: call-stack.cc:781
octave_function * current_function(bool skip_first=false) const
Definition: call-stack.cc:67
octave_value do_global_who_two(const string_vector &patterns, bool have_regexp, bool return_list, bool verbose, const std::string &msg="")
Definition: call-stack.cc:1093
void clear_global_variable_pattern(const std::string &pattern)
Definition: call-stack.cc:881
unwind_protect * curr_fcn_unwind_protect_frame()
Definition: call-stack.cc:191
octave_map backtrace() const
Definition: call-stack.cc:773
int debug_user_code_line() const
Definition: call-stack.cc:238
octave_user_code * debug_user_code() const
Definition: call-stack.cc:211
call_stack(tree_evaluator &evaluator)
Definition: call-stack.cc:59
symbol_info_list all_variables()
Definition: call-stack.cc:838
void push(const symbol_scope &scope)
Definition: call-stack.cc:394
std::list< std::string > top_level_variable_names() const
Definition: call-stack.cc:860
bool all_scripts() const
Definition: call-stack.cc:341
void set_nargin(int nargin)
Definition: call-stack.cc:1213
void clear_global_variable(const std::string &name)
Definition: call-stack.cc:872
octave_user_code * current_user_code() const
Definition: call-stack.cc:121
void goto_base_frame()
Definition: call-stack.cc:658
std::list< frame_info > backtrace_info() const
Definition: call-stack.cc:730
void set_nargout(int nargout)
Definition: call-stack.cc:1219
int current_user_code_line() const
Definition: call-stack.cc:141
std::size_t dbupdown(std::size_t start, int n, bool verbose)
Definition: call-stack.cc:541
int current_column() const
Definition: call-stack.cc:107
std::string get_dispatch_class() const
Definition: call-stack.cc:299
void clear()
Definition: call-stack.cc:831
void clear_global_variable_regexp(const std::string &pattern)
Definition: call-stack.cc:893
void make_persistent(const symbol_record &sym)
Definition: call-stack.cc:944
octave_value max_stack_depth(const octave_value_list &args, int nargout)
Definition: call-stack.cc:936
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
line(const graphics_handle &mh, const graphics_handle &p)
Definition: graphics.h:7672
virtual bool is_user_code() const
Definition: ov-base.h:537
std::string name() const
Definition: ov-fcn.h:206
const Cell & contents(const_iterator p) const
Definition: oct-map.h:310
bool is_defined() const
Definition: ov.h:592
bool is_match(const std::string &buffer) const
Definition: lo-regexp.cc:584
static stack_frame * create(tree_evaluator &tw, octave_function *fcn, std::size_t index, const std::shared_ptr< stack_frame > &parent_link, const std::shared_ptr< stack_frame > &static_link)
std::map< std::string, octave_value > local_vars_map
Definition: stack-frame.h:112
void resize(octave_idx_type n, const std::string &rfv="")
Definition: str-vec.h:95
std::ostream & list_in_columns(std::ostream &, int width=0, const std::string &prefix="") const
Definition: str-vec.cc:201
octave_idx_type numel() const
Definition: str-vec.h:100
void display(std::ostream &os, const std::string &format) const
Definition: syminfo.cc:334
octave_map map_value(const std::string &caller_function_name, int nesting_level) const
Definition: syminfo.cc:193
bool match(const std::string &sym)
Definition: glob-match.cc:86
interpreter & get_interpreter()
Definition: pt-eval.h:420
octave_value do_who(int argc, const string_vector &argv, bool return_list, bool verbose=false)
Definition: pt-eval.cc:4770
octave_value max_stack_depth(const octave_value_list &args, int nargout)
Definition: pt-eval.cc:2765
octave_value whos_line_format(const octave_value_list &args, int nargout)
Definition: pt-eval.cc:4714
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition: defun.h:111
void warning(const char *fmt,...)
Definition: error.cc:1063
void() error(const char *fmt,...)
Definition: error.cc:988
F77_RET_T const F77_DBLE const F77_DBLE * f
octave_idx_type n
Definition: mx-inlines.cc:761
octave_value set_internal_variable(bool &var, const octave_value_list &args, int nargout, const char *nm)
Definition: variables.cc:583
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
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