GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
bp-table.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2001-2018 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
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License 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 <https://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if defined (HAVE_CONFIG_H)
25 # include "config.h"
26 #endif
27 
28 #include <algorithm>
29 #include <fstream>
30 #include <limits>
31 #include <list>
32 #include <map>
33 #include <set>
34 #include <string>
35 #include <sstream>
36 #include <iostream>
37 
38 #include "file-ops.h"
39 
40 #include "bp-table.h"
41 #include "defun-int.h"
42 #include "call-stack.h"
43 #include "error.h"
44 #include "interpreter-private.h"
45 #include "oct-map.h"
46 #include "octave-link.h"
47 #include "ov-usr-fcn.h"
48 #include "ov.h"
49 #include "ovl.h"
50 #include "pager.h"
51 #include "parse.h"
52 #include "pt-eval.h"
53 #include "pt-exp.h"
54 #include "pt-stmt.h"
55 #include "sighandlers.h"
56 #include "symtab.h"
57 
58 namespace octave
59 {
60  // Clear all reasons to stop, other than breakpoints.
61 
63  {
64  Vdebug_on_error = false;
66 
67  Vdebug_on_caught = false;
69 
70  Vdebug_on_warning = false;
72 
74  }
75 
76  // Process the "warn", "errs", "caught" and "intr" fields for a call of
77  // "dbstop (p)".
78 
80  {
81  // process errs
82  // why so many levels of indirection needed?
83  bool fail = false;
84  Cell U = mv.contents ("errs");
85  if (U.numel () != 1)
86  fail = (U.numel () > 1);
87  else
88  {
89  Array<octave_value> W = U.index (static_cast<octave_idx_type> (0));
90  if (W.isempty () || W(0).isempty ())
91  Vdebug_on_error = 1; // like "dbstop if error" with no identifier
92  else if (! W(0).iscell ())
93  fail = true;
94  else
95  {
96  Cell V = W(0).cell_value ();
97  for (int i = 0; i < V.numel (); i++)
98  {
99  m_errors_that_stop.insert (V(i).string_value ());
100  Vdebug_on_error = 1;
101  }
102  }
103  }
104  if (fail)
105  error ("dbstop: invalid 'errs' field");
106 
107  // process caught
108  // why so many levels of indirection needed?
109  fail = false;
110  U = mv.contents ("caught");
111  if (U.numel () != 1)
112  fail = (U.numel () > 1);
113  else
114  {
115  Array<octave_value> W = U.index (static_cast<octave_idx_type> (0));
116  if (W.isempty () || W(0).isempty ())
117  Vdebug_on_caught = 1; // like "dbstop if caught error" with no ID
118  else if (! W(0).iscell ())
119  fail = true;
120  else
121  {
122  Cell V = W(0).cell_value ();
123  for (int i = 0; i < V.numel (); i++)
124  {
125  m_caught_that_stop.insert (V(i).string_value ());
126  Vdebug_on_caught = 1;
127  }
128  }
129  }
130  if (fail)
131  error ("dbstop: invalid 'caught' field");
132 
133  // process warn
134  // why so many levels of indirection needed?
135  fail = false;
136  U = mv.contents ("warn");
137  if (U.numel () != 1)
138  fail = (U.numel () > 1);
139  else
140  {
141  Array<octave_value> W = U.index (static_cast<octave_idx_type> (0));
142  if (W.isempty () || W(0).isempty ())
143  Vdebug_on_warning = 1; // like "dbstop if warning" with no identifier
144  else if (! W(0).iscell ())
145  fail = true;
146  else
147  {
148  Cell V = W(0).cell_value ();
149  for (int i = 0; i < V.numel (); i++)
150  {
151  m_warnings_that_stop.insert (V(i).string_value ());
152  Vdebug_on_warning = 1;
153  }
154  }
155  }
156  if (fail)
157  error ("dbstop: invalid 'warn' field");
158 
159  // process interrupt
160  if (mv.isfield ("intr"))
162  }
163 
164  // Insert a breakpoint in function fcn at line within file fname,
165  // to stop only when condition is true.
166  // Record in m_bp_set that fname contains a breakpoint.
167 
169  const std::string& fname,
170  const bp_table::intmap& line,
171  const std::string& condition,
173  {
174  bool found = false;
175 
176  octave::tree_statement_list *cmds = fcn->body ();
177 
179 
180  if (cmds)
181  {
182  retval = cmds->add_breakpoint (file, line, condition);
183 
184  for (auto& idx_line_p : retval)
185  {
186  if (idx_line_p.second != 0)
187  {
188  // Normalize to store only the file name.
189  // Otherwise, there can be an entry for both
190  // file>subfunction and file, which causes a crash on
191  // dbclear all
192  const char *s = strchr (fname.c_str (), '>');
193  if (s)
194  m_bp_set.insert (fname.substr (0, s - fname.c_str ()));
195  else
196  m_bp_set.insert (fname);
197  found = true;
198  break;
199  }
200  }
201  }
202 
203  return found;
204  }
205 
206  // Cursory check that cond is a valid condition to use for a breakpoint.
207  // Currently allows conditions with side-effects, like 'y+=10' and 'y++';
208  // it is odd that the former is not flagged by "is_assignment_expression".
209  // Throws an exception if not valid.
210 
212  {
213  if (cond.length () > 0)
214  {
215  octave::parser parser (cond + " ;"); // ; to reject partial expr like "y=="
216  parser.reset ();
217  int parse_status = parser.run ();
218  if (parse_status)
219  error ("dbstop: Cannot parse condition '%s'", cond.c_str ());
220  else
221  {
222  octave::tree_statement *stmt = nullptr;
223  if (! parser.m_stmt_list)
224  error ("dbstop: "
225  "condition is not empty, but has nothing to evaluate");
226  else
227  {
228  if (parser.m_stmt_list->length () == 1
229  && (stmt = parser.m_stmt_list->front ())
230  && stmt->is_expression ())
231  {
232  octave::tree_expression *expr = stmt->expression ();
233  if (expr->is_assignment_expression ())
234  error ("dbstop: condition cannot be an assignment. "
235  "Did you mean '=='?");
236  }
237  else
238  error ("dbstop: condition must be an expression");
239  }
240  }
241  }
242  return true;
243  }
244 
246  {
251  };
252 
253  // Parse parameters (args) of dbstop and dbclear commands.
254  // For dbstop, who=="dbstop"; for dbclear, who=="dbclear".
255  // The syntax is: dbstop [[in] symbol] [[at] line [line [...]]] [if condition]
256  // where the form of condition depends on whether or not a file or line has
257  // been seen.
258  // Also execute "if [error|warning|interrupt|naninf]" clauses.
259 
260  void bp_table::parse_dbfunction_params (const char *who,
261  const octave_value_list& args,
262  std::string& symbol_name,
263  bp_table::intmap& lines,
264  std::string& cond)
265  {
266  int nargin = args.length ();
267  int list_idx = 0;
268  symbol_name = "";
269  lines = bp_table::intmap ();
270 
271  if (nargin == 0 || ! args(0).is_string ())
272  print_usage (who);
273 
274  // elements already processed
275  bool seen_in = false, seen_at = false, seen_if = false;
276  int pos = 0;
277  dbstop_args tok = dbstop_none;
278  while (pos < nargin)
279  {
280  // allow "in" and "at" to be implicit
281  if (args(pos).is_string ())
282  {
283  std::string arg = args(pos).string_value ();
284  if (arg == "in")
285  {
286  tok = dbstop_in;
287  pos++;
288  }
289  else if (arg == "at")
290  {
291  tok = dbstop_at;
292  pos++;
293  }
294  else if (arg == "if")
295  {
296  tok = dbstop_if;
297  pos++;
298  }
299  else if (atoi (args(pos).string_value ().c_str ()) > 0)
300  tok = dbstop_at;
301  else
302  tok = dbstop_in;
303  }
304  else
305  tok = dbstop_at;
306 
307  if (pos >= nargin)
308  error ("%s: '%s' missing argument", who,
309  (tok == dbstop_in
310  ? "in" : (tok == dbstop_at ? "at" : "if")));
311 
312  // process the actual arguments
313  switch (tok)
314  {
315  case dbstop_in:
316  symbol_name = args(pos).string_value ();
317  if (seen_in)
318  error ("%s: Too many function names specified -- %s",
319  who, symbol_name.c_str ());
320  else if (seen_at || seen_if)
321  error ("%s: function name must come before line number and 'if'",
322  who);
323  seen_in = true;
324  pos++;
325  break;
326 
327  case dbstop_at:
328  if (seen_at)
329  error ("%s: Only one 'at' clause is allowed -- %s",
330  who, args(pos).string_value ().c_str ());
331  else if (seen_if)
332  error ("%s: line number must come before 'if' clause\n");
333  seen_at = true;
334 
335  if (! seen_in)
336  {
337  // It was a line number. Get function name from debugger.
338  if (Vdebugging)
339  symbol_name = get_user_code ()->profiler_name ();
340  else
341  error ("%s: function name must come before line number "
342  "and 'if'", who);
343  seen_in = true;
344  }
345  else if (seen_if)
346  error ("%s: line number must come before 'if' clause\n");
347 
348  // Read a list of line numbers (or arrays thereof)
349  for ( ; pos < nargin; pos++)
350  {
351  if (args(pos).is_string ())
352  {
353  int line = atoi (args(pos).string_value ().c_str ());
354 
355  if (line > 0)
356  lines[list_idx++] = line;
357  else
358  break; // may be "if"
359  }
360  else if (args(pos).isnumeric ())
361  {
362  const NDArray arg = args(pos).array_value ();
363 
364  for (octave_idx_type j = 0; j < arg.numel (); j++)
365  lines[list_idx++] = static_cast<int> (arg.elem (j));
366  }
367  else
368  error ("%s: Invalid argument type %s",
369  args(pos).type_name ().c_str ());
370  }
371  break;
372 
373  case dbstop_if:
374  if (seen_in) // conditional breakpoint
375  {
376  cond = ""; // remaining arguments form condition
377  for (; pos < nargin; pos++)
378  {
379  if (args(pos).is_string ())
380  cond += ' ' + args(pos).string_value ();
381  else
382  error ("%s: arguments to 'if' must all be strings", who);
383  }
384 
385  cond = cond.substr (1); // omit initial space
386  }
387  else // stop on event (error, warning, interrupt, NaN/inf)
388  {
389  std::string condition = args(pos).string_value ();
390  int on_off = ! strcmp(who, "dbstop");
391 
392  // list of error/warning IDs to update
393  std::set<std::string> *id_list = nullptr;
394  bool *stop_flag = nullptr; // Vdebug_on_... flag
395 
396  if (condition == "error")
397  {
398  id_list = &m_errors_that_stop;
399  stop_flag = &Vdebug_on_error;
400  }
401  else if (condition == "warning")
402  {
403  id_list = &m_warnings_that_stop;
404  stop_flag = &Vdebug_on_warning;
405  }
406  else if (condition == "caught" && nargin > pos+1
407  && args(pos+1).string_value () == "error")
408  {
409  id_list = &m_caught_that_stop;
410  stop_flag = &Vdebug_on_caught;
411  pos++;
412  }
413  else if (condition == "interrupt")
414  {
416  }
417  else if (condition == "naninf")
418  {
419 #if defined (DBSTOP_NANINF)
420  Vdebug_on_naninf = on_off;
421  enable_fpe (on_off);
422 #else
423  warning ("%s: condition '%s' not yet supported",
424  who, condition.c_str ());
425 #endif
426  }
427  else
428  error ("%s: invalid condition %s",
429  who, condition.c_str ());
430 
431  // process ID list for "dbstop if error <error_ID>" etc
432  if (id_list)
433  {
434  pos++;
435  if (pos < nargin) // only affect a single error ID
436  {
437  if (! args(pos).is_string () || nargin > pos+1)
438  error ("%s: ID must be a single string", who);
439  else if (on_off == 1)
440  {
441  id_list->insert (args(pos).string_value ());
442  *stop_flag = true;
443  }
444  else
445  {
446  id_list->erase (args(pos).string_value ());
447  if (id_list->empty ())
448  *stop_flag = false;
449  }
450  }
451  else // unqualified. Turn all on or off
452  {
453  id_list->clear ();
454  *stop_flag = on_off;
455  if (stop_flag == &Vdebug_on_error)
456  {
457  // Matlab stops on both.
459  }
460  }
461  }
462 
463  pos = nargin;
464  }
465  break;
466 
467  default: // dbstop_none should never occur
468  break;
469  }
470  }
471  }
472 
473  /*
474  %!test
475  %! dbclear all; # Clear out breakpoints before test
476  %! dbstop help;
477  %! dbstop in ls;
478  %! dbstop help at 100;
479  %! dbstop in ls 100;
480  %! dbstop help 201 if a==5;
481  %! dbstop if error Octave:undefined-function;
482  %! s = dbstatus;
483  %! dbclear all;
484  %! assert ({s.bkpt(:).name}, {"help", "help", "help>do_contents", "ls", "ls"});
485  %! assert ([s.bkpt(:).line], [48, 100, 201, 58, 100]);
486  %! assert (s.errs, {"Octave:undefined-function"});
487  */
488 
489  // Return the sub/nested/main function of MAIN_FCN that contains
490  // line number LINENO of the source file.
491  // If END_LINE != 0, *END_LINE is set to last line of the returned function.
492 
494  int lineno, int *end_line = nullptr)
495  {
496  octave_user_code *retval = nullptr;
497  octave_user_code *next_fcn = nullptr; // 1st function starting after lineno
498 
499  // Find innermost nested (or parent) function containing lineno.
500  int earliest_end = std::numeric_limits<int>::max ();
501 
502  std::map<std::string, octave_value> subfcns = main_fcn->subfunctions ();
503  for (const auto& str_val_p : subfcns)
504  {
505  if (str_val_p.second.is_user_function ())
506  {
507  auto *dbg_subfcn = str_val_p.second.user_function_value ();
508 
509  // Check if lineno is within dbg_subfcn.
510  // FIXME: we could break when beginning_line() > lineno,
511  // but that makes the code "fragile"
512  // if the order of walking subfcns changes,
513  // for a minor speed improvement in non-critical code.
514  if (dbg_subfcn->ending_line () < earliest_end
515  && dbg_subfcn->ending_line () >= lineno
516  && dbg_subfcn->beginning_line () <= lineno)
517  {
518  earliest_end = dbg_subfcn->ending_line ();
519  retval = find_fcn_by_line (dbg_subfcn, lineno, &earliest_end);
520  }
521 
522  // Find the first fcn starting after lineno.
523  // This is used if line is not inside any function.
524  if (dbg_subfcn->beginning_line () >= lineno && ! next_fcn)
525  next_fcn = dbg_subfcn;
526  }
527  }
528 
529  // The breakpoint is either in the subfunction found above,
530  // or in the main function, which we check now.
531  if (main_fcn->is_user_function ())
532  {
533  int e = dynamic_cast<octave_user_function *> (main_fcn)->ending_line ();
534  if (e >= lineno && e < earliest_end)
535  retval = main_fcn;
536 
537  if (! retval)
538  retval = next_fcn;
539  }
540  else // main_fcn is a script.
541  {
542  if (! retval)
543  retval = main_fcn;
544  }
545 
546  if (end_line && earliest_end < *end_line)
547  *end_line = earliest_end;
548 
549  return retval;
550  }
551 
552  // Given file name fname, find the subfunction at line and create
553  // a breakpoint there. Put the system into debug_mode.
555  const bp_table::intmap& line,
556  const std::string& condition)
557  {
558  octave_user_code *main_fcn = get_user_code (fname);
559 
560  if (! main_fcn)
561  error ("add_breakpoint: unable to find function '%s'\n", fname.c_str ());
562 
563  condition_valid (condition); // Throw error if condition not valid.
564 
565  intmap retval;
566 
567  octave_idx_type len = line.size ();
568 
569  for (int i = 0; i < len; i++)
570  {
571  const_intmap_iterator m = line.find (i);
572 
573  if (m != line.end ())
574  {
575  int lineno = m->second;
576 
577  octave_user_code *dbg_fcn = find_fcn_by_line (main_fcn, lineno);
578 
579  // We've found the right (sub)function. Now insert the breakpoint.
580  // We insert all breakpoints.
581  // If multiple are in the same function, we insert multiple times.
582  intmap ret_one;
583  if (dbg_fcn
584  && add_breakpoint_1 (dbg_fcn, fname, line, condition, ret_one))
585  retval.insert (std::pair<int,int> (i, ret_one.find (i)->second));
586  }
587  }
588 
590  || Vdebugging;
591 
592  return retval;
593  }
594 
596  const std::string& fname,
597  const bp_table::intmap& line)
598  {
599  int retval = 0;
600 
602 
603  octave::tree_statement_list *cmds = fcn->body ();
604 
605  // FIXME: move the operation on cmds to the tree_statement_list class?
606 
607  if (cmds)
608  {
609  octave_value_list results = cmds->list_breakpoints ();
610 
611  if (results.length () > 0)
612  {
613  octave_idx_type len = line.size ();
614 
615  for (int i = 0; i < len; i++)
616  {
617  const_intmap_iterator p = line.find (i);
618 
619  if (p != line.end ())
620  {
621  int lineno = p->second;
622 
623  cmds->delete_breakpoint (lineno);
624 
625  if (! file.empty ())
626  octave_link::update_breakpoint (false, file, lineno);
627  }
628  }
629 
630  results = cmds->list_breakpoints ();
631 
632  bp_set_iterator it = m_bp_set.find (fname);
633  if (results.empty () && it != m_bp_set.end ())
634  m_bp_set.erase (it);
635  }
636 
637  retval = results.length ();
638  }
639 
640  return retval;
641  }
642 
644  const bp_table::intmap& line)
645  {
646  int retval = 0;
647 
648  octave_idx_type len = line.size ();
649 
650  if (len == 0)
651  {
653  retval = results.size ();
654  }
655  else
656  {
657  octave_user_code *dbg_fcn = get_user_code (fname);
658 
659  if (! dbg_fcn)
660  error ("remove_breakpoint: unable to find function %s\n",
661  fname.c_str ());
662 
663  retval = remove_breakpoint_1 (dbg_fcn, fname, line);
664 
665  // Search subfunctions in the order they appear in the file.
666 
667  const std::list<std::string> subfcn_names
668  = dbg_fcn->subfunction_names ();
669 
670  std::map<std::string, octave_value> subfcns
671  = dbg_fcn->subfunctions ();
672 
673  for (const auto& subf_nm : subfcn_names)
674  {
675  const auto q = subfcns.find (subf_nm);
676 
677  if (q != subfcns.end ())
678  {
679  octave_user_code *dbg_subfcn = q->second.user_code_value ();
680 
681  retval += remove_breakpoint_1 (dbg_subfcn, fname, line);
682  }
683  }
684  }
685 
687  || Vdebugging;
688 
689  return retval;
690  }
691 
692  // Remove all breakpoints from a file, including those in subfunctions.
693 
696  bool silent)
697  {
698  intmap retval;
699 
700  octave_user_code *dbg_fcn = get_user_code (fname);
701 
702  if (dbg_fcn)
703  {
704  std::string file = dbg_fcn->fcn_file_name ();
705 
706  octave::tree_statement_list *cmds = dbg_fcn->body ();
707 
708  if (cmds)
709  {
711 
712  bp_set_iterator it = m_bp_set.find (fname);
713  if (it != m_bp_set.end ())
714  m_bp_set.erase (it);
715  }
716  }
717  else if (! silent)
718  error ("remove_all_breakpoint_in_file: "
719  "unable to find function %s\n", fname.c_str ());
720 
722  || Vdebugging;
723 
724  return retval;
725  }
726 
728  {
729  // Odd loop structure required because delete will invalidate m_bp_set iterators
730  for (const_bp_set_iterator it = m_bp_set.begin (), it_next = it;
731  it != m_bp_set.end ();
732  it = it_next)
733  {
734  ++it_next;
736  }
737 
739  || Vdebugging;
740  }
741 
743  {
745 
746  for (int i = 0; i < slist.length (); i++)
747  {
748  if (slist(i).string_value () == match)
749  {
750  retval = slist(i).string_value ();
751  break;
752  }
753  }
754 
755  return retval;
756  }
757 
760  {
762 
763  // make copy since changes may invalidate iters of m_bp_set.
764  std::set<std::string> tmp_bp_set = m_bp_set;
765 
766  for (auto& bp_fname : tmp_bp_set)
767  {
768  if (fname_list.empty ()
769  || find_bkpt_list (fname_list, bp_fname) != "")
770  {
771  octave_user_code *dbg_fcn = get_user_code (bp_fname);
772 
773  if (dbg_fcn)
774  {
775  octave::tree_statement_list *cmds = dbg_fcn->body ();
776 
777  // FIXME: move the operation on cmds to the
778  // tree_statement_list class?
779  if (cmds)
780  {
781  std::list<bp_type> bkpts = cmds->breakpoints_and_conds ();
782 
783  if (! bkpts.empty ())
784  retval[bp_fname] = bkpts;
785  }
786 
787  // look for breakpoints in subfunctions
788  const std::list<std::string> subf_nm
789  = dbg_fcn->subfunction_names ();
790 
791  std::map<std::string, octave_value> subfcns
792  = dbg_fcn->subfunctions ();
793 
794  for (const auto& subfcn_nm : subf_nm)
795  {
796  const auto q = subfcns.find (subfcn_nm);
797 
798  if (q != subfcns.end ())
799  {
800  octave_user_code *dbg_subfcn
801  = q->second.user_code_value ();
802 
803  cmds = dbg_subfcn->body ();
804  if (cmds)
805  {
806  std::list<bp_type> bkpts
807  = cmds->breakpoints_and_conds ();
808 
809  if (! bkpts.empty ())
810  {
811  std::string key
812  = bp_fname + '>' + dbg_subfcn->name ();
813 
814  retval[key] = bkpts;
815  }
816  }
817  }
818  }
819  }
820  }
821  }
822 
823  return retval;
824  }
825 
826  // Report the status of "dbstop if error ..." and "dbstop if warning ..."
827  // If to_screen is true, the output goes to octave_stdout; otherwise it is
828  // returned.
829  // If dbstop if error is true but no explicit IDs are specified, the return
830  // value will have an empty field called "errs". If IDs are specified, the
831  // "errs" field will have a row per ID. If dbstop if error is false, there
832  // is no "errs" field. The "warn" field is set similarly by dbstop if warning
833 
835  {
837 
838  // print dbstop if error information
839  if (Vdebug_on_error)
840  {
841  if (m_errors_that_stop.empty ())
842  {
843  if (to_screen)
844  octave_stdout << "stop if error\n";
845  else
846  retval.assign ("errs", octave_value(""));
847  }
848  else
849  {
850  Cell errs (dim_vector (bp_table::m_errors_that_stop.size (), 1));
851  int i = 0;
852 
853  for (const auto& e : m_errors_that_stop)
854  {
855  if (to_screen)
856  octave_stdout << "stop if error " << e << "\n";
857  else
858  errs(i++) = e;
859  }
860  if (! to_screen)
861  retval.assign ("errs", octave_value (errs));
862  }
863  }
864 
865  // print dbstop if caught error information
866  if (Vdebug_on_caught)
867  {
868  if (m_caught_that_stop.empty ())
869  {
870  if (to_screen)
871  octave_stdout << "stop if caught error\n";
872  else
873  retval.assign ("caught", octave_value(""));
874  }
875  else
876  {
877  Cell errs (dim_vector (m_caught_that_stop.size (), 1));
878  int i = 0;
879 
880  for (const auto& e : m_caught_that_stop)
881  {
882  if (to_screen)
883  octave_stdout << "stop if caught error " << e << "\n";
884  else
885  errs(i++) = e;
886  }
887  if (! to_screen)
888  retval.assign ("caught", octave_value (errs));
889  }
890  }
891 
892  // print dbstop if warning information
893  if (Vdebug_on_warning)
894  {
895  if (m_warnings_that_stop.empty ())
896  {
897  if (to_screen)
898  octave_stdout << "stop if warning\n";
899  else
900  retval.assign ("warn", octave_value(""));
901  }
902  else
903  {
904  Cell warn (dim_vector (m_warnings_that_stop.size (), 1));
905  int i = 0;
906 
907  for (const auto& w : m_warnings_that_stop)
908  {
909  if (to_screen)
910  octave_stdout << "stop if warning " << w << "\n";
911  else
912  warn(i++) = w;
913  }
914  if (! to_screen)
915  retval.assign ("warn", octave_value (warn));
916  }
917  }
918 
919  // print dbstop if interrupt information
921  {
922  if (to_screen)
923  octave_stdout << "stop if interrupt\n";
924  else
925  retval.assign ("intr", octave_value ());
926  }
927 
928  return retval;
929  }
930 
931  // Return a pointer to the user-defined function FNAME. If FNAME is empty,
932  // search backward for the first user-defined function in the
933  // current call stack.
934 
937  {
938  octave_user_code *dbg_fcn = nullptr;
939 
940  if (fname.empty ())
941  {
942  octave::call_stack& cs = octave::__get_call_stack__ ("get_user_code");
943 
944  dbg_fcn = cs.debug_user_code ();
945  }
946  else
947  {
949 
950  if (octave::sys::file_ops::dir_sep_char () != '/' && name[0] == '@')
951  {
952  auto beg = name.begin () + 2; // never have @/method
953  auto end = name.end () - 1; // never have trailing '/'
954  std::replace (beg, end, '/', octave::sys::file_ops::dir_sep_char ());
955  }
956 
957  size_t name_len = name.length ();
958 
959  if (name_len > 2 && name.substr (name_len-2) == ".m")
960  name = name.substr (0, name_len-2);
961 
962  octave::symbol_table& symtab =
963  octave::__get_symbol_table__ ("get_user_code");
964 
965  octave_value fcn = symtab.find_function (name);
966 
967  if (fcn.is_defined () && fcn.is_user_code ())
968  dbg_fcn = fcn.user_code_value ();
969  }
970 
971  return dbg_fcn;
972  }
973 }
virtual std::list< std::string > subfunction_names(void) const
Definition: ov-fcn.h:173
bool Vdebug_on_error
Definition: error.cc:62
virtual octave::tree_statement_list * body(void)=0
Cell index(const octave_value_list &idx, bool resize_ok=false) const
Definition: Cell.cc:152
virtual std::map< std::string, octave_value > subfunctions(void) const
Definition: ov-usr-fcn.cc:116
octave_value find_function(const std::string &name, const octave_value_list &args=octave_value_list(), bool local_funcs=true)
Definition: symtab.cc:412
std::set< std::string > m_warnings_that_stop
Definition: bp-table.h:139
F77_RET_T const F77_INT const F77_INT const F77_INT const F77_DBLE const F77_DBLE F77_INT F77_DBLE * V
virtual bool is_user_function(void) const
Definition: ov-base.h:473
Definition: Cell.h:37
For example cd octave end example noindent changes the current working directory to file
Definition: dirfns.cc:124
is already an absolute the name is checked against the file system instead of Octave s loadpath In this if otherwise an empty string is returned If the first argument is a cell array of search each directory of the loadpath for element of the cell array and return the first that matches If the second optional argument return a cell array containing the list of all files that have the same name in the path If no files are found
Definition: utils.cc:305
bool Vdebug_on_caught
Definition: error.cc:66
bool Vdebug_on_warning
Definition: error.cc:70
octave_user_code * get_user_code(const std::string &fname)
Definition: bp-table.cc:936
fname
Definition: load-save.cc:767
bp_table::intmap remove_all_breakpoints(const std::string &file)
Definition: pt-stmt.cc:270
octave_user_code * debug_user_code(void) const
Definition: call-stack.cc:244
bool isempty(void) const
Definition: Array.h:565
OCTINTERP_API void print_usage(void)
Definition: defun.cc:54
virtual bool is_user_code(void) const
Definition: ov-base.h:475
bool empty(void) const
Definition: ovl.h:98
tree_statement_list * m_stmt_list
Definition: parse.h:476
size_t length(void) const
Definition: base-list.h:50
intmap::const_iterator const_intmap_iterator
Definition: bp-table.h:62
void error(const char *fmt,...)
Definition: error.cc:578
char dir_sep_char(void)
Definition: file-ops.cc:224
void delete_breakpoint(int line)
Definition: pt-stmt.cc:187
octave_value_list list_breakpoints(void)
Definition: pt-stmt.cc:209
bool condition_valid(const std::string &cond)
Definition: bp-table.cc:211
std::map< std::string, std::list< bp_type > > fname_bp_map
Definition: bp-table.h:70
s
Definition: file-io.cc:2729
intmap add_breakpoint(const std::string &fname="", const intmap &lines=intmap(), const std::string &condition="")
Definition: bp-table.cc:554
i e
Definition: data.cc:2591
int remove_breakpoint(const std::string &fname="", const intmap &lines=intmap())
Definition: bp-table.cc:643
virtual std::string fcn_file_name(void) const
Definition: ov-fcn.h:74
std::set< std::string >::iterator bp_set_iterator
Definition: bp-table.h:129
OCTAVE_EXPORT octave_value_list isnumeric
Definition: data.cc:3157
octave_value arg
Definition: pr-output.cc:3244
std::set< std::string > m_caught_that_stop
Definition: bp-table.h:138
octave_function * fcn
Definition: ov-class.cc:1754
bool is_defined(void) const
Definition: ov-fcn.h:68
void dbclear_all_signals(void)
Definition: bp-table.cc:62
octave::call_stack & cs
Definition: ov-class.cc:1752
bool isfield(const std::string &name) const
Definition: oct-map.h:333
symbol_table & __get_symbol_table__(const std::string &who)
nd deftypefn *std::string name
Definition: sysdep.cc:647
octave_value & assign(assign_op op, const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
std::list< bp_type > breakpoints_and_conds(void)
Definition: pt-stmt.cc:219
std::set< std::string > m_errors_that_stop
Definition: bp-table.h:137
void parse_dbfunction_params(const char *, const octave_value_list &, std::string &, bp_table::intmap &, std::string &)
Definition: bp-table.cc:260
bool Vdebug_on_interrupt
Definition: sighandlers.cc:71
std::set< std::string > m_bp_set
Definition: bp-table.h:132
octave_idx_type numel(const octave_value_list &idx)
Definition: ov.h:412
std::string find_bkpt_list(octave_value_list slist, std::string match)
Definition: bp-table.cc:742
bool have_breakpoints(void)
Definition: bp-table.h:94
intmap remove_all_breakpoints_in_file(const std::string &fname, bool silent=false)
Definition: bp-table.cc:695
std::complex< double > w(std::complex< double > z, double relerr=0)
bool strcmp(const T &str_a, const T &str_b)
True if strings are the same.
Definition: oct-string.cc:112
Array< octave_value > array_value(void) const
Definition: ovl.h:86
octave_value retval
Definition: data.cc:6246
const Cell & contents(const_iterator p) const
Definition: oct-map.h:317
std::map< int, int > intmap
Definition: bp-table.h:60
static bool debug_mode
Definition: pt-eval.h:252
virtual octave_user_code * user_code_value(bool silent=false)
Definition: ov-base.cc:898
octave_map stop_on_err_warn_status(bool to_screen)
Definition: bp-table.cc:834
int remove_breakpoint_1(octave_user_code *fcn, const std::string &, const intmap &lines)
Definition: bp-table.cc:595
void warning(const char *fmt,...)
Definition: error.cc:801
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
void dbstop_process_map_args(const octave_map &mv)
Definition: bp-table.cc:79
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:227
fname_bp_map get_breakpoint_list(const octave_value_list &fname_list)
Definition: bp-table.cc:759
#define octave_stdout
Definition: pager.h:174
dbstop_args
Definition: bp-table.cc:245
p
Definition: lu.cc:138
void remove_all_breakpoints(void)
Definition: bp-table.cc:727
call_stack & __get_call_stack__(const std::string &who)
Matrix size(void)
Definition: ov.h:409
bp_table::intmap add_breakpoint(const std::string &file, const bp_table::intmap &line, const std::string &condition)
Definition: pt-stmt.cc:243
octave_idx_type length(void) const
Definition: ovl.h:96
elt_type & front(void)
Definition: base-list.h:97
args.length() nargin
Definition: file-io.cc:589
for i
Definition: data.cc:5264
bool add_breakpoint_1(octave_user_code *fcn, const std::string &fname, const intmap &line, const std::string &condition, intmap &retval)
Definition: bp-table.cc:168
std::set< std::string >::const_iterator const_bp_set_iterator
Definition: bp-table.h:128
virtual std::string profiler_name(void) const
Definition: ov-fcn.h:79
int run(void)
bool is_expression(void) const
Definition: pt-stmt.h:74
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:366
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
bool Vdebugging
Definition: input.cc:97
std::string name(void) const
Definition: ov-fcn.h:182
virtual bool is_assignment_expression(void) const
Definition: pt-exp.h:73
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
static octave_user_code * find_fcn_by_line(octave_user_code *main_fcn, int lineno, int *end_line=nullptr)
Definition: bp-table.cc:493
tree_expression * expression(void)
Definition: pt-stmt.h:92