3805
|
1 /* |
|
2 |
7017
|
3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Ben Sapp |
3805
|
4 |
|
5 This file is part of Octave. |
|
6 |
|
7 Octave is free software; you can redistribute it and/or modify it |
|
8 under the terms of the GNU General Public License as published by the |
7016
|
9 Free Software Foundation; either version 3 of the License, or (at your |
|
10 option) any later version. |
3805
|
11 |
|
12 Octave is distributed in the hope that it will be useful, but WITHOUT |
|
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
15 for more details. |
|
16 |
|
17 You should have received a copy of the GNU General Public License |
7016
|
18 along with Octave; see the file COPYING. If not, see |
|
19 <http://www.gnu.org/licenses/>. |
3805
|
20 |
|
21 */ |
|
22 #ifdef HAVE_CONFIG_H |
|
23 #include <config.h> |
|
24 #endif |
|
25 |
3895
|
26 #include <iostream> |
|
27 #include <fstream> |
3948
|
28 #include <string> |
7082
|
29 #include <set> |
|
30 |
3895
|
31 |
3805
|
32 #include "defun.h" |
|
33 #include "error.h" |
7082
|
34 #include "help.h" |
3805
|
35 #include "input.h" |
|
36 #include "pager.h" |
|
37 #include "oct-obj.h" |
|
38 #include "utils.h" |
|
39 #include "parse.h" |
|
40 #include "symtab.h" |
|
41 #include "gripes.h" |
|
42 #include "ov.h" |
|
43 #include "ov-usr-fcn.h" |
|
44 #include "ov-fcn.h" |
7082
|
45 #include "ov-list.h" |
|
46 #include "ov-struct.h" |
3805
|
47 #include "pt-pr-code.h" |
|
48 #include "pt.h" |
|
49 #include "pt-bp.h" |
|
50 #include "pt-stmt.h" |
|
51 #include "toplev.h" |
|
52 #include "unwind-prot.h" |
|
53 #include "variables.h" |
|
54 |
7082
|
55 #include "debug.h" |
|
56 |
|
57 // Initialize the singleton object |
7083
|
58 bp_table *bp_table::instance = 0; |
7082
|
59 |
5743
|
60 // Return a pointer to the user-defined function FNAME. If FNAME is |
|
61 // empty, search backward for the first user-defined function in the |
|
62 // current call stack. |
7083
|
63 |
3949
|
64 static octave_user_function * |
7083
|
65 get_user_function (const std::string& fname = std::string ()) |
3805
|
66 { |
3956
|
67 octave_user_function *dbg_fcn = 0; |
3805
|
68 |
7083
|
69 if (fname.empty ()) |
5744
|
70 dbg_fcn = octave_call_stack::caller_user_function (); |
5743
|
71 else |
3805
|
72 { |
5743
|
73 symbol_record *ptr = curr_sym_tab->lookup (fname); |
3946
|
74 |
3805
|
75 if (ptr && ptr->is_user_function ()) |
|
76 { |
|
77 octave_value tmp = ptr->def (); |
4346
|
78 dbg_fcn = dynamic_cast<octave_user_function *> (tmp.function_value ()); |
3805
|
79 } |
|
80 else |
|
81 { |
5743
|
82 ptr = lookup_by_name (fname, false); |
7083
|
83 |
3805
|
84 if (ptr && ptr->is_user_function ()) |
|
85 { |
|
86 octave_value tmp = ptr->def (); |
4346
|
87 dbg_fcn = dynamic_cast<octave_user_function *> (tmp.function_value ()); |
3805
|
88 } |
|
89 } |
|
90 } |
|
91 |
|
92 return dbg_fcn; |
|
93 } |
|
94 |
7082
|
95 static void |
|
96 parse_dbfunction_params (const octave_value_list& args, |
|
97 std::string& symbol_name, |
7083
|
98 bp_table::intmap& lines) |
7082
|
99 { |
|
100 octave_idx_type len = 0; |
|
101 int nargin = args.length (); |
|
102 int idx = 0; |
|
103 int list_idx = 0; |
|
104 symbol_name = std::string (); |
|
105 |
7083
|
106 // If we are already in a debugging function. |
|
107 if (octave_call_stack::caller_user_function ()) |
|
108 idx = 0; |
7082
|
109 else |
|
110 { |
|
111 symbol_name = args (0).string_value (); |
|
112 if (error_state) |
|
113 return; |
|
114 idx = 1; |
|
115 } |
|
116 |
|
117 for (int i = idx; i < nargin; i++ ) |
|
118 { |
|
119 if (args (i).is_string ()) |
7083
|
120 len++; |
7082
|
121 else |
|
122 len += args (i).numel (); |
|
123 } |
|
124 |
7083
|
125 lines = bp_table::intmap (); |
7082
|
126 for (int i = idx; i < nargin; i++ ) |
|
127 { |
|
128 if (args (i).is_string ()) |
|
129 { |
7083
|
130 int line = atoi (args(i).string_value().c_str ()); |
7082
|
131 if (error_state) |
7083
|
132 break; |
7082
|
133 lines[list_idx++] = line; |
|
134 } |
|
135 else |
|
136 { |
7083
|
137 const NDArray arg = args(i).array_value (); |
7082
|
138 |
|
139 if (error_state) |
|
140 break; |
|
141 |
7083
|
142 for (octave_idx_type j = 0; j < arg.nelem (); j++) |
7082
|
143 { |
|
144 int line = static_cast<int> (arg.elem (j)); |
|
145 if (error_state) |
|
146 break; |
|
147 lines[list_idx++] = line; |
|
148 } |
|
149 |
|
150 if (error_state) |
|
151 break; |
|
152 } |
|
153 } |
|
154 } |
|
155 |
7083
|
156 bp_table::intmap |
|
157 bp_table::do_add_breakpoint (const std::string& fname, |
|
158 const bp_table::intmap& line) |
7082
|
159 { |
7083
|
160 intmap retval; |
7082
|
161 |
|
162 octave_idx_type len = line.size (); |
7083
|
163 |
7082
|
164 octave_user_function *dbg_fcn = get_user_function (fname); |
|
165 |
|
166 if (dbg_fcn) |
|
167 { |
|
168 tree_statement_list *cmds = dbg_fcn->body (); |
7083
|
169 |
7082
|
170 for (int i = 0; i < len; i++) |
|
171 { |
7083
|
172 const_intmap_iterator p = line.find (i); |
|
173 |
7082
|
174 if (p != line.end ()) |
|
175 { |
|
176 int lineno = p->second; |
7083
|
177 |
7082
|
178 retval[i] = cmds->set_breakpoint (lineno); |
7083
|
179 |
7082
|
180 if (retval[i] != 0) |
7083
|
181 bp_map[fname] = dbg_fcn; |
7082
|
182 } |
|
183 } |
|
184 } |
|
185 else |
|
186 error ("add_breakpoint: unable to find the function requested\n"); |
|
187 |
|
188 return retval; |
|
189 } |
|
190 |
|
191 |
|
192 int |
7083
|
193 bp_table::do_remove_breakpoint (const std::string& fname, |
|
194 const bp_table::intmap& line) |
7082
|
195 { |
7083
|
196 int retval = 0; |
7082
|
197 |
|
198 octave_idx_type len = line.size (); |
|
199 |
|
200 if (len == 0) |
|
201 { |
|
202 intmap results = remove_all_breakpoints_in_file (fname); |
|
203 retval = results.size (); |
|
204 } |
|
205 else |
|
206 { |
|
207 octave_user_function *dbg_fcn = get_user_function (fname); |
|
208 if (dbg_fcn) |
|
209 { |
|
210 tree_statement_list *cmds = dbg_fcn->body (); |
|
211 for (int i = 0; i < len; i++) |
|
212 { |
7083
|
213 const_intmap_iterator p = line.find (i); |
|
214 |
7082
|
215 if (p != line.end ()) |
7083
|
216 cmds->delete_breakpoint (p->second); |
7082
|
217 } |
7083
|
218 |
7082
|
219 octave_value_list results = cmds->list_breakpoints (); |
7083
|
220 |
7082
|
221 if (results.length () == 0) |
7083
|
222 bp_map.erase (bp_map.find (fname)); |
|
223 |
7082
|
224 retval = results.length (); |
|
225 } |
|
226 else |
|
227 error ("remove_breakpoint: unable to find the function requested\n"); |
|
228 } |
|
229 return retval; |
|
230 } |
|
231 |
|
232 |
7083
|
233 bp_table::intmap |
|
234 bp_table::do_remove_all_breakpoints_in_file (const std::string& fname) |
7082
|
235 { |
7083
|
236 intmap retval; |
7082
|
237 |
|
238 octave_user_function *dbg_fcn = get_user_function (fname); |
|
239 |
|
240 if (dbg_fcn) |
|
241 { |
|
242 tree_statement_list *cmds = dbg_fcn->body (); |
7083
|
243 |
|
244 octave_value_list bkpts = cmds->list_breakpoints (); |
|
245 |
7082
|
246 for (int i = 0; i < bkpts.length (); i++) |
|
247 { |
7083
|
248 int lineno = static_cast<int> (bkpts(i).int_value ()); |
7082
|
249 cmds->delete_breakpoint (lineno); |
|
250 retval[i] = lineno; |
|
251 } |
7083
|
252 |
|
253 bp_map.erase (bp_map.find (fname)); |
7082
|
254 } |
|
255 else |
|
256 error ("remove_all_breakpoint_in_file: " |
|
257 "unable to find the function requested\n"); |
|
258 |
|
259 return retval; |
|
260 } |
|
261 |
|
262 void |
7083
|
263 bp_table::do_remove_all_breakpoints (void) |
7082
|
264 { |
7083
|
265 for (const_breakpoint_map_iterator it = bp_map.begin (); |
|
266 it != bp_map.end (); it++) |
|
267 remove_all_breakpoints_in_file (it->first); |
7082
|
268 } |
|
269 |
|
270 std::string |
|
271 do_find_bkpt_list (octave_value_list slist, |
|
272 std::string match) |
|
273 { |
|
274 std::string retval; |
7083
|
275 |
7082
|
276 for (int i = 0; i < slist.length (); i++) |
|
277 { |
|
278 if (slist (i).string_value () == match) |
|
279 { |
7083
|
280 retval = slist(i).string_value (); |
7082
|
281 break; |
|
282 } |
|
283 } |
|
284 return retval; |
|
285 } |
|
286 |
|
287 |
7083
|
288 bp_table::fname_line_map |
|
289 bp_table::do_get_breakpoint_list (const octave_value_list& fname_list) |
7082
|
290 { |
7083
|
291 fname_line_map retval; |
7082
|
292 |
|
293 // Iterate through each of the files in the map and get the |
7083
|
294 // name and list of breakpoints. |
|
295 |
|
296 for (breakpoint_map_iterator it = bp_map.begin (); it != bp_map.end (); it++) |
7082
|
297 { |
7083
|
298 if (fname_list.length () == 0 |
|
299 || do_find_bkpt_list (fname_list, it->first) != "") |
7082
|
300 { |
|
301 octave_value_list bkpts = it->second->body ()->list_breakpoints (); |
7083
|
302 |
7082
|
303 octave_idx_type len = bkpts.length (); |
7083
|
304 |
|
305 bp_table::intmap bkpts_vec; |
|
306 |
7082
|
307 for (int i = 0; i < len; i++) |
|
308 bkpts_vec[i] = bkpts (i).double_value (); |
7083
|
309 |
|
310 retval[it->first] = bkpts_vec; |
7082
|
311 } |
|
312 } |
7083
|
313 |
7082
|
314 return retval; |
|
315 } |
|
316 |
|
317 static octave_value |
7083
|
318 intmap_to_ov (const bp_table::intmap& line) |
7082
|
319 { |
|
320 int idx = 0; |
7083
|
321 |
|
322 NDArray retval (dim_vector (1, line.size ())); |
|
323 |
|
324 for (size_t i = 0; i < line.size (); i++) |
7082
|
325 { |
7083
|
326 bp_table::const_intmap_iterator p = line.find (i); |
|
327 |
7082
|
328 if (p != line.end ()) |
|
329 { |
|
330 int lineno = p->second; |
7083
|
331 retval(idx++) = lineno; |
7082
|
332 } |
|
333 } |
7083
|
334 |
7082
|
335 retval.resize (dim_vector (1, idx)); |
7083
|
336 |
7082
|
337 return retval; |
|
338 } |
3895
|
339 |
4208
|
340 DEFCMD (dbstop, args, , |
3805
|
341 "-*- texinfo -*-\n\ |
7083
|
342 @deftypefn {Loadable Function} {rline =} dbstop (@var{func}, @var{line}, @dots{})\n\ |
3805
|
343 Set a breakpoint in a function\n\ |
|
344 @table @code\n\ |
|
345 @item func\n\ |
|
346 String representing the function name. When already in debug\n\ |
|
347 mode this should be left out and only the line should be given.\n\ |
|
348 @item line\n\ |
6646
|
349 Line you would like the breakpoint to be set on. Multiple\n\ |
7001
|
350 lines might be given as separate arguments or as a vector.\n\ |
3805
|
351 @end table\n\ |
|
352 \n\ |
|
353 The rline returned is the real line that the breakpoint was set at.\n\ |
5642
|
354 @seealso{dbclear, dbstatus, dbnext}\n\ |
|
355 @end deftypefn") |
3805
|
356 { |
7083
|
357 bp_table::intmap retval; |
|
358 std::string symbol_name; |
|
359 bp_table::intmap lines; |
|
360 |
7082
|
361 parse_dbfunction_params (args, symbol_name, lines); |
6646
|
362 |
7083
|
363 if (! error_state) |
7082
|
364 retval = bp_table::add_breakpoint (symbol_name, lines); |
3805
|
365 |
7083
|
366 return intmap_to_ov (retval); |
3805
|
367 } |
|
368 |
4208
|
369 DEFCMD (dbclear, args, , |
3805
|
370 "-*- texinfo -*-\n\ |
7083
|
371 @deftypefn {Loadable Function} {} dbclear (@var{func}, @var{line}, @dots{})\n\ |
3805
|
372 Delete a breakpoint in a function\n\ |
|
373 @table @code\n\ |
|
374 @item func\n\ |
|
375 String representing the function name. When already in debug\n\ |
|
376 mode this should be left out and only the line should be given.\n\ |
|
377 @item line\n\ |
6653
|
378 Line where you would like to remove the breakpoint. Multiple\n\ |
7001
|
379 lines might be given as separate arguments or as a vector.\n\ |
3805
|
380 @end table\n\ |
|
381 No checking is done to make sure that the line you requested is really\n\ |
6646
|
382 a breakpoint. If you get the wrong line nothing will happen.\n\ |
5642
|
383 @seealso{dbstop, dbstatus, dbwhere}\n\ |
|
384 @end deftypefn") |
3805
|
385 { |
|
386 octave_value retval; |
|
387 std::string symbol_name = ""; |
7083
|
388 bp_table::intmap lines; |
|
389 |
7082
|
390 parse_dbfunction_params (args, symbol_name, lines); |
|
391 |
7083
|
392 if (! error_state) |
7082
|
393 bp_table::remove_breakpoint (symbol_name, lines); |
3805
|
394 |
|
395 return retval; |
|
396 } |
|
397 |
7082
|
398 DEFCMD (dbstatus, args, nargout, |
3805
|
399 "-*- texinfo -*-\n\ |
7083
|
400 @deftypefn {Loadable Function} {lst =} dbstatus (@var{func})\n\ |
3805
|
401 Return a vector containing the lines on which a function has \n\ |
|
402 breakpoints set.\n\ |
|
403 @table @code\n\ |
|
404 @item func\n\ |
|
405 String representing the function name. When already in debug\n\ |
|
406 mode this should be left out.\n\ |
|
407 @end table\n\ |
5642
|
408 @seealso{dbclear, dbwhere}\n\ |
|
409 @end deftypefn") |
3805
|
410 { |
7082
|
411 Octave_map retval; |
3805
|
412 int nargin = args.length (); |
7082
|
413 octave_value_list fcn_list; |
7083
|
414 bp_table::fname_line_map bp_list; |
|
415 std::string symbol_name; |
3805
|
416 |
|
417 if (nargin != 0 && nargin != 1) |
|
418 { |
3948
|
419 error ("dbstatus: only zero or one arguements accepted\n"); |
7082
|
420 return octave_value (); |
3805
|
421 } |
|
422 |
|
423 if (nargin == 1) |
|
424 { |
|
425 if (args(0).is_string ()) |
7082
|
426 { |
7083
|
427 symbol_name = args(0).string_value (); |
|
428 fcn_list(0) = symbol_name; |
7082
|
429 bp_list = bp_table::get_breakpoint_list (fcn_list); |
|
430 } |
3805
|
431 else |
7083
|
432 gripe_wrong_type_arg ("dbstatus", args(0)); |
7082
|
433 } |
|
434 else |
|
435 { |
|
436 octave_user_function *dbg_fcn = get_user_function (); |
|
437 if (dbg_fcn) |
|
438 { |
|
439 symbol_name = dbg_fcn->name (); |
7083
|
440 fcn_list(0) = symbol_name; |
7082
|
441 } |
7083
|
442 |
7082
|
443 bp_list = bp_table::get_breakpoint_list (fcn_list); |
3805
|
444 } |
|
445 |
7083
|
446 if (nargout == 0) |
3805
|
447 { |
7083
|
448 // Print out the breakpoint information. |
|
449 |
|
450 for (bp_table::fname_line_map_iterator it = bp_list.begin (); |
|
451 it != bp_list.end (); it++) |
|
452 { |
|
453 octave_stdout << "Breakpoint in " << it->first << " at line(s) "; |
|
454 |
|
455 bp_table::intmap m = it->second; |
|
456 |
|
457 size_t nel = m.size (); |
|
458 |
|
459 for (size_t j = 0; j < nel; j++) |
|
460 octave_stdout << m[j] << ((j < nel - 1) ? ", " : "."); |
|
461 |
|
462 if (nel > 0) |
|
463 octave_stdout << std::endl; |
|
464 } |
|
465 return octave_value (); |
|
466 } |
|
467 else |
|
468 { |
|
469 // Fill in an array for return. |
|
470 |
7082
|
471 int i = 0; |
|
472 Cell names (dim_vector (bp_list.size (), 1)); |
|
473 Cell file (dim_vector (bp_list.size (), 1)); |
|
474 Cell line (dim_vector (bp_list.size (), 1)); |
7083
|
475 |
|
476 for (bp_table::const_fname_line_map_iterator it = bp_list.begin (); |
|
477 it != bp_list.end (); it++) |
3946
|
478 { |
7083
|
479 names(i) = it->first; |
|
480 line(i) = intmap_to_ov (it->second); |
|
481 file(i) = do_which (it->first); |
7082
|
482 i++; |
3805
|
483 } |
7083
|
484 |
7082
|
485 retval.assign ("name", names); |
|
486 retval.assign ("file", file); |
|
487 retval.assign ("line", line); |
7083
|
488 |
7082
|
489 return octave_value (retval); |
3805
|
490 } |
|
491 } |
|
492 |
4208
|
493 DEFCMD (dbwhere, , , |
3805
|
494 "-*- texinfo -*-\n\ |
3895
|
495 @deftypefn {Loadable Function} {} dbwhere ()\n\ |
3805
|
496 Show where we are in the code\n\ |
5642
|
497 @seealso{dbclear, dbstatus, dbstop}\n\ |
5645
|
498 @end deftypefn") |
3805
|
499 { |
|
500 octave_value retval; |
3946
|
501 |
5743
|
502 octave_user_function *dbg_fcn = get_user_function (); |
3805
|
503 |
|
504 if (dbg_fcn) |
|
505 { |
4748
|
506 std::string name = dbg_fcn->name (); |
3805
|
507 |
|
508 octave_stdout << name << ":"; |
|
509 |
|
510 const tree *dbg_stmt = tree::break_statement; |
|
511 |
|
512 if (dbg_stmt) |
|
513 { |
7083
|
514 octave_stdout << " line " << dbg_stmt->line () << ", "; |
3805
|
515 octave_stdout << "column " << dbg_stmt->column () << std::endl; |
|
516 } |
|
517 else |
7083
|
518 octave_stdout << " (unknown line)\n"; |
3805
|
519 } |
|
520 else |
3948
|
521 error ("dbwhere: must be inside of a user function to use dbwhere\n"); |
3895
|
522 |
|
523 return retval; |
|
524 } |
|
525 |
|
526 // Copied and modified from the do_type command in help.cc |
3946
|
527 // Maybe we could share some code? |
|
528 void |
3949
|
529 do_dbtype (std::ostream& os, const std::string& name, int start, int end) |
3895
|
530 { |
|
531 std::string ff = fcn_file_in_path (name); |
|
532 |
|
533 if (! ff.empty ()) |
|
534 { |
|
535 std::ifstream fs (ff.c_str (), std::ios::in); |
3946
|
536 |
3895
|
537 if (fs) |
3946
|
538 { |
3895
|
539 char ch; |
|
540 int line = 1; |
3946
|
541 |
3895
|
542 if (line >= start && line <= end) |
|
543 os << line << "\t"; |
3946
|
544 |
3895
|
545 while (fs.get (ch)) |
|
546 { |
|
547 if (line >= start && line <= end) |
|
548 { |
|
549 os << ch; |
|
550 } |
|
551 |
|
552 if (ch == '\n') |
|
553 { |
|
554 line++; |
|
555 if (line >= start && line <= end) |
3946
|
556 os << line << "\t"; |
3895
|
557 } |
|
558 } |
|
559 } |
3946
|
560 else |
3949
|
561 os << "dbtype: unable to open `" << ff << "' for reading!\n"; |
3895
|
562 } |
|
563 else |
6317
|
564 os << "dbtype: unknown function " << name << "\n"; |
3895
|
565 |
6646
|
566 os.flush (); |
3895
|
567 } |
|
568 |
4208
|
569 DEFCMD (dbtype, args, , |
3895
|
570 "-*- texinfo -*-\n\ |
|
571 @deftypefn {Loadable Function} {} dbtype ()\n\ |
|
572 List script file with line numbers.\n\ |
5642
|
573 @seealso{dbclear, dbstatus, dbstop}\n\ |
|
574 @end deftypefn") |
3895
|
575 { |
|
576 octave_value retval; |
|
577 octave_user_function *dbg_fcn; |
3946
|
578 |
3895
|
579 int nargin = args.length (); |
|
580 string_vector argv = args.make_argv ("dbtype"); |
3946
|
581 |
3895
|
582 if (! error_state) |
|
583 { |
|
584 switch (nargin) |
|
585 { |
|
586 case 0: // dbtype |
|
587 dbg_fcn = get_user_function (); |
|
588 |
|
589 if (dbg_fcn) |
4748
|
590 do_dbtype (octave_stdout, dbg_fcn->name (), 0, INT_MAX); |
3895
|
591 else |
3948
|
592 error ("dbtype: must be in a user function to give no arguments to dbtype\n"); |
3946
|
593 break; |
3895
|
594 |
3946
|
595 case 1: // (dbtype func) || (dbtype start:end) |
3948
|
596 dbg_fcn = get_user_function (argv[1]); |
3895
|
597 |
|
598 if (dbg_fcn) |
4748
|
599 do_dbtype (octave_stdout, dbg_fcn->name (), 0, INT_MAX); |
3895
|
600 else |
|
601 { |
7083
|
602 dbg_fcn = get_user_function (); |
3895
|
603 |
|
604 if (dbg_fcn) |
|
605 { |
3948
|
606 std::string arg = argv[1]; |
|
607 |
|
608 size_t ind = arg.find (':'); |
3895
|
609 |
3948
|
610 if (ind != NPOS) |
|
611 { |
|
612 std::string start_str = arg.substr (0, ind); |
|
613 std::string end_str = arg.substr (ind + 1); |
|
614 |
|
615 int start = atoi (start_str.c_str ()); |
|
616 int end = atoi (end_str.c_str ()); |
3946
|
617 |
6317
|
618 if (std::min (start, end) <= 0) |
|
619 error ("dbtype: start and end lines must be >= 1\n"); |
|
620 |
|
621 if (start <= end) |
|
622 do_dbtype (octave_stdout, dbg_fcn->name (), start, end); |
3948
|
623 else |
6317
|
624 error ("dbtype: start line must be less than end line\n"); |
3895
|
625 } |
3948
|
626 else |
6317
|
627 error ("dbtype: line specification must be `start:end'"); |
3895
|
628 } |
|
629 } |
|
630 break; |
3946
|
631 |
6317
|
632 case 2: // (dbtype func start:end) , (dbtype func start) |
3948
|
633 dbg_fcn = get_user_function (argv[1]); |
3895
|
634 |
|
635 if (dbg_fcn) |
|
636 { |
3948
|
637 std::string arg = argv[2]; |
6317
|
638 int start = 0; |
|
639 int end = 0; |
3948
|
640 size_t ind = arg.find (':'); |
3895
|
641 |
3948
|
642 if (ind != NPOS) |
3895
|
643 { |
3948
|
644 std::string start_str = arg.substr (0, ind); |
|
645 std::string end_str = arg.substr (ind + 1); |
3895
|
646 |
6317
|
647 start = atoi (start_str.c_str ()); |
|
648 end = atoi (end_str.c_str ()); |
|
649 |
3948
|
650 } |
|
651 else |
6317
|
652 { |
|
653 start = atoi (arg.c_str ()); |
|
654 end = start; |
|
655 } |
|
656 |
|
657 if (std::min (start, end) <= 0) |
|
658 error ("dbtype: start and end lines must be >= 1\n"); |
|
659 |
|
660 if (start <= end) |
|
661 do_dbtype (octave_stdout, dbg_fcn->name (), start, end); |
|
662 else |
|
663 error ("dbtype: start line must be less than end line\n"); |
3895
|
664 } |
3946
|
665 break; |
3895
|
666 |
|
667 default: |
3948
|
668 error ("dbtype: expecting zero, one, or two arguments\n"); |
3895
|
669 } |
|
670 } |
3805
|
671 |
|
672 return retval; |
|
673 } |
|
674 |
|
675 /* |
|
676 ;;; Local Variables: *** |
|
677 ;;; mode: C++ *** |
|
678 ;;; End: *** |
|
679 */ |