GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
debug.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2001-2021 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 <deque>
31 #include <fstream>
32 #include <iomanip>
33 #include <iostream>
34 #include <limits>
35 #include <set>
36 #include <string>
37 
38 #include "dNDArray.h"
39 
40 #include "bp-table.h"
41 #include "defun.h"
42 #include "error.h"
43 #include "errwarn.h"
44 #include "file-ops.h"
45 #include "help.h"
46 #include "input.h"
47 #include "interpreter-private.h"
48 #include "interpreter.h"
49 #include "lo-sysdep.h"
51 #include "ov-usr-fcn.h"
52 #include "ov.h"
53 #include "ovl.h"
54 #include "pager.h"
55 #include "parse.h"
56 #include "pt-eval.h"
57 #include "unwind-prot.h"
58 #include "utils.h"
59 #include "utils.h"
60 #include "variables.h"
61 
62 static octave_value
64 {
65  int idx = 0;
66 
67  NDArray retval (dim_vector (1, line.size ()));
68 
69  for (size_t i = 0; i < line.size (); i++)
70  {
72 
73  if (p != line.end ())
74  {
75  int lineno = p->second;
76  retval(idx++) = lineno;
77  }
78  }
79 
80  retval.resize (dim_vector (1, idx));
81 
82  return retval;
83 }
84 
85 DEFMETHOD (dbstop, interp, args, ,
86  doc: /* -*- texinfo -*-
87 @deftypefn {} {} dbstop @var{func}
88 @deftypefnx {} {} dbstop @var{func} @var{line}
89 @deftypefnx {} {} dbstop @var{func} @var{line1} @var{line2} @dots{}
90 @deftypefnx {} {} dbstop @var{line1} @dots{}
91 @deftypefnx {} {} dbstop in @var{func}
92 @deftypefnx {} {} dbstop in @var{func} at @var{line}
93 @deftypefnx {} {} dbstop in @var{func} at @var{line} if "@var{condition}"
94 @deftypefnx {} {} dbstop in @var{class} at @var{method}
95 @deftypefnx {} {} dbstop if @var{event}
96 @deftypefnx {} {} dbstop if @var{event} @var{ID}
97 @deftypefnx {} {} dbstop (@var{bp_struct})
98 @deftypefnx {} {@var{rline} =} dbstop @dots{}
99 
100 Set breakpoints for the built-in debugger.
101 
102 @var{func} is the name of a function on the current @code{path}. When
103 already in debug mode the @var{func} argument can be omitted and the current
104 function will be used. Breakpoints at subfunctions are set with the scope
105 operator @samp{>}. For example, If @file{file.m} has a subfunction
106 @code{func2}, then a breakpoint in @code{func2} can be specified by
107 @code{file>func2}.
108 
109 @var{line} is the line number at which to break. If @var{line} is not
110 specified, it defaults to the first executable line in the file
111 @file{func.m}. Multiple lines can be specified in a single command; when
112 function syntax is used, the lines may also be passed as a single vector
113 argument (@code{[@var{line1}, @var{line2}, @dots{}]}).
114 
115 @var{condition} is any Octave expression that can be evaluated in the code
116 context that exists at the breakpoint. When the breakpoint is encountered,
117 @var{condition} will be evaluated, and execution will stop if
118 @var{condition} is true. If @var{condition} cannot be evaluated, for
119 example because it refers to an undefined variable, an error will be thrown.
120  Expressions with side effects (such as @code{y++ > 1}) will alter
121 variables, and should generally be avoided. Conditions containing quotes
122 (@samp{"}, @samp{'}) or comment characters (@samp{#}, @samp{%}) must be
123 enclosed in quotes. (This does not apply to conditions entered from the
124 editor's context menu.) For example:
125 
126 @example
127 dbstop in axis at 246 if 'any (opt == "x")'
128 @end example
129 
130 The form specifying @var{event} does not cause a specific breakpoint at a
131 given function and line number. Instead it causes debug mode to be entered
132 when certain unexpected events are encountered. Possible values are
133 
134 @table @code
135 @item error
136 Stop when an error is reported. This is equivalent to specifying
137 both @code{debug_on_error (true)} and @code{debug_on_interrupt (true)}.
138 
139 @item caught error
140 Stop when an error is caught by a try-catch block (not yet implemented).
141 
142 @item interrupt
143 Stop when an interrupt (@kbd{Ctrl-C}) occurs.
144 
145 @item naninf
146 Stop when code returns a non-finite value (not yet implemented).
147 
148 @item warning
149 Stop when a warning is reported. This is equivalent to specifying
150 @code{debug_on_warning (true)}.
151 @end table
152 
153 The events @code{error}, @code{caught error}, and @code{warning} can all be
154 followed by a string specifying an error ID or warning ID@. If that is
155 done, only errors with the specified ID will cause execution to stop. To
156 stop on one of a set of IDs, multiple @code{dbstop} commands must be
157 issued.
158 
159 Breakpoints and events can be removed using the @code{dbclear} command with
160 the same syntax.
161 
162 It is possible to save all breakpoints and restore them at once by issuing
163 the commands @code{bp_state = dbstatus; @dots{}; dbstop (bp_state)}.
164 
165 The optional output @var{rline} is the real line number where the breakpoint
166 was set. This can differ from the specified line if the line is not
167 executable. For example, if a breakpoint attempted on a blank line then
168 Octave will set the real breakpoint at the next executable line.
169 
170 When a file is re-parsed, such as when it is modified outside the GUI,
171 all breakpoints within the file are cleared.
172 
173 @seealso{dbclear, dbstatus, dbstep, debug_on_error, debug_on_warning, debug_on_interrupt}
174 @end deftypefn */)
175 {
177  std::string symbol_name = ""; // stays empty for "dbstop if error" etc
178  std::string class_name = "";
180  std::string condition = "";
182 
183  octave::tree_evaluator& tw = interp.get_evaluator ();
184 
185  octave::bp_table& bptab = tw.get_bp_table ();
186 
187  if (args.length() >= 1 && ! args(0).isstruct ())
188  {
189  // explicit function / line / condition
190  bptab.parse_dbfunction_params ("dbstop", args, symbol_name,
191  class_name, lines, condition);
192 
193  if (lines.size () == 0)
194  lines[0] = 1;
195 
196  if (symbol_name != "")
197  {
198  retmap = bptab.add_breakpoint (symbol_name, class_name,
199  lines, condition);
200  retval = intmap_to_ov (retmap);
201  }
202  }
203  else if (args.length () != 1)
204  {
205  print_usage ();
206  }
207  else // structure of the form output by dbstatus
208  {
209  octave_map mv = args(0).map_value ();
210  if (mv.isfield ("bkpt") || mv.isfield ("errs") || mv.isfield ("warn")
211  || mv.isfield ("intr"))
212  {
213  bptab.dbstop_process_map_args (mv);
214 
215  // Replace mv by "bkpt", to use the processing below.
216  octave_value bkpt = mv.getfield ("bkpt");
217  if (bkpt.isempty ())
218  mv = octave_map ();
219  else
220  {
221  if (bkpt.iscell () && bkpt.cell_value ().numel () > 0
222  && bkpt.cell_value () (0).isstruct ())
223  mv = bkpt.cell_value () (0).map_value ();
224  else
225  {
226  error ("dbstop: invalid 'bkpt' field");
227  mv = octave_map ();
228  }
229  }
230  }
231  if (mv.isempty ())
232  {
233  // no changes requested. Occurs if "errs" non-empty but "bkpt" empty
234  }
235  else if (! mv.isfield ("name") || ! mv.isfield ("line"))
236  {
237  error ("dbstop: Cell array must contain fields 'name' and 'line'");
238  retval = octave_value (0);
239  }
240  else
241  {
242  bool use_cond = mv.isfield ("cond");
243  Cell name = mv.getfield ("name");
244  Cell line = mv.getfield ("line");
245  Cell cond = (use_cond ? mv.getfield ("cond") : Cell ());
246  std::string unconditional = "";
247  for (octave_idx_type i = 0; i < line.numel (); i++)
248  {
249  lines [0] = line(i).double_value ();
250  bptab.add_breakpoint (name(i).string_value (), "", lines,
251  (use_cond
252  ? cond(i).string_value ()
253  : unconditional));
254  }
255  retval = octave_value (line.numel ());
256  }
257  }
258 
259  // If we add a breakpoint, we also need to reset debug_mode.
260  tw.reset_debug_state ();
261 
262  return retval;
263 }
264 
265 DEFMETHOD (dbclear, interp, args, ,
266  doc: /* -*- texinfo -*-
267 @deftypefn {} {} dbclear @var{func}
268 @deftypefnx {} {} dbclear @var{func} @var{line}
269 @deftypefnx {} {} dbclear @var{func} @var{line1} @var{line2} @dots{}
270 @deftypefnx {} {} dbclear @var{line} @dots{}
271 @deftypefnx {} {} dbclear all
272 @deftypefnx {} {} dbclear in @var{func}
273 @deftypefnx {} {} dbclear in @var{func} at @var{line}
274 @deftypefnx {} {} dbclear if @var{event}
275 @deftypefnx {} {} dbclear ("@var{func}")
276 @deftypefnx {} {} dbclear ("@var{func}", @var{line})
277 @deftypefnx {} {} dbclear ("@var{func}", @var{line1}, @var{line2}, @dots{})
278 @deftypefnx {} {} dbclear ("@var{func}", @var{line1}, @dots{})
279 @deftypefnx {} {} dbclear (@var{line}, @dots{})
280 @deftypefnx {} {} dbclear ("all")
281 Delete a breakpoint at line number @var{line} in the function @var{func}.
282 
283 Arguments are
284 
285 @table @var
286 @item func
287 Function name as a string variable. When already in debug mode this
288 argument can be omitted and the current function will be used.
289 
290 @item line
291 Line number from which to remove a breakpoint. Multiple lines may be given
292 as separate arguments or as a vector.
293 
294 @item event
295 An event such as @code{error}, @code{interrupt}, or @code{warning}
296 (@pxref{XREFdbstop,,dbstop} for details).
297 @end table
298 
299 When called without a line number specification all breakpoints in the named
300 function are cleared.
301 
302 If the requested line is not a breakpoint no action is performed.
303 
304 The special keyword @qcode{"all"} will clear all breakpoints from all
305 files.
306 @seealso{dbstop, dbstatus, dbwhere}
307 @end deftypefn */)
308 {
309  std::string symbol_name = ""; // stays empty for "dbclear if error" etc
310  std::string class_name = "";
312  std::string dummy; // "if" condition -- only used for dbstop
313 
314  int nargin = args.length ();
315 
316  octave::tree_evaluator& tw = interp.get_evaluator ();
317 
318  octave::bp_table& bptab = tw.get_bp_table ();
319 
320  bptab.parse_dbfunction_params ("dbclear", args, symbol_name, class_name, lines, dummy);
321 
322  if (nargin == 1 && symbol_name == "all")
323  {
324  bptab.remove_all_breakpoints ();
325  bptab.dbclear_all_signals ();
326  }
327  else
328  {
329  if (symbol_name != "")
330  bptab.remove_breakpoint (symbol_name, lines);
331  }
332 
333  // If we remove a breakpoint, we also need to reset debug_mode.
334  tw.reset_debug_state ();
335 
336  return ovl ();
337 }
338 
339 DEFMETHOD (dbstatus, interp, args, nargout,
340  doc: /* -*- texinfo -*-
341 @deftypefn {} {} dbstatus
342 @deftypefnx {} {} dbstatus @var{func}
343 @deftypefnx {} {@var{bp_list} =} dbstatus @dots{}
344 Report the location of active breakpoints.
345 
346 When called with no input or output arguments, print the list of all
347 functions with breakpoints and the line numbers where those breakpoints are
348 set.
349 
350 If a function name @var{func} is specified then only report breakpoints
351 for the named function and its subfunctions.
352 
353 The optional return argument @var{bp_list} is a struct array with the
354 following fields.
355 
356 @table @asis
357 @item name
358 The name of the function with a breakpoint. A subfunction, say @code{func2}
359 within an m-file, say @file{file.m}, is specified as @code{file>func2}.
360 
361 @item file
362 The name of the m-file where the function code is located.
363 
364 @item line
365 The line number with the breakpoint.
366 
367 @item cond
368 The condition that must be satisfied for the breakpoint to be active, or
369 the empty string for unconditional breakpoints.
370 @end table
371 
372 @c Note: When @code{dbstatus} is called from the debug prompt within a function,
373 @c the list of breakpoints is automatically trimmed to the breakpoints in the
374 @c current function.
375 If @code{dbstop if error} is true but no explicit IDs are specified, the
376 return value will have an empty field called @qcode{"errs"}. If IDs are
377 specified, the @code{errs} field will have one row per ID@. If
378 @code{dbstop if error} is false, there is no @qcode{"errs"} field.
379 The @qcode{"warn"} field is set similarly by @code{dbstop if warning}.
380 
381 @seealso{dbstop, dbclear, dbwhere, dblist, dbstack}
382 @end deftypefn */)
383 {
384  int nargin = args.length ();
385 
386  if (nargin != 0 && nargin != 1)
387  error ("dbstatus: only zero or one arguments accepted\n");
388 
389  octave_value_list fcn_list;
391  std::string symbol_name;
392 
393  octave::tree_evaluator& tw = interp.get_evaluator ();
394 
395  octave::bp_table& bptab = tw.get_bp_table ();
396 
397  if (nargin == 1)
398  {
399  if (! args(0).is_string ())
400  err_wrong_type_arg ("dbstatus", args(0));
401 
402  symbol_name = args(0).string_value ();
403  fcn_list(0) = symbol_name;
404  bp_list = bptab.get_breakpoint_list (fcn_list);
405  }
406  else
407  {
408 /*
409  if (tw.in_debug_repl ())
410  {
411  octave_user_code *dbg_fcn = tw.get_user_code ();
412  if (dbg_fcn)
413  {
414  symbol_name = dbg_fcn->name ();
415  fcn_list(0) = symbol_name;
416  }
417  }
418 */
419 
420  bp_list = bptab.get_breakpoint_list (fcn_list);
421  }
422 
423  if (nargout == 0)
424  {
425  // Print out the breakpoint information.
426 
427  for (auto& fnm_bp_p: bp_list)
428  {
429  std::list<octave::bp_type> m = fnm_bp_p.second;
430 
431  // print unconditional breakpoints, if any, on a single line
432 
433  // first, check to see if there are any
434  int have_unconditional = 0;
435  for (const auto& bp : m)
436  {
437  if (bp.cond == "")
438  {
439  if (have_unconditional++)
440  break; // stop once we know its plural
441  }
442  }
443  // If we actually have some, print line numbers only
444  if (have_unconditional)
445  {
446  const char *_s_ = (have_unconditional > 1) ? "s" : "";
447  octave_stdout << "breakpoint" << _s_ << " in " << fnm_bp_p.first
448  << " at line" << _s_ << ' ';
449 
450  for (const auto& bp : m)
451  {
452  if (bp.cond == "")
453  octave_stdout << bp.line << ' ';
454  }
455  octave_stdout << std::endl;
456  }
457 
458  // print conditional breakpoints, one per line, with conditions
459  for (const auto& bp : m)
460  {
461  if (bp.cond != "")
462  octave_stdout << "breakpoint in " << fnm_bp_p.first
463  << " at line " << bp.line
464  << " if " << bp.cond << "\n";
465  }
466  }
467 
468  bptab.stop_on_err_warn_status (true);
469 
470  return ovl ();
471  }
472  else
473  {
474  octave::help_system& help_sys = interp.get_help_system ();
475 
476  // Fill in an array for return.
477  int i = 0;
478  octave_map retmap;
480 
481  // count the number of breakpoints in all files
482  int count = 0;
483  for (const auto& fnm_bp_p : bp_list)
484  count += fnm_bp_p.second.size ();
485 
486  Cell names (dim_vector (count, 1));
487  Cell file (dim_vector (count, 1));
488  Cell line (dim_vector (count, 1));
489  Cell cond (dim_vector (count, 1));
490 
491  for (const auto& fnm_bp_p : bp_list)
492  {
493  std::string filename = fnm_bp_p.first;
494  const char *sub_fun = strchr (filename.c_str (), '>');
495  if (sub_fun)
496  filename = filename.substr(0, sub_fun - filename.c_str ());
497  octave_value path_name;
498  path_name
499  = octave::sys::canonicalize_file_name (help_sys.which (filename));
500 
501  for (const auto& bp : fnm_bp_p.second)
502  {
503  names(i) = fnm_bp_p.first;
504  file(i) = path_name;
505  line(i) = octave_value (bp.line);
506  cond(i) = octave_value (bp.cond);
507  i++;
508  }
509  }
510 
511  retmap.assign ("name", names);
512  retmap.assign ("file", file);
513  retmap.assign ("line", line);
514  retmap.assign ("cond", cond);
515 
516  const octave_map ew = bptab.stop_on_err_warn_status (false);
517  if (ew.isempty ())
518  {
519  retval = octave_value (retmap);
520  }
521  else
522  {
523  octave_map outer (dim_vector (3,1));
524  outer.assign ("bkpt", Cell (retmap));
525  for (auto f = ew.begin (); f != ew.end (); f++)
526  outer.setfield (f->first, ew.contents (f));
527 
528  retval = octave_value (outer);
529  }
530 
531  return retval;
532  }
533 }
534 
535 /*
536 %!test
537 %! if (isguirunning ())
538 %! orig_show_dbg = __event_manager_gui_preference__ ("editor/show_dbg_file",
539 %! "0");
540 %! endif
541 %! unwind_protect
542 %! dbclear all; # Clear out breakpoints before test
543 %! dbstop @ftp/dir;
544 %! dbstop @audioplayer/set 70;
545 %! dbstop quantile>__quantile__;
546 %! dbstop ls;
547 %! s = dbstatus;
548 %! dbclear all;
549 %! assert (s(1).name, "@audioplayer/set>setproperty");
550 %! assert (s(2).name, "@ftp/dir");
551 %! assert (s(3).name, "ls");
552 %! assert (s(4).name, "quantile>__quantile__");
553 %! assert (s(2).file(end-10:end), [filesep "@ftp" filesep "dir.m"]);
554 %! unwind_protect_cleanup
555 %! if (isguirunning ())
556 %! __event_manager_gui_preference__ ("editor/show_dbg_file", orig_show_dbg);
557 %! endif
558 %! end_unwind_protect
559 */
560 
561 DEFMETHOD (dbwhere, interp, , ,
562  doc: /* -*- texinfo -*-
563 @deftypefn {} {} dbwhere
564 In debugging mode, report the current file and line number where execution
565 is stopped.
566 @seealso{dbstack, dblist, dbstatus, dbcont, dbstep, dbup, dbdown}
567 @end deftypefn */)
568 {
569  octave::tree_evaluator& tw = interp.get_evaluator ();
570 
572 
573  return ovl ();
574 }
575 
576 static void
577 do_dbtype (std::ostream& os, const std::string& name, int start, int end)
578 {
579  std::string ff = octave::fcn_file_in_path (name);
580 
581  if (ff.empty ())
582  os << "dbtype: unknown function " << name << "\n";
583  else
584  {
585  std::ifstream fs = octave::sys::ifstream (ff.c_str (), std::ios::in);
586 
587  if (! fs)
588  os << "dbtype: unable to open '" << ff << "' for reading!\n";
589  else
590  {
591  int line = 1;
592  std::string text;
593 
594  while (std::getline (fs, text) && line <= end)
595  {
596  if (line >= start)
597  os << line << "\t" << text << "\n";
598 
599  line++;
600  }
601  }
602  }
603 
604  os.flush ();
605 }
606 
607 DEFMETHOD (dbtype, interp, args, ,
608  doc: /* -*- texinfo -*-
609 @deftypefn {} {} dbtype
610 @deftypefnx {} {} dbtype @var{lineno}
611 @deftypefnx {} {} dbtype @var{startl:endl}
612 @deftypefnx {} {} dbtype @var{startl:end}
613 @deftypefnx {} {} dbtype @var{func}
614 @deftypefnx {} {} dbtype @var{func} @var{lineno}
615 @deftypefnx {} {} dbtype @var{func} @var{startl:endl}
616 @deftypefnx {} {} dbtype @var{func} @var{startl:end}
617 Display a script file with line numbers.
618 
619 When called with no arguments in debugging mode, display the script file
620 currently being debugged.
621 
622 An optional range specification can be used to list only a portion of the
623 file. The special keyword @qcode{"end"} is a valid line number
624 specification for the last line of the file.
625 
626 When called with the name of a function, list that script file with line
627 numbers.
628 @seealso{dblist, dbwhere, dbstatus, dbstop}
629 @end deftypefn */)
630 {
631  octave_user_code *dbg_fcn;
632 
633  string_vector argv = args.make_argv ("dbtype");
634 
635  octave::tree_evaluator& tw = interp.get_evaluator ();
636 
637  switch (args.length ())
638  {
639  case 0: // dbtype
640  dbg_fcn = tw.get_user_code ();
641 
642  if (! dbg_fcn)
643  error ("dbtype: must be inside a user function to give no arguments to dbtype\n");
644 
645  do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (),
647 
648  break;
649 
650  case 1: // (dbtype start:end) || (dbtype func) || (dbtype lineno)
651  {
652  std::string arg = argv[1];
653 
654  size_t ind = arg.find (':');
655 
656  if (ind != std::string::npos) // (dbtype start:end)
657  {
658  dbg_fcn = tw.get_user_code ();
659 
660  if (dbg_fcn)
661  {
662  std::string start_str = arg.substr (0, ind);
663  std::string end_str = arg.substr (ind + 1);
664 
665  int start, end;
666  start = atoi (start_str.c_str ());
667  if (end_str == "end")
669  else
670  end = atoi (end_str.c_str ());
671 
672  if (std::min (start, end) <= 0)
673  error ("dbtype: start and end lines must be >= 1\n");
674 
675  if (start > end)
676  error ("dbtype: start line must be less than end line\n");
677 
678  do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (),
679  start, end);
680  }
681  }
682  else // (dbtype func) || (dbtype lineno)
683  {
684  int line = atoi (arg.c_str ());
685 
686  if (line == 0) // (dbtype func)
687  {
688  dbg_fcn = tw.get_user_code (arg);
689 
690  if (! dbg_fcn)
691  error ("dbtype: function <%s> not found\n", arg.c_str ());
692 
693  do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (),
695  }
696  else // (dbtype lineno)
697  {
698  if (line <= 0)
699  error ("dbtype: start and end lines must be >= 1\n");
700 
701  dbg_fcn = tw.get_user_code ();
702 
703  if (dbg_fcn)
704  do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (),
705  line, line);
706  }
707  }
708  }
709  break;
710 
711  case 2: // (dbtype func start:end) || (dbtype func start)
712  {
713  dbg_fcn = tw.get_user_code (argv[1]);
714 
715  if (! dbg_fcn)
716  error ("dbtype: function <%s> not found\n", argv[1].c_str ());
717 
718  std::string arg = argv[2];
719  int start, end;
720  size_t ind = arg.find (':');
721 
722  if (ind != std::string::npos)
723  {
724  std::string start_str = arg.substr (0, ind);
725  std::string end_str = arg.substr (ind + 1);
726 
727  start = atoi (start_str.c_str ());
728  if (end_str == "end")
730  else
731  end = atoi (end_str.c_str ());
732  }
733  else
734  {
735  start = atoi (arg.c_str ());
736  end = start;
737  }
738 
739  if (std::min (start, end) <= 0)
740  error ("dbtype: start and end lines must be >= 1\n");
741 
742  if (start > end)
743  error ("dbtype: start line must be less than end line\n");
744 
745  do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (), start, end);
746  }
747  break;
748 
749  default:
750  error ("dbtype: expecting zero, one, or two arguments\n");
751  }
752 
753  return ovl ();
754 }
755 
756 DEFMETHOD (dblist, interp, args, ,
757  doc: /* -*- texinfo -*-
758 @deftypefn {} {} dblist
759 @deftypefnx {} {} dblist @var{n}
760 In debugging mode, list @var{n} lines of the function being debugged
761 centered around the current line to be executed.
762 
763 If unspecified @var{n} defaults to 10 (+/- 5 lines)
764 @seealso{dbwhere, dbtype, dbstack}
765 @end deftypefn */)
766 {
767  int n = 10;
768 
769  if (args.length () == 1)
770  {
771  octave_value arg = args(0);
772 
773  if (arg.is_string ())
774  {
775  std::string s_arg = arg.string_value ();
776 
777  n = atoi (s_arg.c_str ());
778  }
779  else
780  n = args(0).int_value ();
781 
782  if (n < 0)
783  error ("dblist: N must be a non-negative integer");
784  }
785 
786  octave::tree_evaluator& tw = interp.get_evaluator ();
787 
788  octave_user_code *dbg_fcn = tw.get_user_code ();
789 
790  if (! dbg_fcn)
791  error ("dblist: must be inside a user function to use dblist\n");
792 
793  bool have_file = true;
794 
795  std::string name = dbg_fcn->fcn_file_name ();
796 
797  if (name.empty ())
798  {
799  have_file = false;
800  name = dbg_fcn->name ();
801  }
802 
803  int l = tw.debug_user_code_line ();
804 
805  if (l > 0)
806  {
807  if (have_file)
808  {
809  int l_min = std::max (l - n/2, 0);
810  int l_max = l + n/2;
811  do_dbtype (octave_stdout, name, l_min, l-1);
812 
813  std::string line = dbg_fcn->get_code_line (l);
814 
815  if (! line.empty ())
816  octave_stdout << l << "-->\t" << line << std::endl;
817 
818  do_dbtype (octave_stdout, name, l+1, l_max);
819  }
820  }
821  else
822  {
823  octave_stdout << "dblist: unable to determine source code line"
824  << std::endl;
825  }
826 
827  return ovl ();
828 }
829 
830 static octave_value_list
832  int nargout, std::ostream& os)
833 {
834  int nargin = args.length ();
835 
836  if (nargin > 2)
837  print_usage ();
838 
840 
842 
843  octave_idx_type curr_frame = -1;
844 
845  size_t nskip = 0;
846 
847  if (nargin == 1 || nargin == 2)
848  {
849  int n = 0;
850 
851  for (octave_idx_type i = 0; i < nargin; i++)
852  {
853  octave_value arg = args(i);
854 
855  if (arg.is_string ())
856  {
857  std::string s_arg = arg.string_value ();
858 
859  // Skip "-completenames", octave returns full names anyway.
860  if (s_arg == "-completenames")
861  continue;
862 
863  n = atoi (s_arg.c_str ());
864  }
865  else
866  n = arg.int_value ();
867 
868  if (n <= 0)
869  error ("dbstack: N must be a non-negative integer");
870  }
871 
872  if (n > 0)
873  nskip = n;
874  }
875 
876  octave::tree_evaluator& tw = interp.get_evaluator ();
877 
878  if (nargout == 0)
879  {
880  octave_map stk = tw.backtrace (curr_frame);
881  octave_idx_type nframes = stk.numel ();
882 
883  if (nframes > 0)
884  {
885  octave::preserve_stream_state stream_state (os);
886 
887  os << "stopped in:\n\n";
888 
889  Cell names = stk.contents ("name");
890  Cell files = stk.contents ("file");
891  Cell lines = stk.contents ("line");
892 
893  bool show_top_level = true;
894 
895  size_t max_name_len = 0;
896 
897  for (octave_idx_type i = nskip; i < nframes; i++)
898  {
899  std::string name = names(i).string_value ();
900 
901  max_name_len = std::max (name.length (), max_name_len);
902  }
903 
904  for (octave_idx_type i = nskip; i < nframes; i++)
905  {
906  std::string name = names(i).string_value ();
907  std::string file = files(i).string_value ();
908  int line = lines(i).int_value ();
909 
910  if (show_top_level && i == curr_frame)
911  show_top_level = false;
912 
913  os << (i == curr_frame ? " --> " : " ")
914  << std::setw (max_name_len) << name
915  << " at line " << line
916  << " [" << file << ']'
917  << std::endl;
918  }
919 
920  if (tw.at_top_level () && show_top_level)
921  os << " --> top level" << std::endl;
922  }
923  }
924  else
925  {
926  octave_map stk = tw.backtrace (curr_frame, false);
927 
928  // If current stack frame is not in the list curr_frame will be
929  // -1 and either nskip caused us to skip it or we are at the top
930  // level, which is not included in the list of frames. So in the
931  // interpreter, 0 will be our invalid frame index value.
932 
933  retval = ovl (stk, curr_frame + 1);
934  }
935 
936  return retval;
937 }
938 
939 // A function that can be easily called from a debugger print the Octave stack.
940 // This can be useful for finding what line of code the interpreter is
941 // currently executing when the debugger is stopped in some C++ function,
942 // for example.
943 
944 void
946 {
947  do_dbstack (octave::__get_interpreter__ ("show_octave_dbstack"),
948  octave_value_list (), 0, std::cerr);
949 }
950 
951 DEFMETHOD (dbstack, interp, args, nargout,
952  doc: /* -*- texinfo -*-
953 @deftypefn {} {} dbstack
954 @deftypefnx {} {} dbstack @var{n}
955 @deftypefnx {} {} dbstack @var{-completenames}
956 @deftypefnx {} {[@var{stack}, @var{idx}] =} dbstack (@dots{})
957 Display or return current debugging function stack information.
958 
959 With optional argument @var{n}, omit the @var{n} innermost stack frames.
960 
961 Although accepted, the argument @var{-completenames} is silently ignored.
962 Octave always returns absolute filenames.
963 
964 The arguments @var{n} and @var{-completenames} can be both specified in any
965 order.
966 
967 The optional return argument @var{stack} is a struct array with the
968 following fields:
969 
970 @table @asis
971 @item file
972 The name of the m-file where the function code is located.
973 
974 @item name
975 The name of the function with a breakpoint.
976 
977 @item line
978 The line number of an active breakpoint.
979 
980 @item column
981 The column number of the line where the breakpoint begins.
982 
983 @item scope
984 Undocumented.
985 
986 @item context
987 Undocumented.
988 @end table
989 
990 The return argument @var{idx} specifies which element of the @var{stack}
991 struct array is currently active.
992 @seealso{dbup, dbdown, dbwhere, dblist, dbstatus}
993 @end deftypefn */)
994 {
995  return do_dbstack (interp, args, nargout, octave_stdout);
996 }
997 
998 static void
1000  const std::string& who)
1001 {
1002  int n = 1;
1003 
1004  if (args.length () == 1)
1005  {
1006  octave_value arg = args(0);
1007 
1008  if (arg.is_string ())
1009  {
1010  std::string s_arg = arg.string_value ();
1011 
1012  n = atoi (s_arg.c_str ());
1013  }
1014  else
1015  n = args(0).int_value ();
1016  }
1017 
1018  if (who == "dbup")
1019  n = -n;
1020 
1021  octave::tree_evaluator& tw = interp.get_evaluator ();
1022 
1023  tw.dbupdown (n, true);
1024 }
1025 
1026 DEFMETHOD (dbup, interp, args, ,
1027  doc: /* -*- texinfo -*-
1028 @deftypefn {} {} dbup
1029 @deftypefnx {} {} dbup @var{n}
1030 In debugging mode, move up the execution stack @var{n} frames.
1031 
1032 If @var{n} is omitted, move up one frame.
1033 @seealso{dbstack, dbdown}
1034 @end deftypefn */)
1035 {
1036  do_dbupdown (interp, args, "dbup");
1037 
1038  return ovl ();
1039 }
1040 
1041 DEFMETHOD (dbdown, interp, args, ,
1042  doc: /* -*- texinfo -*-
1043 @deftypefn {} {} dbdown
1044 @deftypefnx {} {} dbdown @var{n}
1045 In debugging mode, move down the execution stack @var{n} frames.
1046 
1047 If @var{n} is omitted, move down one frame.
1048 @seealso{dbstack, dbup}
1049 @end deftypefn */)
1050 {
1051  do_dbupdown (interp, args, "dbdown");
1052 
1053  return ovl ();
1054 }
1055 
1056 DEFMETHOD (dbstep, interp, args, ,
1057  doc: /* -*- texinfo -*-
1058 @deftypefn {} {} dbstep
1059 @deftypefnx {} {} dbstep @var{n}
1060 @deftypefnx {} {} dbstep in
1061 @deftypefnx {} {} dbstep out
1062 @deftypefnx {} {} dbnext @dots{}
1063 In debugging mode, execute the next @var{n} lines of code.
1064 
1065 If @var{n} is omitted, execute the next single line of code. If the next
1066 line of code is itself defined in terms of an m-file remain in the existing
1067 function.
1068 
1069 Using @code{dbstep in} will cause execution of the next line to step into
1070 any m-files defined on the next line.
1071 
1072 Using @code{dbstep out} will cause execution to continue until the current
1073 function returns.
1074 
1075 @code{dbnext} is an alias for @code{dbstep}.
1076 @seealso{dbcont, dbquit}
1077 @end deftypefn */)
1078 {
1079  octave::tree_evaluator& tw = interp.get_evaluator ();
1080 
1081  if (! tw.in_debug_repl ())
1082  error ("dbstep: can only be called in debug mode");
1083 
1084  int nargin = args.length ();
1085 
1086  if (nargin > 1)
1087  print_usage ();
1088 
1089  int n = 0;
1090 
1091  if (nargin == 1)
1092  {
1093  std::string arg
1094  = args(0).xstring_value ("dbstep: input argument must be a string");
1095 
1096  if (arg == "in")
1097  n = -1;
1098  else if (arg == "out")
1099  n = -2;
1100  else
1101  {
1102  n = atoi (arg.c_str ());
1103 
1104  if (n < 1)
1105  error ("dbstep: invalid argument");
1106  }
1107  }
1108  else
1109  n = 1;
1110 
1111  if (n != 0)
1112  {
1113  tw.set_dbstep_flag (n);
1114 
1115  // If we set the dbstep flag, we also need to reset debug_mode.
1116  tw.reset_debug_state ();
1117 
1118  }
1119 
1120  return ovl ();
1121 }
1122 
1123 DEFALIAS (dbnext, dbstep);
1124 
1125 DEFMETHOD (dbcont, interp, args, ,
1126  doc: /* -*- texinfo -*-
1127 @deftypefn {} {} dbcont
1128 Leave command-line debugging mode and continue code execution normally.
1129 @seealso{dbstep, dbquit}
1130 @end deftypefn */)
1131 {
1132  octave::tree_evaluator& tw = interp.get_evaluator ();
1133 
1134  if (! tw.in_debug_repl ())
1135  error ("dbcont: can only be called in debug mode");
1136 
1137  if (args.length () != 0)
1138  print_usage ();
1139 
1140  tw.dbcont ();
1141 
1142  return ovl ();
1143 }
1144 
1145 DEFMETHOD (dbquit, interp, args, ,
1146  doc: /* -*- texinfo -*-
1147 @deftypefn {} {} dbquit
1148 @deftypefnx {} {} dbquit all
1149 Quit debugging mode immediately without further code execution. With no
1150 arguments, exit the current debugging level. With argument @code{all},
1151 exit all debugging levels and return to the Octave prompt.
1152 @seealso{dbcont, dbstep}
1153 @end deftypefn */)
1154 {
1155  octave::tree_evaluator& tw = interp.get_evaluator ();
1156 
1157  if (! tw.in_debug_repl ())
1158  error ("dbquit: can only be called in debug mode");
1159 
1160  int nargin = args.length ();
1161 
1162  if (nargin > 1)
1163  print_usage ();
1164 
1165  if (nargin == 1)
1166  {
1167  std::string arg
1168  = args(0).xstring_value ("dbquit: input argument must be a string");
1169 
1170  if (arg == "all")
1171  tw.dbquit (true);
1172  else
1173  error ("dbquit: unrecognized argument '%s'", arg.c_str ());
1174  }
1175  else
1176  tw.dbquit ();
1177 
1178  return ovl ();
1179 }
1180 
1181 DEFMETHOD (isdebugmode, interp, args, ,
1182  doc: /* -*- texinfo -*-
1183 @deftypefn {} {} isdebugmode ()
1184 Return true if in debugging mode, otherwise false.
1185 @seealso{dbwhere, dbstack, dbstatus}
1186 @end deftypefn */)
1187 {
1188  if (args.length () != 0)
1189  print_usage ();
1190 
1191  octave::tree_evaluator& tw = interp.get_evaluator ();
1192 
1193  return ovl (tw.in_debug_repl ());
1194 }
1195 
1196 DEFMETHOD (__db_next_breakpoint_quiet__, interp, args, ,
1197  doc: /* -*- texinfo -*-
1198 @deftypefn {} {} __db_next_breakpoint_quiet__ ()
1199 @deftypefnx {} {} __db_next_breakpoint_quiet__ (@var{flag})
1200 Disable line info printing at the next breakpoint.
1201 
1202 With a logical argument @var{flag}, set the state on or off.
1203 @end deftypefn */)
1204 {
1205  int nargin = args.length ();
1206 
1207  if (nargin > 1)
1208  print_usage ();
1209 
1210  bool state = true;
1211 
1212  if (nargin == 1)
1213  state = args(0).bool_value ();
1214 
1215  octave::tree_evaluator& tw = interp.get_evaluator ();
1216 
1218 
1219  return ovl ();
1220 }
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array.cc:1011
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
size_type size(const size_type d) const
Size of the specified dimension.
Definition: Array.h:442
Definition: Cell.h:43
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
void parse_dbfunction_params(const char *who, const octave_value_list &args, std::string &func_name, std::string &class_name, bp_table::intmap &lines, std::string &cond)
Definition: bp-table.cc:282
octave_map stop_on_err_warn_status(bool to_screen)
Definition: bp-table.cc:901
fname_bp_map get_breakpoint_list(const octave_value_list &fname_list)
Definition: bp-table.cc:826
int remove_breakpoint(const std::string &fname="", const intmap &lines=intmap())
Definition: bp-table.cc:708
void dbstop_process_map_args(const octave_map &mv)
Definition: bp-table.cc:80
std::map< std::string, std::list< bp_type > > fname_bp_map
Definition: bp-table.h:75
void dbclear_all_signals(void)
Definition: bp-table.cc:60
intmap add_breakpoint(const std::string &fname="", const std::string &class_name="", const intmap &lines=intmap(), const std::string &condition="")
Definition: bp-table.cc:615
intmap::const_iterator const_intmap_iterator
Definition: bp-table.h:67
void remove_all_breakpoints(void)
Definition: bp-table.cc:794
std::map< int, int > intmap
Definition: bp-table.h:65
std::string which(const std::string &name) const
tree_evaluator & get_evaluator(void)
octave_user_code * get_user_code(const std::string &fname="", const std::string &class_name="")
Definition: pt-eval.cc:2253
bool at_top_level(void) const
Definition: pt-eval.cc:394
int debug_user_code_line(void) const
Definition: pt-eval.cc:1875
bool in_debug_repl(void) const
Definition: pt-eval.cc:4076
bool quiet_breakpoint_flag(void) const
Definition: pt-eval.h:589
bp_table & get_bp_table(void)
Definition: pt-eval.h:372
void dbquit(bool all=false)
Definition: pt-eval.cc:4088
void set_dbstep_flag(int step)
Definition: pt-eval.h:719
void dbupdown(int n, bool verbose=false)
Definition: pt-eval.cc:847
void reset_debug_state(void)
Definition: pt-eval.cc:778
void debug_where(std::ostream &os) const
Definition: pt-eval.cc:1885
octave_map backtrace(octave_idx_type &curr_user_frame, bool print_subfn=true) const
Definition: pt-eval.cc:1984
std::string name(void) const
Definition: ov-fcn.h:214
Cell getfield(const std::string &key) const
Definition: oct-map.cc:275
bool isfield(const std::string &name) const
Definition: oct-map.h:347
void setfield(const std::string &key, const Cell &val)
Definition: oct-map.cc:282
octave_idx_type numel(void) const
Definition: oct-map.h:389
void assign(const std::string &k, const Cell &val)
Definition: oct-map.h:365
const_iterator begin(void) const
Definition: oct-map.h:318
const_iterator end(void) const
Definition: oct-map.h:319
const Cell & contents(const_iterator p) const
Definition: oct-map.h:331
bool isempty(void) const
Definition: oct-map.h:391
std::string get_code_line(size_t line)
Definition: ov-usr-fcn.cc:101
std::string fcn_file_name(void) const
Definition: ov-usr-fcn.h:110
octave_idx_type length(void) const
Definition: ovl.h:113
bool iscell(void) const
Definition: ov.h:560
int int_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:765
bool is_string(void) const
Definition: ov.h:593
Cell cell_value(void) const
std::string string_value(bool force=false) const
Definition: ov.h:927
bool isempty(void) const
Definition: ov.h:557
static octave_value_list do_dbstack(octave::interpreter &interp, const octave_value_list &args, int nargout, std::ostream &os)
Definition: debug.cc:831
static octave_value intmap_to_ov(const octave::bp_table::intmap &line)
Definition: debug.cc:63
void show_octave_dbstack(void)
Definition: debug.cc:945
static void do_dbtype(std::ostream &os, const std::string &name, int start, int end)
Definition: debug.cc:577
static void do_dbupdown(octave::interpreter &interp, const octave_value_list &args, const std::string &who)
Definition: debug.cc:999
OCTINTERP_API void print_usage(void)
Definition: defun.cc:53
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition: defun.h:138
#define DEFALIAS(alias, name)
Macro to define an alias for another existing function name.
Definition: defun.h:214
void error(const char *fmt,...)
Definition: error.cc:968
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:166
QString name
F77_RET_T const F77_DBLE const F77_DBLE * f
T octave_idx_type m
Definition: mx-inlines.cc:773
octave_idx_type n
Definition: mx-inlines.cc:753
std::string canonicalize_file_name(const std::string &name)
Definition: file-ops.cc:693
std::ifstream ifstream(const std::string &filename, const std::ios::openmode mode)
Definition: lo-sysdep.cc:381
static uint32_t state[624]
Definition: randmtzig.cc:190
interpreter & __get_interpreter__(const std::string &who)
std::string fcn_file_in_path(const std::string &name)
Definition: utils.cc:592
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
#define octave_stdout
Definition: pager.h:313