GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
debug.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2001-2013 Ben Sapp
4 Copyright (C) 2007-2009 John Swensen
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along 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 <iomanip>
30 #include <iostream>
31 #include <set>
32 #include <string>
33 
34 #include "file-stat.h"
35 #include "singleton-cleanup.h"
36 
37 #include "defun.h"
38 #include "error.h"
39 #include "help.h"
40 #include "input.h"
41 #include "pager.h"
42 #include "octave-link.h"
43 #include "oct-obj.h"
44 #include "utils.h"
45 #include "parse.h"
46 #include "symtab.h"
47 #include "gripes.h"
48 #include "ov.h"
49 #include "ov-usr-fcn.h"
50 #include "ov-fcn.h"
51 #include "ov-struct.h"
52 #include "pt-pr-code.h"
53 #include "pt-bp.h"
54 #include "pt-eval.h"
55 #include "pt-stmt.h"
56 #include "toplev.h"
57 #include "unwind-prot.h"
58 #include "utils.h"
59 #include "variables.h"
60 
61 #include "debug.h"
62 
63 // Initialize the singleton object
65 
66 static std::string
67 snarf_file (const std::string& fname)
68 {
69  std::string retval;
70 
71  file_stat fs (fname);
72 
73  if (fs)
74  {
75  size_t sz = fs.size ();
76 
77  std::ifstream file (fname.c_str (), std::ios::in|std::ios::binary);
78 
79  if (file)
80  {
81  std::string buf (sz+1, 0);
82 
83  file.read (&buf[0], sz+1);
84 
85  if (file.eof ())
86  {
87  // Expected to read the entire file.
88 
89  retval = buf;
90  }
91  else
92  error ("error reading file %s", fname.c_str ());
93  }
94  }
95 
96  return retval;
97 }
98 
99 static std::deque<size_t>
100 get_line_offsets (const std::string& buf)
101 {
102  // This could maybe be smarter. Is deque the right thing to use
103  // here?
104 
105  std::deque<size_t> offsets;
106 
107  offsets.push_back (0);
108 
109  size_t len = buf.length ();
110 
111  for (size_t i = 0; i < len; i++)
112  {
113  char c = buf[i];
114 
115  if (c == '\r' && ++i < len)
116  {
117  c = buf[i];
118 
119  if (c == '\n')
120  offsets.push_back (i+1);
121  else
122  offsets.push_back (i);
123  }
124  else if (c == '\n')
125  offsets.push_back (i+1);
126  }
127 
128  offsets.push_back (len);
129 
130  return offsets;
131 }
132 
133 std::string
134 get_file_line (const std::string& fname, size_t line)
135 {
136  std::string retval;
137 
138  static std::string last_fname;
139 
140  static std::string buf;
141 
142  static std::deque<size_t> offsets;
143 
144  if (fname != last_fname)
145  {
146  buf = snarf_file (fname);
147 
148  offsets = get_line_offsets (buf);
149  }
150 
151  if (line > 0)
152  line--;
153 
154  if (line < offsets.size () - 1)
155  {
156  size_t bol = offsets[line];
157  size_t eol = offsets[line+1];
158 
159  while (eol > 0 && eol > bol && (buf[eol-1] == '\n' || buf[eol-1] == '\r'))
160  eol--;
161 
162  retval = buf.substr (bol, eol - bol);
163  }
164 
165  return retval;
166 }
167 
168 // Return a pointer to the user-defined function FNAME. If FNAME is
169 // empty, search backward for the first user-defined function in the
170 // current call stack.
171 
172 static octave_user_code *
173 get_user_code (const std::string& fname = std::string ())
174 {
175  octave_user_code *dbg_fcn = 0;
176 
177  if (fname.empty ())
179  else
180  {
182 
183  if (fcn.is_defined () && fcn.is_user_code ())
184  dbg_fcn = fcn.user_code_value ();
185  }
186 
187  return dbg_fcn;
188 }
189 
190 static void
191 parse_dbfunction_params (const char *who, const octave_value_list& args,
192  std::string& symbol_name, bp_table::intmap& lines)
193 {
194  int nargin = args.length ();
195  int idx = 0;
196  int list_idx = 0;
197  symbol_name = std::string ();
198  lines = bp_table::intmap ();
199 
200  if (args.length () == 0)
201  return;
202 
203  // If we are already in a debugging function.
205  {
206  idx = 0;
207  symbol_name = get_user_code ()->name ();
208  }
209  else if (args(0).is_map ())
210  {
211  // Problem because parse_dbfunction_params() can only pass out a
212  // single function
213  }
214  else if (args(0).is_string ())
215  {
216  symbol_name = args(0).string_value ();
217  if (error_state)
218  return;
219  idx = 1;
220  }
221  else
222  error ("%s: invalid parameter specified", who);
223 
224  for (int i = idx; i < nargin; i++ )
225  {
226  if (args(i).is_string ())
227  {
228  int line = atoi (args(i).string_value ().c_str ());
229  if (error_state)
230  break;
231  lines[list_idx++] = line;
232  }
233  else if (args(i).is_map ())
234  octave_stdout << who << ": accepting a struct" << std::endl;
235  else
236  {
237  const NDArray arg = args(i).array_value ();
238 
239  if (error_state)
240  break;
241 
242  for (octave_idx_type j = 0; j < arg.nelem (); j++)
243  {
244  int line = static_cast<int> (arg.elem (j));
245  if (error_state)
246  break;
247  lines[list_idx++] = line;
248  }
249 
250  if (error_state)
251  break;
252  }
253  }
254 }
255 
256 bool
258 {
259  bool retval = true;
260 
261  if (! instance)
262  {
263  instance = new bp_table ();
264 
265  if (instance)
267  }
268 
269  if (! instance)
270  {
271  ::error ("unable to create breakpoint table!");
272  retval = false;
273  }
274 
275  return retval;
276 }
277 
278 bool
280  const std::string& fname,
281  const bp_table::intmap& line,
282  bp_table::intmap& retval)
283 {
284  bool found = false;
285 
286  tree_statement_list *cmds = fcn->body ();
287 
288  std::string file = fcn->fcn_file_name ();
289 
290  if (cmds)
291  {
292  retval = cmds->add_breakpoint (file, line);
293 
294  for (intmap_iterator p = retval.begin (); p != retval.end (); p++)
295  {
296  if (p->second != 0)
297  {
298  bp_set.insert (fname);
299  found = true;
300  break;
301  }
302  }
303  }
304 
305  return found;
306 }
307 
309 bp_table::do_add_breakpoint (const std::string& fname,
310  const bp_table::intmap& line)
311 {
312  intmap retval;
313 
314  octave_user_code *dbg_fcn = get_user_code (fname);
315 
316  if (dbg_fcn)
317  {
318  if (! do_add_breakpoint_1 (dbg_fcn, fname, line, retval))
319  {
320  // Search subfunctions in the order they appear in the file.
321 
322  const std::list<std::string> subfcn_names
323  = dbg_fcn->subfunction_names ();
324 
325  std::map<std::string, octave_value> subfcns
326  = dbg_fcn->subfunctions ();
327 
328  for (std::list<std::string>::const_iterator p = subfcn_names.begin ();
329  p != subfcn_names.end (); p++)
330  {
331  std::map<std::string, octave_value>::const_iterator
332  q = subfcns.find (*p);
333 
334  if (q != subfcns.end ())
335  {
336  octave_user_code *dbg_subfcn = q->second.user_code_value ();
337 
338  if (do_add_breakpoint_1 (dbg_subfcn, fname, line, retval))
339  break;
340  }
341  }
342  }
343  }
344  else
345  error ("add_breakpoint: unable to find the requested function\n");
346 
348 
349  return retval;
350 }
351 
352 
353 int
355  const std::string& fname,
356  const bp_table::intmap& line)
357 {
358  int retval = 0;
359 
360  std::string file = fcn->fcn_file_name ();
361 
362  tree_statement_list *cmds = fcn->body ();
363 
364  // FIXME: move the operation on cmds to the tree_statement_list class?
365 
366  if (cmds)
367  {
368  octave_value_list results = cmds->list_breakpoints ();
369 
370  if (results.length () > 0)
371  {
372  octave_idx_type len = line.size ();
373 
374  for (int i = 0; i < len; i++)
375  {
376  const_intmap_iterator p = line.find (i);
377 
378  if (p != line.end ())
379  {
380  int lineno = p->second;
381 
382  cmds->delete_breakpoint (lineno);
383 
384  if (! file.empty ())
385  octave_link::update_breakpoint (false, file, lineno);
386  }
387  }
388 
389  results = cmds->list_breakpoints ();
390 
391  bp_set_iterator it = bp_set.find (fname);
392  if (results.length () == 0 && it != bp_set.end ())
393  bp_set.erase (it);
394  }
395 
396  retval = results.length ();
397  }
398 
399  return retval;
400 }
401 
402 int
403 bp_table::do_remove_breakpoint (const std::string& fname,
404  const bp_table::intmap& line)
405 {
406  int retval = 0;
407 
408  octave_idx_type len = line.size ();
409 
410  if (len == 0)
411  {
412  intmap results = remove_all_breakpoints_in_file (fname);
413  retval = results.size ();
414  }
415  else
416  {
417  octave_user_code *dbg_fcn = get_user_code (fname);
418 
419  if (dbg_fcn)
420  {
421  retval = do_remove_breakpoint_1 (dbg_fcn, fname, line);
422 
423  // Search subfunctions in the order they appear in the file.
424 
425  const std::list<std::string> subfcn_names
426  = dbg_fcn->subfunction_names ();
427 
428  std::map<std::string, octave_value> subfcns
429  = dbg_fcn->subfunctions ();
430 
431  for (std::list<std::string>::const_iterator p = subfcn_names.begin ();
432  p != subfcn_names.end (); p++)
433  {
434  std::map<std::string, octave_value>::const_iterator
435  q = subfcns.find (*p);
436 
437  if (q != subfcns.end ())
438  {
439  octave_user_code *dbg_subfcn = q->second.user_code_value ();
440 
441  retval += do_remove_breakpoint_1 (dbg_subfcn, fname, line);
442  }
443  }
444  }
445  else
446  error ("remove_breakpoint: unable to find the requested function\n");
447  }
448 
450 
451  return retval;
452 }
453 
456  const std::string& fname)
457 {
458  intmap retval;
459 
460  std::string file = fcn->fcn_file_name ();
461 
462  tree_statement_list *cmds = fcn->body ();
463 
464  if (cmds)
465  {
466  retval = cmds->remove_all_breakpoints (file);
467 
468  bp_set_iterator it = bp_set.find (fname);
469  if (it != bp_set.end ())
470  bp_set.erase (it);
471  }
472 
473  return retval;
474 }
475 
478  bool silent)
479 {
480  intmap retval;
481 
482  octave_user_code *dbg_fcn = get_user_code (fname);
483 
484  if (dbg_fcn)
485  {
486  retval = do_remove_all_breakpoints_in_file_1 (dbg_fcn, fname);
487 
488  // Order is not important here.
489 
490  typedef std::map<std::string, octave_value>::const_iterator
491  subfcns_const_iterator;
492 
493  std::map<std::string, octave_value> subfcns = dbg_fcn->subfunctions ();
494 
495  for (subfcns_const_iterator p = subfcns.begin ();
496  p != subfcns.end (); p++)
497  {
498  octave_user_code *dbg_subfcn = p->second.user_code_value ();
499 
500  intmap tmp = do_remove_all_breakpoints_in_file_1 (dbg_subfcn, fname);
501 
502  // Merge new list with retval.
503  retval.insert (tmp.begin (), tmp.end ());
504  }
505  }
506  else if (! silent)
507  error ("remove_all_breakpoint_in_file: "
508  "unable to find the requested function\n");
509 
511 
512  return retval;
513 }
514 
515 void
517 {
518  for (const_bp_set_iterator it = bp_set.begin (); it != bp_set.end (); it++)
520 
521 
523 }
524 
525 std::string
527  std::string match)
528 {
529  std::string retval;
530 
531  for (int i = 0; i < slist.length (); i++)
532  {
533  if (slist (i).string_value () == match)
534  {
535  retval = slist(i).string_value ();
536  break;
537  }
538  }
539 
540  return retval;
541 }
542 
543 
546 {
547  fname_line_map retval;
548 
549  for (bp_set_iterator it = bp_set.begin (); it != bp_set.end (); it++)
550  {
551  if (fname_list.length () == 0
552  || do_find_bkpt_list (fname_list, *it) != "")
553  {
555 
556  if (f)
557  {
558  tree_statement_list *cmds = f->body ();
559 
560  // FIXME: move the operation on cmds to the
561  // tree_statement_list class?
562  if (cmds)
563  {
564  octave_value_list bkpts = cmds->list_breakpoints ();
565  octave_idx_type len = bkpts.length ();
566 
567  if (len > 0)
568  {
569  bp_table::intmap bkpts_vec;
570 
571  for (int i = 0; i < len; i++)
572  bkpts_vec[i] = bkpts (i).double_value ();
573 
574  std::string symbol_name = f->name ();
575 
576  retval[symbol_name] = bkpts_vec;
577  }
578  }
579  }
580  }
581  }
582 
583  return retval;
584 }
585 
586 static octave_value
588 {
589  int idx = 0;
590 
591  NDArray retval (dim_vector (1, line.size ()));
592 
593  for (size_t i = 0; i < line.size (); i++)
594  {
595  bp_table::const_intmap_iterator p = line.find (i);
596 
597  if (p != line.end ())
598  {
599  int lineno = p->second;
600  retval(idx++) = lineno;
601  }
602  }
603 
604  retval.resize (dim_vector (1, idx));
605 
606  return retval;
607 }
608 
609 DEFUN (dbstop, args, ,
610  "-*- texinfo -*-\n\
611 @deftypefn {Built-in Function} {@var{rline} =} dbstop (\"@var{func}\")\n\
612 @deftypefnx {Built-in Function} {@var{rline} =} dbstop (\"@var{func}\", @var{line})\n\
613 @deftypefnx {Built-in Function} {@var{rline} =} dbstop (\"@var{func}\", @var{line1}, @var{line2}, @dots{})\n\
614 Set a breakpoint in function @var{func}.\n\
615 \n\
616 Arguments are\n\
617 \n\
618 @table @var\n\
619 @item func\n\
620 Function name as a string variable. When already in debug\n\
621 mode this should be left out and only the line should be given.\n\
622 \n\
623 @item line\n\
624 Line number where the breakpoint should be set. Multiple\n\
625 lines may be given as separate arguments or as a vector.\n\
626 @end table\n\
627 \n\
628 When called with a single argument @var{func}, the breakpoint\n\
629 is set at the first executable line in the named function.\n\
630 \n\
631 The optional output @var{rline} is the real line number where the\n\
632 breakpoint was set. This can differ from specified line if\n\
633 the line is not executable. For example, if a breakpoint attempted on a\n\
634 blank line then Octave will set the real breakpoint at the\n\
635 next executable line.\n\
636 @seealso{dbclear, dbstatus, dbstep, debug_on_error, debug_on_warning, debug_on_interrupt}\n\
637 @end deftypefn")
638 {
639  bp_table::intmap retval;
640  std::string symbol_name;
641  bp_table::intmap lines;
642 
643  parse_dbfunction_params ("dbstop", args, symbol_name, lines);
644 
645  if (lines.size () == 0)
646  lines[0] = 1;
647 
648  if (! error_state)
649  retval = bp_table::add_breakpoint (symbol_name, lines);
650 
651  return intmap_to_ov (retval);
652 }
653 
654 DEFUN (dbclear, args, ,
655  "-*- texinfo -*-\n\
656 @deftypefn {Built-in Function} {} dbclear (\"@var{func}\")\n\
657 @deftypefnx {Built-in Function} {} dbclear (\"@var{func}\", @var{line}, @dots{})\n\
658 @deftypefnx {Built-in Function} {} dbclear (@var{line}, @dots{})\n\
659 Delete a breakpoint in the function @var{func}.\n\
660 \n\
661 Arguments are\n\
662 \n\
663 @table @var\n\
664 @item func\n\
665 Function name as a string variable. When already in debug\n\
666 mode this argument should be omitted and only the line number should be\n\
667 given.\n\
668 \n\
669 @item line\n\
670 Line number from which to remove a breakpoint. Multiple\n\
671 lines may be given as separate arguments or as a vector.\n\
672 @end table\n\
673 \n\
674 When called without a line number specification all breakpoints\n\
675 in the named function are cleared.\n\
676 \n\
677 If the requested line is not a breakpoint no action is performed.\n\
678 @seealso{dbstop, dbstatus, dbwhere}\n\
679 @end deftypefn")
680 {
681  octave_value retval;
682  std::string symbol_name = "";
683  bp_table::intmap lines;
684 
685  parse_dbfunction_params ("dbclear", args, symbol_name, lines);
686 
687  if (! error_state)
688  bp_table::remove_breakpoint (symbol_name, lines);
689 
690  return retval;
691 }
692 
693 DEFUN (dbstatus, args, nargout,
694  "-*- texinfo -*-\n\
695 @deftypefn {Built-in Function} {} dbstatus ()\n\
696 @deftypefnx {Built-in Function} {@var{brk_list} =} dbstatus ()\n\
697 @deftypefnx {Built-in Function} {@var{brk_list} =} dbstatus (\"@var{func}\")\n\
698 Report the location of active breakpoints.\n\
699 \n\
700 When called with no input or output arguments, print the list of\n\
701 all functions with breakpoints and the line numbers where those\n\
702 breakpoints are set.\n\
703 If a function name @var{func} is specified then only report breakpoints\n\
704 for the named function.\n\
705 \n\
706 The optional return argument @var{brk_list} is a struct array with the\n\
707 following fields.\n\
708 \n\
709 @table @asis\n\
710 @item name\n\
711 The name of the function with a breakpoint.\n\
712 \n\
713 @item file\n\
714 The name of the m-file where the function code is located.\n\
715 \n\
716 @item line\n\
717 A line number, or vector of line numbers, with a breakpoint.\n\
718 @end table\n\
719 \n\
720 @seealso{dbclear, dbwhere}\n\
721 @end deftypefn")
722 {
723  octave_map retval;
724  int nargin = args.length ();
725  octave_value_list fcn_list;
726  bp_table::fname_line_map bp_list;
727  std::string symbol_name;
728 
729  if (nargin != 0 && nargin != 1)
730  {
731  error ("dbstatus: only zero or one arguments accepted\n");
732  return octave_value ();
733  }
734 
735  if (nargin == 1)
736  {
737  if (args(0).is_string ())
738  {
739  symbol_name = args(0).string_value ();
740  fcn_list(0) = symbol_name;
741  bp_list = bp_table::get_breakpoint_list (fcn_list);
742  }
743  else
744  gripe_wrong_type_arg ("dbstatus", args(0));
745  }
746  else
747  {
748  octave_user_code *dbg_fcn = get_user_code ();
749  if (dbg_fcn)
750  {
751  symbol_name = dbg_fcn->name ();
752  fcn_list(0) = symbol_name;
753  }
754 
755  bp_list = bp_table::get_breakpoint_list (fcn_list);
756  }
757 
758  if (nargout == 0)
759  {
760  // Print out the breakpoint information.
761 
762  for (bp_table::fname_line_map_iterator it = bp_list.begin ();
763  it != bp_list.end (); it++)
764  {
765  bp_table::intmap m = it->second;
766 
767  size_t nel = m.size ();
768 
769  octave_stdout << "breakpoint in " << it->first;
770  if (nel > 1)
771  octave_stdout << " at lines ";
772  else
773  octave_stdout << " at line ";
774 
775  for (size_t j = 0; j < nel; j++)
776  octave_stdout << m[j] << ((j < nel - 1) ? ", " : ".");
777 
778  if (nel > 0)
779  octave_stdout << std::endl;
780  }
781  return octave_value ();
782  }
783  else
784  {
785  // Fill in an array for return.
786 
787  int i = 0;
788  Cell names (dim_vector (bp_list.size (), 1));
789  Cell file (dim_vector (bp_list.size (), 1));
790  Cell line (dim_vector (bp_list.size (), 1));
791 
792  for (bp_table::const_fname_line_map_iterator it = bp_list.begin ();
793  it != bp_list.end (); it++)
794  {
795  names(i) = it->first;
796  line(i) = intmap_to_ov (it->second);
797  file(i) = do_which (it->first);
798  i++;
799  }
800 
801  retval.assign ("name", names);
802  retval.assign ("file", file);
803  retval.assign ("line", line);
804 
805  return octave_value (retval);
806  }
807 }
808 
809 DEFUN (dbwhere, , ,
810  "-*- texinfo -*-\n\
811 @deftypefn {Command} {} dbwhere\n\
812 In debugging mode, report the current file and line number where\n\
813 execution is stopped.\n\
814 @seealso{dbstatus, dbcont, dbstep, dbup}\n\
815 @end deftypefn")
816 {
817  octave_value retval;
818 
819  octave_user_code *dbg_fcn = get_user_code ();
820 
821  if (dbg_fcn)
822  {
823  bool have_file = true;
824 
825  std::string name = dbg_fcn->fcn_file_name ();
826 
827  if (name.empty ())
828  {
829  have_file = false;
830 
831  name = dbg_fcn->name ();
832  }
833 
834  octave_stdout << "stopped in " << name << " at ";
835 
837 
838  if (l > 0)
839  {
840  octave_stdout << " line " << l << std::endl;
841 
842  if (have_file)
843  {
844  std::string line = get_file_line (name, l);
845 
846  if (! line.empty ())
847  octave_stdout << l << ": " << line << std::endl;
848  }
849  }
850  else
851  octave_stdout << " <unknown line>" << std::endl;
852  }
853  else
854  error ("dbwhere: must be inside a user function to use dbwhere\n");
855 
856  return retval;
857 }
858 
859 // Copied and modified from the do_type command in help.cc
860 // Maybe we could share some code?
861 void
862 do_dbtype (std::ostream& os, const std::string& name, int start, int end)
863 {
864  std::string ff = fcn_file_in_path (name);
865 
866  if (! ff.empty ())
867  {
868  std::ifstream fs (ff.c_str (), std::ios::in);
869 
870  if (fs)
871  {
872  char ch;
873  int line = 1;
874  bool isnewline = true;
875 
876  // FIXME: Why not use line-oriented input here [getline()]?
877  while (fs.get (ch) && line <= end)
878  {
879  if (isnewline && line >= start)
880  {
881  os << line << "\t";
882  isnewline = false;
883  }
884 
885  if (line >= start)
886  {
887  os << ch;
888  }
889 
890  if (ch == '\n')
891  {
892  line++;
893  isnewline = true;
894  }
895  }
896  }
897  else
898  os << "dbtype: unable to open '" << ff << "' for reading!\n";
899  }
900  else
901  os << "dbtype: unknown function " << name << "\n";
902 
903  os.flush ();
904 }
905 
906 DEFUN (dbtype, args, ,
907  "-*- texinfo -*-\n\
908 @deftypefn {Command} {} dbtype\n\
909 @deftypefnx {Command} {} dbtype @var{lineno}\n\
910 @deftypefnx {Command} {} dbtype @var{startl:endl}\n\
911 @deftypefnx {Command} {} dbtype @var{startl:end}\n\
912 @deftypefnx {Command} {} dbtype @var{func}\n\
913 @deftypefnx {Command} {} dbtype @var{func} @var{lineno}\n\
914 @deftypefnx {Command} {} dbtype @var{func} @var{startl:endl}\n\
915 @deftypefnx {Command} {} dbtype @var{func} @var{startl:end}\n\
916 Display a script file with line numbers.\n\
917 \n\
918 When called with no arguments in debugging mode, display the script file\n\
919 currently being debugged. An optional range specification can be used to\n\
920 list only a portion of the file. The special keyword @qcode{\"end\"} is a\n\
921 valid line number specification for the last line of the file.\n\
922 \n\
923 When called with the name of a function, list that script file with line\n\
924 numbers.\n\
925 @seealso{dbwhere, dbstatus, dbstop}\n\
926 @end deftypefn")
927 {
928  octave_value retval;
929  octave_user_code *dbg_fcn;
930 
931  int nargin = args.length ();
932  string_vector argv = args.make_argv ("dbtype");
933 
934  if (! error_state)
935  {
936  switch (nargin)
937  {
938  case 0: // dbtype
939  dbg_fcn = get_user_code ();
940 
941  if (dbg_fcn)
942  do_dbtype (octave_stdout, dbg_fcn->name (), 0,
944  else
945  error ("dbtype: must be inside a user function to give no arguments to dbtype\n");
946  break;
947 
948  case 1: // (dbtype func) || (dbtype start:end)
949  {
950  std::string arg = argv[1];
951 
952  size_t ind = arg.find (':');
953 
954  if (ind != std::string::npos) // (dbtype start:end)
955  {
956  dbg_fcn = get_user_code ();
957 
958  if (dbg_fcn)
959  {
960  std::string start_str = arg.substr (0, ind);
961  std::string end_str = arg.substr (ind + 1);
962 
963  int start, end;
964  start = atoi (start_str.c_str ());
965  if (end_str == "end")
967  else
968  end = atoi (end_str.c_str ());
969 
970  if (std::min (start, end) <= 0)
971  error ("dbtype: start and end lines must be >= 1\n");
972 
973  if (start <= end)
974  do_dbtype (octave_stdout, dbg_fcn->name (), start, end);
975  else
976  error ("dbtype: start line must be less than end line\n");
977  }
978  }
979  else // (dbtype func)
980  {
981  dbg_fcn = get_user_code (arg);
982 
983  if (dbg_fcn)
984  do_dbtype (octave_stdout, dbg_fcn->name (), 0,
986  else
987  error ("dbtype: function <%s> not found\n", arg.c_str ());
988  }
989  }
990  break;
991 
992  case 2: // (dbtype func start:end) , (dbtype func start)
993  dbg_fcn = get_user_code (argv[1]);
994 
995  if (dbg_fcn)
996  {
997  std::string arg = argv[2];
998  int start, end;
999  size_t ind = arg.find (':');
1000 
1001  if (ind != std::string::npos)
1002  {
1003  std::string start_str = arg.substr (0, ind);
1004  std::string end_str = arg.substr (ind + 1);
1005 
1006  start = atoi (start_str.c_str ());
1007  if (end_str == "end")
1009  else
1010  end = atoi (end_str.c_str ());
1011  }
1012  else
1013  {
1014  start = atoi (arg.c_str ());
1015  end = start;
1016  }
1017 
1018  if (std::min (start, end) <= 0)
1019  error ("dbtype: start and end lines must be >= 1\n");
1020 
1021  if (start <= end)
1022  do_dbtype (octave_stdout, dbg_fcn->name (), start, end);
1023  else
1024  error ("dbtype: start line must be less than end line\n");
1025  }
1026  else
1027  error ("dbtype: function <%s> not found\n", argv[1].c_str ());
1028 
1029  break;
1030 
1031  default:
1032  error ("dbtype: expecting zero, one, or two arguments\n");
1033  }
1034  }
1035 
1036  return retval;
1037 }
1038 
1039 DEFUN (dblist, args, ,
1040  "-*- texinfo -*-\n\
1041 @deftypefn {Command} {} dblist\n\
1042 @deftypefnx {Command} {} dblist @var{n}\n\
1043 In debugging mode, list @var{n} lines of the function being debugged\n\
1044 centered around the current line to be executed. If unspecified @var{n}\n\
1045 defaults to 10 (+/- 5 lines)\n\
1046 @seealso{dbwhere, dbtype}\n\
1047 @end deftypefn")
1048 {
1049  octave_value retval;
1050 
1051  int n = 10;
1052 
1053  if (args.length () == 1)
1054  {
1055  octave_value arg = args(0);
1056 
1057  if (arg.is_string ())
1058  {
1059  std::string s_arg = arg.string_value ();
1060 
1061  n = atoi (s_arg.c_str ());
1062  }
1063  else
1064  n = args(0).int_value ();
1065 
1066  if (n < 0)
1067  error ("dblist: N must be a non-negative integer");
1068  }
1069 
1070  octave_user_code *dbg_fcn = get_user_code ();
1071 
1072  if (dbg_fcn)
1073  {
1074  bool have_file = true;
1075 
1076  std::string name = dbg_fcn->fcn_file_name ();
1077 
1078  if (name.empty ())
1079  {
1080  have_file = false;
1081  name = dbg_fcn->name ();
1082  }
1083 
1085 
1086  if (l > 0)
1087  {
1088  if (have_file)
1089  {
1090  int l_min = std::max (l - n/2, 0);
1091  int l_max = l + n/2;
1092  do_dbtype (octave_stdout, dbg_fcn->name (), l_min, l-1);
1093 
1094  std::string line = get_file_line (name, l);
1095  if (! line.empty ())
1096  octave_stdout << l << "-->\t" << line << std::endl;
1097 
1098  do_dbtype (octave_stdout, dbg_fcn->name (), l+1, l_max);
1099  }
1100  }
1101  else
1102  {
1103  octave_stdout << "dblist: unable to determine source code line"
1104  << std::endl;
1105  }
1106  }
1107  else
1108  error ("dblist: must be inside a user function to use dblist\n");
1109 
1110  return retval;
1111 }
1112 
1113 static octave_value_list
1114 do_dbstack (const octave_value_list& args, int nargout, std::ostream& os)
1115 {
1116  octave_value_list retval;
1117 
1118  unwind_protect frame;
1119 
1120  octave_idx_type curr_frame = -1;
1121 
1122  size_t nskip = 0;
1123 
1124  octave_idx_type len = args.length ();
1125 
1126  // dbstack accepts up to 2 arguments.
1127 
1128  if (len == 1 || len == 2)
1129  {
1130  int n = 0;
1131 
1132  for (octave_idx_type i = 0; i < len && ! error_state; i++)
1133  {
1134  octave_value arg = args(i);
1135 
1136  if (arg.is_string ())
1137  {
1138  std::string s_arg = arg.string_value ();
1139 
1140  // Skip "-completenames", octave returns full names anyway.
1141 
1142  if (s_arg == "-completenames")
1143  continue;
1144 
1145  n = atoi (s_arg.c_str ());
1146  }
1147  else
1148  n = arg.int_value ();
1149 
1150  if (! error_state && n <= 0)
1151  error ("dbstack: N must be a non-negative integer");
1152  }
1153 
1154  if (n > 0)
1155  nskip = n;
1156  }
1157  else if (len)
1158  print_usage ();
1159 
1160  if (! error_state)
1161  {
1162  octave_map stk = octave_call_stack::backtrace (nskip, curr_frame);
1163 
1164  if (nargout == 0)
1165  {
1166  octave_idx_type nframes_to_display = stk.numel ();
1167 
1168  if (nframes_to_display > 0)
1169  {
1170  octave_preserve_stream_state stream_state (os);
1171 
1172  os << "stopped in:\n\n";
1173 
1174  Cell names = stk.contents ("name");
1175  Cell files = stk.contents ("file");
1176  Cell lines = stk.contents ("line");
1177 
1178  bool show_top_level = true;
1179 
1180  size_t max_name_len = 0;
1181 
1182  for (octave_idx_type i = 0; i < nframes_to_display; i++)
1183  {
1184  std::string name = names(i).string_value ();
1185 
1186  max_name_len = std::max (name.length (), max_name_len);
1187  }
1188 
1189  for (octave_idx_type i = 0; i < nframes_to_display; i++)
1190  {
1191  std::string name = names(i).string_value ();
1192  std::string file = files(i).string_value ();
1193  int line = lines(i).int_value ();
1194 
1195  if (show_top_level && i == curr_frame)
1196  show_top_level = false;
1197 
1198  os << (i == curr_frame ? " --> " : " ")
1199  << std::setw (max_name_len) << name
1200  << " at line " << line
1201  << " [" << file << "]"
1202  << std::endl;
1203  }
1204 
1205  if (show_top_level)
1206  os << " --> top level" << std::endl;
1207  }
1208  }
1209  else
1210  {
1211  retval(1) = curr_frame < 0 ? 1 : curr_frame + 1;
1212  retval(0) = stk;
1213  }
1214  }
1215 
1216  return retval;
1217 }
1218 
1219 // A function that can be easily called from a debugger print the Octave
1220 // stack. This can be useful for finding what line of code the
1221 // interpreter is currently executing when the debugger is stopped in
1222 // some C++ function, for example.
1223 
1224 void
1226 {
1227  do_dbstack (octave_value_list (), 0, std::cerr);
1228 }
1229 
1230 DEFUN (dbstack, args, nargout,
1231  "-*- texinfo -*-\n\
1232 @deftypefn {Command} {} dbstack\n\
1233 @deftypefnx {Command} {} dbstack @var{n}\n\
1234 @deftypefnx {Command} {} dbstack @var{-completenames}\n\
1235 @deftypefnx {Built-in Function} {[@var{stack}, @var{idx}] =} dbstack (@dots{})\n\
1236 Display or return current debugging function stack information.\n\
1237 With optional argument @var{n}, omit the @var{n} innermost stack frames.\n\
1238 \n\
1239 Although accepted, the argument @var{-completenames} is silently ignored.\n\
1240 Octave always returns absolute file names. The arguments @var{n} and\n\
1241 @var{-completenames} can be both specified in any order.\n\
1242 \n\
1243 The optional return argument @var{stack} is a struct array with the\n\
1244 following fields:\n\
1245 \n\
1246 @table @asis\n\
1247 @item file\n\
1248 The name of the m-file where the function code is located.\n\
1249 \n\
1250 @item name\n\
1251 The name of the function with a breakpoint.\n\
1252 \n\
1253 @item line\n\
1254 The line number of an active breakpoint.\n\
1255 \n\
1256 @item column\n\
1257 The column number of the line where the breakpoint begins.\n\
1258 \n\
1259 @item scope\n\
1260 Undocumented.\n\
1261 \n\
1262 @item context\n\
1263 Undocumented.\n\
1264 @end table\n\
1265 \n\
1266 The return argument @var{idx} specifies which element of the @var{stack}\n\
1267 struct array is currently active.\n\
1268 @seealso{dbup, dbdown, dbwhere, dbstatus}\n\
1269 @end deftypefn")
1270 {
1271  return do_dbstack (args, nargout, octave_stdout);
1272 }
1273 
1274 static void
1275 do_dbupdown (const octave_value_list& args, const std::string& who)
1276 {
1277  int n = 1;
1278 
1279  if (args.length () == 1)
1280  {
1281  octave_value arg = args(0);
1282 
1283  if (arg.is_string ())
1284  {
1285  std::string s_arg = arg.string_value ();
1286 
1287  n = atoi (s_arg.c_str ());
1288  }
1289  else
1290  n = args(0).int_value ();
1291  }
1292 
1293  if (! error_state)
1294  {
1295  if (who == "dbup")
1296  n = -n;
1297 
1299  error ("%s: invalid stack frame", who.c_str ());
1300  }
1301 }
1302 
1303 DEFUN (dbup, args, ,
1304  "-*- texinfo -*-\n\
1305 @deftypefn {Built-in Function} {} dbup\n\
1306 @deftypefnx {Built-in Function} {} dbup (@var{n})\n\
1307 In debugging mode, move up the execution stack @var{n} frames.\n\
1308 If @var{n} is omitted, move up one frame.\n\
1309 @seealso{dbstack, dbdown}\n\
1310 @end deftypefn")
1311 {
1312  octave_value retval;
1313 
1314  do_dbupdown (args, "dbup");
1315 
1316  return retval;
1317 }
1318 
1319 DEFUN (dbdown, args, ,
1320  "-*- texinfo -*-\n\
1321 @deftypefn {Built-in Function} {} dbdown\n\
1322 @deftypefnx {Built-in Function} {} dbdown (@var{n})\n\
1323 In debugging mode, move down the execution stack @var{n} frames.\n\
1324 If @var{n} is omitted, move down one frame.\n\
1325 @seealso{dbstack, dbup}\n\
1326 @end deftypefn")
1327 {
1328  octave_value retval;
1329 
1330  do_dbupdown (args, "dbdown");
1331 
1332  return retval;
1333 }
1334 
1335 DEFUN (dbstep, args, ,
1336  "-*- texinfo -*-\n\
1337 @deftypefn {Command} {} dbstep\n\
1338 @deftypefnx {Command} {} dbstep @var{n}\n\
1339 @deftypefnx {Command} {} dbstep in\n\
1340 @deftypefnx {Command} {} dbstep out\n\
1341 @deftypefnx {Command} {} dbnext @dots{}\n\
1342 In debugging mode, execute the next @var{n} lines of code.\n\
1343 If @var{n} is omitted, execute the next single line of code.\n\
1344 If the next line of code is itself defined in terms of an m-file remain in\n\
1345 the existing function.\n\
1346 \n\
1347 Using @code{dbstep in} will cause execution of the next line to step into\n\
1348 any m-files defined on the next line. Using @code{dbstep out} will cause\n\
1349 execution to continue until the current function returns.\n\
1350 \n\
1351 @code{dbnext} is an alias for @code{dbstep}.\n\
1352 @seealso{dbcont, dbquit}\n\
1353 @end deftypefn")
1354 {
1355  if (Vdebugging)
1356  {
1357  int nargin = args.length ();
1358 
1359  if (nargin > 1)
1360  print_usage ();
1361  else if (nargin == 1)
1362  {
1363  if (args(0).is_string ())
1364  {
1365  std::string arg = args(0).string_value ();
1366 
1367  if (! error_state)
1368  {
1369  if (arg == "in")
1370  {
1371  Vdebugging = false;
1372 
1374  }
1375  else if (arg == "out")
1376  {
1377  Vdebugging = false;
1378 
1380  }
1381  else
1382  {
1383  int n = atoi (arg.c_str ());
1384 
1385  if (n > 0)
1386  {
1387  Vdebugging = false;
1388 
1390  }
1391  else
1392  error ("dbstep: invalid argument");
1393  }
1394  }
1395  }
1396  else
1397  error ("dbstep: input argument must be a character string");
1398  }
1399  else
1400  {
1401  Vdebugging = false;
1402 
1404  }
1405  }
1406  else
1407  error ("dbstep: can only be called in debug mode");
1408 
1409  return octave_value_list ();
1410 }
1411 
1412 DEFALIAS (dbnext, dbstep);
1413 
1414 DEFUN (dbcont, args, ,
1415  "-*- texinfo -*-\n\
1416 @deftypefn {Command} {} dbcont\n\
1417 Leave command-line debugging mode and continue code execution normally.\n\
1418 @seealso{dbstep, dbquit}\n\
1419 @end deftypefn")
1420 {
1421  if (Vdebugging)
1422  {
1423  if (args.length () == 0)
1424  {
1425  Vdebugging = false;
1426 
1428  }
1429  else
1430  print_usage ();
1431  }
1432  else
1433  error ("dbcont: can only be called in debug mode");
1434 
1435  return octave_value_list ();
1436 }
1437 
1438 DEFUN (dbquit, args, ,
1439  "-*- texinfo -*-\n\
1440 @deftypefn {Command} {} dbquit\n\
1441 Quit debugging mode immediately without further code execution and\n\
1442 return to the Octave prompt.\n\
1443 @seealso{dbcont, dbstep}\n\
1444 @end deftypefn")
1445 {
1446  if (Vdebugging)
1447  {
1448  if (args.length () == 0)
1449  {
1450  Vdebugging = false;
1451 
1453 
1455  }
1456  else
1457  print_usage ();
1458  }
1459  else
1460  error ("dbquit: can only be called in debug mode");
1461 
1462  return octave_value_list ();
1463 }
1464 
1465 DEFUN (isdebugmode, args, ,
1466  "-*- texinfo -*-\n\
1467 @deftypefn {Built-in Function} {} isdebugmode ()\n\
1468 Return true if in debugging mode, otherwise false.\n\
1469 @seealso{dbwhere, dbstack, dbstatus}\n\
1470 @end deftypefn")
1471 {
1472  octave_value retval;
1473 
1474  if (args.length () == 0)
1475  retval = Vdebugging;
1476  else
1477  print_usage ();
1478 
1479  return retval;
1480 }