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