changelog shortlog tags changeset files revisions annotate raw

src/debug.cc

changeset 10289: 4b124317dc38
parent:d4f813c3f5ed
author: John W. Eaton <jwe@octave.org>
date: Tue Feb 09 20:58:55 2010 -0500 (37 minutes ago)
permissions: -rw-r--r--
description: base_properties::set_children: account for hidden children
1/*
2
3Copyright (C) 2007, 2008, 2009 John Swensen
4Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Ben Sapp
5
6This file is part of Octave.
7
8Octave is free software; you can redistribute it and/or modify it
9under the terms of the GNU General Public License as published by the
10Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13Octave is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along with Octave; see the file COPYING. If not, see
20<http://www.gnu.org/licenses/>.
21
22*/
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include <deque>
28#include <fstream>
29#include <iostream>
30#include <set>
31#include <string>
32
33#include "file-stat.h"
34
35#include "defun.h"
36#include "error.h"
37#include "help.h"
38#include "input.h"
39#include "pager.h"
40#include "oct-obj.h"
41#include "utils.h"
42#include "parse.h"
43#include "symtab.h"
44#include "gripes.h"
45#include "ov.h"
46#include "ov-usr-fcn.h"
47#include "ov-fcn.h"
48#include "ov-struct.h"
49#include "pt-pr-code.h"
50#include "pt-bp.h"
51#include "pt-eval.h"
52#include "pt-stmt.h"
53#include "toplev.h"
54#include "unwind-prot.h"
55#include "variables.h"
56
57#include "debug.h"
58
59// Initialize the singleton object
60bp_table *bp_table::instance = 0;
61
62static std::string
63snarf_file (const std::string& fname)
64{
65 std::string retval;
66
67 file_stat fs (fname);
68
69 if (fs)
70 {
71 size_t sz = fs.size ();
72
73 std::ifstream file (fname.c_str (), std::ios::in|std::ios::binary);
74
75 if (file)
76 {
77 std::string buf (sz+1, 0);
78
79 file.read (&buf[0], sz+1);
80
81 if (file.eof ())
82 {
83 // Expected to read the entire file.
84
85 retval = buf;
86 }
87 else
88 error ("error reading file %s", fname.c_str ());
89 }
90 }
91
92 return retval;
93}
94
95static std::deque<size_t>
96get_line_offsets (const std::string& buf)
97{
98 // This could maybe be smarter. Is deque the right thing to use
99 // here?
100
101 std::deque<size_t> offsets;
102
103 offsets.push_back (0);
104
105 size_t len = buf.length ();
106
107 for (size_t i = 0; i < len; i++)
108 {
109 char c = buf[i];
110
111 if (c == '\r' && ++i < len)
112 {
113 c = buf[i];
114
115 if (c == '\n')
116 offsets.push_back (i+1);
117 else
118 offsets.push_back (i);
119 }
120 else if (c == '\n')
121 offsets.push_back (i+1);
122 }
123
124 offsets.push_back (len);
125
126 return offsets;
127}
128
129std::string
130get_file_line (const std::string& fname, size_t line)
131{
132 std::string retval;
133
134 static std::string last_fname;
135
136 static std::string buf;
137
138 static std::deque<size_t> offsets;
139
140 if (fname != last_fname)
141 {
142 buf = snarf_file (fname);
143
144 offsets = get_line_offsets (buf);
145 }
146
147 if (line > 0)
148 line--;
149
150 if (line < offsets.size () - 1)
151 {
152 size_t bol = offsets[line];
153 size_t eol = offsets[line+1];
154
155 while (eol > 0 && (buf[eol-1] == '\n' || buf[eol-1] == '\r'))
156 eol--;
157
158 retval = buf.substr (bol, eol - bol);
159 }
160
161 return retval;
162}
163
164// Return a pointer to the user-defined function FNAME. If FNAME is
165// empty, search backward for the first user-defined function in the
166// current call stack.
167
168static octave_user_code *
169get_user_code (const std::string& fname = std::string ())
170{
171 octave_user_code *dbg_fcn = 0;
172
173 if (fname.empty ())
174 dbg_fcn = octave_call_stack::caller_user_code ();
175 else
176 {
177 octave_value fcn = symbol_table::find_function (fname);
178
179 if (fcn.is_defined () && fcn.is_user_code ())
180 dbg_fcn = fcn.user_code_value ();
181 }
182
183 return dbg_fcn;
184}
185
186static void
187parse_dbfunction_params (const char *who, const octave_value_list& args,
188 std::string& symbol_name, bp_table::intmap& lines)
189{
190 int nargin = args.length ();
191 int idx = 0;
192 int list_idx = 0;
193 symbol_name = std::string ();
194 lines = bp_table::intmap ();
195
196 if (args.length () == 0)
197 return;
198
199 // If we are already in a debugging function.
200 if (octave_call_stack::caller_user_code ())
201 {
202 idx = 0;
203 symbol_name = get_user_code ()->name ();
204 }
205 else if (args(0).is_map ())
206 {
207 // Problem because parse_dbfunction_params() can only pass out a
208 // single function
209 }
210 else if (args(0).is_string())
211 {
212 symbol_name = args(0).string_value ();
213 if (error_state)
214 return;
215 idx = 1;
216 }
217 else
218 error ("%s: invalid parameter specified", who);
219
220 for (int i = idx; i < nargin; i++ )
221 {
222 if (args(i).is_string ())
223 {
224 int line = atoi (args(i).string_value().c_str ());
225 if (error_state)
226 break;
227 lines[list_idx++] = line;
228 }
229 else if (args(i).is_map ())
230 octave_stdout << who << ": accepting a struct" << std::endl;
231 else
232 {
233 const NDArray arg = args(i).array_value ();
234
235 if (error_state)
236 break;
237
238 for (octave_idx_type j = 0; j < arg.nelem (); j++)
239 {
240 int line = static_cast<int> (arg.elem (j));
241 if (error_state)
242 break;
243 lines[list_idx++] = line;
244 }
245
246 if (error_state)
247 break;
248 }
249 }
250}
251
252bp_table::intmap
253bp_table::do_add_breakpoint (const std::string& fname,
254 const bp_table::intmap& line)
255{
256 intmap retval;
257
258 octave_idx_type len = line.size ();
259
260 octave_user_code *dbg_fcn = get_user_code (fname);
261
262 if (dbg_fcn)
263 {
264 tree_statement_list *cmds = dbg_fcn->body ();
265
266 if (cmds)
267 {
268 for (int i = 0; i < len; i++)
269 {
270 const_intmap_iterator p = line.find (i);
271
272 if (p != line.end ())
273 {
274 int lineno = p->second;
275
276 retval[i] = cmds->set_breakpoint (lineno);
277
278 if (retval[i] != 0)
279 {
280 bp_set.insert (fname);
281 }
282 }
283 }
284 }
285 }
286 else
287 error ("add_breakpoint: unable to find the function requested\n");
288
289 tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging;
290
291 return retval;
292}
293
294
295int
296bp_table::do_remove_breakpoint (const std::string& fname,
297 const bp_table::intmap& line)
298{
299 int retval = 0;
300
301 octave_idx_type len = line.size ();
302
303 if (len == 0)
304 {
305 intmap results = remove_all_breakpoints_in_file (fname);
306 retval = results.size ();
307 }
308 else
309 {
310 octave_user_code *dbg_fcn = get_user_code (fname);
311
312 if (dbg_fcn)
313 {
314 tree_statement_list *cmds = dbg_fcn->body ();
315
316 if (cmds)
317 {
318 octave_value_list results = cmds->list_breakpoints ();
319
320 if (results.length () > 0)
321 {
322 for (int i = 0; i < len; i++)
323 {
324 const_intmap_iterator p = line.find (i);
325
326 if (p != line.end ())
327 cmds->delete_breakpoint (p->second);
328 }
329
330 results = cmds->list_breakpoints ();
331
332 bp_set_iterator it = bp_set.find (fname);
333 if (results.length () == 0 && it != bp_set.end ())
334 bp_set.erase (it);
335
336 }
337
338 retval = results.length ();
339 }
340 }
341 else
342 error ("remove_breakpoint: unable to find the function requested\n");
343 }
344
345 tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging;
346
347 return retval;
348}
349
350
351bp_table::intmap
352bp_table::do_remove_all_breakpoints_in_file (const std::string& fname,
353 bool silent)
354{
355 intmap retval;
356
357 octave_user_code *dbg_fcn = get_user_code (fname);
358
359 if (dbg_fcn)
360 {
361 tree_statement_list *cmds = dbg_fcn->body ();
362
363 if (cmds)
364 {
365 octave_value_list bkpts = cmds->list_breakpoints ();
366
367 for (int i = 0; i < bkpts.length (); i++)
368 {
369 int lineno = static_cast<int> (bkpts(i).int_value ());
370 cmds->delete_breakpoint (lineno);
371 retval[i] = lineno;
372 }
373
374 bp_set_iterator it = bp_set.find (fname);
375 if (it != bp_set.end ())
376 bp_set.erase (it);
377
378 }
379 }
380 else if (! silent)
381 error ("remove_all_breakpoint_in_file: "
382 "unable to find the function requested\n");
383
384 tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging;
385
386 return retval;
387}
388
389void
390bp_table::do_remove_all_breakpoints (void)
391{
392 for (const_bp_set_iterator it = bp_set.begin (); it != bp_set.end (); it++)
393 remove_all_breakpoints_in_file (*it);
394
395
396 tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging;
397}
398
399std::string
400do_find_bkpt_list (octave_value_list slist,
401 std::string match)
402{
403 std::string retval;
404
405 for (int i = 0; i < slist.length (); i++)
406 {
407 if (slist (i).string_value () == match)
408 {
409 retval = slist(i).string_value ();
410 break;
411 }
412 }
413
414 return retval;
415}
416
417
418bp_table::fname_line_map
419bp_table::do_get_breakpoint_list (const octave_value_list& fname_list)
420{
421 fname_line_map retval;
422
423 for (bp_set_iterator it = bp_set.begin (); it != bp_set.end (); it++)
424 {
425 if (fname_list.length () == 0
426 || do_find_bkpt_list (fname_list, *it) != "")
427 {
428 octave_user_code *f = get_user_code (*it);
429
430 if (f)
431 {
432 tree_statement_list *cmds = f->body ();
433
434 if (cmds)
435 {
436 octave_value_list bkpts = cmds->list_breakpoints ();
437 octave_idx_type len = bkpts.length ();
438
439 if (len > 0)
440 {
441 bp_table::intmap bkpts_vec;
442
443 for (int i = 0; i < len; i++)
444 bkpts_vec[i] = bkpts (i).double_value ();
445
446 std::string symbol_name = f->name ();
447
448 retval[symbol_name] = bkpts_vec;
449 }
450 }
451 }
452 }
453 }
454
455 return retval;
456}
457
458static octave_value
459intmap_to_ov (const bp_table::intmap& line)
460{
461 int idx = 0;
462
463 NDArray retval (dim_vector (1, line.size ()));
464
465 for (size_t i = 0; i < line.size (); i++)
466 {
467 bp_table::const_intmap_iterator p = line.find (i);
468
469 if (p != line.end ())
470 {
471 int lineno = p->second;
472 retval(idx++) = lineno;
473 }
474 }
475
476 retval.resize (dim_vector (1, idx));
477
478 return retval;
479}
480
481DEFUN (dbstop, args, ,
482 "-*- texinfo -*-\n\
483@deftypefn {Loadable Function} {@var{rline} =} dbstop (@var{func}, @var{line}, @dots{})\n\
484Set a breakpoint in a function\n\
485@table @code\n\
486@item func\n\
487String representing the function name. When already in debug\n\
488mode this should be left out and only the line should be given.\n\
489@item line\n\
490Line number you would like the breakpoint to be set on. Multiple\n\
491lines might be given as separate arguments or as a vector.\n\
492@end table\n\
493\n\
494The rline returned is the real line that the breakpoint was set at.\n\
495@seealso{dbclear, dbstatus, dbstep}\n\
496@end deftypefn")
497{
498 bp_table::intmap retval;
499 std::string symbol_name;
500 bp_table::intmap lines;
501
502 parse_dbfunction_params ("dbstop", args, symbol_name, lines);
503
504 if (lines.size () == 0)
505 lines[0] = 1;
506
507 if (! error_state)
508 retval = bp_table::add_breakpoint (symbol_name, lines);
509
510 return intmap_to_ov (retval);
511}
512
513DEFUN (dbclear, args, ,
514 "-*- texinfo -*-\n\
515@deftypefn {Loadable Function} {} dbclear (@var{func}, @var{line}, @dots{})\n\
516Delete a breakpoint in a function\n\
517@table @code\n\
518@item func\n\
519String representing the function name. When already in debug\n\
520mode this should be left out and only the line should be given.\n\
521@item line\n\
522Line number where you would like to remove the breakpoint. Multiple\n\
523lines might be given as separate arguments or as a vector.\n\
524@end table\n\
525No checking is done to make sure that the line you requested is really\n\
526a breakpoint. If you get the wrong line nothing will happen.\n\
527@seealso{dbstop, dbstatus, dbwhere}\n\
528@end deftypefn")
529{
530 octave_value retval;
531 std::string symbol_name = "";
532 bp_table::intmap lines;
533
534 parse_dbfunction_params ("dbclear", args, symbol_name, lines);
535
536 if (! error_state)
537 bp_table::remove_breakpoint (symbol_name, lines);
538
539 return retval;
540}
541
542DEFUN (dbstatus, args, nargout,
543 "-*- texinfo -*-\n\
544@deftypefn {Loadable Function} {lst =} dbstatus (@var{func})\n\
545Return a vector containing the lines on which a function has \n\
546breakpoints set.\n\
547@table @code\n\
548@item func\n\
549String representing the function name. When already in debug\n\
550mode this should be left out.\n\
551@end table\n\
552@seealso{dbclear, dbwhere}\n\
553@end deftypefn")
554{
555 Octave_map retval;
556 int nargin = args.length ();
557 octave_value_list fcn_list;
558 bp_table::fname_line_map bp_list;
559 std::string symbol_name;
560
561 if (nargin != 0 && nargin != 1)
562 {
563 error ("dbstatus: only zero or one arguements accepted\n");
564 return octave_value ();
565 }
566
567 if (nargin == 1)
568 {
569 if (args(0).is_string ())
570 {
571 symbol_name = args(0).string_value ();
572 fcn_list(0) = symbol_name;
573 bp_list = bp_table::get_breakpoint_list (fcn_list);
574 }
575 else
576 gripe_wrong_type_arg ("dbstatus", args(0));
577 }
578 else
579 {
580 octave_user_code *dbg_fcn = get_user_code ();
581 if (dbg_fcn)
582 {
583 symbol_name = dbg_fcn->name ();
584 fcn_list(0) = symbol_name;
585 }
586
587 bp_list = bp_table::get_breakpoint_list (fcn_list);
588 }
589
590 if (nargout == 0)
591 {
592 // Print out the breakpoint information.
593
594 for (bp_table::fname_line_map_iterator it = bp_list.begin ();
595 it != bp_list.end (); it++)
596 {
597 octave_stdout << "Breakpoint in " << it->first << " at line(s) ";
598
599 bp_table::intmap m = it->second;
600
601 size_t nel = m.size ();
602
603 for (size_t j = 0; j < nel; j++)
604 octave_stdout << m[j] << ((j < nel - 1) ? ", " : ".");
605
606 if (nel > 0)
607 octave_stdout << std::endl;
608 }
609 return octave_value ();
610 }
611 else
612 {
613 // Fill in an array for return.
614
615 int i = 0;
616 Cell names (dim_vector (bp_list.size (), 1));
617 Cell file (dim_vector (bp_list.size (), 1));
618 Cell line (dim_vector (bp_list.size (), 1));
619
620 for (bp_table::const_fname_line_map_iterator it = bp_list.begin ();
621 it != bp_list.end (); it++)
622 {
623 names(i) = it->first;
624 line(i) = intmap_to_ov (it->second);
625 file(i) = do_which (it->first);
626 i++;
627 }
628
629 retval.assign ("name", names);
630 retval.assign ("file", file);
631 retval.assign ("line", line);
632
633 return octave_value (retval);
634 }
635}
636
637DEFUN (dbwhere, , ,
638 "-*- texinfo -*-\n\
639@deftypefn {Loadable Function} {} dbwhere ()\n\
640Show where we are in the code\n\
641@seealso{dbclear, dbstatus, dbstop}\n\
642@end deftypefn")
643{
644 octave_value retval;
645
646 octave_user_code *dbg_fcn = get_user_code ();
647
648 if (dbg_fcn)
649 {
650 bool have_file = true;
651
652 std::string name = dbg_fcn->fcn_file_name ();
653
654 if (name.empty ())
655 {
656 have_file = false;
657
658 name = dbg_fcn->name ();
659 }
660
661 octave_stdout << name << ":";
662
663 unwind_protect frame;
664
665 frame.add_fcn (octave_call_stack::restore_frame,
666 octave_call_stack::current_frame ());
667
668 // Skip the frame assigned to the dbwhere function.
669 octave_call_stack::goto_frame_relative (0);
670
671 int l = octave_call_stack::current_line ();
672
673 if (l > 0)
674 {
675 octave_stdout << " line " << l;
676
677 int c = octave_call_stack::current_column ();
678
679 if (c > 0)
680 octave_stdout << ", column " << c;
681
682 octave_stdout << std::endl;
683
684 if (have_file)
685 {
686 std::string line = get_file_line (name, l);
687
688 if (! line.empty ())
689 octave_stdout << l << ": " << line << std::endl;
690 }
691 }
692 else
693 octave_stdout << " (unknown line)\n";
694 }
695 else
696 error ("dbwhere: must be inside of a user function to use dbwhere\n");
697
698 return retval;
699}
700
701// Copied and modified from the do_type command in help.cc
702// Maybe we could share some code?
703void
704do_dbtype (std::ostream& os, const std::string& name, int start, int end)
705{
706 std::string ff = fcn_file_in_path (name);
707
708 if (! ff.empty ())
709 {
710 std::ifstream fs (ff.c_str (), std::ios::in);
711
712 if (fs)
713 {
714 char ch;
715 int line = 1;
716
717 if (line >= start && line <= end)
718 os << line << "\t";
719
720 while (fs.get (ch))
721 {
722 if (line >= start && line <= end)
723 {
724 os << ch;
725 }
726
727 if (ch == '\n')
728 {
729 line++;
730 if (line >= start && line <= end)
731 os << line << "\t";
732 }
733 }
734 }
735 else
736 os << "dbtype: unable to open `" << ff << "' for reading!\n";
737 }
738 else
739 os << "dbtype: unknown function " << name << "\n";
740
741 os.flush ();
742}
743
744DEFUN (dbtype, args, ,
745 "-*- texinfo -*-\n\
746@deftypefn {Loadable Function} {} dbtype ()\n\
747List script file with line numbers.\n\
748@seealso{dbclear, dbstatus, dbstop}\n\
749@end deftypefn")
750{
751 octave_value retval;
752 octave_user_code *dbg_fcn;
753
754 int nargin = args.length ();
755 string_vector argv = args.make_argv ("dbtype");
756
757 if (! error_state)
758 {
759 switch (nargin)
760 {
761 case 0: // dbtype
762 dbg_fcn = get_user_code ();
763
764 if (dbg_fcn)
765 do_dbtype (octave_stdout, dbg_fcn->name (), 0, INT_MAX);
766 else
767 error ("dbtype: must be in a user function to give no arguments to dbtype\n");
768 break;
769
770 case 1: // (dbtype func) || (dbtype start:end)
771 dbg_fcn = get_user_code (argv[1]);
772
773 if (dbg_fcn)
774 do_dbtype (octave_stdout, dbg_fcn->name (), 0, INT_MAX);
775 else
776 {
777 dbg_fcn = get_user_code ();
778
779 if (dbg_fcn)
780 {
781 std::string arg = argv[1];
782
783 size_t ind = arg.find (':');
784
785 if (ind != std::string::npos)
786 {
787 std::string start_str = arg.substr (0, ind);
788 std::string end_str = arg.substr (ind + 1);
789
790 int start = atoi (start_str.c_str ());
791 int end = atoi (end_str.c_str ());
792
793 if (std::min (start, end) <= 0)
794 error ("dbtype: start and end lines must be >= 1\n");
795
796 if (start <= end)
797 do_dbtype (octave_stdout, dbg_fcn->name (), start, end);
798 else
799 error ("dbtype: start line must be less than end line\n");
800 }
801 else
802 error ("dbtype: line specification must be `start:end'");
803 }
804 }
805 break;
806
807 case 2: // (dbtype func start:end) , (dbtype func start)
808 dbg_fcn = get_user_code (argv[1]);
809
810 if (dbg_fcn)
811 {
812 std::string arg = argv[2];
813 int start = 0;
814 int end = 0;
815 size_t ind = arg.find (':');
816
817 if (ind != std::string::npos)
818 {
819 std::string start_str = arg.substr (0, ind);
820 std::string end_str = arg.substr (ind + 1);
821
822 start = atoi (start_str.c_str ());
823 end = atoi (end_str.c_str ());
824
825 }
826 else
827 {
828 start = atoi (arg.c_str ());
829 end = start;
830 }
831
832 if (std::min (start, end) <= 0)
833 error ("dbtype: start and end lines must be >= 1\n");
834
835 if (start <= end)
836 do_dbtype (octave_stdout, dbg_fcn->name (), start, end);
837 else
838 error ("dbtype: start line must be less than end line\n");
839 }
840 break;
841
842 default:
843 error ("dbtype: expecting zero, one, or two arguments\n");
844 }
845 }
846
847 return retval;
848}
849
850DEFUN (dbstack, args, nargout,
851 "-*- texinfo -*-\n\
852@deftypefn {Loadable Function} {[@var{stack}, @var{idx}]} dbstack (@var{n})\n\
853Print or return current stack information. With optional argument\n\
854@var{n}, omit the @var{n} innermost stack frames.\n\
855@seealso{dbclear, dbstatus, dbstop}\n\
856@end deftypefn")
857{
858 octave_value_list retval;
859
860 unwind_protect frame;
861
862 octave_idx_type curr_frame = -1;
863
864 size_t nskip = 0;
865
866 if (args.length () == 1)
867 {
868 int n = 0;
869
870 octave_value arg = args(0);
871
872 if (arg.is_string ())
873 {
874 std::string s_arg = arg.string_value ();
875
876 n = atoi (s_arg.c_str ());
877 }
878 else
879 n = args(0).int_value ();
880
881 if (n > 0)
882 nskip = n;
883 else
884 error ("dbstack: expecting N to be a nonnegative integer");
885 }
886
887 if (! error_state)
888 {
889 Octave_map stk = octave_call_stack::backtrace (nskip, curr_frame);
890
891 if (nargout == 0)
892 {
893 octave_idx_type nframes_to_display = stk.numel ();
894
895 if (nframes_to_display > 0)
896 {
897 octave_stdout << "Stopped in:\n\n";
898
899 Cell names = stk.contents ("name");
900 Cell lines = stk.contents ("line");
901 Cell columns = stk.contents ("column");
902
903 for (octave_idx_type i = 0; i < nframes_to_display; i++)
904 {
905 octave_value name = names(i);
906 octave_value line = lines(i);
907 octave_value column = columns(i);
908
909 octave_stdout << (i == curr_frame ? "--> " : " ")
910 << name.string_value ()
911 << " at line " << line.int_value ()
912 << " column " << column.int_value ()
913 << std::endl;
914 }
915 }
916 }
917 else
918 {
919 retval(1) = curr_frame < 0 ? 1 : curr_frame + 1;
920 retval(0) = stk;
921 }
922 }
923
924 return retval;
925}
926
927static void
928do_dbupdown (const octave_value_list& args, const std::string& who)
929{
930 int n = 1;
931
932 if (args.length () == 1)
933 {
934 octave_value arg = args(0);
935
936 if (arg.is_string ())
937 {
938 std::string s_arg = arg.string_value ();
939
940 n = atoi (s_arg.c_str ());
941 }
942 else
943 n = args(0).int_value ();
944 }
945
946 if (! error_state)
947 {
948 if (who == "dbup")
949 n = -n;
950
951 if (! octave_call_stack::goto_frame_relative (n, true))
952 error ("%s: invalid stack frame", who.c_str ());
953 }
954}
955
956DEFUN (dbup, args, ,
957 "-*- texinfo -*-\n\
958@deftypefn {Loadable Function} {} dbup\n\
959@deftypefnx {Loadable Function} {} dbup (@var{n})\n\
960In debugging mode, move up the execution stack @var{n} frames.\n\
961If @var{n} is omitted, move up one frame.\n\
962@seealso{dbstack}\n\
963@end deftypefn")
964{
965 octave_value retval;
966
967 do_dbupdown (args, "dbup");
968
969 return retval;
970}
971
972DEFUN (dbdown, args, ,
973 "-*- texinfo -*-\n\
974@deftypefn {Loadable Function} {} dbdown\n\
975@deftypefnx {Loadable Function} {} dbdown (@var{n})\n\
976In debugging mode, move down the execution stack @var{n} frames.\n\
977If @var{n} is omitted, move down one frame.\n\
978@seealso{dbstack}\n\
979@end deftypefn")
980{
981 octave_value retval;
982
983 do_dbupdown (args, "dbdown");
984
985 return retval;
986}
987
988DEFUN (dbstep, args, ,
989 "-*- texinfo -*-\n\
990@deftypefn {Command} {} dbstep\n\
991@deftypefnx {Command} {} dbstep @var{n}\n\
992@deftypefnx {Command} {} dbstep in\n\
993@deftypefnx {Command} {} dbstep out\n\
994In debugging mode, execute the next @var{n} lines of code.\n\
995If @var{n} is omitted , execute the next single line of code.\n\
996If the next line of code is itself\n\
997defined in terms of an m-file remain in the existing function.\n\
998\n\
999Using @code{dbstep in} will cause execution of the next line to step into\n\
1000any m-files defined on the next line. Using @code{dbstep out} will cause\n\
1001execution to continue until the current function returns.\n\
1002@seealso{dbcont, dbquit}\n\
1003@end deftypefn")
1004{
1005 if (Vdebugging)
1006 {
1007 int nargin = args.length ();
1008
1009 if (nargin > 1)
1010 print_usage ();
1011 else if (nargin == 1)
1012 {
1013 if (args(0).is_string ())
1014 {
1015 std::string arg = args(0).string_value ();
1016
1017 if (! error_state)
1018 {
1019 if (arg == "in")
1020 {
1021 Vdebugging = false;
1022
1023 tree_evaluator::dbstep_flag = -1;
1024 }
1025 else if (arg == "out")
1026 {
1027 Vdebugging = false;
1028
1029 tree_evaluator::dbstep_flag = -2;
1030 }
1031 else
1032 {
1033 int n = atoi (arg.c_str ());
1034
1035 if (n > 0)
1036 {
1037 Vdebugging = false;
1038
1039 tree_evaluator::dbstep_flag = n;
1040 }
1041 else
1042 error ("dbstep: invalid argument");
1043 }
1044 }
1045 }
1046 else
1047 error ("dbstep: expecting character string as argument");
1048 }
1049 else
1050 {
1051 Vdebugging = false;
1052
1053 tree_evaluator::dbstep_flag = 1;
1054 }
1055 }
1056 else
1057 error ("dbstep: can only be called in debug mode");
1058
1059 return octave_value_list ();
1060}
1061
1062DEFALIAS (dbnext, dbstep);
1063
1064DEFUN (dbcont, args, ,
1065 "-*- texinfo -*-\n\
1066@deftypefn {Command} {} dbcont\n\
1067In debugging mode, quit debugging mode and continue execution.\n\
1068@seealso{dbstep, dbquit}\n\
1069@end deftypefn")
1070{
1071 if (Vdebugging)
1072 {
1073 if (args.length () == 0)
1074 {
1075 Vdebugging = false;
1076
1077 tree_evaluator::reset_debug_state ();
1078 }
1079 else
1080 print_usage ();
1081 }
1082 else
1083 error ("dbcont: can only be called in debug mode");
1084
1085 return octave_value_list ();
1086}
1087
1088DEFUN (dbquit, args, ,
1089 "-*- texinfo -*-\n\
1090@deftypefn {Command} {} dbquit\n\
1091In debugging mode, quit debugging mode and return to the top level.\n\
1092@seealso{dbstep, dbcont}\n\
1093@end deftypefn")
1094{
1095 if (Vdebugging)
1096 {
1097 if (args.length () == 0)
1098 {
1099 Vdebugging = false;
1100
1101 tree_evaluator::reset_debug_state ();
1102
1103 octave_throw_interrupt_exception ();
1104 }
1105 else
1106 print_usage ();
1107 }
1108 else
1109 error ("dbquit: can only be called in debug mode");
1110
1111 return octave_value_list ();
1112}
1113
1114DEFUN (isdebugmode, args, ,
1115 "-*- texinfo -*-\n\
1116@deftypefn {Loadable Function} {} isdebugmode ()\n\
1117Return true if debug mode is on, otherwise false.\n\
1118@seealso{dbstack, dbclear, dbstop, dbstatus}\n\
1119@end deftypefn")
1120{
1121 octave_value retval;
1122
1123 if (args.length () == 0)
1124 retval = Vdebugging;
1125 else
1126 print_usage ();
1127
1128 return retval;
1129}