GNU Octave 7.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-2022 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
50OCTAVE_NAMESPACE_BEGIN
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
776 {
777 while (! m_cs.empty ())
778 pop ();
779 }
780
781 symbol_info_list call_stack::all_variables (void)
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
847 symbol_info_list
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
853 symbol_info_list
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
859 symbol_info_list call_stack::get_symbol_info (void)
860 {
861 return m_cs[m_curr_frame]->get_symbol_info ();
862 }
863
864 symbol_info_list call_stack::top_scope_symbol_info (void) const
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
876 void call_stack::make_persistent (const symbol_record& sym)
877 {
878 m_cs[m_curr_frame]->make_persistent (sym);
879 }
880
881 void call_stack::make_global (const symbol_record& sym)
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
894 {
895 return m_global_values[name];
896 }
897
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
1126 void call_stack::set_auto_fcn_var (stack_frame::auto_var_type avt,
1127 const octave_value& val)
1128 {
1129 m_cs[m_curr_frame]->set_auto_fcn_var (avt, val);
1130 }
1131
1132 octave_value call_stack::get_auto_fcn_var (stack_frame::auto_var_type avt) const
1133 {
1134 return m_cs[m_curr_frame]->get_auto_fcn_var (avt);
1135 }
1136
1137DEFMETHOD (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 {} {} max_stack_depth (@var{new_val}, "local")
1142Query or set the internal limit on the number of times a function may
1143be called recursively.
1144
1145If the limit is exceeded, an error message is printed and control returns to
1146the top level.
1147
1148When called from inside a function with the @qcode{"local"} option, the
1149variable is changed locally for the function and any subroutines it calls.
1150The 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
1172DEFMETHOD (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 ("pattern", @dots{})
1178List currently defined variables matching the given patterns.
1179
1180Valid pattern syntax is the same as described for the @code{clear} command.
1181If no patterns are supplied, all variables are listed.
1182
1183By default, only variables visible in the local scope are displayed.
1184
1185The following are valid options, but may not be combined.
1186
1187@table @code
1188@item global
1189List variables in the global scope rather than the current scope.
1190
1191@item -regexp
1192The patterns are considered to be regular expressions when matching the
1193variables to display. The same pattern syntax accepted by the @code{regexp}
1194function is used.
1195
1196@item -file
1197The next argument is treated as a filename. All variables found within the
1198specified file are listed. No patterns are accepted when reading variables
1199from a file.
1200@end table
1201
1202If called as a function, return a cell array of defined variable names
1203matching 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
1235DEFMETHOD (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{})
1241Provide detailed information on currently defined variables matching the
1242given patterns.
1243
1244Options and pattern syntax are the same as for the @code{who} command.
1245
1246Extended information about each variable is summarized in a table with the
1247following default entries.
1248
1249@table @asis
1250@item Attr
1251Attributes of the listed variable. Possible attributes are:
1252
1253@table @asis
1254@item blank
1255Variable in local scope
1256
1257@item @code{c}
1258Variable of complex type.
1259
1260@item @code{f}
1261Formal parameter (function argument).
1262
1263@item @code{g}
1264Variable with global scope.
1265
1266@item @code{p}
1267Persistent variable.
1268@end table
1269
1270@item Name
1271The name of the variable.
1272
1273@item Size
1274The 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
1278The amount of memory currently used to store the variable.
1279
1280@item Class
1281The class of the variable. Examples include double, single, char, uint16,
1282cell, and struct.
1283@end table
1284
1285The table can be customized to display more or less information through
1286the function @code{whos_line_format}.
1287
1288If @code{whos} is called as a function, return a struct array of defined
1289variable names matching the given patterns. Fields in the structure
1290describing each variable are: name, size, bytes, class, global, sparse,
1291complex, 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
1304OCTAVE_NAMESPACE_END
static const octave_fields bt_fields(bt_fieldnames)
static OCTAVE_NAMESPACE_BEGIN 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 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:509
std::string name(void) const
Definition: ov-fcn.h:207
const Cell & contents(const_iterator p) const
Definition: oct-map.h:331
bool is_defined(void) const
Definition: ov.h:637
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
octave_value do_who(int argc, const string_vector &argv, bool return_list, bool verbose=false)
Definition: pt-eval.cc:4559
octave_value max_stack_depth(const octave_value_list &args, int nargout)
Definition: pt-eval.cc:2704
octave_value whos_line_format(const octave_value_list &args, int nargout)
Definition: pt-eval.cc:4504
#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:1055
void error(const char *fmt,...)
Definition: error.cc:980
QString name
F77_RET_T const F77_DBLE const F77_DBLE * f
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:10300
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:587