changelog shortlog tags changeset files revisions annotate raw

src/debug.cc

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