26#if defined (HAVE_CONFIG_H)
66 : m_ok (false), m_file (file), m_dir (), m_fcn (), m_class_name ()
68 std::string abs_file = sys::env::make_absolute (file);
70 std::string dir = sys::file_ops::dirname (abs_file);
71 std::string fcn = sys::file_ops::tail (abs_file);
72 std::size_t
len = fcn.length ();
73 if (
len >= 2 && fcn[
len-2] ==
'.' && fcn[
len-1] ==
'm')
74 fcn = fcn.substr (0,
len-2);
76 std::size_t pos = dir.rfind (sys::file_ops::dir_sep_chars ());
78 if (pos != std::string::npos && pos < dir.length () - 1)
80 if (dir[pos+1] ==
'@')
82 m_class_name = dir.substr (pos+1);
84 fcn = sys::file_ops::concat (m_class_name, fcn);
86 dir = dir.substr (0, pos);
101 std::string file ()
const {
return m_file; }
102 std::string dir ()
const {
return m_fcn; }
103 std::string fcn ()
const {
return m_fcn; }
104 std::string class_name ()
const {
return m_class_name; }
106 bool ok ()
const {
return m_ok; }
114 std::string m_class_name;
126 bp_table::m_errors_that_stop.clear ();
129 bp_table::m_caught_that_stop.clear ();
132 bp_table::m_warnings_that_stop.clear ();
151 fail = (U.
numel () > 1);
157 else if (! W(0).iscell ())
161 Cell V = W(0).cell_value ();
162 for (
int i = 0; i <
V.numel (); i++)
164 m_errors_that_stop.insert (
V(i).string_value ());
171 error (
"dbstop: invalid 'errs' field");
178 fail = (U.
numel () > 1);
184 else if (! W(0).iscell ())
188 Cell V = W(0).cell_value ();
189 for (
int i = 0; i <
V.numel (); i++)
191 m_caught_that_stop.insert (
V(i).string_value ());
198 error (
"dbstop: invalid 'caught' field");
205 fail = (U.
numel () > 1);
211 else if (! W(0).iscell ())
215 Cell V = W(0).cell_value ();
216 for (
int i = 0; i <
V.numel (); i++)
218 m_warnings_that_stop.insert (
V(i).string_value ());
225 error (
"dbstop: invalid 'warn' field");
238 const std::string& fcn_ident,
240 const std::string& condition,
257 for (
auto& lineno : retval)
265 const char *s = strchr (fcn_ident.c_str (),
'>');
267 m_bp_set.insert (fcn_ident.substr (0, s - fcn_ident.c_str ()));
269 m_bp_set.insert (fcn_ident);
288 if (cond.length () > 0)
295 error (
"dbstop: Cannot parse condition '%s'", cond.c_str ());
300 std::shared_ptr<tree_statement_list> stmt_list
305 "condition is not empty, but has nothing to evaluate");
308 if (stmt_list->size () == 1
309 && (stmt = stmt_list->front ())
314 error (
"dbstop: condition cannot be an assignment. "
315 "Did you mean '=='?");
318 error (
"dbstop: condition must be an expression");
349 std::string& fcn_name,
350 std::string& class_name,
354 int nargin = args.
length ();
359 if (nargin == 0 || ! args(0).is_string ())
363 bool seen_in =
false;
364 bool seen_at =
false;
365 bool seen_if =
false;
371 if (args(pos).is_string ())
376 std::string arg = args(pos).string_value ();
382 else if (arg ==
"at")
387 else if (arg ==
"if")
396 if (std::stoi (args(pos).string_value ()) > 0)
399 catch (
const std::invalid_argument&) { }
400 catch (
const std::out_of_range&) { }
407 error (
"%s: '%s' missing argument", who,
409 ?
"in" : (tok ==
dbstop_at ?
"at" :
"if")));
415 fcn_name = args(pos).string_value ();
417 error (
"%s: Too many function names specified -- %s",
418 who, fcn_name.c_str ());
419 else if (seen_at || seen_if)
420 error (
"%s: function name must come before line number and 'if'",
428 error (
"%s: Only one 'at' clause is allowed -- %s",
429 who, args(pos).string_value ().c_str ());
431 error (
"%s: line number must come before 'if' clause\n", who);
435 error (
"%s: line number must come before 'if' clause\n", who);
438 std::string arg = args(pos).string_value ();
445 bool int_conv_ok =
true;
449 if (std::stoi (arg) == 0)
452 catch (
const std::invalid_argument&)
456 catch (
const std::out_of_range&)
466 class_name = fcn_name;
479 error (
"%s: function name must come before line number "
485 for ( ; pos < nargin; pos++)
487 if (args(pos).is_string ())
489 std::string str = args(pos).string_value ();
493 int line = std::stoi (str);
500 catch (
const std::invalid_argument&)
504 catch (
const std::out_of_range&)
506 error (
"dbstop: location value out of range '%s'", str.c_str ());
509 else if (args(pos).isnumeric ())
514 lines.
insert (
static_cast<int> (arg.
elem (j)));
517 error (
"%s: Invalid argument type %s",
518 who, args(pos).type_name ().c_str ());
526 for (; pos < nargin; pos++)
528 if (args(pos).is_string ())
529 cond +=
' ' + args(pos).string_value ();
531 error (
"%s: arguments to 'if' must all be strings", who);
534 cond = cond.substr (1);
538 std::string condition = args(pos).string_value ();
539 bool on_off = !
strcmp (who,
"dbstop");
544 if (condition ==
"error")
545 process_id_list (who, condition, args, nargin, pos, on_off,
547 else if (condition ==
"warning")
548 process_id_list (who, condition, args, nargin, pos, on_off,
549 m_warnings_that_stop);
550 else if (condition ==
"caught" && nargin > pos+1
551 && args(pos+1).string_value () ==
"error")
554 process_id_list (who, condition, args, nargin, pos, on_off,
557 else if (condition ==
"interrupt")
561 else if (condition ==
"naninf")
563#if defined (DBSTOP_NANINF)
564 Vdebug_on_naninf = on_off;
567 warning (
"%s: condition '%s' not yet supported",
568 who, condition.c_str ());
572 error (
"%s: invalid condition %s",
573 who, condition.c_str ());
612bp_table::set_stop_flag (
const char *who,
const std::string& condition,
618 if (condition ==
"error")
620 else if (condition ==
"warning")
622 else if (condition ==
"caught")
625 error (
"%s: internal error in set_stop_flag", who);
629bp_table::process_id_list (
const char *who,
630 const std::string& condition,
632 int nargin,
int& pos,
bool on_off,
633 std::set<std::string>& id_list)
639 if (! args(pos).is_string () || nargin > pos+1)
640 error (
"%s: ID must be a single string", who);
643 id_list.insert (args(pos).string_value ());
644 set_stop_flag (who, condition,
true);
648 id_list.erase (args(pos).string_value ());
649 if (id_list.empty ())
650 set_stop_flag (who, condition,
false);
656 set_stop_flag (who, condition, on_off);
658 if (condition ==
"error")
671find_fcn_by_line (
octave_user_code *main_fcn,
int lineno,
int *found_end_line =
nullptr)
677 int earliest_end = std::numeric_limits<int>::max ();
679 std::map<std::string, octave_value> subfcns = main_fcn->
subfunctions ();
680 for (
const auto& str_val_p : subfcns)
682 if (str_val_p.second.is_user_function ())
684 auto *dbg_subfcn = str_val_p.second.user_function_value ();
692 filepos beg_pos = dbg_subfcn->beg_pos ();
693 filepos end_pos = dbg_subfcn->end_pos ();
695 int beginning_line = beg_pos.
line ();
696 int ending_line = end_pos.
line ();
698 if (ending_line < earliest_end && ending_line >= lineno && beginning_line <= lineno)
700 earliest_end = ending_line;
701 retval = find_fcn_by_line (dbg_subfcn, lineno, &earliest_end);
706 if (beginning_line >= lineno && ! next_fcn)
707 next_fcn = dbg_subfcn;
717 int ending_line = end_pos.
line ();
719 if (ending_line >= lineno && ending_line < earliest_end)
731 if (found_end_line && earliest_end < *found_end_line)
732 *found_end_line = earliest_end;
742 const std::string& condition)
745 line_info.insert (line);
750 return result.empty () ? 0 : *(result.begin ());
757class user_code_provider
760 user_code_provider (
const std::string& who,
const std::string& fcn_ident,
762 : m_fcn (nullptr), m_is_valid (false)
765 if (m_fcn && ! (m_fcn->is_classdef_method ()
766 || m_fcn->is_classdef_constructor ()))
777 std::string class_name = fcn_ident;
778 const char *s = strchr (fcn_ident.c_str (),
'/');
779 if (s && fcn_ident[0] ==
'@')
780 class_name = fcn_ident.substr (1, s - fcn_ident.c_str () - 1);
783 m_is_valid = m_cls.ok () && (m_cls.get_name () == class_name);
785 populate_function_cache ();
787 error (
"%s: unable to find function '%s'\n", who.c_str (),
798 return find_fcn_by_line (m_fcn, line);
810 bool is_function ()
const {
return m_fcn; }
812 bool is_valid ()
const {
return m_is_valid; }
814 size_t number_of_functions ()
const
822 return m_methods_cache.
size ();
833 if (i < m_methods_cache.size ())
834 return m_methods_cache[i];
840 void populate_function_cache ()
842 if (m_methods_cache.empty ())
845 const std::map<std::string, cdef_method>& map
846 = m_cls.get_method_map (
false,
true);
847 for (
const auto& meth : map)
852 m_methods_cache.push_back (fcn);
856 const std::map<property_key, cdef_property>& prop_map
858 for (
const auto& prop : prop_map)
866 m_methods_cache.push_back (fcn);
875 m_methods_cache.push_back (fcn);
882 std::vector<octave_user_code *> m_methods_cache;
893 const std::string& condition)
895 user_code_provider user_code (
"add_breakpoints_in_function", fcn_ident,
902 for (
const auto& lineno : lines)
907 error (
"add_breakpoints_in_function: unable to find function '%s'\n",
912 line_info.insert (lineno);
916 std::string ident = fcn_ident;
917 if (! user_code.is_function () && fcn_ident[0] !=
'@')
920 ident =
"@" + fcn_ident +
"/" + dbg_fcn->
name ();
923 if (add_breakpoint_1 (dbg_fcn, ident, line_info, condition, ret_one))
925 if (! ret_one.empty ())
927 int line = *(ret_one.begin ());
930 retval.insert (line);
943 const std::string& condition)
948 bp_file_info info (m_evaluator, file);
953 std::string fcn_ident;
954 if (info.class_name ().empty () || info.fcn ()[0] ==
'@')
955 fcn_ident = info.fcn ();
957 fcn_ident =
"@" + info.class_name () +
"/" + info.fcn ();
965 const std::string& condition)
970 bp_file_info info (m_evaluator, file);
975 std::string fcn_ident;
976 if (info.class_name ().empty () || info.fcn ()[0] ==
'@')
977 fcn_ident = info.fcn ();
979 fcn_ident =
"@" + info.class_name () +
"/" + info.fcn ();
986 const std::string& fcn_ident,
1001 if (results.
length () > 0)
1007 for (
const auto& lineno : lines)
1011 if (! file.empty ())
1017 auto it = m_bp_set.find (fcn_ident);
1018 if (results.
empty () && it != m_bp_set.end ())
1019 m_bp_set.erase (it);
1022 retval = results.
length ();
1033 line_info.insert (line);
1047 retval = results.size ();
1052 user_code_provider user_code (
"remove_breakpoints_from_function",
1053 fcn_ident, dbg_fcn);
1056 for (
const auto line : lines)
1066 if (results.
length () > 0)
1073 if (! file.empty ())
1080 if (dbg_fcn !=
nullptr)
1083 const std::list<std::string> subfcn_names
1086 std::map<std::string, octave_value> subfcns
1089 for (
const auto& subf_nm : subfcn_names)
1091 const auto q = subfcns.find (subf_nm);
1093 if (q != subfcns.end ())
1098 retval += remove_breakpoint_1 (dbg_subfcn, fcn_ident, lines);
1104 const bool no_breakpoints
1106 auto iter = m_bp_set.find (fcn_ident);
1107 if (no_breakpoints && iter != m_bp_set.end ())
1108 m_bp_set.erase (iter);
1125 user_code_provider user_code (
"remove_all_breakpoints_from_function",
1126 fcn_ident, fcn, silent);
1128 if (user_code.is_valid ())
1130 for (
size_t i = 0; i != user_code.number_of_functions (); ++i)
1147 auto it = m_bp_set.find (fcn_ident);
1148 if (it != m_bp_set.end ())
1149 m_bp_set.erase (it);
1163 bp_file_info info (m_evaluator, file);
1178 bp_file_info info (m_evaluator, file);
1193 bp_file_info info (m_evaluator, file);
1206 for (
auto it = m_bp_set.cbegin (), it_next = it;
1207 it != m_bp_set.cend ();
1222 for (
int i = 0; i < slist.
length (); i++)
1224 if (slist(i).string_value () == match)
1226 retval = slist(i).string_value ();
1240 std::set<std::string> tmp_bp_set = m_bp_set;
1242 for (
auto& bp_fname : tmp_bp_set)
1244 if (fname_list.
empty ()
1248 user_code_provider user_code (
"get_breakpoint_list", bp_fname,
1251 std::list<bp_type> all_bkpts;
1252 std::list<bp_type>::iterator it (all_bkpts.begin ());
1253 for (
size_t i = 0; i != user_code.number_of_functions (); ++i)
1263 const std::list<bp_type>& bp
1266 it = all_bkpts.insert (it, bp.cbegin (),
1272 if (! all_bkpts.empty ())
1273 retval[bp_fname] = all_bkpts;
1277 if (dbg_fcn !=
nullptr)
1279 const std::list<std::string> subf_nm
1282 std::map<std::string, octave_value> subfcns
1285 for (
const auto& subfcn_nm : subf_nm)
1287 const auto q = subfcns.find (subfcn_nm);
1289 if (q != subfcns.end ())
1297 std::list<bp_type> bkpts
1300 if (! bkpts.empty ())
1303 = bp_fname +
'>' + dbg_subfcn->
name ();
1305 retval[key] = bkpts;
1336 if (m_errors_that_stop.empty ())
1345 Cell errs (
dim_vector (bp_table::m_errors_that_stop.size (), 1));
1348 for (
const auto& e : m_errors_that_stop)
1363 if (m_caught_that_stop.empty ())
1375 for (
const auto& e : m_caught_that_stop)
1390 if (m_warnings_that_stop.empty ())
1402 for (
const auto& w : m_warnings_that_stop)
1426OCTAVE_END_NAMESPACE(octave)
std::string find_bkpt_list(octave_value_list slist, std::string match)
cdef_class lookup_class(const std::string &name, bool error_if_not_found, bool load_if_not_found)
N Dimensional Array with copy-on-write semantics.
T & elem(octave_idx_type n)
Size of the specified dimension.
Array< T, Alloc > & insert(const Array< T, Alloc > &a, const Array< octave_idx_type > &idx)
Insert an array into another at a specified position.
bool isempty() const
Size of the specified dimension.
octave_idx_type numel() const
Number of elements in the array.
Cell index(const octave_value_list &idx, bool resize_ok=false) const
void statement_list(std::shared_ptr< tree_statement_list > &lst)
bool condition_valid(const std::string &cond)
int remove_breakpoint_from_function(const std::string &fcn_ident="", int line=1)
int remove_breakpoint_from_file(const std::string &file="", int line=1)
void remove_all_breakpoints()
bp_lines remove_all_breakpoints_from_function(const std::string &fcn_ident, bool silent=false)
fname_bp_map get_breakpoint_list(const octave_value_list &fname_list)
int remove_breakpoints_from_file(const std::string &file="", const bp_lines &lines=bp_lines())
int remove_breakpoints_from_function(const std::string &fcn_ident="", const bp_lines &lines=bp_lines())
int add_breakpoint_in_function(const std::string &fcn_ident="", int line=1, const std::string &condition="")
bp_lines add_breakpoints_in_function(const std::string &fcn_ident="", const bp_lines &lines=bp_lines(), const std::string &condition="")
void dbstop_process_map_args(const octave_map &mv)
int add_breakpoint_in_file(const std::string &file="", int line=1, const std::string &condition="")
std::map< std::string, std::list< bp_type > > fname_bp_map
bp_lines add_breakpoints_in_file(const std::string &file="", const bp_lines &lines=bp_lines(), const std::string &condition="")
bp_lines remove_all_breakpoints_from_file(const std::string &file, bool silent=false)
void dbclear_all_signals()
octave_map stop_on_err_warn_status(bool to_screen)
void parse_dbfunction_params(const char *who, const octave_value_list &args, std::string &fcn_name, std::string &class_name, bp_table::bp_lines &lines, std::string &cond)
Vector representing the dimensions (size) of an Array.
octave_value debug_on_warning(const octave_value_list &args, int nargout)
octave_value debug_on_caught(const octave_value_list &args, int nargout)
octave_value debug_on_error(const octave_value_list &args, int nargout)
Provides threadsafe access to octave.
void update_breakpoint(bool insert, const std::string &file, int line, const std::string &cond="")
error_system & get_error_system()
load_path & get_load_path()
event_manager & get_event_manager()
bool contains_file_in_dir(const std::string &file_name, const std::string &dir_name)
virtual bool is_user_function() const
virtual octave_user_code * user_code_value(bool silent=false)
virtual std::string profiler_name() const
virtual std::list< std::string > subfunction_names() const
const Cell & contents(const_iterator p) const
bool isfield(const std::string &name) const
void assign(const std::string &k, const Cell &val)
std::string fcn_file_name() const
virtual std::map< std::string, octave_value > subfunctions() const
octave::tree_statement_list * body()
octave_user_code * user_code_value(bool=false)
Array< octave_value > array_value() const
octave_idx_type length() const
bool is_function_handle() const
octave_user_function * user_function_value(bool silent=false) const
octave_user_code * user_code_value(bool silent=false) const
interpreter & get_interpreter()
bool in_debug_repl() const
octave_user_code * get_user_code(const std::string &fname="")
virtual bool is_assignment_expression() const
octave_value_list list_breakpoints()
std::list< bp_type > breakpoints_and_conds()
void delete_breakpoint(int line)
bp_table::bp_lines remove_all_breakpoints(event_manager &evmgr, const std::string &file)
bp_table::bp_lines add_breakpoint(event_manager &evmgr, const std::string &file, const bp_table::bp_lines &lines, const std::string &condition)
tree_expression * expression()
bool is_expression() const
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void warning(const char *fmt,...)
void error(const char *fmt,...)
F77_RET_T const F77_INT const F77_INT const F77_INT const F77_DBLE const F77_DBLE F77_INT F77_DBLE * V
bool strcmp(const T &str_a, const T &str_b)
Octave string utility functions.