GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
call-stack.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1995-2025 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.
54static const char *bt_fieldnames[] =
55{ "file", "name", "line", "column", nullptr };
56
57static 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
67call_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
92int
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
106int
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
140int
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
165int
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
237int
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
267int
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
298std::string
300{
301 return m_cs[m_curr_frame]->get_dispatch_class ();
302}
303
304void
305call_stack::set_dispatch_class (const std::string& class_name)
306{
307 m_cs[m_curr_frame]->set_dispatch_class (class_name);
308}
309
310bool
311call_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
325bool
326call_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
340bool
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
363void 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
393void
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
411void
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
431void
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
452void
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
470void
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
488bool
489call_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
510std::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
528std::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
540std::size_t
541call_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
631std::size_t
632call_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
644void
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
657void
659{
660 if (m_curr_frame > 0)
661 m_curr_frame = 0;
662}
663
664std::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
698std::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
706std::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
729std::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
786void
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
809std::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
830void
832{
833 while (! m_cs.empty ())
834 pop ();
835}
836
839{
840 return m_cs[m_curr_frame]->all_variables ();
841}
842
843std::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
859std::list<std::string>
861{
862 return m_cs[0]->variable_names ();
863}
864
865std::list<std::string>
867{
868 return m_cs[m_curr_frame]->variable_names ();
869}
870
871void
872call_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
880void
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
892void
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
904void
906{
907 for (auto& nm_ov : m_global_values)
908 nm_ov.second = octave_value ();
909}
910
912call_stack::glob_symbol_info (const std::string& pattern) const
913{
914 return m_cs[m_curr_frame]->glob_symbol_info (pattern);
915}
916
918call_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
943void
945{
946 m_cs[m_curr_frame]->make_persistent (sym);
947}
948
949void
951{
952 m_cs[m_curr_frame]->make_global (sym);
953}
954
956call_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
964call_stack::global_varref (const std::string& name)
965{
966 return m_global_values[name];
967}
968
970call_stack::get_top_level_value (const std::string& name) const
971{
972 return m_cs[0]->varval (name);
973}
974
975void
976call_stack::set_top_level_value (const std::string& name,
977 const octave_value& value)
978{
979 m_cs[0]->assign (name, value);
980}
981
983call_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 ([this] () { 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.push_back (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
1190void
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
1205void
1207 const octave_value& val)
1208{
1209 m_cs[m_curr_frame]->set_auto_fcn_var (avt, val);
1210}
1211
1212void
1214{
1215 m_cs[m_curr_frame]->set_nargin (nargin);
1216}
1217
1218void
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
1230DEFMETHOD (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")
1235Query or set the internal limit on the number of times a function may
1236be called recursively.
1237
1238If the limit is exceeded, an error message is printed and control returns to
1239the top level.
1240
1241When called from inside a function with the @qcode{"local"} option, the
1242variable is changed locally for the function and any subroutines it calls.
1243The 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
1265DEFMETHOD (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{})
1271List currently defined variables matching the given patterns.
1272
1273Valid pattern syntax is the same as described for the @code{clear} command.
1274If no patterns are supplied, all variables are listed.
1275
1276By default, only variables visible in the local scope are displayed.
1277
1278The following are valid options, but may not be combined.
1279
1280@table @code
1281@item global
1282List variables in the global scope rather than the current scope.
1283
1284@item -regexp
1285The patterns are considered to be regular expressions when matching the
1286variables to display. The same pattern syntax accepted by the @code{regexp}
1287function is used.
1288
1289@item -file
1290The next argument is treated as a filename. All variables found within the
1291specified file are listed. No patterns are accepted when reading variables
1292from a file.
1293@end table
1294
1295If called as a function, return a cell array of defined variable names
1296matching 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
1328DEFMETHOD (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{})
1334Provide detailed information on currently defined variables matching the
1335given patterns.
1336
1337Options and pattern syntax are the same as for the @code{who} command.
1338
1339Extended information about each variable is summarized in a table with the
1340following default entries.
1341
1342@table @asis
1343@item Attr
1344Attributes of the listed variable. Possible attributes are:
1345
1346@table @asis
1347@item blank
1348Variable in local scope
1349
1350@item @code{c}
1351Variable of complex type.
1352
1353@item @code{f}
1354Formal parameter (function argument).
1355
1356@item @code{g}
1357Variable with global scope.
1358
1359@item @code{p}
1360Persistent variable.
1361@end table
1362
1363@item Name
1364The name of the variable.
1365
1366@item Size
1367The 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
1371The amount of memory currently used to store the variable.
1372
1373@item Class
1374The class of the variable. Examples include double, single, char, uint16,
1375cell, and struct.
1376@end table
1377
1378The table can be customized to display more or less information through
1379the function @code{whos_line_format}.
1380
1381If @code{whos} is called as a function, return a struct array of defined
1382variable names matching the given patterns. Fields in the structure
1383describing each variable are: name, size, bytes, class, global, sparse,
1384complex, 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
1397OCTAVE_END_NAMESPACE(octave)
Definition Cell.h:41
Cell column(octave_idx_type i) const
Definition Cell.cc:303
void set_dispatch_class(const std::string &class_name)
octave_value do_who(int argc, const string_vector &argv, bool return_list, bool verbose=false)
octave_value get_top_level_value(const std::string &name) const
octave_value global_varval(const std::string &name) const
std::size_t find_current_user_frame() const
std::list< std::shared_ptr< stack_frame > > backtrace_frames() const
octave_value & global_varref(const std::string &name)
octave_value do_who_two(const string_vector &patterns, bool have_regexp, bool return_list, bool verbose, const std::string &msg="")
void set_top_level_value(const std::string &name, const octave_value &value)
int current_user_code_column() const
int current_line() const
Definition call-stack.cc:93
void display() const
octave_value get_auto_fcn_var(stack_frame::auto_var_type avt) const
std::list< std::string > variable_names() const
symbol_info_list regexp_symbol_info(const std::string &pattern) const
void make_global(const symbol_record &sym)
std::shared_ptr< stack_frame > current_user_frame() const
std::size_t size() const
Definition call-stack.h:87
std::shared_ptr< stack_frame > pop_return()
void clear_global_variables()
symbol_info_list glob_symbol_info(const std::string &pattern) const
bool is_class_method_executing(std::string &dispatch_class) const
bool goto_frame(std::size_t n=0, bool verbose=false)
int debug_user_code_column() const
void set_auto_fcn_var(stack_frame::auto_var_type avt, const octave_value &val)
symbol_info_list get_symbol_info()
octave_function * caller_function() const
Definition call-stack.h:74
symbol_info_list top_scope_symbol_info() const
std::list< std::string > global_variable_names() const
bool is_class_constructor_executing(std::string &dispatch_class) const
void goto_caller_frame()
octave_map empty_backtrace() const
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="")
void clear_global_variable_pattern(const std::string &pattern)
unwind_protect * curr_fcn_unwind_protect_frame()
octave_map backtrace() const
int debug_user_code_line() const
octave_user_code * debug_user_code() const
call_stack(tree_evaluator &evaluator)
Definition call-stack.cc:59
symbol_info_list all_variables()
void push(const symbol_scope &scope)
std::list< std::string > top_level_variable_names() const
bool all_scripts() const
void set_nargin(int nargin)
void clear_global_variable(const std::string &name)
octave_user_code * current_user_code() const
void goto_base_frame()
std::list< frame_info > backtrace_info() const
void set_nargout(int nargout)
int current_user_code_line() const
std::size_t dbupdown(std::size_t start, int n, bool verbose)
int current_column() const
std::string get_dispatch_class() const
void clear()
void clear_global_variable_regexp(const std::string &pattern)
void make_persistent(const symbol_record &sym)
octave_value max_stack_depth(const octave_value_list &args, int nargout)
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
virtual bool is_user_code() const
Definition ov-base.h:549
std::string name() const
Definition ov-fcn.h:208
const Cell & contents(const_iterator p) const
Definition oct-map.h:310
bool is_defined() const
Definition ov.h:592
octave_idx_type length() const
bool is_match(const std::string &buffer) const
Definition lo-regexp.cc:582
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
void resize(octave_idx_type n, const std::string &rfv="")
Definition str-vec.h:93
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:98
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:422
octave_value do_who(int argc, const string_vector &argv, bool return_list, bool verbose=false)
Definition pt-eval.cc:4857
octave_value max_stack_depth(const octave_value_list &args, int nargout)
Definition pt-eval.cc:2817
octave_value whos_line_format(const octave_value_list &args, int nargout)
Definition pt-eval.cc:4801
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:1078
void error(const char *fmt,...)
Definition error.cc:1003
F77_RET_T const F77_DBLE const F77_DBLE * f
octave_value_list Fload(octave::interpreter &interp, const octave_value_list &args, int nargout)
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition ovl.h:217
#define octave_stdout
Definition pager.h:301
octave_value set_internal_variable(bool &var, const octave_value_list &args, int nargout, const char *nm)
Definition variables.cc:583