line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
package DB ; |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
## |
5
|
|
|
|
|
|
|
## Expedient fix for perl 5.8.0. True DB::DB is further down. |
6
|
|
|
|
|
|
|
## |
7
|
|
|
|
|
|
|
## |
8
|
0
|
|
|
0
|
0
|
|
sub DB {} |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
2941
|
use Tk ; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# |
15
|
|
|
|
|
|
|
# If you've loaded this file via a browser |
16
|
|
|
|
|
|
|
# select "Save As..." from your file menu |
17
|
|
|
|
|
|
|
# |
18
|
|
|
|
|
|
|
# ptkdb Perl Tk perl Debugger |
19
|
|
|
|
|
|
|
# |
20
|
|
|
|
|
|
|
# Copyright 1998, 2003, Andrew E. Page |
21
|
|
|
|
|
|
|
# All rights reserved. |
22
|
|
|
|
|
|
|
# |
23
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or modify |
24
|
|
|
|
|
|
|
# it under the terms of either: |
25
|
|
|
|
|
|
|
# |
26
|
|
|
|
|
|
|
# a) the GNU General Public License as published by the Free |
27
|
|
|
|
|
|
|
# Software Foundation; either version 1, or (at your option) any |
28
|
|
|
|
|
|
|
# later version, or |
29
|
|
|
|
|
|
|
# |
30
|
|
|
|
|
|
|
# b) the "Artistic License" which comes with this Kit. |
31
|
|
|
|
|
|
|
# |
32
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful, |
33
|
|
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
34
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either |
35
|
|
|
|
|
|
|
# the GNU General Public License or the Artistic License for more details. |
36
|
|
|
|
|
|
|
# |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
#################################### |
40
|
|
|
|
|
|
|
### Sample .Xresources for ptkdb ### |
41
|
|
|
|
|
|
|
#################################### |
42
|
|
|
|
|
|
|
# /* |
43
|
|
|
|
|
|
|
# * Perl Tk Debugger XResources. |
44
|
|
|
|
|
|
|
# * Note... These resources are subject to change. |
45
|
|
|
|
|
|
|
# * |
46
|
|
|
|
|
|
|
# * Use 'xfontsel' to select different fonts. |
47
|
|
|
|
|
|
|
# * |
48
|
|
|
|
|
|
|
# * Append these resource to ~/.Xdefaults | ~/.Xresources |
49
|
|
|
|
|
|
|
# * and use xrdb -override ~/.Xdefaults | ~/.Xresources |
50
|
|
|
|
|
|
|
# * to activate them. |
51
|
|
|
|
|
|
|
# */ |
52
|
|
|
|
|
|
|
# /* Set Value to se to place scrollbars on the right side of windows |
53
|
|
|
|
|
|
|
# CAUTION: extra whitespace at the end of the line is causing |
54
|
|
|
|
|
|
|
# failures with Tk800.011. |
55
|
|
|
|
|
|
|
# */ |
56
|
|
|
|
|
|
|
# ptkdb*scrollbars: sw |
57
|
|
|
|
|
|
|
# |
58
|
|
|
|
|
|
|
# /* controls where the code pane is oriented, down the left side, or across the top */ |
59
|
|
|
|
|
|
|
# /* values can be set to left, right, top, bottom */ |
60
|
|
|
|
|
|
|
# ptkdb*codeside: left |
61
|
|
|
|
|
|
|
# /* |
62
|
|
|
|
|
|
|
# * Background color for the balloon |
63
|
|
|
|
|
|
|
# * CAUTION: For certain versions of Tk trailing |
64
|
|
|
|
|
|
|
# * characters after the color produces an error |
65
|
|
|
|
|
|
|
# */ |
66
|
|
|
|
|
|
|
# ptkdb.frame2.frame1.rotext.balloon.background: green |
67
|
|
|
|
|
|
|
# ptkdb.frame2.frame1.rotext.balloon.font: fixed /* Hot Variable Balloon Font */ |
68
|
|
|
|
|
|
|
# |
69
|
|
|
|
|
|
|
# |
70
|
|
|
|
|
|
|
# ptkdb.frame*font: fixed /* Menu Bar */ |
71
|
|
|
|
|
|
|
# ptkdb.frame.menubutton.font: fixed /* File menu */ |
72
|
|
|
|
|
|
|
# ptkdb.frame2.frame1.rotext.font: fixed /* Code Pane */ |
73
|
|
|
|
|
|
|
# ptkdb.notebook.datapage.frame1.hlist.font: fixed /* Expression Notebook Page */ |
74
|
|
|
|
|
|
|
# |
75
|
|
|
|
|
|
|
# ptkdb.notebook.subspage*font: fixed /* Subroutine Notebook Page */ |
76
|
|
|
|
|
|
|
# ptkdb.notebook.brkptspage*entry.font: fixed /* Delete Breakpoint Buttons */ |
77
|
|
|
|
|
|
|
# ptkdb.notebook.brkptspage*button.font: fixed /* Breakpoint Expression Entries */ |
78
|
|
|
|
|
|
|
# ptkdb.notebook.brkptspage*button1.font: fixed /* Breakpoint Expression Entries */ |
79
|
|
|
|
|
|
|
# ptkdb.notebook.brkptspage*checkbutton.font: fixed /* Breakpoint Checkbuttons */ |
80
|
|
|
|
|
|
|
# ptkdb.notebook.brkptspage*label.font: fixed /* Breakpoint "Cond" label */ |
81
|
|
|
|
|
|
|
# |
82
|
|
|
|
|
|
|
# ptkdb.toplevel.frame.textundo.font: fixed /* Eval Expression Entry Window */ |
83
|
|
|
|
|
|
|
# ptkdb.toplevel.frame1.text.font: fixed /* Eval Expression Results Window */ |
84
|
|
|
|
|
|
|
# ptkdb.toplevel.button.font: fixed /* "Eval..." Button */ |
85
|
|
|
|
|
|
|
# ptkdb.toplevel.button1.font: fixed /* "Clear Eval" Button */ |
86
|
|
|
|
|
|
|
# ptkdb.toplevel.button2.font: fixed /* "Clear Results" Button */ |
87
|
|
|
|
|
|
|
# ptkdb.toplevel.button3.font: fixed /* "Clear Dismiss" Button */ |
88
|
|
|
|
|
|
|
# |
89
|
|
|
|
|
|
|
# |
90
|
|
|
|
|
|
|
# /* |
91
|
|
|
|
|
|
|
# * Background color for where the debugger has stopped |
92
|
|
|
|
|
|
|
# */ |
93
|
|
|
|
|
|
|
# ptkdb*stopcolor: blue |
94
|
|
|
|
|
|
|
# |
95
|
|
|
|
|
|
|
# /* |
96
|
|
|
|
|
|
|
# * Background color for set breakpoints |
97
|
|
|
|
|
|
|
# */ |
98
|
|
|
|
|
|
|
# ptkdb*breaktagcolor: red |
99
|
|
|
|
|
|
|
# |
100
|
|
|
|
|
|
|
# /* |
101
|
|
|
|
|
|
|
# * Font for where the debugger has stopped |
102
|
|
|
|
|
|
|
# */ |
103
|
|
|
|
|
|
|
# ptkdb*stopfont: -*-fixed-bold-*-*-*-*-*-*-*-*-*-*-* |
104
|
|
|
|
|
|
|
# |
105
|
|
|
|
|
|
|
# /* |
106
|
|
|
|
|
|
|
# * Background color for the search tag |
107
|
|
|
|
|
|
|
# */ |
108
|
|
|
|
|
|
|
# ptkdb*searchtagcolor: green |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
use strict ; |
111
|
|
|
|
|
|
|
use vars qw($VERSION @dbline %dbline); |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# |
115
|
|
|
|
|
|
|
# This package is the main_window object |
116
|
|
|
|
|
|
|
# for the debugger. We start with the Devel:: |
117
|
|
|
|
|
|
|
# prefix because we want to install it with |
118
|
|
|
|
|
|
|
# the DB:: package that is required to be in a Devel/ |
119
|
|
|
|
|
|
|
# subdir of a directory in the @INC set. |
120
|
|
|
|
|
|
|
# |
121
|
|
|
|
|
|
|
package Devel::ptkdb ; |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
## |
124
|
|
|
|
|
|
|
## do this check once, rather than repeating the string comparison again and again |
125
|
|
|
|
|
|
|
## |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
my $isWin32 = $^O eq 'MSWin32' ; |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=head1 NAME |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
Devel::ptkdb - Perl debugger using a Tk GUI |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=head1 DESCRIPTION |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
ptkdb is a debugger for perl that uses perlTk for a user interface. |
137
|
|
|
|
|
|
|
Features include: |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Hot Variable Inspection |
140
|
|
|
|
|
|
|
Breakpoint Control Panel |
141
|
|
|
|
|
|
|
Expression List |
142
|
|
|
|
|
|
|
Subroutine Tree |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=begin html |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=end html |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=head1 SYNOPSIS |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
To debug a script using ptkdb invoke perl like this: |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
perl -d:ptkdb myscript.pl |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=head1 Usage |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
perl -d:ptkdb myscript.pl |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=head1 Code Pane |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=over 4 |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=item Line Numbers |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
Line numbers are presented on the left side of the window. Lines that |
168
|
|
|
|
|
|
|
have lines through them are not breakable. Lines that are plain text |
169
|
|
|
|
|
|
|
are breakable. Clicking on these line numbers will insert a |
170
|
|
|
|
|
|
|
breakpoint on that line and change the line number color to |
171
|
|
|
|
|
|
|
$ENV{'PTKDB_BRKPT_COLOR'} (Defaults to Red). Clicking on the number |
172
|
|
|
|
|
|
|
again will remove the breakpoint. If you disable the breakpoint with |
173
|
|
|
|
|
|
|
the controls on the BrkPt notebook page the color will change to |
174
|
|
|
|
|
|
|
$ENV{'PTKDB_DISABLEDBRKPT_COLOR'}(Defaults to Green). |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=item Cursor Motion |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
If you place the cursor over a variable (i.e. $myVar, @myVar, or |
179
|
|
|
|
|
|
|
%myVar) and pause for a second the debugger will evaluate the current |
180
|
|
|
|
|
|
|
value of the variable and pop a balloon up with the evaluated |
181
|
|
|
|
|
|
|
result. I |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
If Data::Dumper(standard with perl5.00502)is available it will be used |
184
|
|
|
|
|
|
|
to format the result. If there is an active selection, the text of |
185
|
|
|
|
|
|
|
that selection will be evaluated. |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=back |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=head1 Notebook Pane |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=over 2 |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=item Exprs |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
This is a list of expressions that are evaluated each time the |
196
|
|
|
|
|
|
|
debugger stops. The results of the expresssion are presented |
197
|
|
|
|
|
|
|
heirarchically for expression that result in hashes or lists. Double |
198
|
|
|
|
|
|
|
clicking on such an expression will cause it to collapse; double |
199
|
|
|
|
|
|
|
clicking again will cause the expression to expand. Expressions are |
200
|
|
|
|
|
|
|
entered through B entry, or by Alt-E when text is |
201
|
|
|
|
|
|
|
selected in the code pane. |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
The B entry, will take an expression, evaluate it, and |
204
|
|
|
|
|
|
|
replace the entries contents with the result. The result is also |
205
|
|
|
|
|
|
|
transfered to the 'clipboard' for pasting. |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=item Subs |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Displays a list of all the packages invoked with the script |
210
|
|
|
|
|
|
|
heirarchially. At the bottom of the heirarchy are the subroutines |
211
|
|
|
|
|
|
|
within the packages. Double click on a package to expand |
212
|
|
|
|
|
|
|
it. Subroutines are listed by their full package names. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=item BrkPts |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
Presents a list of the breakpoints current in use. The pushbutton |
217
|
|
|
|
|
|
|
allows a breakpoint to be 'disabled' without removing it. Expressions |
218
|
|
|
|
|
|
|
can be applied to the breakpoint. If the expression evaluates to be |
219
|
|
|
|
|
|
|
'true'(results in a defined value that is not 0) the debugger will |
220
|
|
|
|
|
|
|
stop the script. Pressing the 'Goto' button will set the text pane |
221
|
|
|
|
|
|
|
to that file and line where the breakpoint is set. Pressing the |
222
|
|
|
|
|
|
|
'Delete' button will delete the breakpoint. |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=back |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=head1 Menus |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=head2 File Menu |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=over |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=item About... |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
Presents a dialog box telling you about the version of ptkdb. It |
235
|
|
|
|
|
|
|
recovers your OS name, version of perl, version of Tk, and some other |
236
|
|
|
|
|
|
|
information |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=item Open |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
Presents a list of files that are part of the invoked perl |
241
|
|
|
|
|
|
|
script. Selecting a file from this list will present this file in the |
242
|
|
|
|
|
|
|
text window. |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=item Save Config... |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
Requires Data::Dumper. Prompts for a filename to save the |
247
|
|
|
|
|
|
|
configuration to. Saves the breakpoints, expressions, eval text and |
248
|
|
|
|
|
|
|
window geometry. If the name given as the default is used and the |
249
|
|
|
|
|
|
|
script is reinvoked, this configuration will be reloaded |
250
|
|
|
|
|
|
|
automatically. |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
B You may find this preferable to using |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=item Restore Config... |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
Requires Data::Dumper. Prompts for a filename to restore a configuration saved with |
257
|
|
|
|
|
|
|
the "Save Config..." menu item. |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=item Goto Line... |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
Prompts for a line number. Pressing the "Okay" button sends the window to the line number entered. |
262
|
|
|
|
|
|
|
item Find Text... |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
Prompts for text to search for. Options include forward search, |
265
|
|
|
|
|
|
|
backwards search, and regular expression searching. |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=item Quit |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
Causes the debugger and the target script to exit. |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=back |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=head2 Control Menu |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=over |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=item Run |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
The debugger allows the script to run to the next breakpoint or until the script exits. |
280
|
|
|
|
|
|
|
item Run To Here |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
Runs the debugger until it comes to wherever the insertion cursor |
283
|
|
|
|
|
|
|
in text window is placed. |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=item Set Breakpoint |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
Sets a breakpoint on the line at the insertion cursor. |
288
|
|
|
|
|
|
|
item Clear Breakpoint |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
Remove a breakpoint on the at the insertion cursor. |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=item Clear All Breakpoints |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
Removes all current breakpoints |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=item Step Over |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
Causes the debugger to step over the next line. If the line is a |
299
|
|
|
|
|
|
|
subroutine call it steps over the call, stopping when the subroutine |
300
|
|
|
|
|
|
|
returns. |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=item Step In |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
Causes the debugger to step into the next line. If the line is a |
305
|
|
|
|
|
|
|
subroutine call it steps into the subroutine, stopping at the first |
306
|
|
|
|
|
|
|
executable line within the subroutine. |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=item Return |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
Runs the script until it returns from the currently executing |
311
|
|
|
|
|
|
|
subroutine. |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
=item Restart |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
Saves the breakpoints and expressions in a temporary file and restarts |
316
|
|
|
|
|
|
|
the script from the beginning. CAUTION: This feature will not work |
317
|
|
|
|
|
|
|
properly with debugging of CGI Scripts. |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=item Stop On Warning |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
When C<-w> is enabled the debugger will stop when warnings such as, "Use |
322
|
|
|
|
|
|
|
of uninitialized value at undef_warn.pl line N" are encountered. The debugger |
323
|
|
|
|
|
|
|
will stop on the NEXT line of execution since the error can't be detected |
324
|
|
|
|
|
|
|
until the current line has executed. |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
This feature can be turned on at startup by adding: |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
$DB::ptkdb::stop_on_warning = 1 ; |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
to a .ptkdbrc file |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=back |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=head2 Data Menu |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
=over |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=item Enter Expression |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
When an expression is entered in the "Enter Expression:" text box, |
341
|
|
|
|
|
|
|
selecting this item will enter the expression into the expression |
342
|
|
|
|
|
|
|
list. Each time the debugger stops this expression will be evaluated |
343
|
|
|
|
|
|
|
and its result updated in the list window. |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=item Delete Expression |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
Deletes the highlighted expression in the expression window. |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=item Delete All Expressions |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
Delete all expressions in the expression window. |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
=item Expression Eval Window |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
Pops up a two pane window. Expressions of virtually unlimitted length |
356
|
|
|
|
|
|
|
can be entered in the top pane. Pressing the 'Eval' button will cause |
357
|
|
|
|
|
|
|
the expression to be evaluated and its placed in the lower pane. If |
358
|
|
|
|
|
|
|
Data::Dumper is available it will be used to format the resulting |
359
|
|
|
|
|
|
|
text. Undo is enabled for the text in the upper pane. |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
HINT: You can enter multiple expressions by separating them with commas. |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=item Use Data::Dumper for Eval Window |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
Enables or disables the use of Data::Dumper for formatting the results |
366
|
|
|
|
|
|
|
of expressions in the Eval window. |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
=back |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
=head2 Stack Menu |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
Maintains a list of the current subroutine stack each time the |
373
|
|
|
|
|
|
|
debugger stops. Selecting an item from this menu will set the text in |
374
|
|
|
|
|
|
|
the code window to that particular subourtine entry point. |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=head2 Bookmarks Menu |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
Maintains a list of bookmarks. The booksmarks are saved in ~/.ptkdb_bookmarks |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
=over |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
=item Add Bookmark |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
Adds a bookmark to the bookmark list. |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
=back |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
=head1 Options |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
Here is a list of the current active XResources options. Several of |
391
|
|
|
|
|
|
|
these can be overridden with environmental variables. Resources can be |
392
|
|
|
|
|
|
|
added to .Xresources or .Xdefaults depending on your X configuration. |
393
|
|
|
|
|
|
|
To enable these resources you must either restart your X server or use |
394
|
|
|
|
|
|
|
the xrdb -override resFile command. xfontsel can be used to select |
395
|
|
|
|
|
|
|
fonts. |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
/* |
398
|
|
|
|
|
|
|
* Perl Tk Debugger XResources. |
399
|
|
|
|
|
|
|
* Note... These resources are subject to change. |
400
|
|
|
|
|
|
|
* |
401
|
|
|
|
|
|
|
* Use 'xfontsel' to select different fonts. |
402
|
|
|
|
|
|
|
* |
403
|
|
|
|
|
|
|
* Append these resource to ~/.Xdefaults | ~/.Xresources |
404
|
|
|
|
|
|
|
* and use xrdb -override ~/.Xdefaults | ~/.Xresources |
405
|
|
|
|
|
|
|
* to activate them. |
406
|
|
|
|
|
|
|
*/ |
407
|
|
|
|
|
|
|
/* Set Value to se to place scrollbars on the right side of windows |
408
|
|
|
|
|
|
|
CAUTION: extra whitespace at the end of the line is causing |
409
|
|
|
|
|
|
|
failures with Tk800.011. |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sw -> puts scrollbars on left, se puts scrollars on the right |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
*/ |
414
|
|
|
|
|
|
|
ptkdb*scrollbars: sw |
415
|
|
|
|
|
|
|
/* controls where the code pane is oriented, down the left side, or across the top */ |
416
|
|
|
|
|
|
|
/* values can be set to left, right, top, bottom */ |
417
|
|
|
|
|
|
|
ptkdb*codeside: left |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
/* |
420
|
|
|
|
|
|
|
* Background color for the balloon |
421
|
|
|
|
|
|
|
* CAUTION: For certain versions of Tk trailing |
422
|
|
|
|
|
|
|
* characters after the color produces an error |
423
|
|
|
|
|
|
|
*/ |
424
|
|
|
|
|
|
|
ptkdb.frame2.frame1.rotext.balloon.background: green |
425
|
|
|
|
|
|
|
ptkdb.frame2.frame1.rotext.balloon.font: fixed /* Hot Variable Balloon Font */ |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
ptkdb.frame*font: fixed /* Menu Bar */ |
429
|
|
|
|
|
|
|
ptkdb.frame.menubutton.font: fixed /* File menu */ |
430
|
|
|
|
|
|
|
ptkdb.frame2.frame1.rotext.font: fixed /* Code Pane */ |
431
|
|
|
|
|
|
|
ptkdb.notebook.datapage.frame1.hlist.font: fixed /* Expression Notebook Page */ |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
ptkdb.notebook.subspage*font: fixed /* Subroutine Notebook Page */ |
434
|
|
|
|
|
|
|
ptkdb.notebook.brkptspage*entry.font: fixed /* Delete Breakpoint Buttons */ |
435
|
|
|
|
|
|
|
ptkdb.notebook.brkptspage*button.font: fixed /* Breakpoint Expression Entries */ |
436
|
|
|
|
|
|
|
ptkdb.notebook.brkptspage*button1.font: fixed /* Breakpoint Expression Entries */ |
437
|
|
|
|
|
|
|
ptkdb.notebook.brkptspage*checkbutton.font: fixed /* Breakpoint Checkbuttons */ |
438
|
|
|
|
|
|
|
ptkdb.notebook.brkptspage*label.font: fixed /* Breakpoint Checkbuttons */ |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
ptkdb.toplevel.frame.textundo.font: fixed /* Eval Expression Entry Window */ |
441
|
|
|
|
|
|
|
ptkdb.toplevel.frame1.text.font: fixed /* Eval Expression Results Window */ |
442
|
|
|
|
|
|
|
ptkdb.toplevel.button.font: fixed /* "Eval..." Button */ |
443
|
|
|
|
|
|
|
ptkdb.toplevel.button1.font: fixed /* "Clear Eval" Button */ |
444
|
|
|
|
|
|
|
ptkdb.toplevel.button2.font: fixed /* "Clear Results" Button */ |
445
|
|
|
|
|
|
|
ptkdb.toplevel.button3.font: fixed /* "Clear Dismiss" Button */ |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
/* |
448
|
|
|
|
|
|
|
* Background color for where the debugger has stopped |
449
|
|
|
|
|
|
|
*/ |
450
|
|
|
|
|
|
|
ptkdb*stopcolor: blue |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
/* |
453
|
|
|
|
|
|
|
* Background color for set breakpoints |
454
|
|
|
|
|
|
|
*/ |
455
|
|
|
|
|
|
|
ptkdb*breaktagcolor*background: yellow |
456
|
|
|
|
|
|
|
ptkdb*disabledbreaktagcolor*background: white |
457
|
|
|
|
|
|
|
/* |
458
|
|
|
|
|
|
|
* Font for where the debugger has stopped |
459
|
|
|
|
|
|
|
*/ |
460
|
|
|
|
|
|
|
ptkdb*stopfont: -*-fixed-bold-*-*-*-*-*-*-*-*-*-*-* |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
/* |
463
|
|
|
|
|
|
|
* Background color for the search tag |
464
|
|
|
|
|
|
|
*/ |
465
|
|
|
|
|
|
|
ptkdb*searchtagcolor: green |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
=head1 Environmental Variables |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
=over 4 |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=item PTKDB_BRKPT_COLOR |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
Sets the background color of a set breakpoint |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=item PTKDB_DISABLEDBRKPT_COLOR |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
Sets the background color of a disabled breakpoint |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
=item PTKDB_CODE_FONT |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
Sets the font of the Text in the code pane. |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
=item PTKDB_CODE_SIDE |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
Sets which side the code pane is packed onto. Defaults to 'left'. |
486
|
|
|
|
|
|
|
Can be set to 'left', 'right', 'top', 'bottom'. |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
Overrides the Xresource ptkdb*codeside: I. |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=item PTKDB_EXPRESSION_FONT |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
Sets the font used in the expression notebook page. |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
=item PTKDB_EVAL_FONT |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
Sets the font used in the Expression Eval Window |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
=item PTKDB_EVAL_DUMP_INDENT |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
Sets the value used for Data::Dumper 'indent' setting. See man Data::Dumper |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
=item PTKDB_SCROLLBARS_ONRIGHT |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
A non-zero value Sets the scrollbars of all windows to be on the |
505
|
|
|
|
|
|
|
right side of the window. Useful for Windows users using ptkdb in an |
506
|
|
|
|
|
|
|
XWindows environment. |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=item PTKDB_LINENUMBER_FORMAT |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
Sets the format of line numbers on the left side of the window. Default value is %05d. useful |
511
|
|
|
|
|
|
|
if you have a script that contains more than 99999 lines. |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
=item PTKDB_DISPLAY |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
Sets the X display that the ptkdb window will appear on when invoked. Useful for debugging CGI |
516
|
|
|
|
|
|
|
scripts on remote systems. |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
=item PTKDB_BOOKMARKS_PATH |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
Sets the path of the bookmarks file. Default is $ENV{'HOME'}/.ptkdb_bookmarks |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
=item PTKDB_STOP_TAG_COLOR |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
Sets the color that highlights the line where the debugger is stopped |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
=back |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
=head1 FILES |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
=head2 .ptkdbrc |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
If this file is present in ~/ or in the directory where perl is |
533
|
|
|
|
|
|
|
invoked the file will be read and executed as a perl script before the |
534
|
|
|
|
|
|
|
debugger makes its initial stop at startup. There are several 'api' |
535
|
|
|
|
|
|
|
calls that can be used with such scripts. There is an internal |
536
|
|
|
|
|
|
|
variable $DB::no_stop_at_start that may be set to non-zero to prevent |
537
|
|
|
|
|
|
|
the debugger from stopping at the first line of the script. This is |
538
|
|
|
|
|
|
|
useful for debugging CGI scripts. |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
There is a system ptkdbrc file in $PREFIX/lib/perl5/$VERS/Devel/ptkdbrc |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
=over 4 |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
=item brkpt($fname, @lines) |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
Sets breakspoints on the list of lines in $fname. A warning message |
547
|
|
|
|
|
|
|
is generated if a line is not breakable. |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
=item condbrkpt($fname, @($line, $expr) ) |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
Sets conditional breakpoints in $fname on pairs of $line and $expr. A |
552
|
|
|
|
|
|
|
warning message is generated if a line is not breakable. NOTE: the |
553
|
|
|
|
|
|
|
validity of the expression will not be determined until execution of |
554
|
|
|
|
|
|
|
that particular line. |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
=item brkonsub(@names) |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
Sets a breakpoint on each subroutine name listed. A warning message is |
559
|
|
|
|
|
|
|
generated if a subroutine does not exist. NOTE: for a script with no |
560
|
|
|
|
|
|
|
other packages the default package is "main::" and the subroutines |
561
|
|
|
|
|
|
|
would be "main::mySubs". |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
=item brkonsub_regex(@regExprs) |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
Uses the list of @regExprs as a list of regular expressions to set breakpoints. Sets breakpoints |
566
|
|
|
|
|
|
|
on every subroutine that matches any of the listed regular expressions. |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
=item textTagConfigure(tag, ?option?, ?value?) |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
Allows the user to format the text in the code window. The option |
571
|
|
|
|
|
|
|
value pairs are the same values as the option for the tagConfigure |
572
|
|
|
|
|
|
|
method documented in Tk::Text. Currently the following tags are in |
573
|
|
|
|
|
|
|
effect: |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
'code' Format for code in the text pane |
577
|
|
|
|
|
|
|
'stoppt' Format applied to the line where the debugger is currently stopped |
578
|
|
|
|
|
|
|
'breakableLine' Format applied to line numbers where the code is 'breakable' |
579
|
|
|
|
|
|
|
'nonbreakableLine' Format applied to line numbers where the code is no breakable |
580
|
|
|
|
|
|
|
'breaksetLine' Format applied to line numbers were a breakpoint is set |
581
|
|
|
|
|
|
|
'breakdisabledLine' Format applied to line numbers were a disabled breakpoint is set |
582
|
|
|
|
|
|
|
'search_tag' Format applied to text when located by a search. |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
Example: |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
# |
587
|
|
|
|
|
|
|
# Turns off the overstrike on lines that you can't set a breakpoint on |
588
|
|
|
|
|
|
|
# and makes the text color yellow. |
589
|
|
|
|
|
|
|
# |
590
|
|
|
|
|
|
|
textTagConfigure('nonbreakableLine', -overstrike => 0, -foreground => "yellow") ; |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
=item add_exprs(@exprList) |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
Add a list of expressions to the 'Exprs' window. NOTE: use the single |
595
|
|
|
|
|
|
|
quote character \' to prevent the expression from being "evaluated" in |
596
|
|
|
|
|
|
|
the string context. |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
Example: |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
# |
602
|
|
|
|
|
|
|
# Adds the $_ and @_ expressions to the active list |
603
|
|
|
|
|
|
|
# |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
add_exprs('$_', '@_') ; |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
=back |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
=head1 NOTES |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
=head2 Debugging Other perlTk Applications |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
ptkdb can be used to debug other perlTk applications if some cautions |
614
|
|
|
|
|
|
|
are observed. Basically, do not click the mouse in the application's |
615
|
|
|
|
|
|
|
window(s) when you've entered the debugger and do not click in the |
616
|
|
|
|
|
|
|
debugger's window(s) while the application is running. Doing either |
617
|
|
|
|
|
|
|
one is not necessarily fatal, but it can confuse things that are going |
618
|
|
|
|
|
|
|
on and produce unexpected results. |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
Be aware that most perlTk applications have a central event loop. |
621
|
|
|
|
|
|
|
User actions, such as mouse clicks, key presses, window exposures, etc |
622
|
|
|
|
|
|
|
will generate 'events' that the script will process. When a perlTk |
623
|
|
|
|
|
|
|
application is running, its 'MainLoop' call will accept these events |
624
|
|
|
|
|
|
|
and then dispatch them to appropriate callbacks associated with the |
625
|
|
|
|
|
|
|
appropriate widgets. |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
Ptkdb has its own event loop that runs whenever you've stopped at a |
628
|
|
|
|
|
|
|
breakpoint and entered the debugger. However, it can accept events |
629
|
|
|
|
|
|
|
that are generated by other perlTk windows and dispatch their |
630
|
|
|
|
|
|
|
callbacks. The problem here is that the application is supposed to be |
631
|
|
|
|
|
|
|
'stopped', and logically the application should not be able to process |
632
|
|
|
|
|
|
|
events. |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
A future version of ptkdb will have an extension that will 'filter' |
635
|
|
|
|
|
|
|
events so that application events are not processed while the debugger |
636
|
|
|
|
|
|
|
is active, and debugger events will not be processed while the target |
637
|
|
|
|
|
|
|
script is active. |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
=head2 Debugging CGI Scripts |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
One advantage of ptkdb over the builtin debugger(-d) is that it can be |
642
|
|
|
|
|
|
|
used to debug CGI perl scripts as they run on a web server. Be sure |
643
|
|
|
|
|
|
|
that that your web server's perl instalation includes Tk. |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
Change your |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
#! /usr/local/bin/perl |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
to |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
#! /usr/local/bin/perl -d:ptkdb |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
TIP: You can debug scripts remotely if you're using a unix based |
654
|
|
|
|
|
|
|
Xserver and where you are authoring the script has an Xserver. The |
655
|
|
|
|
|
|
|
Xserver can be another unix workstation, a Macintosh or Win32 platform |
656
|
|
|
|
|
|
|
with an appropriate XWindows package. In your script insert the |
657
|
|
|
|
|
|
|
following BEGIN subroutine: |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
sub BEGIN { |
660
|
|
|
|
|
|
|
$ENV{'DISPLAY'} = "myHostname:0.0" ; |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
Be sure that your web server has permission to open windows on your |
664
|
|
|
|
|
|
|
Xserver (see the xhost manpage). |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
Access your web page with your browswer and 'submit' the script as |
667
|
|
|
|
|
|
|
normal. The ptkdb window should appear on myHostname's monitor. At |
668
|
|
|
|
|
|
|
this point you can start debugging your script. Be aware that your |
669
|
|
|
|
|
|
|
browser may timeout waiting for the script to run. |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
To expedite debugging you may want to setup your breakpoints in |
672
|
|
|
|
|
|
|
advance with a .ptkdbrc file and use the $DB::no_stop_at_start |
673
|
|
|
|
|
|
|
variable. NOTE: for debugging web scripts you may have to have the |
674
|
|
|
|
|
|
|
.ptkdbrc file installed in the server account's home directory (~www) |
675
|
|
|
|
|
|
|
or whatever username your webserver is running under. Also try |
676
|
|
|
|
|
|
|
installing a .ptkdbrc file in the same directory as the target script. |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=head1 KNOWN PROBLEMS |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
=over |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
=item I |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
If the size of the right hand pane is too small the breakpoint controls |
685
|
|
|
|
|
|
|
are not visible. The breakpoints are still there, the window may have |
686
|
|
|
|
|
|
|
to be enlarged in order for them to be visible. |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
=item Balloons and Tk400 |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
The Balloons in Tk400 will not work with ptkdb. All other functions |
691
|
|
|
|
|
|
|
are supported, but the Balloons require Tk800 or higher. |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
=back |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
=head1 AUTHOR |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
Andrew E. Page, aepage@users.sourceforge.net |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
Matthew Persico For suggestions, and beta testing. |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
=head1 BUG REPORTING |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
Please report bugs through the following URL: |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
http://sourceforge.net/tracker/?atid=437609&group_id=43854&func=browse |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
=cut |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
require 5.004 ; |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
## |
716
|
|
|
|
|
|
|
## Perform a check to see if we have the Tk library, if not, attempt |
717
|
|
|
|
|
|
|
## to load it for the user |
718
|
|
|
|
|
|
|
## |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
sub BEGIN { |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
eval { |
723
|
|
|
|
|
|
|
require Tk ; |
724
|
|
|
|
|
|
|
} ; |
725
|
|
|
|
|
|
|
if( $@ ) { |
726
|
|
|
|
|
|
|
print << "__PTKDBTK_INSTALL__" ; |
727
|
|
|
|
|
|
|
*** |
728
|
|
|
|
|
|
|
*** The PerlTk library could not be found. Ptkdb requires the PerlTk library. |
729
|
|
|
|
|
|
|
*** |
730
|
|
|
|
|
|
|
Preferably Tk800.015 or better: |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
In order to install this the following conditions must be met: |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
1. You have to have access to a C compiler. |
735
|
|
|
|
|
|
|
2. You must have sufficient permissions to install the libraries on your system. |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
To install PerlTk: |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
a Download the Tk library source from http://www.perl.com/CPAN/modules/by-category/08_User_Interfaces/Tk |
740
|
|
|
|
|
|
|
b Uncompress the archive and run "perl Makefile.PL" |
741
|
|
|
|
|
|
|
c run "make install" |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
If this process completes successfully ptkdb should be operational now. |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
We can attempt to run the CPAN module for you. This will, after some questions, download |
746
|
|
|
|
|
|
|
and install the Tk library automatically. |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
Would you like to run the CPAN module? (y/n) |
749
|
|
|
|
|
|
|
__PTKDBTK_INSTALL__ |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
my $answer = ; |
752
|
|
|
|
|
|
|
chomp $answer ; |
753
|
|
|
|
|
|
|
if( $answer =~ /y|yes/i) { |
754
|
|
|
|
|
|
|
require CPAN ; |
755
|
|
|
|
|
|
|
CPAN::install Tk ; |
756
|
|
|
|
|
|
|
} # if |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
} # if $@ |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
} # end of sub BEGIN |
762
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
use Tk 800 ; |
764
|
|
|
|
|
|
|
use Data::Dumper ; |
765
|
|
|
|
|
|
|
use FileHandle ; |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
require Tk::Dialog; |
768
|
|
|
|
|
|
|
require Tk::TextUndo ; |
769
|
|
|
|
|
|
|
require Tk::ROText; |
770
|
|
|
|
|
|
|
require Tk::NoteBook ; |
771
|
|
|
|
|
|
|
require Tk::HList ; |
772
|
|
|
|
|
|
|
require Tk::Table ; |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
use vars qw(@dbline) ; |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
use Config ; |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
sub DoBugReport { |
779
|
|
|
|
|
|
|
my($str) = 'sourceforge.net/tracker/?atid=437609&group_id=43854&func=browse' ; |
780
|
|
|
|
|
|
|
my(@browsers) = qw/netscape mozilla/ ; |
781
|
|
|
|
|
|
|
my($fh, $pid, $sh) ; |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
if( $isWin32 ) { |
784
|
|
|
|
|
|
|
$sh = '' ; |
785
|
|
|
|
|
|
|
@browsers = '"' . $ENV{'PROGRAMFILES'} . '\\Internet Explorer\\IEXPLORE.EXE' . '"' ; |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
} |
788
|
|
|
|
|
|
|
else { |
789
|
|
|
|
|
|
|
$sh = 'sh' ; |
790
|
|
|
|
|
|
|
$str = "\'http://" . $str . "\'" ; |
791
|
|
|
|
|
|
|
} |
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
$fh = new FileHandle() ; |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
for( @browsers ) { |
796
|
|
|
|
|
|
|
$pid = open($fh, "$sh $_ $str 2&> /dev/null |") ; |
797
|
|
|
|
|
|
|
sleep(2) ; |
798
|
|
|
|
|
|
|
waitpid $pid, 0 ; |
799
|
|
|
|
|
|
|
return if( $? == 0 ) ; |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
print "##\n" ; |
803
|
|
|
|
|
|
|
print "## Please submit a bug report through the following URL:\n" ; |
804
|
|
|
|
|
|
|
print '## http://sourceforge.net/tracker/?atid=437609&group_id=43854&func=browse', "\n" ; |
805
|
|
|
|
|
|
|
print "##\n" ; |
806
|
|
|
|
|
|
|
} |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
# |
809
|
|
|
|
|
|
|
# Check to see if the package actually |
810
|
|
|
|
|
|
|
# exists. If it does import the routines |
811
|
|
|
|
|
|
|
# and return a true value ; |
812
|
|
|
|
|
|
|
# |
813
|
|
|
|
|
|
|
# NOTE: this needs to be above the 'BEGIN' subroutine, |
814
|
|
|
|
|
|
|
# otherwise it will not have been compiled by the time |
815
|
|
|
|
|
|
|
# that it is called by sub BEGIN. |
816
|
|
|
|
|
|
|
# |
817
|
|
|
|
|
|
|
sub check_avail { |
818
|
|
|
|
|
|
|
my ($mod, @list) = @_ ; |
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
eval { |
821
|
|
|
|
|
|
|
require $mod ; import $mod @list ; |
822
|
|
|
|
|
|
|
} ; |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
return 0 if $@ ; |
825
|
|
|
|
|
|
|
return 1 ; |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
} # end of check_avail |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
sub BEGIN { |
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
$DB::on = 0 ; |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
$DB::subroutine_depth = 0 ; # our subroutine depth counter |
834
|
|
|
|
|
|
|
$DB::step_over_depth = -1 ; |
835
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
# |
837
|
|
|
|
|
|
|
# the bindings and font specs for these operations have been placed here |
838
|
|
|
|
|
|
|
# to make them accessible to people who might want to customize the |
839
|
|
|
|
|
|
|
# operations. REF The 'bind.html' file, included in the perlTk FAQ has |
840
|
|
|
|
|
|
|
# a fairly good explanation of the binding syntax. |
841
|
|
|
|
|
|
|
# |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
# |
844
|
|
|
|
|
|
|
# These lists of key bindings will be applied |
845
|
|
|
|
|
|
|
# to the "Step In", "Step Out", "Return" Commands |
846
|
|
|
|
|
|
|
# |
847
|
|
|
|
|
|
|
$Devel::ptkdb::pathSep = '\x00' ; |
848
|
|
|
|
|
|
|
$Devel::ptkdb::pathSepReplacement = "\0x01" ; |
849
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
@Devel::ptkdb::step_in_keys = ( '', '', '' ) ; # step into a subroutine |
851
|
|
|
|
|
|
|
@Devel::ptkdb::step_over_keys = ( '', '', '' ) ; # step over a subroutine |
852
|
|
|
|
|
|
|
@Devel::ptkdb::return_keys = ( '', '' ) ; # return from a subroutine |
853
|
|
|
|
|
|
|
@Devel::ptkdb::toggle_breakpt_keys = ( '' ) ; # set or unset a breakpoint |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
# Fonts used in the displays |
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
# |
858
|
|
|
|
|
|
|
# NOTE: The environmental variable syntax here works like this: |
859
|
|
|
|
|
|
|
# $ENV{'NAME'} accesses the environmental variable "NAME" |
860
|
|
|
|
|
|
|
# |
861
|
|
|
|
|
|
|
# $ENV{'NAME'} || 'string' results in $ENV{'NAME'} or 'string' if $ENV{'NAME'} is not defined. |
862
|
|
|
|
|
|
|
# |
863
|
|
|
|
|
|
|
# |
864
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
@Devel::ptkdb::button_font = $ENV{'PTKDB_BUTTON_FONT'} ? ( "-font" => $ENV{'PTKDB_CODE_FONT'} ) : () ; # font for buttons |
866
|
|
|
|
|
|
|
@Devel::ptkdb::code_text_font = $ENV{'PTKDB_CODE_FONT'} ? ( "-font" => $ENV{'PTKDB_CODE_FONT'} ) : () ; |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
@Devel::ptkdb::expression_text_font = $ENV{'PTKDB_EXPRESSION_FONT'} ? ( "-font" => $ENV{'PTKDB_EXPRESSION_FONT'} ) : () ; |
869
|
|
|
|
|
|
|
@Devel::ptkdb::eval_text_font = $ENV{'PTKDB_EVAL_FONT'} ? ( -font => $ENV{'PTKDB_EVAL_FONT'} ) : () ; # text for the expression eval window |
870
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
$Devel::ptkdb::eval_dump_indent = $ENV{'PTKDB_EVAL_DUMP_INDENT'} || 1 ; |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
# |
874
|
|
|
|
|
|
|
# Windows users are more used to having scroll bars on the right. |
875
|
|
|
|
|
|
|
# If they've set PTKDB_SCROLLBARS_ONRIGHT to a non-zero value |
876
|
|
|
|
|
|
|
# this will configure our scrolled windows with scrollbars on the right |
877
|
|
|
|
|
|
|
# |
878
|
|
|
|
|
|
|
# this can also be done by setting: |
879
|
|
|
|
|
|
|
# |
880
|
|
|
|
|
|
|
# ptkdb*scrollbars: se |
881
|
|
|
|
|
|
|
# |
882
|
|
|
|
|
|
|
# in the .Xdefaults/.Xresources file on X based systems |
883
|
|
|
|
|
|
|
# |
884
|
|
|
|
|
|
|
if( exists $ENV{'PTKDB_SCROLLBARS_ONRIGHT'} && $ENV{'PTKDB_SCROLLBARS_ONRIGHT'} ) { |
885
|
|
|
|
|
|
|
@Devel::ptkdb::scrollbar_cfg = ('-scrollbars' => 'se') ; |
886
|
|
|
|
|
|
|
} |
887
|
|
|
|
|
|
|
else { |
888
|
|
|
|
|
|
|
@Devel::ptkdb::scrollbar_cfg = ( ) ; |
889
|
|
|
|
|
|
|
} |
890
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
# |
892
|
|
|
|
|
|
|
# Controls how far an expression result will be 'decomposed'. Setting it |
893
|
|
|
|
|
|
|
# to 0 will take it down only one level, setting it to -1 will make it |
894
|
|
|
|
|
|
|
# decompose it all the way down. However, if you have a situation where |
895
|
|
|
|
|
|
|
# an element is a ref back to the array or a root of the array |
896
|
|
|
|
|
|
|
# you could hang the debugger by making it recursively evaluate an expression |
897
|
|
|
|
|
|
|
# |
898
|
|
|
|
|
|
|
$Devel::ptkdb::expr_depth = -1 ; |
899
|
|
|
|
|
|
|
$Devel::ptkdb::add_expr_depth = 1 ; # how much further to expand an expression when clicked |
900
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
$Devel::ptkdb::linenumber_format = $ENV{'PTKDB_LINENUMBER_FORMAT'} || "%05d " ; |
902
|
|
|
|
|
|
|
$Devel::ptkdb::linenumber_length = 5 ; |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
$Devel::ptkdb::linenumber_offset = length sprintf($Devel::ptkdb::linenumber_format, 0) ; |
905
|
|
|
|
|
|
|
$Devel::ptkdb::linenumber_offset -= 1 ; |
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
# |
908
|
|
|
|
|
|
|
# Check to see if "Data Dumper" is available |
909
|
|
|
|
|
|
|
# if it is we can save breakpoints and other |
910
|
|
|
|
|
|
|
# various "functions". This call will also |
911
|
|
|
|
|
|
|
# load the subroutines needed. |
912
|
|
|
|
|
|
|
# |
913
|
|
|
|
|
|
|
$Devel::ptkdb::DataDumperAvailable = 1 ; # assuming that it is now |
914
|
|
|
|
|
|
|
$Devel::ptkdb::useDataDumperForEval = $Devel::ptkdb::DataDumperAvailable ; |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
# |
917
|
|
|
|
|
|
|
# DB Options (things not directly involving the window) |
918
|
|
|
|
|
|
|
# |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
# Flag to disable us from intercepting $SIG{'INT'} |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
$DB::sigint_disable = defined $ENV{'PTKDB_SIGINT_DISABLE'} && $ENV{'PTKDB_SIGINT_DISABLE'} ; |
923
|
|
|
|
|
|
|
# |
924
|
|
|
|
|
|
|
# Possibly for debugging perl CGI Web scripts on |
925
|
|
|
|
|
|
|
# remote machines. |
926
|
|
|
|
|
|
|
# |
927
|
|
|
|
|
|
|
$ENV{'DISPLAY'} = $ENV{'PTKDB_DISPLAY'} if exists $ENV{'PTKDB_DISPLAY'} ; |
928
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
} # end of BEGIN |
930
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
## |
932
|
|
|
|
|
|
|
## subroutine provided to the user for initializing |
933
|
|
|
|
|
|
|
## files in .ptkdbrc |
934
|
|
|
|
|
|
|
## |
935
|
|
|
|
|
|
|
sub brkpt { |
936
|
|
|
|
|
|
|
my ($fName, @idx) = @_ ; |
937
|
|
|
|
|
|
|
my($offset) ; |
938
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fName} ; |
939
|
|
|
|
|
|
|
|
940
|
|
|
|
|
|
|
$offset = $dbline[1] =~ /use\s+.*Devel::_?ptkdb/ ? 1 : 0 ; |
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
for( @idx ) { |
943
|
|
|
|
|
|
|
if( !&DB::checkdbline($fName, $_ + $offset) ) { |
944
|
|
|
|
|
|
|
my ($package, $filename, $line) = caller ; |
945
|
|
|
|
|
|
|
print "$filename:$line: $fName line $_ is not breakable\n" ; |
946
|
|
|
|
|
|
|
next ; |
947
|
|
|
|
|
|
|
} |
948
|
|
|
|
|
|
|
$DB::window->insertBreakpoint($fName, $_, 1) ; # insert a simple breakpoint |
949
|
|
|
|
|
|
|
} |
950
|
|
|
|
|
|
|
} # end of brkpt |
951
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
# |
953
|
|
|
|
|
|
|
# Set conditional breakpoint(s) |
954
|
|
|
|
|
|
|
# |
955
|
|
|
|
|
|
|
sub condbrkpt { |
956
|
|
|
|
|
|
|
my ($fname) = shift ; |
957
|
|
|
|
|
|
|
my($offset) ; |
958
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname} ; |
959
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
$offset = $dbline[1] =~ /use\s+.*Devel::_?ptkdb/ ? 1 : 0 ; |
961
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
while( @_ ) { # arg loop |
963
|
|
|
|
|
|
|
my($index, $expr) = splice @_, 0, 2 ; # take args 2 at a time |
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
if( !&DB::checkdbline($fname, $index + $offset) ) { |
966
|
|
|
|
|
|
|
my ($package, $filename, $line) = caller ; |
967
|
|
|
|
|
|
|
print "$filename:$line: $fname line $index is not breakable\n" ; |
968
|
|
|
|
|
|
|
next ; |
969
|
|
|
|
|
|
|
} |
970
|
|
|
|
|
|
|
$DB::window->insertBreakpoint($fname, $index, 1, $expr) ; # insert a simple breakpoint |
971
|
|
|
|
|
|
|
} # end of arg loop |
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
} # end of conditionalbrkpt |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
sub brkonsub { |
976
|
|
|
|
|
|
|
my(@names) = @_ ; |
977
|
|
|
|
|
|
|
|
978
|
|
|
|
|
|
|
for( @names ) { |
979
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
# get the filename and line number range of the target subroutine |
981
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
if( !exists $DB::sub{$_} ) { |
983
|
|
|
|
|
|
|
print "No subroutine $_. Try main::$_\n" ; |
984
|
|
|
|
|
|
|
next ; |
985
|
|
|
|
|
|
|
} |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
$DB::sub{$_} =~ /(.*):([0-9]+)-([0-9]+)$/o ; # file name will be in $1, start line $2, end line $3 |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
for( $2..$3 ) { |
990
|
|
|
|
|
|
|
next unless &DB::checkdbline($1, $_) ; |
991
|
|
|
|
|
|
|
$DB::window->insertBreakpoint($1, $_, 1) ; |
992
|
|
|
|
|
|
|
last ; # only need the one breakpoint |
993
|
|
|
|
|
|
|
} |
994
|
|
|
|
|
|
|
} # end of name loop |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
} # end of brkonsub |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
# |
999
|
|
|
|
|
|
|
# set breakpoints on subroutines matching a regular |
1000
|
|
|
|
|
|
|
# expression |
1001
|
|
|
|
|
|
|
# |
1002
|
|
|
|
|
|
|
sub brkonsub_regex { |
1003
|
|
|
|
|
|
|
my(@regexps) = @_ ; |
1004
|
|
|
|
|
|
|
my($regexp, @subList) ; |
1005
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
# |
1007
|
|
|
|
|
|
|
# accumulate matching subroutines |
1008
|
|
|
|
|
|
|
# |
1009
|
|
|
|
|
|
|
foreach $regexp ( @regexps ) { |
1010
|
|
|
|
|
|
|
study $regexp ; |
1011
|
|
|
|
|
|
|
push @subList, grep /$regexp/, keys %DB::sub ; |
1012
|
|
|
|
|
|
|
} # end of brkonsub_regex |
1013
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
brkonsub(@subList) ; # set breakpoints on matching subroutines |
1015
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
} # end of brkonsub_regex |
1017
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
# |
1019
|
|
|
|
|
|
|
# Allow the user Access to our tag configurations |
1020
|
|
|
|
|
|
|
# |
1021
|
|
|
|
|
|
|
sub textTagConfigure { |
1022
|
|
|
|
|
|
|
my ($tag, @config) = @_ ; |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
$DB::window->{'text'}->tagConfigure($tag, @config) ; |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
} # end of textTagConfigure |
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
## |
1029
|
|
|
|
|
|
|
## Change the tabs in the text field |
1030
|
|
|
|
|
|
|
## |
1031
|
|
|
|
|
|
|
sub setTabs { |
1032
|
|
|
|
|
|
|
|
1033
|
|
|
|
|
|
|
$DB::window->{'text'}->configure(-tabs => [ @_ ]) ; |
1034
|
|
|
|
|
|
|
|
1035
|
|
|
|
|
|
|
} |
1036
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
# |
1038
|
|
|
|
|
|
|
# User .ptkdbrc API |
1039
|
|
|
|
|
|
|
# allows the user to add expressions to |
1040
|
|
|
|
|
|
|
# the expression list window. |
1041
|
|
|
|
|
|
|
# |
1042
|
|
|
|
|
|
|
sub add_exprs { |
1043
|
|
|
|
|
|
|
push @{$DB::window->{'expr_list'}}, map { 'expr' => $_, 'depth' => $Devel::ptkdb::expr_depth }, @_ ; |
1044
|
|
|
|
|
|
|
} # end of add_exprs |
1045
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
## |
1048
|
|
|
|
|
|
|
## register a subroutine reference that will be called whenever |
1049
|
|
|
|
|
|
|
## ptkdb sets up it's windows |
1050
|
|
|
|
|
|
|
## |
1051
|
|
|
|
|
|
|
sub register_user_window_init { |
1052
|
|
|
|
|
|
|
push @{$DB::window->{'user_window_init_list'}}, @_ ; |
1053
|
|
|
|
|
|
|
} # end of register_user_window_init |
1054
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
## |
1056
|
|
|
|
|
|
|
## register a subroutine reference that will be called whenever |
1057
|
|
|
|
|
|
|
## ptkdb enters from code |
1058
|
|
|
|
|
|
|
## |
1059
|
|
|
|
|
|
|
sub register_user_DB_entry { |
1060
|
|
|
|
|
|
|
push @{$DB::window->{'user_window_DB_entry_list'}}, @_ ; |
1061
|
|
|
|
|
|
|
} # end of register_user_DB_entry |
1062
|
|
|
|
|
|
|
|
1063
|
|
|
|
|
|
|
sub get_notebook_widget { |
1064
|
|
|
|
|
|
|
return $DB::window->{'notebook'} ; |
1065
|
|
|
|
|
|
|
} # end of get_notebook_widget |
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
# |
1069
|
|
|
|
|
|
|
# Run files provided by the user |
1070
|
|
|
|
|
|
|
# |
1071
|
|
|
|
|
|
|
sub do_user_init_files { |
1072
|
|
|
|
|
|
|
use vars qw($dbg_window) ; |
1073
|
|
|
|
|
|
|
local $dbg_window = shift ; |
1074
|
|
|
|
|
|
|
|
1075
|
|
|
|
|
|
|
eval { |
1076
|
|
|
|
|
|
|
do "$Config{'installprivlib'}/Devel/ptkdbrc" ; |
1077
|
|
|
|
|
|
|
} if -e "$Config{'installprivlib'}/Devel/ptkdbrc" ; |
1078
|
|
|
|
|
|
|
|
1079
|
|
|
|
|
|
|
if( $@ ) { |
1080
|
|
|
|
|
|
|
print "System init file $Config{'installprivlib'}/ptkdbrc failed: $@\n" ; |
1081
|
|
|
|
|
|
|
} |
1082
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
eval { |
1084
|
|
|
|
|
|
|
do "$ENV{'HOME'}/.ptkdbrc" ; |
1085
|
|
|
|
|
|
|
} if exists $ENV{'HOME'} && -e "$ENV{'HOME'}/.ptkdbrc" ; |
1086
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
if( $@ ) { |
1088
|
|
|
|
|
|
|
print "User init file $ENV{'HOME'}/.ptkdbrc failed: $@\n" ; |
1089
|
|
|
|
|
|
|
} |
1090
|
|
|
|
|
|
|
|
1091
|
|
|
|
|
|
|
eval { |
1092
|
|
|
|
|
|
|
do ".ptkdbrc" ; |
1093
|
|
|
|
|
|
|
} if -e ".ptkdbrc" ; |
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
if( $@ ) { |
1096
|
|
|
|
|
|
|
print "User init file .ptkdbrc failed: $@\n" ; |
1097
|
|
|
|
|
|
|
} |
1098
|
|
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
&set_stop_on_warning() ; |
1100
|
|
|
|
|
|
|
} |
1101
|
|
|
|
|
|
|
|
1102
|
|
|
|
|
|
|
# |
1103
|
|
|
|
|
|
|
# Constructor for our Devel::ptkdb |
1104
|
|
|
|
|
|
|
# |
1105
|
|
|
|
|
|
|
sub new { |
1106
|
|
|
|
|
|
|
my($type) = @_ ; |
1107
|
|
|
|
|
|
|
my($self) = {} ; |
1108
|
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
bless $self, $type ; |
1110
|
|
|
|
|
|
|
|
1111
|
|
|
|
|
|
|
# Current position of the executing program |
1112
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
$self->{DisableOnLeave} = [] ; # List o' Widgets to disable when leaving the debugger |
1114
|
|
|
|
|
|
|
|
1115
|
|
|
|
|
|
|
$self->{current_file} = "" ; |
1116
|
|
|
|
|
|
|
$self->{current_line} = -1 ; # initial value indicating we haven't set our line/tag |
1117
|
|
|
|
|
|
|
$self->{window_pos_offset} = 10 ; # when we enter how far from the top of the text are we positioned down |
1118
|
|
|
|
|
|
|
$self->{search_start} = "0.0" ; |
1119
|
|
|
|
|
|
|
$self->{fwdOrBack} = 1 ; |
1120
|
|
|
|
|
|
|
$self->{BookMarksPath} = $ENV{'PTKDB_BOOKMARKS_PATH'} || "$ENV{'HOME'}/.ptkdb_bookmarks" || '.ptkdb_bookmarks' ; |
1121
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
$self->{'expr_list'} = [] ; # list of expressions to eval in our window fields: {'expr'} The expr itself {'depth'} expansion depth |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
$self->{'brkPtCnt'} = 0 ; |
1126
|
|
|
|
|
|
|
$self->{'brkPtSlots'} = [] ; # open slots for adding breakpoints to the table |
1127
|
|
|
|
|
|
|
|
1128
|
|
|
|
|
|
|
$self->{'main_window'} = undef ; |
1129
|
|
|
|
|
|
|
|
1130
|
|
|
|
|
|
|
$self->{'user_window_init_list'} = [] ; |
1131
|
|
|
|
|
|
|
$self->{'user_window_DB_entry_list'} = [] ; |
1132
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
$self->{'subs_list_cnt'} = 0 ; |
1134
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
$self->setup_main_window() ; |
1136
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
return $self ; |
1138
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
} # end of new |
1140
|
|
|
|
|
|
|
|
1141
|
|
|
|
|
|
|
sub setup_main_window { |
1142
|
|
|
|
|
|
|
my($self) = @_ ; |
1143
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
# Main Window |
1145
|
|
|
|
|
|
|
|
1146
|
|
|
|
|
|
|
|
1147
|
|
|
|
|
|
|
$self->{main_window} = MainWindow->new() ; |
1148
|
|
|
|
|
|
|
$self->{main_window}->geometry($ENV{'PTKDB_GEOMETRY'} || "800x600") ; |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
$self->setup_options() ; # must be done after MainWindow and before other frames are setup |
1151
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
$self->{main_window}->bind('', \&DB::dbint_handler) ; |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
# |
1155
|
|
|
|
|
|
|
# Bind our 'quit' routine to a close command from the window manager (Alt-F4) |
1156
|
|
|
|
|
|
|
# |
1157
|
|
|
|
|
|
|
$self->{main_window}->protocol('WM_DELETE_WINDOW', sub { $self->close_ptkdb_window() ; } ) ; |
1158
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
# Menu bar |
1160
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
$self->setup_menu_bar() ; |
1162
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
# |
1164
|
|
|
|
|
|
|
# setup Frames |
1165
|
|
|
|
|
|
|
# |
1166
|
|
|
|
|
|
|
# Setup our Code, Data, and breakpoints |
1167
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
$self->setup_frames() ; |
1169
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
} |
1171
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
# |
1173
|
|
|
|
|
|
|
# Check for changes to the bookmarks and quit |
1174
|
|
|
|
|
|
|
# |
1175
|
|
|
|
|
|
|
sub DoQuit { |
1176
|
|
|
|
|
|
|
my($self) = @_ ; |
1177
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
$self->save_bookmarks($self->{BookMarksPath}) if $Devel::ptkdb::DataDumperAvailable && $self->{'bookmarks_changed'}; |
1179
|
|
|
|
|
|
|
$self->{main_window}->destroy if $self->{main_window} ; |
1180
|
|
|
|
|
|
|
$self->{main_window} = undef if defined $self->{main_window} ; |
1181
|
|
|
|
|
|
|
|
1182
|
|
|
|
|
|
|
exit ; |
1183
|
|
|
|
|
|
|
} |
1184
|
|
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
# |
1186
|
|
|
|
|
|
|
# This supports the File -> Open menu item |
1187
|
|
|
|
|
|
|
# We create a new window and list all of the files |
1188
|
|
|
|
|
|
|
# that are contained in the program. We also |
1189
|
|
|
|
|
|
|
# pick up all of the perlTk files that are supporting |
1190
|
|
|
|
|
|
|
# the debugger. |
1191
|
|
|
|
|
|
|
# |
1192
|
|
|
|
|
|
|
sub DoOpen { |
1193
|
|
|
|
|
|
|
my $self = shift ; |
1194
|
|
|
|
|
|
|
my ($topLevel, $listBox, $frame, $selectedFile, @fList) ; |
1195
|
|
|
|
|
|
|
|
1196
|
|
|
|
|
|
|
# |
1197
|
|
|
|
|
|
|
# subroutine we call when we've selected a file |
1198
|
|
|
|
|
|
|
# |
1199
|
|
|
|
|
|
|
|
1200
|
|
|
|
|
|
|
my $chooseSub = sub { $selectedFile = $listBox->get('active') ; |
1201
|
|
|
|
|
|
|
print "attempting to open $selectedFile\n" ; |
1202
|
|
|
|
|
|
|
$DB::window->set_file($selectedFile, 0) ; |
1203
|
|
|
|
|
|
|
destroy $topLevel ; |
1204
|
|
|
|
|
|
|
} ; |
1205
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
# |
1207
|
|
|
|
|
|
|
# Take the list the files and resort it. |
1208
|
|
|
|
|
|
|
# we put all of the local files first, and |
1209
|
|
|
|
|
|
|
# then list all of the system libraries. |
1210
|
|
|
|
|
|
|
# |
1211
|
|
|
|
|
|
|
@fList = sort { |
1212
|
|
|
|
|
|
|
# sort comparison function block |
1213
|
|
|
|
|
|
|
my $fa = substr($a, 0, 1) ; |
1214
|
|
|
|
|
|
|
my $fb = substr($b, 0, 1) ; |
1215
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
return $a cmp $b if ($fa eq '/') && ($fb eq '/') ; |
1217
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
return -1 if ($fb eq '/') && ($fa ne '/') ; |
1219
|
|
|
|
|
|
|
return 1 if ($fa eq '/' ) && ($fb ne '/') ; |
1220
|
|
|
|
|
|
|
|
1221
|
|
|
|
|
|
|
return $a cmp $b ; |
1222
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
} grep s/^_/, keys %main:: ; |
1224
|
|
|
|
|
|
|
|
1225
|
|
|
|
|
|
|
# |
1226
|
|
|
|
|
|
|
# Create a list box with all of our files |
1227
|
|
|
|
|
|
|
# to select from |
1228
|
|
|
|
|
|
|
# |
1229
|
|
|
|
|
|
|
$topLevel = $self->{main_window}->Toplevel(-title => "File Select", -overanchor => 'cursor') ; |
1230
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
$listBox = $topLevel->Scrolled('Listbox', |
1232
|
|
|
|
|
|
|
@Devel::ptkdb::scrollbar_cfg, |
1233
|
|
|
|
|
|
|
@Devel::ptkdb::expression_text_font, |
1234
|
|
|
|
|
|
|
-width => 30)->pack(-side => 'top', -fill => 'both', -expand => 1) ; |
1235
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
# Bind a double click on the mouse button to the same action |
1238
|
|
|
|
|
|
|
# as pressing the Okay button |
1239
|
|
|
|
|
|
|
|
1240
|
|
|
|
|
|
|
$listBox->bind('' => $chooseSub) ; |
1241
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
$listBox->insert('end', @fList) ; |
1243
|
|
|
|
|
|
|
|
1244
|
|
|
|
|
|
|
$topLevel->Button( -text => "Okay", -command => $chooseSub, @Devel::ptkdb::button_font, |
1245
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
$topLevel->Button( -text => "Cancel", @Devel::ptkdb::button_font, |
1248
|
|
|
|
|
|
|
-command => sub { destroy $topLevel ; } )->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
1249
|
|
|
|
|
|
|
} # end of DoOpen |
1250
|
|
|
|
|
|
|
|
1251
|
|
|
|
|
|
|
sub do_tabs { |
1252
|
|
|
|
|
|
|
my($tabs_str) ; |
1253
|
|
|
|
|
|
|
my($w, $result, $tabs_cfg) ; |
1254
|
|
|
|
|
|
|
require Tk::Dialog ; |
1255
|
|
|
|
|
|
|
|
1256
|
|
|
|
|
|
|
$w = $DB::window->{'main_window'}->DialogBox(-title => "Tabs", -buttons => [qw/Okay Cancel/]) ; |
1257
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
$tabs_cfg = $DB::window->{'text'}->cget(-tabs) ; |
1259
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
$tabs_str = join " ", @$tabs_cfg if $tabs_cfg ; |
1261
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
$w->add('Label', -text => 'Tabs:')->pack(-side => 'left') ; |
1263
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
$w->add('Entry', -textvariable => \$tabs_str)->pack(-side => 'left')->selectionRange(0,'end') ; |
1265
|
|
|
|
|
|
|
|
1266
|
|
|
|
|
|
|
$result = $w->Show() ; |
1267
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
return unless $result eq 'Okay' ; |
1269
|
|
|
|
|
|
|
|
1270
|
|
|
|
|
|
|
$DB::window->{'text'}->configure(-tabs => [ split /\s/, $tabs_str ]) ; |
1271
|
|
|
|
|
|
|
} |
1272
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
sub close_ptkdb_window { |
1274
|
|
|
|
|
|
|
my($self) = @_ ; |
1275
|
|
|
|
|
|
|
|
1276
|
|
|
|
|
|
|
$DB::window->{'event'} = 'run' ; |
1277
|
|
|
|
|
|
|
$self->{current_file} = "" ; # force a file reset |
1278
|
|
|
|
|
|
|
$self->{'main_window'}->destroy ; |
1279
|
|
|
|
|
|
|
$self->{'main_window'} = undef ; |
1280
|
|
|
|
|
|
|
} |
1281
|
|
|
|
|
|
|
|
1282
|
|
|
|
|
|
|
sub setup_menu_bar { |
1283
|
|
|
|
|
|
|
my ($self) = @_ ; |
1284
|
|
|
|
|
|
|
my $mw = $self->{main_window} ; |
1285
|
|
|
|
|
|
|
my ($mb, $items) ; |
1286
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
# |
1288
|
|
|
|
|
|
|
# We have menu items/features that are not available if the Data::DataDumper module |
1289
|
|
|
|
|
|
|
# isn't present. For any feature that requires it we add this option list. |
1290
|
|
|
|
|
|
|
# |
1291
|
|
|
|
|
|
|
my @dataDumperEnableOpt = ( state => 'disabled' ) unless $Devel::ptkdb::DataDumperAvailable ; |
1292
|
|
|
|
|
|
|
|
1293
|
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
$self->{menu_bar} = $mw->Frame(-relief => 'raised', -borderwidth => '1')->pack(-side => 'top', -fill => 'x') ; |
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
$mb = $self->{menu_bar} ; |
1297
|
|
|
|
|
|
|
|
1298
|
|
|
|
|
|
|
# file menu in menu bar |
1299
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
$items = [ [ 'command' => 'About...', -command => sub { $self->DoAbout() ; } ], |
1301
|
|
|
|
|
|
|
[ 'command' => 'Bug Report...', -command => \&DoBugReport ], |
1302
|
|
|
|
|
|
|
"-", |
1303
|
|
|
|
|
|
|
|
1304
|
|
|
|
|
|
|
[ 'command' => 'Open', -accelerator => 'Alt+O', |
1305
|
|
|
|
|
|
|
-underline => 0, |
1306
|
|
|
|
|
|
|
-command => sub { $self->DoOpen() ; } ], |
1307
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
[ 'command' => 'Save Config...', |
1309
|
|
|
|
|
|
|
-underline => 0, |
1310
|
|
|
|
|
|
|
-command => \&DB::SaveState, |
1311
|
|
|
|
|
|
|
@dataDumperEnableOpt ], |
1312
|
|
|
|
|
|
|
|
1313
|
|
|
|
|
|
|
[ 'command' => 'Restore Config...', |
1314
|
|
|
|
|
|
|
-underline => 0, |
1315
|
|
|
|
|
|
|
-command => \&DB::RestoreState, |
1316
|
|
|
|
|
|
|
@dataDumperEnableOpt ], |
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
[ 'command' => 'Goto Line...', |
1319
|
|
|
|
|
|
|
-underline => 0, |
1320
|
|
|
|
|
|
|
-accelerator => 'Alt-g', |
1321
|
|
|
|
|
|
|
-command => sub { $self->GotoLine() ; }, |
1322
|
|
|
|
|
|
|
@dataDumperEnableOpt ] , |
1323
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
[ 'command' => 'Find Text...', |
1325
|
|
|
|
|
|
|
-accelerator => 'Ctrl-f', |
1326
|
|
|
|
|
|
|
-underline => 0, |
1327
|
|
|
|
|
|
|
-command => sub { $self->FindText() ; } ], |
1328
|
|
|
|
|
|
|
|
1329
|
|
|
|
|
|
|
[ 'command' => "Tabs...", -command => \&do_tabs ], |
1330
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
"-", |
1332
|
|
|
|
|
|
|
|
1333
|
|
|
|
|
|
|
[ 'command' => 'Close Window and Run', -accelerator => 'Alt+W', |
1334
|
|
|
|
|
|
|
-underline => 6, -command => sub { $self->close_ptkdb_window ; } ], |
1335
|
|
|
|
|
|
|
|
1336
|
|
|
|
|
|
|
[ 'command' => 'Quit...', -accelerator => 'Alt+Q', |
1337
|
|
|
|
|
|
|
-underline => 0, |
1338
|
|
|
|
|
|
|
-command => sub { $self->DoQuit } ] |
1339
|
|
|
|
|
|
|
] ; |
1340
|
|
|
|
|
|
|
|
1341
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
$mw->bind('' => sub { $self->GotoLine() ; }) ; |
1343
|
|
|
|
|
|
|
$mw->bind('' => sub { $self->FindText() ; }) ; |
1344
|
|
|
|
|
|
|
$mw->bind('' => \&Devel::ptkdb::DoRestart) ; |
1345
|
|
|
|
|
|
|
$mw->bind('' => sub { $self->{'event'} = 'quit' } ) ; |
1346
|
|
|
|
|
|
|
$mw->bind('' => sub { $self->close_ptkdb_window ; }) ; |
1347
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
$self->{file_menu_button} = $mb->Menubutton(-text => 'File', |
1349
|
|
|
|
|
|
|
-underline => 0, |
1350
|
|
|
|
|
|
|
-menuitems => $items |
1351
|
|
|
|
|
|
|
)->pack(-side =>, 'left', |
1352
|
|
|
|
|
|
|
-anchor => 'nw', |
1353
|
|
|
|
|
|
|
-padx => 2) ; |
1354
|
|
|
|
|
|
|
|
1355
|
|
|
|
|
|
|
# Control Menu |
1356
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
my $runSub = sub { $DB::step_over_depth = -1 ; $self->{'event'} = 'run' } ; |
1358
|
|
|
|
|
|
|
|
1359
|
|
|
|
|
|
|
my $runToSub = sub { $DB::window->{'event'} = 'run' if $DB::window->SetBreakPoint(1) ; } ; |
1360
|
|
|
|
|
|
|
|
1361
|
|
|
|
|
|
|
my $stepOverSub = sub { &DB::SetStepOverBreakPoint(0) ; |
1362
|
|
|
|
|
|
|
$DB::single = 1 ; |
1363
|
|
|
|
|
|
|
$DB::window->{'event'} = 'step' ; |
1364
|
|
|
|
|
|
|
} ; |
1365
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
|
1367
|
|
|
|
|
|
|
my $stepInSub = sub { |
1368
|
|
|
|
|
|
|
$DB::step_over_depth = -1 ; |
1369
|
|
|
|
|
|
|
$DB::single = 1 ; |
1370
|
|
|
|
|
|
|
$DB::window->{'event'} = 'step' ; } ; |
1371
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
|
1373
|
|
|
|
|
|
|
my $returnSub = sub { |
1374
|
|
|
|
|
|
|
&DB::SetStepOverBreakPoint(-1) ; |
1375
|
|
|
|
|
|
|
$self->{'event'} = 'run' ; |
1376
|
|
|
|
|
|
|
} ; |
1377
|
|
|
|
|
|
|
|
1378
|
|
|
|
|
|
|
|
1379
|
|
|
|
|
|
|
$items = [ [ 'command' => 'Run', -accelerator => 'Alt+r', -underline => 0, -command => $runSub ], |
1380
|
|
|
|
|
|
|
[ 'command' => 'Run To Here', -accelerator => 'Alt+t', -underline => 5, -command => $runToSub ], |
1381
|
|
|
|
|
|
|
'-', |
1382
|
|
|
|
|
|
|
[ 'command' => 'Set Breakpoint', -underline => 4, -command => sub { $self->SetBreakPoint ; }, -accelerator => 'Ctrl-b' ], |
1383
|
|
|
|
|
|
|
[ 'command' => 'Clear Breakpoint', -command => sub { $self->UnsetBreakPoint } ], |
1384
|
|
|
|
|
|
|
[ 'command' => 'Clear All Breakpoints', -underline => 6, -command => sub { |
1385
|
|
|
|
|
|
|
$DB::window->removeAllBreakpoints($DB::window->{current_file}) ; |
1386
|
|
|
|
|
|
|
&DB::clearalldblines() ; |
1387
|
|
|
|
|
|
|
} ], |
1388
|
|
|
|
|
|
|
'-', |
1389
|
|
|
|
|
|
|
[ 'command' => 'Step Over', -accelerator => 'Alt+N', -underline => 0, -command => $stepOverSub ], |
1390
|
|
|
|
|
|
|
[ 'command' => 'Step In', -accelerator => 'Alt+S', -underline => 5, -command => $stepInSub ], |
1391
|
|
|
|
|
|
|
[ 'command' => 'Return', -accelerator => 'Alt+U', -underline => 3, -command => $returnSub ], |
1392
|
|
|
|
|
|
|
'-', |
1393
|
|
|
|
|
|
|
[ 'command' => 'Restart...', -accelerator => 'Ctrl-r', -underline => 0, -command => \&Devel::ptkdb::DoRestart ], |
1394
|
|
|
|
|
|
|
'-', |
1395
|
|
|
|
|
|
|
[ 'checkbutton' => 'Stop On Warning', -variable => \$DB::ptkdb::stop_on_warning, -command => \&set_stop_on_warning ] |
1396
|
|
|
|
|
|
|
|
1397
|
|
|
|
|
|
|
|
1398
|
|
|
|
|
|
|
] ; # end of control menu items |
1399
|
|
|
|
|
|
|
|
1400
|
|
|
|
|
|
|
|
1401
|
|
|
|
|
|
|
$self->{control_menu_button} = $mb->Menubutton(-text => 'Control', |
1402
|
|
|
|
|
|
|
-underline => 0, |
1403
|
|
|
|
|
|
|
-menuitems => $items, |
1404
|
|
|
|
|
|
|
)->pack(-side =>, 'left', |
1405
|
|
|
|
|
|
|
-padx => 2) ; |
1406
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
|
1408
|
|
|
|
|
|
|
$mw->bind('' => $runSub) ; |
1409
|
|
|
|
|
|
|
$mw->bind('', $runToSub) ; |
1410
|
|
|
|
|
|
|
$mw->bind('', sub { $self->SetBreakPoint ; }) ; |
1411
|
|
|
|
|
|
|
|
1412
|
|
|
|
|
|
|
for( @Devel::ptkdb::step_over_keys ) { |
1413
|
|
|
|
|
|
|
$mw->bind($_ => $stepOverSub ); |
1414
|
|
|
|
|
|
|
} |
1415
|
|
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
for( @Devel::ptkdb::step_in_keys ) { |
1417
|
|
|
|
|
|
|
$mw->bind($_ => $stepInSub ); |
1418
|
|
|
|
|
|
|
} |
1419
|
|
|
|
|
|
|
|
1420
|
|
|
|
|
|
|
for( @Devel::ptkdb::return_keys ) { |
1421
|
|
|
|
|
|
|
$mw->bind($_ => $returnSub ); |
1422
|
|
|
|
|
|
|
} |
1423
|
|
|
|
|
|
|
|
1424
|
|
|
|
|
|
|
# Data Menu |
1425
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
$items = [ [ 'command' => 'Enter Expression', -accelerator => 'Alt+E', -command => sub { $self->EnterExpr() } ], |
1427
|
|
|
|
|
|
|
[ 'command' => 'Delete Expression', -accelerator => 'Ctrl+D', -command => sub { $self->deleteExpr() } ], |
1428
|
|
|
|
|
|
|
[ 'command' => 'Delete All Expressions', -command => sub { |
1429
|
|
|
|
|
|
|
$self->deleteAllExprs() ; |
1430
|
|
|
|
|
|
|
$self->{'expr_list'} = [] ; # clears list by dropping ref to it, replacing it with a new one |
1431
|
|
|
|
|
|
|
} ], |
1432
|
|
|
|
|
|
|
'-', |
1433
|
|
|
|
|
|
|
[ 'command' => 'Expression Eval Window...', -accelerator => 'F8', -command => sub { $self->setupEvalWindow() ; } ], |
1434
|
|
|
|
|
|
|
[ 'checkbutton' => "Use DataDumper for Eval Window?", -variable => \$Devel::ptkdb::useDataDumperForEval, @dataDumperEnableOpt ] |
1435
|
|
|
|
|
|
|
] ; |
1436
|
|
|
|
|
|
|
|
1437
|
|
|
|
|
|
|
|
1438
|
|
|
|
|
|
|
$self->{data_menu_button} = $mb->Menubutton(-text => 'Data', -menuitems => $items, |
1439
|
|
|
|
|
|
|
-underline => 0, |
1440
|
|
|
|
|
|
|
)->pack(-side => 'left', |
1441
|
|
|
|
|
|
|
-padx => 2) ; |
1442
|
|
|
|
|
|
|
|
1443
|
|
|
|
|
|
|
$mw->bind('' => sub { $self->EnterExpr() } ) ; |
1444
|
|
|
|
|
|
|
$mw->bind('' => sub { $self->deleteExpr() } ); |
1445
|
|
|
|
|
|
|
$mw->bind('', sub { $self->setupEvalWindow() ; }) ; |
1446
|
|
|
|
|
|
|
# |
1447
|
|
|
|
|
|
|
# Stack menu |
1448
|
|
|
|
|
|
|
# |
1449
|
|
|
|
|
|
|
$self->{stack_menu} = $mb->Menubutton(-text => 'Stack', |
1450
|
|
|
|
|
|
|
-underline => 2, |
1451
|
|
|
|
|
|
|
)->pack(-side => 'left', |
1452
|
|
|
|
|
|
|
-padx => 2) ; |
1453
|
|
|
|
|
|
|
|
1454
|
|
|
|
|
|
|
# |
1455
|
|
|
|
|
|
|
# Bookmarks menu |
1456
|
|
|
|
|
|
|
# |
1457
|
|
|
|
|
|
|
$self->{bookmarks_menu} = $mb->Menubutton(-text => 'Bookmarks', |
1458
|
|
|
|
|
|
|
-underline => 0, |
1459
|
|
|
|
|
|
|
@dataDumperEnableOpt |
1460
|
|
|
|
|
|
|
)->pack(-side => 'left', |
1461
|
|
|
|
|
|
|
-padx => 2) ; |
1462
|
|
|
|
|
|
|
$self->setup_bookmarks_menu() ; |
1463
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
# |
1465
|
|
|
|
|
|
|
# Windows Menu |
1466
|
|
|
|
|
|
|
# |
1467
|
|
|
|
|
|
|
my($bsub) = sub { $self->{'text'}->focus() } ; |
1468
|
|
|
|
|
|
|
my($csub) = sub { $self->{'quick_entry'}->focus() } ; |
1469
|
|
|
|
|
|
|
my($dsub) = sub { $self->{'entry'}->focus() } ; |
1470
|
|
|
|
|
|
|
|
1471
|
|
|
|
|
|
|
$items = [ [ 'command' => 'Code Pane', -accelerator => 'Alt+0', -command => $bsub ], |
1472
|
|
|
|
|
|
|
[ 'command' => 'Quick Entry', -accelerator => 'F9', -command => $csub ], |
1473
|
|
|
|
|
|
|
[ 'command' => 'Expr Entry', -accelerator => 'F11', -command => $dsub ] |
1474
|
|
|
|
|
|
|
] ; |
1475
|
|
|
|
|
|
|
|
1476
|
|
|
|
|
|
|
$mb->Menubutton(-text => 'Windows', -menuitems => $items |
1477
|
|
|
|
|
|
|
)->pack(-side => 'left', |
1478
|
|
|
|
|
|
|
-padx => 2) ; |
1479
|
|
|
|
|
|
|
|
1480
|
|
|
|
|
|
|
$mw->bind('', $bsub) ; |
1481
|
|
|
|
|
|
|
$mw->bind('', $csub) ; |
1482
|
|
|
|
|
|
|
$mw->bind('', $dsub) ; |
1483
|
|
|
|
|
|
|
|
1484
|
|
|
|
|
|
|
# |
1485
|
|
|
|
|
|
|
# Bar for some popular controls |
1486
|
|
|
|
|
|
|
# |
1487
|
|
|
|
|
|
|
|
1488
|
|
|
|
|
|
|
$self->{button_bar} = $mw->Frame()->pack(-side => 'top') ; |
1489
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
$self->{stepin_button} = $self->{button_bar}->Button(-text, => "Step In", @Devel::ptkdb::button_font, |
1491
|
|
|
|
|
|
|
-command => $stepInSub) ; |
1492
|
|
|
|
|
|
|
$self->{stepin_button}->pack(-side => 'left') ; |
1493
|
|
|
|
|
|
|
|
1494
|
|
|
|
|
|
|
$self->{stepover_button} = $self->{button_bar}->Button(-text, => "Step Over", @Devel::ptkdb::button_font, |
1495
|
|
|
|
|
|
|
-command => $stepOverSub) ; |
1496
|
|
|
|
|
|
|
$self->{stepover_button}->pack(-side => 'left') ; |
1497
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
$self->{return_button} = $self->{button_bar}->Button(-text, => "Return", @Devel::ptkdb::button_font, |
1499
|
|
|
|
|
|
|
-command => $returnSub) ; |
1500
|
|
|
|
|
|
|
$self->{return_button}->pack(-side => 'left') ; |
1501
|
|
|
|
|
|
|
|
1502
|
|
|
|
|
|
|
$self->{run_button} = $self->{button_bar}->Button(-background => 'green', -text, => "Run", @Devel::ptkdb::button_font, |
1503
|
|
|
|
|
|
|
-command => $runSub) ; |
1504
|
|
|
|
|
|
|
$self->{run_button}->pack(-side => 'left') ; |
1505
|
|
|
|
|
|
|
|
1506
|
|
|
|
|
|
|
$self->{run_to_button} = $self->{button_bar}->Button(-text, => "Run To", @Devel::ptkdb::button_font, |
1507
|
|
|
|
|
|
|
-command => $runToSub) ; |
1508
|
|
|
|
|
|
|
$self->{run_to_button}->pack(-side => 'left') ; |
1509
|
|
|
|
|
|
|
|
1510
|
|
|
|
|
|
|
$self->{breakpt_button} = $self->{button_bar}->Button(-text, => "Break", @Devel::ptkdb::button_font, |
1511
|
|
|
|
|
|
|
-command => sub { $self->SetBreakPoint ; } ) ; |
1512
|
|
|
|
|
|
|
$self->{breakpt_button}->pack(-side => 'left') ; |
1513
|
|
|
|
|
|
|
|
1514
|
|
|
|
|
|
|
push @{$self->{DisableOnLeave}}, @$self{'stepin_button', 'stepover_button', 'return_button', 'run_button', 'run_to_button', 'breakpt_button'} ; |
1515
|
|
|
|
|
|
|
|
1516
|
|
|
|
|
|
|
} # end of setup_menu_bar |
1517
|
|
|
|
|
|
|
|
1518
|
|
|
|
|
|
|
sub edit_bookmarks { |
1519
|
|
|
|
|
|
|
my ($self) = @_ ; |
1520
|
|
|
|
|
|
|
|
1521
|
|
|
|
|
|
|
my ($top) = $self->{main_window}->Toplevel(-title => "Edit Bookmarks") ; |
1522
|
|
|
|
|
|
|
|
1523
|
|
|
|
|
|
|
my $list = $top->Scrolled('Listbox', -selectmode => 'multiple')->pack(-side => 'top', -fill => 'both', -expand => 1) ; |
1524
|
|
|
|
|
|
|
|
1525
|
|
|
|
|
|
|
my $deleteSub = sub { |
1526
|
|
|
|
|
|
|
my $cnt = 0 ; |
1527
|
|
|
|
|
|
|
for( $list->curselection ) { |
1528
|
|
|
|
|
|
|
$list->delete($_ - $cnt++) ; |
1529
|
|
|
|
|
|
|
} |
1530
|
|
|
|
|
|
|
} ; |
1531
|
|
|
|
|
|
|
|
1532
|
|
|
|
|
|
|
my $okaySub = sub { |
1533
|
|
|
|
|
|
|
$self->{'bookmarks'} = [ $list->get(0, 'end') ] ; # replace the bookmarks |
1534
|
|
|
|
|
|
|
} ; |
1535
|
|
|
|
|
|
|
|
1536
|
|
|
|
|
|
|
my $frm = $top->Frame()->pack(-side => 'top', -fill => 'x', -expand => 1 ) ; |
1537
|
|
|
|
|
|
|
|
1538
|
|
|
|
|
|
|
my $deleteBtn = $frm->Button(-text => 'Delete', -command => $deleteSub)->pack(-side => 'left', -fill => 'x', -expand => 1 ) ; |
1539
|
|
|
|
|
|
|
my $cancelBtn = $frm->Button(-text => 'Cancel', -command => sub { destroy $top ; })->pack(-side =>'left', -fill => 'x', -expand => 1 ) ; |
1540
|
|
|
|
|
|
|
my $dismissBtn = $frm->Button(-text => 'Okay', -command => $okaySub)->pack(-side => 'left', -fill => 'x', -expand => 1 ) ; |
1541
|
|
|
|
|
|
|
|
1542
|
|
|
|
|
|
|
$list->insert('end', @{$self->{'bookmarks'}}) ; |
1543
|
|
|
|
|
|
|
|
1544
|
|
|
|
|
|
|
} # end of edit_bookmarks |
1545
|
|
|
|
|
|
|
|
1546
|
|
|
|
|
|
|
sub setup_bookmarks_menu { |
1547
|
|
|
|
|
|
|
my ($self) = @_ ; |
1548
|
|
|
|
|
|
|
|
1549
|
|
|
|
|
|
|
# |
1550
|
|
|
|
|
|
|
# "Add bookmark" item |
1551
|
|
|
|
|
|
|
# |
1552
|
|
|
|
|
|
|
my $bkMarkSub = sub { $self->add_bookmark() ; } ; |
1553
|
|
|
|
|
|
|
|
1554
|
|
|
|
|
|
|
$self->{'bookmarks_menu'}->command(-label => "Add Bookmark", |
1555
|
|
|
|
|
|
|
-accelerator => 'Alt+k', |
1556
|
|
|
|
|
|
|
-command => $bkMarkSub |
1557
|
|
|
|
|
|
|
) ; |
1558
|
|
|
|
|
|
|
|
1559
|
|
|
|
|
|
|
$self->{'main_window'}->bind('', $bkMarkSub) ; |
1560
|
|
|
|
|
|
|
|
1561
|
|
|
|
|
|
|
$self->{'bookmarks_menu'}->command(-label => "Edit Bookmarks", |
1562
|
|
|
|
|
|
|
-command => sub { $self->edit_bookmarks() } ) ; |
1563
|
|
|
|
|
|
|
|
1564
|
|
|
|
|
|
|
$self->{'bookmarks_menu'}->separator() ; |
1565
|
|
|
|
|
|
|
|
1566
|
|
|
|
|
|
|
# |
1567
|
|
|
|
|
|
|
# Check to see if there is a bookmarks file |
1568
|
|
|
|
|
|
|
# |
1569
|
|
|
|
|
|
|
return unless -e $self->{BookMarksPath} && -r $self->{BookMarksPath} ; |
1570
|
|
|
|
|
|
|
|
1571
|
|
|
|
|
|
|
use vars qw($ptkdb_bookmarks) ; |
1572
|
|
|
|
|
|
|
local($ptkdb_bookmarks) ; # ref to hash of bookmark entries |
1573
|
|
|
|
|
|
|
|
1574
|
|
|
|
|
|
|
do $self->{BookMarksPath} ; # eval the file |
1575
|
|
|
|
|
|
|
|
1576
|
|
|
|
|
|
|
$self->add_bookmark_items(@$ptkdb_bookmarks) ; |
1577
|
|
|
|
|
|
|
|
1578
|
|
|
|
|
|
|
} # end of setup_bookmarks_menu |
1579
|
|
|
|
|
|
|
|
1580
|
|
|
|
|
|
|
# |
1581
|
|
|
|
|
|
|
# $item = "$fname:$lineno" |
1582
|
|
|
|
|
|
|
# |
1583
|
|
|
|
|
|
|
sub add_bookmark_items { |
1584
|
|
|
|
|
|
|
my($self, @items) = @_ ; |
1585
|
|
|
|
|
|
|
my($menu) = ( $self->{'bookmarks_menu'} ) ; |
1586
|
|
|
|
|
|
|
|
1587
|
|
|
|
|
|
|
$self->{'bookmarks_changed'} = 1 ; |
1588
|
|
|
|
|
|
|
|
1589
|
|
|
|
|
|
|
for( @items ) { |
1590
|
|
|
|
|
|
|
my $item = $_ ; |
1591
|
|
|
|
|
|
|
$menu->command( -label => $_, |
1592
|
|
|
|
|
|
|
-command => sub { $self->bookmark_cmd($item) }) ; |
1593
|
|
|
|
|
|
|
push @{$self->{'bookmarks'}}, $item ; |
1594
|
|
|
|
|
|
|
} |
1595
|
|
|
|
|
|
|
} # end of add_bookmark_item |
1596
|
|
|
|
|
|
|
|
1597
|
|
|
|
|
|
|
# |
1598
|
|
|
|
|
|
|
# Invoked from the "Add Bookmark" command |
1599
|
|
|
|
|
|
|
# |
1600
|
|
|
|
|
|
|
sub add_bookmark { |
1601
|
|
|
|
|
|
|
my($self) = @_ ; |
1602
|
|
|
|
|
|
|
|
1603
|
|
|
|
|
|
|
my $line = $self->get_lineno() ; |
1604
|
|
|
|
|
|
|
my $fname = $self->{'current_file'} ; |
1605
|
|
|
|
|
|
|
$self->add_bookmark_items("$fname:$line") ; |
1606
|
|
|
|
|
|
|
|
1607
|
|
|
|
|
|
|
} # end of add_bookmark |
1608
|
|
|
|
|
|
|
|
1609
|
|
|
|
|
|
|
# |
1610
|
|
|
|
|
|
|
# Command executed when someone selects |
1611
|
|
|
|
|
|
|
# a bookmark |
1612
|
|
|
|
|
|
|
# |
1613
|
|
|
|
|
|
|
sub bookmark_cmd { |
1614
|
|
|
|
|
|
|
my ($self, $item) = @_ ; |
1615
|
|
|
|
|
|
|
|
1616
|
|
|
|
|
|
|
$item =~ /(.*):([0-9]+)$/ ; |
1617
|
|
|
|
|
|
|
|
1618
|
|
|
|
|
|
|
$self->set_file($1,$2) ; |
1619
|
|
|
|
|
|
|
|
1620
|
|
|
|
|
|
|
} # end of bookmark_cmd |
1621
|
|
|
|
|
|
|
|
1622
|
|
|
|
|
|
|
sub save_bookmarks { |
1623
|
|
|
|
|
|
|
my($self, $pathName) = @_ ; |
1624
|
|
|
|
|
|
|
|
1625
|
|
|
|
|
|
|
return unless $Devel::ptkdb::DataDumperAvailable ; # we can't save without the data dumper |
1626
|
|
|
|
|
|
|
local(*F) ; |
1627
|
|
|
|
|
|
|
|
1628
|
|
|
|
|
|
|
eval { |
1629
|
|
|
|
|
|
|
open F, ">$pathName" || die "open failed" ; |
1630
|
|
|
|
|
|
|
my $d = Data::Dumper->new([ $self->{'bookmarks'} ], |
1631
|
|
|
|
|
|
|
[ 'ptkdb_bookmarks' ]) ; |
1632
|
|
|
|
|
|
|
|
1633
|
|
|
|
|
|
|
$d->Indent(2) ; # make it more editable for people |
1634
|
|
|
|
|
|
|
|
1635
|
|
|
|
|
|
|
my $str ; |
1636
|
|
|
|
|
|
|
if( $d->can('Dumpxs') ) { |
1637
|
|
|
|
|
|
|
$str = $d->Dumpxs() ; |
1638
|
|
|
|
|
|
|
} |
1639
|
|
|
|
|
|
|
else { |
1640
|
|
|
|
|
|
|
$str = $d->Dump() ; |
1641
|
|
|
|
|
|
|
} |
1642
|
|
|
|
|
|
|
|
1643
|
|
|
|
|
|
|
print F $str || die "outputing bookmarks failed" ; |
1644
|
|
|
|
|
|
|
close(F) ; |
1645
|
|
|
|
|
|
|
} ; |
1646
|
|
|
|
|
|
|
|
1647
|
|
|
|
|
|
|
if( $@ ) { |
1648
|
|
|
|
|
|
|
$self->DoAlert("Couldn't save bookmarks file $@") ; |
1649
|
|
|
|
|
|
|
return ; |
1650
|
|
|
|
|
|
|
} |
1651
|
|
|
|
|
|
|
|
1652
|
|
|
|
|
|
|
} # end of save_bookmarks |
1653
|
|
|
|
|
|
|
|
1654
|
|
|
|
|
|
|
# |
1655
|
|
|
|
|
|
|
# This is our callback from a double click in our |
1656
|
|
|
|
|
|
|
# HList. A click in an expanded item will delete |
1657
|
|
|
|
|
|
|
# the children beneath it, and the next time it |
1658
|
|
|
|
|
|
|
# updates, it will only update that entry to that |
1659
|
|
|
|
|
|
|
# depth. If an item is 'unexpanded' such as |
1660
|
|
|
|
|
|
|
# a hash or a list, it will expand it one more |
1661
|
|
|
|
|
|
|
# level. How much further an item is expanded is |
1662
|
|
|
|
|
|
|
# controled by package variable $Devel::ptkdb::add_expr_depth |
1663
|
|
|
|
|
|
|
# |
1664
|
|
|
|
|
|
|
sub expr_expand { |
1665
|
|
|
|
|
|
|
my ($path) = @_ ; |
1666
|
|
|
|
|
|
|
my $hl = $DB::window->{'data_list'} ; |
1667
|
|
|
|
|
|
|
my ($parent, $root, $index, @children, $depth) ; |
1668
|
|
|
|
|
|
|
|
1669
|
|
|
|
|
|
|
$parent = $path ; |
1670
|
|
|
|
|
|
|
$root = $path ; |
1671
|
|
|
|
|
|
|
$depth = 0 ; |
1672
|
|
|
|
|
|
|
|
1673
|
|
|
|
|
|
|
for( $root = $path ; defined $parent && $parent ne "" ; $parent = $hl->infoParent($root) ) { |
1674
|
|
|
|
|
|
|
$root = $parent ; |
1675
|
|
|
|
|
|
|
$depth += 1 ; |
1676
|
|
|
|
|
|
|
} #end of root search |
1677
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
# |
1679
|
|
|
|
|
|
|
# Determine the index of the root of our expression |
1680
|
|
|
|
|
|
|
# |
1681
|
|
|
|
|
|
|
$index = 0 ; |
1682
|
|
|
|
|
|
|
for( @{$DB::window->{'expr_list'}} ) { |
1683
|
|
|
|
|
|
|
last if $_->{'expr'} eq $root ; |
1684
|
|
|
|
|
|
|
$index += 1 ; |
1685
|
|
|
|
|
|
|
} |
1686
|
|
|
|
|
|
|
|
1687
|
|
|
|
|
|
|
# |
1688
|
|
|
|
|
|
|
# if we have children we're going to delete them |
1689
|
|
|
|
|
|
|
# |
1690
|
|
|
|
|
|
|
|
1691
|
|
|
|
|
|
|
@children = $hl->infoChildren($path) ; |
1692
|
|
|
|
|
|
|
|
1693
|
|
|
|
|
|
|
if( scalar @children > 0 ) { |
1694
|
|
|
|
|
|
|
|
1695
|
|
|
|
|
|
|
$hl->deleteOffsprings($path) ; |
1696
|
|
|
|
|
|
|
|
1697
|
|
|
|
|
|
|
$DB::window->{'expr_list'}->[$index]->{'depth'} = $depth - 1 ; # adjust our depth |
1698
|
|
|
|
|
|
|
} |
1699
|
|
|
|
|
|
|
else { |
1700
|
|
|
|
|
|
|
# |
1701
|
|
|
|
|
|
|
# Delete the existing tree and insert a new one |
1702
|
|
|
|
|
|
|
# |
1703
|
|
|
|
|
|
|
$hl->deleteEntry($root) ; |
1704
|
|
|
|
|
|
|
$hl->add($root, -at => $index) ; |
1705
|
|
|
|
|
|
|
$DB::window->{'expr_list'}->[$index]->{'depth'} += $Devel::ptkdb::add_expr_depth ; |
1706
|
|
|
|
|
|
|
# |
1707
|
|
|
|
|
|
|
# Force an update on our expressions |
1708
|
|
|
|
|
|
|
# |
1709
|
|
|
|
|
|
|
$DB::window->{'event'} = 'update' ; |
1710
|
|
|
|
|
|
|
} |
1711
|
|
|
|
|
|
|
} # end of expr_expand |
1712
|
|
|
|
|
|
|
|
1713
|
|
|
|
|
|
|
sub line_number_from_coord { |
1714
|
|
|
|
|
|
|
my($txtWidget, $coord) = @_ ; |
1715
|
|
|
|
|
|
|
my($index) ; |
1716
|
|
|
|
|
|
|
|
1717
|
|
|
|
|
|
|
$index = $txtWidget->index($coord) ; |
1718
|
|
|
|
|
|
|
|
1719
|
|
|
|
|
|
|
# index is in the format of lineno.column |
1720
|
|
|
|
|
|
|
|
1721
|
|
|
|
|
|
|
$index =~ /([0-9]*)\.([0-9]*)/o ; |
1722
|
|
|
|
|
|
|
|
1723
|
|
|
|
|
|
|
# |
1724
|
|
|
|
|
|
|
# return a list of (col, line). Why |
1725
|
|
|
|
|
|
|
# backwards? |
1726
|
|
|
|
|
|
|
# |
1727
|
|
|
|
|
|
|
|
1728
|
|
|
|
|
|
|
return ($2 ,$1) ; |
1729
|
|
|
|
|
|
|
|
1730
|
|
|
|
|
|
|
} # end of line_number_from_coord |
1731
|
|
|
|
|
|
|
|
1732
|
|
|
|
|
|
|
# |
1733
|
|
|
|
|
|
|
# It may seem as if $txtWidget and $self are |
1734
|
|
|
|
|
|
|
# erroneously reversed, but this is a result |
1735
|
|
|
|
|
|
|
# of the calling syntax of the text-bind callback. |
1736
|
|
|
|
|
|
|
# |
1737
|
|
|
|
|
|
|
sub set_breakpoint_tag { |
1738
|
|
|
|
|
|
|
my($txtWidget, $self, $coord, $value) = @_ ; |
1739
|
|
|
|
|
|
|
my($idx) ; |
1740
|
|
|
|
|
|
|
|
1741
|
|
|
|
|
|
|
$idx = line_number_from_coord($txtWidget, $coord) ; |
1742
|
|
|
|
|
|
|
|
1743
|
|
|
|
|
|
|
$self->insertBreakpoint($self->{'current_file'}, $idx, $value) ; |
1744
|
|
|
|
|
|
|
|
1745
|
|
|
|
|
|
|
} # end of set_breakpoint_tag |
1746
|
|
|
|
|
|
|
|
1747
|
|
|
|
|
|
|
sub clear_breakpoint_tag { |
1748
|
|
|
|
|
|
|
my($txtWidget, $self, $coord) = @_ ; |
1749
|
|
|
|
|
|
|
my($idx) ; |
1750
|
|
|
|
|
|
|
|
1751
|
|
|
|
|
|
|
$idx = line_number_from_coord($txtWidget, $coord) ; |
1752
|
|
|
|
|
|
|
|
1753
|
|
|
|
|
|
|
$self->removeBreakpoint($self->{'current_file'}, $idx) ; |
1754
|
|
|
|
|
|
|
|
1755
|
|
|
|
|
|
|
} # end of clear_breakpoint_tag |
1756
|
|
|
|
|
|
|
|
1757
|
|
|
|
|
|
|
sub change_breakpoint_tag { |
1758
|
|
|
|
|
|
|
my($txtWidget, $self, $coord, $value) = @_ ; |
1759
|
|
|
|
|
|
|
my($idx, $brkPt, @tagSet) ; |
1760
|
|
|
|
|
|
|
|
1761
|
|
|
|
|
|
|
$idx = line_number_from_coord($txtWidget, $coord) ; |
1762
|
|
|
|
|
|
|
|
1763
|
|
|
|
|
|
|
# |
1764
|
|
|
|
|
|
|
# Change the value of the breakpoint |
1765
|
|
|
|
|
|
|
# |
1766
|
|
|
|
|
|
|
@tagSet = ( "$idx.0", "$idx.$Devel::ptkdb::linenumber_length" ) ; |
1767
|
|
|
|
|
|
|
|
1768
|
|
|
|
|
|
|
$brkPt = &DB::getdbline($self->{'current_file'}, $idx + $self->{'line_offset'}) ; |
1769
|
|
|
|
|
|
|
return unless $brkPt ; |
1770
|
|
|
|
|
|
|
|
1771
|
|
|
|
|
|
|
# |
1772
|
|
|
|
|
|
|
# Check the breakpoint tag |
1773
|
|
|
|
|
|
|
# |
1774
|
|
|
|
|
|
|
|
1775
|
|
|
|
|
|
|
if ( $txtWidget ) { |
1776
|
|
|
|
|
|
|
$txtWidget->tagRemove('breaksetLine', @tagSet ) ; |
1777
|
|
|
|
|
|
|
$txtWidget->tagRemove('breakdisabledLine', @tagSet ) ; |
1778
|
|
|
|
|
|
|
} |
1779
|
|
|
|
|
|
|
|
1780
|
|
|
|
|
|
|
$brkPt->{'value'} = $value ; |
1781
|
|
|
|
|
|
|
|
1782
|
|
|
|
|
|
|
if ( $txtWidget ) { |
1783
|
|
|
|
|
|
|
if ( $brkPt->{'value'} ) { |
1784
|
|
|
|
|
|
|
$txtWidget->tagAdd('breaksetLine', @tagSet ) ; |
1785
|
|
|
|
|
|
|
} |
1786
|
|
|
|
|
|
|
else { |
1787
|
|
|
|
|
|
|
$txtWidget->tagAdd('breakdisabledLine', @tagSet ) ; |
1788
|
|
|
|
|
|
|
} |
1789
|
|
|
|
|
|
|
} |
1790
|
|
|
|
|
|
|
|
1791
|
|
|
|
|
|
|
} # end of change_breakpoint_tag |
1792
|
|
|
|
|
|
|
|
1793
|
|
|
|
|
|
|
# |
1794
|
|
|
|
|
|
|
# God Forbid anyone comment something complex and tightly optimized. |
1795
|
|
|
|
|
|
|
# |
1796
|
|
|
|
|
|
|
# We can get a list of the subroutines from the interpreter |
1797
|
|
|
|
|
|
|
# by querrying the *DB::sub typeglob: keys %DB::sub |
1798
|
|
|
|
|
|
|
# |
1799
|
|
|
|
|
|
|
# The list appears broken down by module: |
1800
|
|
|
|
|
|
|
# |
1801
|
|
|
|
|
|
|
# main::BEGIN |
1802
|
|
|
|
|
|
|
# main::mySub |
1803
|
|
|
|
|
|
|
# main::otherSub |
1804
|
|
|
|
|
|
|
# Tk::Adjuster::Mapped |
1805
|
|
|
|
|
|
|
# Tk::Adjuster::Packed |
1806
|
|
|
|
|
|
|
# Tk::Button::BEGIN |
1807
|
|
|
|
|
|
|
# Tk::Button::Enter |
1808
|
|
|
|
|
|
|
# |
1809
|
|
|
|
|
|
|
# We would like to break this list down into a heirarchy. |
1810
|
|
|
|
|
|
|
# |
1811
|
|
|
|
|
|
|
# main Tk |
1812
|
|
|
|
|
|
|
# | | | | |
1813
|
|
|
|
|
|
|
# BEGIN mySub OtherSub | | |
1814
|
|
|
|
|
|
|
# Adjuster Button |
1815
|
|
|
|
|
|
|
# | | | | |
1816
|
|
|
|
|
|
|
# Mapped Packed BEGIN Enter |
1817
|
|
|
|
|
|
|
# |
1818
|
|
|
|
|
|
|
# |
1819
|
|
|
|
|
|
|
# We translate this list into a heirarchy of hashes(say three times fast). |
1820
|
|
|
|
|
|
|
# We take each entry and split it into elements. Each element is a leaf in the tree. |
1821
|
|
|
|
|
|
|
# We traverse the tree with the inner for loop. |
1822
|
|
|
|
|
|
|
# With each branch we check to see if it already exists or |
1823
|
|
|
|
|
|
|
# we create it. When we reach the last element, this becomes our entry. |
1824
|
|
|
|
|
|
|
# |
1825
|
|
|
|
|
|
|
|
1826
|
|
|
|
|
|
|
# |
1827
|
|
|
|
|
|
|
# An incoming list is potentially 'large' so we |
1828
|
|
|
|
|
|
|
# pass in the ref to it instead. |
1829
|
|
|
|
|
|
|
# |
1830
|
|
|
|
|
|
|
# New entries can be inserted by providing a $topH |
1831
|
|
|
|
|
|
|
# hash ref to an existing tree. |
1832
|
|
|
|
|
|
|
# |
1833
|
|
|
|
|
|
|
sub tree_split { |
1834
|
|
|
|
|
|
|
my ($listRef, $separator, $topH) = @_ ; |
1835
|
|
|
|
|
|
|
my ($h, $list_elem) ; |
1836
|
|
|
|
|
|
|
|
1837
|
|
|
|
|
|
|
$topH = {} unless $topH ; |
1838
|
|
|
|
|
|
|
|
1839
|
|
|
|
|
|
|
foreach $list_elem ( @$listRef ) { |
1840
|
|
|
|
|
|
|
$h = $topH ; |
1841
|
|
|
|
|
|
|
for( split /$separator/o, $list_elem ) { # Tk::Adjuster::Mapped -> ( Tk Adjuster Mapped ) |
1842
|
|
|
|
|
|
|
$h->{$_} or $h->{$_} = {} ; # either we have an entry for this OR we create one |
1843
|
|
|
|
|
|
|
$h = $h->{$_} ; |
1844
|
|
|
|
|
|
|
} |
1845
|
|
|
|
|
|
|
@$h{'name', 'path'} = ($_, $list_elem) ; # the last leaf is our entry |
1846
|
|
|
|
|
|
|
} # end of tree_split loop |
1847
|
|
|
|
|
|
|
|
1848
|
|
|
|
|
|
|
return $topH ; |
1849
|
|
|
|
|
|
|
|
1850
|
|
|
|
|
|
|
} # end of tree_split |
1851
|
|
|
|
|
|
|
|
1852
|
|
|
|
|
|
|
# |
1853
|
|
|
|
|
|
|
# callback executed when someone double clicks |
1854
|
|
|
|
|
|
|
# an entry in the 'Subs' Tk::Notebook page. |
1855
|
|
|
|
|
|
|
# |
1856
|
|
|
|
|
|
|
sub sub_list_cmd { |
1857
|
|
|
|
|
|
|
my ($self, $path) = @_ ; |
1858
|
|
|
|
|
|
|
my ($h) ; |
1859
|
|
|
|
|
|
|
my $sub_list = $self->{'sub_list'} ; |
1860
|
|
|
|
|
|
|
|
1861
|
|
|
|
|
|
|
if ( $sub_list->info('children', $path) ) { |
1862
|
|
|
|
|
|
|
# |
1863
|
|
|
|
|
|
|
# Delete the children |
1864
|
|
|
|
|
|
|
# |
1865
|
|
|
|
|
|
|
$sub_list->deleteOffsprings($path) ; |
1866
|
|
|
|
|
|
|
return ; |
1867
|
|
|
|
|
|
|
} |
1868
|
|
|
|
|
|
|
|
1869
|
|
|
|
|
|
|
# |
1870
|
|
|
|
|
|
|
# split the path up into elements |
1871
|
|
|
|
|
|
|
# end descend through the tree. |
1872
|
|
|
|
|
|
|
# |
1873
|
|
|
|
|
|
|
$h = $Devel::ptkdb::subs_tree ; |
1874
|
|
|
|
|
|
|
for ( split /\./o, $path ) { |
1875
|
|
|
|
|
|
|
$h = $h->{$_} ; # next level down |
1876
|
|
|
|
|
|
|
} |
1877
|
|
|
|
|
|
|
|
1878
|
|
|
|
|
|
|
# |
1879
|
|
|
|
|
|
|
# if we don't have a 'name' entry we |
1880
|
|
|
|
|
|
|
# still have levels to decend through. |
1881
|
|
|
|
|
|
|
# |
1882
|
|
|
|
|
|
|
if ( !exists $h->{'name'} ) { |
1883
|
|
|
|
|
|
|
# |
1884
|
|
|
|
|
|
|
# Add the next level paths |
1885
|
|
|
|
|
|
|
# |
1886
|
|
|
|
|
|
|
for ( sort keys %$h ) { |
1887
|
|
|
|
|
|
|
|
1888
|
|
|
|
|
|
|
if ( exists $h->{$_}->{'path'} ) { |
1889
|
|
|
|
|
|
|
$sub_list->add($path . '.' . $_, -text => $h->{$_}->{'path'}) ; |
1890
|
|
|
|
|
|
|
} |
1891
|
|
|
|
|
|
|
else { |
1892
|
|
|
|
|
|
|
$sub_list->add($path . '.' . $_, -text => $_) ; |
1893
|
|
|
|
|
|
|
} |
1894
|
|
|
|
|
|
|
} |
1895
|
|
|
|
|
|
|
return ; |
1896
|
|
|
|
|
|
|
} |
1897
|
|
|
|
|
|
|
|
1898
|
|
|
|
|
|
|
$DB::sub{$h->{'path'}} =~ /(.*):([0-9]+)-[0-9]+$/o ; # file name will be in $1, line number will be in $2 */ |
1899
|
|
|
|
|
|
|
|
1900
|
|
|
|
|
|
|
$self->set_file($1, $2) ; |
1901
|
|
|
|
|
|
|
|
1902
|
|
|
|
|
|
|
} # end of sub_list_cmd |
1903
|
|
|
|
|
|
|
|
1904
|
|
|
|
|
|
|
sub fill_subs_page { |
1905
|
|
|
|
|
|
|
my($self) = @_ ; |
1906
|
|
|
|
|
|
|
|
1907
|
|
|
|
|
|
|
$self->{'sub_list'}->delete('all') ; # clear existing entries |
1908
|
|
|
|
|
|
|
|
1909
|
|
|
|
|
|
|
my @list = keys %DB::sub ; |
1910
|
|
|
|
|
|
|
|
1911
|
|
|
|
|
|
|
$Devel::ptkdb::subs_tree = tree_split(\@list, "::") ; |
1912
|
|
|
|
|
|
|
|
1913
|
|
|
|
|
|
|
# setup to level of list |
1914
|
|
|
|
|
|
|
|
1915
|
|
|
|
|
|
|
for ( sort keys %$Devel::ptkdb::subs_tree ) { |
1916
|
|
|
|
|
|
|
$self->{'sub_list'}->add($_, -text => $_) ; |
1917
|
|
|
|
|
|
|
} # end of top level loop |
1918
|
|
|
|
|
|
|
} |
1919
|
|
|
|
|
|
|
|
1920
|
|
|
|
|
|
|
sub setup_subs_page { |
1921
|
|
|
|
|
|
|
my($self) = @_ ; |
1922
|
|
|
|
|
|
|
|
1923
|
|
|
|
|
|
|
$self->{'subs_page_activated'} = 1 ; |
1924
|
|
|
|
|
|
|
|
1925
|
|
|
|
|
|
|
$self->{'sub_list'} = $self->{'subs_page'}->Scrolled('HList', -command => sub { $self->sub_list_cmd(@_) ; } ) ; |
1926
|
|
|
|
|
|
|
|
1927
|
|
|
|
|
|
|
$self->fill_subs_page() ; |
1928
|
|
|
|
|
|
|
|
1929
|
|
|
|
|
|
|
$self->{'sub_list'}->pack(-side => 'left', -fill => 'both', -expand => 1 |
1930
|
|
|
|
|
|
|
) ; |
1931
|
|
|
|
|
|
|
|
1932
|
|
|
|
|
|
|
$self->{'subs_list_cnt'} = scalar keys %DB::sub ; |
1933
|
|
|
|
|
|
|
|
1934
|
|
|
|
|
|
|
|
1935
|
|
|
|
|
|
|
} # end of setup_subs_page |
1936
|
|
|
|
|
|
|
|
1937
|
|
|
|
|
|
|
|
1938
|
|
|
|
|
|
|
sub check_search_request { |
1939
|
|
|
|
|
|
|
my($entry, $self, $searchButton, $regexBtn) = @_ ; |
1940
|
|
|
|
|
|
|
my($txt) = $entry->get ; |
1941
|
|
|
|
|
|
|
|
1942
|
|
|
|
|
|
|
if( $txt =~ /^\s*[0-9]+\s*$/ ) { |
1943
|
|
|
|
|
|
|
$self->DoGoto($entry) ; |
1944
|
|
|
|
|
|
|
return ; |
1945
|
|
|
|
|
|
|
} |
1946
|
|
|
|
|
|
|
|
1947
|
|
|
|
|
|
|
if( $txt =~ /\.\*/ ) { # common regex search pattern |
1948
|
|
|
|
|
|
|
$self->FindSearch($entry, $regexBtn, 1) ; |
1949
|
|
|
|
|
|
|
return ; |
1950
|
|
|
|
|
|
|
} |
1951
|
|
|
|
|
|
|
|
1952
|
|
|
|
|
|
|
# vanilla search |
1953
|
|
|
|
|
|
|
$self->FindSearch($entry, $searchButton, 0) ; |
1954
|
|
|
|
|
|
|
} |
1955
|
|
|
|
|
|
|
|
1956
|
|
|
|
|
|
|
sub setup_search_panel { |
1957
|
|
|
|
|
|
|
my ($self, $parent, @packArgs) = @_ ; |
1958
|
|
|
|
|
|
|
my ($frm, $srchBtn, $regexBtn, $entry) ; |
1959
|
|
|
|
|
|
|
|
1960
|
|
|
|
|
|
|
$frm = $parent->Frame() ; |
1961
|
|
|
|
|
|
|
|
1962
|
|
|
|
|
|
|
$frm->Button(-text => 'Goto', -command => sub { $self->DoGoto($entry) })->pack(-side => 'left') ; |
1963
|
|
|
|
|
|
|
$srchBtn = $frm->Button(-text => 'Search', -command => sub { $self->FindSearch($entry, $srchBtn, 0) ; } |
1964
|
|
|
|
|
|
|
)->pack(-side => 'left' ) ; |
1965
|
|
|
|
|
|
|
|
1966
|
|
|
|
|
|
|
$regexBtn = $frm->Button(-text => 'Regex', |
1967
|
|
|
|
|
|
|
-command => sub { $self->FindSearch($entry, $regexBtn, 1) ; } |
1968
|
|
|
|
|
|
|
)->pack(-side => 'left', |
1969
|
|
|
|
|
|
|
) ; |
1970
|
|
|
|
|
|
|
|
1971
|
|
|
|
|
|
|
|
1972
|
|
|
|
|
|
|
$entry = $frm->Entry(-width => 50)->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
1973
|
|
|
|
|
|
|
|
1974
|
|
|
|
|
|
|
$entry->bind('', sub { check_search_request($entry, $self, $srchBtn, $regexBtn) ; } ) ; |
1975
|
|
|
|
|
|
|
|
1976
|
|
|
|
|
|
|
$frm->pack(@packArgs) ; |
1977
|
|
|
|
|
|
|
|
1978
|
|
|
|
|
|
|
} # end of setup search_panel |
1979
|
|
|
|
|
|
|
|
1980
|
|
|
|
|
|
|
sub setup_breakpts_page { |
1981
|
|
|
|
|
|
|
my ($self) = @_ ; |
1982
|
|
|
|
|
|
|
require Tk::Table ; |
1983
|
|
|
|
|
|
|
|
1984
|
|
|
|
|
|
|
$self->{'breakpts_page'} = $self->{'notebook'}->add("brkptspage", -label => "BrkPts") ; |
1985
|
|
|
|
|
|
|
|
1986
|
|
|
|
|
|
|
$self->{'breakpts_table'} = $self->{'breakpts_page'}->Table(-columns => 1, -scrollbars => 'se')-> |
1987
|
|
|
|
|
|
|
pack(-side => 'top', -fill => 'both', -expand => 1 |
1988
|
|
|
|
|
|
|
) ; |
1989
|
|
|
|
|
|
|
|
1990
|
|
|
|
|
|
|
$self->{'breakpts_table_data'} = { } ; # controls addressed by "fname:lineno" |
1991
|
|
|
|
|
|
|
|
1992
|
|
|
|
|
|
|
} # end of setup_breakpts_page |
1993
|
|
|
|
|
|
|
|
1994
|
|
|
|
|
|
|
sub setup_frames { |
1995
|
|
|
|
|
|
|
my ($self) = @_ ; |
1996
|
|
|
|
|
|
|
my $mw = $self->{'main_window'} ; |
1997
|
|
|
|
|
|
|
my ($txt, $place_holder, $frm) ; |
1998
|
|
|
|
|
|
|
require Tk::ROText ; |
1999
|
|
|
|
|
|
|
require Tk::NoteBook ; |
2000
|
|
|
|
|
|
|
require Tk::HList ; |
2001
|
|
|
|
|
|
|
require Tk::Balloon ; |
2002
|
|
|
|
|
|
|
require Tk::Adjuster ; |
2003
|
|
|
|
|
|
|
|
2004
|
|
|
|
|
|
|
# get the side that we want to put the code pane on |
2005
|
|
|
|
|
|
|
|
2006
|
|
|
|
|
|
|
my($codeSide) = $ENV{'PTKDB_CODE_SIDE'} || $mw->optionGet("codeside", "") || 'left' ; |
2007
|
|
|
|
|
|
|
|
2008
|
|
|
|
|
|
|
|
2009
|
|
|
|
|
|
|
|
2010
|
|
|
|
|
|
|
$mw->update ; # force geometry manager to map main_window |
2011
|
|
|
|
|
|
|
$frm = $mw->Frame(-width => $mw->reqwidth()) ; # frame for our code pane and search controls |
2012
|
|
|
|
|
|
|
|
2013
|
|
|
|
|
|
|
$self->setup_search_panel($frm, -side => 'top', -fill => 'x') ; |
2014
|
|
|
|
|
|
|
|
2015
|
|
|
|
|
|
|
# |
2016
|
|
|
|
|
|
|
# Text window for the code of our currently viewed file |
2017
|
|
|
|
|
|
|
# |
2018
|
|
|
|
|
|
|
$self->{'text'} = $frm->Scrolled('ROText', |
2019
|
|
|
|
|
|
|
-wrap => "none", |
2020
|
|
|
|
|
|
|
@Devel::ptkdb::scrollbar_cfg, |
2021
|
|
|
|
|
|
|
@Devel::ptkdb::code_text_font |
2022
|
|
|
|
|
|
|
) ; |
2023
|
|
|
|
|
|
|
|
2024
|
|
|
|
|
|
|
|
2025
|
|
|
|
|
|
|
$txt = $self->{'text'} ; |
2026
|
|
|
|
|
|
|
for( $txt->children ) { |
2027
|
|
|
|
|
|
|
next unless (ref $_) =~ /ROText$/ ; |
2028
|
|
|
|
|
|
|
$self->{'text'} = $_ ; |
2029
|
|
|
|
|
|
|
last ; |
2030
|
|
|
|
|
|
|
} |
2031
|
|
|
|
|
|
|
|
2032
|
|
|
|
|
|
|
$frm->packPropagate(0) ; |
2033
|
|
|
|
|
|
|
$txt->packPropagate(0) ; |
2034
|
|
|
|
|
|
|
|
2035
|
|
|
|
|
|
|
$frm->packAdjust(-side => $codeSide, -fill => 'both', -expand => 1) ; |
2036
|
|
|
|
|
|
|
$txt->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
2037
|
|
|
|
|
|
|
|
2038
|
|
|
|
|
|
|
# $txt->form(-top => [ $self->{'menu_bar'} ], -left => '%0', -right => '%50') ; |
2039
|
|
|
|
|
|
|
# $frm->form(-top => [ $self->{'menu_bar'} ], -left => '%50', -right => '%100') ; |
2040
|
|
|
|
|
|
|
|
2041
|
|
|
|
|
|
|
$self->configure_text() ; |
2042
|
|
|
|
|
|
|
|
2043
|
|
|
|
|
|
|
# |
2044
|
|
|
|
|
|
|
# Notebook |
2045
|
|
|
|
|
|
|
# |
2046
|
|
|
|
|
|
|
|
2047
|
|
|
|
|
|
|
$self->{'notebook'} = $mw->NoteBook() ; |
2048
|
|
|
|
|
|
|
$self->{'notebook'}->packPropagate(0) ; |
2049
|
|
|
|
|
|
|
$self->{'notebook'}->pack(-side => $codeSide, -fill => 'both', -expand => 1) ; |
2050
|
|
|
|
|
|
|
|
2051
|
|
|
|
|
|
|
# |
2052
|
|
|
|
|
|
|
# an hlist for the data entries |
2053
|
|
|
|
|
|
|
# |
2054
|
|
|
|
|
|
|
$self->{'data_page'} = $self->{'notebook'}->add("datapage", -label => "Exprs") ; |
2055
|
|
|
|
|
|
|
|
2056
|
|
|
|
|
|
|
# |
2057
|
|
|
|
|
|
|
# frame, entry and label for quick expressions |
2058
|
|
|
|
|
|
|
# |
2059
|
|
|
|
|
|
|
my $frame = $self->{'data_page'}->Frame()->pack(-side => 'top', -fill => 'x') ; |
2060
|
|
|
|
|
|
|
|
2061
|
|
|
|
|
|
|
my $label = $frame->Label(-text => "Quick Expr:")->pack(-side => 'left') ; |
2062
|
|
|
|
|
|
|
|
2063
|
|
|
|
|
|
|
$self->{'quick_entry'} = $frame->Entry()->pack(-side => 'left', -fill => 'x', -expand => 1) ; |
2064
|
|
|
|
|
|
|
|
2065
|
|
|
|
|
|
|
$self->{'quick_entry'}->bind('', sub { $self->QuickExpr() ; } ) ; |
2066
|
|
|
|
|
|
|
|
2067
|
|
|
|
|
|
|
|
2068
|
|
|
|
|
|
|
# |
2069
|
|
|
|
|
|
|
# Entry widget for expressions and breakpoints |
2070
|
|
|
|
|
|
|
# |
2071
|
|
|
|
|
|
|
$frame = $self->{'data_page'}->Frame()->pack(-side => 'top', -fill => 'x') ; |
2072
|
|
|
|
|
|
|
|
2073
|
|
|
|
|
|
|
$label = $frame->Label(-text => "Enter Expr:")->pack(-side => 'left') ; |
2074
|
|
|
|
|
|
|
|
2075
|
|
|
|
|
|
|
$self->{'entry'} = $frame->Entry()->pack(-side => 'left', -fill => 'x', -expand => 1) ; |
2076
|
|
|
|
|
|
|
|
2077
|
|
|
|
|
|
|
$self->{'entry'}->bind('', sub { $self->EnterExpr() }) ; |
2078
|
|
|
|
|
|
|
|
2079
|
|
|
|
|
|
|
# |
2080
|
|
|
|
|
|
|
# Hlist for data expressions |
2081
|
|
|
|
|
|
|
# |
2082
|
|
|
|
|
|
|
|
2083
|
|
|
|
|
|
|
|
2084
|
|
|
|
|
|
|
$self->{data_list} = $self->{'data_page'}->Scrolled('HList', |
2085
|
|
|
|
|
|
|
@Devel::ptkdb::scrollbar_cfg, |
2086
|
|
|
|
|
|
|
separator => $Devel::ptkdb::pathSep, |
2087
|
|
|
|
|
|
|
@Devel::ptkdb::expression_text_font, |
2088
|
|
|
|
|
|
|
-command => \&Devel::ptkdb::expr_expand, |
2089
|
|
|
|
|
|
|
-selectmode => 'multiple' |
2090
|
|
|
|
|
|
|
) ; |
2091
|
|
|
|
|
|
|
|
2092
|
|
|
|
|
|
|
$self->{data_list}->pack(-side => 'top', -fill => 'both', -expand => 1 |
2093
|
|
|
|
|
|
|
) ; |
2094
|
|
|
|
|
|
|
|
2095
|
|
|
|
|
|
|
|
2096
|
|
|
|
|
|
|
$self->{'subs_page_activated'} = 0 ; |
2097
|
|
|
|
|
|
|
$self->{'subs_page'} = $self->{'notebook'}->add("subspage", -label => "Subs", -createcmd => sub { $self->setup_subs_page }) ; |
2098
|
|
|
|
|
|
|
|
2099
|
|
|
|
|
|
|
$self->setup_breakpts_page() ; |
2100
|
|
|
|
|
|
|
|
2101
|
|
|
|
|
|
|
} # end of setup_frames |
2102
|
|
|
|
|
|
|
|
2103
|
|
|
|
|
|
|
|
2104
|
|
|
|
|
|
|
|
2105
|
|
|
|
|
|
|
sub configure_text { |
2106
|
|
|
|
|
|
|
my($self) = @_ ; |
2107
|
|
|
|
|
|
|
my($txt, $mw) = ($self->{'text'}, $self->{'main_window'}) ; |
2108
|
|
|
|
|
|
|
my($place_holder) ; |
2109
|
|
|
|
|
|
|
|
2110
|
|
|
|
|
|
|
$self->{'expr_balloon'} = $txt->Balloon(); |
2111
|
|
|
|
|
|
|
$self->{'balloon_expr'} = ' ' ; # initial expression |
2112
|
|
|
|
|
|
|
|
2113
|
|
|
|
|
|
|
# If Data::Dumper is available setup a dumper for the balloon |
2114
|
|
|
|
|
|
|
|
2115
|
|
|
|
|
|
|
if ( $Devel::ptkdb::DataDumperAvailable ) { |
2116
|
|
|
|
|
|
|
$self->{'balloon_dumper'} = new Data::Dumper([$place_holder]) ; |
2117
|
|
|
|
|
|
|
$self->{'balloon_dumper'}->Terse(1) ; |
2118
|
|
|
|
|
|
|
$self->{'balloon_dumper'}->Indent($Devel::ptkdb::eval_dump_indent) ; |
2119
|
|
|
|
|
|
|
|
2120
|
|
|
|
|
|
|
$self->{'quick_dumper'} = new Data::Dumper([$place_holder]) ; |
2121
|
|
|
|
|
|
|
$self->{'quick_dumper'}->Terse(1) ; |
2122
|
|
|
|
|
|
|
$self->{'quick_dumper'}->Indent(0) ; |
2123
|
|
|
|
|
|
|
} |
2124
|
|
|
|
|
|
|
|
2125
|
|
|
|
|
|
|
$self->{'expr_ballon_msg'} = ' ' ; |
2126
|
|
|
|
|
|
|
|
2127
|
|
|
|
|
|
|
$self->{'expr_balloon'}->attach($txt, -initwait => 300, |
2128
|
|
|
|
|
|
|
-msg => \$self->{'expr_ballon_msg'}, |
2129
|
|
|
|
|
|
|
-balloonposition => 'mouse', |
2130
|
|
|
|
|
|
|
-postcommand => \&Devel::ptkdb::balloon_post, |
2131
|
|
|
|
|
|
|
-motioncommand => \&Devel::ptkdb::balloon_motion ) ; |
2132
|
|
|
|
|
|
|
|
2133
|
|
|
|
|
|
|
# tags for the text |
2134
|
|
|
|
|
|
|
|
2135
|
|
|
|
|
|
|
my @stopTagConfig = ( -foreground => 'white', -background => $mw->optionGet("stopcolor", "background") || $ENV{'PTKDB_STOP_TAG_COLOR'} || 'blue' ) ; |
2136
|
|
|
|
|
|
|
|
2137
|
|
|
|
|
|
|
my $stopFnt = $mw->optionGet("stopfont", "background") || $ENV{'PTKDB_STOP_TAG_FONT'} ; |
2138
|
|
|
|
|
|
|
push @stopTagConfig, ( -font => $stopFnt ) if $stopFnt ; # user may not have specified a font, if not, stay with the default |
2139
|
|
|
|
|
|
|
|
2140
|
|
|
|
|
|
|
$txt->tagConfigure('stoppt', @stopTagConfig) ; |
2141
|
|
|
|
|
|
|
$txt->tagConfigure('search_tag', "-background" => $mw->optionGet("searchtagcolor", "background") || "green") ; |
2142
|
|
|
|
|
|
|
|
2143
|
|
|
|
|
|
|
$txt->tagConfigure("breakableLine", -overstrike => 0) ; |
2144
|
|
|
|
|
|
|
$txt->tagConfigure("nonbreakableLine", -overstrike => 1) ; |
2145
|
|
|
|
|
|
|
$txt->tagConfigure("breaksetLine", -background => $mw->optionGet("breaktagcolor", "background") || $ENV{'PTKDB_BRKPT_COLOR'} || 'red') ; |
2146
|
|
|
|
|
|
|
$txt->tagConfigure("breakdisabledLine", -background => $mw->optionGet("disabledbreaktagcolor", "background") || $ENV{'PTKDB_DISABLEDBRKPT_COLOR'} || 'green') ; |
2147
|
|
|
|
|
|
|
|
2148
|
|
|
|
|
|
|
$txt->tagBind("breakableLine", '', [ \&Devel::ptkdb::set_breakpoint_tag, $self, Ev('@'), 1 ] ) ; |
2149
|
|
|
|
|
|
|
$txt->tagBind("breakableLine", '', [ \&Devel::ptkdb::set_breakpoint_tag, $self, Ev('@'), 0 ] ) ; |
2150
|
|
|
|
|
|
|
|
2151
|
|
|
|
|
|
|
$txt->tagBind("breaksetLine", '', [ \&Devel::ptkdb::clear_breakpoint_tag, $self, Ev('@') ] ) ; |
2152
|
|
|
|
|
|
|
$txt->tagBind("breaksetLine", '', [ \&Devel::ptkdb::change_breakpoint_tag, $self, Ev('@'), 0 ] ) ; |
2153
|
|
|
|
|
|
|
|
2154
|
|
|
|
|
|
|
$txt->tagBind("breakdisabledLine", '', [ \&Devel::ptkdb::clear_breakpoint_tag, $self, Ev('@') ] ) ; |
2155
|
|
|
|
|
|
|
$txt->tagBind("breakdisabledLine", '', [ \&Devel::ptkdb::change_breakpoint_tag, $self, Ev('@'), 1 ] ) ; |
2156
|
|
|
|
|
|
|
|
2157
|
|
|
|
|
|
|
} # end of configure_text |
2158
|
|
|
|
|
|
|
|
2159
|
|
|
|
|
|
|
|
2160
|
|
|
|
|
|
|
sub setup_options { |
2161
|
|
|
|
|
|
|
my ($self) = @_ ; |
2162
|
|
|
|
|
|
|
my $mw = $self->{main_window} ; |
2163
|
|
|
|
|
|
|
|
2164
|
|
|
|
|
|
|
return unless $mw->can('appname') ; |
2165
|
|
|
|
|
|
|
|
2166
|
|
|
|
|
|
|
$mw->appname("ptkdb") ; |
2167
|
|
|
|
|
|
|
$mw->optionAdd("stopcolor" => 'cyan', 60 ) ; |
2168
|
|
|
|
|
|
|
$mw->optionAdd("stopfont" => 'fixed', 60 ) ; |
2169
|
|
|
|
|
|
|
$mw->optionAdd("breaktag" => 'red', 60 ) ; |
2170
|
|
|
|
|
|
|
$mw->optionAdd("searchtagcolor" => 'green') ; |
2171
|
|
|
|
|
|
|
|
2172
|
|
|
|
|
|
|
$mw->optionClear ; # necessary to reload xresources |
2173
|
|
|
|
|
|
|
|
2174
|
|
|
|
|
|
|
} # end of setup_options |
2175
|
|
|
|
|
|
|
|
2176
|
|
|
|
|
|
|
sub DoAlert { |
2177
|
|
|
|
|
|
|
my($self, $msg, $title) = @_ ; |
2178
|
|
|
|
|
|
|
my($dlg) ; |
2179
|
|
|
|
|
|
|
my $okaySub = sub { |
2180
|
|
|
|
|
|
|
destroy $dlg ; |
2181
|
|
|
|
|
|
|
} ; |
2182
|
|
|
|
|
|
|
|
2183
|
|
|
|
|
|
|
$dlg = $self->{main_window}->Toplevel(-title => $title || "Alert", -overanchor => 'cursor') ; |
2184
|
|
|
|
|
|
|
|
2185
|
|
|
|
|
|
|
$dlg->Label( -text => $msg )->pack( -side => 'top' ) ; |
2186
|
|
|
|
|
|
|
|
2187
|
|
|
|
|
|
|
$dlg->Button( -text => "Okay", -command => $okaySub )->pack( -side => 'top' )->focus ; |
2188
|
|
|
|
|
|
|
$dlg->bind('', $okaySub) ; |
2189
|
|
|
|
|
|
|
|
2190
|
|
|
|
|
|
|
} # end of DoAlert |
2191
|
|
|
|
|
|
|
|
2192
|
|
|
|
|
|
|
sub simplePromptBox { |
2193
|
|
|
|
|
|
|
my ($self, $title, $defaultText, $okaySub, $cancelSub) = @_ ; |
2194
|
|
|
|
|
|
|
my ($top, $entry, $okayBtn) ; |
2195
|
|
|
|
|
|
|
|
2196
|
|
|
|
|
|
|
$top = $self->{main_window}->Toplevel(-title => $title, -overanchor => 'cursor' ) ; |
2197
|
|
|
|
|
|
|
|
2198
|
|
|
|
|
|
|
$Devel::ptkdb::promptString = $defaultText ; |
2199
|
|
|
|
|
|
|
|
2200
|
|
|
|
|
|
|
$entry = $top->Entry('-textvariable' => \$Devel::ptkdb::promptString)->pack(-side => 'top', -fill => 'both', -expand => 1) ; |
2201
|
|
|
|
|
|
|
|
2202
|
|
|
|
|
|
|
|
2203
|
|
|
|
|
|
|
$okayBtn = $top->Button( -text => "Okay", @Devel::ptkdb::button_font, -command => sub { &$okaySub() ; $top->destroy ;} |
2204
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
2205
|
|
|
|
|
|
|
|
2206
|
|
|
|
|
|
|
$top->Button( -text => "Cancel", -command => sub { &$cancelSub() if $cancelSub ; $top->destroy() }, @Devel::ptkdb::button_font, |
2207
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
2208
|
|
|
|
|
|
|
|
2209
|
|
|
|
|
|
|
$entry->icursor('end') ; |
2210
|
|
|
|
|
|
|
|
2211
|
|
|
|
|
|
|
$entry->selectionRange(0, 'end') if $entry->can('selectionRange') ; # some win32 Tk installations can't do this |
2212
|
|
|
|
|
|
|
|
2213
|
|
|
|
|
|
|
$entry->focus() ; |
2214
|
|
|
|
|
|
|
|
2215
|
|
|
|
|
|
|
return $top ; |
2216
|
|
|
|
|
|
|
|
2217
|
|
|
|
|
|
|
} # end of simplePromptBox |
2218
|
|
|
|
|
|
|
|
2219
|
|
|
|
|
|
|
sub get_entry_text { |
2220
|
|
|
|
|
|
|
my($self) = @_ ; |
2221
|
|
|
|
|
|
|
|
2222
|
|
|
|
|
|
|
return $self->{entry}->get() ; # get the text in the entry |
2223
|
|
|
|
|
|
|
} # end of get_entry_text |
2224
|
|
|
|
|
|
|
|
2225
|
|
|
|
|
|
|
|
2226
|
|
|
|
|
|
|
# |
2227
|
|
|
|
|
|
|
# Clear any text that is in the entry field. If there |
2228
|
|
|
|
|
|
|
# was any text in that field return it. If there |
2229
|
|
|
|
|
|
|
# was no text then return any selection that may be active. |
2230
|
|
|
|
|
|
|
# |
2231
|
|
|
|
|
|
|
sub clear_entry_text { |
2232
|
|
|
|
|
|
|
my($self) = @_ ; |
2233
|
|
|
|
|
|
|
my $str = $self->{'entry'}->get() ; |
2234
|
|
|
|
|
|
|
$self->{'entry'}->delete(0, 'end') ; |
2235
|
|
|
|
|
|
|
|
2236
|
|
|
|
|
|
|
# |
2237
|
|
|
|
|
|
|
# No String |
2238
|
|
|
|
|
|
|
# Empty String |
2239
|
|
|
|
|
|
|
# Or a string that is only whitespace |
2240
|
|
|
|
|
|
|
# |
2241
|
|
|
|
|
|
|
if( !$str || $str eq "" || $str =~ /^\s+$/ ) { |
2242
|
|
|
|
|
|
|
# |
2243
|
|
|
|
|
|
|
# If there is no string or the string is just white text |
2244
|
|
|
|
|
|
|
# Get the text in the selction( if any) |
2245
|
|
|
|
|
|
|
# |
2246
|
|
|
|
|
|
|
if( $self->{'text'}->tagRanges('sel') ) { # check to see if 'sel' tag exists (return undef value) |
2247
|
|
|
|
|
|
|
$str = $self->{'text'}->get("sel.first", "sel.last") ; # get the text between the 'first' and 'last' point of the sel (selection) tag |
2248
|
|
|
|
|
|
|
} |
2249
|
|
|
|
|
|
|
# If still no text, bring the focus to the entry |
2250
|
|
|
|
|
|
|
elsif( !$str || $str eq "" || $str =~ /^\s+$/ ) { |
2251
|
|
|
|
|
|
|
$self->{'entry'}->focus() ; |
2252
|
|
|
|
|
|
|
$str = "" ; |
2253
|
|
|
|
|
|
|
} |
2254
|
|
|
|
|
|
|
} |
2255
|
|
|
|
|
|
|
# |
2256
|
|
|
|
|
|
|
# Erase existing text |
2257
|
|
|
|
|
|
|
# |
2258
|
|
|
|
|
|
|
return $str ; |
2259
|
|
|
|
|
|
|
} # end of clear_entry_text |
2260
|
|
|
|
|
|
|
|
2261
|
|
|
|
|
|
|
sub brkPtCheckbutton { |
2262
|
|
|
|
|
|
|
my ($self, $fname, $idx, $brkPt) = @_ ; |
2263
|
|
|
|
|
|
|
my ($widg) ; |
2264
|
|
|
|
|
|
|
|
2265
|
|
|
|
|
|
|
change_breakpoint_tag($self->{'text'}, $self, "$idx.0", $brkPt->{'value'}) if $fname eq $self->{'current_file'} ; |
2266
|
|
|
|
|
|
|
|
2267
|
|
|
|
|
|
|
} # end of brkPtCheckbutton |
2268
|
|
|
|
|
|
|
|
2269
|
|
|
|
|
|
|
# |
2270
|
|
|
|
|
|
|
# insert a breakpoint control into our breakpoint list. |
2271
|
|
|
|
|
|
|
# returns a handle to the control |
2272
|
|
|
|
|
|
|
# |
2273
|
|
|
|
|
|
|
# Expression, if defined, is to be evaluated at the breakpoint |
2274
|
|
|
|
|
|
|
# and execution stopped if it is non-zero/defined. |
2275
|
|
|
|
|
|
|
# |
2276
|
|
|
|
|
|
|
# If action is defined && True then it will be evalled |
2277
|
|
|
|
|
|
|
# before continuing. |
2278
|
|
|
|
|
|
|
# |
2279
|
|
|
|
|
|
|
sub insertBreakpoint { |
2280
|
|
|
|
|
|
|
my ($self, $fname, @brks) = @_ ; |
2281
|
|
|
|
|
|
|
my ($btn, $cnt, $item) ; |
2282
|
|
|
|
|
|
|
|
2283
|
|
|
|
|
|
|
my($offset) ; |
2284
|
|
|
|
|
|
|
|
2285
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname} ; |
2286
|
|
|
|
|
|
|
|
2287
|
|
|
|
|
|
|
$offset = $dbline[1] =~ /use\s+.*Devel::_?ptkdb/ ? 1 : 0 ; |
2288
|
|
|
|
|
|
|
|
2289
|
|
|
|
|
|
|
while( @brks ) { |
2290
|
|
|
|
|
|
|
my($index, $value, $expression) = splice @brks, 0, 3 ; # take args 3 at a time |
2291
|
|
|
|
|
|
|
|
2292
|
|
|
|
|
|
|
my $brkPt = {} ; |
2293
|
|
|
|
|
|
|
my $txt = &DB::getdbtextline($fname, $index) ; |
2294
|
|
|
|
|
|
|
@$brkPt{'type', 'line', 'expr', 'value', 'fname', 'text'} = |
2295
|
|
|
|
|
|
|
('user', $index, $expression, $value, $fname, "$txt") ; |
2296
|
|
|
|
|
|
|
|
2297
|
|
|
|
|
|
|
&DB::setdbline($fname, $index + $offset, $brkPt) ; |
2298
|
|
|
|
|
|
|
$self->add_brkpt_to_brkpt_page($brkPt) ; |
2299
|
|
|
|
|
|
|
|
2300
|
|
|
|
|
|
|
next unless $fname eq $self->{'current_file'} ; |
2301
|
|
|
|
|
|
|
|
2302
|
|
|
|
|
|
|
$self->{'text'}->tagRemove("breakableLine", "$index.0", "$index.$Devel::ptkdb::linenumber_length") ; |
2303
|
|
|
|
|
|
|
$self->{'text'}->tagAdd($value ? "breaksetLine" : "breakdisabledLine", "$index.0", "$index.$Devel::ptkdb::linenumber_length") ; |
2304
|
|
|
|
|
|
|
} # end of loop |
2305
|
|
|
|
|
|
|
} # end of insertBreakpoint |
2306
|
|
|
|
|
|
|
|
2307
|
|
|
|
|
|
|
sub add_brkpt_to_brkpt_page { |
2308
|
|
|
|
|
|
|
my($self, $brkPt) = @_ ; |
2309
|
|
|
|
|
|
|
my($btn, $fname, $index, $frm, $upperFrame, $lowerFrame) ; |
2310
|
|
|
|
|
|
|
my ($row, $btnName, $width) ; |
2311
|
|
|
|
|
|
|
# |
2312
|
|
|
|
|
|
|
# Add the breakpoint to the breakpoints page |
2313
|
|
|
|
|
|
|
# |
2314
|
|
|
|
|
|
|
($fname, $index) = @$brkPt{'fname', 'line'} ; |
2315
|
|
|
|
|
|
|
return if exists $self->{'breakpts_table_data'}->{"$fname:$index"} ; |
2316
|
|
|
|
|
|
|
$self->{'brkPtCnt'} += 1 ; |
2317
|
|
|
|
|
|
|
|
2318
|
|
|
|
|
|
|
$btnName = $fname ; |
2319
|
|
|
|
|
|
|
$btnName =~ s/.*\/([^\/]*)$/$1/o ; |
2320
|
|
|
|
|
|
|
|
2321
|
|
|
|
|
|
|
# take the last leaf of the pathname |
2322
|
|
|
|
|
|
|
|
2323
|
|
|
|
|
|
|
$frm = $self->{'breakpts_table'}->Frame(-relief => 'raised') ; |
2324
|
|
|
|
|
|
|
$upperFrame = $frm->Frame()->pack(-side => 'top', '-fill' => 'x', -expand => 1) ; |
2325
|
|
|
|
|
|
|
|
2326
|
|
|
|
|
|
|
|
2327
|
|
|
|
|
|
|
$btn = $upperFrame->Checkbutton(-text => "$btnName:$index", |
2328
|
|
|
|
|
|
|
-variable => \$brkPt->{'value'}, # CAUTION value tracking |
2329
|
|
|
|
|
|
|
-command => sub { $self->brkPtCheckbutton($fname, $index, $brkPt) }) ; |
2330
|
|
|
|
|
|
|
|
2331
|
|
|
|
|
|
|
$btn->pack(-side => 'left') ; |
2332
|
|
|
|
|
|
|
|
2333
|
|
|
|
|
|
|
$btn = $upperFrame->Button(-text => "Delete", -command => sub { $self->removeBreakpoint($fname, $index) ; } ) ; |
2334
|
|
|
|
|
|
|
$btn->pack(-side => 'left', -fill => 'x', -expand => 1) ; |
2335
|
|
|
|
|
|
|
|
2336
|
|
|
|
|
|
|
$btn = $upperFrame->Button(-text => "Goto", -command => sub { $self->set_file($fname, $index) ; } ) ; |
2337
|
|
|
|
|
|
|
$btn->pack(-side => 'left', -fill => 'x', -expand => 1) ; |
2338
|
|
|
|
|
|
|
|
2339
|
|
|
|
|
|
|
$lowerFrame = $frm->Frame()->pack(-side => 'top', '-fill' => 'x', -expand => 1) ; |
2340
|
|
|
|
|
|
|
|
2341
|
|
|
|
|
|
|
$lowerFrame->Label(-text => "Cond:")->pack(-side => 'left') ; |
2342
|
|
|
|
|
|
|
|
2343
|
|
|
|
|
|
|
$btn = $lowerFrame->Entry(-textvariable => \$brkPt->{'expr'}) ; |
2344
|
|
|
|
|
|
|
$btn->pack(-side => 'left', -fill => 'x', -expand => 1) ; |
2345
|
|
|
|
|
|
|
|
2346
|
|
|
|
|
|
|
$frm->pack(-side => 'top', -fill => 'x', -expand => 1) ; |
2347
|
|
|
|
|
|
|
|
2348
|
|
|
|
|
|
|
$row = pop @{$self->{'brkPtSlots'}} or $row = $self->{'brkPtCnt'} ; |
2349
|
|
|
|
|
|
|
|
2350
|
|
|
|
|
|
|
$self->{'breakpts_table'}->put($row, 1, $frm) ; |
2351
|
|
|
|
|
|
|
|
2352
|
|
|
|
|
|
|
$self->{'breakpts_table_data'}->{"$fname:$index"}->{'frm'} = $frm ; |
2353
|
|
|
|
|
|
|
$self->{'breakpts_table_data'}->{"$fname:$index"}->{'row'} = $row ; |
2354
|
|
|
|
|
|
|
|
2355
|
|
|
|
|
|
|
$self->{'main_window'}->update ; |
2356
|
|
|
|
|
|
|
|
2357
|
|
|
|
|
|
|
$width = $frm->width ; |
2358
|
|
|
|
|
|
|
|
2359
|
|
|
|
|
|
|
if ( $width > $self->{'breakpts_table'}->width ) { |
2360
|
|
|
|
|
|
|
$self->{'notebook'}->configure(-width => $width) ; |
2361
|
|
|
|
|
|
|
} |
2362
|
|
|
|
|
|
|
|
2363
|
|
|
|
|
|
|
} # end of add_brkpt_to_brkpt_page |
2364
|
|
|
|
|
|
|
|
2365
|
|
|
|
|
|
|
sub remove_brkpt_from_brkpt_page { |
2366
|
|
|
|
|
|
|
my($self, $fname, $idx) = @_ ; |
2367
|
|
|
|
|
|
|
my($table) ; |
2368
|
|
|
|
|
|
|
|
2369
|
|
|
|
|
|
|
$table = $self->{'breakpts_table'} ; |
2370
|
|
|
|
|
|
|
|
2371
|
|
|
|
|
|
|
# Delete the breakpoint control in the breakpoints window |
2372
|
|
|
|
|
|
|
|
2373
|
|
|
|
|
|
|
$table->put($self->{'breakpts_table_data'}->{"$fname:$idx"}->{'row'}, 1) ; # delete? |
2374
|
|
|
|
|
|
|
|
2375
|
|
|
|
|
|
|
# |
2376
|
|
|
|
|
|
|
# Add this now empty slot to the list of ones we have open |
2377
|
|
|
|
|
|
|
# |
2378
|
|
|
|
|
|
|
|
2379
|
|
|
|
|
|
|
push @{$self->{'brkPtSlots'}}, $self->{'breakpts_table_data'}->{"$fname:$idx"}->{'row'} ; |
2380
|
|
|
|
|
|
|
|
2381
|
|
|
|
|
|
|
$self->{'brkPtSlots'} = [ sort { $b <=> $a } @{$self->{'brkPtSlots'}} ] ; |
2382
|
|
|
|
|
|
|
|
2383
|
|
|
|
|
|
|
delete $self->{'breakpts_table_data'}->{"$fname:$idx"} ; |
2384
|
|
|
|
|
|
|
|
2385
|
|
|
|
|
|
|
$self->{'brkPtCnt'} -= 1 ; |
2386
|
|
|
|
|
|
|
|
2387
|
|
|
|
|
|
|
} # end of remove_brkpt_from_brkpt_page |
2388
|
|
|
|
|
|
|
|
2389
|
|
|
|
|
|
|
|
2390
|
|
|
|
|
|
|
# |
2391
|
|
|
|
|
|
|
# Supporting the "Run To Here..." command |
2392
|
|
|
|
|
|
|
# |
2393
|
|
|
|
|
|
|
sub insertTempBreakpoint { |
2394
|
|
|
|
|
|
|
my ($self, $fname, $index) = @_ ; |
2395
|
|
|
|
|
|
|
my($offset) ; |
2396
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname} ; |
2397
|
|
|
|
|
|
|
|
2398
|
|
|
|
|
|
|
$offset = $dbline[1] =~ /use\s+.*Devel::_?ptkdb/ ? 1 : 0 ; |
2399
|
|
|
|
|
|
|
|
2400
|
|
|
|
|
|
|
return if( &DB::getdbline($fname, $index + $offset) ) ; # we already have a breakpoint here |
2401
|
|
|
|
|
|
|
|
2402
|
|
|
|
|
|
|
&DB::setdbline($fname, $index + $offset, {'type' => 'temp', 'line' => $index, 'value' => 1 } ) ; |
2403
|
|
|
|
|
|
|
|
2404
|
|
|
|
|
|
|
} # end of insertTempBreakpoint |
2405
|
|
|
|
|
|
|
|
2406
|
|
|
|
|
|
|
sub reinsertBreakpoints { |
2407
|
|
|
|
|
|
|
my ($self, $fname) = @_ ; |
2408
|
|
|
|
|
|
|
my ($brkPt) ; |
2409
|
|
|
|
|
|
|
|
2410
|
|
|
|
|
|
|
foreach $brkPt ( &DB::getbreakpoints($fname) ) { |
2411
|
|
|
|
|
|
|
# |
2412
|
|
|
|
|
|
|
# Our breakpoints are indexed by line |
2413
|
|
|
|
|
|
|
# therefore we can have 'gaps' where there |
2414
|
|
|
|
|
|
|
# lines, but not breaks set for them. |
2415
|
|
|
|
|
|
|
# |
2416
|
|
|
|
|
|
|
next unless defined $brkPt ; |
2417
|
|
|
|
|
|
|
|
2418
|
|
|
|
|
|
|
$self->insertBreakpoint($fname, @$brkPt{'line', 'value', 'expr'}) if( $brkPt->{'type'} eq 'user' ) ; |
2419
|
|
|
|
|
|
|
$self->insertTempBreakpoint($fname, $brkPt->{line}) if( $brkPt->{'type'} eq 'temp' ) ; |
2420
|
|
|
|
|
|
|
} # end of reinsert loop |
2421
|
|
|
|
|
|
|
|
2422
|
|
|
|
|
|
|
} # end of reinsertBreakpoints |
2423
|
|
|
|
|
|
|
|
2424
|
|
|
|
|
|
|
sub removeBreakpointTags { |
2425
|
|
|
|
|
|
|
my ($self, @brkPts) = @_ ; |
2426
|
|
|
|
|
|
|
my($idx, $brkPt) ; |
2427
|
|
|
|
|
|
|
|
2428
|
|
|
|
|
|
|
foreach $brkPt (@brkPts) { |
2429
|
|
|
|
|
|
|
|
2430
|
|
|
|
|
|
|
$idx = $brkPt->{'line'} ; |
2431
|
|
|
|
|
|
|
|
2432
|
|
|
|
|
|
|
if ( $brkPt->{'value'} ) { |
2433
|
|
|
|
|
|
|
$self->{'text'}->tagRemove("breaksetLine", "$idx.0", "$idx.$Devel::ptkdb::linenumber_length") ; |
2434
|
|
|
|
|
|
|
} |
2435
|
|
|
|
|
|
|
else { |
2436
|
|
|
|
|
|
|
$self->{'text'}->tagRemove("breakdisabledLine", "$idx.0", "$idx.$Devel::ptkdb::linenumber_length") ; |
2437
|
|
|
|
|
|
|
} |
2438
|
|
|
|
|
|
|
|
2439
|
|
|
|
|
|
|
$self->{'text'}->tagAdd("breakableLine", "$idx.0", "$idx.$Devel::ptkdb::linenumber_length") ; |
2440
|
|
|
|
|
|
|
} |
2441
|
|
|
|
|
|
|
} # end of removeBreakpointTags |
2442
|
|
|
|
|
|
|
|
2443
|
|
|
|
|
|
|
# |
2444
|
|
|
|
|
|
|
# Remove a breakpoint from the current window |
2445
|
|
|
|
|
|
|
# |
2446
|
|
|
|
|
|
|
sub removeBreakpoint { |
2447
|
|
|
|
|
|
|
my ($self, $fname, @idx) = @_ ; |
2448
|
|
|
|
|
|
|
my ($idx, $chkIdx, $i, $j, $info) ; |
2449
|
|
|
|
|
|
|
my($offset) ; |
2450
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname} ; |
2451
|
|
|
|
|
|
|
|
2452
|
|
|
|
|
|
|
$offset = $dbline[1] =~ /use\s+.*Devel::_?ptkdb/ ? 1 : 0 ; |
2453
|
|
|
|
|
|
|
|
2454
|
|
|
|
|
|
|
foreach $idx (@idx) { # end of removal loop |
2455
|
|
|
|
|
|
|
next unless defined $idx ; |
2456
|
|
|
|
|
|
|
my $brkPt = &DB::getdbline($fname, $idx + $offset) ; |
2457
|
|
|
|
|
|
|
next unless $brkPt ; # if we do not have an entry |
2458
|
|
|
|
|
|
|
&DB::cleardbline($fname, $idx + $offset) ; |
2459
|
|
|
|
|
|
|
|
2460
|
|
|
|
|
|
|
$self->remove_brkpt_from_brkpt_page($fname, $idx) ; |
2461
|
|
|
|
|
|
|
|
2462
|
|
|
|
|
|
|
next unless $brkPt->{fname} eq $self->{'current_file'} ; # if this isn't our current file there will be no controls |
2463
|
|
|
|
|
|
|
|
2464
|
|
|
|
|
|
|
# Delete the ext associated with the breakpoint expression (if any) |
2465
|
|
|
|
|
|
|
|
2466
|
|
|
|
|
|
|
$self->removeBreakpointTags($brkPt) ; |
2467
|
|
|
|
|
|
|
} # end of remove loop |
2468
|
|
|
|
|
|
|
|
2469
|
|
|
|
|
|
|
return ; |
2470
|
|
|
|
|
|
|
} # end of removeBreakpoint |
2471
|
|
|
|
|
|
|
|
2472
|
|
|
|
|
|
|
sub removeAllBreakpoints { |
2473
|
|
|
|
|
|
|
my ($self, $fname) = @_ ; |
2474
|
|
|
|
|
|
|
|
2475
|
|
|
|
|
|
|
$self->removeBreakpoint($fname, &DB::getdblineindexes($fname)) ; |
2476
|
|
|
|
|
|
|
|
2477
|
|
|
|
|
|
|
} # end of removeAllBreakpoints |
2478
|
|
|
|
|
|
|
|
2479
|
|
|
|
|
|
|
# |
2480
|
|
|
|
|
|
|
# Delete expressions prior to an update |
2481
|
|
|
|
|
|
|
# |
2482
|
|
|
|
|
|
|
sub deleteAllExprs { |
2483
|
|
|
|
|
|
|
my ($self) = @_ ; |
2484
|
|
|
|
|
|
|
$self->{'data_list'}->delete('all') ; |
2485
|
|
|
|
|
|
|
} # end of deleteAllExprs |
2486
|
|
|
|
|
|
|
|
2487
|
|
|
|
|
|
|
sub EnterExpr { |
2488
|
|
|
|
|
|
|
my ($self) = @_ ; |
2489
|
|
|
|
|
|
|
my $str = $self->clear_entry_text() ; |
2490
|
|
|
|
|
|
|
if( $str && $str ne "" && $str !~ /^\s+$/ ) { # if there is an expression and it's more than white space |
2491
|
|
|
|
|
|
|
$self->{'expr'} = $str ; |
2492
|
|
|
|
|
|
|
$self->{'event'} = 'expr' ; |
2493
|
|
|
|
|
|
|
} |
2494
|
|
|
|
|
|
|
} # end of EnterExpr |
2495
|
|
|
|
|
|
|
|
2496
|
|
|
|
|
|
|
# |
2497
|
|
|
|
|
|
|
# |
2498
|
|
|
|
|
|
|
# |
2499
|
|
|
|
|
|
|
sub QuickExpr { |
2500
|
|
|
|
|
|
|
my ($self) = @_ ; |
2501
|
|
|
|
|
|
|
|
2502
|
|
|
|
|
|
|
my $str = $self->{'quick_entry'}->get() ; |
2503
|
|
|
|
|
|
|
|
2504
|
|
|
|
|
|
|
if( $str && $str ne "" && $str !~ /^\s+$/ ) { # if there is an expression and it's more than white space |
2505
|
|
|
|
|
|
|
$self->{'qexpr'} = $str ; |
2506
|
|
|
|
|
|
|
$self->{'event'} = 'qexpr' ; |
2507
|
|
|
|
|
|
|
} |
2508
|
|
|
|
|
|
|
} # end of QuickExpr |
2509
|
|
|
|
|
|
|
|
2510
|
|
|
|
|
|
|
sub deleteExpr { |
2511
|
|
|
|
|
|
|
my ($self) = @_ ; |
2512
|
|
|
|
|
|
|
my ($entry, $i, @indexes) ; |
2513
|
|
|
|
|
|
|
my @sList = $self->{'data_list'}->info('select') ; |
2514
|
|
|
|
|
|
|
|
2515
|
|
|
|
|
|
|
# |
2516
|
|
|
|
|
|
|
# if we're deleteing a top level expression |
2517
|
|
|
|
|
|
|
# we have to take it out of the list of expressions |
2518
|
|
|
|
|
|
|
# |
2519
|
|
|
|
|
|
|
|
2520
|
|
|
|
|
|
|
foreach $entry ( @sList ) { |
2521
|
|
|
|
|
|
|
next if ($entry =~ /\//) ; # goto next expression if we're not a top level ( expr/entry) |
2522
|
|
|
|
|
|
|
$i = 0 ; |
2523
|
|
|
|
|
|
|
grep { push @indexes, $i if ($_->{'expr'} eq $entry) ; $i++ ; } @{$self->{'expr_list'}} ; |
2524
|
|
|
|
|
|
|
} # end of check loop |
2525
|
|
|
|
|
|
|
|
2526
|
|
|
|
|
|
|
# now take out our list of indexes ; |
2527
|
|
|
|
|
|
|
|
2528
|
|
|
|
|
|
|
for( 0..$#indexes ) { |
2529
|
|
|
|
|
|
|
splice @{$self->{'expr_list'}}, $indexes[$_] - $_, 1 ; |
2530
|
|
|
|
|
|
|
} |
2531
|
|
|
|
|
|
|
|
2532
|
|
|
|
|
|
|
for( @sList ) { |
2533
|
|
|
|
|
|
|
$self->{'data_list'}->delete('entry', $_) ; |
2534
|
|
|
|
|
|
|
} |
2535
|
|
|
|
|
|
|
} # end of deleteExpr |
2536
|
|
|
|
|
|
|
|
2537
|
|
|
|
|
|
|
sub fixExprPath { |
2538
|
|
|
|
|
|
|
my(@pathList) = @_ ; |
2539
|
|
|
|
|
|
|
|
2540
|
|
|
|
|
|
|
for (@pathList) { |
2541
|
|
|
|
|
|
|
s/$Devel::ptkdb::pathSep/$Devel::ptkdb::pathSepReplacement/go ; |
2542
|
|
|
|
|
|
|
} # end of path list |
2543
|
|
|
|
|
|
|
|
2544
|
|
|
|
|
|
|
return $pathList[0] unless wantarray ; |
2545
|
|
|
|
|
|
|
return @pathList ; |
2546
|
|
|
|
|
|
|
|
2547
|
|
|
|
|
|
|
} # end of fixExprPath |
2548
|
|
|
|
|
|
|
|
2549
|
|
|
|
|
|
|
## |
2550
|
|
|
|
|
|
|
## Inserts an expression($theRef) into an HList Widget($dl). If the expression |
2551
|
|
|
|
|
|
|
## is an array, blessed array, hash, or blessed hash(typical object), then this |
2552
|
|
|
|
|
|
|
## routine is called recursively, adding the members to the next level of heirarchy, |
2553
|
|
|
|
|
|
|
## prefixing array members with a [idx] and the hash members with the key name. |
2554
|
|
|
|
|
|
|
## This continues until the entire expression is decomposed to it's atomic constituents. |
2555
|
|
|
|
|
|
|
## Protection is given(with $reusedRefs) to ensure that 'circular' references within |
2556
|
|
|
|
|
|
|
## arrays or hashes(i.e. where a member of a array or hash contains a reference to a |
2557
|
|
|
|
|
|
|
## parent element within the heirarchy. |
2558
|
|
|
|
|
|
|
## |
2559
|
|
|
|
|
|
|
# |
2560
|
|
|
|
|
|
|
# Returns 1 if sucessfully added 0 if not |
2561
|
|
|
|
|
|
|
# |
2562
|
|
|
|
|
|
|
sub insertExpr { |
2563
|
|
|
|
|
|
|
my($self, $reusedRefs, $dl, $theRef, $name, $depth, $dirPath) = @_ ; |
2564
|
|
|
|
|
|
|
my($label, $type, $result, $selfCnt, @circRefs) ; |
2565
|
|
|
|
|
|
|
local($^W) = 0 ; # spare us uncessary warnings about comparing strings with == |
2566
|
|
|
|
|
|
|
|
2567
|
|
|
|
|
|
|
# |
2568
|
|
|
|
|
|
|
# Add data new data entries to the bottom |
2569
|
|
|
|
|
|
|
# |
2570
|
|
|
|
|
|
|
$dirPath = "" unless defined $dirPath ; |
2571
|
|
|
|
|
|
|
|
2572
|
|
|
|
|
|
|
$label = "" ; |
2573
|
|
|
|
|
|
|
$selfCnt = 0 ; |
2574
|
|
|
|
|
|
|
|
2575
|
|
|
|
|
|
|
while( ref $theRef eq 'SCALAR' ) { |
2576
|
|
|
|
|
|
|
$theRef = $$theRef ; |
2577
|
|
|
|
|
|
|
} |
2578
|
|
|
|
|
|
|
REF_CHECK: for( ; ; ) { |
2579
|
|
|
|
|
|
|
push @circRefs, $theRef ; |
2580
|
|
|
|
|
|
|
$type = ref $theRef ; |
2581
|
|
|
|
|
|
|
last unless ($type eq "REF") ; |
2582
|
|
|
|
|
|
|
$theRef = $$theRef ; # dref again |
2583
|
|
|
|
|
|
|
|
2584
|
|
|
|
|
|
|
$label .= "\\" ; # append a |
2585
|
|
|
|
|
|
|
if( grep $_ == $theRef, @circRefs ) { |
2586
|
|
|
|
|
|
|
$label .= "(circular)" ; |
2587
|
|
|
|
|
|
|
last ; |
2588
|
|
|
|
|
|
|
} |
2589
|
|
|
|
|
|
|
} |
2590
|
|
|
|
|
|
|
|
2591
|
|
|
|
|
|
|
if( !$type || $type eq "" || $type eq "GLOB" || $type eq "CODE") { |
2592
|
|
|
|
|
|
|
eval { |
2593
|
|
|
|
|
|
|
if( !defined $theRef ) { |
2594
|
|
|
|
|
|
|
$dl->add($dirPath . $name, -text => "$name = $label" . "undef") ; |
2595
|
|
|
|
|
|
|
} |
2596
|
|
|
|
|
|
|
else { |
2597
|
|
|
|
|
|
|
$dl->add($dirPath . $name, -text => "$name = $label$theRef") ; |
2598
|
|
|
|
|
|
|
} |
2599
|
|
|
|
|
|
|
} ; |
2600
|
|
|
|
|
|
|
$self->DoAlert($@), return 0 if $@ ; |
2601
|
|
|
|
|
|
|
return 1 ; |
2602
|
|
|
|
|
|
|
} |
2603
|
|
|
|
|
|
|
|
2604
|
|
|
|
|
|
|
if( $type eq 'ARRAY' or "$theRef" =~ /ARRAY/ ) { |
2605
|
|
|
|
|
|
|
my ($r, $idx) ; |
2606
|
|
|
|
|
|
|
$idx = 0 ; |
2607
|
|
|
|
|
|
|
eval { |
2608
|
|
|
|
|
|
|
$dl->add($dirPath . $name, -text => "$name = $theRef") ; |
2609
|
|
|
|
|
|
|
} ; |
2610
|
|
|
|
|
|
|
if( $@ ) { |
2611
|
|
|
|
|
|
|
$self->DoAlert($@) ; |
2612
|
|
|
|
|
|
|
return 0 ; |
2613
|
|
|
|
|
|
|
} |
2614
|
|
|
|
|
|
|
$result = 1 ; |
2615
|
|
|
|
|
|
|
foreach $r ( @{$theRef} ) { |
2616
|
|
|
|
|
|
|
|
2617
|
|
|
|
|
|
|
if( grep $_ == $r, @$reusedRefs ) { # check to make sure that we're not doing a single level self reference |
2618
|
|
|
|
|
|
|
eval { |
2619
|
|
|
|
|
|
|
$dl->add($dirPath . fixExprPath($name) . $Devel::ptkdb::pathSep . "__ptkdb_self_path" . $selfCnt++, -text => "[$idx] = $r REUSED ADDR") ; |
2620
|
|
|
|
|
|
|
} ; |
2621
|
|
|
|
|
|
|
$self->DoAlert($@) if( $@ ) ; |
2622
|
|
|
|
|
|
|
next ; |
2623
|
|
|
|
|
|
|
} |
2624
|
|
|
|
|
|
|
|
2625
|
|
|
|
|
|
|
push @$reusedRefs, $r ; |
2626
|
|
|
|
|
|
|
$result = $self->insertExpr($reusedRefs, $dl, $r, "[$idx]", $depth-1, $dirPath . fixExprPath($name) . $Devel::ptkdb::pathSep) unless $depth == 0 ; |
2627
|
|
|
|
|
|
|
pop @$reusedRefs ; |
2628
|
|
|
|
|
|
|
|
2629
|
|
|
|
|
|
|
return 0 unless $result ; |
2630
|
|
|
|
|
|
|
$idx += 1 ; |
2631
|
|
|
|
|
|
|
} |
2632
|
|
|
|
|
|
|
return 1 ; |
2633
|
|
|
|
|
|
|
} # end of array case |
2634
|
|
|
|
|
|
|
|
2635
|
|
|
|
|
|
|
if( "$theRef" !~ /HASH\050\060x[0-9a-f]*\051/o ) { |
2636
|
|
|
|
|
|
|
eval { |
2637
|
|
|
|
|
|
|
$dl->add($dirPath . fixExprPath($name), -text => "$name = $theRef") ; |
2638
|
|
|
|
|
|
|
} ; |
2639
|
|
|
|
|
|
|
if( $@ ) { |
2640
|
|
|
|
|
|
|
$self->DoAlert($@) ; |
2641
|
|
|
|
|
|
|
return 0 ; |
2642
|
|
|
|
|
|
|
} |
2643
|
|
|
|
|
|
|
return 1 ; |
2644
|
|
|
|
|
|
|
} |
2645
|
|
|
|
|
|
|
# |
2646
|
|
|
|
|
|
|
# Anything else at this point is |
2647
|
|
|
|
|
|
|
# either a 'HASH' or an object |
2648
|
|
|
|
|
|
|
# of some kind. |
2649
|
|
|
|
|
|
|
# |
2650
|
|
|
|
|
|
|
my($r, @theKeys, $idx) ; |
2651
|
|
|
|
|
|
|
$idx = 0 ; |
2652
|
|
|
|
|
|
|
@theKeys = sort keys %{$theRef} ; |
2653
|
|
|
|
|
|
|
$dl->add($dirPath . $name, -text => "$name = " . "$theRef") ; |
2654
|
|
|
|
|
|
|
$result = 1 ; |
2655
|
|
|
|
|
|
|
|
2656
|
|
|
|
|
|
|
foreach $r ( @$theRef{@theKeys} ) { # slice out the values with the sorted list |
2657
|
|
|
|
|
|
|
|
2658
|
|
|
|
|
|
|
if( grep $_ == $r, @$reusedRefs ) { # check to make sure that we're not doing a single level self reference |
2659
|
|
|
|
|
|
|
eval { |
2660
|
|
|
|
|
|
|
$dl->add($dirPath . fixExprPath($name) . $Devel::ptkdb::pathSep . "__ptkdb_self_path" . $selfCnt++, -text => "$theKeys[$idx++] = $r REUSED ADDR") ; |
2661
|
|
|
|
|
|
|
} ; |
2662
|
|
|
|
|
|
|
print "bad path $@\n" if( $@ ) ; |
2663
|
|
|
|
|
|
|
next ; |
2664
|
|
|
|
|
|
|
} |
2665
|
|
|
|
|
|
|
|
2666
|
|
|
|
|
|
|
push @$reusedRefs, $r ; |
2667
|
|
|
|
|
|
|
|
2668
|
|
|
|
|
|
|
$result = $self->insertExpr($reusedRefs, # recursion protection |
2669
|
|
|
|
|
|
|
$dl, # data list widget |
2670
|
|
|
|
|
|
|
$r, # reference whose value is displayed |
2671
|
|
|
|
|
|
|
$theKeys[$idx], # name |
2672
|
|
|
|
|
|
|
$depth-1, # remaining expansion depth |
2673
|
|
|
|
|
|
|
$dirPath . $name . $Devel::ptkdb::pathSep # path to add to |
2674
|
|
|
|
|
|
|
) unless $depth == 0 ; |
2675
|
|
|
|
|
|
|
|
2676
|
|
|
|
|
|
|
pop @$reusedRefs ; |
2677
|
|
|
|
|
|
|
|
2678
|
|
|
|
|
|
|
return 0 unless $result ; |
2679
|
|
|
|
|
|
|
$idx += 1 ; |
2680
|
|
|
|
|
|
|
} # end of ref add loop |
2681
|
|
|
|
|
|
|
|
2682
|
|
|
|
|
|
|
return 1 ; |
2683
|
|
|
|
|
|
|
} # end of insertExpr |
2684
|
|
|
|
|
|
|
|
2685
|
|
|
|
|
|
|
# |
2686
|
|
|
|
|
|
|
# We're setting the line where we are stopped. |
2687
|
|
|
|
|
|
|
# Create a tag for this and set it as bold. |
2688
|
|
|
|
|
|
|
# |
2689
|
|
|
|
|
|
|
sub set_line { |
2690
|
|
|
|
|
|
|
my ($self, $lineno) = @_ ; |
2691
|
|
|
|
|
|
|
my $text = $self->{'text'} ; |
2692
|
|
|
|
|
|
|
|
2693
|
|
|
|
|
|
|
return if( $lineno <= 0 ) ; |
2694
|
|
|
|
|
|
|
|
2695
|
|
|
|
|
|
|
if( $self->{current_line} > 0 ) { |
2696
|
|
|
|
|
|
|
$text->tagRemove('stoppt', "$self->{current_line}.0 linestart", "$self->{current_line}.0 lineend") ; |
2697
|
|
|
|
|
|
|
} |
2698
|
|
|
|
|
|
|
$self->{current_line} = $lineno - $self->{'line_offset'} ; |
2699
|
|
|
|
|
|
|
$text->tagAdd('stoppt', "$self->{current_line}.0 linestart", "$self->{current_line}.0 lineend") ; |
2700
|
|
|
|
|
|
|
|
2701
|
|
|
|
|
|
|
$self->{'text'}->see("$self->{current_line}.0 linestart") ; |
2702
|
|
|
|
|
|
|
} # end of set_line |
2703
|
|
|
|
|
|
|
|
2704
|
|
|
|
|
|
|
# |
2705
|
|
|
|
|
|
|
# Set the file that is in the code window. |
2706
|
|
|
|
|
|
|
# |
2707
|
|
|
|
|
|
|
# $fname the 'new' file to view |
2708
|
|
|
|
|
|
|
# $line the line number we're at |
2709
|
|
|
|
|
|
|
# $brkPts any breakpoints that may have been set in this file |
2710
|
|
|
|
|
|
|
# |
2711
|
|
|
|
|
|
|
|
2712
|
|
|
|
|
|
|
use Carp ; |
2713
|
|
|
|
|
|
|
|
2714
|
|
|
|
|
|
|
sub set_file { |
2715
|
|
|
|
|
|
|
my ($self, $fname, $line) = @_ ; |
2716
|
|
|
|
|
|
|
my ($lineStr, $offset, $text, $i, @text, $noCode, $title) ; |
2717
|
|
|
|
|
|
|
my (@breakableTagList, @nonBreakableTagList) ; |
2718
|
|
|
|
|
|
|
|
2719
|
|
|
|
|
|
|
return unless $fname ; # we're getting an undef here on 'Restart...' |
2720
|
|
|
|
|
|
|
|
2721
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname}; |
2722
|
|
|
|
|
|
|
|
2723
|
|
|
|
|
|
|
# |
2724
|
|
|
|
|
|
|
# with the #! /usr/bin/perl -d:ptkdb at the header of the file |
2725
|
|
|
|
|
|
|
# we've found that with various combinations of other options the |
2726
|
|
|
|
|
|
|
# files haven't come in at the right offsets |
2727
|
|
|
|
|
|
|
# |
2728
|
|
|
|
|
|
|
$offset = 0 ; |
2729
|
|
|
|
|
|
|
$offset = 1 if $dbline[1] =~ /use\s+.*Devel::_?ptkdb/ ; |
2730
|
|
|
|
|
|
|
$self->{'line_offset'} = $offset ; |
2731
|
|
|
|
|
|
|
|
2732
|
|
|
|
|
|
|
$text = $self->{'text'} ; |
2733
|
|
|
|
|
|
|
|
2734
|
|
|
|
|
|
|
if( $fname eq $self->{current_file} ) { |
2735
|
|
|
|
|
|
|
$self->set_line($line) ; |
2736
|
|
|
|
|
|
|
return ; |
2737
|
|
|
|
|
|
|
} ; |
2738
|
|
|
|
|
|
|
|
2739
|
|
|
|
|
|
|
$title = $fname ; # removing the - messes up stashes on -e invocations |
2740
|
|
|
|
|
|
|
$title =~ s/^\-// ; # Tk does not like leadiing '-'s |
2741
|
|
|
|
|
|
|
$self->{main_window}->configure('-title' => $title) ; |
2742
|
|
|
|
|
|
|
|
2743
|
|
|
|
|
|
|
# Erase any existing text |
2744
|
|
|
|
|
|
|
|
2745
|
|
|
|
|
|
|
$text->delete('0.0','end') ; |
2746
|
|
|
|
|
|
|
|
2747
|
|
|
|
|
|
|
my $len = $Devel::ptkdb::linenumber_length ; |
2748
|
|
|
|
|
|
|
|
2749
|
|
|
|
|
|
|
# |
2750
|
|
|
|
|
|
|
# This is the tightest loop we have in the ptkdb code. |
2751
|
|
|
|
|
|
|
# It is here where performance is the most critical. |
2752
|
|
|
|
|
|
|
# The map block formats perl code for display. Since |
2753
|
|
|
|
|
|
|
# the file could be potentially large, we will try |
2754
|
|
|
|
|
|
|
# to make this loop as thin as possible. |
2755
|
|
|
|
|
|
|
# |
2756
|
|
|
|
|
|
|
# NOTE: For a new perl individual this may appear as |
2757
|
|
|
|
|
|
|
# if it was intentionally obfuscated. This is not |
2758
|
|
|
|
|
|
|
# not the case. The following code is the result |
2759
|
|
|
|
|
|
|
# of an intensive effort to optimize this code. |
2760
|
|
|
|
|
|
|
# Prior versions of this code were quite easier |
2761
|
|
|
|
|
|
|
# to read, but took 3 times longer. |
2762
|
|
|
|
|
|
|
# |
2763
|
|
|
|
|
|
|
|
2764
|
|
|
|
|
|
|
$lineStr = " " x 200 ; # pre-allocate space for $lineStr |
2765
|
|
|
|
|
|
|
$i = 1 ; |
2766
|
|
|
|
|
|
|
|
2767
|
|
|
|
|
|
|
local($^W) = 0 ; # spares us useless warnings under -w when checking $dbline[$_] != 0 |
2768
|
|
|
|
|
|
|
# |
2769
|
|
|
|
|
|
|
# The 'map' call will build list of 'string', 'tag' pairs |
2770
|
|
|
|
|
|
|
# that will become arguments to the 'insert' call. Passing |
2771
|
|
|
|
|
|
|
# the text to insert "all at once" rather than one insert->('end', 'string', 'tag') |
2772
|
|
|
|
|
|
|
# call at time provides a MASSIVE savings in execution time. |
2773
|
|
|
|
|
|
|
# |
2774
|
|
|
|
|
|
|
$noCode = ($#dbline - ($offset + 1)) < 0 ; |
2775
|
|
|
|
|
|
|
|
2776
|
|
|
|
|
|
|
$text->insert('end', map { |
2777
|
|
|
|
|
|
|
# |
2778
|
|
|
|
|
|
|
# build collections of tags representing |
2779
|
|
|
|
|
|
|
# the line numbers for breakable and |
2780
|
|
|
|
|
|
|
# non-breakable lines. We apply these |
2781
|
|
|
|
|
|
|
# tags after we've built the text |
2782
|
|
|
|
|
|
|
# |
2783
|
|
|
|
|
|
|
|
2784
|
|
|
|
|
|
|
($_ != 0 && push @breakableTagList, "$i.0", "$i.$len") || push @nonBreakableTagList, "$i.0", "$i.$len" ; |
2785
|
|
|
|
|
|
|
|
2786
|
|
|
|
|
|
|
$lineStr = sprintf($Devel::ptkdb::linenumber_format, $i++) . $_ ; # line number + text of the line |
2787
|
|
|
|
|
|
|
|
2788
|
|
|
|
|
|
|
substr $lineStr, -2, 1, '' if $isWin32 ; # removes the CR from win32 instances |
2789
|
|
|
|
|
|
|
|
2790
|
|
|
|
|
|
|
$lineStr .= "\n" unless /\n$/o ; # append a \n if there isn't one already |
2791
|
|
|
|
|
|
|
|
2792
|
|
|
|
|
|
|
($lineStr, 'code') ; # return value for block, a string,tag pair for text insert |
2793
|
|
|
|
|
|
|
|
2794
|
|
|
|
|
|
|
} @dbline[$offset+1 .. $#dbline] ) unless $noCode ; |
2795
|
|
|
|
|
|
|
|
2796
|
|
|
|
|
|
|
# |
2797
|
|
|
|
|
|
|
# Apply the tags that we've collected |
2798
|
|
|
|
|
|
|
# NOTE: it was attempted to incorporate these |
2799
|
|
|
|
|
|
|
# operations into the 'map' block above, but that |
2800
|
|
|
|
|
|
|
# actually degraded performance. |
2801
|
|
|
|
|
|
|
# |
2802
|
|
|
|
|
|
|
$text->tagAdd("breakableLine", @breakableTagList) if @breakableTagList ; # apply tag to line numbers where the lines are breakable |
2803
|
|
|
|
|
|
|
$text->tagAdd("nonbreakableLine", @nonBreakableTagList) if @nonBreakableTagList ; # apply tag to line numbers where the lines are not breakable. |
2804
|
|
|
|
|
|
|
|
2805
|
|
|
|
|
|
|
# |
2806
|
|
|
|
|
|
|
# Reinsert breakpoints (if info provided) |
2807
|
|
|
|
|
|
|
# |
2808
|
|
|
|
|
|
|
|
2809
|
|
|
|
|
|
|
$self->set_line($line) ; |
2810
|
|
|
|
|
|
|
$self->{current_file} = $fname ; |
2811
|
|
|
|
|
|
|
return $self->reinsertBreakpoints($fname) ; |
2812
|
|
|
|
|
|
|
} # end of set_file |
2813
|
|
|
|
|
|
|
|
2814
|
|
|
|
|
|
|
# |
2815
|
|
|
|
|
|
|
# Get the current line that the insert cursor is in |
2816
|
|
|
|
|
|
|
# |
2817
|
|
|
|
|
|
|
sub get_lineno { |
2818
|
|
|
|
|
|
|
my ($self) = @_ ; |
2819
|
|
|
|
|
|
|
my ($info) ; |
2820
|
|
|
|
|
|
|
|
2821
|
|
|
|
|
|
|
$info = $self->{'text'}->index('insert') ; # get the location for the insertion point |
2822
|
|
|
|
|
|
|
$info =~ s/\..*$/\.0/ ; |
2823
|
|
|
|
|
|
|
|
2824
|
|
|
|
|
|
|
return int $info ; |
2825
|
|
|
|
|
|
|
} # end of get_lineno |
2826
|
|
|
|
|
|
|
|
2827
|
|
|
|
|
|
|
sub DoGoto { |
2828
|
|
|
|
|
|
|
my ($self, $entry) = @_ ; |
2829
|
|
|
|
|
|
|
|
2830
|
|
|
|
|
|
|
my $txt = $entry->get() ; |
2831
|
|
|
|
|
|
|
|
2832
|
|
|
|
|
|
|
$txt =~ s/(\d*).*/$1/ ; # take the first blob of digits |
2833
|
|
|
|
|
|
|
if( $txt eq "" ) { |
2834
|
|
|
|
|
|
|
print "invalid text range\n" ; |
2835
|
|
|
|
|
|
|
return if $txt eq "" ; |
2836
|
|
|
|
|
|
|
} |
2837
|
|
|
|
|
|
|
|
2838
|
|
|
|
|
|
|
$self->{'text'}->see("$txt.0") ; |
2839
|
|
|
|
|
|
|
|
2840
|
|
|
|
|
|
|
$entry->selectionRange(0, 'end') if $entry->can('selectionRange') |
2841
|
|
|
|
|
|
|
|
2842
|
|
|
|
|
|
|
} # end of DoGoto |
2843
|
|
|
|
|
|
|
|
2844
|
|
|
|
|
|
|
sub GotoLine { |
2845
|
|
|
|
|
|
|
my ($self) = @_ ; |
2846
|
|
|
|
|
|
|
my ($topLevel) ; |
2847
|
|
|
|
|
|
|
|
2848
|
|
|
|
|
|
|
if( $self->{goto_window} ) { |
2849
|
|
|
|
|
|
|
$self->{goto_window}->raise() ; |
2850
|
|
|
|
|
|
|
$self->{goto_text}->focus() ; |
2851
|
|
|
|
|
|
|
return ; |
2852
|
|
|
|
|
|
|
} |
2853
|
|
|
|
|
|
|
|
2854
|
|
|
|
|
|
|
# |
2855
|
|
|
|
|
|
|
# Construct a dialog that has an |
2856
|
|
|
|
|
|
|
# entry field, okay and cancel buttons |
2857
|
|
|
|
|
|
|
# |
2858
|
|
|
|
|
|
|
my $okaySub = sub { $self->DoGoto($self->{'goto_text'}) } ; |
2859
|
|
|
|
|
|
|
|
2860
|
|
|
|
|
|
|
$topLevel = $self->{main_window}->Toplevel(-title => "Goto Line?", -overanchor => 'cursor') ; |
2861
|
|
|
|
|
|
|
|
2862
|
|
|
|
|
|
|
$self->{goto_text} = $topLevel->Entry()->pack(-side => 'top', -fill => 'both', -expand => 1) ; |
2863
|
|
|
|
|
|
|
|
2864
|
|
|
|
|
|
|
$self->{goto_text}->bind('', $okaySub) ; # make a CR do the same thing as pressing an okay |
2865
|
|
|
|
|
|
|
|
2866
|
|
|
|
|
|
|
$self->{goto_text}->focus() ; |
2867
|
|
|
|
|
|
|
|
2868
|
|
|
|
|
|
|
# Bind a double click on the mouse button to the same action |
2869
|
|
|
|
|
|
|
# as pressing the Okay button |
2870
|
|
|
|
|
|
|
|
2871
|
|
|
|
|
|
|
$topLevel->Button( -text => "Okay", -command => $okaySub, @Devel::ptkdb::button_font, |
2872
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
2873
|
|
|
|
|
|
|
|
2874
|
|
|
|
|
|
|
# |
2875
|
|
|
|
|
|
|
# Subroutone called when the 'Dismiss' |
2876
|
|
|
|
|
|
|
# button is pushed. |
2877
|
|
|
|
|
|
|
# |
2878
|
|
|
|
|
|
|
my $dismissSub = sub { |
2879
|
|
|
|
|
|
|
delete $self->{goto_text} ; |
2880
|
|
|
|
|
|
|
destroy {$self->{goto_window}} ; |
2881
|
|
|
|
|
|
|
delete $self->{goto_window} ; # remove the entry from our hash so we won't |
2882
|
|
|
|
|
|
|
} ; |
2883
|
|
|
|
|
|
|
|
2884
|
|
|
|
|
|
|
$topLevel->Button( -text => "Dismiss", @Devel::ptkdb::button_font, |
2885
|
|
|
|
|
|
|
-command => $dismissSub )->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
2886
|
|
|
|
|
|
|
|
2887
|
|
|
|
|
|
|
$topLevel->protocol('WM_DELETE_WINDOW', sub { destroy $topLevel ; } ) ; |
2888
|
|
|
|
|
|
|
|
2889
|
|
|
|
|
|
|
$self->{goto_window} = $topLevel ; |
2890
|
|
|
|
|
|
|
|
2891
|
|
|
|
|
|
|
} # end of GotoLine |
2892
|
|
|
|
|
|
|
|
2893
|
|
|
|
|
|
|
|
2894
|
|
|
|
|
|
|
# |
2895
|
|
|
|
|
|
|
# Subroutine called when the 'okay' button is pressed |
2896
|
|
|
|
|
|
|
# |
2897
|
|
|
|
|
|
|
sub FindSearch { |
2898
|
|
|
|
|
|
|
my ($self, $entry, $btn, $regExp) = @_ ; |
2899
|
|
|
|
|
|
|
my (@switches, $result) ; |
2900
|
|
|
|
|
|
|
my $txt = $entry->get() ; |
2901
|
|
|
|
|
|
|
|
2902
|
|
|
|
|
|
|
return if $txt eq "" ; |
2903
|
|
|
|
|
|
|
|
2904
|
|
|
|
|
|
|
push @switches, "-forward" if $self->{fwdOrBack} eq "forward" ; |
2905
|
|
|
|
|
|
|
push @switches, "-backward" if $self->{fwdOrBack} eq "backward" ; |
2906
|
|
|
|
|
|
|
|
2907
|
|
|
|
|
|
|
if( $regExp ) { |
2908
|
|
|
|
|
|
|
push @switches, "-regexp" ; |
2909
|
|
|
|
|
|
|
} |
2910
|
|
|
|
|
|
|
else { |
2911
|
|
|
|
|
|
|
push @switches, "-nocase" ; # if we're not doing regex we may as well do caseless search |
2912
|
|
|
|
|
|
|
} |
2913
|
|
|
|
|
|
|
|
2914
|
|
|
|
|
|
|
$result = $self->{'text'}->search(@switches, $txt, $self->{search_start}) ; |
2915
|
|
|
|
|
|
|
|
2916
|
|
|
|
|
|
|
# untag the previously found text |
2917
|
|
|
|
|
|
|
|
2918
|
|
|
|
|
|
|
$self->{'text'}->tagRemove('search_tag', @{$self->{search_tag}}) if defined $self->{search_tag} ; |
2919
|
|
|
|
|
|
|
|
2920
|
|
|
|
|
|
|
if( !$result || $result eq "" ) { |
2921
|
|
|
|
|
|
|
# No Text was found |
2922
|
|
|
|
|
|
|
$btn->flash() ; |
2923
|
|
|
|
|
|
|
$btn->bell() ; |
2924
|
|
|
|
|
|
|
|
2925
|
|
|
|
|
|
|
delete $self->{search_tag} ; |
2926
|
|
|
|
|
|
|
$self->{'search_start'} = "0.0" ; |
2927
|
|
|
|
|
|
|
} |
2928
|
|
|
|
|
|
|
else { # text found |
2929
|
|
|
|
|
|
|
$self->{'text'}->see($result) ; |
2930
|
|
|
|
|
|
|
# set the insertion of the text as well |
2931
|
|
|
|
|
|
|
$self->{'text'}->markSet('insert' => $result) ; |
2932
|
|
|
|
|
|
|
my $len = length $txt ; |
2933
|
|
|
|
|
|
|
|
2934
|
|
|
|
|
|
|
if( $self->{fwdOrBack} ) { |
2935
|
|
|
|
|
|
|
$self->{search_start} = "$result +$len chars" ; |
2936
|
|
|
|
|
|
|
$self->{search_tag} = [ $result, $self->{search_start} ] ; |
2937
|
|
|
|
|
|
|
} |
2938
|
|
|
|
|
|
|
else { |
2939
|
|
|
|
|
|
|
# backwards search |
2940
|
|
|
|
|
|
|
$self->{search_start} = "$result -$len chars" ; |
2941
|
|
|
|
|
|
|
$self->{search_tag} = [ $result, "$result +$len chars" ] ; |
2942
|
|
|
|
|
|
|
} |
2943
|
|
|
|
|
|
|
|
2944
|
|
|
|
|
|
|
# tag the newly found text |
2945
|
|
|
|
|
|
|
|
2946
|
|
|
|
|
|
|
$self->{'text'}->tagAdd('search_tag', @{$self->{search_tag}}) ; |
2947
|
|
|
|
|
|
|
} # end of text found |
2948
|
|
|
|
|
|
|
|
2949
|
|
|
|
|
|
|
$entry->selectionRange(0, 'end') if $entry->can('selectionRange') ; |
2950
|
|
|
|
|
|
|
|
2951
|
|
|
|
|
|
|
} # end of FindSearch |
2952
|
|
|
|
|
|
|
|
2953
|
|
|
|
|
|
|
|
2954
|
|
|
|
|
|
|
# |
2955
|
|
|
|
|
|
|
# Support for the Find Text... Menu command |
2956
|
|
|
|
|
|
|
# |
2957
|
|
|
|
|
|
|
sub FindText { |
2958
|
|
|
|
|
|
|
my ($self) = @_ ; |
2959
|
|
|
|
|
|
|
my ($top, $entry, $rad1, $rad2, $chk, $regExp, $frm, $okayBtn) ; |
2960
|
|
|
|
|
|
|
|
2961
|
|
|
|
|
|
|
# |
2962
|
|
|
|
|
|
|
# if we already have the Find Text Window |
2963
|
|
|
|
|
|
|
# open don't bother openning another, bring |
2964
|
|
|
|
|
|
|
# the existing one to the front. |
2965
|
|
|
|
|
|
|
# |
2966
|
|
|
|
|
|
|
if( $self->{find_window} ) { |
2967
|
|
|
|
|
|
|
$self->{find_window}->raise() ; |
2968
|
|
|
|
|
|
|
$self->{find_text}->focus() ; |
2969
|
|
|
|
|
|
|
return ; |
2970
|
|
|
|
|
|
|
} |
2971
|
|
|
|
|
|
|
|
2972
|
|
|
|
|
|
|
$self->{search_start} = $self->{'text'}->index('insert') if( $self->{search_start} eq "" ) ; |
2973
|
|
|
|
|
|
|
|
2974
|
|
|
|
|
|
|
# |
2975
|
|
|
|
|
|
|
# Subroutine called when the 'Dismiss' button |
2976
|
|
|
|
|
|
|
# is pushed. |
2977
|
|
|
|
|
|
|
# |
2978
|
|
|
|
|
|
|
my $dismissSub = sub { |
2979
|
|
|
|
|
|
|
$self->{'text'}->tagRemove('search_tag', @{$self->{search_tag}}) if defined $self->{search_tag} ; |
2980
|
|
|
|
|
|
|
$self->{search_start} = "" ; |
2981
|
|
|
|
|
|
|
destroy {$self->{find_window}} ; |
2982
|
|
|
|
|
|
|
delete $self->{search_tag} ; |
2983
|
|
|
|
|
|
|
delete $self->{find_window} ; |
2984
|
|
|
|
|
|
|
} ; |
2985
|
|
|
|
|
|
|
|
2986
|
|
|
|
|
|
|
# |
2987
|
|
|
|
|
|
|
# Construct a dialog that has an entry field, forward, backward, regex option, okay and cancel buttons |
2988
|
|
|
|
|
|
|
# |
2989
|
|
|
|
|
|
|
$top = $self->{main_window}->Toplevel(-title => "Find Text?") ; |
2990
|
|
|
|
|
|
|
|
2991
|
|
|
|
|
|
|
$self->{find_text} = $top->Entry()->pack(-side => 'top', -fill => 'both', -expand => 1) ; |
2992
|
|
|
|
|
|
|
|
2993
|
|
|
|
|
|
|
|
2994
|
|
|
|
|
|
|
$frm = $top->Frame()->pack(-side => 'top', -fill => 'both', -expand => 1) ; |
2995
|
|
|
|
|
|
|
|
2996
|
|
|
|
|
|
|
$self->{fwdOrBack} = 'forward' ; |
2997
|
|
|
|
|
|
|
$rad1 = $frm->Radiobutton(-text => "Forward", -value => 1, -variable => \$self->{fwdOrBack}) ; |
2998
|
|
|
|
|
|
|
$rad1->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
2999
|
|
|
|
|
|
|
$rad2 = $frm->Radiobutton(-text => "Backward", -value => 0, -variable => \$self->{fwdOrBack}) ; |
3000
|
|
|
|
|
|
|
$rad2->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
3001
|
|
|
|
|
|
|
|
3002
|
|
|
|
|
|
|
$regExp = 0 ; |
3003
|
|
|
|
|
|
|
$chk = $frm->Checkbutton(-text => "RegExp", -variable => \$regExp) ; |
3004
|
|
|
|
|
|
|
$chk->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
3005
|
|
|
|
|
|
|
|
3006
|
|
|
|
|
|
|
# Okay and cancel buttons |
3007
|
|
|
|
|
|
|
|
3008
|
|
|
|
|
|
|
# Bind a double click on the mouse button to the same action |
3009
|
|
|
|
|
|
|
# as pressing the Okay button |
3010
|
|
|
|
|
|
|
|
3011
|
|
|
|
|
|
|
$okayBtn = $top->Button( -text => "Okay", -command => sub { $self->FindSearch($self->{find_text}, $okayBtn, $regExp) ; }, |
3012
|
|
|
|
|
|
|
@Devel::ptkdb::button_font, |
3013
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
3014
|
|
|
|
|
|
|
|
3015
|
|
|
|
|
|
|
$self->{find_text}->bind('', sub { $self->FindSearch($self->{find_text}, $okayBtn, $regExp) ; }) ; |
3016
|
|
|
|
|
|
|
|
3017
|
|
|
|
|
|
|
$top->Button( -text => "Dismiss", @Devel::ptkdb::button_font, |
3018
|
|
|
|
|
|
|
-command => $dismissSub)->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
3019
|
|
|
|
|
|
|
|
3020
|
|
|
|
|
|
|
$top->protocol('WM_DELETE_WINDOW', $dismissSub) ; |
3021
|
|
|
|
|
|
|
|
3022
|
|
|
|
|
|
|
$self->{find_text}->focus() ; |
3023
|
|
|
|
|
|
|
|
3024
|
|
|
|
|
|
|
$self->{find_window} = $top ; |
3025
|
|
|
|
|
|
|
|
3026
|
|
|
|
|
|
|
} # end of FindText |
3027
|
|
|
|
|
|
|
|
3028
|
|
|
|
|
|
|
sub main_loop { |
3029
|
|
|
|
|
|
|
my ($self) = @_ ; |
3030
|
|
|
|
|
|
|
my ($evt, $str, $result) ; |
3031
|
|
|
|
|
|
|
my $i = 0; |
3032
|
|
|
|
|
|
|
SWITCH: for ($self->{'event'} = 'null' ; ; $self->{'event'} = undef ) { |
3033
|
|
|
|
|
|
|
|
3034
|
|
|
|
|
|
|
Tk::DoOneEvent(0); |
3035
|
|
|
|
|
|
|
next unless $self->{'event'} ; |
3036
|
|
|
|
|
|
|
|
3037
|
|
|
|
|
|
|
$evt = $self->{'event'} ; |
3038
|
|
|
|
|
|
|
$evt =~ /step/o && do { last SWITCH ; } ; |
3039
|
|
|
|
|
|
|
$evt =~ /null/o && do { next SWITCH ; } ; |
3040
|
|
|
|
|
|
|
$evt =~ /run/o && do { last SWITCH ; } ; |
3041
|
|
|
|
|
|
|
$evt =~ /quit/o && do { $self->DoQuit ; } ; |
3042
|
|
|
|
|
|
|
$evt =~ /expr/o && do { return $evt ; } ; # adds an expression to our expression window |
3043
|
|
|
|
|
|
|
$evt =~ /qexpr/o && do { return $evt ; } ; # does a 'quick' expression |
3044
|
|
|
|
|
|
|
$evt =~ /update/o && do { return $evt ; } ; # forces an update on our expression window |
3045
|
|
|
|
|
|
|
$evt =~ /reeval/o && do { return $evt ; } ; # updated the open expression eval window |
3046
|
|
|
|
|
|
|
$evt =~ /balloon_eval/ && do { return $evt } ; |
3047
|
|
|
|
|
|
|
} # end of switch block |
3048
|
|
|
|
|
|
|
return $evt ; |
3049
|
|
|
|
|
|
|
} # end of main_loop |
3050
|
|
|
|
|
|
|
|
3051
|
|
|
|
|
|
|
# |
3052
|
|
|
|
|
|
|
# $subStackRef A reference to the current subroutine stack |
3053
|
|
|
|
|
|
|
# |
3054
|
|
|
|
|
|
|
|
3055
|
|
|
|
|
|
|
sub goto_sub_from_stack { |
3056
|
|
|
|
|
|
|
my ($self, $f, $lineno) = @_ ; |
3057
|
|
|
|
|
|
|
$self->set_file($f, $lineno) ; |
3058
|
|
|
|
|
|
|
} # end of goto_sub_from_stack ; |
3059
|
|
|
|
|
|
|
|
3060
|
|
|
|
|
|
|
sub refresh_stack_menu { |
3061
|
|
|
|
|
|
|
my ($self) = @_ ; |
3062
|
|
|
|
|
|
|
my ($str, $name, $i, $sub_offset, $subStack) ; |
3063
|
|
|
|
|
|
|
|
3064
|
|
|
|
|
|
|
# |
3065
|
|
|
|
|
|
|
# CAUTION: In the effort to 'rationalize' the code |
3066
|
|
|
|
|
|
|
# are moving some of this function down from DB::DB |
3067
|
|
|
|
|
|
|
# to here. $sub_offset represents how far 'down' |
3068
|
|
|
|
|
|
|
# we are from DB::DB. The $DB::subroutine_depth is |
3069
|
|
|
|
|
|
|
# tracked in such a way that while we are 'in' the debugger |
3070
|
|
|
|
|
|
|
# it will not be incremented, and thus represents the stack depth |
3071
|
|
|
|
|
|
|
# of the target program. |
3072
|
|
|
|
|
|
|
# |
3073
|
|
|
|
|
|
|
$sub_offset = 1 ; |
3074
|
|
|
|
|
|
|
$subStack = [] ; |
3075
|
|
|
|
|
|
|
|
3076
|
|
|
|
|
|
|
# clear existing entries |
3077
|
|
|
|
|
|
|
|
3078
|
|
|
|
|
|
|
for( $i = 0 ; $i <= $DB::subroutine_depth ; $i++ ) { |
3079
|
|
|
|
|
|
|
my ($package, $filename, $line, $subName) = caller $i+$sub_offset ; |
3080
|
|
|
|
|
|
|
last if !$subName ; |
3081
|
|
|
|
|
|
|
push @$subStack, { 'name' => $subName, 'pck' => $package, 'filename' => $filename, 'line' => $line } ; |
3082
|
|
|
|
|
|
|
} |
3083
|
|
|
|
|
|
|
|
3084
|
|
|
|
|
|
|
$self->{stack_menu}->menu->delete(0, 'last') ; # delete existing menu items |
3085
|
|
|
|
|
|
|
|
3086
|
|
|
|
|
|
|
for( $i = 0 ; $subStack->[$i] ; $i++ ) { |
3087
|
|
|
|
|
|
|
|
3088
|
|
|
|
|
|
|
$str = defined $subStack->[$i+1] ? "$subStack->[$i+1]->{name}" : "MAIN" ; |
3089
|
|
|
|
|
|
|
|
3090
|
|
|
|
|
|
|
my ($f, $line) = ($subStack->[$i]->{filename}, $subStack->[$i]->{line}) ; # make copies of the values for use in 'sub' |
3091
|
|
|
|
|
|
|
$self->{stack_menu}->command(-label => $str, -command => sub { $self->goto_sub_from_stack($f, $line) ; } ) ; |
3092
|
|
|
|
|
|
|
} |
3093
|
|
|
|
|
|
|
} # end of refresh_stack_menu |
3094
|
|
|
|
|
|
|
|
3095
|
|
|
|
|
|
|
no strict ; |
3096
|
|
|
|
|
|
|
|
3097
|
|
|
|
|
|
|
sub get_state { |
3098
|
|
|
|
|
|
|
my ($self, $fname) = @_ ; |
3099
|
|
|
|
|
|
|
my ($val) ; |
3100
|
|
|
|
|
|
|
local($files, $expr_list, $eval_saved_text, $main_win_geometry) ; |
3101
|
|
|
|
|
|
|
|
3102
|
|
|
|
|
|
|
do "$fname" ; |
3103
|
|
|
|
|
|
|
|
3104
|
|
|
|
|
|
|
if( $@ ) { |
3105
|
|
|
|
|
|
|
$self->DoAlert($@) ; |
3106
|
|
|
|
|
|
|
return ( undef ) x 4 ; # return a list of 4 undefined values |
3107
|
|
|
|
|
|
|
} |
3108
|
|
|
|
|
|
|
|
3109
|
|
|
|
|
|
|
return ($files, $expr_list, $eval_saved_text, $main_win_geometry) ; |
3110
|
|
|
|
|
|
|
} # end of get_state |
3111
|
|
|
|
|
|
|
|
3112
|
|
|
|
|
|
|
use strict ; |
3113
|
|
|
|
|
|
|
|
3114
|
|
|
|
|
|
|
sub restoreStateFile { |
3115
|
|
|
|
|
|
|
my ($self, $fname) = @_ ; |
3116
|
|
|
|
|
|
|
local(*F) ; |
3117
|
|
|
|
|
|
|
my ($saveCurFile, $s, @n, $n) ; |
3118
|
|
|
|
|
|
|
|
3119
|
|
|
|
|
|
|
if (!(-e $fname && -r $fname)) { |
3120
|
|
|
|
|
|
|
$self->DoAlert("$fname does not exist") ; |
3121
|
|
|
|
|
|
|
return ; |
3122
|
|
|
|
|
|
|
} |
3123
|
|
|
|
|
|
|
|
3124
|
|
|
|
|
|
|
my ($files, $expr_list, $eval_saved_text, $main_win_geometry) = $self->get_state($fname) ; |
3125
|
|
|
|
|
|
|
my ($f, $brks) ; |
3126
|
|
|
|
|
|
|
|
3127
|
|
|
|
|
|
|
return unless defined $files || defined $expr_list ; |
3128
|
|
|
|
|
|
|
|
3129
|
|
|
|
|
|
|
&DB::restore_breakpoints_from_save($files) ; |
3130
|
|
|
|
|
|
|
|
3131
|
|
|
|
|
|
|
# |
3132
|
|
|
|
|
|
|
# This should force the breakpoints to be restored |
3133
|
|
|
|
|
|
|
# |
3134
|
|
|
|
|
|
|
$saveCurFile = $self->{current_file} ; |
3135
|
|
|
|
|
|
|
|
3136
|
|
|
|
|
|
|
@$self{ 'current_file', 'expr_list', 'eval_saved_text' } = |
3137
|
|
|
|
|
|
|
( "" , $expr_list, $eval_saved_text) ; |
3138
|
|
|
|
|
|
|
|
3139
|
|
|
|
|
|
|
$self->set_file($saveCurFile, $self->{current_line}) ; |
3140
|
|
|
|
|
|
|
|
3141
|
|
|
|
|
|
|
$self->{'event'} = 'update' ; |
3142
|
|
|
|
|
|
|
|
3143
|
|
|
|
|
|
|
if ( $main_win_geometry && $self->{'main_window'} ) { |
3144
|
|
|
|
|
|
|
# restore the height and width of the window |
3145
|
|
|
|
|
|
|
$self->{main_window}->geometry( $main_win_geometry ) ; |
3146
|
|
|
|
|
|
|
} |
3147
|
|
|
|
|
|
|
} # end of retstoreState |
3148
|
|
|
|
|
|
|
|
3149
|
|
|
|
|
|
|
sub updateEvalWindow { |
3150
|
|
|
|
|
|
|
my ($self, @result) = @_ ; |
3151
|
|
|
|
|
|
|
my ($leng, $str, $d) ; |
3152
|
|
|
|
|
|
|
|
3153
|
|
|
|
|
|
|
$leng = 0 ; |
3154
|
|
|
|
|
|
|
for( @result ) { |
3155
|
|
|
|
|
|
|
if( $self->{hexdump_evals} ) { |
3156
|
|
|
|
|
|
|
# eventually put hex dumper code in here |
3157
|
|
|
|
|
|
|
|
3158
|
|
|
|
|
|
|
$self->{eval_results}->insert('end', hexDump($_)) ; |
3159
|
|
|
|
|
|
|
|
3160
|
|
|
|
|
|
|
} |
3161
|
|
|
|
|
|
|
elsif( !$Devel::ptkdb::DataDumperAvailable || !$Devel::ptkdb::useDataDumperForEval ) { |
3162
|
|
|
|
|
|
|
$str = "$_\n" ; |
3163
|
|
|
|
|
|
|
} |
3164
|
|
|
|
|
|
|
else { |
3165
|
|
|
|
|
|
|
$d = Data::Dumper->new([ $_ ]) ; |
3166
|
|
|
|
|
|
|
$d->Indent($Devel::ptkdb::eval_dump_indent) ; |
3167
|
|
|
|
|
|
|
$d->Terse(1) ; |
3168
|
|
|
|
|
|
|
if( Data::Dumper->can('Dumpxs') ) { |
3169
|
|
|
|
|
|
|
$str = $d->Dumpxs( $_ ) ; |
3170
|
|
|
|
|
|
|
} |
3171
|
|
|
|
|
|
|
else { |
3172
|
|
|
|
|
|
|
$str = $d->Dump( $_ ) ; |
3173
|
|
|
|
|
|
|
} |
3174
|
|
|
|
|
|
|
} |
3175
|
|
|
|
|
|
|
$leng += length $str ; |
3176
|
|
|
|
|
|
|
$self->{eval_results}->insert('end', $str) ; |
3177
|
|
|
|
|
|
|
} |
3178
|
|
|
|
|
|
|
} # end of updateEvalWindow |
3179
|
|
|
|
|
|
|
|
3180
|
|
|
|
|
|
|
|
3181
|
|
|
|
|
|
|
## |
3182
|
|
|
|
|
|
|
## converts non printable chars to '.' for a string |
3183
|
|
|
|
|
|
|
## |
3184
|
|
|
|
|
|
|
sub printablestr { |
3185
|
|
|
|
|
|
|
return join "", map { (ord($_) >= 32 && ord($_) < 127) ? $_ : '.' } split //, $_[0] ; |
3186
|
|
|
|
|
|
|
} |
3187
|
|
|
|
|
|
|
|
3188
|
|
|
|
|
|
|
## |
3189
|
|
|
|
|
|
|
## hex dump utility function |
3190
|
|
|
|
|
|
|
## |
3191
|
|
|
|
|
|
|
sub hexDump { |
3192
|
|
|
|
|
|
|
my(@retList) ; |
3193
|
|
|
|
|
|
|
my($width) = 8 ; |
3194
|
|
|
|
|
|
|
my($offset) ; |
3195
|
|
|
|
|
|
|
my($len, $fmt, $n, @elems) ; |
3196
|
|
|
|
|
|
|
|
3197
|
|
|
|
|
|
|
for( @_ ) { |
3198
|
|
|
|
|
|
|
my($str) ; |
3199
|
|
|
|
|
|
|
$len = length $_ ; |
3200
|
|
|
|
|
|
|
|
3201
|
|
|
|
|
|
|
while($len) { |
3202
|
|
|
|
|
|
|
$n = $len >= $width ? $width : $len ; |
3203
|
|
|
|
|
|
|
|
3204
|
|
|
|
|
|
|
$fmt = "\n%04X " . ("%02X " x $n ) . ( ' ' x ($width - $n) ) . " %s" ; |
3205
|
|
|
|
|
|
|
@elems = map ord, split //, (substr $_, $offset, $n) ; |
3206
|
|
|
|
|
|
|
$str .= sprintf($fmt, $offset, @elems, printablestr(substr $_, $offset, $n)) ; |
3207
|
|
|
|
|
|
|
$offset += $width ; |
3208
|
|
|
|
|
|
|
|
3209
|
|
|
|
|
|
|
$len -= $n ; |
3210
|
|
|
|
|
|
|
} # while |
3211
|
|
|
|
|
|
|
|
3212
|
|
|
|
|
|
|
push @retList, $str ; |
3213
|
|
|
|
|
|
|
} # for |
3214
|
|
|
|
|
|
|
|
3215
|
|
|
|
|
|
|
return $retList[0] unless wantarray ; |
3216
|
|
|
|
|
|
|
return @retList ; |
3217
|
|
|
|
|
|
|
} # end of hd |
3218
|
|
|
|
|
|
|
|
3219
|
|
|
|
|
|
|
|
3220
|
|
|
|
|
|
|
sub setupEvalWindow { |
3221
|
|
|
|
|
|
|
my($self) = @_ ; |
3222
|
|
|
|
|
|
|
my($top, $dismissSub) ; |
3223
|
|
|
|
|
|
|
my $f ; |
3224
|
|
|
|
|
|
|
$self->{eval_window}->focus(), return if exists $self->{eval_window} ; # already running this window? |
3225
|
|
|
|
|
|
|
|
3226
|
|
|
|
|
|
|
$top = $self->{main_window}->Toplevel(-title => "Evaluate Expressions...") ; |
3227
|
|
|
|
|
|
|
$self->{eval_window} = $top ; |
3228
|
|
|
|
|
|
|
$self->{eval_text} = $top->Scrolled('TextUndo', |
3229
|
|
|
|
|
|
|
@Devel::ptkdb::scrollbar_cfg, |
3230
|
|
|
|
|
|
|
@Devel::ptkdb::eval_text_font, |
3231
|
|
|
|
|
|
|
width => 50, |
3232
|
|
|
|
|
|
|
height => 10, |
3233
|
|
|
|
|
|
|
-wrap => "none", |
3234
|
|
|
|
|
|
|
)->packAdjust(-side => 'top', -fill => 'both', -expand => 1) ; |
3235
|
|
|
|
|
|
|
|
3236
|
|
|
|
|
|
|
$self->{eval_text}->insert('end', $self->{eval_saved_text}) if exists $self->{eval_saved_text} && defined $self->{eval_saved_text} ; |
3237
|
|
|
|
|
|
|
|
3238
|
|
|
|
|
|
|
$top->Label(-text, "Results:")->pack(-side => 'top', -fill => 'both', -expand => 'n') ; |
3239
|
|
|
|
|
|
|
|
3240
|
|
|
|
|
|
|
$self->{eval_results} = $top->Scrolled('Text', |
3241
|
|
|
|
|
|
|
@Devel::ptkdb::scrollbar_cfg, |
3242
|
|
|
|
|
|
|
width => 50, |
3243
|
|
|
|
|
|
|
height => 10, |
3244
|
|
|
|
|
|
|
-wrap => "none", |
3245
|
|
|
|
|
|
|
@Devel::ptkdb::eval_text_font |
3246
|
|
|
|
|
|
|
)->pack(-side => 'top', -fill => 'both', -expand => 1) ; |
3247
|
|
|
|
|
|
|
|
3248
|
|
|
|
|
|
|
my $btn = $top->Button(-text => 'Eval...', -command => sub { $DB::window->{event} = 'reeval' ; } |
3249
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'x', -expand => 1) ; |
3250
|
|
|
|
|
|
|
|
3251
|
|
|
|
|
|
|
$dismissSub = sub { |
3252
|
|
|
|
|
|
|
$self->{eval_saved_text} = $self->{eval_text}->get('0.0', 'end') ; |
3253
|
|
|
|
|
|
|
$self->{eval_window}->destroy ; |
3254
|
|
|
|
|
|
|
delete $self->{eval_window} ; |
3255
|
|
|
|
|
|
|
} ; |
3256
|
|
|
|
|
|
|
|
3257
|
|
|
|
|
|
|
$top->protocol('WM_DELETE_WINDOW', $dismissSub ) ; |
3258
|
|
|
|
|
|
|
|
3259
|
|
|
|
|
|
|
$top->Button(-text => 'Clear Eval', -command => sub { $self->{eval_text}->delete('0.0', 'end') } |
3260
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'x', -expand => 1) ; |
3261
|
|
|
|
|
|
|
|
3262
|
|
|
|
|
|
|
$top->Button(-text => 'Clear Results', -command => sub { $self->{eval_results}->delete('0.0', 'end') } |
3263
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'x', -expand => 1) ; |
3264
|
|
|
|
|
|
|
|
3265
|
|
|
|
|
|
|
$top->Button(-text => 'Dismiss', -command => $dismissSub)->pack(-side => 'left', -fill => 'x', -expand => 1) ; |
3266
|
|
|
|
|
|
|
$top->Checkbutton(-text => 'Hex', -variable => \$self->{hexdump_evals})->pack(-side => 'left') ; |
3267
|
|
|
|
|
|
|
|
3268
|
|
|
|
|
|
|
} # end of setupEvalWindow ; |
3269
|
|
|
|
|
|
|
|
3270
|
|
|
|
|
|
|
sub filterBreakPts { |
3271
|
|
|
|
|
|
|
my ($breakPtsListRef, $fname) = @_ ; |
3272
|
|
|
|
|
|
|
my $dbline = $main::{'_<' . $fname}; # breakable lines |
3273
|
|
|
|
|
|
|
local($^W) = 0 ; |
3274
|
|
|
|
|
|
|
# |
3275
|
|
|
|
|
|
|
# Go through the list of breaks and take out any that |
3276
|
|
|
|
|
|
|
# are no longer breakable |
3277
|
|
|
|
|
|
|
# |
3278
|
|
|
|
|
|
|
|
3279
|
|
|
|
|
|
|
for( @$breakPtsListRef ) { |
3280
|
|
|
|
|
|
|
next unless defined $_ ; |
3281
|
|
|
|
|
|
|
|
3282
|
|
|
|
|
|
|
next if $dbline->[$_->{'line'}] != 0 ; # still breakable |
3283
|
|
|
|
|
|
|
|
3284
|
|
|
|
|
|
|
$_ = undef ; |
3285
|
|
|
|
|
|
|
} |
3286
|
|
|
|
|
|
|
} # end of filterBreakPts |
3287
|
|
|
|
|
|
|
|
3288
|
|
|
|
|
|
|
sub DoAbout { |
3289
|
|
|
|
|
|
|
my $self = shift ; |
3290
|
|
|
|
|
|
|
my $str = "ptkdb $DB::VERSION\nCopyright 1998,2003 by Andrew E. Page\nFeedback to aepage\@users.sourceforge.net\n\n" ; |
3291
|
|
|
|
|
|
|
my $threadString = "" ; |
3292
|
|
|
|
|
|
|
|
3293
|
|
|
|
|
|
|
$threadString = "Threads Available" if $Config::Config{usethreads} ; |
3294
|
|
|
|
|
|
|
$threadString = " Thread Debugging Enabled" if $DB::usethreads ; |
3295
|
|
|
|
|
|
|
|
3296
|
|
|
|
|
|
|
$str .= <<"__STR__" ; |
3297
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify |
3298
|
|
|
|
|
|
|
it under the terms of either: |
3299
|
|
|
|
|
|
|
|
3300
|
|
|
|
|
|
|
a) the GNU General Public License as published by the Free |
3301
|
|
|
|
|
|
|
Software Foundation; either version 1, or (at your option) any |
3302
|
|
|
|
|
|
|
later version, or |
3303
|
|
|
|
|
|
|
|
3304
|
|
|
|
|
|
|
b) the "Artistic License" which comes with this Kit. |
3305
|
|
|
|
|
|
|
|
3306
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, |
3307
|
|
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
3308
|
|
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either |
3309
|
|
|
|
|
|
|
the GNU General Public License or the Artistic License for more details. |
3310
|
|
|
|
|
|
|
|
3311
|
|
|
|
|
|
|
OS $^O |
3312
|
|
|
|
|
|
|
Tk Version $Tk::VERSION |
3313
|
|
|
|
|
|
|
Perl Version $] |
3314
|
|
|
|
|
|
|
Data::Dumper Version $Data::Dumper::VERSION |
3315
|
|
|
|
|
|
|
$threadString |
3316
|
|
|
|
|
|
|
__STR__ |
3317
|
|
|
|
|
|
|
|
3318
|
|
|
|
|
|
|
$self->DoAlert($str, "About ptkdb") ; |
3319
|
|
|
|
|
|
|
} # end of DoAbout |
3320
|
|
|
|
|
|
|
|
3321
|
|
|
|
|
|
|
# |
3322
|
|
|
|
|
|
|
# return 1 if succesfully set, |
3323
|
|
|
|
|
|
|
# return 0 if otherwise |
3324
|
|
|
|
|
|
|
# |
3325
|
|
|
|
|
|
|
sub SetBreakPoint { |
3326
|
|
|
|
|
|
|
my ($self, $isTemp) = @_ ; |
3327
|
|
|
|
|
|
|
my $dbw = $DB::window ; |
3328
|
|
|
|
|
|
|
my $lineno = $dbw->get_lineno() ; |
3329
|
|
|
|
|
|
|
my $expr = $dbw->clear_entry_text() ; |
3330
|
|
|
|
|
|
|
local($^W) = 0 ; |
3331
|
|
|
|
|
|
|
|
3332
|
|
|
|
|
|
|
if( !&DB::checkdbline($DB::window->{current_file}, $lineno + $self->{'line_offset'}) ) { |
3333
|
|
|
|
|
|
|
$dbw->DoAlert("line $lineno in $DB::window->{current_file} is not breakable") ; |
3334
|
|
|
|
|
|
|
return 0 ; |
3335
|
|
|
|
|
|
|
} |
3336
|
|
|
|
|
|
|
|
3337
|
|
|
|
|
|
|
if( !$isTemp ) { |
3338
|
|
|
|
|
|
|
$dbw->insertBreakpoint($DB::window->{current_file}, $lineno, 1, $expr) ; |
3339
|
|
|
|
|
|
|
return 1 ; |
3340
|
|
|
|
|
|
|
} |
3341
|
|
|
|
|
|
|
else { |
3342
|
|
|
|
|
|
|
$dbw->insertTempBreakpoint($DB::window->{current_file}, $lineno) ; |
3343
|
|
|
|
|
|
|
return 1 ; |
3344
|
|
|
|
|
|
|
} |
3345
|
|
|
|
|
|
|
|
3346
|
|
|
|
|
|
|
return 0 ; |
3347
|
|
|
|
|
|
|
} # end of SetBreakPoint |
3348
|
|
|
|
|
|
|
|
3349
|
|
|
|
|
|
|
sub UnsetBreakPoint { |
3350
|
|
|
|
|
|
|
my ($self) = @_ ; |
3351
|
|
|
|
|
|
|
my $lineno = $self->get_lineno() ; |
3352
|
|
|
|
|
|
|
|
3353
|
|
|
|
|
|
|
$self->removeBreakpoint($DB::window->{current_file}, $lineno) ; |
3354
|
|
|
|
|
|
|
} # end of UnsetBreakPoint |
3355
|
|
|
|
|
|
|
|
3356
|
|
|
|
|
|
|
sub balloon_post { |
3357
|
|
|
|
|
|
|
my $self = $DB::window ; |
3358
|
|
|
|
|
|
|
my $txt = $DB::window->{'text'} ; |
3359
|
|
|
|
|
|
|
|
3360
|
|
|
|
|
|
|
return 0 if ($self->{'expr_ballon_msg'} eq "") || ($self->{'balloon_expr'} eq "") ; # don't post for an empty string |
3361
|
|
|
|
|
|
|
|
3362
|
|
|
|
|
|
|
return $self->{'balloon_coord'} ; |
3363
|
|
|
|
|
|
|
} |
3364
|
|
|
|
|
|
|
|
3365
|
|
|
|
|
|
|
sub balloon_motion { |
3366
|
|
|
|
|
|
|
my ($txt, $x, $y) = @_ ; |
3367
|
|
|
|
|
|
|
my ($offset_x, $offset_y) = ($x + 4, $y + 4) ; |
3368
|
|
|
|
|
|
|
my $self = $DB::window ; |
3369
|
|
|
|
|
|
|
my $txt2 = $self->{'text'} ; |
3370
|
|
|
|
|
|
|
my $data ; |
3371
|
|
|
|
|
|
|
|
3372
|
|
|
|
|
|
|
$self->{'balloon_coord'} = "$offset_x,$offset_y" ; |
3373
|
|
|
|
|
|
|
|
3374
|
|
|
|
|
|
|
$x -= $txt->rootx ; |
3375
|
|
|
|
|
|
|
$y -= $txt->rooty ; |
3376
|
|
|
|
|
|
|
# |
3377
|
|
|
|
|
|
|
# Post an event that will cause us to put up a popup |
3378
|
|
|
|
|
|
|
# |
3379
|
|
|
|
|
|
|
|
3380
|
|
|
|
|
|
|
if( $txt2->tagRanges('sel') ) { # check to see if 'sel' tag exists (return undef value) |
3381
|
|
|
|
|
|
|
$data = $txt2->get("sel.first", "sel.last") ; # get the text between the 'first' and 'last' point of the sel (selection) tag |
3382
|
|
|
|
|
|
|
} |
3383
|
|
|
|
|
|
|
else { |
3384
|
|
|
|
|
|
|
$data = $DB::window->retrieve_text_expr($x, $y) ; |
3385
|
|
|
|
|
|
|
} |
3386
|
|
|
|
|
|
|
|
3387
|
|
|
|
|
|
|
if( !$data ) { |
3388
|
|
|
|
|
|
|
$self->{'balloon_expr'} = "" ; |
3389
|
|
|
|
|
|
|
return 0 ; |
3390
|
|
|
|
|
|
|
} |
3391
|
|
|
|
|
|
|
|
3392
|
|
|
|
|
|
|
return 0 if ($data eq $self->{'balloon_expr'}) ; # nevermind if it's the same expression |
3393
|
|
|
|
|
|
|
|
3394
|
|
|
|
|
|
|
$self->{'event'} = 'balloon_eval' ; |
3395
|
|
|
|
|
|
|
$self->{'balloon_expr'} = $data ; |
3396
|
|
|
|
|
|
|
|
3397
|
|
|
|
|
|
|
return 1 ; # ballon will be canceled and a new one put up(maybe) |
3398
|
|
|
|
|
|
|
} # end of balloon_motion |
3399
|
|
|
|
|
|
|
|
3400
|
|
|
|
|
|
|
sub retrieve_text_expr { |
3401
|
|
|
|
|
|
|
my($self, $x, $y) = @_ ; |
3402
|
|
|
|
|
|
|
my $txt = $self->{'text'} ; |
3403
|
|
|
|
|
|
|
|
3404
|
|
|
|
|
|
|
my $coord = "\@$x,$y" ; |
3405
|
|
|
|
|
|
|
|
3406
|
|
|
|
|
|
|
my($idx, $col, $data, $offset) ; |
3407
|
|
|
|
|
|
|
|
3408
|
|
|
|
|
|
|
($col, $idx) = line_number_from_coord($txt, $coord) ; |
3409
|
|
|
|
|
|
|
|
3410
|
|
|
|
|
|
|
$offset = $Devel::ptkdb::linenumber_length + 1 ; # line number text + 1 space |
3411
|
|
|
|
|
|
|
|
3412
|
|
|
|
|
|
|
return undef if $col < $offset ; # no posting |
3413
|
|
|
|
|
|
|
|
3414
|
|
|
|
|
|
|
$col -= $offset ; |
3415
|
|
|
|
|
|
|
|
3416
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $self->{current_file}} ; |
3417
|
|
|
|
|
|
|
|
3418
|
|
|
|
|
|
|
return undef if( !defined $dbline[$idx] || $dbline[$idx] == 0 ) ; # no executable text, no real variable(?) |
3419
|
|
|
|
|
|
|
|
3420
|
|
|
|
|
|
|
$data = $dbline[$idx] ; |
3421
|
|
|
|
|
|
|
|
3422
|
|
|
|
|
|
|
# if we're sitting over white space, leave |
3423
|
|
|
|
|
|
|
my $len = length $data ; |
3424
|
|
|
|
|
|
|
return unless $data && $col && $len > 0 ; |
3425
|
|
|
|
|
|
|
|
3426
|
|
|
|
|
|
|
return if substr($data, $col, 1) =~ /\s/ ; |
3427
|
|
|
|
|
|
|
|
3428
|
|
|
|
|
|
|
# walk backwards till we find some whitespace |
3429
|
|
|
|
|
|
|
|
3430
|
|
|
|
|
|
|
$col = $len if $len < $col ; |
3431
|
|
|
|
|
|
|
while( --$col >= 0 ) { |
3432
|
|
|
|
|
|
|
last if substr($data, $col, 1) =~ /[\s\$\@\%]/ ; |
3433
|
|
|
|
|
|
|
} |
3434
|
|
|
|
|
|
|
|
3435
|
|
|
|
|
|
|
substr($data, $col) =~ /^([\$\@\%][a-zA-Z0-9_]+)/ ; |
3436
|
|
|
|
|
|
|
|
3437
|
|
|
|
|
|
|
return $1 ; |
3438
|
|
|
|
|
|
|
} |
3439
|
|
|
|
|
|
|
|
3440
|
|
|
|
|
|
|
# |
3441
|
|
|
|
|
|
|
# after DB::eval get's us a result |
3442
|
|
|
|
|
|
|
# |
3443
|
|
|
|
|
|
|
sub code_motion_eval { |
3444
|
|
|
|
|
|
|
my ($self, @result) = @_ ; |
3445
|
|
|
|
|
|
|
my $str ; |
3446
|
|
|
|
|
|
|
|
3447
|
|
|
|
|
|
|
if( exists $self->{'balloon_dumper'} ) { |
3448
|
|
|
|
|
|
|
|
3449
|
|
|
|
|
|
|
my $d = $self->{'balloon_dumper'} ; |
3450
|
|
|
|
|
|
|
|
3451
|
|
|
|
|
|
|
$d->Reset() ; |
3452
|
|
|
|
|
|
|
$d->Values( [ $#result == 0 ? @result : \@result ] ) ; |
3453
|
|
|
|
|
|
|
|
3454
|
|
|
|
|
|
|
if( $d->can('Dumpxs') ) { |
3455
|
|
|
|
|
|
|
$str = $d->Dumpxs() ; |
3456
|
|
|
|
|
|
|
} |
3457
|
|
|
|
|
|
|
else { |
3458
|
|
|
|
|
|
|
$str = $d->Dump() ; |
3459
|
|
|
|
|
|
|
} |
3460
|
|
|
|
|
|
|
|
3461
|
|
|
|
|
|
|
chomp($str) ; |
3462
|
|
|
|
|
|
|
} |
3463
|
|
|
|
|
|
|
else { |
3464
|
|
|
|
|
|
|
$str = "@result" ; |
3465
|
|
|
|
|
|
|
} |
3466
|
|
|
|
|
|
|
|
3467
|
|
|
|
|
|
|
# |
3468
|
|
|
|
|
|
|
# Cut the string down to 1024 characters to keep from |
3469
|
|
|
|
|
|
|
# overloading the balloon window |
3470
|
|
|
|
|
|
|
# |
3471
|
|
|
|
|
|
|
|
3472
|
|
|
|
|
|
|
$self->{'expr_ballon_msg'} = "$self->{'balloon_expr'} = " . substr $str, 0, 1024 ; |
3473
|
|
|
|
|
|
|
} # end of code motion eval |
3474
|
|
|
|
|
|
|
|
3475
|
|
|
|
|
|
|
# |
3476
|
|
|
|
|
|
|
# Subroutine called when we enter DB::DB() |
3477
|
|
|
|
|
|
|
# In other words when the target script 'stops' |
3478
|
|
|
|
|
|
|
# in the Debugger |
3479
|
|
|
|
|
|
|
# |
3480
|
|
|
|
|
|
|
sub EnterActions { |
3481
|
|
|
|
|
|
|
my($self) = @_ ; |
3482
|
|
|
|
|
|
|
|
3483
|
|
|
|
|
|
|
# $self->{'main_window'}->Unbusy() ; |
3484
|
|
|
|
|
|
|
|
3485
|
|
|
|
|
|
|
} # end of EnterActions |
3486
|
|
|
|
|
|
|
|
3487
|
|
|
|
|
|
|
# |
3488
|
|
|
|
|
|
|
# Subroutine called when we return from DB::DB() |
3489
|
|
|
|
|
|
|
# When the target script resumes. |
3490
|
|
|
|
|
|
|
# |
3491
|
|
|
|
|
|
|
sub LeaveActions { |
3492
|
|
|
|
|
|
|
my($self) = @_ ; |
3493
|
|
|
|
|
|
|
|
3494
|
|
|
|
|
|
|
# $self->{'main_window'}->Busy() ; |
3495
|
|
|
|
|
|
|
} # end of LeaveActions |
3496
|
|
|
|
|
|
|
|
3497
|
|
|
|
|
|
|
|
3498
|
|
|
|
|
|
|
sub BEGIN { |
3499
|
|
|
|
|
|
|
$Devel::ptkdb::scriptName = $0 ; |
3500
|
|
|
|
|
|
|
@Devel::ptkdb::script_args = @ARGV ; # copy args |
3501
|
|
|
|
|
|
|
|
3502
|
|
|
|
|
|
|
} |
3503
|
|
|
|
|
|
|
|
3504
|
|
|
|
|
|
|
## |
3505
|
|
|
|
|
|
|
## Save the ptkdb state file and restart the debugger |
3506
|
|
|
|
|
|
|
## |
3507
|
|
|
|
|
|
|
sub DoRestart { |
3508
|
|
|
|
|
|
|
my($fname) ; |
3509
|
|
|
|
|
|
|
|
3510
|
|
|
|
|
|
|
$fname = $ENV{'TMP'} || $ENV{'TMPDIR'} || $ENV{'TMP_DIR'} || $ENV{'TEMP'} || $ENV{'HOME'} ; |
3511
|
|
|
|
|
|
|
$fname .= '/' if $fname ; |
3512
|
|
|
|
|
|
|
$fname = "" unless $fname ; |
3513
|
|
|
|
|
|
|
|
3514
|
|
|
|
|
|
|
$fname .= "ptkdb_restart_state$$" ; |
3515
|
|
|
|
|
|
|
|
3516
|
|
|
|
|
|
|
# print "saving temp state file $fname\n" ; |
3517
|
|
|
|
|
|
|
|
3518
|
|
|
|
|
|
|
&DB::save_state_file($fname) ; |
3519
|
|
|
|
|
|
|
|
3520
|
|
|
|
|
|
|
$ENV{'PTKDB_RESTART_STATE_FILE'} = $fname ; |
3521
|
|
|
|
|
|
|
|
3522
|
|
|
|
|
|
|
## |
3523
|
|
|
|
|
|
|
## build up the command to do the restart |
3524
|
|
|
|
|
|
|
## |
3525
|
|
|
|
|
|
|
|
3526
|
|
|
|
|
|
|
$fname = "perl -w -d:ptkdb $Devel::ptkdb::scriptName @Devel::ptkdb::script_args" ; |
3527
|
|
|
|
|
|
|
|
3528
|
|
|
|
|
|
|
# print "$$ doing a restart with $fname\n" ; |
3529
|
|
|
|
|
|
|
|
3530
|
|
|
|
|
|
|
exec $fname ; |
3531
|
|
|
|
|
|
|
|
3532
|
|
|
|
|
|
|
} # end of DoRestart |
3533
|
|
|
|
|
|
|
|
3534
|
|
|
|
|
|
|
## |
3535
|
|
|
|
|
|
|
## Enables/Disables the feature where we stop |
3536
|
|
|
|
|
|
|
## if we've encountered a perl warning such as: |
3537
|
|
|
|
|
|
|
## "Use of uninitialized value at undef_warn.pl line N" |
3538
|
|
|
|
|
|
|
## |
3539
|
|
|
|
|
|
|
|
3540
|
|
|
|
|
|
|
sub stop_on_warning_cb { |
3541
|
|
|
|
|
|
|
&$DB::ptkdb::warn_sig_save() if $DB::ptkdb::warn_sig_save ; # call any previously registered warning |
3542
|
|
|
|
|
|
|
$DB::window->DoAlert(@_) ; |
3543
|
|
|
|
|
|
|
$DB::single = 1 ; # forces debugger to stop next time |
3544
|
|
|
|
|
|
|
} |
3545
|
|
|
|
|
|
|
|
3546
|
|
|
|
|
|
|
sub set_stop_on_warning { |
3547
|
|
|
|
|
|
|
|
3548
|
|
|
|
|
|
|
if( $DB::ptkdb::stop_on_warning ) { |
3549
|
|
|
|
|
|
|
|
3550
|
|
|
|
|
|
|
return if $DB::ptkdb::warn_sig_save == \&stop_on_warning_cb ; # prevents recursion |
3551
|
|
|
|
|
|
|
|
3552
|
|
|
|
|
|
|
$DB::ptkdb::warn_sig_save = $SIG{'__WARN__'} if $SIG{'__WARN__'} ; |
3553
|
|
|
|
|
|
|
$SIG{'__WARN__'} = \&stop_on_warning_cb ; |
3554
|
|
|
|
|
|
|
} |
3555
|
|
|
|
|
|
|
else { |
3556
|
|
|
|
|
|
|
## |
3557
|
|
|
|
|
|
|
## Restore any previous warning signal |
3558
|
|
|
|
|
|
|
## |
3559
|
|
|
|
|
|
|
local($^W) = 0 ; |
3560
|
|
|
|
|
|
|
$SIG{'__WARN__'} = $DB::ptkdb::warn_sig_save ; |
3561
|
|
|
|
|
|
|
} |
3562
|
|
|
|
|
|
|
} # end of set_stop_on_warning |
3563
|
|
|
|
|
|
|
|
3564
|
|
|
|
|
|
|
1 ; # end of Devel::ptkdb |
3565
|
|
|
|
|
|
|
|
3566
|
|
|
|
|
|
|
package DB ; |
3567
|
|
|
|
|
|
|
|
3568
|
|
|
|
|
|
|
use vars '$VERSION', '$header' ; |
3569
|
|
|
|
|
|
|
|
3570
|
|
|
|
|
|
|
$VERSION = '1.1091' ; |
3571
|
|
|
|
|
|
|
$header = "ptkdb.pm version $DB::VERSION"; |
3572
|
|
|
|
|
|
|
$DB::window->{current_file} = "" ; |
3573
|
|
|
|
|
|
|
|
3574
|
|
|
|
|
|
|
# |
3575
|
|
|
|
|
|
|
# Here's the clue... |
3576
|
|
|
|
|
|
|
# eval only seems to eval the context of |
3577
|
|
|
|
|
|
|
# the executing script while in the DB |
3578
|
|
|
|
|
|
|
# package. When we had updateExprs in the Devel::ptkdb |
3579
|
|
|
|
|
|
|
# package eval would turn up an undef result. |
3580
|
|
|
|
|
|
|
# |
3581
|
|
|
|
|
|
|
|
3582
|
|
|
|
|
|
|
sub updateExprs { |
3583
|
|
|
|
|
|
|
my ($package) = @_ ; |
3584
|
|
|
|
|
|
|
# |
3585
|
|
|
|
|
|
|
# Update expressions |
3586
|
|
|
|
|
|
|
# |
3587
|
|
|
|
|
|
|
$DB::window->deleteAllExprs() ; |
3588
|
|
|
|
|
|
|
my ($expr, @result); |
3589
|
|
|
|
|
|
|
|
3590
|
|
|
|
|
|
|
foreach $expr ( @{$DB::window->{'expr_list'}} ) { |
3591
|
|
|
|
|
|
|
next if length $expr == 0 ; |
3592
|
|
|
|
|
|
|
|
3593
|
|
|
|
|
|
|
@result = &DB::dbeval($package, $expr->{'expr'}) ; |
3594
|
|
|
|
|
|
|
|
3595
|
|
|
|
|
|
|
if( @result == 1 ) { |
3596
|
|
|
|
|
|
|
$DB::window->insertExpr([ $result[0] ], $DB::window->{'data_list'}, $result[0], $expr->{'expr'}, $expr->{'depth'}) ; |
3597
|
|
|
|
|
|
|
} |
3598
|
|
|
|
|
|
|
else { |
3599
|
|
|
|
|
|
|
$DB::window->insertExpr([ \@result ], $DB::window->{'data_list'}, \@result, $expr->{'expr'}, $expr->{'depth'}) ; |
3600
|
|
|
|
|
|
|
} |
3601
|
|
|
|
|
|
|
} |
3602
|
|
|
|
|
|
|
|
3603
|
|
|
|
|
|
|
} # end of updateExprs |
3604
|
|
|
|
|
|
|
|
3605
|
|
|
|
|
|
|
no strict ; # turning strict off (shame shame) because we keep getting errrs for the local(*dbline) |
3606
|
|
|
|
|
|
|
|
3607
|
|
|
|
|
|
|
# |
3608
|
|
|
|
|
|
|
# returns true if line is breakable |
3609
|
|
|
|
|
|
|
# |
3610
|
|
|
|
|
|
|
use Carp ; |
3611
|
|
|
|
|
|
|
sub checkdbline($$) { |
3612
|
|
|
|
|
|
|
my ($fname, $lineno) = @_ ; |
3613
|
|
|
|
|
|
|
|
3614
|
|
|
|
|
|
|
return 0 unless $fname; # we're getting an undef here on 'Restart...' |
3615
|
|
|
|
|
|
|
|
3616
|
|
|
|
|
|
|
local($^W) = 0 ; # spares us warnings under -w |
3617
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname} ; |
3618
|
|
|
|
|
|
|
|
3619
|
|
|
|
|
|
|
my $flag = $dbline[$lineno] != 0 ; |
3620
|
|
|
|
|
|
|
|
3621
|
|
|
|
|
|
|
return $flag; |
3622
|
|
|
|
|
|
|
|
3623
|
|
|
|
|
|
|
} # end of checkdbline |
3624
|
|
|
|
|
|
|
|
3625
|
|
|
|
|
|
|
# |
3626
|
|
|
|
|
|
|
# sets a breakpoint 'through' a magic |
3627
|
|
|
|
|
|
|
# variable that perl is able to interpert |
3628
|
|
|
|
|
|
|
# |
3629
|
|
|
|
|
|
|
sub setdbline($$$) { |
3630
|
|
|
|
|
|
|
my ($fname, $lineno, $value) = @_ ; |
3631
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname}; |
3632
|
|
|
|
|
|
|
|
3633
|
|
|
|
|
|
|
$dbline{$lineno} = $value ; |
3634
|
|
|
|
|
|
|
} # end of setdbline |
3635
|
|
|
|
|
|
|
|
3636
|
|
|
|
|
|
|
sub getdbline($$) { |
3637
|
|
|
|
|
|
|
my ($fname, $lineno) = @_ ; |
3638
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname}; |
3639
|
|
|
|
|
|
|
return $dbline{$lineno} ; |
3640
|
|
|
|
|
|
|
} # end of getdbline |
3641
|
|
|
|
|
|
|
|
3642
|
|
|
|
|
|
|
sub getdbtextline { |
3643
|
|
|
|
|
|
|
my ($fname, $lineno) = @_ ; |
3644
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname}; |
3645
|
|
|
|
|
|
|
return $dbline[$lineno] ; |
3646
|
|
|
|
|
|
|
} # end of getdbline |
3647
|
|
|
|
|
|
|
|
3648
|
|
|
|
|
|
|
|
3649
|
|
|
|
|
|
|
sub cleardbline($$;&) { |
3650
|
|
|
|
|
|
|
my ($fname, $lineno, $clearsub) = @_ ; |
3651
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname}; |
3652
|
|
|
|
|
|
|
my $value ; # just in case we want it for something |
3653
|
|
|
|
|
|
|
|
3654
|
|
|
|
|
|
|
$value = $dbline{$lineno} ; |
3655
|
|
|
|
|
|
|
delete $dbline{$lineno} ; |
3656
|
|
|
|
|
|
|
&$clearsub($value) if $value && $clearsub ; |
3657
|
|
|
|
|
|
|
|
3658
|
|
|
|
|
|
|
return $value ; |
3659
|
|
|
|
|
|
|
} # end of cleardbline |
3660
|
|
|
|
|
|
|
|
3661
|
|
|
|
|
|
|
sub clearalldblines(;&) { |
3662
|
|
|
|
|
|
|
my ($clearsub) = @_ ; |
3663
|
|
|
|
|
|
|
my ($key, $value, $brkPt, $dbkey) ; |
3664
|
|
|
|
|
|
|
local(*dbline) ; |
3665
|
|
|
|
|
|
|
|
3666
|
|
|
|
|
|
|
while ( ($key, $value) = each %main:: ) { # key loop |
3667
|
|
|
|
|
|
|
next unless $key =~ /^_ ; |
3668
|
|
|
|
|
|
|
*dbline = $value ; |
3669
|
|
|
|
|
|
|
|
3670
|
|
|
|
|
|
|
foreach $dbkey (keys %dbline) { |
3671
|
|
|
|
|
|
|
$brkPt = $dbline{$dbkey} ; |
3672
|
|
|
|
|
|
|
delete $dbline{$dbkey} ; |
3673
|
|
|
|
|
|
|
next unless $brkPt && $clearSub ; |
3674
|
|
|
|
|
|
|
&$clearsub($brkPt) ; # if specificed, call the sub routine to clear the breakpoint |
3675
|
|
|
|
|
|
|
} |
3676
|
|
|
|
|
|
|
|
3677
|
|
|
|
|
|
|
} # end of key loop |
3678
|
|
|
|
|
|
|
|
3679
|
|
|
|
|
|
|
} # end of clearalldblines |
3680
|
|
|
|
|
|
|
|
3681
|
|
|
|
|
|
|
sub getdblineindexes { |
3682
|
|
|
|
|
|
|
my ($fname) = @_ ; |
3683
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname} ; |
3684
|
|
|
|
|
|
|
return keys %dbline ; |
3685
|
|
|
|
|
|
|
} # end of getdblineindexes |
3686
|
|
|
|
|
|
|
|
3687
|
|
|
|
|
|
|
sub getbreakpoints { |
3688
|
|
|
|
|
|
|
my (@fnames) = @_ ; |
3689
|
|
|
|
|
|
|
my ($fname, @retList) ; |
3690
|
|
|
|
|
|
|
|
3691
|
|
|
|
|
|
|
foreach $fname (@fnames) { |
3692
|
|
|
|
|
|
|
next unless $main::{'_<' . $fname} ; |
3693
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname} ; |
3694
|
|
|
|
|
|
|
push @retList, values %dbline ; |
3695
|
|
|
|
|
|
|
} |
3696
|
|
|
|
|
|
|
return @retList ; |
3697
|
|
|
|
|
|
|
} # end of getbreakpoints |
3698
|
|
|
|
|
|
|
|
3699
|
|
|
|
|
|
|
# |
3700
|
|
|
|
|
|
|
# Construct a hash of the files |
3701
|
|
|
|
|
|
|
# that have breakpoints to save |
3702
|
|
|
|
|
|
|
# |
3703
|
|
|
|
|
|
|
sub breakpoints_to_save { |
3704
|
|
|
|
|
|
|
my ($file, @breaks, $brkPt, $svBrkPt, $list) ; |
3705
|
|
|
|
|
|
|
my ($brkList) ; |
3706
|
|
|
|
|
|
|
|
3707
|
|
|
|
|
|
|
$brkList = {} ; |
3708
|
|
|
|
|
|
|
|
3709
|
|
|
|
|
|
|
foreach $file ( keys %main:: ) { # file loop |
3710
|
|
|
|
|
|
|
next unless $file =~ /^_ && exists $main::{$file} ; |
3711
|
|
|
|
|
|
|
local(*dbline) = $main::{$file} ; |
3712
|
|
|
|
|
|
|
|
3713
|
|
|
|
|
|
|
next unless @breaks = values %dbline ; |
3714
|
|
|
|
|
|
|
$list = [] ; |
3715
|
|
|
|
|
|
|
foreach $brkPt ( @breaks ) { |
3716
|
|
|
|
|
|
|
|
3717
|
|
|
|
|
|
|
$svBrkPt = { %$brkPt } ; # make a copy of it's data |
3718
|
|
|
|
|
|
|
|
3719
|
|
|
|
|
|
|
push @$list, $svBrkPt ; |
3720
|
|
|
|
|
|
|
|
3721
|
|
|
|
|
|
|
} # end of breakpoint loop |
3722
|
|
|
|
|
|
|
|
3723
|
|
|
|
|
|
|
$brkList->{$file} = $list ; |
3724
|
|
|
|
|
|
|
|
3725
|
|
|
|
|
|
|
} # end of file loop |
3726
|
|
|
|
|
|
|
|
3727
|
|
|
|
|
|
|
return $brkList ; |
3728
|
|
|
|
|
|
|
|
3729
|
|
|
|
|
|
|
} # end of breakpoints_to_save |
3730
|
|
|
|
|
|
|
|
3731
|
|
|
|
|
|
|
# |
3732
|
|
|
|
|
|
|
# When we restore breakpoints from a state file |
3733
|
|
|
|
|
|
|
# they've often 'moved' because the file |
3734
|
|
|
|
|
|
|
# has been editted. |
3735
|
|
|
|
|
|
|
# |
3736
|
|
|
|
|
|
|
# We search for the line starting with the original line number, |
3737
|
|
|
|
|
|
|
# then we walk it back 20 lines, then with line right after the |
3738
|
|
|
|
|
|
|
# orginal line number and walk forward 20 lines. |
3739
|
|
|
|
|
|
|
# |
3740
|
|
|
|
|
|
|
# NOTE: dbline is expected to be 'local' |
3741
|
|
|
|
|
|
|
# when called |
3742
|
|
|
|
|
|
|
# |
3743
|
|
|
|
|
|
|
sub fix_breakpoints { |
3744
|
|
|
|
|
|
|
my(@brkPts) = @_ ; |
3745
|
|
|
|
|
|
|
my($startLine, $endLine, $nLines, $brkPt) ; |
3746
|
|
|
|
|
|
|
my (@retList) ; |
3747
|
|
|
|
|
|
|
local($^W) = 0 ; |
3748
|
|
|
|
|
|
|
|
3749
|
|
|
|
|
|
|
$nLines = scalar @dbline ; |
3750
|
|
|
|
|
|
|
|
3751
|
|
|
|
|
|
|
foreach $brkPt (@brkPts) { |
3752
|
|
|
|
|
|
|
|
3753
|
|
|
|
|
|
|
$startLine = $brkPt->{'line'} > 20 ? $brkPt->{'line'} - 20 : 0 ; |
3754
|
|
|
|
|
|
|
$endLine = $brkPt->{'line'} < $nLines - 20 ? $brkPt->{'line'} + 20 : $nLines ; |
3755
|
|
|
|
|
|
|
|
3756
|
|
|
|
|
|
|
for( (reverse $startLine..$brkPt->{'line'}), $brkPt->{'line'} + 1 .. $endLine ) { |
3757
|
|
|
|
|
|
|
next unless $brkPt->{'text'} eq $dbline[$_] ; |
3758
|
|
|
|
|
|
|
$brkPt->{'line'} = $_ ; |
3759
|
|
|
|
|
|
|
push @retList, $brkPt ; |
3760
|
|
|
|
|
|
|
last ; |
3761
|
|
|
|
|
|
|
} |
3762
|
|
|
|
|
|
|
} # end of breakpoint list |
3763
|
|
|
|
|
|
|
|
3764
|
|
|
|
|
|
|
return @retList ; |
3765
|
|
|
|
|
|
|
|
3766
|
|
|
|
|
|
|
} # end of fix_breakpoints |
3767
|
|
|
|
|
|
|
|
3768
|
|
|
|
|
|
|
# |
3769
|
|
|
|
|
|
|
# Restore breakpoints saved above |
3770
|
|
|
|
|
|
|
# |
3771
|
|
|
|
|
|
|
sub restore_breakpoints_from_save { |
3772
|
|
|
|
|
|
|
my ($brkList) = @_ ; |
3773
|
|
|
|
|
|
|
my ($offset, $key, $list, $brkPt, @newList) ; |
3774
|
|
|
|
|
|
|
|
3775
|
|
|
|
|
|
|
while ( ($key, $list) = each %$brkList ) { # reinsert loop |
3776
|
|
|
|
|
|
|
next unless exists $main::{$key} ; |
3777
|
|
|
|
|
|
|
local(*dbline) = $main::{$key} ; |
3778
|
|
|
|
|
|
|
|
3779
|
|
|
|
|
|
|
$offset = 0 ; |
3780
|
|
|
|
|
|
|
$offset = 1 if $dbline[1] =~ /use\s+.*Devel::_?ptkdb/ ; |
3781
|
|
|
|
|
|
|
|
3782
|
|
|
|
|
|
|
@newList = fix_breakpoints(@$list) ; |
3783
|
|
|
|
|
|
|
|
3784
|
|
|
|
|
|
|
foreach $brkPt ( @newList ) { |
3785
|
|
|
|
|
|
|
if( !&DB::checkdbline($key, $brkPt->{'line'} + $offset) ) { |
3786
|
|
|
|
|
|
|
print "Breakpoint $key:$brkPt->{'line'} in config file is not breakable.\n" ; |
3787
|
|
|
|
|
|
|
next ; |
3788
|
|
|
|
|
|
|
} |
3789
|
|
|
|
|
|
|
$dbline{$brkPt->{'line'}} = { %$brkPt } ; # make a fresh copy |
3790
|
|
|
|
|
|
|
} |
3791
|
|
|
|
|
|
|
} # end of reinsert loop |
3792
|
|
|
|
|
|
|
|
3793
|
|
|
|
|
|
|
} # end of restore_breakpoints_from_save ; |
3794
|
|
|
|
|
|
|
|
3795
|
|
|
|
|
|
|
use strict ; |
3796
|
|
|
|
|
|
|
|
3797
|
|
|
|
|
|
|
sub dbint_handler { |
3798
|
|
|
|
|
|
|
my($sigName) = @_ ; |
3799
|
|
|
|
|
|
|
$DB::single = 1 ; |
3800
|
|
|
|
|
|
|
print "signalled\n" ; |
3801
|
|
|
|
|
|
|
} # end of dbint_handler |
3802
|
|
|
|
|
|
|
|
3803
|
|
|
|
|
|
|
# |
3804
|
|
|
|
|
|
|
# Do first time initialization at the startup |
3805
|
|
|
|
|
|
|
# of DB::DB |
3806
|
|
|
|
|
|
|
# |
3807
|
|
|
|
|
|
|
sub Initialize { |
3808
|
|
|
|
|
|
|
my ($fName) = @_ ; |
3809
|
|
|
|
|
|
|
return if $DB::ptkdb::isInitialized ; |
3810
|
|
|
|
|
|
|
$DB::ptkdb::isInitialized = 1 ; |
3811
|
|
|
|
|
|
|
|
3812
|
|
|
|
|
|
|
$DB::window = new Devel::ptkdb ; |
3813
|
|
|
|
|
|
|
|
3814
|
|
|
|
|
|
|
$DB::window->do_user_init_files() ; |
3815
|
|
|
|
|
|
|
|
3816
|
|
|
|
|
|
|
|
3817
|
|
|
|
|
|
|
$DB::dbint_handler_save = $SIG{'INT'} unless $DB::sigint_disable ; # saves the old handler |
3818
|
|
|
|
|
|
|
$SIG{'INT'} = "DB::dbint_handler" unless $DB::sigint_disable ; |
3819
|
|
|
|
|
|
|
|
3820
|
|
|
|
|
|
|
# Save the file name we started up with |
3821
|
|
|
|
|
|
|
$DB::startupFname = $fName ; |
3822
|
|
|
|
|
|
|
|
3823
|
|
|
|
|
|
|
# Check for a 'restart' file |
3824
|
|
|
|
|
|
|
|
3825
|
|
|
|
|
|
|
if( $ENV{'PTKDB_RESTART_STATE_FILE'} && $Devel::ptkdb::DataDumperAvailable && -e $ENV{'PTKDB_RESTART_STATE_FILE'} ) { |
3826
|
|
|
|
|
|
|
## |
3827
|
|
|
|
|
|
|
## Restore expressions and breakpoints in state file |
3828
|
|
|
|
|
|
|
## |
3829
|
|
|
|
|
|
|
$DB::window->restoreStateFile($ENV{'PTKDB_RESTART_STATE_FILE'}) ; |
3830
|
|
|
|
|
|
|
unlink $ENV{'PTKDB_RESTART_STATE_FILE'} ; # delete state file |
3831
|
|
|
|
|
|
|
|
3832
|
|
|
|
|
|
|
# print "restoring state from $ENV{'PTKDB_RESTART_STATE_FILE'}\n" ; |
3833
|
|
|
|
|
|
|
|
3834
|
|
|
|
|
|
|
$ENV{'PTKDB_RESTART_STATE_FILE'} = "" ; # clear entry |
3835
|
|
|
|
|
|
|
} |
3836
|
|
|
|
|
|
|
else { |
3837
|
|
|
|
|
|
|
&DB::restoreState($fName) if $Devel::ptkdb::DataDumperAvailable ; |
3838
|
|
|
|
|
|
|
} |
3839
|
|
|
|
|
|
|
|
3840
|
|
|
|
|
|
|
} # end of Initialize |
3841
|
|
|
|
|
|
|
|
3842
|
|
|
|
|
|
|
sub restoreState { |
3843
|
|
|
|
|
|
|
my($fName) = @_ ; |
3844
|
|
|
|
|
|
|
my ($stateFile, $files, $expr_list, $eval_saved_text, $main_win_geometry, $restoreName) ; |
3845
|
|
|
|
|
|
|
|
3846
|
|
|
|
|
|
|
$stateFile = makeFileSaveName($fName) ; |
3847
|
|
|
|
|
|
|
|
3848
|
|
|
|
|
|
|
if( -e $stateFile && -r $stateFile ) { |
3849
|
|
|
|
|
|
|
($files, $expr_list, $eval_saved_text, $main_win_geometry) = $DB::window->get_state($stateFile) ; |
3850
|
|
|
|
|
|
|
&DB::restore_breakpoints_from_save($files) ; |
3851
|
|
|
|
|
|
|
$DB::window->{'expr_list'} = $expr_list if defined $expr_list ; |
3852
|
|
|
|
|
|
|
$DB::window->{eval_saved_text} = $eval_saved_text ; |
3853
|
|
|
|
|
|
|
|
3854
|
|
|
|
|
|
|
if ( $main_win_geometry ) { |
3855
|
|
|
|
|
|
|
# restore the height and width of the window |
3856
|
|
|
|
|
|
|
$DB::window->{main_window}->geometry($main_win_geometry) ; |
3857
|
|
|
|
|
|
|
} |
3858
|
|
|
|
|
|
|
} |
3859
|
|
|
|
|
|
|
|
3860
|
|
|
|
|
|
|
} # end of Restore State |
3861
|
|
|
|
|
|
|
|
3862
|
|
|
|
|
|
|
sub makeFileSaveName { |
3863
|
|
|
|
|
|
|
my ($fName) = @_ ; |
3864
|
|
|
|
|
|
|
my $saveName = $fName ; |
3865
|
|
|
|
|
|
|
|
3866
|
|
|
|
|
|
|
if( $saveName =~ /.p[lm]$/ ) { |
3867
|
|
|
|
|
|
|
$saveName =~ s/.pl$/.ptkdb/ ; |
3868
|
|
|
|
|
|
|
} |
3869
|
|
|
|
|
|
|
else { |
3870
|
|
|
|
|
|
|
$saveName .= ".ptkdb" ; |
3871
|
|
|
|
|
|
|
} |
3872
|
|
|
|
|
|
|
|
3873
|
|
|
|
|
|
|
return $saveName ; |
3874
|
|
|
|
|
|
|
} # end of makeFileSaveName |
3875
|
|
|
|
|
|
|
|
3876
|
|
|
|
|
|
|
sub save_state_file { |
3877
|
|
|
|
|
|
|
my($fname) = @_ ; |
3878
|
|
|
|
|
|
|
my($files, $d, $saveStr) ; |
3879
|
|
|
|
|
|
|
|
3880
|
|
|
|
|
|
|
$files = &DB::breakpoints_to_save() ; |
3881
|
|
|
|
|
|
|
|
3882
|
|
|
|
|
|
|
$d = Data::Dumper->new( [ $files, $DB::window->{'expr_list'}, "" ], |
3883
|
|
|
|
|
|
|
[ "files", "expr_list", "eval_saved_text" ] ) ; |
3884
|
|
|
|
|
|
|
|
3885
|
|
|
|
|
|
|
$d->Purity(1) ; |
3886
|
|
|
|
|
|
|
if( Data::Dumper->can('Dumpxs') ) { |
3887
|
|
|
|
|
|
|
$saveStr = $d->Dumpxs() ; |
3888
|
|
|
|
|
|
|
} else { |
3889
|
|
|
|
|
|
|
$saveStr = $d->Dump() ; |
3890
|
|
|
|
|
|
|
} |
3891
|
|
|
|
|
|
|
|
3892
|
|
|
|
|
|
|
local(*F) ; |
3893
|
|
|
|
|
|
|
open F, ">$fname" || die "Couldn't open file $fname" ; |
3894
|
|
|
|
|
|
|
|
3895
|
|
|
|
|
|
|
print F $saveStr || die "Couldn't write file" ; |
3896
|
|
|
|
|
|
|
|
3897
|
|
|
|
|
|
|
close F ; |
3898
|
|
|
|
|
|
|
} # end of save_state_file |
3899
|
|
|
|
|
|
|
|
3900
|
|
|
|
|
|
|
sub SaveState { |
3901
|
|
|
|
|
|
|
my($name_in) = @_ ; |
3902
|
|
|
|
|
|
|
my ($top, $entry, $okayBtn, $win) ; |
3903
|
|
|
|
|
|
|
my ($fname, $saveSub, $cancelSub, $saveName, $eval_saved_text, $d) ; |
3904
|
|
|
|
|
|
|
my ($files, $main_win_geometry); |
3905
|
|
|
|
|
|
|
# |
3906
|
|
|
|
|
|
|
# Create our default name |
3907
|
|
|
|
|
|
|
# |
3908
|
|
|
|
|
|
|
$win = $DB::window ; |
3909
|
|
|
|
|
|
|
|
3910
|
|
|
|
|
|
|
# |
3911
|
|
|
|
|
|
|
# Extract the height and width of our window |
3912
|
|
|
|
|
|
|
# |
3913
|
|
|
|
|
|
|
$main_win_geometry = $win->{main_window}->geometry ; |
3914
|
|
|
|
|
|
|
|
3915
|
|
|
|
|
|
|
if ( defined $win->{save_box} ) { |
3916
|
|
|
|
|
|
|
$win->{save_box}->raise ; |
3917
|
|
|
|
|
|
|
$win->{save_box}->focus ; |
3918
|
|
|
|
|
|
|
return ; |
3919
|
|
|
|
|
|
|
} |
3920
|
|
|
|
|
|
|
|
3921
|
|
|
|
|
|
|
$saveName = $name_in || makeFileSaveName($DB::startupFname) ; |
3922
|
|
|
|
|
|
|
|
3923
|
|
|
|
|
|
|
|
3924
|
|
|
|
|
|
|
|
3925
|
|
|
|
|
|
|
$saveSub = sub { |
3926
|
|
|
|
|
|
|
$win->{'event'} = 'null' ; |
3927
|
|
|
|
|
|
|
|
3928
|
|
|
|
|
|
|
my $saveStr ; |
3929
|
|
|
|
|
|
|
|
3930
|
|
|
|
|
|
|
delete $win->{save_box} ; |
3931
|
|
|
|
|
|
|
|
3932
|
|
|
|
|
|
|
if( exists $win->{eval_window} ) { |
3933
|
|
|
|
|
|
|
$eval_saved_text = $win->{eval_text}->get('0.0', 'end') ; |
3934
|
|
|
|
|
|
|
} |
3935
|
|
|
|
|
|
|
else { |
3936
|
|
|
|
|
|
|
$eval_saved_text = $win->{eval_saved_text} ; |
3937
|
|
|
|
|
|
|
} |
3938
|
|
|
|
|
|
|
|
3939
|
|
|
|
|
|
|
$files = &DB::breakpoints_to_save() ; |
3940
|
|
|
|
|
|
|
|
3941
|
|
|
|
|
|
|
$d = Data::Dumper->new( [ $files, $win->{'expr_list'}, $eval_saved_text, $main_win_geometry ], |
3942
|
|
|
|
|
|
|
[ "files", "expr_list", "eval_saved_text", "main_win_geometry"] ) ; |
3943
|
|
|
|
|
|
|
|
3944
|
|
|
|
|
|
|
$d->Purity(1) ; |
3945
|
|
|
|
|
|
|
if( Data::Dumper->can('Dumpxs') ) { |
3946
|
|
|
|
|
|
|
$saveStr = $d->Dumpxs() ; |
3947
|
|
|
|
|
|
|
} else { |
3948
|
|
|
|
|
|
|
$saveStr = $d->Dump() ; |
3949
|
|
|
|
|
|
|
} |
3950
|
|
|
|
|
|
|
|
3951
|
|
|
|
|
|
|
local(*F) ; |
3952
|
|
|
|
|
|
|
eval { |
3953
|
|
|
|
|
|
|
open F, ">$saveName" || die "Couldn't open file $saveName" ; |
3954
|
|
|
|
|
|
|
|
3955
|
|
|
|
|
|
|
print F $saveStr || die "Couldn't write file" ; |
3956
|
|
|
|
|
|
|
|
3957
|
|
|
|
|
|
|
close F ; |
3958
|
|
|
|
|
|
|
} ; |
3959
|
|
|
|
|
|
|
$win->DoAlert($@) if $@ ; |
3960
|
|
|
|
|
|
|
} ; # end of save sub |
3961
|
|
|
|
|
|
|
|
3962
|
|
|
|
|
|
|
$cancelSub = sub { |
3963
|
|
|
|
|
|
|
delete $win->{'save_box'} |
3964
|
|
|
|
|
|
|
} ; # end of cancel sub |
3965
|
|
|
|
|
|
|
|
3966
|
|
|
|
|
|
|
# |
3967
|
|
|
|
|
|
|
# Create a dialog |
3968
|
|
|
|
|
|
|
# |
3969
|
|
|
|
|
|
|
|
3970
|
|
|
|
|
|
|
$win->{'save_box'} = $win->simplePromptBox("Save Config?", $saveName, $saveSub, $cancelSub) ; |
3971
|
|
|
|
|
|
|
|
3972
|
|
|
|
|
|
|
} # end of SaveState |
3973
|
|
|
|
|
|
|
|
3974
|
|
|
|
|
|
|
sub RestoreState { |
3975
|
|
|
|
|
|
|
my ($top, $restoreSub) ; |
3976
|
|
|
|
|
|
|
|
3977
|
|
|
|
|
|
|
$restoreSub = sub { |
3978
|
|
|
|
|
|
|
$DB::window->restoreStateFile($Devel::ptkdb::promptString) ; |
3979
|
|
|
|
|
|
|
} ; |
3980
|
|
|
|
|
|
|
|
3981
|
|
|
|
|
|
|
$top = $DB::window->simplePromptBox("Restore Config?", makeFileSaveName($DB::startupFname), $restoreSub) ; |
3982
|
|
|
|
|
|
|
|
3983
|
|
|
|
|
|
|
} # end of RestoreState |
3984
|
|
|
|
|
|
|
|
3985
|
|
|
|
|
|
|
sub SetStepOverBreakPoint { |
3986
|
|
|
|
|
|
|
my ($offset) = @_ ; |
3987
|
|
|
|
|
|
|
$DB::step_over_depth = $DB::subroutine_depth + ($offset ? $offset : 0) ; |
3988
|
|
|
|
|
|
|
} # end of SetStepOverBreakPoint |
3989
|
|
|
|
|
|
|
|
3990
|
|
|
|
|
|
|
# |
3991
|
|
|
|
|
|
|
# NOTE: It may be logical and somewhat more economical |
3992
|
|
|
|
|
|
|
# lines of codewise to set $DB::step_over_depth_saved |
3993
|
|
|
|
|
|
|
# when we enter the subroutine, but this gets called |
3994
|
|
|
|
|
|
|
# for EVERY callable line of code in a program that |
3995
|
|
|
|
|
|
|
# is being debugged, so we try to save every line of |
3996
|
|
|
|
|
|
|
# execution that we can. |
3997
|
|
|
|
|
|
|
# |
3998
|
|
|
|
|
|
|
sub isBreakPoint { |
3999
|
|
|
|
|
|
|
my ($fname, $line, $package) = @_ ; |
4000
|
|
|
|
|
|
|
my ($brkPt) ; |
4001
|
|
|
|
|
|
|
|
4002
|
|
|
|
|
|
|
if ( $DB::single && ($DB::step_over_depth < $DB::subroutine_depth) && ($DB::step_over_depth > 0) && !$DB::on) { |
4003
|
|
|
|
|
|
|
$DB::single = 0 ; |
4004
|
|
|
|
|
|
|
return 0 ; |
4005
|
|
|
|
|
|
|
} |
4006
|
|
|
|
|
|
|
# |
4007
|
|
|
|
|
|
|
# doing a step over/in |
4008
|
|
|
|
|
|
|
# |
4009
|
|
|
|
|
|
|
|
4010
|
|
|
|
|
|
|
if( $DB::single || $DB::signal ) { |
4011
|
|
|
|
|
|
|
$DB::single = 0 ; |
4012
|
|
|
|
|
|
|
$DB::signal = 0 ; |
4013
|
|
|
|
|
|
|
$DB::subroutine_depth = $DB::subroutine_depth ; |
4014
|
|
|
|
|
|
|
return 1 ; |
4015
|
|
|
|
|
|
|
} |
4016
|
|
|
|
|
|
|
# |
4017
|
|
|
|
|
|
|
# 1st Check to see if there is even a breakpoint there. |
4018
|
|
|
|
|
|
|
# 2nd If there is a breakpoint check to see if it's check box control is 'on' |
4019
|
|
|
|
|
|
|
# 3rd If there is any kind of expression, evaluate it and see if it's true. |
4020
|
|
|
|
|
|
|
# |
4021
|
|
|
|
|
|
|
$brkPt = &DB::getdbline($fname, $line) ; |
4022
|
|
|
|
|
|
|
|
4023
|
|
|
|
|
|
|
return 0 if( !$brkPt || !$brkPt->{'value'} || !breakPointEvalExpr($brkPt, $package) ) ; |
4024
|
|
|
|
|
|
|
|
4025
|
|
|
|
|
|
|
&DB::cleardbline($fname, $line) if( $brkPt->{'type'} eq 'temp' ) ; |
4026
|
|
|
|
|
|
|
|
4027
|
|
|
|
|
|
|
$DB::subroutine_depth = $DB::subroutine_depth ; |
4028
|
|
|
|
|
|
|
|
4029
|
|
|
|
|
|
|
return 1 ; |
4030
|
|
|
|
|
|
|
} # end of isBreakPoint |
4031
|
|
|
|
|
|
|
|
4032
|
|
|
|
|
|
|
# |
4033
|
|
|
|
|
|
|
# Check the breakpoint expression to see if it |
4034
|
|
|
|
|
|
|
# is true. |
4035
|
|
|
|
|
|
|
# |
4036
|
|
|
|
|
|
|
sub breakPointEvalExpr { |
4037
|
|
|
|
|
|
|
my ($brkPt, $package) = @_ ; |
4038
|
|
|
|
|
|
|
my (@result) ; |
4039
|
|
|
|
|
|
|
|
4040
|
|
|
|
|
|
|
return 1 unless $brkPt->{expr} ; # return if there is no expression |
4041
|
|
|
|
|
|
|
|
4042
|
|
|
|
|
|
|
no strict ; |
4043
|
|
|
|
|
|
|
|
4044
|
|
|
|
|
|
|
@result = &DB::dbeval($package, $brkPt->{'expr'}) ; |
4045
|
|
|
|
|
|
|
|
4046
|
|
|
|
|
|
|
use strict ; |
4047
|
|
|
|
|
|
|
|
4048
|
|
|
|
|
|
|
$DB::window->DoAlert($@) if $@ ; |
4049
|
|
|
|
|
|
|
|
4050
|
|
|
|
|
|
|
return $result[0] or @result ; # we could have a case where the 1st element is undefined |
4051
|
|
|
|
|
|
|
# but subsequent elements are defined |
4052
|
|
|
|
|
|
|
|
4053
|
|
|
|
|
|
|
} # end of breakPointEvalExpr |
4054
|
|
|
|
|
|
|
|
4055
|
|
|
|
|
|
|
# |
4056
|
|
|
|
|
|
|
# Evaluate the given expression, return the result. |
4057
|
|
|
|
|
|
|
# MUST BE CALLED from within DB::DB in order for it |
4058
|
|
|
|
|
|
|
# to properly interpret the vars |
4059
|
|
|
|
|
|
|
# |
4060
|
|
|
|
|
|
|
sub dbeval { |
4061
|
|
|
|
|
|
|
my($ptkdb__package, $ptkdb__expr) = @_ ; |
4062
|
|
|
|
|
|
|
my(@ptkdb__result, $ptkdb__str) ; |
4063
|
|
|
|
|
|
|
my(@ptkdb_args) ; |
4064
|
|
|
|
|
|
|
local($^W) = 0 ; # temporarily turn off warnings |
4065
|
|
|
|
|
|
|
|
4066
|
|
|
|
|
|
|
no strict ; |
4067
|
|
|
|
|
|
|
# |
4068
|
|
|
|
|
|
|
# This substitution is done so that |
4069
|
|
|
|
|
|
|
# we return HASH, as opposed to an ARRAY. |
4070
|
|
|
|
|
|
|
# An expression of %hash results in a |
4071
|
|
|
|
|
|
|
# list of key/value pairs. |
4072
|
|
|
|
|
|
|
# |
4073
|
|
|
|
|
|
|
|
4074
|
|
|
|
|
|
|
$ptkdb__expr =~ s/^\s*%/\\%/o ; |
4075
|
|
|
|
|
|
|
|
4076
|
|
|
|
|
|
|
@_ = @DB::saved_args ; # replace @_ arg array with what we came in with |
4077
|
|
|
|
|
|
|
|
4078
|
|
|
|
|
|
|
@ptkdb__result = eval <<__EVAL__ ; |
4079
|
|
|
|
|
|
|
|
4080
|
|
|
|
|
|
|
|
4081
|
|
|
|
|
|
|
\$\@ = \$DB::save_err ; |
4082
|
|
|
|
|
|
|
|
4083
|
|
|
|
|
|
|
package $ptkdb__package ; |
4084
|
|
|
|
|
|
|
|
4085
|
|
|
|
|
|
|
$ptkdb__expr ; |
4086
|
|
|
|
|
|
|
|
4087
|
|
|
|
|
|
|
__EVAL__ |
4088
|
|
|
|
|
|
|
|
4089
|
|
|
|
|
|
|
@ptkdb__result = ("ERROR ($@)") if $@ ; |
4090
|
|
|
|
|
|
|
|
4091
|
|
|
|
|
|
|
use strict ; |
4092
|
|
|
|
|
|
|
|
4093
|
|
|
|
|
|
|
return @ptkdb__result ; |
4094
|
|
|
|
|
|
|
} # end of dbeval |
4095
|
|
|
|
|
|
|
|
4096
|
|
|
|
|
|
|
# |
4097
|
|
|
|
|
|
|
# Call back we give to our 'quit' button |
4098
|
|
|
|
|
|
|
# and binding to the WM_DELETE_WINDOW protocol |
4099
|
|
|
|
|
|
|
# to quit the debugger. |
4100
|
|
|
|
|
|
|
# |
4101
|
|
|
|
|
|
|
sub dbexit { |
4102
|
|
|
|
|
|
|
exit ; |
4103
|
|
|
|
|
|
|
} # end of dbexit |
4104
|
|
|
|
|
|
|
|
4105
|
|
|
|
|
|
|
# |
4106
|
|
|
|
|
|
|
# This is the primary entry point for the debugger. When a perl program |
4107
|
|
|
|
|
|
|
# is parsed with the -d(in our case -d:ptkdb) option set the parser will |
4108
|
|
|
|
|
|
|
# insert a call to DB::DB in front of every excecutable statement. |
4109
|
|
|
|
|
|
|
# |
4110
|
|
|
|
|
|
|
# Refs: Progamming Perl 2nd Edition, Larry Wall, O'Reilly & Associates, Chapter 8 |
4111
|
|
|
|
|
|
|
# |
4112
|
|
|
|
|
|
|
|
4113
|
|
|
|
|
|
|
|
4114
|
|
|
|
|
|
|
## |
4115
|
|
|
|
|
|
|
## Since perl 5.8.0 we need to predeclare the sub DB{} at the start of the |
4116
|
|
|
|
|
|
|
## package or else the compilation fails. We need to disable warnings though |
4117
|
|
|
|
|
|
|
## since in 5.6.x we get warnings on the sub DB begin redeclared. Using |
4118
|
|
|
|
|
|
|
## local($^W) = 0 will leave warnings disabled for the rest of the compile |
4119
|
|
|
|
|
|
|
## and we don't want that. |
4120
|
|
|
|
|
|
|
## |
4121
|
|
|
|
|
|
|
my($saveW) ; |
4122
|
|
|
|
|
|
|
sub BEGIN { |
4123
|
|
|
|
|
|
|
$saveW = $^W ; |
4124
|
|
|
|
|
|
|
$^W = 0 ; |
4125
|
|
|
|
|
|
|
} |
4126
|
|
|
|
|
|
|
|
4127
|
|
|
|
|
|
|
no strict ; |
4128
|
|
|
|
|
|
|
sub DB { |
4129
|
|
|
|
|
|
|
@DB::saved_args = @_ ; # save arg context |
4130
|
|
|
|
|
|
|
$DB::save_err = $@ ; # save value of $@ |
4131
|
|
|
|
|
|
|
my ($package, $filename, $line) = caller ; |
4132
|
|
|
|
|
|
|
my ($stop, $cnt) ; |
4133
|
|
|
|
|
|
|
|
4134
|
|
|
|
|
|
|
$^W = $saveW ; |
4135
|
|
|
|
|
|
|
unless( $DB::ptkdb::isInitialized ) { |
4136
|
|
|
|
|
|
|
return if( $filename ne $0 ) ; # not in our target file |
4137
|
|
|
|
|
|
|
&DB::Initialize($filename) ; |
4138
|
|
|
|
|
|
|
} |
4139
|
|
|
|
|
|
|
|
4140
|
|
|
|
|
|
|
if (!isBreakPoint($filename, $line, $package) ) { |
4141
|
|
|
|
|
|
|
$DB::single = 0 ; |
4142
|
|
|
|
|
|
|
$@ = $DB::save_err ; |
4143
|
|
|
|
|
|
|
return ; |
4144
|
|
|
|
|
|
|
} |
4145
|
|
|
|
|
|
|
|
4146
|
|
|
|
|
|
|
if ( !$DB::window ) { # not setup yet |
4147
|
|
|
|
|
|
|
$@ = $DB::save_err ; |
4148
|
|
|
|
|
|
|
return ; |
4149
|
|
|
|
|
|
|
} |
4150
|
|
|
|
|
|
|
|
4151
|
|
|
|
|
|
|
$DB::window->setup_main_window() unless $DB::window->{'main_window'} ; |
4152
|
|
|
|
|
|
|
|
4153
|
|
|
|
|
|
|
$DB::window->EnterActions() ; |
4154
|
|
|
|
|
|
|
|
4155
|
|
|
|
|
|
|
my ($saveP) ; |
4156
|
|
|
|
|
|
|
$saveP = $^P ; |
4157
|
|
|
|
|
|
|
$^P = 0 ; |
4158
|
|
|
|
|
|
|
|
4159
|
|
|
|
|
|
|
$DB::on = 1 ; |
4160
|
|
|
|
|
|
|
|
4161
|
|
|
|
|
|
|
# |
4162
|
|
|
|
|
|
|
# The user can specify this variable in one of the startup files, |
4163
|
|
|
|
|
|
|
# this will make the debugger run right after startup without |
4164
|
|
|
|
|
|
|
# the user having to press the 'run' button. |
4165
|
|
|
|
|
|
|
# |
4166
|
|
|
|
|
|
|
if( $DB::no_stop_at_start ) { |
4167
|
|
|
|
|
|
|
$DB::no_stop_at_start = 0 ; |
4168
|
|
|
|
|
|
|
$DB::on = 0 ; |
4169
|
|
|
|
|
|
|
$@ = $DB::save_err ; |
4170
|
|
|
|
|
|
|
return ; |
4171
|
|
|
|
|
|
|
} |
4172
|
|
|
|
|
|
|
|
4173
|
|
|
|
|
|
|
if( !$DB::sigint_disable ) { |
4174
|
|
|
|
|
|
|
$SIG{'INT'} = $DB::dbint_handler_save if $DB::dbint_handler_save ; # restore original signal handler |
4175
|
|
|
|
|
|
|
$SIG{'INT'} = "DB::dbexit" unless $DB::dbint_handler_save ; |
4176
|
|
|
|
|
|
|
} |
4177
|
|
|
|
|
|
|
|
4178
|
|
|
|
|
|
|
#$DB::window->{main_window}->raise() ; # bring us to the top make sure OUR event loop runs |
4179
|
|
|
|
|
|
|
$DB::window->{main_window}->focus() ; |
4180
|
|
|
|
|
|
|
|
4181
|
|
|
|
|
|
|
$DB::window->set_file($filename, $line) ; |
4182
|
|
|
|
|
|
|
# |
4183
|
|
|
|
|
|
|
# Refresh the exprs to see if anything has changed |
4184
|
|
|
|
|
|
|
# |
4185
|
|
|
|
|
|
|
updateExprs($package) ; |
4186
|
|
|
|
|
|
|
|
4187
|
|
|
|
|
|
|
# |
4188
|
|
|
|
|
|
|
# Update subs Page if necessary |
4189
|
|
|
|
|
|
|
# |
4190
|
|
|
|
|
|
|
$cnt = scalar keys %DB::sub ; |
4191
|
|
|
|
|
|
|
if ( $cnt != $DB::window->{'subs_list_cnt'} && $DB::window->{'subs_page_activated'} ) { |
4192
|
|
|
|
|
|
|
$DB::window->fill_subs_page() ; |
4193
|
|
|
|
|
|
|
$DB::window->{'subs_list_cnt'} = $cnt ; |
4194
|
|
|
|
|
|
|
} |
4195
|
|
|
|
|
|
|
# |
4196
|
|
|
|
|
|
|
# Update the subroutine stack menu |
4197
|
|
|
|
|
|
|
# |
4198
|
|
|
|
|
|
|
$DB::window->refresh_stack_menu() ; |
4199
|
|
|
|
|
|
|
|
4200
|
|
|
|
|
|
|
$DB::window->{run_flag} = 1 ; |
4201
|
|
|
|
|
|
|
|
4202
|
|
|
|
|
|
|
my ($evt, @result, $r) ; |
4203
|
|
|
|
|
|
|
|
4204
|
|
|
|
|
|
|
for( ; ; ) { |
4205
|
|
|
|
|
|
|
# |
4206
|
|
|
|
|
|
|
# we wait here for something to do |
4207
|
|
|
|
|
|
|
# |
4208
|
|
|
|
|
|
|
$evt = $DB::window->main_loop() ; |
4209
|
|
|
|
|
|
|
|
4210
|
|
|
|
|
|
|
last if( $evt eq 'step' ) ; |
4211
|
|
|
|
|
|
|
|
4212
|
|
|
|
|
|
|
$DB::single = 0 if ($evt eq 'run' ) ; |
4213
|
|
|
|
|
|
|
|
4214
|
|
|
|
|
|
|
if ($evt eq 'balloon_eval' ) { |
4215
|
|
|
|
|
|
|
$DB::window->code_motion_eval(&DB::dbeval($package, $DB::window->{'balloon_expr'})) ; |
4216
|
|
|
|
|
|
|
next ; |
4217
|
|
|
|
|
|
|
} |
4218
|
|
|
|
|
|
|
|
4219
|
|
|
|
|
|
|
if ( $evt eq 'qexpr' ) { |
4220
|
|
|
|
|
|
|
my $str ; |
4221
|
|
|
|
|
|
|
@result = &DB::dbeval($package, $DB::window->{'qexpr'}) ; |
4222
|
|
|
|
|
|
|
$DB::window->{'quick_entry'}->delete(0, 'end') ; # clear old text |
4223
|
|
|
|
|
|
|
if (exists $DB::window->{'quick_dumper'}) { |
4224
|
|
|
|
|
|
|
$DB::window->{'quick_dumper'}->Reset() ; |
4225
|
|
|
|
|
|
|
$DB::window->{'quick_dumper'}->Values( [ $#result == 0 ? @result : \@result ] ) ; |
4226
|
|
|
|
|
|
|
if( $DB::window->{'quick_dumper'}->can('Dumpxs') ) { |
4227
|
|
|
|
|
|
|
$str = $DB::window->{'quick_dumper'}->Dumpxs() ; |
4228
|
|
|
|
|
|
|
} |
4229
|
|
|
|
|
|
|
else { |
4230
|
|
|
|
|
|
|
$str = $DB::window->{'quick_dumper'}->Dump() ; |
4231
|
|
|
|
|
|
|
} |
4232
|
|
|
|
|
|
|
} |
4233
|
|
|
|
|
|
|
else { |
4234
|
|
|
|
|
|
|
$str = "@result" ; |
4235
|
|
|
|
|
|
|
} |
4236
|
|
|
|
|
|
|
$DB::window->{'quick_entry'}->insert(0, $str) ; #enter the text |
4237
|
|
|
|
|
|
|
$DB::window->{'quick_entry'}->selectionRange(0, 'end') ; # select it |
4238
|
|
|
|
|
|
|
$evt = 'update' ; # force an update on the expressions |
4239
|
|
|
|
|
|
|
} |
4240
|
|
|
|
|
|
|
|
4241
|
|
|
|
|
|
|
if( $evt eq 'expr' ) { |
4242
|
|
|
|
|
|
|
# |
4243
|
|
|
|
|
|
|
# Append the new expression to the list |
4244
|
|
|
|
|
|
|
# but first check to make sure that we don't |
4245
|
|
|
|
|
|
|
# already have it. |
4246
|
|
|
|
|
|
|
# |
4247
|
|
|
|
|
|
|
|
4248
|
|
|
|
|
|
|
if ( grep $_->{'expr'} eq $DB::window->{'expr'}, @{$DB::window->{'expr_list'}} ) { |
4249
|
|
|
|
|
|
|
$DB::window->DoAlert("$DB::window->{'expr'} is already listed") ; |
4250
|
|
|
|
|
|
|
next ; |
4251
|
|
|
|
|
|
|
} |
4252
|
|
|
|
|
|
|
|
4253
|
|
|
|
|
|
|
@result = &DB::dbeval($package, $DB::window->{expr}) ; |
4254
|
|
|
|
|
|
|
|
4255
|
|
|
|
|
|
|
if( @result == 1 ) { |
4256
|
|
|
|
|
|
|
$r = $DB::window->insertExpr([ $result[0] ], $DB::window->{'data_list'}, $result[0], $DB::window->{'expr'}, $Devel::ptkdb::expr_depth) ; |
4257
|
|
|
|
|
|
|
} |
4258
|
|
|
|
|
|
|
else { |
4259
|
|
|
|
|
|
|
$r = $DB::window->insertExpr([ \@result ], $DB::window->{'data_list'}, \@result, $DB::window->{'expr'}, $Devel::ptkdb::expr_depth) ; |
4260
|
|
|
|
|
|
|
} |
4261
|
|
|
|
|
|
|
|
4262
|
|
|
|
|
|
|
# |
4263
|
|
|
|
|
|
|
# $r will be 1 if the expression was added succesfully, 0 if not, |
4264
|
|
|
|
|
|
|
# and it if wasn't added sucessfully it won't be reevalled the |
4265
|
|
|
|
|
|
|
# next time through. |
4266
|
|
|
|
|
|
|
# |
4267
|
|
|
|
|
|
|
push @{$DB::window->{'expr_list'}}, { 'expr' => $DB::window->{'expr'}, 'depth' => $Devel::ptkdb::expr_depth } if $r ; |
4268
|
|
|
|
|
|
|
|
4269
|
|
|
|
|
|
|
next ; |
4270
|
|
|
|
|
|
|
} |
4271
|
|
|
|
|
|
|
if( $evt eq 'update' ) { |
4272
|
|
|
|
|
|
|
updateExprs($package) ; |
4273
|
|
|
|
|
|
|
next ; |
4274
|
|
|
|
|
|
|
} |
4275
|
|
|
|
|
|
|
if( $evt eq 'reeval' ) { |
4276
|
|
|
|
|
|
|
# |
4277
|
|
|
|
|
|
|
# Reevaluate the contents of the expression eval window |
4278
|
|
|
|
|
|
|
# |
4279
|
|
|
|
|
|
|
my $txt = $DB::window->{'eval_text'}->get('0.0', 'end') ; |
4280
|
|
|
|
|
|
|
my @result = &DB::dbeval($package, $txt) ; |
4281
|
|
|
|
|
|
|
|
4282
|
|
|
|
|
|
|
$DB::window->updateEvalWindow(@result) ; |
4283
|
|
|
|
|
|
|
|
4284
|
|
|
|
|
|
|
next ; |
4285
|
|
|
|
|
|
|
} |
4286
|
|
|
|
|
|
|
last ; |
4287
|
|
|
|
|
|
|
} |
4288
|
|
|
|
|
|
|
$^P = $saveP ; |
4289
|
|
|
|
|
|
|
$SIG{'INT'} = "DB::dbint_handler" unless $DB::sigint_disable ; # set our signal handler |
4290
|
|
|
|
|
|
|
|
4291
|
|
|
|
|
|
|
$DB::window->LeaveActions() ; |
4292
|
|
|
|
|
|
|
|
4293
|
|
|
|
|
|
|
$@ = $DB::save_err ; |
4294
|
|
|
|
|
|
|
$DB::on = 0 ; |
4295
|
|
|
|
|
|
|
} # end of DB |
4296
|
|
|
|
|
|
|
|
4297
|
|
|
|
|
|
|
## |
4298
|
|
|
|
|
|
|
## in this case we do not use local($^W) since we would like warnings |
4299
|
|
|
|
|
|
|
## to be issued past this point, and the localized copy of $^W will not |
4300
|
|
|
|
|
|
|
## go out of scope until the end of compilation |
4301
|
|
|
|
|
|
|
## |
4302
|
|
|
|
|
|
|
## |
4303
|
|
|
|
|
|
|
|
4304
|
|
|
|
|
|
|
# |
4305
|
|
|
|
|
|
|
# This is another place where we'll try and keep the |
4306
|
|
|
|
|
|
|
# code as 'lite' as possible to prevent the debugger |
4307
|
|
|
|
|
|
|
# from slowing down the user's application |
4308
|
|
|
|
|
|
|
# |
4309
|
|
|
|
|
|
|
# When a perl program is parsed with the -d(in our case a -d:ptkdb) option |
4310
|
|
|
|
|
|
|
# the parser will route all subroutine calls through here, setting $DB::sub |
4311
|
|
|
|
|
|
|
# to the name of the subroutine to be called, leaving it to the debugger to |
4312
|
|
|
|
|
|
|
# make the actual subroutine call and do any pre or post processing it may |
4313
|
|
|
|
|
|
|
# need to do. In our case we take the opportunity to track the depth of the call |
4314
|
|
|
|
|
|
|
# stack so that we can update our 'Stack' menu when we stop. |
4315
|
|
|
|
|
|
|
# |
4316
|
|
|
|
|
|
|
# Refs: Progamming Perl 2nd Edition, Larry Wall, O'Reilly & Associates, Chapter 8 |
4317
|
|
|
|
|
|
|
# |
4318
|
|
|
|
|
|
|
# |
4319
|
|
|
|
|
|
|
sub sub { |
4320
|
|
|
|
|
|
|
my ($result, @result) ; |
4321
|
|
|
|
|
|
|
# |
4322
|
|
|
|
|
|
|
# See NOTES(1) |
4323
|
|
|
|
|
|
|
# |
4324
|
|
|
|
|
|
|
$DB::subroutine_depth += 1 unless $DB::on ; |
4325
|
|
|
|
|
|
|
$DB::single = 0 if ( ($DB::step_over_depth < $DB::subroutine_depth) && ($DB::step_over_depth >= 0) && !$DB::on) ; |
4326
|
|
|
|
|
|
|
|
4327
|
|
|
|
|
|
|
if( wantarray ) { |
4328
|
|
|
|
|
|
|
# |
4329
|
|
|
|
|
|
|
# array context |
4330
|
|
|
|
|
|
|
# |
4331
|
|
|
|
|
|
|
no strict ; # otherwise perl gripes about calling the sub by the reference |
4332
|
|
|
|
|
|
|
@result = &$DB::sub ; # call the subroutine by name |
4333
|
|
|
|
|
|
|
use strict ; |
4334
|
|
|
|
|
|
|
|
4335
|
|
|
|
|
|
|
$DB::subroutine_depth -= 1 unless $DB::on ; |
4336
|
|
|
|
|
|
|
$DB::single = 1 if ($DB::step_over_depth >= $DB::subroutine_depth && !$DB::on) ; |
4337
|
|
|
|
|
|
|
return @result ; |
4338
|
|
|
|
|
|
|
} |
4339
|
|
|
|
|
|
|
elsif(defined wantarray) { |
4340
|
|
|
|
|
|
|
|
4341
|
|
|
|
|
|
|
# |
4342
|
|
|
|
|
|
|
# scalar context |
4343
|
|
|
|
|
|
|
# |
4344
|
|
|
|
|
|
|
no strict ; |
4345
|
|
|
|
|
|
|
$result = &$DB::sub ; |
4346
|
|
|
|
|
|
|
use strict ; |
4347
|
|
|
|
|
|
|
|
4348
|
|
|
|
|
|
|
$DB::subroutine_depth -= 1 unless $DB::on ; |
4349
|
|
|
|
|
|
|
$DB::single = 1 if ($DB::step_over_depth >= $DB::subroutine_depth && !$DB::on) ; |
4350
|
|
|
|
|
|
|
return $result ; |
4351
|
|
|
|
|
|
|
} else { |
4352
|
|
|
|
|
|
|
# |
4353
|
|
|
|
|
|
|
# void context |
4354
|
|
|
|
|
|
|
# |
4355
|
|
|
|
|
|
|
|
4356
|
|
|
|
|
|
|
no strict ; |
4357
|
|
|
|
|
|
|
&$DB::sub ; |
4358
|
|
|
|
|
|
|
use strict ; |
4359
|
|
|
|
|
|
|
|
4360
|
|
|
|
|
|
|
$DB::subroutine_depth -= 1 unless $DB::on ; |
4361
|
|
|
|
|
|
|
$DB::single = 1 if ($DB::step_over_depth >= $DB::subroutine_depth && !$DB::on) ; |
4362
|
|
|
|
|
|
|
return $result ; |
4363
|
|
|
|
|
|
|
|
4364
|
|
|
|
|
|
|
return ; |
4365
|
|
|
|
|
|
|
} |
4366
|
|
|
|
|
|
|
|
4367
|
|
|
|
|
|
|
} # end of sub |
4368
|
|
|
|
|
|
|
|
4369
|
|
|
|
|
|
|
1 ; # return true value |
4370
|
|
|
|
|
|
|
|
4371
|
|
|
|
|
|
|
# ptkdb.pm,v |
4372
|
|
|
|
|
|
|
# Revision 1.15 2004/03/31 02:08:40 aepage |
4373
|
|
|
|
|
|
|
# fixes for various lacks of backwards compatiblity in Tk804 |
4374
|
|
|
|
|
|
|
# Added a 'bug report' item to the File Menu. |
4375
|
|
|
|
|
|
|
# |
4376
|
|
|
|
|
|
|
# Revision 1.14 2003/11/20 01:59:40 aepage |
4377
|
|
|
|
|
|
|
# version fix |
4378
|
|
|
|
|
|
|
# |
4379
|
|
|
|
|
|
|
# Revision 1.12 2003/11/20 01:46:45 aepage |
4380
|
|
|
|
|
|
|
# Hex Dumper and correction of some parameters for Tk804.025_beta6 |
4381
|
|
|
|
|
|
|
# |
4382
|
|
|
|
|
|
|
# Revision 1.11 2003/06/26 13:42:49 aepage |
4383
|
|
|
|
|
|
|
# fix for chars at the end of win32 platforms. |
4384
|
|
|
|
|
|
|
# |
4385
|
|
|
|
|
|
|
# Revision 1.10 2003/05/12 14:38:34 aepage |
4386
|
|
|
|
|
|
|
# win32 pushback |
4387
|
|
|
|
|
|
|
# |
4388
|
|
|
|
|
|
|
# Revision 1.9 2003/05/12 13:46:46 aepage |
4389
|
|
|
|
|
|
|
# optmization of win32 line fixing |
4390
|
|
|
|
|
|
|
# |
4391
|
|
|
|
|
|
|
# Revision 1.8 2003/05/11 23:42:20 aepage |
4392
|
|
|
|
|
|
|
# fix to remove stray win32 chars |
4393
|
|
|
|
|
|
|
# |
4394
|
|
|
|
|
|
|
# Revision 1.7 2003/05/11 23:15:26 aepage |
4395
|
|
|
|
|
|
|
# email address changes, fixes for perl 5.8.0 |
4396
|
|
|
|
|
|
|
# |
4397
|
|
|
|
|
|
|
# Revision 1.6 2002/11/28 19:17:43 aepage |
4398
|
|
|
|
|
|
|
# Changed many options to widgets and pack from bareword or 'bareword' |
4399
|
|
|
|
|
|
|
# to -bareword to support Tk804.024(Devel). |
4400
|
|
|
|
|
|
|
# |
4401
|
|
|
|
|
|
|
# Revision 1.5 2002/11/25 23:47:03 aepage |
4402
|
|
|
|
|
|
|
# A perl debugger package is required to define a subroutine name 'sub'. |
4403
|
|
|
|
|
|
|
# This routine is a 'proxy' for handling subroutine calls and allows the |
4404
|
|
|
|
|
|
|
# debugger pacakage to track subroutine depth so that it can implement |
4405
|
|
|
|
|
|
|
# 'step over', 'step in' and 'return' functionality. It must also |
4406
|
|
|
|
|
|
|
# handle the same context as the proxied routine; it must return a |
4407
|
|
|
|
|
|
|
# scalar where a scalar was being expected, an array where an array is |
4408
|
|
|
|
|
|
|
# being expected and a void where a void was being expected. Ptkdb was |
4409
|
|
|
|
|
|
|
# not handling the case for void. 99.9% of the time this will have no |
4410
|
|
|
|
|
|
|
# ill effects although it is being handled incorrectly. Ref Programming |
4411
|
|
|
|
|
|
|
# Perl 3rd Edition pg 827 |
4412
|
|
|
|
|
|
|
# |
4413
|
|
|
|
|
|
|
# Revision 1.4 2002/10/24 17:07:10 aepage |
4414
|
|
|
|
|
|
|
# fix for warning for undefined value assigend to typeglob during restart |
4415
|
|
|
|
|
|
|
# |
4416
|
|
|
|
|
|
|
# Revision 1.3 2002/10/20 23:49:51 aepage |
4417
|
|
|
|
|
|
|
# |
4418
|
|
|
|
|
|
|
# changed email address to aepage@ptkdb.sourceforge.net
|
4419
|
|
|
|
|
|
|
#
|
4420
|
|
|
|
|
|
|
# localized $^W in dbeval
|
4421
|
|
|
|
|
|
|
#
|
4422
|
|
|
|
|
|
|
# fix for instances where there is no code in a package.
|
4423
|
|
|
|
|
|
|
#
|
4424
|
|
|
|
|
|
|
# Initialized $self->{'subs_list_cnt'} in the new constructor to 0 to
|
4425
|
|
|
|
|
|
|
# prevent warnings with -w. |
4426
|
|
|
|
|
|
|
# |