line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
$tcltkdb::VERSION = '2.1'; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
1007
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
30
|
|
4
|
1
|
|
|
1
|
|
872
|
use Data::Dumper; |
|
1
|
|
|
|
|
9822
|
|
|
1
|
|
|
|
|
57
|
|
5
|
1
|
|
|
1
|
|
1360
|
use Tcl::Tk; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
# |
8
|
|
|
|
|
|
|
# This package is the main_window object for the debugger. We start |
9
|
|
|
|
|
|
|
# with the Devel:: prefix because we want to install it with |
10
|
|
|
|
|
|
|
# the DB:: package that is required to be in a Devel/ subdir of a |
11
|
|
|
|
|
|
|
# directory in the @INC set. |
12
|
|
|
|
|
|
|
# |
13
|
|
|
|
|
|
|
package Devel::tcltkdb; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 NAME |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
Devel::tcltkdb - Perl debugger using a Tcl/Tk GUI |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 DESCRIPTION |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
tcltkdb is a debugger for perl that uses perl+Tcl/Tk for a user interface. |
23
|
|
|
|
|
|
|
Features include: |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
Hot Variable Inspection (currently disabled) |
26
|
|
|
|
|
|
|
Breakpoint Control Panel |
27
|
|
|
|
|
|
|
Expression List |
28
|
|
|
|
|
|
|
Subroutine Tree |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 SYNOPSIS |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
To debug a script using tcltkdb invoke perl like this: |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
perl -d:tcltkdb myscript.pl |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=head1 Usage |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
perl -d:tcltkdb myscript.pl |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head1 Code Pane |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=over 4 |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=item Line Numbers |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
Line numbers are presented on the left side of the window. Lines that |
47
|
|
|
|
|
|
|
have lines through them are not breakable. Lines that are plain text |
48
|
|
|
|
|
|
|
are breakable. Clicking on these line numbers will insert a |
49
|
|
|
|
|
|
|
breakpoint on that line and change the line number color to |
50
|
|
|
|
|
|
|
$ENV{'PTKDB_BRKPT_COLOR'} (Defaults to Red). Clicking on the number |
51
|
|
|
|
|
|
|
again will remove the breakpoint. If you disable the breakpoint with |
52
|
|
|
|
|
|
|
the controls on the BrkPt notebook page the color will change to |
53
|
|
|
|
|
|
|
$ENV{'PTKDB_DISABLEDBRKPT_COLOR'} (Defaults to Green). |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=item Cursor Motion |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
If you place the cursor over a variable (i.e. $myVar, @myVar, or |
58
|
|
|
|
|
|
|
%myVar) and pause for a second the debugger will evaluate the current |
59
|
|
|
|
|
|
|
value of the variable and pop a balloon up with the evaluated |
60
|
|
|
|
|
|
|
result. |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
Data::Dumper will be used to format the result. If there is an active |
63
|
|
|
|
|
|
|
selection, the text of that selection will be evaluated. |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=back |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=head1 Notebook Pane |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=over 2 |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=item Exprs |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
This is a list of expressions that are evaluated each time the |
74
|
|
|
|
|
|
|
debugger stops. The results of the expresssion are presented |
75
|
|
|
|
|
|
|
heirarchically for expression that result in hashes or lists. Double |
76
|
|
|
|
|
|
|
clicking on such an expression will cause it to collapse; double |
77
|
|
|
|
|
|
|
clicking again will cause the expression to expand. Expressions are |
78
|
|
|
|
|
|
|
entered through B entry, or by Alt-E when text is |
79
|
|
|
|
|
|
|
selected in the code pane. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
The B entry, will take an expression, evaluate it, and |
82
|
|
|
|
|
|
|
replace the entries contents with the result. The result is also |
83
|
|
|
|
|
|
|
transfered to the 'clipboard' for pasting. |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=item Subs |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
Displays a list of all the packages invoked with the script |
88
|
|
|
|
|
|
|
heirarchially. At the bottom of the heirarchy are the subroutines |
89
|
|
|
|
|
|
|
within the packages. Double click on a package to expand |
90
|
|
|
|
|
|
|
it. Subroutines are listed by their full package names. |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=item BrkPts |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
Presents a list of the breakpoints current in use. The pushbutton |
95
|
|
|
|
|
|
|
allows a breakpoint to be 'disabled' without removing it. Expressions |
96
|
|
|
|
|
|
|
can be applied to the breakpoint. If the expression evaluates to be |
97
|
|
|
|
|
|
|
'true'(results in a defined value that is not 0) the debugger will |
98
|
|
|
|
|
|
|
stop the script. Pressing the 'Goto' button will set the text pane |
99
|
|
|
|
|
|
|
to that file and line where the breakpoint is set. Pressing the |
100
|
|
|
|
|
|
|
'Delete' button will delete the breakpoint. |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=back |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=head1 Menus |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=head2 File Menu |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=over |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=item About... |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
Presents a dialog box telling you about the version of ptkdb. It |
113
|
|
|
|
|
|
|
recovers your OS name, version of perl, version of Tcl/Tk, and some other |
114
|
|
|
|
|
|
|
information |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=item Open |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
Presents a list of files that are part of the invoked perl |
119
|
|
|
|
|
|
|
script. Selecting a file from this list will present this file in the |
120
|
|
|
|
|
|
|
text window. |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=item Save Config... |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
Prompts for a filename to save the |
125
|
|
|
|
|
|
|
configuration to. Saves the breakpoints, expressions, eval text and |
126
|
|
|
|
|
|
|
window geometry. If the name given as the default is used and the |
127
|
|
|
|
|
|
|
script is reinvoked, this configuration will be reloaded automatically. |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
B You may find this preferable to using |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=item Restore Config... |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
Prompts for a filename to restore a configuration saved with |
134
|
|
|
|
|
|
|
the "Save Config..." menu item. |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=item Goto Line... |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
Prompts for a line number. Pressing the "Okay" button sends the window |
139
|
|
|
|
|
|
|
to the line number entered. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=item Find Text... |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
Prompts for text to search for. Options include forward search, |
144
|
|
|
|
|
|
|
backwards search, and regular expression searching. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=item Quit |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
Causes the debugger and the target script to exit. |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=back |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=head2 Control Menu |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=over |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=item Run |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
The debugger allows the script to run to the next breakpoint or until |
159
|
|
|
|
|
|
|
the script exits. |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=item Run To Here |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
Runs the debugger until it comes to wherever the insertion cursor |
164
|
|
|
|
|
|
|
in text window is placed. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=item Set Breakpoint |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
Sets a breakpoint on the line at the insertion cursor. |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=item Clear Breakpoint |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
Remove a breakpoint on the at the insertion cursor. |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=item Clear All Breakpoints |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
Removes all current breakpoints |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=item Step Over |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
Causes the debugger to step over the next line. If the line is a |
181
|
|
|
|
|
|
|
subroutine call it steps over the call, stopping when the subroutine |
182
|
|
|
|
|
|
|
returns. |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=item Step In |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
Causes the debugger to step into the next line. If the line is a |
187
|
|
|
|
|
|
|
subroutine call it steps into the subroutine, stopping at the first |
188
|
|
|
|
|
|
|
executable line within the subroutine. |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=item Return |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
Runs the script until it returns from the currently executing subroutine. |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=item Restart |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
Saves the breakpoints and expressions in a temporary file and restarts |
197
|
|
|
|
|
|
|
the script from the beginning. CAUTION: This feature will not work |
198
|
|
|
|
|
|
|
properly with debugging of CGI Scripts. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=item Stop On Warning |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
When C<-w> is enabled the debugger will stop when warnings such as, "Use |
203
|
|
|
|
|
|
|
of uninitialized value at undef_warn.pl line N" are encountered. The debugger |
204
|
|
|
|
|
|
|
will stop on the NEXT line of execution since the error can't be detected |
205
|
|
|
|
|
|
|
until the current line has executed. |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
This feature can be turned on at startup by adding: |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
$DB::tcltkdb::stop_on_warning = 1 ; |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
to a .ptkdbrc file |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=back |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=head2 Data Menu |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=over |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=item Enter Expression |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
When an expression is entered in the "Enter Expression:" text box, |
222
|
|
|
|
|
|
|
selecting this item will enter the expression into the expression |
223
|
|
|
|
|
|
|
list. Each time the debugger stops this expression will be evaluated |
224
|
|
|
|
|
|
|
and its result updated in the list window. |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=item Delete Expression |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
Deletes the highlighted expression in the expression window. |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=item Delete All Expressions |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
Delete all expressions in the expression window. |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=item Expression Eval Window |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
Pops up a two pane window. Expressions of virtually unlimitted length |
237
|
|
|
|
|
|
|
can be entered in the top pane. Pressing the 'Eval' button will cause |
238
|
|
|
|
|
|
|
the expression to be evaluated and its placed in the lower pane. |
239
|
|
|
|
|
|
|
Data::Dumper is used to format the resulting |
240
|
|
|
|
|
|
|
text. Undo is enabled for the text in the upper pane. |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
HINT: You can enter multiple expressions by separating them with commas. |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=item Use Data::Dumper for Eval Window |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
Enables or disables the use of Data::Dumper for formatting the results |
247
|
|
|
|
|
|
|
of expressions in the Eval window. |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
=back |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=head2 Stack Menu |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
Maintains a list of the current subroutine stack each time the |
254
|
|
|
|
|
|
|
debugger stops. Selecting an item from this menu will set the text in |
255
|
|
|
|
|
|
|
the code window to that particular subourtine entry point. |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
=head2 Bookmarks Menu |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
Maintains a list of bookmarks. The booksmarks are saved in ~/.ptkdb_bookmarks |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=over |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=item Add Bookmark |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
Adds a bookmark to the bookmark list. |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=back |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=head1 Options |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
Here is a list of the current active XResources options. Several of |
272
|
|
|
|
|
|
|
these can be overridden with environmental variables. Resources can be |
273
|
|
|
|
|
|
|
added to .Xresources or .Xdefaults depending on your X configuration. |
274
|
|
|
|
|
|
|
To enable these resources you must either restart your X server or use |
275
|
|
|
|
|
|
|
the xrdb -override resFile command. xfontsel can be used to select |
276
|
|
|
|
|
|
|
fonts. |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
/* |
279
|
|
|
|
|
|
|
* Perl Tk Debugger XResources. |
280
|
|
|
|
|
|
|
* Note... These resources are subject to change. |
281
|
|
|
|
|
|
|
* |
282
|
|
|
|
|
|
|
* Use 'xfontsel' to select different fonts. |
283
|
|
|
|
|
|
|
* |
284
|
|
|
|
|
|
|
* Append these resource to ~/.Xdefaults | ~/.Xresources |
285
|
|
|
|
|
|
|
* and use xrdb -override ~/.Xdefaults | ~/.Xresources |
286
|
|
|
|
|
|
|
* to activate them. |
287
|
|
|
|
|
|
|
*/ |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
ptkdb.frame*font: fixed /* Menu Bar */ |
290
|
|
|
|
|
|
|
ptkdb.frame2.frame1.rotext.font: fixed /* Code Pane */ |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
ptkdb.toplevel.frame.textundo.font: fixed /* Eval Expression Entry Window */ |
293
|
|
|
|
|
|
|
ptkdb.toplevel.frame1.text.font: fixed /* Eval Expression Results Window */ |
294
|
|
|
|
|
|
|
ptkdb.toplevel.button.font: fixed /* "Eval..." Button */ |
295
|
|
|
|
|
|
|
ptkdb.toplevel.button1.font: fixed /* "Clear Eval" Button */ |
296
|
|
|
|
|
|
|
ptkdb.toplevel.button2.font: fixed /* "Clear Results" Button */ |
297
|
|
|
|
|
|
|
ptkdb.toplevel.button3.font: fixed /* "Clear Dismiss" Button */ |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
/* |
300
|
|
|
|
|
|
|
* Background color for where the debugger has stopped |
301
|
|
|
|
|
|
|
*/ |
302
|
|
|
|
|
|
|
ptkdb*stopcolor: blue |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
/* |
305
|
|
|
|
|
|
|
* Background color for set breakpoints |
306
|
|
|
|
|
|
|
*/ |
307
|
|
|
|
|
|
|
ptkdb*breaktagcolor*background: yellow |
308
|
|
|
|
|
|
|
ptkdb*disabledbreaktagcolor*background: white |
309
|
|
|
|
|
|
|
/* |
310
|
|
|
|
|
|
|
* Font for where the debugger has stopped |
311
|
|
|
|
|
|
|
*/ |
312
|
|
|
|
|
|
|
ptkdb*stopfont: -*-fixed-bold-*-*-*-*-*-*-*-*-*-*-* |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
/* |
315
|
|
|
|
|
|
|
* Background color for the search tag |
316
|
|
|
|
|
|
|
*/ |
317
|
|
|
|
|
|
|
ptkdb*searchtagcolor: green |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=head1 Environmental Variables |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
=over 4 |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
=item PTKDB_BRKPT_COLOR |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
Sets the background color of a set breakpoint |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
=item PTKDB_DISABLEDBRKPT_COLOR |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
Sets the background color of a disabled breakpoint |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
=item PTKDB_CODE_FONT |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
Sets the font of the Text in the code pane. |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=item PTKDB_EXPRESSION_FONT |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
Sets the font used in the expression notebook page. |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=item PTKDB_EVAL_FONT |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
Sets the font used in the Expression Eval Window |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
=item PTKDB_DISPLAY |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
Sets the X display that the ptkdb window will appear on when invoked. |
346
|
|
|
|
|
|
|
Useful for debugging CGI scripts on remote systems. |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=item PTKDB_BOOKMARKS_PATH |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
Sets the path of the bookmarks file. Default is $ENV{'HOME'}/.ptkdb_bookmarks |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=item PTKDB_STOP_TAG_COLOR |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
Sets the color that highlights the line where the debugger is stopped |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=back |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=head1 FILES |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
=head2 .ptkdbrc |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
If this file is present in ~/ or in the directory where perl is |
363
|
|
|
|
|
|
|
invoked the file will be read and executed as a perl script before the |
364
|
|
|
|
|
|
|
debugger makes its initial stop at startup. There are several 'api' |
365
|
|
|
|
|
|
|
calls that can be used with such scripts. There is an internal |
366
|
|
|
|
|
|
|
variable $DB::no_stop_at_start that may be set to non-zero to prevent |
367
|
|
|
|
|
|
|
the debugger from stopping at the first line of the script. This is |
368
|
|
|
|
|
|
|
useful for debugging CGI scripts. |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
=over 4 |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
=item brkpt($fname, @lines) |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
Sets breakspoints on the list of lines in $fname. A warning message |
375
|
|
|
|
|
|
|
is generated if a line is not breakable. |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=item condbrkpt($fname, @($line, $expr) ) |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
Sets conditional breakpoints in $fname on pairs of $line and $expr. A |
380
|
|
|
|
|
|
|
warning message is generated if a line is not breakable. NOTE: the |
381
|
|
|
|
|
|
|
validity of the expression will not be determined until execution of |
382
|
|
|
|
|
|
|
that particular line. |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=item brkonsub(@names) |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
Sets a breakpoint on each subroutine name listed. A warning message is |
387
|
|
|
|
|
|
|
generated if a subroutine does not exist. NOTE: for a script with no |
388
|
|
|
|
|
|
|
other packages the default package is "main::" and the subroutines |
389
|
|
|
|
|
|
|
would be "main::mySubs". |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=item brkonsub_regex(@regExprs) |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
Uses the list of @regExprs as a list of regular expressions to set breakpoints. Sets breakpoints |
394
|
|
|
|
|
|
|
on every subroutine that matches any of the listed regular expressions. |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
=back |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=head1 NOTES |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
=head2 Debugging Other perlTk Applications |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
ptkdb can be used to debug other perlTk applications if some cautions |
403
|
|
|
|
|
|
|
are observed. Basically, do not click the mouse in the application's |
404
|
|
|
|
|
|
|
window(s) when you've entered the debugger and do not click in the |
405
|
|
|
|
|
|
|
debugger's window(s) while the application is running. Doing either |
406
|
|
|
|
|
|
|
one is not necessarily fatal, but it can confuse things that are going |
407
|
|
|
|
|
|
|
on and produce unexpected results. |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
Be aware that most perlTk applications have a central event loop. |
410
|
|
|
|
|
|
|
User actions, such as mouse clicks, key presses, window exposures, etc |
411
|
|
|
|
|
|
|
will generate 'events' that the script will process. When a perlTk |
412
|
|
|
|
|
|
|
application is running, its 'MainLoop' call will accept these events |
413
|
|
|
|
|
|
|
and then dispatch them to appropriate callbacks associated with the |
414
|
|
|
|
|
|
|
appropriate widgets. |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
Ptkdb has its own event loop that runs whenever you've stopped at a |
417
|
|
|
|
|
|
|
breakpoint and entered the debugger. However, it can accept events |
418
|
|
|
|
|
|
|
that are generated by other perlTk windows and dispatch their |
419
|
|
|
|
|
|
|
callbacks. The problem here is that the application is supposed to be |
420
|
|
|
|
|
|
|
'stopped', and logically the application should not be able to process |
421
|
|
|
|
|
|
|
events. |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
=head2 Debugging CGI Scripts |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
One advantage of ptkdb over the builtin debugger(-d) is that it can be |
426
|
|
|
|
|
|
|
used to debug CGI perl scripts as they run on a web server. Be sure |
427
|
|
|
|
|
|
|
that that your web server's perl instalation includes Tcl::Tk. |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
Change your |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
#! /usr/local/bin/perl |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
to |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
#! /usr/local/bin/perl -d:tcltkdb |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
TIP: You can debug scripts remotely if you're using a unix based |
438
|
|
|
|
|
|
|
Xserver and where you are authoring the script has an Xserver. The |
439
|
|
|
|
|
|
|
Xserver can be another unix workstation, a Macintosh or Win32 platform |
440
|
|
|
|
|
|
|
with an appropriate XWindows package. In your script insert the |
441
|
|
|
|
|
|
|
following BEGIN subroutine: |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
sub BEGIN { |
444
|
|
|
|
|
|
|
$ENV{'DISPLAY'} = "myHostname:0.0" ; |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
Be sure that your web server has permission to open windows on your |
448
|
|
|
|
|
|
|
Xserver (see the xhost manpage). |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
Access your web page with your browswer and 'submit' the script as |
451
|
|
|
|
|
|
|
normal. The ptkdb window should appear on myHostname's monitor. At |
452
|
|
|
|
|
|
|
this point you can start debugging your script. Be aware that your |
453
|
|
|
|
|
|
|
browser may timeout waiting for the script to run. |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
To expedite debugging you may want to setup your breakpoints in |
456
|
|
|
|
|
|
|
advance with a .ptkdbrc file and use the $DB::no_stop_at_start |
457
|
|
|
|
|
|
|
variable. NOTE: for debugging web scripts you may have to have the |
458
|
|
|
|
|
|
|
.ptkdbrc file installed in the server account's home directory (~www) |
459
|
|
|
|
|
|
|
or whatever username your webserver is running under. Also try |
460
|
|
|
|
|
|
|
installing a .ptkdbrc file in the same directory as the target script. |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
=head1 AUTHORS |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
Andrew E. Page |
465
|
|
|
|
|
|
|
Vadim Konovalov |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
=cut |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
use vars qw(@dbline); |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
sub BEGIN { |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
$DB::on = 0 ; |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
$DB::subroutine_depth = 0 ; # our subroutine depth counter |
476
|
|
|
|
|
|
|
$DB::step_over_depth = -1 ; |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
# Fonts used in the displays |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
@Devel::tcltkdb::button_font = $ENV{'PTKDB_BUTTON_FONT'} ? ( "-font" => $ENV{'PTKDB_CODE_FONT'} ) : () ; # font for buttons |
481
|
|
|
|
|
|
|
@Devel::tcltkdb::code_text_font = $ENV{'PTKDB_CODE_FONT'} ? ( "-font" => $ENV{'PTKDB_CODE_FONT'} ) : () ; |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
@Devel::tcltkdb::expression_text_font = $ENV{'PTKDB_EXPRESSION_FONT'} ? ( "-font" => $ENV{'PTKDB_EXPRESSION_FONT'} ) : () ; |
484
|
|
|
|
|
|
|
@Devel::tcltkdb::eval_text_font = $ENV{'PTKDB_EVAL_FONT'} ? ( -font => $ENV{'PTKDB_EVAL_FONT'} ) : () ; # text for the expression eval window |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
$Devel::tcltkdb::linenumber_length = 5; |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
# |
489
|
|
|
|
|
|
|
# DB Options (things not directly involving the window) |
490
|
|
|
|
|
|
|
# |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
# Flag to disable us from intercepting $SIG{'INT'} |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
$DB::sigint_disable = defined $ENV{'PTKDB_SIGINT_DISABLE'} && $ENV{'PTKDB_SIGINT_DISABLE'} ; |
495
|
|
|
|
|
|
|
# |
496
|
|
|
|
|
|
|
# Possibly for debugging perl CGI Web scripts on |
497
|
|
|
|
|
|
|
# remote machines. |
498
|
|
|
|
|
|
|
# |
499
|
|
|
|
|
|
|
$ENV{'DISPLAY'} = $ENV{'PTKDB_DISPLAY'} if exists $ENV{'PTKDB_DISPLAY'} ; |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
} # end of BEGIN |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
## |
504
|
|
|
|
|
|
|
## subroutine provided to the user for initializing |
505
|
|
|
|
|
|
|
## files in .ptkdbrc |
506
|
|
|
|
|
|
|
## |
507
|
|
|
|
|
|
|
sub brkpt { |
508
|
|
|
|
|
|
|
my ($fName, @idx) = @_ ; |
509
|
|
|
|
|
|
|
my($offset) ; |
510
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fName} ; |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
$offset = $dbline[1] =~ /use\s+.*Devel::_?tcltkdb/ ? 1 : 0 ; |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
for( @idx ) { |
515
|
|
|
|
|
|
|
if( !&DB::checkdbline($fName, $_ + $offset) ) { |
516
|
|
|
|
|
|
|
my ($package, $filename, $line) = caller ; |
517
|
|
|
|
|
|
|
print "$filename:$line: $fName line $_ is not breakable\n" ; |
518
|
|
|
|
|
|
|
next ; |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
$DB::window->insertBreakpoint($fName, $_, 1) ; # insert a simple breakpoint |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
} # end of brkpt |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
# |
525
|
|
|
|
|
|
|
# Set conditional breakpoint(s) |
526
|
|
|
|
|
|
|
# |
527
|
|
|
|
|
|
|
sub condbrkpt { |
528
|
|
|
|
|
|
|
my ($fname) = shift ; |
529
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname} ; |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
my $offset = $dbline[1] =~ /use\s+.*Devel::_?tcltkdb/ ? 1 : 0 ; |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
while( @_ ) { # arg loop |
534
|
|
|
|
|
|
|
my($index, $expr) = splice @_, 0, 2 ; # take args 2 at a time |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
if( !&DB::checkdbline($fname, $index + $offset) ) { |
537
|
|
|
|
|
|
|
my ($package, $filename, $line) = caller ; |
538
|
|
|
|
|
|
|
print "$filename:$line: $fname line $index is not breakable\n" ; |
539
|
|
|
|
|
|
|
next ; |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
$DB::window->insertBreakpoint($fname, $index, 1, $expr) ; # insert a simple breakpoint |
542
|
|
|
|
|
|
|
} # end of arg loop |
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
sub brkonsub { |
546
|
|
|
|
|
|
|
my(@names) = @_ ; |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
for (@names) { |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
# get the filename and line number range of the target subroutine |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
if( !exists $DB::sub{$_} ) { |
553
|
|
|
|
|
|
|
print "No subroutine $_. Try main::$_\n" ; |
554
|
|
|
|
|
|
|
next ; |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
$DB::sub{$_} =~ /(.*):(\d+)-(\d+)$/o ; # file name will be in $1, start line $2, end line $3 |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
for( $2..$3 ) { |
560
|
|
|
|
|
|
|
next unless &DB::checkdbline($1, $_) ; |
561
|
|
|
|
|
|
|
$DB::window->insertBreakpoint($1, $_, 1) ; |
562
|
|
|
|
|
|
|
last ; # only need the one breakpoint |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
} # end of name loop |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
# |
568
|
|
|
|
|
|
|
# set breakpoints on subroutines matching a regular |
569
|
|
|
|
|
|
|
# expression |
570
|
|
|
|
|
|
|
# |
571
|
|
|
|
|
|
|
sub brkonsub_regex { |
572
|
|
|
|
|
|
|
my(@regexps) = @_ ; |
573
|
|
|
|
|
|
|
my($regexp, @subList) ; |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
# |
576
|
|
|
|
|
|
|
# accumulate matching subroutines |
577
|
|
|
|
|
|
|
# |
578
|
|
|
|
|
|
|
foreach $regexp ( @regexps ) { |
579
|
|
|
|
|
|
|
study $regexp ; |
580
|
|
|
|
|
|
|
push @subList, grep /$regexp/, keys %DB::sub ; |
581
|
|
|
|
|
|
|
} # end of brkonsub_regex |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
brkonsub(@subList) ; # set breakpoints on matching subroutines |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
} # end of brkonsub_regex |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
# |
588
|
|
|
|
|
|
|
# Run files provided by the user |
589
|
|
|
|
|
|
|
# |
590
|
|
|
|
|
|
|
sub do_user_init_files { |
591
|
|
|
|
|
|
|
for (grep {-e} ( (exists $ENV{'HOME'}?("$ENV{'HOME'}/.ptkdbrc"):()), ".ptkdbrc")) { |
592
|
|
|
|
|
|
|
do $_; |
593
|
|
|
|
|
|
|
if ($@) { |
594
|
|
|
|
|
|
|
print STDERR "init file $_ failed: $@\n" ; |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
&set_stop_on_warning(); |
598
|
|
|
|
|
|
|
} |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
# |
601
|
|
|
|
|
|
|
# Constructor for our Devel::tcltkdb |
602
|
|
|
|
|
|
|
# |
603
|
|
|
|
|
|
|
sub new { |
604
|
|
|
|
|
|
|
my($type) = @_ ; |
605
|
|
|
|
|
|
|
my($self) = {} ; |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
bless $self, $type ; |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
# Current position of the executing program |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
$self->{current_file} = "" ; |
612
|
|
|
|
|
|
|
$self->{current_line} = -1 ; # initial value indicating we haven't set our line/tag |
613
|
|
|
|
|
|
|
$self->{window_pos_offset} = 10 ; # when we enter how far from the top of the text are we positioned down |
614
|
|
|
|
|
|
|
$self->{search_start} = "1.0" ; |
615
|
|
|
|
|
|
|
$self->{fwdOrBack} = 1 ; |
616
|
|
|
|
|
|
|
$self->{BookMarksPath} = $ENV{'PTKDB_BOOKMARKS_PATH'} || "$ENV{'HOME'}/.ptkdb_bookmarks" || '.ptkdb_bookmarks' ; |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
$self->{'expr_list'} = [] ; # list of expressions to eval in our window fields: {'expr'} The expr itself {'depth'} expansion depth |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
$self->{'brkPtCnt'} = 0 ; |
622
|
|
|
|
|
|
|
$self->{'brkPtSlots'} = [] ; # open slots for adding breakpoints to the table |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
$self->{'main_window'} = undef ; |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
$self->{'subs_list_cnt'} = 0 ; |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
$self->setup_main_window() ; |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
return $self ; |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
} # end of new |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
sub setup_main_window { |
635
|
|
|
|
|
|
|
my($self) = @_ ; |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
# Main Window |
638
|
|
|
|
|
|
|
$self->{int} = new Tcl::Tk; |
639
|
|
|
|
|
|
|
$self->{int}->packageRequireTreectrl; |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
$self->{main_window} = $self->{int}->mainwindow(); |
642
|
|
|
|
|
|
|
$self->{main_window}->geometry($ENV{'PTKDB_GEOMETRY'} || "800x600") ; |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
$self->{main_window}->bind('', \&DB::dbint_handler) ; |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
# |
647
|
|
|
|
|
|
|
# Bind our 'quit' routine to a close command from the window manager (Alt-F4) |
648
|
|
|
|
|
|
|
# |
649
|
|
|
|
|
|
|
$self->{main_window}->protocol('WM_DELETE_WINDOW', sub { $self->close_ptkdb_window(); } ); |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
# Menu bar |
652
|
|
|
|
|
|
|
$self->setup_menu_bar(); |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
# |
655
|
|
|
|
|
|
|
# setup Frames |
656
|
|
|
|
|
|
|
# Setup our Code, Data, and breakpoints |
657
|
|
|
|
|
|
|
$self->setup_frames(); |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
} |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
# |
662
|
|
|
|
|
|
|
# Check for changes to the bookmarks and quit |
663
|
|
|
|
|
|
|
# |
664
|
|
|
|
|
|
|
sub DoQuit { |
665
|
|
|
|
|
|
|
print STDERR "DoQuit\n"; |
666
|
|
|
|
|
|
|
my($self) = @_; |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
$self->save_bookmarks($self->{BookMarksPath}) if $self->{'bookmarks_changed'}; |
669
|
|
|
|
|
|
|
$self->{main_window}->destroy if $self->{main_window} ; |
670
|
|
|
|
|
|
|
$self->{main_window} = undef; |
671
|
|
|
|
|
|
|
} |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
# |
674
|
|
|
|
|
|
|
# This supports the File -> Open menu item |
675
|
|
|
|
|
|
|
# We create a new window and list all of the files |
676
|
|
|
|
|
|
|
# that are contained in the program. We also |
677
|
|
|
|
|
|
|
# pick up all of the perlTk files that are supporting |
678
|
|
|
|
|
|
|
# the debugger. |
679
|
|
|
|
|
|
|
# |
680
|
|
|
|
|
|
|
sub DoOpen { |
681
|
|
|
|
|
|
|
my $self = shift ; |
682
|
|
|
|
|
|
|
my ($topLevel, $listBox, $frame, $selectedFile, @fList) ; |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
# |
685
|
|
|
|
|
|
|
# subroutine we call when we've selected a file |
686
|
|
|
|
|
|
|
# |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
my $chooseSub = sub { $selectedFile = $listBox->get('active') ; |
689
|
|
|
|
|
|
|
print "attempting to open $selectedFile\n" ; |
690
|
|
|
|
|
|
|
$DB::window->set_file($selectedFile, 0) ; |
691
|
|
|
|
|
|
|
$topLevel->destroy; |
692
|
|
|
|
|
|
|
} ; |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
# |
695
|
|
|
|
|
|
|
# Take the list the files and resort it. |
696
|
|
|
|
|
|
|
# we put all of the local files first, and |
697
|
|
|
|
|
|
|
# then list all of the system libraries. |
698
|
|
|
|
|
|
|
# |
699
|
|
|
|
|
|
|
@fList = sort { |
700
|
|
|
|
|
|
|
# sort comparison function block |
701
|
|
|
|
|
|
|
my $fa = substr($a, 0, 1); |
702
|
|
|
|
|
|
|
my $fb = substr($b, 0, 1); |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
return $a cmp $b if ($fa eq '/') && ($fb eq '/'); |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
return -1 if ($fb eq '/'); |
707
|
|
|
|
|
|
|
return 1 if ($fa eq '/' ); |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
return $a cmp $b ; |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
} grep s/^_/, keys %main:: ; |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
# |
714
|
|
|
|
|
|
|
# Create a list box with all of our files |
715
|
|
|
|
|
|
|
# to select from |
716
|
|
|
|
|
|
|
# |
717
|
|
|
|
|
|
|
$topLevel = $self->{main_window}->Toplevel(-title => "File Select", -overanchor => 'cursor') ; |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
$listBox = $topLevel->Scrolled('Listbox', |
720
|
|
|
|
|
|
|
@Devel::tcltkdb::expression_text_font, |
721
|
|
|
|
|
|
|
-width => 30)->pack(qw/-side top -fill both -expand 1/); |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
# Bind a double click on the mouse button to the same action |
725
|
|
|
|
|
|
|
# as pressing the Okay button |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
$listBox->bind('' => $chooseSub) ; |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
$listBox->_insertEnd(@fList); |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
$topLevel->Button(-text => "Okay", -command => $chooseSub, @Devel::tcltkdb::button_font, |
732
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
$topLevel->Button( -text => "Cancel", @Devel::tcltkdb::button_font, |
735
|
|
|
|
|
|
|
-command => sub { $topLevel->destroy; } )->pack(qw/-side left -fill both -expand 1/); |
736
|
|
|
|
|
|
|
} # end of DoOpen |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
sub do_tabs { |
739
|
|
|
|
|
|
|
my $w = $DB::window->{'main_window'}->DialogBox(-title => "Tabs", -buttons => [qw/Okay Cancel/]) ; |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
my $tabs_cfg = $DB::window->{'text'}->cget('-tabs'); |
742
|
|
|
|
|
|
|
my $tabs_str = join " ", @$tabs_cfg if $tabs_cfg; |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
$w->add('Label', -text => 'Tabs:')->pack(-side => 'left'); |
745
|
|
|
|
|
|
|
$w->add('Entry', -textvariable => \$tabs_str)->pack(-side => 'left')->selectionRange(0,'end'); |
746
|
|
|
|
|
|
|
my $result = $w->Show(); |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
$DB::window->{'text'}->configure(-tabs => [ split /\s+/, $tabs_str ]) |
749
|
|
|
|
|
|
|
if $result eq 'Okay' ; |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
sub close_ptkdb_window { |
753
|
|
|
|
|
|
|
print STDERR "close_ptkdb_window\n"; |
754
|
|
|
|
|
|
|
my($self) = @_ ; |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
$DB::window->{'event'} = 'run'; |
757
|
|
|
|
|
|
|
$self->{current_file} = ""; # force a file reset |
758
|
|
|
|
|
|
|
$self->{'main_window'}->destroy; |
759
|
|
|
|
|
|
|
$self->{'main_window'} = undef; |
760
|
|
|
|
|
|
|
} |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
sub setup_menu_bar { |
763
|
|
|
|
|
|
|
my ($self) = @_; |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
my $mw = $self->{main_window} ; |
766
|
|
|
|
|
|
|
my $int = $mw->interp; |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
# file menu in menu bar |
770
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
my $items1 = [ [ 'command' => 'About...', -command => sub { $self->DoAbout() ; } ], |
772
|
|
|
|
|
|
|
[ 'command' => 'Bug Report...', -command => 'puts "bugreport TBD"' ], |
773
|
|
|
|
|
|
|
"-", |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
[ 'command' => 'Open', -accelerator => 'Alt+O', |
776
|
|
|
|
|
|
|
-underline => 0, |
777
|
|
|
|
|
|
|
-command => sub { $self->DoOpen() ; } ], |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
[ 'command' => 'Save Config...', |
780
|
|
|
|
|
|
|
-underline => 0, |
781
|
|
|
|
|
|
|
-command => \&DB::SaveState ], |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
[ 'command' => 'Restore Config...', |
784
|
|
|
|
|
|
|
-underline => 0, |
785
|
|
|
|
|
|
|
-command => \&DB::RestoreState], |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
[ 'command' => 'Goto Line...', |
788
|
|
|
|
|
|
|
-underline => 0, |
789
|
|
|
|
|
|
|
-accelerator => 'Alt-g', |
790
|
|
|
|
|
|
|
-command => sub { $self->GotoLine() ; } ], |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
[ 'command' => 'Find Text...', |
793
|
|
|
|
|
|
|
-accelerator => 'Ctrl-f', |
794
|
|
|
|
|
|
|
-underline => 0, |
795
|
|
|
|
|
|
|
-command => sub { $self->FindText() ; } ], |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
[ 'command' => "Tabs...", -command => \&do_tabs ], |
798
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
"-", |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
[ 'command' => 'Close Window and Run', -accelerator => 'Alt+W', |
802
|
|
|
|
|
|
|
-underline => 6, -command => sub { $self->close_ptkdb_window ; } ], |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
[ 'command' => 'Quit...', -accelerator => 'Alt+Q', |
805
|
|
|
|
|
|
|
-underline => 0, |
806
|
|
|
|
|
|
|
-command => sub { $self->DoQuit } ] |
807
|
|
|
|
|
|
|
]; |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
$mw->bind('' => sub { $self->GotoLine() ; }) ; |
811
|
|
|
|
|
|
|
$mw->bind('' => sub { $self->FindText() ; }) ; |
812
|
|
|
|
|
|
|
$mw->bind('' => \&Devel::tcltkdb::DoRestart) ; |
813
|
|
|
|
|
|
|
$mw->bind('' => sub { $self->{'event'} = 'quit' } ) ; |
814
|
|
|
|
|
|
|
$mw->bind('' => sub { $self->close_ptkdb_window ; }) ; |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
# Control Menu |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
my $runSub = sub { $DB::step_over_depth = -1 ; $self->{'event'} = 'run' } ; |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
my $runToSub = sub { $DB::window->{'event'} = 'run' if $DB::window->SetBreakPoint(1) ; } ; |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
my $stepOverSub = sub { &DB::SetStepOverBreakPoint(0) ; |
824
|
|
|
|
|
|
|
$DB::single = 1 ; |
825
|
|
|
|
|
|
|
$DB::window->{'event'} = 'step' ; |
826
|
|
|
|
|
|
|
} ; |
827
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
my $stepInSub = sub { |
829
|
|
|
|
|
|
|
$DB::step_over_depth = -1 ; |
830
|
|
|
|
|
|
|
$DB::single = 1 ; |
831
|
|
|
|
|
|
|
$DB::window->{'event'} = 'step' ; |
832
|
|
|
|
|
|
|
}; |
833
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
my $returnSub = sub { |
835
|
|
|
|
|
|
|
&DB::SetStepOverBreakPoint(-1) ; |
836
|
|
|
|
|
|
|
$self->{'event'} = 'run' ; |
837
|
|
|
|
|
|
|
}; |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
my $items2 = [ [ 'command' => 'Run', -accelerator => 'Alt+r', -underline => 0, -command => $runSub ], |
841
|
|
|
|
|
|
|
[ 'command' => 'Run To Here', -accelerator => 'Alt+t', -underline => 5, -command => $runToSub ], |
842
|
|
|
|
|
|
|
'-', |
843
|
|
|
|
|
|
|
[ 'command' => 'Set Breakpoint', -underline => 4, -command => sub { $self->SetBreakPoint ; }, -accelerator => 'Ctrl-b' ], |
844
|
|
|
|
|
|
|
[ 'command' => 'Clear Breakpoint', -command => sub { $self->UnsetBreakPoint } ], |
845
|
|
|
|
|
|
|
[ 'command' => 'Clear All Breakpoints', -underline => 6, -command => sub { |
846
|
|
|
|
|
|
|
$DB::window->removeAllBreakpoints($DB::window->{current_file}); |
847
|
|
|
|
|
|
|
&DB::clearalldblines(); |
848
|
|
|
|
|
|
|
} ], |
849
|
|
|
|
|
|
|
'-', |
850
|
|
|
|
|
|
|
[ 'command' => 'Step Over', -accelerator => 'Alt+N', -underline => 0, -command => $stepOverSub ], |
851
|
|
|
|
|
|
|
[ 'command' => 'Step In', -accelerator => 'Alt+S', -underline => 5, -command => $stepInSub ], |
852
|
|
|
|
|
|
|
[ 'command' => 'Return', -accelerator => 'Alt+U', -underline => 3, -command => $returnSub ], |
853
|
|
|
|
|
|
|
'-', |
854
|
|
|
|
|
|
|
[ 'command' => 'Restart...', -accelerator => 'Ctrl-r', -underline => 0, -command => \&Devel::tcltkdb::DoRestart ], |
855
|
|
|
|
|
|
|
'-', |
856
|
|
|
|
|
|
|
[ 'checkbutton' => 'Stop On Warning', -variable => \$DB::tcltkdb::stop_on_warning, -command => \&set_stop_on_warning ] |
857
|
|
|
|
|
|
|
] ; # end of control menu items |
858
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
$mw->bind('' => $runSub) ; |
860
|
|
|
|
|
|
|
$mw->bind('', $runToSub) ; |
861
|
|
|
|
|
|
|
$mw->bind('', sub { $self->SetBreakPoint ; }); |
862
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
# step over a subroutine |
864
|
|
|
|
|
|
|
for ('', '', '') { |
865
|
|
|
|
|
|
|
$mw->bind($_ => $stepOverSub); |
866
|
|
|
|
|
|
|
} |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
# keys for step into a subroutine |
869
|
|
|
|
|
|
|
for ('', '', '') { |
870
|
|
|
|
|
|
|
$mw->bind($_ => $stepInSub ); |
871
|
|
|
|
|
|
|
} |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
# return from a subroutine |
874
|
|
|
|
|
|
|
for ('', '') { |
875
|
|
|
|
|
|
|
$mw->bind($_ => $returnSub ); |
876
|
|
|
|
|
|
|
} |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
# Data Menu |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
my $items3 = [ [ 'command' => 'Enter Expression', -accelerator => 'Alt+E', -command => sub { $self->EnterExpr() } ], |
881
|
|
|
|
|
|
|
[ 'command' => 'Delete Expression', -accelerator => 'Ctrl+D', -command => sub { $self->deleteExpr() } ], |
882
|
|
|
|
|
|
|
[ 'command' => 'Delete All Expressions', -command => sub { |
883
|
|
|
|
|
|
|
$self->deleteAllExprs() ; |
884
|
|
|
|
|
|
|
$self->{'expr_list'} = [] ; # clears list by dropping ref to it, replacing it with a new one |
885
|
|
|
|
|
|
|
} ], |
886
|
|
|
|
|
|
|
'-', |
887
|
|
|
|
|
|
|
[ 'command' => 'Expression Eval Window...', -accelerator => 'F8', -command => sub { $self->setupEvalWindow() ; } ], |
888
|
|
|
|
|
|
|
]; |
889
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
$mw->bind('' => sub { $self->EnterExpr() } ) ; |
891
|
|
|
|
|
|
|
$mw->bind('' => sub { $self->deleteExpr() } ); |
892
|
|
|
|
|
|
|
$mw->bind('', sub { $self->setupEvalWindow() ; }) ; |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
# |
895
|
|
|
|
|
|
|
# Windows Menu |
896
|
|
|
|
|
|
|
# |
897
|
|
|
|
|
|
|
my $bsub = sub { $self->{'text'}->focus() }; |
898
|
|
|
|
|
|
|
my $csub = sub { $self->{'quick_entry'}->focus() }; |
899
|
|
|
|
|
|
|
my $dsub = sub { $self->{'entry'}->focus() }; |
900
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
my $items4 = [ [ 'command' => 'Code Pane', -accelerator => 'Alt+0', -command => $bsub ], |
902
|
|
|
|
|
|
|
[ 'command' => 'Quick Entry', -accelerator => 'F9', -command => $csub ], |
903
|
|
|
|
|
|
|
[ 'command' => 'Expr Entry', -accelerator => 'F11', -command => $dsub ] |
904
|
|
|
|
|
|
|
]; |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
$mw->bind('', $bsub); |
907
|
|
|
|
|
|
|
$mw->bind('', $csub); |
908
|
|
|
|
|
|
|
$mw->bind('', $dsub); |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
my $menu = $mw->Menu(-menuitems => [ |
911
|
|
|
|
|
|
|
[Cascade=>'File', -tearoff => 0, -underline=>0, -menuitems=>$items1], |
912
|
|
|
|
|
|
|
[Cascade=>'Control', -tearoff=>0, -underline=>0, -menuitems => $items2], |
913
|
|
|
|
|
|
|
[Cascade=>'Data', -tearoff=>0, -menuitems => $items3, -underline => 0], |
914
|
|
|
|
|
|
|
[Cascade=>'Stack', -tearoff=>0, -underline => 2], |
915
|
|
|
|
|
|
|
[Cascade=>'Bookmarks', -tearoff=>0, -underline=>0], |
916
|
|
|
|
|
|
|
[Cascade=>'Windows', -tearoff=>0, -menuitems => $items4] |
917
|
|
|
|
|
|
|
]); |
918
|
|
|
|
|
|
|
# |
919
|
|
|
|
|
|
|
# Stack menu |
920
|
|
|
|
|
|
|
$self->{stack_menu} = $int->widget($menu->entrycget(4,'-menu'),'Menubutton'); |
921
|
|
|
|
|
|
|
# |
922
|
|
|
|
|
|
|
# Bookmarks menu |
923
|
|
|
|
|
|
|
$self->{bookmarks_menu} = $int->widget($menu->entrycget(5,'-menu'),'Menubutton'); |
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
$self->setup_bookmarks_menu(); |
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
$mw->config(-menu=>$menu); |
928
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
# |
930
|
|
|
|
|
|
|
# Bar for some popular controls |
931
|
|
|
|
|
|
|
my $bb = $mw->Frame()->pack(-side => 'top'); |
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
$bb->Button(-text => "Step In", @Devel::tcltkdb::button_font, |
934
|
|
|
|
|
|
|
-command => $stepInSub) ->pack(-side => 'left'); |
935
|
|
|
|
|
|
|
$bb->Button(-text => "Step Over", @Devel::tcltkdb::button_font, |
936
|
|
|
|
|
|
|
-command => $stepOverSub) ->pack(-side => 'left'); |
937
|
|
|
|
|
|
|
$bb->Button(-text => "Return", @Devel::tcltkdb::button_font, |
938
|
|
|
|
|
|
|
-command => $returnSub) ->pack(-side => 'left'); |
939
|
|
|
|
|
|
|
$bb->Button(-text => "Run", -background => 'green', @Devel::tcltkdb::button_font, |
940
|
|
|
|
|
|
|
-command => $runSub) ->pack(-side => 'left'); |
941
|
|
|
|
|
|
|
$bb->Button(-text => "Run To", @Devel::tcltkdb::button_font, |
942
|
|
|
|
|
|
|
-command => $runToSub) ->pack(-side => 'left'); |
943
|
|
|
|
|
|
|
$bb->Button(-text => "Break", @Devel::tcltkdb::button_font, |
944
|
|
|
|
|
|
|
-command => sub { $self->SetBreakPoint ; } ) ->pack(-side => 'left'); |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
} # end of setup_menu_bar |
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
sub edit_bookmarks { |
949
|
|
|
|
|
|
|
my ($self) = @_ ; |
950
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
my $top = $self->{main_window}->Toplevel(-title => "Edit Bookmarks"); |
952
|
|
|
|
|
|
|
my $list = $top->Scrolled('Listbox', -selectmode => 'multiple')->pack(-side => 'top', -fill => 'both', -expand => 1) ; |
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
my $deleteSub = sub { |
955
|
|
|
|
|
|
|
my $cnt = 0 ; |
956
|
|
|
|
|
|
|
for( $list->curselection ) { |
957
|
|
|
|
|
|
|
$list->delete($_ - $cnt++) ; |
958
|
|
|
|
|
|
|
} |
959
|
|
|
|
|
|
|
}; |
960
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
my $okaySub = sub { |
962
|
|
|
|
|
|
|
$self->{'bookmarks'} = [ $list->get(0, 'end') ] ; # replace the bookmarks |
963
|
|
|
|
|
|
|
}; |
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
my $frm = $top->Frame()->pack(-side => 'top', -fill => 'x', -expand => 1 ) ; |
966
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
my $deleteBtn = $frm->Button(-text => 'Delete', -command => $deleteSub)->pack(-side => 'left', -fill => 'x', -expand => 1 ); |
968
|
|
|
|
|
|
|
my $cancelBtn = $frm->Button(-text => 'Cancel', -command => sub { $top->destroy; })->pack(-side =>'left', -fill => 'x', -expand => 1 ); |
969
|
|
|
|
|
|
|
my $dismissBtn = $frm->Button(-text => 'Okay', -command => $okaySub)->pack(-side => 'left', -fill => 'x', -expand => 1 ); |
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
$list->insert('end', @{$self->{'bookmarks'}}) ; |
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
} # end of edit_bookmarks |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
sub setup_bookmarks_menu { |
976
|
|
|
|
|
|
|
my ($self) = @_ ; |
977
|
|
|
|
|
|
|
|
978
|
|
|
|
|
|
|
# |
979
|
|
|
|
|
|
|
# "Add bookmark" item |
980
|
|
|
|
|
|
|
# |
981
|
|
|
|
|
|
|
my $bkMarkSub = sub { $self->add_bookmark() ; } ; |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
$self->{'bookmarks_menu'}->command(-label => "Add Bookmark", |
984
|
|
|
|
|
|
|
-accelerator => 'Alt+k', |
985
|
|
|
|
|
|
|
-command => $bkMarkSub |
986
|
|
|
|
|
|
|
) ; |
987
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
$self->{'main_window'}->bind('', $bkMarkSub) ; |
989
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
$self->{'bookmarks_menu'}->command(-label => "Edit Bookmarks", |
991
|
|
|
|
|
|
|
-command => sub { $self->edit_bookmarks() } ) ; |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
$self->{'bookmarks_menu'}->separator() ; |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
# |
996
|
|
|
|
|
|
|
# Check to see if there is a bookmarks file |
997
|
|
|
|
|
|
|
# |
998
|
|
|
|
|
|
|
return unless -e $self->{BookMarksPath} && -r $self->{BookMarksPath} ; |
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
use vars qw($ptkdb_bookmarks) ; |
1001
|
|
|
|
|
|
|
local($ptkdb_bookmarks) ; # ref to hash of bookmark entries |
1002
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
do $self->{BookMarksPath} ; # eval the file |
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
$self->add_bookmark_items(@$ptkdb_bookmarks) ; |
1006
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
} # end of setup_bookmarks_menu |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
# |
1010
|
|
|
|
|
|
|
# $item = "$fname:$lineno" |
1011
|
|
|
|
|
|
|
# |
1012
|
|
|
|
|
|
|
sub add_bookmark_items { |
1013
|
|
|
|
|
|
|
my($self, @items) = @_ ; |
1014
|
|
|
|
|
|
|
my($menu) = ( $self->{'bookmarks_menu'} ) ; |
1015
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
$self->{'bookmarks_changed'} = 1 ; |
1017
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
for( @items ) { |
1019
|
|
|
|
|
|
|
my $item = $_ ; |
1020
|
|
|
|
|
|
|
$menu->command( -label => $_, |
1021
|
|
|
|
|
|
|
-command => sub { $self->bookmark_cmd($item) }); |
1022
|
|
|
|
|
|
|
push @{$self->{'bookmarks'}}, $item; |
1023
|
|
|
|
|
|
|
} |
1024
|
|
|
|
|
|
|
} # end of add_bookmark_item |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
# |
1027
|
|
|
|
|
|
|
# Invoked from the "Add Bookmark" command |
1028
|
|
|
|
|
|
|
# |
1029
|
|
|
|
|
|
|
sub add_bookmark { |
1030
|
|
|
|
|
|
|
my($self) = @_ ; |
1031
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
my $line = $self->get_lineno(); |
1033
|
|
|
|
|
|
|
my $fname = $self->{'current_file'}; |
1034
|
|
|
|
|
|
|
$self->add_bookmark_items("$fname:$line"); |
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
} # end of add_bookmark |
1037
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
# |
1039
|
|
|
|
|
|
|
# Command executed when someone selects a bookmark |
1040
|
|
|
|
|
|
|
# |
1041
|
|
|
|
|
|
|
sub bookmark_cmd { |
1042
|
|
|
|
|
|
|
my ($self, $item) = @_; |
1043
|
|
|
|
|
|
|
$item =~ /^(.*):(\d+)$/; |
1044
|
|
|
|
|
|
|
$self->set_file($1,$2); |
1045
|
|
|
|
|
|
|
} |
1046
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
sub save_bookmarks { |
1048
|
|
|
|
|
|
|
my($self, $pathName) = @_ ; |
1049
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
local(*F) ; |
1051
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
eval { |
1053
|
|
|
|
|
|
|
open F, ">$pathName" || die "open failed" ; |
1054
|
|
|
|
|
|
|
my $d = Data::Dumper->new([ $self->{'bookmarks'} ], |
1055
|
|
|
|
|
|
|
[ 'ptkdb_bookmarks' ]); |
1056
|
|
|
|
|
|
|
$d->Indent(2) ; # make it more editable for people |
1057
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
print F $d->Dump() || die "outputing bookmarks failed"; |
1059
|
|
|
|
|
|
|
close(F); |
1060
|
|
|
|
|
|
|
}; |
1061
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
if ($@) { |
1063
|
|
|
|
|
|
|
$self->DoAlert("Couldn't save bookmarks file $@") ; |
1064
|
|
|
|
|
|
|
return; |
1065
|
|
|
|
|
|
|
} |
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
} # end of save_bookmarks |
1068
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
sub line_number_from_coord { |
1071
|
|
|
|
|
|
|
my($txtWidget, $coord) = @_ ; |
1072
|
|
|
|
|
|
|
$txtWidget->index($coord) =~ /^(\d*)\.(\d*)$/; |
1073
|
|
|
|
|
|
|
return $1; |
1074
|
|
|
|
|
|
|
} # end of line_number_from_coord |
1075
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
# |
1077
|
|
|
|
|
|
|
# It may seem as if $txtWidget and $self are |
1078
|
|
|
|
|
|
|
# erroneously reversed, but this is a result |
1079
|
|
|
|
|
|
|
# of the calling syntax of the text-bind callback. |
1080
|
|
|
|
|
|
|
# |
1081
|
|
|
|
|
|
|
sub set_breakpoint_tag { |
1082
|
|
|
|
|
|
|
my ($self, $txtWidget, $coord, $value) = @_ ; |
1083
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
my $idx = line_number_from_coord($txtWidget, $coord) ; |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
$self->insertBreakpoint($self->{'current_file'}, $idx, $value) ; |
1087
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
} # end of set_breakpoint_tag |
1089
|
|
|
|
|
|
|
|
1090
|
|
|
|
|
|
|
sub clear_breakpoint_tag { |
1091
|
|
|
|
|
|
|
my ($self, $txtWidget, $coord) = @_ ; |
1092
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
my $idx = line_number_from_coord($txtWidget, $coord) ; |
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
$self->removeBreakpoint($self->{'current_file'}, $idx) ; |
1096
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
} # end of clear_breakpoint_tag |
1098
|
|
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
sub change_breakpoint_tag { |
1100
|
|
|
|
|
|
|
my ($self, $txtWidget, $coord, $value) = @_ ; |
1101
|
|
|
|
|
|
|
my ($brkPt, @tagSet) ; |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
my $idx = line_number_from_coord($txtWidget, $coord) ; |
1104
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
# |
1106
|
|
|
|
|
|
|
# Change the value of the breakpoint |
1107
|
|
|
|
|
|
|
# |
1108
|
|
|
|
|
|
|
@tagSet = ( "$idx.0", "$idx.$Devel::tcltkdb::linenumber_length" ) ; |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
$brkPt = &DB::getdbline($self->{'current_file'}, $idx + $self->{'line_offset'}) ; |
1111
|
|
|
|
|
|
|
return unless $brkPt ; |
1112
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
# |
1114
|
|
|
|
|
|
|
# Check the breakpoint tag |
1115
|
|
|
|
|
|
|
# |
1116
|
|
|
|
|
|
|
|
1117
|
|
|
|
|
|
|
if ( $txtWidget ) { |
1118
|
|
|
|
|
|
|
$txtWidget->tagRemove('breaksetLine', @tagSet ) ; |
1119
|
|
|
|
|
|
|
$txtWidget->tagRemove('breakdisabledLine', @tagSet ) ; |
1120
|
|
|
|
|
|
|
} |
1121
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
$brkPt->{'value'} = $value ; |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
if ( $txtWidget ) { |
1125
|
|
|
|
|
|
|
if ( $brkPt->{'value'} ) { |
1126
|
|
|
|
|
|
|
$txtWidget->tagAdd('breaksetLine', @tagSet ) ; |
1127
|
|
|
|
|
|
|
} |
1128
|
|
|
|
|
|
|
else { |
1129
|
|
|
|
|
|
|
$txtWidget->tagAdd('breakdisabledLine', @tagSet ) ; |
1130
|
|
|
|
|
|
|
} |
1131
|
|
|
|
|
|
|
} |
1132
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
} # end of change_breakpoint_tag |
1134
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
# |
1136
|
|
|
|
|
|
|
# God Forbid anyone comment something complex and tightly optimized. |
1137
|
|
|
|
|
|
|
# |
1138
|
|
|
|
|
|
|
# We can get a list of the subroutines from the interpreter |
1139
|
|
|
|
|
|
|
# by querrying the *DB::sub typeglob: keys %DB::sub |
1140
|
|
|
|
|
|
|
# |
1141
|
|
|
|
|
|
|
# The list appears broken down by module: |
1142
|
|
|
|
|
|
|
# |
1143
|
|
|
|
|
|
|
# main::BEGIN |
1144
|
|
|
|
|
|
|
# main::mySub |
1145
|
|
|
|
|
|
|
# main::otherSub |
1146
|
|
|
|
|
|
|
# Tk::Adjuster::Mapped |
1147
|
|
|
|
|
|
|
# Tk::Adjuster::Packed |
1148
|
|
|
|
|
|
|
# Tk::Button::BEGIN |
1149
|
|
|
|
|
|
|
# Tk::Button::Enter |
1150
|
|
|
|
|
|
|
# |
1151
|
|
|
|
|
|
|
# We would like to break this list down into a heirarchy. |
1152
|
|
|
|
|
|
|
# |
1153
|
|
|
|
|
|
|
# main Tk |
1154
|
|
|
|
|
|
|
# | | | | |
1155
|
|
|
|
|
|
|
# BEGIN mySub OtherSub | | |
1156
|
|
|
|
|
|
|
# Adjuster Button |
1157
|
|
|
|
|
|
|
# | | | | |
1158
|
|
|
|
|
|
|
# Mapped Packed BEGIN Enter |
1159
|
|
|
|
|
|
|
# |
1160
|
|
|
|
|
|
|
# |
1161
|
|
|
|
|
|
|
# We translate this list into a heirarchy of hashes(say three times fast). |
1162
|
|
|
|
|
|
|
# We take each entry and split it into elements. Each element is a leaf in the tree. |
1163
|
|
|
|
|
|
|
# We traverse the tree with the inner for loop. |
1164
|
|
|
|
|
|
|
# With each branch we check to see if it already exists or |
1165
|
|
|
|
|
|
|
# we create it. When we reach the last element, this becomes our entry. |
1166
|
|
|
|
|
|
|
# |
1167
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
# |
1169
|
|
|
|
|
|
|
# An incoming list is potentially 'large' so we |
1170
|
|
|
|
|
|
|
# pass in the ref to it instead. |
1171
|
|
|
|
|
|
|
# |
1172
|
|
|
|
|
|
|
# New entries can be inserted by providing a $topH |
1173
|
|
|
|
|
|
|
# hash ref to an existing tree. |
1174
|
|
|
|
|
|
|
# |
1175
|
|
|
|
|
|
|
sub tree_split { |
1176
|
|
|
|
|
|
|
my ($listRef) = @_; |
1177
|
|
|
|
|
|
|
my $topH = {}; |
1178
|
|
|
|
|
|
|
|
1179
|
|
|
|
|
|
|
for my $list_elem (@$listRef) { |
1180
|
|
|
|
|
|
|
my $h = $topH ; |
1181
|
|
|
|
|
|
|
for (split /::/, $list_elem) { # Tk::Adjuster::Mapped -> ( Tk Adjuster Mapped ) |
1182
|
|
|
|
|
|
|
$h->{$_} or $h->{$_} = {}; # either we have an entry for this OR we create one |
1183
|
|
|
|
|
|
|
$h = $h->{$_}; |
1184
|
|
|
|
|
|
|
} |
1185
|
|
|
|
|
|
|
@$h{'name', 'path'} = (undef, $list_elem) ; # the last leaf is our entry |
1186
|
|
|
|
|
|
|
} # end of tree_split loop |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
return $topH ; |
1189
|
|
|
|
|
|
|
} # end of tree_split |
1190
|
|
|
|
|
|
|
|
1191
|
|
|
|
|
|
|
# |
1192
|
|
|
|
|
|
|
# callback executed when someone double clicks |
1193
|
|
|
|
|
|
|
# an entry in the 'Subs' Tk::Notebook page. |
1194
|
|
|
|
|
|
|
# |
1195
|
|
|
|
|
|
|
sub sub_list_cmd { |
1196
|
|
|
|
|
|
|
my ($self, $path) = @_; |
1197
|
|
|
|
|
|
|
print STDERR "arg=[[@_]]\n"; |
1198
|
|
|
|
|
|
|
my $sub_list = $self->{'sub_list'} ; |
1199
|
|
|
|
|
|
|
|
1200
|
|
|
|
|
|
|
if ($sub_list->info('children', $path)) { |
1201
|
|
|
|
|
|
|
# |
1202
|
|
|
|
|
|
|
# Delete the children |
1203
|
|
|
|
|
|
|
$sub_list->deleteOffsprings($path); |
1204
|
|
|
|
|
|
|
print STDERR "vvvv2\n"; |
1205
|
|
|
|
|
|
|
return; |
1206
|
|
|
|
|
|
|
} |
1207
|
|
|
|
|
|
|
print STDERR "vvvv3\n"; |
1208
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
# |
1210
|
|
|
|
|
|
|
# split the path up into elements |
1211
|
|
|
|
|
|
|
# end descend through the tree. |
1212
|
|
|
|
|
|
|
# |
1213
|
|
|
|
|
|
|
my $h = $Devel::tcltkdb::subs_tree ; |
1214
|
|
|
|
|
|
|
for ( split /\./, $path ) { |
1215
|
|
|
|
|
|
|
$h = $h->{$_} ; # next level down |
1216
|
|
|
|
|
|
|
} |
1217
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
# |
1219
|
|
|
|
|
|
|
# if we don't have a 'name' entry we |
1220
|
|
|
|
|
|
|
# still have levels to decend through. |
1221
|
|
|
|
|
|
|
# |
1222
|
|
|
|
|
|
|
if ( !exists $h->{'name'} ) { |
1223
|
|
|
|
|
|
|
# |
1224
|
|
|
|
|
|
|
# Add the next level paths |
1225
|
|
|
|
|
|
|
# |
1226
|
|
|
|
|
|
|
for ( sort keys %$h ) { |
1227
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
if ( exists $h->{$_}->{'path'} ) { |
1229
|
|
|
|
|
|
|
$sub_list->add($path . '.' . $_, -text => $h->{$_}->{'path'}) ; |
1230
|
|
|
|
|
|
|
} else { |
1231
|
|
|
|
|
|
|
$sub_list->add($path . '.' . $_, -text => $_) ; |
1232
|
|
|
|
|
|
|
} |
1233
|
|
|
|
|
|
|
} |
1234
|
|
|
|
|
|
|
return ; |
1235
|
|
|
|
|
|
|
} |
1236
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
$DB::sub{$h->{'path'}} =~ /^(.*):(\d+)-\d+$/; # file name will be in $1, line number will be in $2 |
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
$self->set_file($1, $2); |
1240
|
|
|
|
|
|
|
} # end of sub_list_cmd |
1241
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
sub sub_list_cmd0 { |
1243
|
|
|
|
|
|
|
my ($self) = @_; |
1244
|
|
|
|
|
|
|
my $list = $self->{sub_list0} ; |
1245
|
|
|
|
|
|
|
my ($la, $le) = ($list->_indexActive,$list->_indexEnd); |
1246
|
|
|
|
|
|
|
print STDERR "<<$la-$le>>\n"; |
1247
|
|
|
|
|
|
|
my @l = map {$list->get($_)} $la .. $le; |
1248
|
|
|
|
|
|
|
# check if items following $l[0] are its children, and delete it, if it is the case |
1249
|
|
|
|
|
|
|
my @levs = map {/^(\s*)/;length($1)} @l; |
1250
|
|
|
|
|
|
|
print STDERR "{{@l}}\n"; |
1251
|
|
|
|
|
|
|
print STDERR "{{@levs}}\n"; |
1252
|
|
|
|
|
|
|
my $lev = $levs[0]; |
1253
|
|
|
|
|
|
|
my $l1 = 1; |
1254
|
|
|
|
|
|
|
my $direct_children=0; |
1255
|
|
|
|
|
|
|
while ($l1<=$#l and $lev<$levs[$l1]) { |
1256
|
|
|
|
|
|
|
# delete list[l1] |
1257
|
|
|
|
|
|
|
$list->delete($la+1); |
1258
|
|
|
|
|
|
|
$l1++; |
1259
|
|
|
|
|
|
|
$direct_children=1; |
1260
|
|
|
|
|
|
|
} |
1261
|
|
|
|
|
|
|
return if $direct_children; |
1262
|
|
|
|
|
|
|
|
1263
|
|
|
|
|
|
|
# |
1264
|
|
|
|
|
|
|
# split the path up into elements end descend through the tree. |
1265
|
|
|
|
|
|
|
my $path = $list->get($la); |
1266
|
|
|
|
|
|
|
$path =~ s/^\s+//; |
1267
|
|
|
|
|
|
|
my $h = $Devel::tcltkdb::subs_tree; |
1268
|
|
|
|
|
|
|
for ( split /::/, $path ) { |
1269
|
|
|
|
|
|
|
$h = $h->{$_} ; # next level down |
1270
|
|
|
|
|
|
|
} |
1271
|
|
|
|
|
|
|
|
1272
|
|
|
|
|
|
|
# |
1273
|
|
|
|
|
|
|
# if we don't have a 'name' entry we |
1274
|
|
|
|
|
|
|
# still have levels to decend through. |
1275
|
|
|
|
|
|
|
# |
1276
|
|
|
|
|
|
|
if ( !exists $h->{'name'} ) { |
1277
|
|
|
|
|
|
|
# |
1278
|
|
|
|
|
|
|
# Add the next level paths |
1279
|
|
|
|
|
|
|
my $sp = " " x ($lev+1); |
1280
|
|
|
|
|
|
|
for (sort keys %$h) { |
1281
|
|
|
|
|
|
|
if ( exists $h->{$_}->{'path'} ) { |
1282
|
|
|
|
|
|
|
$list->insert($la+$l1,$sp.$h->{$_}->{'path'}); |
1283
|
|
|
|
|
|
|
} else { |
1284
|
|
|
|
|
|
|
$list->insert($la+$l1,$sp.$_); |
1285
|
|
|
|
|
|
|
} |
1286
|
|
|
|
|
|
|
$l1++; |
1287
|
|
|
|
|
|
|
} |
1288
|
|
|
|
|
|
|
return ; |
1289
|
|
|
|
|
|
|
} |
1290
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
$DB::sub{$h->{'path'}} =~ /(.*):(\d+)-\d+$/; # file name will be in $1, line number in $2 |
1292
|
|
|
|
|
|
|
|
1293
|
|
|
|
|
|
|
$self->set_file($1, $2); |
1294
|
|
|
|
|
|
|
} |
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
sub fill_subs_page { |
1297
|
|
|
|
|
|
|
my $self = shift; |
1298
|
|
|
|
|
|
|
my @list = keys %DB::sub; |
1299
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
$self->{sub_list0}->delete(0,'end'); # clear existing entries |
1301
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
$Devel::tcltkdb::subs_tree = tree_split(\@list); |
1303
|
|
|
|
|
|
|
|
1304
|
|
|
|
|
|
|
for ( sort keys %$Devel::tcltkdb::subs_tree ) { |
1305
|
|
|
|
|
|
|
$self->{sub_list0}->_insertEnd($_); |
1306
|
|
|
|
|
|
|
} |
1307
|
|
|
|
|
|
|
} |
1308
|
|
|
|
|
|
|
|
1309
|
|
|
|
|
|
|
sub setup_subs_page { |
1310
|
|
|
|
|
|
|
my $self = shift; |
1311
|
|
|
|
|
|
|
|
1312
|
|
|
|
|
|
|
$self->{'subs_page_activated'} = 1; |
1313
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
my $w1 = $self->{'subs_page'}->Scrolled('Listbox', -selectmode=>'single'); |
1315
|
|
|
|
|
|
|
$self->{'sub_list0'} = $w1->Subwidget; |
1316
|
|
|
|
|
|
|
$self->{int}->bind($self->{'sub_list0'}, "" => sub { $self->sub_list_cmd0(@_); }); |
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
$w1->pack(qw/-side left -fill both -expand 1/); |
1319
|
|
|
|
|
|
|
|
1320
|
|
|
|
|
|
|
$self->fill_subs_page(); |
1321
|
|
|
|
|
|
|
|
1322
|
|
|
|
|
|
|
$self->{'subs_list_cnt'} = scalar keys %DB::sub; |
1323
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
} # end of setup_subs_page |
1325
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
sub check_search_request { |
1328
|
|
|
|
|
|
|
my($entry, $self, $searchButton, $regexBtn) = @_ ; |
1329
|
|
|
|
|
|
|
my($txt) = $entry->get ; |
1330
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
if( $txt =~ /^\s*\d+\s*$/ ) { |
1332
|
|
|
|
|
|
|
$self->DoGoto($entry) ; |
1333
|
|
|
|
|
|
|
return ; |
1334
|
|
|
|
|
|
|
} |
1335
|
|
|
|
|
|
|
|
1336
|
|
|
|
|
|
|
if( $txt =~ /\.\*/ ) { # common regex search pattern |
1337
|
|
|
|
|
|
|
$self->FindSearch($entry, $regexBtn, 1) ; |
1338
|
|
|
|
|
|
|
return ; |
1339
|
|
|
|
|
|
|
} |
1340
|
|
|
|
|
|
|
|
1341
|
|
|
|
|
|
|
# vanilla search |
1342
|
|
|
|
|
|
|
$self->FindSearch($entry, $searchButton, 0) ; |
1343
|
|
|
|
|
|
|
} |
1344
|
|
|
|
|
|
|
|
1345
|
|
|
|
|
|
|
sub setup_search_panel { |
1346
|
|
|
|
|
|
|
my ($self, $parent) = @_ ; |
1347
|
|
|
|
|
|
|
my ($srchBtn, $regexBtn, $entry) ; |
1348
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
my $frm = $parent->Frame(); |
1350
|
|
|
|
|
|
|
|
1351
|
|
|
|
|
|
|
$frm->Button(-text => 'Goto', -command => sub { $self->DoGoto($entry) })->pack(-side => 'left'); |
1352
|
|
|
|
|
|
|
$srchBtn = $frm->Button(-text => 'Search', -command => sub { $self->FindSearch($entry, $srchBtn, 0) ; } |
1353
|
|
|
|
|
|
|
)->pack(-side => 'left'); |
1354
|
|
|
|
|
|
|
|
1355
|
|
|
|
|
|
|
$regexBtn = $frm->Button(-text => 'Regex', |
1356
|
|
|
|
|
|
|
-command => sub { $self->FindSearch($entry, $regexBtn, 1) ; } |
1357
|
|
|
|
|
|
|
)->pack(-side => 'left'); |
1358
|
|
|
|
|
|
|
|
1359
|
|
|
|
|
|
|
$entry = $frm->Entry(-width => 50)->pack(qw/-side left -fill both -expand 1/); |
1360
|
|
|
|
|
|
|
|
1361
|
|
|
|
|
|
|
$entry->bind('', sub { check_search_request($entry, $self, $srchBtn, $regexBtn) ; } ); |
1362
|
|
|
|
|
|
|
|
1363
|
|
|
|
|
|
|
$frm->pack(qw/-side top -fill x/); |
1364
|
|
|
|
|
|
|
|
1365
|
|
|
|
|
|
|
} # end of setup search_panel |
1366
|
|
|
|
|
|
|
|
1367
|
|
|
|
|
|
|
sub setup_breakpts_page { |
1368
|
|
|
|
|
|
|
my ($self) = @_ ; |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
$self->{'notebook'}->_insertEnd("brkptspage", -text => "BrkPts") ; |
1371
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
my $sw = $self->{'notebook'}->getframe("brkptspage")->ScrolledWindow()->pack(qw(-side top -fill both -expand 1)); |
1373
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
$self->{'breakpts_table'} = $sw->ScrollableFrame(); |
1375
|
|
|
|
|
|
|
$sw->setwidget($self->{'breakpts_table'}); |
1376
|
|
|
|
|
|
|
|
1377
|
|
|
|
|
|
|
$self->{'breakpts_table_data'} = {}; # controls addressed by "fname:lineno" |
1378
|
|
|
|
|
|
|
|
1379
|
|
|
|
|
|
|
} # end of setup_breakpts_page |
1380
|
|
|
|
|
|
|
|
1381
|
|
|
|
|
|
|
sub setup_frames { |
1382
|
|
|
|
|
|
|
my ($self) = @_; |
1383
|
|
|
|
|
|
|
my $mw = $self->{'main_window'}; |
1384
|
|
|
|
|
|
|
|
1385
|
|
|
|
|
|
|
my $pw = $mw->Panedwindow()->pack(qw/-side left -fill both -expand 1/); |
1386
|
|
|
|
|
|
|
my $frm = $pw->Frame->pack(qw/-side top -fill both -expand 1/); # frame for our code pane and search controls |
1387
|
|
|
|
|
|
|
|
1388
|
|
|
|
|
|
|
$self->setup_search_panel($frm); |
1389
|
|
|
|
|
|
|
|
1390
|
|
|
|
|
|
|
# |
1391
|
|
|
|
|
|
|
# Text window for the code of our currently viewed file |
1392
|
|
|
|
|
|
|
# |
1393
|
|
|
|
|
|
|
my $txt = $frm->Scrolled('ROText', -wrap => "none", |
1394
|
|
|
|
|
|
|
@Devel::tcltkdb::code_text_font |
1395
|
|
|
|
|
|
|
)->pack(qw/-side top -fill both -expand 1/); |
1396
|
|
|
|
|
|
|
$self->{'text'} = $txt->Subwidget; |
1397
|
|
|
|
|
|
|
|
1398
|
|
|
|
|
|
|
$self->configure_text(); |
1399
|
|
|
|
|
|
|
|
1400
|
|
|
|
|
|
|
# |
1401
|
|
|
|
|
|
|
# Notebook |
1402
|
|
|
|
|
|
|
# |
1403
|
|
|
|
|
|
|
|
1404
|
|
|
|
|
|
|
my $nb = $self->{'notebook'} = $pw->BWNoteBook() |
1405
|
|
|
|
|
|
|
->pack(qw/-side left -fill both -expand 1/); |
1406
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
$pw->add($frm, $nb); |
1408
|
|
|
|
|
|
|
|
1409
|
|
|
|
|
|
|
# |
1410
|
|
|
|
|
|
|
# a widget for the data entries |
1411
|
|
|
|
|
|
|
# |
1412
|
|
|
|
|
|
|
$nb->_insertEnd("datapage", -text => "Exprs"); |
1413
|
|
|
|
|
|
|
$self->{'data_page'} = $nb->getframe("datapage"); |
1414
|
|
|
|
|
|
|
|
1415
|
|
|
|
|
|
|
# |
1416
|
|
|
|
|
|
|
# frame, entry and label for quick expressions |
1417
|
|
|
|
|
|
|
# |
1418
|
|
|
|
|
|
|
my $frame = $self->{'data_page'}->Frame()->pack(-side => 'top', -fill => 'x') ; |
1419
|
|
|
|
|
|
|
my $label = $frame->Label(-text => "Quick Expr:")->pack(-side => 'left') ; |
1420
|
|
|
|
|
|
|
|
1421
|
|
|
|
|
|
|
$self->{'quick_entry'} = $frame->Entry()->pack(-side => 'left', -fill => 'x', -expand => 1) ; |
1422
|
|
|
|
|
|
|
$self->{'quick_entry'}->bind('', sub { $self->QuickExpr() ; } ) ; |
1423
|
|
|
|
|
|
|
|
1424
|
|
|
|
|
|
|
# |
1425
|
|
|
|
|
|
|
# Entry widget for expressions and breakpoints |
1426
|
|
|
|
|
|
|
# |
1427
|
|
|
|
|
|
|
$frame = $self->{'data_page'}->Frame()->pack(-side => 'top', -fill => 'x') ; |
1428
|
|
|
|
|
|
|
$label = $frame->Label(-text => "Enter Expr:")->pack(-side => 'left') ; |
1429
|
|
|
|
|
|
|
|
1430
|
|
|
|
|
|
|
$self->{'entry'} = $frame->Entry()->pack(-side => 'left', -fill => 'x', -expand => 1) ; |
1431
|
|
|
|
|
|
|
$self->{'entry'}->bind('', sub { $self->EnterExpr() }) ; |
1432
|
|
|
|
|
|
|
|
1433
|
|
|
|
|
|
|
# |
1434
|
|
|
|
|
|
|
# tk widget for data expressions |
1435
|
|
|
|
|
|
|
# |
1436
|
|
|
|
|
|
|
my $w_tree = $self->{'data_page'}->Scrolled('Treectrl',-showroot=>1,-showrootbutton=>1) |
1437
|
|
|
|
|
|
|
->pack(qw/-side top -fill both -expand 1/); |
1438
|
|
|
|
|
|
|
$self->{data_list0} = [$w_tree->Subwidget, $w_tree->columnCreate()]; |
1439
|
|
|
|
|
|
|
$w_tree->elementCreate('foo','text'); |
1440
|
|
|
|
|
|
|
$w_tree->elementCreate('bar','rect',-showfocus=>1); |
1441
|
|
|
|
|
|
|
$w_tree->styleCreate('st'); |
1442
|
|
|
|
|
|
|
$w_tree->styleElements('st',['foo','bar']); |
1443
|
|
|
|
|
|
|
$w_tree->styleLayout('st','bar',-union=>'foo'); |
1444
|
|
|
|
|
|
|
$w_tree->configure(-defaultstyle=>'st',-treecolumn=>$self->{data_list0}->[1]); |
1445
|
|
|
|
|
|
|
|
1446
|
|
|
|
|
|
|
$self->{'subs_page_activated'} = 0 ; |
1447
|
|
|
|
|
|
|
$nb->_insertEnd("subspage", -text => "Subs"); |
1448
|
|
|
|
|
|
|
$self->{'subs_page'} = $nb->getframe("subspage"); |
1449
|
|
|
|
|
|
|
|
1450
|
|
|
|
|
|
|
$self->setup_subs_page(); |
1451
|
|
|
|
|
|
|
$self->setup_breakpts_page(); |
1452
|
|
|
|
|
|
|
|
1453
|
|
|
|
|
|
|
$nb->_raise("datapage"); |
1454
|
|
|
|
|
|
|
|
1455
|
|
|
|
|
|
|
} # end of setup_frames |
1456
|
|
|
|
|
|
|
|
1457
|
|
|
|
|
|
|
|
1458
|
|
|
|
|
|
|
sub configure_text { |
1459
|
|
|
|
|
|
|
my($self) = @_ ; |
1460
|
|
|
|
|
|
|
my($txt, $mw) = ($self->{'text'}, $self->{'main_window'}) ; |
1461
|
|
|
|
|
|
|
|
1462
|
|
|
|
|
|
|
if (0) { |
1463
|
|
|
|
|
|
|
# balloon |
1464
|
|
|
|
|
|
|
$self->{'expr_balloon'} = $txt->Balloon(); |
1465
|
|
|
|
|
|
|
$self->{'balloon_expr'} = ' '; # initial expression |
1466
|
|
|
|
|
|
|
|
1467
|
|
|
|
|
|
|
$self->{'expr_ballon_msg'} = ' '; |
1468
|
|
|
|
|
|
|
$self->{'expr_balloon'}->attach($txt, -initwait => 300, |
1469
|
|
|
|
|
|
|
-msg => \$self->{'expr_ballon_msg'}, |
1470
|
|
|
|
|
|
|
-balloonposition => 'mouse', |
1471
|
|
|
|
|
|
|
-postcommand => \&Devel::tcltkdb::balloon_post, |
1472
|
|
|
|
|
|
|
-motioncommand => \&Devel::tcltkdb::balloon_motion ); |
1473
|
|
|
|
|
|
|
} |
1474
|
|
|
|
|
|
|
|
1475
|
|
|
|
|
|
|
$self->{'quick_dumper'} = new Data::Dumper([]); |
1476
|
|
|
|
|
|
|
$self->{'quick_dumper'}->Terse(1); |
1477
|
|
|
|
|
|
|
$self->{'quick_dumper'}->Indent(0); |
1478
|
|
|
|
|
|
|
|
1479
|
|
|
|
|
|
|
|
1480
|
|
|
|
|
|
|
# tags for the text |
1481
|
|
|
|
|
|
|
# 'code' Format for code in the text pane |
1482
|
|
|
|
|
|
|
# 'stoppt' Format applied to the line where the debugger is currently stopped |
1483
|
|
|
|
|
|
|
# 'breakableLine' Format applied to line numbers where the code is 'breakable' |
1484
|
|
|
|
|
|
|
# 'nonbreakableLine' Format applied to line numbers where the code is no breakable |
1485
|
|
|
|
|
|
|
# 'breaksetLine' Format applied to line numbers were a breakpoint is set |
1486
|
|
|
|
|
|
|
# 'breakdisabledLine' Format applied to line numbers were a disabled breakpoint is set |
1487
|
|
|
|
|
|
|
# 'search_tag' Format applied to text when located by a search. |
1488
|
|
|
|
|
|
|
|
1489
|
|
|
|
|
|
|
my @stopTagConfig = ( -foreground => 'white', -background => $mw->optionGet("stopcolor", "background") || $ENV{'PTKDB_STOP_TAG_COLOR'} || 'blue' ); |
1490
|
|
|
|
|
|
|
|
1491
|
|
|
|
|
|
|
my $stopFnt = $mw->optionGet("stopfont", "background") || $ENV{'PTKDB_STOP_TAG_FONT'} ; |
1492
|
|
|
|
|
|
|
push @stopTagConfig, ( -font => $stopFnt ) if $stopFnt ; # user may not have specified a font, if not, stay with the default |
1493
|
|
|
|
|
|
|
|
1494
|
|
|
|
|
|
|
$txt->_tagConfigure('stoppt', @stopTagConfig) ; |
1495
|
|
|
|
|
|
|
$txt->_tagConfigure('search_tag', "-background" => $mw->optionGet("searchtagcolor", "background") || "green") ; |
1496
|
|
|
|
|
|
|
|
1497
|
|
|
|
|
|
|
$txt->_tagConfigure("breakableLine", -overstrike => 0) ; |
1498
|
|
|
|
|
|
|
$txt->_tagConfigure("nonbreakableLine", -overstrike => 1) ; |
1499
|
|
|
|
|
|
|
$txt->_tagConfigure("breaksetLine", -background => $mw->optionGet("breaktagcolor", "background") || $ENV{'PTKDB_BRKPT_COLOR'} || 'red') ; |
1500
|
|
|
|
|
|
|
$txt->_tagConfigure("breakdisabledLine", -background => $mw->optionGet("disabledbreaktagcolor", "background") || $ENV{'PTKDB_DISABLEDBRKPT_COLOR'} || 'green') ; |
1501
|
|
|
|
|
|
|
|
1502
|
|
|
|
|
|
|
$txt->tagBind("breakableLine", '', \\'xy', sub {my($ex,$ey)=($_[-2],$_[-1]);$self->set_breakpoint_tag($txt, "\@$ex,$ey", 1 )} ); |
1503
|
|
|
|
|
|
|
$txt->tagBind("breakableLine", '', \\'xy', sub {my($ex,$ey)=($_[-2],$_[-1]); $self->set_breakpoint_tag($txt, "\@$ex,$ey", 0 )} ) ; |
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
$txt->tagBind("breaksetLine", '', \\'xy', sub {my($ex,$ey)=($_[-2],$_[-1]); $self->clear_breakpoint_tag($txt, "\@$ex,$ey", )} ) ; |
1506
|
|
|
|
|
|
|
$txt->tagBind("breaksetLine", '', \\'xy', sub {my($ex,$ey)=($_[-2],$_[-1]); $self->change_breakpoint_tag($txt, "\@$ex,$ey", 0 )} ) ; |
1507
|
|
|
|
|
|
|
|
1508
|
|
|
|
|
|
|
$txt->tagBind("breakdisabledLine", '', \\'xy', sub {my($ex,$ey)=($_[-2],$_[-1]); $self->clear_breakpoint_tag($txt, "\@$ex,$ey", )} ) ; |
1509
|
|
|
|
|
|
|
$txt->tagBind("breakdisabledLine", '', \\'xy', sub {my($ex,$ey)=($_[-2],$_[-1]); $self->change_breakpoint_tag($txt, "\@$ex,$ey", 1) } ) ; |
1510
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
} # end of configure_text |
1512
|
|
|
|
|
|
|
|
1513
|
|
|
|
|
|
|
|
1514
|
|
|
|
|
|
|
sub DoAlert { |
1515
|
|
|
|
|
|
|
my($self, $msg, $title) = @_ ; |
1516
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
my $dlg = $self->{main_window}->Toplevel(-title => $title || "Alert", -overanchor => 'cursor') ; |
1518
|
|
|
|
|
|
|
my $okaySub = sub { |
1519
|
|
|
|
|
|
|
$dlg->destroy; |
1520
|
|
|
|
|
|
|
}; |
1521
|
|
|
|
|
|
|
|
1522
|
|
|
|
|
|
|
$dlg->Label(-text => $msg )->pack( -side => 'top' ) ; |
1523
|
|
|
|
|
|
|
$dlg->Button(-text => "Okay", -command => $okaySub )->pack(-side => 'top')->focus; |
1524
|
|
|
|
|
|
|
$dlg->bind('', $okaySub); |
1525
|
|
|
|
|
|
|
|
1526
|
|
|
|
|
|
|
} # end of DoAlert |
1527
|
|
|
|
|
|
|
|
1528
|
|
|
|
|
|
|
sub simplePromptBox { |
1529
|
|
|
|
|
|
|
my ($self, $title, $defaultText, $okaySub, $cancelSub) = @_ ; |
1530
|
|
|
|
|
|
|
$Devel::tcltkdb::promptString = $defaultText; |
1531
|
|
|
|
|
|
|
|
1532
|
|
|
|
|
|
|
my $top = $self->{main_window}->Toplevel(-title => $title, -overanchor => 'cursor'); |
1533
|
|
|
|
|
|
|
my $entry = $top->Entry(-textvariable => \$Devel::tcltkdb::promptString)->pack(-side => 'top', -fill => 'both', -expand => 1); |
1534
|
|
|
|
|
|
|
$top->Button(-text => "Okay", @Devel::tcltkdb::button_font, -command => sub { &$okaySub(); $top->destroy ;} |
1535
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'both', -expand => 1); |
1536
|
|
|
|
|
|
|
$top->Button(-text => "Cancel", -command => sub { &$cancelSub() if $cancelSub ; $top->destroy() }, |
1537
|
|
|
|
|
|
|
@Devel::tcltkdb::button_font)->pack(-side => 'left', -fill => 'both', -expand => 1); |
1538
|
|
|
|
|
|
|
$entry->icursor('end'); |
1539
|
|
|
|
|
|
|
$entry->selectionRange(0, 'end'); |
1540
|
|
|
|
|
|
|
$entry->focus(); |
1541
|
|
|
|
|
|
|
|
1542
|
|
|
|
|
|
|
return $top ; |
1543
|
|
|
|
|
|
|
} # end of simplePromptBox |
1544
|
|
|
|
|
|
|
|
1545
|
|
|
|
|
|
|
|
1546
|
|
|
|
|
|
|
# |
1547
|
|
|
|
|
|
|
# Clear any text that is in the entry field. If there |
1548
|
|
|
|
|
|
|
# was any text in that field return it. If there |
1549
|
|
|
|
|
|
|
# was no text then return any selection that may be active. |
1550
|
|
|
|
|
|
|
# |
1551
|
|
|
|
|
|
|
sub clear_entry_text { |
1552
|
|
|
|
|
|
|
my($self) = @_ ; |
1553
|
|
|
|
|
|
|
my $str = $self->{'entry'}->get() ; |
1554
|
|
|
|
|
|
|
$self->{'entry'}->delete(0, 'end') ; |
1555
|
|
|
|
|
|
|
|
1556
|
|
|
|
|
|
|
# |
1557
|
|
|
|
|
|
|
# No String |
1558
|
|
|
|
|
|
|
# Empty String |
1559
|
|
|
|
|
|
|
# Or a string that is only whitespace |
1560
|
|
|
|
|
|
|
# |
1561
|
|
|
|
|
|
|
if( !$str || $str =~ /^\s*$/ ) { |
1562
|
|
|
|
|
|
|
# |
1563
|
|
|
|
|
|
|
# If there is no string or the string is just white text |
1564
|
|
|
|
|
|
|
# Get the text in the selection (if any) |
1565
|
|
|
|
|
|
|
# |
1566
|
|
|
|
|
|
|
if( $self->{'text'}->tagRanges('sel') ) { # check to see if 'sel' tag exists |
1567
|
|
|
|
|
|
|
$str = $self->{'text'}->get("sel.first", "sel.last") ; # get the text between the 'first' and 'last' point of the sel (selection) tag |
1568
|
|
|
|
|
|
|
} |
1569
|
|
|
|
|
|
|
# If still no text, bring the focus to the entry |
1570
|
|
|
|
|
|
|
if (!$str || $str =~ /^\s*$/) { |
1571
|
|
|
|
|
|
|
$self->{'entry'}->focus(); |
1572
|
|
|
|
|
|
|
$str = ""; |
1573
|
|
|
|
|
|
|
} |
1574
|
|
|
|
|
|
|
} |
1575
|
|
|
|
|
|
|
# |
1576
|
|
|
|
|
|
|
# Erase existing text |
1577
|
|
|
|
|
|
|
# |
1578
|
|
|
|
|
|
|
return $str; |
1579
|
|
|
|
|
|
|
} # end of clear_entry_text |
1580
|
|
|
|
|
|
|
|
1581
|
|
|
|
|
|
|
sub brkPtCheckbutton { |
1582
|
|
|
|
|
|
|
my ($self, $fname, $idx, $brkPt) = @_ ; |
1583
|
|
|
|
|
|
|
my ($widg) ; |
1584
|
|
|
|
|
|
|
|
1585
|
|
|
|
|
|
|
$self->change_breakpoint_tag($self->{'text'}, "$idx.0", $brkPt->{'value'}) if $fname eq $self->{'current_file'} ; |
1586
|
|
|
|
|
|
|
|
1587
|
|
|
|
|
|
|
} # end of brkPtCheckbutton |
1588
|
|
|
|
|
|
|
|
1589
|
|
|
|
|
|
|
# |
1590
|
|
|
|
|
|
|
# insert a breakpoint control into our breakpoint list. |
1591
|
|
|
|
|
|
|
# returns a handle to the control |
1592
|
|
|
|
|
|
|
# |
1593
|
|
|
|
|
|
|
# Expression, if defined, is to be evaluated at the breakpoint |
1594
|
|
|
|
|
|
|
# and execution stopped if it is non-zero/defined. |
1595
|
|
|
|
|
|
|
# |
1596
|
|
|
|
|
|
|
# If action is defined && True then it will be evalled |
1597
|
|
|
|
|
|
|
# before continuing. |
1598
|
|
|
|
|
|
|
# |
1599
|
|
|
|
|
|
|
sub insertBreakpoint { |
1600
|
|
|
|
|
|
|
my ($self, $fname, @brks) = @_ ; |
1601
|
|
|
|
|
|
|
my ($btn, $cnt, $item) ; |
1602
|
|
|
|
|
|
|
|
1603
|
|
|
|
|
|
|
my($offset) ; |
1604
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname} ; |
1605
|
|
|
|
|
|
|
|
1606
|
|
|
|
|
|
|
$offset = $dbline[1] =~ /use\s+.*Devel::_?tcltkdb/ ? 1 : 0 ; |
1607
|
|
|
|
|
|
|
|
1608
|
|
|
|
|
|
|
while( @brks ) { |
1609
|
|
|
|
|
|
|
my($index, $value, $expression) = splice @brks, 0, 3 ; # take args 3 at a time |
1610
|
|
|
|
|
|
|
|
1611
|
|
|
|
|
|
|
my $brkPt = {} ; |
1612
|
|
|
|
|
|
|
my $txt = &DB::getdbtextline($fname, $index) ; |
1613
|
|
|
|
|
|
|
@$brkPt{'type', 'line', 'expr', 'value', 'fname', 'text'} = |
1614
|
|
|
|
|
|
|
('user', $index, $expression, $value, $fname, "$txt") ; |
1615
|
|
|
|
|
|
|
|
1616
|
|
|
|
|
|
|
&DB::setdbline($fname, $index + $offset, $brkPt) ; |
1617
|
|
|
|
|
|
|
$self->add_brkpt_to_brkpt_page($brkPt) ; |
1618
|
|
|
|
|
|
|
|
1619
|
|
|
|
|
|
|
next unless $fname eq $self->{'current_file'} ; |
1620
|
|
|
|
|
|
|
|
1621
|
|
|
|
|
|
|
$self->{'text'}->tagRemove("breakableLine", "$index.0", "$index.$Devel::tcltkdb::linenumber_length") ; |
1622
|
|
|
|
|
|
|
$self->{'text'}->tagAdd($value ? "breaksetLine" : "breakdisabledLine", "$index.0", "$index.$Devel::tcltkdb::linenumber_length") ; |
1623
|
|
|
|
|
|
|
} # end of loop |
1624
|
|
|
|
|
|
|
} # end of insertBreakpoint |
1625
|
|
|
|
|
|
|
|
1626
|
|
|
|
|
|
|
sub add_brkpt_to_brkpt_page { |
1627
|
|
|
|
|
|
|
my($self, $brkPt) = @_ ; |
1628
|
|
|
|
|
|
|
# |
1629
|
|
|
|
|
|
|
# Add the breakpoint to the breakpoints page |
1630
|
|
|
|
|
|
|
# |
1631
|
|
|
|
|
|
|
my ($fname, $index) = @$brkPt{'fname', 'line'} ; |
1632
|
|
|
|
|
|
|
return if exists $self->{'breakpts_table_data'}->{"$fname:$index"} ; |
1633
|
|
|
|
|
|
|
$self->{'brkPtCnt'} += 1 ; |
1634
|
|
|
|
|
|
|
|
1635
|
|
|
|
|
|
|
my $btnName = $fname ; |
1636
|
|
|
|
|
|
|
$btnName =~ s/.*\/([^\/]*)$/$1/o ; |
1637
|
|
|
|
|
|
|
|
1638
|
|
|
|
|
|
|
# take the last leaf of the pathname |
1639
|
|
|
|
|
|
|
|
1640
|
|
|
|
|
|
|
my $frm = $self->{'breakpts_table'}->getframe; |
1641
|
|
|
|
|
|
|
my $upperFrame = $frm->Frame()->pack(qw/-side top -fill x -expand 1/); |
1642
|
|
|
|
|
|
|
|
1643
|
|
|
|
|
|
|
|
1644
|
|
|
|
|
|
|
my $btn = $upperFrame->Checkbutton(-text => "$btnName:$index", |
1645
|
|
|
|
|
|
|
-variable => \$brkPt->{'value'}, # CAUTION value tracking |
1646
|
|
|
|
|
|
|
-command => sub { $self->brkPtCheckbutton($fname, $index, $brkPt) }) ; |
1647
|
|
|
|
|
|
|
|
1648
|
|
|
|
|
|
|
$btn->pack(-side => 'left') ; |
1649
|
|
|
|
|
|
|
|
1650
|
|
|
|
|
|
|
$btn = $upperFrame->Button(-text => "Delete", -command => sub { $self->removeBreakpoint($fname, $index) ; } ) |
1651
|
|
|
|
|
|
|
->pack(qw/-side left -fill x -expand 1/); |
1652
|
|
|
|
|
|
|
|
1653
|
|
|
|
|
|
|
$btn = $upperFrame->Button(-text => "Goto", -command => sub { $self->set_file($fname, $index) ; } ) |
1654
|
|
|
|
|
|
|
->pack(qw/-side left -fill x -expand 1/); |
1655
|
|
|
|
|
|
|
|
1656
|
|
|
|
|
|
|
my $lowerFrame = $frm->Frame()->pack(-side => 'top', '-fill' => 'x', '-expand' => 1) ; |
1657
|
|
|
|
|
|
|
|
1658
|
|
|
|
|
|
|
$lowerFrame->Label(-text => "Cond:")->pack(-side => 'left') ; |
1659
|
|
|
|
|
|
|
|
1660
|
|
|
|
|
|
|
$btn = $lowerFrame->Entry(-textvariable => \$brkPt->{'expr'}) |
1661
|
|
|
|
|
|
|
->pack(qw/-side left -fill x -expand 1/); |
1662
|
|
|
|
|
|
|
|
1663
|
|
|
|
|
|
|
my $row; |
1664
|
|
|
|
|
|
|
$row = pop @{$self->{'brkPtSlots'}} or $row = $self->{'brkPtCnt'} ; |
1665
|
|
|
|
|
|
|
|
1666
|
|
|
|
|
|
|
$self->{'breakpts_table_data'}->{"$fname:$index"}->{'frm'} = $frm ; |
1667
|
|
|
|
|
|
|
$self->{'breakpts_table_data'}->{"$fname:$index"}->{'row'} = $row ; |
1668
|
|
|
|
|
|
|
|
1669
|
|
|
|
|
|
|
#TODO $self->{'main_window'}->update; |
1670
|
|
|
|
|
|
|
|
1671
|
|
|
|
|
|
|
#TODO my $width = $frm->cget('-width') ;#TODO < Must be widget method |
1672
|
|
|
|
|
|
|
#TODO if ( $width > $self->{'breakpts_table'}->width ) { |
1673
|
|
|
|
|
|
|
#TODO $self->{'notebook'}->configure(-width => $width) ; |
1674
|
|
|
|
|
|
|
#TODO } |
1675
|
|
|
|
|
|
|
|
1676
|
|
|
|
|
|
|
} # end of add_brkpt_to_brkpt_page |
1677
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
sub remove_brkpt_from_brkpt_page { |
1679
|
|
|
|
|
|
|
my($self, $fname, $idx) = @_ ; |
1680
|
|
|
|
|
|
|
|
1681
|
|
|
|
|
|
|
my $table = $self->{'breakpts_table'} ; |
1682
|
|
|
|
|
|
|
|
1683
|
|
|
|
|
|
|
# Delete the breakpoint control in the breakpoints window |
1684
|
|
|
|
|
|
|
|
1685
|
|
|
|
|
|
|
# TODO deleting means ->packForget, with {'row'} etc go away |
1686
|
|
|
|
|
|
|
$table->windowDelete(($self->{'breakpts_table_data'}->{"$fname:$idx"}->{'row'}-1).',0' ) ; # delete? |
1687
|
|
|
|
|
|
|
|
1688
|
|
|
|
|
|
|
# |
1689
|
|
|
|
|
|
|
# Add this now empty slot to the list of ones we have open |
1690
|
|
|
|
|
|
|
# |
1691
|
|
|
|
|
|
|
|
1692
|
|
|
|
|
|
|
push @{$self->{'brkPtSlots'}}, $self->{'breakpts_table_data'}->{"$fname:$idx"}->{'row'} ; |
1693
|
|
|
|
|
|
|
|
1694
|
|
|
|
|
|
|
$self->{'brkPtSlots'} = [ sort { $b <=> $a } @{$self->{'brkPtSlots'}} ] ; |
1695
|
|
|
|
|
|
|
|
1696
|
|
|
|
|
|
|
delete $self->{'breakpts_table_data'}->{"$fname:$idx"} ; |
1697
|
|
|
|
|
|
|
|
1698
|
|
|
|
|
|
|
$self->{'brkPtCnt'} -= 1 ; |
1699
|
|
|
|
|
|
|
|
1700
|
|
|
|
|
|
|
} # end of remove_brkpt_from_brkpt_page |
1701
|
|
|
|
|
|
|
|
1702
|
|
|
|
|
|
|
|
1703
|
|
|
|
|
|
|
# |
1704
|
|
|
|
|
|
|
# Supporting the "Run To Here..." command |
1705
|
|
|
|
|
|
|
# |
1706
|
|
|
|
|
|
|
sub insertTempBreakpoint { |
1707
|
|
|
|
|
|
|
my ($self, $fname, $index) = @_ ; |
1708
|
|
|
|
|
|
|
my($offset) ; |
1709
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname} ; |
1710
|
|
|
|
|
|
|
|
1711
|
|
|
|
|
|
|
$offset = $dbline[1] =~ /use\s+.*Devel::_?tcltkdb/ ? 1 : 0 ; |
1712
|
|
|
|
|
|
|
|
1713
|
|
|
|
|
|
|
return if( &DB::getdbline($fname, $index + $offset) ) ; # we already have a breakpoint here |
1714
|
|
|
|
|
|
|
|
1715
|
|
|
|
|
|
|
&DB::setdbline($fname, $index + $offset, {'type' => 'temp', 'line' => $index, 'value' => 1 } ) ; |
1716
|
|
|
|
|
|
|
|
1717
|
|
|
|
|
|
|
} # end of insertTempBreakpoint |
1718
|
|
|
|
|
|
|
|
1719
|
|
|
|
|
|
|
sub reinsertBreakpoints { |
1720
|
|
|
|
|
|
|
my ($self, $fname) = @_ ; |
1721
|
|
|
|
|
|
|
my ($brkPt) ; |
1722
|
|
|
|
|
|
|
|
1723
|
|
|
|
|
|
|
foreach $brkPt ( &DB::getbreakpoints($fname) ) { |
1724
|
|
|
|
|
|
|
# |
1725
|
|
|
|
|
|
|
# Our breakpoints are indexed by line |
1726
|
|
|
|
|
|
|
# therefore we can have 'gaps' where there |
1727
|
|
|
|
|
|
|
# lines, but not breaks set for them. |
1728
|
|
|
|
|
|
|
# |
1729
|
|
|
|
|
|
|
next unless defined $brkPt ; |
1730
|
|
|
|
|
|
|
|
1731
|
|
|
|
|
|
|
$self->insertBreakpoint($fname, @$brkPt{'line', 'value', 'expr'}) if( $brkPt->{'type'} eq 'user' ) ; |
1732
|
|
|
|
|
|
|
$self->insertTempBreakpoint($fname, $brkPt->{line}) if( $brkPt->{'type'} eq 'temp' ) ; |
1733
|
|
|
|
|
|
|
} # end of reinsert loop |
1734
|
|
|
|
|
|
|
|
1735
|
|
|
|
|
|
|
} # end of reinsertBreakpoints |
1736
|
|
|
|
|
|
|
|
1737
|
|
|
|
|
|
|
sub removeBreakpointTags { |
1738
|
|
|
|
|
|
|
my ($self, @brkPts) = @_ ; |
1739
|
|
|
|
|
|
|
my($idx, $brkPt) ; |
1740
|
|
|
|
|
|
|
|
1741
|
|
|
|
|
|
|
foreach $brkPt (@brkPts) { |
1742
|
|
|
|
|
|
|
|
1743
|
|
|
|
|
|
|
$idx = $brkPt->{'line'} ; |
1744
|
|
|
|
|
|
|
|
1745
|
|
|
|
|
|
|
if ( $brkPt->{'value'} ) { |
1746
|
|
|
|
|
|
|
$self->{'text'}->tagRemove("breaksetLine", "$idx.0", "$idx.$Devel::tcltkdb::linenumber_length") ; |
1747
|
|
|
|
|
|
|
} |
1748
|
|
|
|
|
|
|
else { |
1749
|
|
|
|
|
|
|
$self->{'text'}->tagRemove("breakdisabledLine", "$idx.0", "$idx.$Devel::tcltkdb::linenumber_length") ; |
1750
|
|
|
|
|
|
|
} |
1751
|
|
|
|
|
|
|
|
1752
|
|
|
|
|
|
|
$self->{'text'}->tagAdd("breakableLine", "$idx.0", "$idx.$Devel::tcltkdb::linenumber_length") ; |
1753
|
|
|
|
|
|
|
} |
1754
|
|
|
|
|
|
|
} # end of removeBreakpointTags |
1755
|
|
|
|
|
|
|
|
1756
|
|
|
|
|
|
|
# |
1757
|
|
|
|
|
|
|
# Remove a breakpoint from the current window |
1758
|
|
|
|
|
|
|
# |
1759
|
|
|
|
|
|
|
sub removeBreakpoint { |
1760
|
|
|
|
|
|
|
my ($self, $fname, @idx) = @_ ; |
1761
|
|
|
|
|
|
|
my ($idx, $chkIdx, $i, $j, $info) ; |
1762
|
|
|
|
|
|
|
my($offset) ; |
1763
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname} ; |
1764
|
|
|
|
|
|
|
|
1765
|
|
|
|
|
|
|
$offset = $dbline[1] =~ /use\s+.*Devel::_?tcltkdb/ ? 1 : 0 ; |
1766
|
|
|
|
|
|
|
|
1767
|
|
|
|
|
|
|
foreach $idx (@idx) { # end of removal loop |
1768
|
|
|
|
|
|
|
next unless defined $idx ; |
1769
|
|
|
|
|
|
|
my $brkPt = &DB::getdbline($fname, $idx + $offset) ; |
1770
|
|
|
|
|
|
|
next unless $brkPt ; # if we do not have an entry |
1771
|
|
|
|
|
|
|
&DB::cleardbline($fname, $idx + $offset) ; |
1772
|
|
|
|
|
|
|
|
1773
|
|
|
|
|
|
|
$self->remove_brkpt_from_brkpt_page($fname, $idx) ; |
1774
|
|
|
|
|
|
|
|
1775
|
|
|
|
|
|
|
next unless $brkPt->{fname} eq $self->{'current_file'} ; # if this isn't our current file there will be no controls |
1776
|
|
|
|
|
|
|
|
1777
|
|
|
|
|
|
|
# Delete the ext associated with the breakpoint expression (if any) |
1778
|
|
|
|
|
|
|
|
1779
|
|
|
|
|
|
|
$self->removeBreakpointTags($brkPt) ; |
1780
|
|
|
|
|
|
|
} # end of remove loop |
1781
|
|
|
|
|
|
|
|
1782
|
|
|
|
|
|
|
return ; |
1783
|
|
|
|
|
|
|
} # end of removeBreakpoint |
1784
|
|
|
|
|
|
|
|
1785
|
|
|
|
|
|
|
sub removeAllBreakpoints { |
1786
|
|
|
|
|
|
|
my ($self, $fname) = @_ ; |
1787
|
|
|
|
|
|
|
|
1788
|
|
|
|
|
|
|
$self->removeBreakpoint($fname, &DB::getdblineindexes($fname)) ; |
1789
|
|
|
|
|
|
|
|
1790
|
|
|
|
|
|
|
} # end of removeAllBreakpoints |
1791
|
|
|
|
|
|
|
|
1792
|
|
|
|
|
|
|
# |
1793
|
|
|
|
|
|
|
# Delete expressions prior to an update |
1794
|
|
|
|
|
|
|
# |
1795
|
|
|
|
|
|
|
sub deleteAllExprs { |
1796
|
|
|
|
|
|
|
my ($self) = @_ ; |
1797
|
|
|
|
|
|
|
my @c = $self->{data_list0}->[0]->itemChildrenRoot =~ /(\d+)/g; |
1798
|
|
|
|
|
|
|
print STDERR "{{{@c;$#c}}}"; |
1799
|
|
|
|
|
|
|
$self->{data_list0}->[0]->itemDelete($_) for @c; |
1800
|
|
|
|
|
|
|
} # end of deleteAllExprs |
1801
|
|
|
|
|
|
|
|
1802
|
|
|
|
|
|
|
sub EnterExpr { |
1803
|
|
|
|
|
|
|
my ($self) = @_ ; |
1804
|
|
|
|
|
|
|
my $str = $self->clear_entry_text() ; |
1805
|
|
|
|
|
|
|
if( $str && $str !~ /^\s*$/ ) { # if there is an expression and it's more than white space |
1806
|
|
|
|
|
|
|
$self->{'expr'} = $str ; |
1807
|
|
|
|
|
|
|
$self->{'event'} = 'expr' ; |
1808
|
|
|
|
|
|
|
} |
1809
|
|
|
|
|
|
|
} # end of EnterExpr |
1810
|
|
|
|
|
|
|
|
1811
|
|
|
|
|
|
|
# |
1812
|
|
|
|
|
|
|
# |
1813
|
|
|
|
|
|
|
sub QuickExpr { |
1814
|
|
|
|
|
|
|
my ($self) = @_ ; |
1815
|
|
|
|
|
|
|
|
1816
|
|
|
|
|
|
|
my $str = $self->{'quick_entry'}->get() ; |
1817
|
|
|
|
|
|
|
|
1818
|
|
|
|
|
|
|
if( $str && $str !~ /^\s*$/ ) { # if there is an expression and it's more than white space |
1819
|
|
|
|
|
|
|
$self->{'qexpr'} = $str ; |
1820
|
|
|
|
|
|
|
$self->{'event'} = 'qexpr' ; |
1821
|
|
|
|
|
|
|
} |
1822
|
|
|
|
|
|
|
} # end of QuickExpr |
1823
|
|
|
|
|
|
|
|
1824
|
|
|
|
|
|
|
sub deleteExpr { |
1825
|
|
|
|
|
|
|
my ($self) = @_ ; |
1826
|
|
|
|
|
|
|
my ($entry, @indexes) ; |
1827
|
|
|
|
|
|
|
my @sList = $self->{'data_list'}->info('select'); # TBD TODO TBD |
1828
|
|
|
|
|
|
|
my @sList0 = $self->{data_list0}->[0]->selectionGet; |
1829
|
|
|
|
|
|
|
|
1830
|
|
|
|
|
|
|
# |
1831
|
|
|
|
|
|
|
# if we're deleteing a top level expression |
1832
|
|
|
|
|
|
|
# we have to take it out of the list of expressions |
1833
|
|
|
|
|
|
|
# |
1834
|
|
|
|
|
|
|
|
1835
|
|
|
|
|
|
|
foreach $entry ( @sList ) { |
1836
|
|
|
|
|
|
|
next if ($entry =~ /\//) ; # goto next expression if we're not a top level ( expr/entry) |
1837
|
|
|
|
|
|
|
my $i = 0 ; |
1838
|
|
|
|
|
|
|
grep { push @indexes, $i if ($_->{'expr'} eq $entry) ; $i++ ; } @{$self->{'expr_list'}} ; |
1839
|
|
|
|
|
|
|
} # end of check loop |
1840
|
|
|
|
|
|
|
|
1841
|
|
|
|
|
|
|
# now take out our list of indexes ; |
1842
|
|
|
|
|
|
|
|
1843
|
|
|
|
|
|
|
for (0..$#indexes) { |
1844
|
|
|
|
|
|
|
splice @{$self->{'expr_list'}}, $indexes[$_] - $_, 1 ; |
1845
|
|
|
|
|
|
|
} |
1846
|
|
|
|
|
|
|
|
1847
|
|
|
|
|
|
|
for( @sList ) { |
1848
|
|
|
|
|
|
|
$self->{'data_list'}->delete('entry', $_) ; |
1849
|
|
|
|
|
|
|
} |
1850
|
|
|
|
|
|
|
} # end of deleteExpr |
1851
|
|
|
|
|
|
|
|
1852
|
|
|
|
|
|
|
## |
1853
|
|
|
|
|
|
|
## Inserts an expression($theRef) into tk widget. If the expression |
1854
|
|
|
|
|
|
|
## is an array, blessed array, hash, or blessed hash(typical object), then this |
1855
|
|
|
|
|
|
|
## routine is called recursively, adding the members to the next level of heirarchy, |
1856
|
|
|
|
|
|
|
## prefixing array members with a [idx] and the hash members with the key name. |
1857
|
|
|
|
|
|
|
## This continues until the entire expression is decomposed to it's atomic constituents. |
1858
|
|
|
|
|
|
|
## Protection is given(with $reusedRefs) to ensure that 'circular' references within |
1859
|
|
|
|
|
|
|
## arrays or hashes(i.e. where a member of a array or hash contains a reference to a |
1860
|
|
|
|
|
|
|
## parent element within the heirarchy. |
1861
|
|
|
|
|
|
|
## |
1862
|
|
|
|
|
|
|
# |
1863
|
|
|
|
|
|
|
# Returns 1 if sucessfully added 0 if not |
1864
|
|
|
|
|
|
|
# |
1865
|
|
|
|
|
|
|
sub insertExpr { |
1866
|
|
|
|
|
|
|
my($self, $reusedRefs, $theRef, $name, $depth, $el) = @_ ; |
1867
|
|
|
|
|
|
|
my($type, $result, @circRefs, $t) ; |
1868
|
|
|
|
|
|
|
local($^W) = 0 ; # spare us uncessary warnings about comparing strings with == |
1869
|
|
|
|
|
|
|
my ($tv, $tcol) = @{$self->{data_list0}}; |
1870
|
|
|
|
|
|
|
|
1871
|
|
|
|
|
|
|
while( ref $theRef eq 'SCALAR' ) { |
1872
|
|
|
|
|
|
|
$theRef = $$theRef ; |
1873
|
|
|
|
|
|
|
} |
1874
|
|
|
|
|
|
|
|
1875
|
|
|
|
|
|
|
my $label = "" ; |
1876
|
|
|
|
|
|
|
REF_CHECK: for( ; ; ) { |
1877
|
|
|
|
|
|
|
push @circRefs, $theRef ; |
1878
|
|
|
|
|
|
|
$type = ref $theRef ; |
1879
|
|
|
|
|
|
|
last unless ($type eq "REF") ; |
1880
|
|
|
|
|
|
|
$theRef = $$theRef ; # dref again |
1881
|
|
|
|
|
|
|
|
1882
|
|
|
|
|
|
|
$label .= "\\" ; # append a |
1883
|
|
|
|
|
|
|
if( grep $_ == $theRef, @circRefs ) { |
1884
|
|
|
|
|
|
|
$label .= "(circular)" ; |
1885
|
|
|
|
|
|
|
last ; |
1886
|
|
|
|
|
|
|
} |
1887
|
|
|
|
|
|
|
} |
1888
|
|
|
|
|
|
|
|
1889
|
|
|
|
|
|
|
if( !$type || $type eq "" || $type eq "GLOB" || $type eq "CODE") { |
1890
|
|
|
|
|
|
|
eval { |
1891
|
|
|
|
|
|
|
$t = "$name = $label" . (defined $theRef?$theRef:"undef"); |
1892
|
|
|
|
|
|
|
$el = $tv->itemCreate(-button=>'yes',-parent=>$el); |
1893
|
|
|
|
|
|
|
$tv->itemElementConfigure($el, $tcol, 'foo', -text=>"$t"); |
1894
|
|
|
|
|
|
|
}; |
1895
|
|
|
|
|
|
|
$self->DoAlert($@), return 0 if $@ ; |
1896
|
|
|
|
|
|
|
return 1 ; |
1897
|
|
|
|
|
|
|
} |
1898
|
|
|
|
|
|
|
|
1899
|
|
|
|
|
|
|
if( $type eq 'ARRAY' or "$theRef" =~ /ARRAY/ ) { |
1900
|
|
|
|
|
|
|
my $idx = 0 ; |
1901
|
|
|
|
|
|
|
eval { |
1902
|
|
|
|
|
|
|
$el = $tv->itemCreate(-button=>'yes',-parent=>$el); |
1903
|
|
|
|
|
|
|
$tv->itemElementConfigure($el, $tcol, 'foo', -text=>"$name = $theRef"); |
1904
|
|
|
|
|
|
|
} ; |
1905
|
|
|
|
|
|
|
if( $@ ) { |
1906
|
|
|
|
|
|
|
$self->DoAlert($@) ; |
1907
|
|
|
|
|
|
|
return 0 ; |
1908
|
|
|
|
|
|
|
} |
1909
|
|
|
|
|
|
|
$result = 1 ; |
1910
|
|
|
|
|
|
|
for my $r ( @$theRef ) { |
1911
|
|
|
|
|
|
|
|
1912
|
|
|
|
|
|
|
if( grep $_ == $r, @$reusedRefs ) { # check to make sure that we're not doing a single level self reference |
1913
|
|
|
|
|
|
|
eval { |
1914
|
|
|
|
|
|
|
$el = $tv->itemCreate(-button=>'yes',-parent=>$el); |
1915
|
|
|
|
|
|
|
$tv->itemElementConfigure($el, $tcol, 'foo', -text=>"[$idx] = $r REUSED ADDR"); |
1916
|
|
|
|
|
|
|
} ; |
1917
|
|
|
|
|
|
|
$self->DoAlert($@) if( $@ ) ; |
1918
|
|
|
|
|
|
|
next ; |
1919
|
|
|
|
|
|
|
} |
1920
|
|
|
|
|
|
|
|
1921
|
|
|
|
|
|
|
push @$reusedRefs, $r ; |
1922
|
|
|
|
|
|
|
$result = $self->insertExpr($reusedRefs, $r, "[$idx]", $depth-1, $el) unless $depth == 0 ; |
1923
|
|
|
|
|
|
|
pop @$reusedRefs ; |
1924
|
|
|
|
|
|
|
|
1925
|
|
|
|
|
|
|
return 0 unless $result ; |
1926
|
|
|
|
|
|
|
$idx += 1 ; |
1927
|
|
|
|
|
|
|
} |
1928
|
|
|
|
|
|
|
return 1 ; |
1929
|
|
|
|
|
|
|
} # end of array case |
1930
|
|
|
|
|
|
|
|
1931
|
|
|
|
|
|
|
if ("$theRef" !~ /HASH\050\060x[\da-f]*\051/) { |
1932
|
|
|
|
|
|
|
eval { |
1933
|
|
|
|
|
|
|
$el = $tv->itemCreate(-button=>'yes',-parent=>$el); |
1934
|
|
|
|
|
|
|
$tv->itemElementConfigure($el, $tcol, 'foo', -text=>"$name = $theRef"); |
1935
|
|
|
|
|
|
|
}; |
1936
|
|
|
|
|
|
|
if( $@ ) { |
1937
|
|
|
|
|
|
|
$self->DoAlert($@) ; |
1938
|
|
|
|
|
|
|
return 0 ; |
1939
|
|
|
|
|
|
|
} |
1940
|
|
|
|
|
|
|
return 1 ; |
1941
|
|
|
|
|
|
|
} |
1942
|
|
|
|
|
|
|
# |
1943
|
|
|
|
|
|
|
# Anything else at this point is |
1944
|
|
|
|
|
|
|
# either a 'HASH' or an object |
1945
|
|
|
|
|
|
|
# of some kind. |
1946
|
|
|
|
|
|
|
# |
1947
|
|
|
|
|
|
|
my $idx = 0 ; |
1948
|
|
|
|
|
|
|
my @theKeys = sort keys %$theRef; |
1949
|
|
|
|
|
|
|
$el = $tv->itemCreate(-parent=>$el); |
1950
|
|
|
|
|
|
|
$tv->itemElementConfigure($el, $tcol, 'foo', -text=>"$name = " . "$theRef"); |
1951
|
|
|
|
|
|
|
$result = 1 ; |
1952
|
|
|
|
|
|
|
|
1953
|
|
|
|
|
|
|
for my $r ( @$theRef{@theKeys} ) { # slice out the values with the sorted list |
1954
|
|
|
|
|
|
|
|
1955
|
|
|
|
|
|
|
if( grep $_ == $r, @$reusedRefs ) { # check to make sure that we're not doing a single level self reference |
1956
|
|
|
|
|
|
|
eval { |
1957
|
|
|
|
|
|
|
$el = $tv->itemCreate(-parent=>$el); |
1958
|
|
|
|
|
|
|
$tv->itemElementConfigure($el, $tcol, 'foo', -text=>"$theKeys[$idx++] = $r REUSED ADDR"); |
1959
|
|
|
|
|
|
|
} ; |
1960
|
|
|
|
|
|
|
print "bad path $@\n" if( $@ ) ; |
1961
|
|
|
|
|
|
|
next ; |
1962
|
|
|
|
|
|
|
} |
1963
|
|
|
|
|
|
|
|
1964
|
|
|
|
|
|
|
push @$reusedRefs, $r; |
1965
|
|
|
|
|
|
|
|
1966
|
|
|
|
|
|
|
$result = $self->insertExpr($reusedRefs, # recursion protection |
1967
|
|
|
|
|
|
|
$r, # reference whose value is displayed |
1968
|
|
|
|
|
|
|
$theKeys[$idx], # name |
1969
|
|
|
|
|
|
|
$depth-1, # remaining expansion depth |
1970
|
|
|
|
|
|
|
$el) |
1971
|
|
|
|
|
|
|
unless $depth == 0 ; |
1972
|
|
|
|
|
|
|
|
1973
|
|
|
|
|
|
|
pop @$reusedRefs ; |
1974
|
|
|
|
|
|
|
|
1975
|
|
|
|
|
|
|
return 0 unless $result ; |
1976
|
|
|
|
|
|
|
$idx += 1 ; |
1977
|
|
|
|
|
|
|
} # end of ref add loop |
1978
|
|
|
|
|
|
|
|
1979
|
|
|
|
|
|
|
return 1 ; |
1980
|
|
|
|
|
|
|
} # end of insertExpr |
1981
|
|
|
|
|
|
|
|
1982
|
|
|
|
|
|
|
# |
1983
|
|
|
|
|
|
|
# We're setting the line where we are stopped. |
1984
|
|
|
|
|
|
|
# Create a tag for this and set it as bold. |
1985
|
|
|
|
|
|
|
# |
1986
|
|
|
|
|
|
|
sub set_line { |
1987
|
|
|
|
|
|
|
my ($self, $lineno) = @_ ; |
1988
|
|
|
|
|
|
|
my $text = $self->{'text'} ; |
1989
|
|
|
|
|
|
|
|
1990
|
|
|
|
|
|
|
return if( $lineno <= 0 ) ; |
1991
|
|
|
|
|
|
|
|
1992
|
|
|
|
|
|
|
if( $self->{current_line} > 0 ) { |
1993
|
|
|
|
|
|
|
$text->tagRemove('stoppt', "$self->{current_line}.0 linestart", "$self->{current_line}.0 lineend") ; |
1994
|
|
|
|
|
|
|
} |
1995
|
|
|
|
|
|
|
$self->{current_line} = $lineno - $self->{'line_offset'} ; |
1996
|
|
|
|
|
|
|
$text->tagAdd('stoppt', "$self->{current_line}.0 linestart", "$self->{current_line}.0 lineend") ; |
1997
|
|
|
|
|
|
|
|
1998
|
|
|
|
|
|
|
$self->{'text'}->see("$self->{current_line}.0 linestart") ; |
1999
|
|
|
|
|
|
|
} # end of set_line |
2000
|
|
|
|
|
|
|
|
2001
|
|
|
|
|
|
|
# |
2002
|
|
|
|
|
|
|
# Set the file that is in the code window. |
2003
|
|
|
|
|
|
|
# |
2004
|
|
|
|
|
|
|
# $fname the 'new' file to view |
2005
|
|
|
|
|
|
|
# $line the line number we're at |
2006
|
|
|
|
|
|
|
# $brkPts any breakpoints that may have been set in this file |
2007
|
|
|
|
|
|
|
# |
2008
|
|
|
|
|
|
|
|
2009
|
|
|
|
|
|
|
sub set_file { |
2010
|
|
|
|
|
|
|
my ($self, $fname, $line) = @_ ; |
2011
|
|
|
|
|
|
|
my ($lineStr, $offset, $text, @text); |
2012
|
|
|
|
|
|
|
|
2013
|
|
|
|
|
|
|
return unless $fname ; # we're getting an undef here on 'Restart...' |
2014
|
|
|
|
|
|
|
|
2015
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname}; |
2016
|
|
|
|
|
|
|
|
2017
|
|
|
|
|
|
|
# |
2018
|
|
|
|
|
|
|
# with the #! /usr/bin/perl -d:tcltkdb at the header of the file |
2019
|
|
|
|
|
|
|
# we've found that with various combinations of other options the |
2020
|
|
|
|
|
|
|
# files haven't come in at the right offsets |
2021
|
|
|
|
|
|
|
# |
2022
|
|
|
|
|
|
|
$offset = 0 ; |
2023
|
|
|
|
|
|
|
$offset = 1 if $dbline[1] =~ /use\s+.*Devel::_?tcltkdb/ ; |
2024
|
|
|
|
|
|
|
$self->{'line_offset'} = $offset ; |
2025
|
|
|
|
|
|
|
|
2026
|
|
|
|
|
|
|
$text = $self->{'text'} ; |
2027
|
|
|
|
|
|
|
|
2028
|
|
|
|
|
|
|
if( $fname eq $self->{current_file} ) { |
2029
|
|
|
|
|
|
|
$self->set_line($line) ; |
2030
|
|
|
|
|
|
|
return ; |
2031
|
|
|
|
|
|
|
} ; |
2032
|
|
|
|
|
|
|
|
2033
|
|
|
|
|
|
|
$self->{main_window}->configure('-title' => $fname) ; |
2034
|
|
|
|
|
|
|
|
2035
|
|
|
|
|
|
|
# Erase any existing text |
2036
|
|
|
|
|
|
|
$text->delete('1.0','end'); |
2037
|
|
|
|
|
|
|
|
2038
|
|
|
|
|
|
|
# |
2039
|
|
|
|
|
|
|
# This is the tightest loop we have in the ptkdb code. |
2040
|
|
|
|
|
|
|
# It is here where performance is the most critical. |
2041
|
|
|
|
|
|
|
# The map block formats perl code for display. Since |
2042
|
|
|
|
|
|
|
# the file could be potentially large, we will try |
2043
|
|
|
|
|
|
|
# to make this loop as thin as possible. |
2044
|
|
|
|
|
|
|
# |
2045
|
|
|
|
|
|
|
|
2046
|
|
|
|
|
|
|
local($^W) = 0 ; # spares us useless warnings under -w when checking $dbline[$_] != 0 |
2047
|
|
|
|
|
|
|
|
2048
|
|
|
|
|
|
|
my $noCode = ($#dbline - ($offset + 1)) < 0 ; |
2049
|
|
|
|
|
|
|
|
2050
|
|
|
|
|
|
|
my $i0 = "0" x $Devel::tcltkdb::linenumber_length; |
2051
|
|
|
|
|
|
|
$text->_insertEnd(map { |
2052
|
|
|
|
|
|
|
#$lineStr .= "\n" unless /\n$/; # append a \n if there isn't one already |
2053
|
|
|
|
|
|
|
($i0++, ($_==0?'nonbreakableLine':'breakableLine'), " $_", 'code') # a string,tag pair for text insert |
2054
|
|
|
|
|
|
|
|
2055
|
|
|
|
|
|
|
} @dbline[$offset+1 .. $#dbline] ) unless $noCode; |
2056
|
|
|
|
|
|
|
|
2057
|
|
|
|
|
|
|
# |
2058
|
|
|
|
|
|
|
# Reinsert breakpoints (if info provided) |
2059
|
|
|
|
|
|
|
# |
2060
|
|
|
|
|
|
|
|
2061
|
|
|
|
|
|
|
$self->set_line($line); |
2062
|
|
|
|
|
|
|
$self->{current_file} = $fname; |
2063
|
|
|
|
|
|
|
return $self->reinsertBreakpoints($fname); |
2064
|
|
|
|
|
|
|
} # end of set_file |
2065
|
|
|
|
|
|
|
|
2066
|
|
|
|
|
|
|
# |
2067
|
|
|
|
|
|
|
# Get the current line that the insert cursor is in |
2068
|
|
|
|
|
|
|
# |
2069
|
|
|
|
|
|
|
sub get_lineno { |
2070
|
|
|
|
|
|
|
my ($self) = @_ ; |
2071
|
|
|
|
|
|
|
|
2072
|
|
|
|
|
|
|
my $info = $self->{'text'}->index('insert'); # get the location for the insertion point |
2073
|
|
|
|
|
|
|
$info =~ s/\..*$/\.0/ ; |
2074
|
|
|
|
|
|
|
|
2075
|
|
|
|
|
|
|
return int $info ; |
2076
|
|
|
|
|
|
|
} # end of get_lineno |
2077
|
|
|
|
|
|
|
|
2078
|
|
|
|
|
|
|
sub DoGoto { |
2079
|
|
|
|
|
|
|
my ($self, $entry) = @_ ; |
2080
|
|
|
|
|
|
|
|
2081
|
|
|
|
|
|
|
my $txt = $entry->get() ; |
2082
|
|
|
|
|
|
|
|
2083
|
|
|
|
|
|
|
$txt =~ s/(\d*).*/$1/; # take the first blob of digits |
2084
|
|
|
|
|
|
|
if( $txt eq "" ) { |
2085
|
|
|
|
|
|
|
print "invalid text range\n"; |
2086
|
|
|
|
|
|
|
return; |
2087
|
|
|
|
|
|
|
} |
2088
|
|
|
|
|
|
|
|
2089
|
|
|
|
|
|
|
$self->{'text'}->see("$txt.0") ; |
2090
|
|
|
|
|
|
|
|
2091
|
|
|
|
|
|
|
$entry->_selectionRange(0, 'end'); |
2092
|
|
|
|
|
|
|
} # end of DoGoto |
2093
|
|
|
|
|
|
|
|
2094
|
|
|
|
|
|
|
sub GotoLine { |
2095
|
|
|
|
|
|
|
my ($self) = @_ ; |
2096
|
|
|
|
|
|
|
|
2097
|
|
|
|
|
|
|
if( $self->{goto_window} ) { |
2098
|
|
|
|
|
|
|
$self->{goto_window}->raise() ; |
2099
|
|
|
|
|
|
|
$self->{goto_text}->focus() ; |
2100
|
|
|
|
|
|
|
return ; |
2101
|
|
|
|
|
|
|
} |
2102
|
|
|
|
|
|
|
|
2103
|
|
|
|
|
|
|
# |
2104
|
|
|
|
|
|
|
# Construct a dialog that has an |
2105
|
|
|
|
|
|
|
# entry field, okay and cancel buttons |
2106
|
|
|
|
|
|
|
# |
2107
|
|
|
|
|
|
|
my $okaySub = sub { $self->DoGoto($self->{'goto_text'}) } ; |
2108
|
|
|
|
|
|
|
|
2109
|
|
|
|
|
|
|
my $topLevel = $self->{main_window}->Toplevel(-title => "Goto Line?", -overanchor => 'cursor') ; |
2110
|
|
|
|
|
|
|
|
2111
|
|
|
|
|
|
|
$self->{goto_text} = $topLevel->Entry()->pack(-side => 'top', -fill => 'both', -expand => 1) ; |
2112
|
|
|
|
|
|
|
$self->{goto_text}->bind('', $okaySub) ; # make a CR do the same thing as pressing an okay |
2113
|
|
|
|
|
|
|
$self->{goto_text}->focus(); |
2114
|
|
|
|
|
|
|
|
2115
|
|
|
|
|
|
|
$topLevel->Button( -text => "Okay", -command => $okaySub, @Devel::tcltkdb::button_font, |
2116
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
2117
|
|
|
|
|
|
|
|
2118
|
|
|
|
|
|
|
# |
2119
|
|
|
|
|
|
|
# Subroutone called when the 'Dismiss' button is pushed. |
2120
|
|
|
|
|
|
|
my $dismissSub = sub { |
2121
|
|
|
|
|
|
|
delete $self->{goto_text} ; |
2122
|
|
|
|
|
|
|
$self->{goto_window}->destroy; |
2123
|
|
|
|
|
|
|
delete $self->{goto_window} ; # remove the entry from our hash so we won't |
2124
|
|
|
|
|
|
|
} ; |
2125
|
|
|
|
|
|
|
|
2126
|
|
|
|
|
|
|
$topLevel->Button( -text => "Dismiss", @Devel::tcltkdb::button_font, |
2127
|
|
|
|
|
|
|
-command => $dismissSub )->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
2128
|
|
|
|
|
|
|
|
2129
|
|
|
|
|
|
|
$topLevel->protocol('WM_DELETE_WINDOW', sub { $topLevel->destroy; } ) ; |
2130
|
|
|
|
|
|
|
$self->{goto_window} = $topLevel; |
2131
|
|
|
|
|
|
|
|
2132
|
|
|
|
|
|
|
} # end of GotoLine |
2133
|
|
|
|
|
|
|
|
2134
|
|
|
|
|
|
|
|
2135
|
|
|
|
|
|
|
# |
2136
|
|
|
|
|
|
|
# Subroutine called when the 'okay' button is pressed |
2137
|
|
|
|
|
|
|
# |
2138
|
|
|
|
|
|
|
sub FindSearch { |
2139
|
|
|
|
|
|
|
my ($self, $entry, $btn, $regExp) = @_ ; |
2140
|
|
|
|
|
|
|
my (@switches, $result) ; |
2141
|
|
|
|
|
|
|
my $txt = $entry->get() ; |
2142
|
|
|
|
|
|
|
|
2143
|
|
|
|
|
|
|
return if $txt eq "" ; |
2144
|
|
|
|
|
|
|
|
2145
|
|
|
|
|
|
|
push @switches, "-forward" if $self->{fwdOrBack} eq "forward" ; |
2146
|
|
|
|
|
|
|
push @switches, "-backward" if $self->{fwdOrBack} eq "backward" ; |
2147
|
|
|
|
|
|
|
|
2148
|
|
|
|
|
|
|
if( $regExp ) { |
2149
|
|
|
|
|
|
|
push @switches, "-regexp" ; |
2150
|
|
|
|
|
|
|
} |
2151
|
|
|
|
|
|
|
else { |
2152
|
|
|
|
|
|
|
push @switches, "-nocase" ; # if we're not doing regex we may as well do caseless search |
2153
|
|
|
|
|
|
|
} |
2154
|
|
|
|
|
|
|
|
2155
|
|
|
|
|
|
|
$result = $self->{'text'}->search(@switches, $txt, $self->{search_start}) ; |
2156
|
|
|
|
|
|
|
|
2157
|
|
|
|
|
|
|
# untag the previously found text |
2158
|
|
|
|
|
|
|
|
2159
|
|
|
|
|
|
|
$self->{'text'}->tagRemove('search_tag', @{$self->{search_tag}}) if defined $self->{search_tag} ; |
2160
|
|
|
|
|
|
|
|
2161
|
|
|
|
|
|
|
if( !$result || $result eq "" ) { |
2162
|
|
|
|
|
|
|
# No Text was found |
2163
|
|
|
|
|
|
|
$btn->flash() ; |
2164
|
|
|
|
|
|
|
$btn->bell() ; |
2165
|
|
|
|
|
|
|
|
2166
|
|
|
|
|
|
|
delete $self->{search_tag} ; |
2167
|
|
|
|
|
|
|
$self->{'search_start'} = "0.0" ; |
2168
|
|
|
|
|
|
|
} |
2169
|
|
|
|
|
|
|
else { # text found |
2170
|
|
|
|
|
|
|
$self->{'text'}->see($result) ; |
2171
|
|
|
|
|
|
|
# set the insertion of the text as well |
2172
|
|
|
|
|
|
|
$self->{'text'}->markSet('insert' => $result) ; |
2173
|
|
|
|
|
|
|
my $len = length $txt; |
2174
|
|
|
|
|
|
|
|
2175
|
|
|
|
|
|
|
if( $self->{fwdOrBack} ) { |
2176
|
|
|
|
|
|
|
$self->{search_start} = "$result +$len chars" ; |
2177
|
|
|
|
|
|
|
$self->{search_tag} = [ $result, $self->{search_start} ] ; |
2178
|
|
|
|
|
|
|
} |
2179
|
|
|
|
|
|
|
else { |
2180
|
|
|
|
|
|
|
# backwards search |
2181
|
|
|
|
|
|
|
$self->{search_start} = "$result -$len chars" ; |
2182
|
|
|
|
|
|
|
$self->{search_tag} = [ $result, "$result +$len chars" ] ; |
2183
|
|
|
|
|
|
|
} |
2184
|
|
|
|
|
|
|
|
2185
|
|
|
|
|
|
|
# tag the newly found text |
2186
|
|
|
|
|
|
|
|
2187
|
|
|
|
|
|
|
$self->{'text'}->tagAdd('search_tag', @{$self->{search_tag}}) ; |
2188
|
|
|
|
|
|
|
} # end of text found |
2189
|
|
|
|
|
|
|
|
2190
|
|
|
|
|
|
|
$entry->_selectionRange(0, 'end'); |
2191
|
|
|
|
|
|
|
|
2192
|
|
|
|
|
|
|
} # end of FindSearch |
2193
|
|
|
|
|
|
|
|
2194
|
|
|
|
|
|
|
|
2195
|
|
|
|
|
|
|
# |
2196
|
|
|
|
|
|
|
# Support for the Find Text... Menu command |
2197
|
|
|
|
|
|
|
# |
2198
|
|
|
|
|
|
|
sub FindText { |
2199
|
|
|
|
|
|
|
my ($self) = @_ ; |
2200
|
|
|
|
|
|
|
my ($okayBtn); |
2201
|
|
|
|
|
|
|
|
2202
|
|
|
|
|
|
|
# |
2203
|
|
|
|
|
|
|
# if we already have the Find Text Window open don't bother openning |
2204
|
|
|
|
|
|
|
# another, bring the existing one to the front. |
2205
|
|
|
|
|
|
|
if( $self->{find_window} ) { |
2206
|
|
|
|
|
|
|
$self->{find_window}->raise(); |
2207
|
|
|
|
|
|
|
return; |
2208
|
|
|
|
|
|
|
} |
2209
|
|
|
|
|
|
|
|
2210
|
|
|
|
|
|
|
$self->{search_start} = $self->{'text'}->index('insert') if( $self->{search_start} eq "" ) ; |
2211
|
|
|
|
|
|
|
|
2212
|
|
|
|
|
|
|
# |
2213
|
|
|
|
|
|
|
# Subroutine called when the 'Dismiss' button is pushed. |
2214
|
|
|
|
|
|
|
my $dismissSub = sub { |
2215
|
|
|
|
|
|
|
$self->{'text'}->tagRemove('search_tag', @{$self->{search_tag}}) if defined $self->{search_tag} ; |
2216
|
|
|
|
|
|
|
$self->{search_start} = "" ; |
2217
|
|
|
|
|
|
|
$self->{find_window}->destroy; |
2218
|
|
|
|
|
|
|
delete $self->{search_tag} ; |
2219
|
|
|
|
|
|
|
delete $self->{find_window} ; |
2220
|
|
|
|
|
|
|
}; |
2221
|
|
|
|
|
|
|
|
2222
|
|
|
|
|
|
|
# |
2223
|
|
|
|
|
|
|
# Construct a dialog that has an entry field, forward, backward, regex option, okay and cancel buttons |
2224
|
|
|
|
|
|
|
# |
2225
|
|
|
|
|
|
|
my $top = $self->{main_window}->Toplevel(-title => "Find Text?"); |
2226
|
|
|
|
|
|
|
|
2227
|
|
|
|
|
|
|
my $we = $top->Entry()->pack(qw/-side top -fill both -expand 1/); |
2228
|
|
|
|
|
|
|
|
2229
|
|
|
|
|
|
|
my $frm = $top->Frame()->pack(qw/-side top -fill both -expand 1/); |
2230
|
|
|
|
|
|
|
|
2231
|
|
|
|
|
|
|
$self->{fwdOrBack} = 'forward'; |
2232
|
|
|
|
|
|
|
$frm->Radiobutton(-text => "Forward", -value => 1, -variable => \$self->{fwdOrBack}) |
2233
|
|
|
|
|
|
|
->pack(-side => 'left', -fill => 'both', -expand => 1); |
2234
|
|
|
|
|
|
|
$frm->Radiobutton(-text => "Backward", -value => 0, -variable => \$self->{fwdOrBack}) |
2235
|
|
|
|
|
|
|
->pack(-side => 'left', -fill => 'both', -expand => 1); |
2236
|
|
|
|
|
|
|
|
2237
|
|
|
|
|
|
|
my $regExp = 0 ; |
2238
|
|
|
|
|
|
|
$frm->Checkbutton(-text => "RegExp", -variable => \$regExp) |
2239
|
|
|
|
|
|
|
->pack(-side => 'left', -fill => 'both', -expand => 1); |
2240
|
|
|
|
|
|
|
|
2241
|
|
|
|
|
|
|
# Okay and dismiss buttons |
2242
|
|
|
|
|
|
|
$okayBtn = $top->Button( -text => "Okay", -command => sub { $self->FindSearch($we, $okayBtn, $regExp) ; }, |
2243
|
|
|
|
|
|
|
@Devel::tcltkdb::button_font, |
2244
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
2245
|
|
|
|
|
|
|
|
2246
|
|
|
|
|
|
|
$we->bind('', sub { $self->FindSearch($we, $okayBtn, $regExp) ; }) ; |
2247
|
|
|
|
|
|
|
|
2248
|
|
|
|
|
|
|
$top->Button( -text => "Dismiss", @Devel::tcltkdb::button_font, |
2249
|
|
|
|
|
|
|
-command => $dismissSub)->pack(-side => 'left', -fill => 'both', -expand => 1) ; |
2250
|
|
|
|
|
|
|
|
2251
|
|
|
|
|
|
|
$top->protocol('WM_DELETE_WINDOW', $dismissSub) ; |
2252
|
|
|
|
|
|
|
$we->focus(); |
2253
|
|
|
|
|
|
|
$self->{find_window} = $top; |
2254
|
|
|
|
|
|
|
|
2255
|
|
|
|
|
|
|
} # end of FindText |
2256
|
|
|
|
|
|
|
|
2257
|
|
|
|
|
|
|
sub main_loop { |
2258
|
|
|
|
|
|
|
my ($self) = @_; |
2259
|
|
|
|
|
|
|
my $evt; |
2260
|
|
|
|
|
|
|
|
2261
|
|
|
|
|
|
|
SWITCH: for ($self->{'event'} = 'null' ; $DB::window->{main_window}; $self->{'event'} = undef ) { |
2262
|
|
|
|
|
|
|
|
2263
|
|
|
|
|
|
|
$DB::window->{main_window}->update; |
2264
|
|
|
|
|
|
|
next unless $self->{'event'} ; |
2265
|
|
|
|
|
|
|
|
2266
|
|
|
|
|
|
|
$evt = $self->{'event'} ; |
2267
|
|
|
|
|
|
|
$evt =~ /step/ && do { last SWITCH ; } ; |
2268
|
|
|
|
|
|
|
$evt =~ /null/ && do { next SWITCH ; } ; |
2269
|
|
|
|
|
|
|
$evt =~ /run/ && do { last SWITCH ; } ; |
2270
|
|
|
|
|
|
|
$evt =~ /quit/ && do { $self->DoQuit ; } ; |
2271
|
|
|
|
|
|
|
$evt =~ /expr/ && do { return $evt ; } ; # adds an expression to our expression window |
2272
|
|
|
|
|
|
|
$evt =~ /qexpr/ && do { return $evt ; } ; # does a 'quick' expression |
2273
|
|
|
|
|
|
|
$evt =~ /update/ && do { return $evt ; } ; # forces an update on our expression window |
2274
|
|
|
|
|
|
|
$evt =~ /reeval/ && do { return $evt ; } ; # updated the open expression eval window |
2275
|
|
|
|
|
|
|
$evt =~ /balloon_eval/ && do { return $evt } ; |
2276
|
|
|
|
|
|
|
} # end of switch block |
2277
|
|
|
|
|
|
|
return $evt ; |
2278
|
|
|
|
|
|
|
} # end of main_loop |
2279
|
|
|
|
|
|
|
|
2280
|
|
|
|
|
|
|
# |
2281
|
|
|
|
|
|
|
# $subStackRef A reference to the current subroutine stack |
2282
|
|
|
|
|
|
|
# |
2283
|
|
|
|
|
|
|
|
2284
|
|
|
|
|
|
|
sub goto_sub_from_stack { |
2285
|
|
|
|
|
|
|
my ($self, $f, $lineno) = @_ ; |
2286
|
|
|
|
|
|
|
$self->set_file($f, $lineno) ; |
2287
|
|
|
|
|
|
|
} # end of goto_sub_from_stack ; |
2288
|
|
|
|
|
|
|
|
2289
|
|
|
|
|
|
|
sub refresh_stack_menu { |
2290
|
|
|
|
|
|
|
my ($self) = @_ ; |
2291
|
|
|
|
|
|
|
my ($name, $i, $sub_offset, $subStack) ; |
2292
|
|
|
|
|
|
|
|
2293
|
|
|
|
|
|
|
# |
2294
|
|
|
|
|
|
|
# CAUTION: In the effort to 'rationalize' the code |
2295
|
|
|
|
|
|
|
# are moving some of this function down from DB::DB |
2296
|
|
|
|
|
|
|
# to here. $sub_offset represents how far 'down' |
2297
|
|
|
|
|
|
|
# we are from DB::DB. The $DB::subroutine_depth is |
2298
|
|
|
|
|
|
|
# tracked in such a way that while we are 'in' the debugger |
2299
|
|
|
|
|
|
|
# it will not be incremented, and thus represents the stack depth |
2300
|
|
|
|
|
|
|
# of the target program. |
2301
|
|
|
|
|
|
|
# |
2302
|
|
|
|
|
|
|
$sub_offset = 1 ; |
2303
|
|
|
|
|
|
|
$subStack = [] ; |
2304
|
|
|
|
|
|
|
|
2305
|
|
|
|
|
|
|
# clear existing entries |
2306
|
|
|
|
|
|
|
|
2307
|
|
|
|
|
|
|
for( $i = 0 ; $i <= $DB::subroutine_depth ; $i++ ) { |
2308
|
|
|
|
|
|
|
my ($package, $filename, $line, $subName) = caller $i+$sub_offset ; |
2309
|
|
|
|
|
|
|
last if !$subName ; |
2310
|
|
|
|
|
|
|
push @$subStack, { 'name' => $subName, 'pck' => $package, 'filename' => $filename, 'line' => $line } ; |
2311
|
|
|
|
|
|
|
} |
2312
|
|
|
|
|
|
|
|
2313
|
|
|
|
|
|
|
$self->{stack_menu}->menu->delete(0, 'last') ; # delete existing menu items |
2314
|
|
|
|
|
|
|
|
2315
|
|
|
|
|
|
|
for( $i = 0 ; $subStack->[$i] ; $i++ ) { |
2316
|
|
|
|
|
|
|
|
2317
|
|
|
|
|
|
|
my $str = defined $subStack->[$i+1] ? "$subStack->[$i+1]->{name}" : "MAIN" ; |
2318
|
|
|
|
|
|
|
|
2319
|
|
|
|
|
|
|
my ($f, $line) = ($subStack->[$i]->{filename}, $subStack->[$i]->{line}) ; # make copies of the values for use in 'sub' |
2320
|
|
|
|
|
|
|
$self->{stack_menu}->command(-label => $str, -command => sub { $self->goto_sub_from_stack($f, $line) ; } ) ; |
2321
|
|
|
|
|
|
|
} |
2322
|
|
|
|
|
|
|
} # end of refresh_stack_menu |
2323
|
|
|
|
|
|
|
|
2324
|
|
|
|
|
|
|
no strict ; |
2325
|
|
|
|
|
|
|
|
2326
|
|
|
|
|
|
|
sub get_state { |
2327
|
|
|
|
|
|
|
my ($self, $fname) = @_ ; |
2328
|
|
|
|
|
|
|
my ($val) ; |
2329
|
|
|
|
|
|
|
local($files, $expr_list, $eval_saved_text, $main_win_geometry) ; |
2330
|
|
|
|
|
|
|
|
2331
|
|
|
|
|
|
|
do "$fname" ; |
2332
|
|
|
|
|
|
|
|
2333
|
|
|
|
|
|
|
if( $@ ) { |
2334
|
|
|
|
|
|
|
$self->DoAlert($@) ; |
2335
|
|
|
|
|
|
|
return ( undef ) x 4 ; # return a list of 4 undefined values |
2336
|
|
|
|
|
|
|
} |
2337
|
|
|
|
|
|
|
|
2338
|
|
|
|
|
|
|
return ($files, $expr_list, $eval_saved_text, $main_win_geometry) ; |
2339
|
|
|
|
|
|
|
} # end of get_state |
2340
|
|
|
|
|
|
|
|
2341
|
|
|
|
|
|
|
use strict ; |
2342
|
|
|
|
|
|
|
|
2343
|
|
|
|
|
|
|
sub restoreStateFile { |
2344
|
|
|
|
|
|
|
my ($self, $fname) = @_ ; |
2345
|
|
|
|
|
|
|
local(*F) ; |
2346
|
|
|
|
|
|
|
my ($saveCurFile, $s, @n, $n) ; |
2347
|
|
|
|
|
|
|
|
2348
|
|
|
|
|
|
|
if (!(-e $fname && -r $fname)) { |
2349
|
|
|
|
|
|
|
$self->DoAlert("$fname does not exist") ; |
2350
|
|
|
|
|
|
|
return ; |
2351
|
|
|
|
|
|
|
} |
2352
|
|
|
|
|
|
|
|
2353
|
|
|
|
|
|
|
my ($files, $expr_list, $eval_saved_text, $main_win_geometry) = $self->get_state($fname) ; |
2354
|
|
|
|
|
|
|
my ($f, $brks) ; |
2355
|
|
|
|
|
|
|
|
2356
|
|
|
|
|
|
|
return unless defined $files || defined $expr_list ; |
2357
|
|
|
|
|
|
|
|
2358
|
|
|
|
|
|
|
&DB::restore_breakpoints_from_save($files) ; |
2359
|
|
|
|
|
|
|
|
2360
|
|
|
|
|
|
|
# |
2361
|
|
|
|
|
|
|
# This should force the breakpoints to be restored |
2362
|
|
|
|
|
|
|
# |
2363
|
|
|
|
|
|
|
$saveCurFile = $self->{current_file} ; |
2364
|
|
|
|
|
|
|
|
2365
|
|
|
|
|
|
|
@$self{ 'current_file', 'expr_list', 'eval_saved_text' } = |
2366
|
|
|
|
|
|
|
( "" , $expr_list, $eval_saved_text) ; |
2367
|
|
|
|
|
|
|
|
2368
|
|
|
|
|
|
|
$self->set_file($saveCurFile, $self->{current_line}) ; |
2369
|
|
|
|
|
|
|
|
2370
|
|
|
|
|
|
|
$self->{'event'} = 'update' ; |
2371
|
|
|
|
|
|
|
|
2372
|
|
|
|
|
|
|
if ( $main_win_geometry && $self->{'main_window'} ) { |
2373
|
|
|
|
|
|
|
# restore the height and width of the window |
2374
|
|
|
|
|
|
|
$self->{main_window}->geometry( $main_win_geometry ) ; |
2375
|
|
|
|
|
|
|
} |
2376
|
|
|
|
|
|
|
} # end of retstoreState |
2377
|
|
|
|
|
|
|
|
2378
|
|
|
|
|
|
|
sub updateEvalWindow { |
2379
|
|
|
|
|
|
|
my ($self, @result) = @_ ; |
2380
|
|
|
|
|
|
|
my ($leng, $str) = (0,''); |
2381
|
|
|
|
|
|
|
|
2382
|
|
|
|
|
|
|
for (@result) { |
2383
|
|
|
|
|
|
|
if( $self->{hexdump_evals} ) { |
2384
|
|
|
|
|
|
|
# eventually put hex dumper code in here |
2385
|
|
|
|
|
|
|
$self->{eval_results}->insert('end', hexDump($_)) ; |
2386
|
|
|
|
|
|
|
} else { |
2387
|
|
|
|
|
|
|
my $d = Data::Dumper->new([$_]); |
2388
|
|
|
|
|
|
|
$d->Indent(2); |
2389
|
|
|
|
|
|
|
$d->Terse(1); |
2390
|
|
|
|
|
|
|
$str = $d->Dump($_); |
2391
|
|
|
|
|
|
|
} |
2392
|
|
|
|
|
|
|
$leng += length $str ; |
2393
|
|
|
|
|
|
|
$self->{eval_results}->insert('end', $str) ; |
2394
|
|
|
|
|
|
|
} |
2395
|
|
|
|
|
|
|
} # end of updateEvalWindow |
2396
|
|
|
|
|
|
|
|
2397
|
|
|
|
|
|
|
## |
2398
|
|
|
|
|
|
|
## converts non printable chars to '.' for a string |
2399
|
|
|
|
|
|
|
## |
2400
|
|
|
|
|
|
|
sub printablestr { |
2401
|
|
|
|
|
|
|
return join "", map { (ord($_) >= 32 && ord($_) < 127) ? $_ : '.' } split //, $_[0] ; |
2402
|
|
|
|
|
|
|
} |
2403
|
|
|
|
|
|
|
|
2404
|
|
|
|
|
|
|
## |
2405
|
|
|
|
|
|
|
## hex dump utility function |
2406
|
|
|
|
|
|
|
## |
2407
|
|
|
|
|
|
|
sub hexDump { |
2408
|
|
|
|
|
|
|
my @retList; |
2409
|
|
|
|
|
|
|
my $width = 8; |
2410
|
|
|
|
|
|
|
my $offset = 0; |
2411
|
|
|
|
|
|
|
|
2412
|
|
|
|
|
|
|
for (@_) { |
2413
|
|
|
|
|
|
|
my $str = ''; |
2414
|
|
|
|
|
|
|
my $len = length $_ ; |
2415
|
|
|
|
|
|
|
|
2416
|
|
|
|
|
|
|
while($len) { |
2417
|
|
|
|
|
|
|
my $n = $len >= $width ? $width : $len ; |
2418
|
|
|
|
|
|
|
|
2419
|
|
|
|
|
|
|
my $fmt = "\n%04X " . ("%02X " x $n ) . ( ' ' x ($width - $n) ) . " %s" ; |
2420
|
|
|
|
|
|
|
my @elems = map ord, split //, (substr $_, $offset, $n) ; |
2421
|
|
|
|
|
|
|
$str .= sprintf($fmt, $offset, @elems, printablestr(substr $_, $offset, $n)) ; |
2422
|
|
|
|
|
|
|
$offset += $width; |
2423
|
|
|
|
|
|
|
|
2424
|
|
|
|
|
|
|
$len -= $n; |
2425
|
|
|
|
|
|
|
} # while |
2426
|
|
|
|
|
|
|
|
2427
|
|
|
|
|
|
|
push @retList, $str; |
2428
|
|
|
|
|
|
|
} # for |
2429
|
|
|
|
|
|
|
|
2430
|
|
|
|
|
|
|
return $retList[0] unless wantarray ; |
2431
|
|
|
|
|
|
|
return @retList ; |
2432
|
|
|
|
|
|
|
} # end of hd |
2433
|
|
|
|
|
|
|
|
2434
|
|
|
|
|
|
|
|
2435
|
|
|
|
|
|
|
sub setupEvalWindow { |
2436
|
|
|
|
|
|
|
my($self) = @_; |
2437
|
|
|
|
|
|
|
$self->{eval_window}->focus(), return if exists $self->{eval_window} ; # already running this window? |
2438
|
|
|
|
|
|
|
|
2439
|
|
|
|
|
|
|
my $top = $self->{main_window}->Toplevel(-title => "Evaluate Expressions..."); |
2440
|
|
|
|
|
|
|
$self->{eval_window} = $top; |
2441
|
|
|
|
|
|
|
$self->{eval_text} = $top->Scrolled('Text', |
2442
|
|
|
|
|
|
|
@Devel::tcltkdb::eval_text_font, |
2443
|
|
|
|
|
|
|
-width => 50, |
2444
|
|
|
|
|
|
|
-height => 10, |
2445
|
|
|
|
|
|
|
-wrap => "none", |
2446
|
|
|
|
|
|
|
)->pack(qw/-side top -fill both -expand 1/); |
2447
|
|
|
|
|
|
|
|
2448
|
|
|
|
|
|
|
$self->{eval_text}->insert('end', $self->{eval_saved_text}) if exists $self->{eval_saved_text} && defined $self->{eval_saved_text}; |
2449
|
|
|
|
|
|
|
|
2450
|
|
|
|
|
|
|
$top->Label(-text => "Results:")->pack(qw/-side top -fill both -expand n/); |
2451
|
|
|
|
|
|
|
|
2452
|
|
|
|
|
|
|
$self->{eval_results} = $top->Scrolled('Text', |
2453
|
|
|
|
|
|
|
-width => 50, |
2454
|
|
|
|
|
|
|
-height => 10, |
2455
|
|
|
|
|
|
|
-wrap => "none", |
2456
|
|
|
|
|
|
|
@Devel::tcltkdb::eval_text_font |
2457
|
|
|
|
|
|
|
)->pack(qw/-side top -fill both -expand 1/); |
2458
|
|
|
|
|
|
|
|
2459
|
|
|
|
|
|
|
my $btn = $top->Button(-text => 'Eval...', -command => sub { $DB::window->{event} = 'reeval' ; } |
2460
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'x', -expand => 1); |
2461
|
|
|
|
|
|
|
|
2462
|
|
|
|
|
|
|
my $dismissSub = sub { |
2463
|
|
|
|
|
|
|
$self->{eval_saved_text} = $self->{eval_text}->get('0.0', 'end') ; |
2464
|
|
|
|
|
|
|
$self->{eval_window}->destroy ; |
2465
|
|
|
|
|
|
|
delete $self->{eval_window} ; |
2466
|
|
|
|
|
|
|
}; |
2467
|
|
|
|
|
|
|
|
2468
|
|
|
|
|
|
|
$top->protocol('WM_DELETE_WINDOW', $dismissSub ) ; |
2469
|
|
|
|
|
|
|
|
2470
|
|
|
|
|
|
|
$top->Button(-text => 'Clear Eval', -command => sub { $self->{eval_text}->delete('0.0', 'end') } |
2471
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'x', -expand => 1); |
2472
|
|
|
|
|
|
|
|
2473
|
|
|
|
|
|
|
$top->Button(-text => 'Clear Results', -command => sub { $self->{eval_results}->delete('0.0', 'end') } |
2474
|
|
|
|
|
|
|
)->pack(-side => 'left', -fill => 'x', -expand => 1) ; |
2475
|
|
|
|
|
|
|
|
2476
|
|
|
|
|
|
|
$top->Button(-text => 'Dismiss', -command => $dismissSub)->pack(-side => 'left', -fill => 'x', -expand => 1) ; |
2477
|
|
|
|
|
|
|
$top->Checkbutton(-text => 'Hex', -variable => \$self->{hexdump_evals})->pack(-side => 'left') ; |
2478
|
|
|
|
|
|
|
|
2479
|
|
|
|
|
|
|
} # end of setupEvalWindow ; |
2480
|
|
|
|
|
|
|
|
2481
|
|
|
|
|
|
|
sub filterBreakPts { |
2482
|
|
|
|
|
|
|
my ($breakPtsListRef, $fname) = @_ ; |
2483
|
|
|
|
|
|
|
my $dbline = $main::{'_<' . $fname}; # breakable lines |
2484
|
|
|
|
|
|
|
local($^W) = 0 ; |
2485
|
|
|
|
|
|
|
# |
2486
|
|
|
|
|
|
|
# Go through the list of breaks and take out any that |
2487
|
|
|
|
|
|
|
# are no longer breakable |
2488
|
|
|
|
|
|
|
# |
2489
|
|
|
|
|
|
|
|
2490
|
|
|
|
|
|
|
for( @$breakPtsListRef ) { |
2491
|
|
|
|
|
|
|
next unless defined $_ ; |
2492
|
|
|
|
|
|
|
|
2493
|
|
|
|
|
|
|
next if $dbline->[$_->{'line'}] != 0 ; # still breakable |
2494
|
|
|
|
|
|
|
|
2495
|
|
|
|
|
|
|
$_ = undef ; |
2496
|
|
|
|
|
|
|
} |
2497
|
|
|
|
|
|
|
} # end of filterBreakPts |
2498
|
|
|
|
|
|
|
|
2499
|
|
|
|
|
|
|
sub DoAbout { |
2500
|
|
|
|
|
|
|
my $self = shift ; |
2501
|
|
|
|
|
|
|
my $str = <<"__STR__" ; |
2502
|
|
|
|
|
|
|
tcltkdb $tcltkdb::VERSION |
2503
|
|
|
|
|
|
|
Copyright 1998,2003 by Andrew E. Page, 2010,2011 Vadim Konovalov. |
2504
|
|
|
|
|
|
|
|
2505
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify |
2506
|
|
|
|
|
|
|
it under the terms of either: |
2507
|
|
|
|
|
|
|
|
2508
|
|
|
|
|
|
|
a) the GNU General Public License as published by the Free |
2509
|
|
|
|
|
|
|
Software Foundation; either version 1, or (at your option) any |
2510
|
|
|
|
|
|
|
later version, or |
2511
|
|
|
|
|
|
|
|
2512
|
|
|
|
|
|
|
b) the "Artistic License" which comes with this Kit. |
2513
|
|
|
|
|
|
|
|
2514
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, |
2515
|
|
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
2516
|
|
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either |
2517
|
|
|
|
|
|
|
the GNU General Public License or the Artistic License for more details. |
2518
|
|
|
|
|
|
|
|
2519
|
|
|
|
|
|
|
OS $^O |
2520
|
|
|
|
|
|
|
Tcl/Tk Version $Tcl::Tk::TK_VERSION |
2521
|
|
|
|
|
|
|
Tcl::Tk Version $Tcl::Tk::VERSION |
2522
|
|
|
|
|
|
|
Perl Version $] |
2523
|
|
|
|
|
|
|
__STR__ |
2524
|
|
|
|
|
|
|
|
2525
|
|
|
|
|
|
|
$self->DoAlert($str, "About ptkdb") ; |
2526
|
|
|
|
|
|
|
} # end of DoAbout |
2527
|
|
|
|
|
|
|
|
2528
|
|
|
|
|
|
|
# |
2529
|
|
|
|
|
|
|
# return 1 if succesfully set, |
2530
|
|
|
|
|
|
|
# return 0 if otherwise |
2531
|
|
|
|
|
|
|
# |
2532
|
|
|
|
|
|
|
sub SetBreakPoint { |
2533
|
|
|
|
|
|
|
my ($self, $isTemp) = @_ ; |
2534
|
|
|
|
|
|
|
my $dbw = $DB::window ; |
2535
|
|
|
|
|
|
|
my $lineno = $dbw->get_lineno(); |
2536
|
|
|
|
|
|
|
my $expr = $dbw->clear_entry_text() ; |
2537
|
|
|
|
|
|
|
local($^W) = 0 ; |
2538
|
|
|
|
|
|
|
|
2539
|
|
|
|
|
|
|
if( !&DB::checkdbline($DB::window->{current_file}, $lineno + $self->{'line_offset'}) ) { |
2540
|
|
|
|
|
|
|
$dbw->DoAlert("line $lineno in $DB::window->{current_file} is not breakable") ; |
2541
|
|
|
|
|
|
|
return 0 ; |
2542
|
|
|
|
|
|
|
} |
2543
|
|
|
|
|
|
|
|
2544
|
|
|
|
|
|
|
if( !$isTemp ) { |
2545
|
|
|
|
|
|
|
$dbw->insertBreakpoint($DB::window->{current_file}, $lineno, 1, $expr) ; |
2546
|
|
|
|
|
|
|
return 1 ; |
2547
|
|
|
|
|
|
|
} |
2548
|
|
|
|
|
|
|
else { |
2549
|
|
|
|
|
|
|
$dbw->insertTempBreakpoint($DB::window->{current_file}, $lineno) ; |
2550
|
|
|
|
|
|
|
return 1 ; |
2551
|
|
|
|
|
|
|
} |
2552
|
|
|
|
|
|
|
|
2553
|
|
|
|
|
|
|
return 0 ; |
2554
|
|
|
|
|
|
|
} # end of SetBreakPoint |
2555
|
|
|
|
|
|
|
|
2556
|
|
|
|
|
|
|
sub UnsetBreakPoint { |
2557
|
|
|
|
|
|
|
my ($self) = @_ ; |
2558
|
|
|
|
|
|
|
my $lineno = $self->get_lineno(); |
2559
|
|
|
|
|
|
|
|
2560
|
|
|
|
|
|
|
$self->removeBreakpoint($DB::window->{current_file}, $lineno) ; |
2561
|
|
|
|
|
|
|
} # end of UnsetBreakPoint |
2562
|
|
|
|
|
|
|
|
2563
|
|
|
|
|
|
|
sub balloon_post { |
2564
|
|
|
|
|
|
|
my $self = $DB::window ; |
2565
|
|
|
|
|
|
|
my $txt = $DB::window->{'text'} ; |
2566
|
|
|
|
|
|
|
|
2567
|
|
|
|
|
|
|
return 0 if ($self->{'expr_ballon_msg'} eq "") || ($self->{'balloon_expr'} eq "") ; # don't post for an empty string |
2568
|
|
|
|
|
|
|
|
2569
|
|
|
|
|
|
|
return $self->{'balloon_coord'} ; |
2570
|
|
|
|
|
|
|
} |
2571
|
|
|
|
|
|
|
|
2572
|
|
|
|
|
|
|
sub balloon_motion { |
2573
|
|
|
|
|
|
|
my ($txt, $x, $y) = @_ ; |
2574
|
|
|
|
|
|
|
my ($offset_x, $offset_y) = ($x + 4, $y + 4) ; |
2575
|
|
|
|
|
|
|
my $self = $DB::window ; |
2576
|
|
|
|
|
|
|
my $txt2 = $self->{'text'} ; |
2577
|
|
|
|
|
|
|
my $data ; |
2578
|
|
|
|
|
|
|
|
2579
|
|
|
|
|
|
|
$self->{'balloon_coord'} = "$offset_x,$offset_y" ; |
2580
|
|
|
|
|
|
|
|
2581
|
|
|
|
|
|
|
$x -= $txt->rootx ; |
2582
|
|
|
|
|
|
|
$y -= $txt->rooty ; |
2583
|
|
|
|
|
|
|
# |
2584
|
|
|
|
|
|
|
# Post an event that will cause us to put up a popup |
2585
|
|
|
|
|
|
|
# |
2586
|
|
|
|
|
|
|
|
2587
|
|
|
|
|
|
|
if ($txt2->_tagRangesSel) { # check to see if 'sel' tag exists (return undef value) |
2588
|
|
|
|
|
|
|
$data = $txt2->get("sel.first", "sel.last") ; # get the text between the 'first' and 'last' point of the sel (selection) tag |
2589
|
|
|
|
|
|
|
} |
2590
|
|
|
|
|
|
|
else { |
2591
|
|
|
|
|
|
|
$data = $DB::window->retrieve_text_expr($x, $y) ; |
2592
|
|
|
|
|
|
|
} |
2593
|
|
|
|
|
|
|
|
2594
|
|
|
|
|
|
|
if( !$data ) { |
2595
|
|
|
|
|
|
|
$self->{'balloon_expr'} = "" ; |
2596
|
|
|
|
|
|
|
return 0 ; |
2597
|
|
|
|
|
|
|
} |
2598
|
|
|
|
|
|
|
|
2599
|
|
|
|
|
|
|
return 0 if ($data eq $self->{'balloon_expr'}) ; # nevermind if it's the same expression |
2600
|
|
|
|
|
|
|
|
2601
|
|
|
|
|
|
|
$self->{'event'} = 'balloon_eval' ; |
2602
|
|
|
|
|
|
|
$self->{'balloon_expr'} = $data ; |
2603
|
|
|
|
|
|
|
|
2604
|
|
|
|
|
|
|
return 1 ; # ballon will be canceled and a new one put up(maybe) |
2605
|
|
|
|
|
|
|
} # end of balloon_motion |
2606
|
|
|
|
|
|
|
|
2607
|
|
|
|
|
|
|
sub retrieve_text_expr { |
2608
|
|
|
|
|
|
|
my($self, $x, $y) = @_ ; |
2609
|
|
|
|
|
|
|
my $txt = $self->{'text'} ; |
2610
|
|
|
|
|
|
|
|
2611
|
|
|
|
|
|
|
my ($idx, $col) = $txt->index("\@$x,$y") =~ /^(\d*)\.(\d*)$/; |
2612
|
|
|
|
|
|
|
|
2613
|
|
|
|
|
|
|
my $offset = $Devel::tcltkdb::linenumber_length + 1 ; # line number text + 1 space |
2614
|
|
|
|
|
|
|
|
2615
|
|
|
|
|
|
|
return undef if $col < $offset ; # no posting |
2616
|
|
|
|
|
|
|
|
2617
|
|
|
|
|
|
|
$col -= $offset ; |
2618
|
|
|
|
|
|
|
|
2619
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $self->{current_file}} ; |
2620
|
|
|
|
|
|
|
|
2621
|
|
|
|
|
|
|
return undef if( !defined $dbline[$idx] || $dbline[$idx] == 0 ) ; # no executable text, no real variable(?) |
2622
|
|
|
|
|
|
|
|
2623
|
|
|
|
|
|
|
my $data = $dbline[$idx] ; |
2624
|
|
|
|
|
|
|
|
2625
|
|
|
|
|
|
|
# if we're sitting over white space, leave |
2626
|
|
|
|
|
|
|
my $len = length $data ; |
2627
|
|
|
|
|
|
|
return unless $data && $col && $len > 0 ; |
2628
|
|
|
|
|
|
|
|
2629
|
|
|
|
|
|
|
return if substr($data, $col, 1) =~ /\s/ ; |
2630
|
|
|
|
|
|
|
|
2631
|
|
|
|
|
|
|
# walk backwards till we find some whitespace |
2632
|
|
|
|
|
|
|
|
2633
|
|
|
|
|
|
|
$col = $len if $len < $col ; |
2634
|
|
|
|
|
|
|
while( --$col >= 0 ) { |
2635
|
|
|
|
|
|
|
last if substr($data, $col, 1) =~ /[\s\$\@\%]/ ; |
2636
|
|
|
|
|
|
|
} |
2637
|
|
|
|
|
|
|
|
2638
|
|
|
|
|
|
|
substr($data, $col) =~ /^([\$\@\%]\w+)/ ; |
2639
|
|
|
|
|
|
|
|
2640
|
|
|
|
|
|
|
return $1 ; |
2641
|
|
|
|
|
|
|
} |
2642
|
|
|
|
|
|
|
|
2643
|
|
|
|
|
|
|
# |
2644
|
|
|
|
|
|
|
# after DB::eval get's us a result |
2645
|
|
|
|
|
|
|
# |
2646
|
|
|
|
|
|
|
sub code_motion_eval { |
2647
|
|
|
|
|
|
|
my ($self, @result) = @_; |
2648
|
|
|
|
|
|
|
my $d = new Data::Dumper([]); |
2649
|
|
|
|
|
|
|
$d->Terse(1); |
2650
|
|
|
|
|
|
|
$d->Indent(2); |
2651
|
|
|
|
|
|
|
$d->Values( [ $#result == 0 ? @result : \@result ]); |
2652
|
|
|
|
|
|
|
my $str = $d->Dump(); |
2653
|
|
|
|
|
|
|
chomp($str) ; |
2654
|
|
|
|
|
|
|
# Cut the string down to 1024 characters to keep from overloading the balloon window |
2655
|
|
|
|
|
|
|
$self->{'expr_ballon_msg'} = "$self->{'balloon_expr'} = " . substr $str, 0, 1024 ; |
2656
|
|
|
|
|
|
|
} # end of code motion eval |
2657
|
|
|
|
|
|
|
|
2658
|
|
|
|
|
|
|
# |
2659
|
|
|
|
|
|
|
# Subroutine called when we enter DB::DB() |
2660
|
|
|
|
|
|
|
# In other words when the target script 'stops' |
2661
|
|
|
|
|
|
|
# in the Debugger |
2662
|
|
|
|
|
|
|
# |
2663
|
|
|
|
|
|
|
sub EnterActions { |
2664
|
|
|
|
|
|
|
my($self) = @_ ; |
2665
|
|
|
|
|
|
|
|
2666
|
|
|
|
|
|
|
# $self->{'main_window'}->Unbusy() ; |
2667
|
|
|
|
|
|
|
} |
2668
|
|
|
|
|
|
|
|
2669
|
|
|
|
|
|
|
# |
2670
|
|
|
|
|
|
|
# Subroutine called when we return from DB::DB() |
2671
|
|
|
|
|
|
|
# When the target script resumes. |
2672
|
|
|
|
|
|
|
# |
2673
|
|
|
|
|
|
|
sub LeaveActions { |
2674
|
|
|
|
|
|
|
my($self) = @_ ; |
2675
|
|
|
|
|
|
|
|
2676
|
|
|
|
|
|
|
# $self->{'main_window'}->Busy() ; |
2677
|
|
|
|
|
|
|
} |
2678
|
|
|
|
|
|
|
|
2679
|
|
|
|
|
|
|
|
2680
|
|
|
|
|
|
|
sub BEGIN { |
2681
|
|
|
|
|
|
|
$Devel::tcltkdb::scriptName = $0 ; |
2682
|
|
|
|
|
|
|
@Devel::tcltkdb::script_args = @ARGV ; # copy args |
2683
|
|
|
|
|
|
|
} |
2684
|
|
|
|
|
|
|
|
2685
|
|
|
|
|
|
|
## |
2686
|
|
|
|
|
|
|
## Save the ptkdb state file and restart the debugger |
2687
|
|
|
|
|
|
|
## |
2688
|
|
|
|
|
|
|
sub DoRestart { |
2689
|
|
|
|
|
|
|
my($fname) ; |
2690
|
|
|
|
|
|
|
|
2691
|
|
|
|
|
|
|
$fname = $ENV{'TMP'} || $ENV{'TMPDIR'} || $ENV{'TMP_DIR'} || $ENV{'TEMP'} || $ENV{'HOME'} ; |
2692
|
|
|
|
|
|
|
$fname .= '/' if $fname ; |
2693
|
|
|
|
|
|
|
$fname = "" unless $fname ; |
2694
|
|
|
|
|
|
|
|
2695
|
|
|
|
|
|
|
$fname .= "ptkdb_restart_state$$" ; |
2696
|
|
|
|
|
|
|
|
2697
|
|
|
|
|
|
|
# print "saving temp state file $fname\n" ; |
2698
|
|
|
|
|
|
|
|
2699
|
|
|
|
|
|
|
&DB::save_state_file($fname) ; |
2700
|
|
|
|
|
|
|
|
2701
|
|
|
|
|
|
|
$ENV{'PTKDB_RESTART_STATE_FILE'} = $fname ; |
2702
|
|
|
|
|
|
|
|
2703
|
|
|
|
|
|
|
## |
2704
|
|
|
|
|
|
|
## build up the command to do the restart |
2705
|
|
|
|
|
|
|
## |
2706
|
|
|
|
|
|
|
|
2707
|
|
|
|
|
|
|
$fname = "perl -w -d:tcltkdb $Devel::tcltkdb::scriptName @Devel::tcltkdb::script_args" ; |
2708
|
|
|
|
|
|
|
|
2709
|
|
|
|
|
|
|
# print "$$ doing a restart with $fname\n" ; |
2710
|
|
|
|
|
|
|
|
2711
|
|
|
|
|
|
|
exec $fname ; |
2712
|
|
|
|
|
|
|
|
2713
|
|
|
|
|
|
|
} # end of DoRestart |
2714
|
|
|
|
|
|
|
|
2715
|
|
|
|
|
|
|
## |
2716
|
|
|
|
|
|
|
## Enables/Disables the feature where we stop |
2717
|
|
|
|
|
|
|
## if we've encountered a perl warning such as: |
2718
|
|
|
|
|
|
|
## "Use of uninitialized value at undef_warn.pl line N" |
2719
|
|
|
|
|
|
|
## |
2720
|
|
|
|
|
|
|
|
2721
|
|
|
|
|
|
|
sub stop_on_warning_cb { |
2722
|
|
|
|
|
|
|
&$DB::tcltkdb::warn_sig_save() if $DB::tcltkdb::warn_sig_save ; # call any previously registered warning |
2723
|
|
|
|
|
|
|
$DB::window->DoAlert(@_) ; |
2724
|
|
|
|
|
|
|
$DB::single = 1 ; # forces debugger to stop next time |
2725
|
|
|
|
|
|
|
} |
2726
|
|
|
|
|
|
|
|
2727
|
|
|
|
|
|
|
sub set_stop_on_warning { |
2728
|
|
|
|
|
|
|
|
2729
|
|
|
|
|
|
|
if( $DB::tcltkdb::stop_on_warning ) { |
2730
|
|
|
|
|
|
|
|
2731
|
|
|
|
|
|
|
return if $DB::tcltkdb::warn_sig_save == \&stop_on_warning_cb ; # prevents recursion |
2732
|
|
|
|
|
|
|
|
2733
|
|
|
|
|
|
|
$DB::tcltkdb::warn_sig_save = $SIG{'__WARN__'} if $SIG{'__WARN__'} ; |
2734
|
|
|
|
|
|
|
$SIG{'__WARN__'} = \&stop_on_warning_cb ; |
2735
|
|
|
|
|
|
|
} |
2736
|
|
|
|
|
|
|
else { |
2737
|
|
|
|
|
|
|
## |
2738
|
|
|
|
|
|
|
## Restore any previous warning signal |
2739
|
|
|
|
|
|
|
## |
2740
|
|
|
|
|
|
|
local($^W) = 0 ; |
2741
|
|
|
|
|
|
|
$SIG{'__WARN__'} = $DB::tcltkdb::warn_sig_save ; |
2742
|
|
|
|
|
|
|
} |
2743
|
|
|
|
|
|
|
} # end of set_stop_on_warning |
2744
|
|
|
|
|
|
|
|
2745
|
|
|
|
|
|
|
# end of Devel::tcltkdb |
2746
|
|
|
|
|
|
|
|
2747
|
|
|
|
|
|
|
package DB; |
2748
|
|
|
|
|
|
|
|
2749
|
|
|
|
|
|
|
use vars '$VERSION'; |
2750
|
|
|
|
|
|
|
use vars '@dbline', '%dbline'; |
2751
|
|
|
|
|
|
|
|
2752
|
|
|
|
|
|
|
$VERSION = '2.0'; |
2753
|
|
|
|
|
|
|
$DB::window->{current_file} = "" ; |
2754
|
|
|
|
|
|
|
|
2755
|
|
|
|
|
|
|
# |
2756
|
|
|
|
|
|
|
# Here's the clue... |
2757
|
|
|
|
|
|
|
# eval only seems to eval the context of |
2758
|
|
|
|
|
|
|
# the executing script while in the DB |
2759
|
|
|
|
|
|
|
# package. When we had updateExprs in the Devel::tcltkdb |
2760
|
|
|
|
|
|
|
# package eval would turn up an undef result. |
2761
|
|
|
|
|
|
|
# |
2762
|
|
|
|
|
|
|
|
2763
|
|
|
|
|
|
|
sub updateExprs { |
2764
|
|
|
|
|
|
|
my ($package) = @_ ; |
2765
|
|
|
|
|
|
|
# |
2766
|
|
|
|
|
|
|
# Update expressions |
2767
|
|
|
|
|
|
|
# |
2768
|
|
|
|
|
|
|
$DB::window->deleteAllExprs(); |
2769
|
|
|
|
|
|
|
|
2770
|
|
|
|
|
|
|
foreach my $expr (@{$DB::window->{'expr_list'}}) { |
2771
|
|
|
|
|
|
|
next if length $expr == 0 ; |
2772
|
|
|
|
|
|
|
|
2773
|
|
|
|
|
|
|
my @result = &DB::dbeval($package, $expr->{'expr'}) ; |
2774
|
|
|
|
|
|
|
|
2775
|
|
|
|
|
|
|
my $r = (@result==1?$result[0]:\@result); |
2776
|
|
|
|
|
|
|
$DB::window->insertExpr([$r], $r, $expr->{'expr'}, $expr->{'depth'},'root'); |
2777
|
|
|
|
|
|
|
} |
2778
|
|
|
|
|
|
|
} # end of updateExprs |
2779
|
|
|
|
|
|
|
|
2780
|
|
|
|
|
|
|
#no strict ; # turning strict off (shame shame) because we keep getting errrs for the local(*dbline) |
2781
|
|
|
|
|
|
|
|
2782
|
|
|
|
|
|
|
# |
2783
|
|
|
|
|
|
|
# returns true if line is breakable |
2784
|
|
|
|
|
|
|
# |
2785
|
|
|
|
|
|
|
sub checkdbline($$) { |
2786
|
|
|
|
|
|
|
my ($fname, $lineno) = @_ ; |
2787
|
|
|
|
|
|
|
|
2788
|
|
|
|
|
|
|
return 0 unless $fname; # we're getting an undef here on 'Restart...' |
2789
|
|
|
|
|
|
|
|
2790
|
|
|
|
|
|
|
local($^W) = 0 ; # spares us warnings under -w |
2791
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname} ; |
2792
|
|
|
|
|
|
|
|
2793
|
|
|
|
|
|
|
my $flag = $dbline[$lineno] != 0 ; |
2794
|
|
|
|
|
|
|
|
2795
|
|
|
|
|
|
|
return $flag; |
2796
|
|
|
|
|
|
|
|
2797
|
|
|
|
|
|
|
} # end of checkdbline |
2798
|
|
|
|
|
|
|
|
2799
|
|
|
|
|
|
|
# |
2800
|
|
|
|
|
|
|
# sets a breakpoint 'through' a magic |
2801
|
|
|
|
|
|
|
# variable that perl is able to interpert |
2802
|
|
|
|
|
|
|
# |
2803
|
|
|
|
|
|
|
sub setdbline($$$) { |
2804
|
|
|
|
|
|
|
my ($fname, $lineno, $value) = @_ ; |
2805
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname}; |
2806
|
|
|
|
|
|
|
|
2807
|
|
|
|
|
|
|
$dbline{$lineno} = $value ; |
2808
|
|
|
|
|
|
|
} # end of setdbline |
2809
|
|
|
|
|
|
|
|
2810
|
|
|
|
|
|
|
sub getdbline($$) { |
2811
|
|
|
|
|
|
|
my ($fname, $lineno) = @_ ; |
2812
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname}; |
2813
|
|
|
|
|
|
|
return $dbline{$lineno} ; |
2814
|
|
|
|
|
|
|
} # end of getdbline |
2815
|
|
|
|
|
|
|
|
2816
|
|
|
|
|
|
|
sub getdbtextline { |
2817
|
|
|
|
|
|
|
my ($fname, $lineno) = @_ ; |
2818
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname}; |
2819
|
|
|
|
|
|
|
return $dbline[$lineno] ; |
2820
|
|
|
|
|
|
|
} # end of getdbline |
2821
|
|
|
|
|
|
|
|
2822
|
|
|
|
|
|
|
|
2823
|
|
|
|
|
|
|
sub cleardbline($$;&) { |
2824
|
|
|
|
|
|
|
my ($fname, $lineno, $clearsub) = @_ ; |
2825
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname}; |
2826
|
|
|
|
|
|
|
my $value ; # just in case we want it for something |
2827
|
|
|
|
|
|
|
|
2828
|
|
|
|
|
|
|
$value = $dbline{$lineno} ; |
2829
|
|
|
|
|
|
|
delete $dbline{$lineno} ; |
2830
|
|
|
|
|
|
|
&$clearsub($value) if $value && $clearsub ; |
2831
|
|
|
|
|
|
|
|
2832
|
|
|
|
|
|
|
return $value ; |
2833
|
|
|
|
|
|
|
} # end of cleardbline |
2834
|
|
|
|
|
|
|
|
2835
|
|
|
|
|
|
|
sub clearalldblines(;&) { |
2836
|
|
|
|
|
|
|
my ($clearsub) = @_ ; |
2837
|
|
|
|
|
|
|
my ($key, $value, $brkPt, $dbkey) ; |
2838
|
|
|
|
|
|
|
local(*dbline) ; |
2839
|
|
|
|
|
|
|
|
2840
|
|
|
|
|
|
|
while ( ($key, $value) = each %main:: ) { # key loop |
2841
|
|
|
|
|
|
|
next unless $key =~ /^_ ; |
2842
|
|
|
|
|
|
|
*dbline = $value ; |
2843
|
|
|
|
|
|
|
|
2844
|
|
|
|
|
|
|
foreach $dbkey (keys %dbline) { |
2845
|
|
|
|
|
|
|
$brkPt = $dbline{$dbkey} ; |
2846
|
|
|
|
|
|
|
delete $dbline{$dbkey} ; |
2847
|
|
|
|
|
|
|
next unless $brkPt && $clearsub ; |
2848
|
|
|
|
|
|
|
&$clearsub($brkPt) ; # if specificed, call the sub routine to clear the breakpoint |
2849
|
|
|
|
|
|
|
} |
2850
|
|
|
|
|
|
|
|
2851
|
|
|
|
|
|
|
} # end of key loop |
2852
|
|
|
|
|
|
|
|
2853
|
|
|
|
|
|
|
} # end of clearalldblines |
2854
|
|
|
|
|
|
|
|
2855
|
|
|
|
|
|
|
sub getdblineindexes { |
2856
|
|
|
|
|
|
|
my ($fname) = @_ ; |
2857
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname} ; |
2858
|
|
|
|
|
|
|
return keys %dbline ; |
2859
|
|
|
|
|
|
|
} # end of getdblineindexes |
2860
|
|
|
|
|
|
|
|
2861
|
|
|
|
|
|
|
sub getbreakpoints { |
2862
|
|
|
|
|
|
|
my (@fnames) = @_; |
2863
|
|
|
|
|
|
|
my @retList; |
2864
|
|
|
|
|
|
|
|
2865
|
|
|
|
|
|
|
for my $fname (@fnames) { |
2866
|
|
|
|
|
|
|
next unless $main::{'_<' . $fname}; |
2867
|
|
|
|
|
|
|
local(*dbline) = $main::{'_<' . $fname}; |
2868
|
|
|
|
|
|
|
push @retList, values %dbline; |
2869
|
|
|
|
|
|
|
} |
2870
|
|
|
|
|
|
|
return @retList; |
2871
|
|
|
|
|
|
|
} # end of getbreakpoints |
2872
|
|
|
|
|
|
|
|
2873
|
|
|
|
|
|
|
# |
2874
|
|
|
|
|
|
|
# Construct a hash of the files that have breakpoints to save |
2875
|
|
|
|
|
|
|
# |
2876
|
|
|
|
|
|
|
sub breakpoints_to_save { |
2877
|
|
|
|
|
|
|
my (@breaks); |
2878
|
|
|
|
|
|
|
my $brkList = {}; |
2879
|
|
|
|
|
|
|
|
2880
|
|
|
|
|
|
|
for my $file ( keys %main:: ) { # file loop |
2881
|
|
|
|
|
|
|
next unless $file =~ /^_ && exists $main::{$file}; |
2882
|
|
|
|
|
|
|
local(*dbline) = $main::{$file}; |
2883
|
|
|
|
|
|
|
|
2884
|
|
|
|
|
|
|
next unless @breaks = values %dbline; |
2885
|
|
|
|
|
|
|
|
2886
|
|
|
|
|
|
|
$brkList->{$file} = [map { { %$_ } } @breaks]; # list of anon.hashes |
2887
|
|
|
|
|
|
|
} # end of file loop |
2888
|
|
|
|
|
|
|
|
2889
|
|
|
|
|
|
|
return $brkList; |
2890
|
|
|
|
|
|
|
|
2891
|
|
|
|
|
|
|
} # end of breakpoints_to_save |
2892
|
|
|
|
|
|
|
|
2893
|
|
|
|
|
|
|
# |
2894
|
|
|
|
|
|
|
# When we restore breakpoints from a state file |
2895
|
|
|
|
|
|
|
# they've often 'moved' because the file has been editted. |
2896
|
|
|
|
|
|
|
# |
2897
|
|
|
|
|
|
|
# We search for the line starting with the original line number, |
2898
|
|
|
|
|
|
|
# then we walk it back 20 lines, then with line right after the |
2899
|
|
|
|
|
|
|
# orginal line number and walk forward 20 lines. |
2900
|
|
|
|
|
|
|
# |
2901
|
|
|
|
|
|
|
# NOTE: dbline is expected to be 'local' when called |
2902
|
|
|
|
|
|
|
# |
2903
|
|
|
|
|
|
|
sub fix_breakpoints { |
2904
|
|
|
|
|
|
|
my(@brkPts) = @_ ; |
2905
|
|
|
|
|
|
|
my (@retList) ; |
2906
|
|
|
|
|
|
|
local($^W) = 0; |
2907
|
|
|
|
|
|
|
|
2908
|
|
|
|
|
|
|
my $nLines = scalar @dbline; |
2909
|
|
|
|
|
|
|
|
2910
|
|
|
|
|
|
|
for my $brkPt (@brkPts) { |
2911
|
|
|
|
|
|
|
|
2912
|
|
|
|
|
|
|
my $startLine = $brkPt->{'line'} > 20 ? $brkPt->{'line'} - 20 : 0 ; |
2913
|
|
|
|
|
|
|
my $endLine = $brkPt->{'line'} < $nLines - 20 ? $brkPt->{'line'} + 20 : $nLines; |
2914
|
|
|
|
|
|
|
|
2915
|
|
|
|
|
|
|
for( (reverse $startLine..$brkPt->{'line'}), $brkPt->{'line'} + 1 .. $endLine ) { |
2916
|
|
|
|
|
|
|
next unless $brkPt->{'text'} eq $dbline[$_] ; |
2917
|
|
|
|
|
|
|
$brkPt->{'line'} = $_ ; |
2918
|
|
|
|
|
|
|
push @retList, $brkPt ; |
2919
|
|
|
|
|
|
|
last; |
2920
|
|
|
|
|
|
|
} |
2921
|
|
|
|
|
|
|
} # end of breakpoint list |
2922
|
|
|
|
|
|
|
|
2923
|
|
|
|
|
|
|
return @retList; |
2924
|
|
|
|
|
|
|
} # end of fix_breakpoints |
2925
|
|
|
|
|
|
|
|
2926
|
|
|
|
|
|
|
# |
2927
|
|
|
|
|
|
|
# Restore breakpoints saved above |
2928
|
|
|
|
|
|
|
# |
2929
|
|
|
|
|
|
|
sub restore_breakpoints_from_save { |
2930
|
|
|
|
|
|
|
my ($brkList) = @_ ; |
2931
|
|
|
|
|
|
|
my ($key, $list, $brkPt, @newList) ; |
2932
|
|
|
|
|
|
|
|
2933
|
|
|
|
|
|
|
while ( ($key, $list) = each %$brkList ) { # reinsert loop |
2934
|
|
|
|
|
|
|
next unless exists $main::{$key} ; |
2935
|
|
|
|
|
|
|
local(*dbline) = $main::{$key} ; |
2936
|
|
|
|
|
|
|
|
2937
|
|
|
|
|
|
|
my $offset = 0; |
2938
|
|
|
|
|
|
|
$offset = 1 if $dbline[1] =~ /use\s+.*Devel::_?tcltkdb/ ; |
2939
|
|
|
|
|
|
|
|
2940
|
|
|
|
|
|
|
@newList = fix_breakpoints(@$list) ; |
2941
|
|
|
|
|
|
|
|
2942
|
|
|
|
|
|
|
foreach $brkPt ( @newList ) { |
2943
|
|
|
|
|
|
|
if( !&DB::checkdbline($key, $brkPt->{'line'} + $offset) ) { |
2944
|
|
|
|
|
|
|
print "Breakpoint $key:$brkPt->{'line'} in config file is not breakable.\n" ; |
2945
|
|
|
|
|
|
|
next ; |
2946
|
|
|
|
|
|
|
} |
2947
|
|
|
|
|
|
|
$dbline{$brkPt->{'line'}} = { %$brkPt } ; # make a fresh copy |
2948
|
|
|
|
|
|
|
} |
2949
|
|
|
|
|
|
|
} # end of reinsert loop |
2950
|
|
|
|
|
|
|
|
2951
|
|
|
|
|
|
|
} # end of restore_breakpoints_from_save ; |
2952
|
|
|
|
|
|
|
|
2953
|
|
|
|
|
|
|
sub dbint_handler { |
2954
|
|
|
|
|
|
|
my($sigName) = @_; |
2955
|
|
|
|
|
|
|
$DB::single = 1; |
2956
|
|
|
|
|
|
|
print STDERR "signalled\n"; |
2957
|
|
|
|
|
|
|
} # end of dbint_handler |
2958
|
|
|
|
|
|
|
|
2959
|
|
|
|
|
|
|
# |
2960
|
|
|
|
|
|
|
# Do first time initialization at the startup of DB::DB |
2961
|
|
|
|
|
|
|
# |
2962
|
|
|
|
|
|
|
my $isInitialized=0; |
2963
|
|
|
|
|
|
|
sub Initialize { |
2964
|
|
|
|
|
|
|
my ($fName) = @_ ; |
2965
|
|
|
|
|
|
|
$isInitialized = 1; |
2966
|
|
|
|
|
|
|
|
2967
|
|
|
|
|
|
|
$DB::window = new Devel::tcltkdb; |
2968
|
|
|
|
|
|
|
|
2969
|
|
|
|
|
|
|
$DB::window->do_user_init_files(); |
2970
|
|
|
|
|
|
|
|
2971
|
|
|
|
|
|
|
$DB::dbint_handler_save = $SIG{'INT'} unless $DB::sigint_disable ; # saves the old handler |
2972
|
|
|
|
|
|
|
$SIG{'INT'} = "DB::dbint_handler" unless $DB::sigint_disable ; |
2973
|
|
|
|
|
|
|
|
2974
|
|
|
|
|
|
|
# Save the file name we started up with |
2975
|
|
|
|
|
|
|
$DB::startupFname = $fName ; |
2976
|
|
|
|
|
|
|
|
2977
|
|
|
|
|
|
|
# Check for a 'restart' file |
2978
|
|
|
|
|
|
|
|
2979
|
|
|
|
|
|
|
if( $ENV{'PTKDB_RESTART_STATE_FILE'} && -e $ENV{'PTKDB_RESTART_STATE_FILE'} ) { |
2980
|
|
|
|
|
|
|
## |
2981
|
|
|
|
|
|
|
## Restore expressions and breakpoints in state file |
2982
|
|
|
|
|
|
|
## |
2983
|
|
|
|
|
|
|
$DB::window->restoreStateFile($ENV{'PTKDB_RESTART_STATE_FILE'}) ; |
2984
|
|
|
|
|
|
|
unlink $ENV{'PTKDB_RESTART_STATE_FILE'} ; # delete state file |
2985
|
|
|
|
|
|
|
|
2986
|
|
|
|
|
|
|
# print "restoring state from $ENV{'PTKDB_RESTART_STATE_FILE'}\n" ; |
2987
|
|
|
|
|
|
|
|
2988
|
|
|
|
|
|
|
$ENV{'PTKDB_RESTART_STATE_FILE'} = "" ; # clear entry |
2989
|
|
|
|
|
|
|
} |
2990
|
|
|
|
|
|
|
else { |
2991
|
|
|
|
|
|
|
&DB::restoreState($fName); |
2992
|
|
|
|
|
|
|
} |
2993
|
|
|
|
|
|
|
|
2994
|
|
|
|
|
|
|
} # end of Initialize |
2995
|
|
|
|
|
|
|
|
2996
|
|
|
|
|
|
|
sub restoreState { |
2997
|
|
|
|
|
|
|
my ($fName) = @_ ; |
2998
|
|
|
|
|
|
|
|
2999
|
|
|
|
|
|
|
my $stateFile = makeFileSaveName($fName); |
3000
|
|
|
|
|
|
|
if( -e $stateFile && -r $stateFile ) { |
3001
|
|
|
|
|
|
|
my ($files, $expr_list, $eval_saved_text, $main_win_geometry) = $DB::window->get_state($stateFile) ; |
3002
|
|
|
|
|
|
|
&DB::restore_breakpoints_from_save($files) ; |
3003
|
|
|
|
|
|
|
$DB::window->{'expr_list'} = $expr_list if defined $expr_list ; |
3004
|
|
|
|
|
|
|
$DB::window->{eval_saved_text} = $eval_saved_text ; |
3005
|
|
|
|
|
|
|
|
3006
|
|
|
|
|
|
|
if ($main_win_geometry) { |
3007
|
|
|
|
|
|
|
# restore the height and width of the window |
3008
|
|
|
|
|
|
|
$DB::window->{main_window}->geometry($main_win_geometry) ; |
3009
|
|
|
|
|
|
|
} |
3010
|
|
|
|
|
|
|
} |
3011
|
|
|
|
|
|
|
|
3012
|
|
|
|
|
|
|
} # end of Restore State |
3013
|
|
|
|
|
|
|
|
3014
|
|
|
|
|
|
|
sub makeFileSaveName { |
3015
|
|
|
|
|
|
|
return "$_[0].ptkdb"; |
3016
|
|
|
|
|
|
|
} |
3017
|
|
|
|
|
|
|
|
3018
|
|
|
|
|
|
|
sub save_state_file { |
3019
|
|
|
|
|
|
|
my($fname) = @_ ; |
3020
|
|
|
|
|
|
|
|
3021
|
|
|
|
|
|
|
my $files = &DB::breakpoints_to_save(); |
3022
|
|
|
|
|
|
|
|
3023
|
|
|
|
|
|
|
my $d = Data::Dumper->new( [ $files, $DB::window->{'expr_list'}, "" ], |
3024
|
|
|
|
|
|
|
[ "files", "expr_list", "eval_saved_text" ] ) ; |
3025
|
|
|
|
|
|
|
$d->Purity(1) ; |
3026
|
|
|
|
|
|
|
|
3027
|
|
|
|
|
|
|
local(*F) ; |
3028
|
|
|
|
|
|
|
open F, ">$fname" || die "Couldn't open file $fname" ; |
3029
|
|
|
|
|
|
|
print F $d->Dump() || die "Couldn't write file" ; |
3030
|
|
|
|
|
|
|
close F ; |
3031
|
|
|
|
|
|
|
} # end of save_state_file |
3032
|
|
|
|
|
|
|
|
3033
|
|
|
|
|
|
|
sub SaveState { |
3034
|
|
|
|
|
|
|
my($name_in) = @_ ; |
3035
|
|
|
|
|
|
|
my ($top, $entry, $okayBtn); |
3036
|
|
|
|
|
|
|
my ($fname, $saveSub, $cancelSub, $saveName, $eval_saved_text, $d) ; |
3037
|
|
|
|
|
|
|
my ($files, $main_win_geometry); |
3038
|
|
|
|
|
|
|
# |
3039
|
|
|
|
|
|
|
# Create our default name |
3040
|
|
|
|
|
|
|
# |
3041
|
|
|
|
|
|
|
my $win = $DB::window ; |
3042
|
|
|
|
|
|
|
|
3043
|
|
|
|
|
|
|
# |
3044
|
|
|
|
|
|
|
# Extract the height and width of our window |
3045
|
|
|
|
|
|
|
# |
3046
|
|
|
|
|
|
|
$main_win_geometry = $win->{main_window}->geometry ; |
3047
|
|
|
|
|
|
|
|
3048
|
|
|
|
|
|
|
if ( defined $win->{save_box} ) { |
3049
|
|
|
|
|
|
|
$win->{save_box}->raise ; |
3050
|
|
|
|
|
|
|
$win->{save_box}->focus ; |
3051
|
|
|
|
|
|
|
return ; |
3052
|
|
|
|
|
|
|
} |
3053
|
|
|
|
|
|
|
|
3054
|
|
|
|
|
|
|
$saveName = $name_in || makeFileSaveName($DB::startupFname) ; |
3055
|
|
|
|
|
|
|
|
3056
|
|
|
|
|
|
|
|
3057
|
|
|
|
|
|
|
$saveSub = sub { |
3058
|
|
|
|
|
|
|
$win->{'event'} = 'null' ; |
3059
|
|
|
|
|
|
|
|
3060
|
|
|
|
|
|
|
delete $win->{save_box} ; |
3061
|
|
|
|
|
|
|
|
3062
|
|
|
|
|
|
|
if( exists $win->{eval_window} ) { |
3063
|
|
|
|
|
|
|
$eval_saved_text = $win->{eval_text}->get('0.0', 'end') ; |
3064
|
|
|
|
|
|
|
} |
3065
|
|
|
|
|
|
|
else { |
3066
|
|
|
|
|
|
|
$eval_saved_text = $win->{eval_saved_text} ; |
3067
|
|
|
|
|
|
|
} |
3068
|
|
|
|
|
|
|
|
3069
|
|
|
|
|
|
|
$files = &DB::breakpoints_to_save(); |
3070
|
|
|
|
|
|
|
|
3071
|
|
|
|
|
|
|
$d = Data::Dumper->new( [ $files, $win->{'expr_list'}, $eval_saved_text, $main_win_geometry ], |
3072
|
|
|
|
|
|
|
[ "files", "expr_list", "eval_saved_text", "main_win_geometry"] ) ; |
3073
|
|
|
|
|
|
|
$d->Purity(1) ; |
3074
|
|
|
|
|
|
|
|
3075
|
|
|
|
|
|
|
local(*F) ; |
3076
|
|
|
|
|
|
|
eval { |
3077
|
|
|
|
|
|
|
open F, ">$saveName" || die "Couldn't open file $saveName" ; |
3078
|
|
|
|
|
|
|
print F $d->Dump() || die "Couldn't write file" ; |
3079
|
|
|
|
|
|
|
close F ; |
3080
|
|
|
|
|
|
|
}; |
3081
|
|
|
|
|
|
|
$win->DoAlert($@) if $@ ; |
3082
|
|
|
|
|
|
|
}; # end of save sub |
3083
|
|
|
|
|
|
|
|
3084
|
|
|
|
|
|
|
$cancelSub = sub { |
3085
|
|
|
|
|
|
|
delete $win->{'save_box'} |
3086
|
|
|
|
|
|
|
} ; # end of cancel sub |
3087
|
|
|
|
|
|
|
|
3088
|
|
|
|
|
|
|
# |
3089
|
|
|
|
|
|
|
# Create a dialog |
3090
|
|
|
|
|
|
|
# |
3091
|
|
|
|
|
|
|
|
3092
|
|
|
|
|
|
|
$win->{'save_box'} = $win->simplePromptBox("Save Config?", $saveName, $saveSub, $cancelSub) ; |
3093
|
|
|
|
|
|
|
|
3094
|
|
|
|
|
|
|
} # end of SaveState |
3095
|
|
|
|
|
|
|
|
3096
|
|
|
|
|
|
|
sub RestoreState { |
3097
|
|
|
|
|
|
|
my $restoreSub = sub { |
3098
|
|
|
|
|
|
|
$DB::window->restoreStateFile($Devel::tcltkdb::promptString); |
3099
|
|
|
|
|
|
|
}; |
3100
|
|
|
|
|
|
|
$DB::window->simplePromptBox("Restore Config?", makeFileSaveName($DB::startupFname), $restoreSub) ; |
3101
|
|
|
|
|
|
|
} # end of RestoreState |
3102
|
|
|
|
|
|
|
|
3103
|
|
|
|
|
|
|
sub SetStepOverBreakPoint { |
3104
|
|
|
|
|
|
|
my ($offset) = @_ ; |
3105
|
|
|
|
|
|
|
$DB::step_over_depth = $DB::subroutine_depth + ($offset ? $offset : 0) ; |
3106
|
|
|
|
|
|
|
} # end of SetStepOverBreakPoint |
3107
|
|
|
|
|
|
|
|
3108
|
|
|
|
|
|
|
# |
3109
|
|
|
|
|
|
|
# NOTE: It may be logical and somewhat more economical |
3110
|
|
|
|
|
|
|
# lines of codewise to set $DB::step_over_depth_saved |
3111
|
|
|
|
|
|
|
# when we enter the subroutine, but this gets called |
3112
|
|
|
|
|
|
|
# for EVERY callable line of code in a program that |
3113
|
|
|
|
|
|
|
# is being debugged, so we try to save every line of |
3114
|
|
|
|
|
|
|
# execution that we can. |
3115
|
|
|
|
|
|
|
# |
3116
|
|
|
|
|
|
|
sub isBreakPoint { |
3117
|
|
|
|
|
|
|
my ($fname, $line, $package) = @_ ; |
3118
|
|
|
|
|
|
|
|
3119
|
|
|
|
|
|
|
if ( $DB::single && ($DB::step_over_depth < $DB::subroutine_depth) && ($DB::step_over_depth > 0) && !$DB::on) { |
3120
|
|
|
|
|
|
|
$DB::single = 0 ; |
3121
|
|
|
|
|
|
|
return 0 ; |
3122
|
|
|
|
|
|
|
} |
3123
|
|
|
|
|
|
|
# |
3124
|
|
|
|
|
|
|
# doing a step over/in |
3125
|
|
|
|
|
|
|
# |
3126
|
|
|
|
|
|
|
|
3127
|
|
|
|
|
|
|
if( $DB::single || $DB::signal ) { |
3128
|
|
|
|
|
|
|
$DB::single = 0 ; |
3129
|
|
|
|
|
|
|
$DB::signal = 0 ; |
3130
|
|
|
|
|
|
|
$DB::subroutine_depth = $DB::subroutine_depth ; |
3131
|
|
|
|
|
|
|
return 1 ; |
3132
|
|
|
|
|
|
|
} |
3133
|
|
|
|
|
|
|
# |
3134
|
|
|
|
|
|
|
# 1st Check to see if there is even a breakpoint there. |
3135
|
|
|
|
|
|
|
# 2nd If there is a breakpoint check to see if it's check box control is 'on' |
3136
|
|
|
|
|
|
|
# 3rd If there is any kind of expression, evaluate it and see if it's true. |
3137
|
|
|
|
|
|
|
# |
3138
|
|
|
|
|
|
|
my $brkPt = &DB::getdbline($fname, $line) ; |
3139
|
|
|
|
|
|
|
|
3140
|
|
|
|
|
|
|
return 0 if( !$brkPt || !$brkPt->{'value'} || !breakPointEvalExpr($brkPt, $package) ) ; |
3141
|
|
|
|
|
|
|
|
3142
|
|
|
|
|
|
|
&DB::cleardbline($fname, $line) if( $brkPt->{'type'} eq 'temp' ) ; |
3143
|
|
|
|
|
|
|
|
3144
|
|
|
|
|
|
|
$DB::subroutine_depth = $DB::subroutine_depth ; |
3145
|
|
|
|
|
|
|
|
3146
|
|
|
|
|
|
|
return 1 ; |
3147
|
|
|
|
|
|
|
} # end of isBreakPoint |
3148
|
|
|
|
|
|
|
|
3149
|
|
|
|
|
|
|
# |
3150
|
|
|
|
|
|
|
# Check the breakpoint expression to see if it is true. |
3151
|
|
|
|
|
|
|
# |
3152
|
|
|
|
|
|
|
sub breakPointEvalExpr { |
3153
|
|
|
|
|
|
|
my ($brkPt, $package) = @_ ; |
3154
|
|
|
|
|
|
|
my (@result) ; |
3155
|
|
|
|
|
|
|
|
3156
|
|
|
|
|
|
|
return 1 unless $brkPt->{expr} ; # return if there is no expression |
3157
|
|
|
|
|
|
|
|
3158
|
|
|
|
|
|
|
no strict ; |
3159
|
|
|
|
|
|
|
@result = &DB::dbeval($package, $brkPt->{'expr'}) ; |
3160
|
|
|
|
|
|
|
use strict ; |
3161
|
|
|
|
|
|
|
|
3162
|
|
|
|
|
|
|
$DB::window->DoAlert($@) if $@ ; |
3163
|
|
|
|
|
|
|
|
3164
|
|
|
|
|
|
|
return $result[0] or @result ; # we could have a case where the 1st element is undefined |
3165
|
|
|
|
|
|
|
# but subsequent elements are defined |
3166
|
|
|
|
|
|
|
|
3167
|
|
|
|
|
|
|
} # end of breakPointEvalExpr |
3168
|
|
|
|
|
|
|
|
3169
|
|
|
|
|
|
|
# |
3170
|
|
|
|
|
|
|
# Evaluate the given expression, return the result. |
3171
|
|
|
|
|
|
|
# MUST BE CALLED from within DB::DB in order for it |
3172
|
|
|
|
|
|
|
# to properly interpret the vars |
3173
|
|
|
|
|
|
|
# |
3174
|
|
|
|
|
|
|
sub dbeval { |
3175
|
|
|
|
|
|
|
my($ptkdb__package, $ptkdb__expr) = @_ ; |
3176
|
|
|
|
|
|
|
my(@ptkdb__result, $ptkdb__str) ; |
3177
|
|
|
|
|
|
|
my(@ptkdb_args) ; |
3178
|
|
|
|
|
|
|
local($^W) = 0 ; # temporarily turn off warnings |
3179
|
|
|
|
|
|
|
|
3180
|
|
|
|
|
|
|
no strict ; |
3181
|
|
|
|
|
|
|
# |
3182
|
|
|
|
|
|
|
# This substitution is done so that |
3183
|
|
|
|
|
|
|
# we return HASH, as opposed to an ARRAY. |
3184
|
|
|
|
|
|
|
# An expression of %hash results in a |
3185
|
|
|
|
|
|
|
# list of key/value pairs. |
3186
|
|
|
|
|
|
|
# |
3187
|
|
|
|
|
|
|
|
3188
|
|
|
|
|
|
|
$ptkdb__expr =~ s/^\s*%/\\%/; |
3189
|
|
|
|
|
|
|
|
3190
|
|
|
|
|
|
|
@_ = @DB::saved_args ; # replace @_ arg array with what we came in with |
3191
|
|
|
|
|
|
|
|
3192
|
|
|
|
|
|
|
@ptkdb__result = eval <<__EVAL__ ; |
3193
|
|
|
|
|
|
|
|
3194
|
|
|
|
|
|
|
|
3195
|
|
|
|
|
|
|
\$\@ = \$DB::save_err ; |
3196
|
|
|
|
|
|
|
|
3197
|
|
|
|
|
|
|
package $ptkdb__package; |
3198
|
|
|
|
|
|
|
|
3199
|
|
|
|
|
|
|
$ptkdb__expr; |
3200
|
|
|
|
|
|
|
|
3201
|
|
|
|
|
|
|
__EVAL__ |
3202
|
|
|
|
|
|
|
|
3203
|
|
|
|
|
|
|
@ptkdb__result = ("ERROR ($@)") if $@ ; |
3204
|
|
|
|
|
|
|
|
3205
|
|
|
|
|
|
|
use strict ; |
3206
|
|
|
|
|
|
|
|
3207
|
|
|
|
|
|
|
return @ptkdb__result ; |
3208
|
|
|
|
|
|
|
} # end of dbeval |
3209
|
|
|
|
|
|
|
|
3210
|
|
|
|
|
|
|
# |
3211
|
|
|
|
|
|
|
# Call back we give to our 'quit' button |
3212
|
|
|
|
|
|
|
# and binding to the WM_DELETE_WINDOW protocol |
3213
|
|
|
|
|
|
|
# to quit the debugger. |
3214
|
|
|
|
|
|
|
# |
3215
|
|
|
|
|
|
|
sub dbexit { |
3216
|
|
|
|
|
|
|
print STDERR "dbexit\n"; |
3217
|
|
|
|
|
|
|
exit ; |
3218
|
|
|
|
|
|
|
} # end of dbexit |
3219
|
|
|
|
|
|
|
|
3220
|
|
|
|
|
|
|
# |
3221
|
|
|
|
|
|
|
# This is the primary entry point for the debugger. When a perl program |
3222
|
|
|
|
|
|
|
# is parsed with the -d(in our case -d:tcltkdb) option set the parser will |
3223
|
|
|
|
|
|
|
# insert a call to DB::DB in front of every excecutable statement. |
3224
|
|
|
|
|
|
|
# |
3225
|
|
|
|
|
|
|
# Refs: Progamming Perl 2nd Edition, Larry Wall, O'Reilly & Associates, Chapter 8 |
3226
|
|
|
|
|
|
|
# |
3227
|
|
|
|
|
|
|
|
3228
|
|
|
|
|
|
|
sub DB { |
3229
|
|
|
|
|
|
|
@DB::saved_args = @_ ; # save arg context |
3230
|
|
|
|
|
|
|
$DB::save_err = $@ ; # save value of $@ |
3231
|
|
|
|
|
|
|
my ($package, $filename, $line) = caller ; |
3232
|
|
|
|
|
|
|
|
3233
|
|
|
|
|
|
|
unless( $isInitialized ) { |
3234
|
|
|
|
|
|
|
return if( $filename ne $0 ) ; # not in our target file |
3235
|
|
|
|
|
|
|
&DB::Initialize($filename) ; |
3236
|
|
|
|
|
|
|
} |
3237
|
|
|
|
|
|
|
|
3238
|
|
|
|
|
|
|
if (!isBreakPoint($filename, $line, $package) ) { |
3239
|
|
|
|
|
|
|
$DB::single = 0; |
3240
|
|
|
|
|
|
|
$@ = $DB::save_err; |
3241
|
|
|
|
|
|
|
return; |
3242
|
|
|
|
|
|
|
} |
3243
|
|
|
|
|
|
|
|
3244
|
|
|
|
|
|
|
if ( !$DB::window ) { # not setup yet |
3245
|
|
|
|
|
|
|
$@ = $DB::save_err; |
3246
|
|
|
|
|
|
|
return; |
3247
|
|
|
|
|
|
|
} |
3248
|
|
|
|
|
|
|
|
3249
|
|
|
|
|
|
|
$DB::window->setup_main_window() unless $DB::window->{'main_window'} ; |
3250
|
|
|
|
|
|
|
|
3251
|
|
|
|
|
|
|
$DB::window->EnterActions() ; |
3252
|
|
|
|
|
|
|
|
3253
|
|
|
|
|
|
|
my ($saveP) = $^P; |
3254
|
|
|
|
|
|
|
$^P = 0 ; |
3255
|
|
|
|
|
|
|
|
3256
|
|
|
|
|
|
|
$DB::on = 1 ; |
3257
|
|
|
|
|
|
|
|
3258
|
|
|
|
|
|
|
# |
3259
|
|
|
|
|
|
|
# The user can specify this variable in one of the startup files, |
3260
|
|
|
|
|
|
|
# this will make the debugger run right after startup without |
3261
|
|
|
|
|
|
|
# the user having to press the 'run' button. |
3262
|
|
|
|
|
|
|
# |
3263
|
|
|
|
|
|
|
if( $DB::no_stop_at_start ) { |
3264
|
|
|
|
|
|
|
$DB::no_stop_at_start = 0 ; |
3265
|
|
|
|
|
|
|
$DB::on = 0 ; |
3266
|
|
|
|
|
|
|
$@ = $DB::save_err ; |
3267
|
|
|
|
|
|
|
return ; |
3268
|
|
|
|
|
|
|
} |
3269
|
|
|
|
|
|
|
|
3270
|
|
|
|
|
|
|
if( !$DB::sigint_disable ) { |
3271
|
|
|
|
|
|
|
$SIG{'INT'} = $DB::dbint_handler_save if $DB::dbint_handler_save ; # restore original signal handler |
3272
|
|
|
|
|
|
|
$SIG{'INT'} = "DB::dbexit" unless $DB::dbint_handler_save ; |
3273
|
|
|
|
|
|
|
} |
3274
|
|
|
|
|
|
|
|
3275
|
|
|
|
|
|
|
#$DB::window->{main_window}->raise() ; # bring us to the top make sure OUR event loop runs |
3276
|
|
|
|
|
|
|
$DB::window->{main_window}->focus() ; |
3277
|
|
|
|
|
|
|
|
3278
|
|
|
|
|
|
|
$DB::window->set_file($filename, $line) ; |
3279
|
|
|
|
|
|
|
# |
3280
|
|
|
|
|
|
|
# Refresh the exprs to see if anything has changed |
3281
|
|
|
|
|
|
|
# |
3282
|
|
|
|
|
|
|
updateExprs($package) ; |
3283
|
|
|
|
|
|
|
|
3284
|
|
|
|
|
|
|
# |
3285
|
|
|
|
|
|
|
# Update subs Page if necessary |
3286
|
|
|
|
|
|
|
# |
3287
|
|
|
|
|
|
|
my $cnt = scalar keys %DB::sub ; |
3288
|
|
|
|
|
|
|
if ( $cnt != $DB::window->{'subs_list_cnt'} && $DB::window->{'subs_page_activated'} ) { |
3289
|
|
|
|
|
|
|
$DB::window->fill_subs_page(); |
3290
|
|
|
|
|
|
|
$DB::window->{'subs_list_cnt'} = $cnt; |
3291
|
|
|
|
|
|
|
} |
3292
|
|
|
|
|
|
|
# |
3293
|
|
|
|
|
|
|
# Update the subroutine stack menu |
3294
|
|
|
|
|
|
|
# |
3295
|
|
|
|
|
|
|
$DB::window->refresh_stack_menu() ; |
3296
|
|
|
|
|
|
|
$DB::window->{run_flag} = 1 ; |
3297
|
|
|
|
|
|
|
|
3298
|
|
|
|
|
|
|
my ($evt, @result, $r) ; |
3299
|
|
|
|
|
|
|
|
3300
|
|
|
|
|
|
|
for( ; ; ) { |
3301
|
|
|
|
|
|
|
# |
3302
|
|
|
|
|
|
|
# we wait here for something to do |
3303
|
|
|
|
|
|
|
# |
3304
|
|
|
|
|
|
|
$evt = $DB::window->main_loop() ; |
3305
|
|
|
|
|
|
|
|
3306
|
|
|
|
|
|
|
last if( $evt eq 'step' ) ; |
3307
|
|
|
|
|
|
|
|
3308
|
|
|
|
|
|
|
$DB::single = 0 if ($evt eq 'run' ) ; |
3309
|
|
|
|
|
|
|
|
3310
|
|
|
|
|
|
|
if ($evt eq 'balloon_eval' ) { |
3311
|
|
|
|
|
|
|
$DB::window->code_motion_eval(&DB::dbeval($package, $DB::window->{'balloon_expr'})) ; |
3312
|
|
|
|
|
|
|
next ; |
3313
|
|
|
|
|
|
|
} |
3314
|
|
|
|
|
|
|
|
3315
|
|
|
|
|
|
|
if ( $evt eq 'qexpr' ) { |
3316
|
|
|
|
|
|
|
@result = &DB::dbeval($package, $DB::window->{'qexpr'}) ; |
3317
|
|
|
|
|
|
|
$DB::window->{'quick_entry'}->delete(0, 'end') ; # clear old text |
3318
|
|
|
|
|
|
|
$DB::window->{'quick_dumper'}->Reset() ; |
3319
|
|
|
|
|
|
|
$DB::window->{'quick_dumper'}->Values( [ $#result == 0 ? @result : \@result ] ) ; |
3320
|
|
|
|
|
|
|
$DB::window->{'quick_entry'}->insert(0, $DB::window->{'quick_dumper'}->Dump()); |
3321
|
|
|
|
|
|
|
$DB::window->{'quick_entry'}->selectionRange(0, 'end') ; # select it |
3322
|
|
|
|
|
|
|
$evt = 'update' ; # force an update on the expressions |
3323
|
|
|
|
|
|
|
} |
3324
|
|
|
|
|
|
|
|
3325
|
|
|
|
|
|
|
if( $evt eq 'expr' ) { |
3326
|
|
|
|
|
|
|
# |
3327
|
|
|
|
|
|
|
# Append the new expression to the list |
3328
|
|
|
|
|
|
|
# but first check to make sure that we don't already have it. |
3329
|
|
|
|
|
|
|
# |
3330
|
|
|
|
|
|
|
|
3331
|
|
|
|
|
|
|
if ( grep $_->{'expr'} eq $DB::window->{'expr'}, @{$DB::window->{'expr_list'}} ) { |
3332
|
|
|
|
|
|
|
$DB::window->DoAlert("$DB::window->{'expr'} is already listed") ; |
3333
|
|
|
|
|
|
|
next ; |
3334
|
|
|
|
|
|
|
} |
3335
|
|
|
|
|
|
|
|
3336
|
|
|
|
|
|
|
@result = &DB::dbeval($package, $DB::window->{expr}) ; |
3337
|
|
|
|
|
|
|
my $rr = (@result == 1? $result[0] : \@result); |
3338
|
|
|
|
|
|
|
$r = $DB::window->insertExpr([ $rr ], $rr, $DB::window->{'expr'}, -1,'root') ; |
3339
|
|
|
|
|
|
|
|
3340
|
|
|
|
|
|
|
# |
3341
|
|
|
|
|
|
|
# $r will be 1 if the expression was added succesfully, 0 if not, |
3342
|
|
|
|
|
|
|
# and it if wasn't added sucessfully it won't be reevalled the |
3343
|
|
|
|
|
|
|
# next time through. |
3344
|
|
|
|
|
|
|
# |
3345
|
|
|
|
|
|
|
push @{$DB::window->{'expr_list'}}, { 'expr' => $DB::window->{'expr'}, 'depth' => -1 } if $r; |
3346
|
|
|
|
|
|
|
|
3347
|
|
|
|
|
|
|
next; |
3348
|
|
|
|
|
|
|
} |
3349
|
|
|
|
|
|
|
if( $evt eq 'update' ) { |
3350
|
|
|
|
|
|
|
updateExprs($package); |
3351
|
|
|
|
|
|
|
next; |
3352
|
|
|
|
|
|
|
} |
3353
|
|
|
|
|
|
|
if( $evt eq 'reeval' ) { |
3354
|
|
|
|
|
|
|
# |
3355
|
|
|
|
|
|
|
# Reevaluate the contents of the expression eval window |
3356
|
|
|
|
|
|
|
my $txt = $DB::window->{'eval_text'}->get('1.0', 'end') ; |
3357
|
|
|
|
|
|
|
my @result = &DB::dbeval($package, $txt) ; |
3358
|
|
|
|
|
|
|
|
3359
|
|
|
|
|
|
|
$DB::window->updateEvalWindow(@result) ; |
3360
|
|
|
|
|
|
|
|
3361
|
|
|
|
|
|
|
next ; |
3362
|
|
|
|
|
|
|
} |
3363
|
|
|
|
|
|
|
last ; |
3364
|
|
|
|
|
|
|
} |
3365
|
|
|
|
|
|
|
$^P = $saveP ; |
3366
|
|
|
|
|
|
|
$SIG{'INT'} = "DB::dbint_handler" unless $DB::sigint_disable ; # set our signal handler |
3367
|
|
|
|
|
|
|
|
3368
|
|
|
|
|
|
|
$DB::window->LeaveActions() ; |
3369
|
|
|
|
|
|
|
|
3370
|
|
|
|
|
|
|
$@ = $DB::save_err ; |
3371
|
|
|
|
|
|
|
$DB::on = 0 ; |
3372
|
|
|
|
|
|
|
} # end of DB |
3373
|
|
|
|
|
|
|
|
3374
|
|
|
|
|
|
|
## |
3375
|
|
|
|
|
|
|
## in this case we do not use local($^W) since we would like warnings |
3376
|
|
|
|
|
|
|
## to be issued past this point, and the localized copy of $^W will not |
3377
|
|
|
|
|
|
|
## go out of scope until the end of compilation |
3378
|
|
|
|
|
|
|
## |
3379
|
|
|
|
|
|
|
## |
3380
|
|
|
|
|
|
|
|
3381
|
|
|
|
|
|
|
# |
3382
|
|
|
|
|
|
|
# This is another place where we'll try and keep the |
3383
|
|
|
|
|
|
|
# code as 'lite' as possible to prevent the debugger |
3384
|
|
|
|
|
|
|
# from slowing down the user's application |
3385
|
|
|
|
|
|
|
# |
3386
|
|
|
|
|
|
|
# When a perl program is parsed with the -d(in our case a -d:tcltkdb) option |
3387
|
|
|
|
|
|
|
# the parser will route all subroutine calls through here, setting $DB::sub |
3388
|
|
|
|
|
|
|
# to the name of the subroutine to be called, leaving it to the debugger to |
3389
|
|
|
|
|
|
|
# make the actual subroutine call and do any pre or post processing it may |
3390
|
|
|
|
|
|
|
# need to do. In our case we take the opportunity to track the depth of the call |
3391
|
|
|
|
|
|
|
# stack so that we can update our 'Stack' menu when we stop. |
3392
|
|
|
|
|
|
|
# |
3393
|
|
|
|
|
|
|
# Refs: Progamming Perl 2nd Edition, Larry Wall, O'Reilly & Associates, Chapter 8 |
3394
|
|
|
|
|
|
|
# |
3395
|
|
|
|
|
|
|
# |
3396
|
|
|
|
|
|
|
sub sub { |
3397
|
|
|
|
|
|
|
my ($result, @result) ; |
3398
|
|
|
|
|
|
|
# |
3399
|
|
|
|
|
|
|
# See NOTES(1) |
3400
|
|
|
|
|
|
|
# |
3401
|
|
|
|
|
|
|
$DB::subroutine_depth += 1 unless $DB::on ; |
3402
|
|
|
|
|
|
|
$DB::single = 0 if ( ($DB::step_over_depth < $DB::subroutine_depth) && ($DB::step_over_depth >= 0) && !$DB::on) ; |
3403
|
|
|
|
|
|
|
|
3404
|
|
|
|
|
|
|
if( wantarray ) { |
3405
|
|
|
|
|
|
|
# array context |
3406
|
|
|
|
|
|
|
|
3407
|
|
|
|
|
|
|
no strict ; # otherwise perl gripes about calling the sub by the reference |
3408
|
|
|
|
|
|
|
@result = &$DB::sub ; # call the subroutine by name |
3409
|
|
|
|
|
|
|
use strict ; |
3410
|
|
|
|
|
|
|
|
3411
|
|
|
|
|
|
|
$DB::subroutine_depth -= 1 unless $DB::on ; |
3412
|
|
|
|
|
|
|
$DB::single = 1 if ($DB::step_over_depth >= $DB::subroutine_depth && !$DB::on); |
3413
|
|
|
|
|
|
|
return @result; |
3414
|
|
|
|
|
|
|
|
3415
|
|
|
|
|
|
|
} elsif(defined wantarray) { |
3416
|
|
|
|
|
|
|
# scalar context |
3417
|
|
|
|
|
|
|
|
3418
|
|
|
|
|
|
|
no strict; |
3419
|
|
|
|
|
|
|
$result = &$DB::sub; |
3420
|
|
|
|
|
|
|
use strict; |
3421
|
|
|
|
|
|
|
|
3422
|
|
|
|
|
|
|
$DB::subroutine_depth -= 1 unless $DB::on; |
3423
|
|
|
|
|
|
|
$DB::single = 1 if ($DB::step_over_depth >= $DB::subroutine_depth && !$DB::on); |
3424
|
|
|
|
|
|
|
return $result; |
3425
|
|
|
|
|
|
|
|
3426
|
|
|
|
|
|
|
} else { |
3427
|
|
|
|
|
|
|
# void context |
3428
|
|
|
|
|
|
|
|
3429
|
|
|
|
|
|
|
no strict; |
3430
|
|
|
|
|
|
|
&$DB::sub; |
3431
|
|
|
|
|
|
|
use strict; |
3432
|
|
|
|
|
|
|
|
3433
|
|
|
|
|
|
|
$DB::subroutine_depth -= 1 unless $DB::on ; |
3434
|
|
|
|
|
|
|
$DB::single = 1 if ($DB::step_over_depth >= $DB::subroutine_depth && !$DB::on); |
3435
|
|
|
|
|
|
|
return; |
3436
|
|
|
|
|
|
|
|
3437
|
|
|
|
|
|
|
} |
3438
|
|
|
|
|
|
|
|
3439
|
|
|
|
|
|
|
} # end of sub |
3440
|
|
|
|
|
|
|
|
3441
|
|
|
|
|
|
|
1; # return true value |
3442
|
|
|
|
|
|
|
|