line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# vi: set autoindent shiftwidth=4 tabstop=8 softtabstop=4 expandtab: |
2
|
|
|
|
|
|
|
package DB; |
3
|
|
|
|
|
|
|
|
4
|
1
|
|
|
1
|
|
21695
|
use 5.006001; |
|
1
|
|
|
|
|
3
|
|
5
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
28
|
|
6
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
33
|
|
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
5
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
85
|
|
9
|
1
|
|
|
1
|
|
8
|
use B qw(svref_2object comppadlist class); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
66
|
|
10
|
1
|
|
|
1
|
|
17221
|
use B::Showlex; |
|
1
|
|
|
|
|
21166
|
|
|
1
|
|
|
|
|
31
|
|
11
|
1
|
|
|
1
|
|
451
|
use Curses; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use Curses::UI; |
13
|
|
|
|
|
|
|
use Curses::UI::Common; |
14
|
|
|
|
|
|
|
use Data::Dumper; |
15
|
|
|
|
|
|
|
use Cwd; |
16
|
|
|
|
|
|
|
use File::Basename; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use Devel::PDB::Source; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
use vars qw(*dbline $usercontext $db_stop $ini_warn); |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
our $VERSION = '1.6'; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
our $single; |
25
|
|
|
|
|
|
|
our $sub; |
26
|
|
|
|
|
|
|
our $trace; |
27
|
|
|
|
|
|
|
our $signal; |
28
|
|
|
|
|
|
|
our $stack_depth; |
29
|
|
|
|
|
|
|
our @stack; |
30
|
|
|
|
|
|
|
our $current_sub; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
my @compiled; |
33
|
|
|
|
|
|
|
my $inited = 0; |
34
|
|
|
|
|
|
|
my $cui; |
35
|
|
|
|
|
|
|
my $sv_win; |
36
|
|
|
|
|
|
|
my $sv; |
37
|
|
|
|
|
|
|
my $exit = 0; |
38
|
|
|
|
|
|
|
my $db_exit = 0; |
39
|
|
|
|
|
|
|
my $yield; |
40
|
|
|
|
|
|
|
my %sources; |
41
|
|
|
|
|
|
|
my $new_single; |
42
|
|
|
|
|
|
|
my $current_source; |
43
|
|
|
|
|
|
|
my $evalarg; |
44
|
|
|
|
|
|
|
my $package; |
45
|
|
|
|
|
|
|
my $filename; |
46
|
|
|
|
|
|
|
my $line; |
47
|
|
|
|
|
|
|
my @watch_exprs; |
48
|
|
|
|
|
|
|
my $update_watch_list; |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
my $std_file_win; |
51
|
|
|
|
|
|
|
my $std_file; |
52
|
|
|
|
|
|
|
my $help_win; |
53
|
|
|
|
|
|
|
my $help; |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
my $lower_win; |
56
|
|
|
|
|
|
|
my $auto_win; |
57
|
|
|
|
|
|
|
my $watch_win; |
58
|
|
|
|
|
|
|
my $padvar_list; |
59
|
|
|
|
|
|
|
my $watch_list; |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
my $padlist_scope; |
62
|
|
|
|
|
|
|
my %padlist; |
63
|
|
|
|
|
|
|
my @padlist_disp; |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
my $stdout; |
66
|
|
|
|
|
|
|
my $stderr; |
67
|
|
|
|
|
|
|
my $output; |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
my $user_conf_readed = 0; |
70
|
|
|
|
|
|
|
my $ui_window_focused = 0; |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
$trace = $signal = $single = 0; |
73
|
|
|
|
|
|
|
$stack_depth = 0; |
74
|
|
|
|
|
|
|
@stack = (0); |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
my %def_style = ( |
77
|
|
|
|
|
|
|
-bg => 'white', |
78
|
|
|
|
|
|
|
-fg => 'blue', |
79
|
|
|
|
|
|
|
-bbg => 'blue', |
80
|
|
|
|
|
|
|
-bfg => 'white', |
81
|
|
|
|
|
|
|
-tbg => 'white', |
82
|
|
|
|
|
|
|
-tfg => 'blue', |
83
|
|
|
|
|
|
|
); |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# |
86
|
|
|
|
|
|
|
# Set or return window colour style |
87
|
|
|
|
|
|
|
# |
88
|
|
|
|
|
|
|
sub window_style { |
89
|
|
|
|
|
|
|
if (@_) { |
90
|
|
|
|
|
|
|
my %h = @_; |
91
|
|
|
|
|
|
|
while (my ($k, $v) = each %h) { |
92
|
|
|
|
|
|
|
$def_style{$k} = $v if ($k =~ /^-[tbs]?[fb]g$/); |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
return %def_style; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
BEGIN { |
99
|
|
|
|
|
|
|
$Devel::PDB::scriptName = $0; |
100
|
|
|
|
|
|
|
@Devel::PDB::script_args = @ARGV; # copy args |
101
|
|
|
|
|
|
|
$ini_warn = $^W; |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# This is the flag that says "a debugger is running, please call |
104
|
|
|
|
|
|
|
# DB::DB and DB::sub". We will turn it on forcibly before we try to |
105
|
|
|
|
|
|
|
# execute anything in the user's context, because we always want to |
106
|
|
|
|
|
|
|
# get control back. |
107
|
|
|
|
|
|
|
$db_stop = 0; # Compiler warning ... |
108
|
|
|
|
|
|
|
$db_stop = 1 << 30; # ... because this is only used in an eval() later. |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
END { |
112
|
|
|
|
|
|
|
open STDOUT, ">>&", $stdout if $stdout; |
113
|
|
|
|
|
|
|
$single = 0; |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# Save actual breakpoints and watches |
116
|
|
|
|
|
|
|
save_state_file(config_file("conf.rc")); |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
my @ab = ({ |
119
|
|
|
|
|
|
|
-label => '< Quit >', |
120
|
|
|
|
|
|
|
-value => 1, |
121
|
|
|
|
|
|
|
-shortcut => 'q' |
122
|
|
|
|
|
|
|
}, |
123
|
|
|
|
|
|
|
{ -label => '< Show STD* files >', |
124
|
|
|
|
|
|
|
-value => 2, |
125
|
|
|
|
|
|
|
-shortcut => 'f' |
126
|
|
|
|
|
|
|
}, |
127
|
|
|
|
|
|
|
{ -label => '< Restart >', |
128
|
|
|
|
|
|
|
-value => 3, |
129
|
|
|
|
|
|
|
-shortcut => 'r' |
130
|
|
|
|
|
|
|
}, |
131
|
|
|
|
|
|
|
{ -label => '< Save config & Quit >', |
132
|
|
|
|
|
|
|
-value => 4, |
133
|
|
|
|
|
|
|
-shortcut => 's' |
134
|
|
|
|
|
|
|
}, |
135
|
|
|
|
|
|
|
{ -label => '< Save config & Restart >', |
136
|
|
|
|
|
|
|
-value => 'a', |
137
|
|
|
|
|
|
|
-shortcut => 5 |
138
|
|
|
|
|
|
|
}, |
139
|
|
|
|
|
|
|
); |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
my $exitloop = ($db_exit || !$cui) ? 1 : 0; |
142
|
|
|
|
|
|
|
while (!$exitloop) { |
143
|
|
|
|
|
|
|
my $t = $cui->dialog( |
144
|
|
|
|
|
|
|
-title => 'Exiting', |
145
|
|
|
|
|
|
|
-buttons => \@ab, |
146
|
|
|
|
|
|
|
-message => 'Choose one of this functions : ', |
147
|
|
|
|
|
|
|
window_style(), |
148
|
|
|
|
|
|
|
); |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
if ($t == 1) { |
151
|
|
|
|
|
|
|
$exitloop = 1; |
152
|
|
|
|
|
|
|
} elsif ($t == 2) { |
153
|
|
|
|
|
|
|
db_view_std_files(1); |
154
|
|
|
|
|
|
|
} elsif ($t == 3) { |
155
|
|
|
|
|
|
|
DoRestart(); |
156
|
|
|
|
|
|
|
} elsif ($t == 4) { |
157
|
|
|
|
|
|
|
save_state_file(config_file("conf")); |
158
|
|
|
|
|
|
|
$exitloop = 1; |
159
|
|
|
|
|
|
|
} elsif ($t == 5) { |
160
|
|
|
|
|
|
|
save_state_file(config_file("conf")); |
161
|
|
|
|
|
|
|
DoRestart(); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
endwin(); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# |
168
|
|
|
|
|
|
|
# Method for restarting debugger |
169
|
|
|
|
|
|
|
# |
170
|
|
|
|
|
|
|
sub DoRestart { |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# There is problem with Destroyer in Curses::UI |
173
|
|
|
|
|
|
|
endwin(); |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# We must destroyed $cui |
176
|
|
|
|
|
|
|
$cui = undef; |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
my @flags = (); |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# If warn was on before, turn it on again. |
181
|
|
|
|
|
|
|
push @flags, '-w' if $ini_warn; |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# Rebuild the -I flags that were on the initial # command line. |
184
|
|
|
|
|
|
|
my %h_inc = @INC; |
185
|
|
|
|
|
|
|
foreach (split(" ", `perl -e 'print "\@INC";'`)) { |
186
|
|
|
|
|
|
|
delete($h_inc{$_}); |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
foreach (keys %h_inc) { |
190
|
|
|
|
|
|
|
push @flags, '-I', $_; |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# Turn on taint if it was on before. |
194
|
|
|
|
|
|
|
push @flags, '-T' if ${^TAINT}; |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
if ($Devel::PDB::scriptName eq '-e') { |
197
|
|
|
|
|
|
|
my $cl; |
198
|
|
|
|
|
|
|
my $lines = *{$main::{'_<-e'}}{ARRAY}; |
199
|
|
|
|
|
|
|
for (1 .. $#$lines) { # The first line is PERL5DB |
200
|
|
|
|
|
|
|
chomp($cl = $lines->[$_]); |
201
|
|
|
|
|
|
|
push @flags, '-e', $cl; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
} elsif ($Devel::PDB::scriptName !~ /perl/) { |
204
|
|
|
|
|
|
|
push @flags, $Devel::PDB::scriptName; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
# print "$$ doing a restart with $fname\n" ; |
208
|
|
|
|
|
|
|
exec "perl", "-d:PDB", @flags, @Devel::PDB::script_args; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
# |
212
|
|
|
|
|
|
|
# print any error which is put as arguments |
213
|
|
|
|
|
|
|
# |
214
|
|
|
|
|
|
|
sub print_error { |
215
|
|
|
|
|
|
|
$cui->error( |
216
|
|
|
|
|
|
|
-title => "Error", |
217
|
|
|
|
|
|
|
-message => join("\n", @_), |
218
|
|
|
|
|
|
|
DB::window_style(), |
219
|
|
|
|
|
|
|
) if ($cui); |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# |
223
|
|
|
|
|
|
|
# returns true if line is breakable |
224
|
|
|
|
|
|
|
# |
225
|
|
|
|
|
|
|
sub checkdbline($$) { |
226
|
|
|
|
|
|
|
my ($fname, $lineno) = @_; |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
return 0 unless $fname; # we're getting an undef here on 'Restart...' |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
local ($^W) = 0; # spares us warnings under -w |
231
|
|
|
|
|
|
|
local (*dbline) = $main::{'_<' . $fname}; |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
my $flag = $dbline[$lineno] != 0; |
234
|
|
|
|
|
|
|
return $flag; |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
} # end of checkdbline |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
# |
239
|
|
|
|
|
|
|
# sets a breakpoint 'through' a magic |
240
|
|
|
|
|
|
|
# variable that perl is able to interpert |
241
|
|
|
|
|
|
|
# |
242
|
|
|
|
|
|
|
sub setdbline($$$) { |
243
|
|
|
|
|
|
|
my ($fname, $lineno, $value) = @_; |
244
|
|
|
|
|
|
|
local (*dbline) = $main::{'_<' . $fname}; |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
$dbline{$lineno} = $value; |
247
|
|
|
|
|
|
|
} # end of setdbline |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub getdbline($$) { |
250
|
|
|
|
|
|
|
my ($fname, $lineno) = @_; |
251
|
|
|
|
|
|
|
local (*dbline) = $main::{'_<' . $fname}; |
252
|
|
|
|
|
|
|
return $dbline{$lineno}; |
253
|
|
|
|
|
|
|
} # end of getdbline |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub getdbtextline { |
256
|
|
|
|
|
|
|
my ($fname, $lineno) = @_; |
257
|
|
|
|
|
|
|
local (*dbline) = $main::{'_<' . $fname}; |
258
|
|
|
|
|
|
|
return $dbline[$lineno]; |
259
|
|
|
|
|
|
|
} # end of getdbline |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
sub cleardbline($$;&) { |
262
|
|
|
|
|
|
|
my ($fname, $lineno, $clearsub) = @_; |
263
|
|
|
|
|
|
|
local (*dbline) = $main::{'_<' . $fname}; |
264
|
|
|
|
|
|
|
my $value; # just in case we want it for something |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
$value = $dbline{$lineno}; |
267
|
|
|
|
|
|
|
delete $dbline{$lineno}; |
268
|
|
|
|
|
|
|
&$clearsub($value) if $value && $clearsub; |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
return $value; |
271
|
|
|
|
|
|
|
} # end of cleardbline |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub clearalldblines(;&) { |
274
|
|
|
|
|
|
|
my ($clearsub) = @_; |
275
|
|
|
|
|
|
|
my ($key, $value, $brkPt, $dbkey); |
276
|
|
|
|
|
|
|
local (*dbline); |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
while (($key, $value) = each %main::) { # key loop |
279
|
|
|
|
|
|
|
next unless $key =~ /^_; |
280
|
|
|
|
|
|
|
*dbline = $value; |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
foreach $dbkey (keys %dbline) { |
283
|
|
|
|
|
|
|
$brkPt = $dbline{$dbkey}; |
284
|
|
|
|
|
|
|
delete $dbline{$dbkey}; |
285
|
|
|
|
|
|
|
next unless $brkPt && $clearsub; |
286
|
|
|
|
|
|
|
&$clearsub($brkPt); # if specificed, call the sub routine to clear the breakpoint |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
} # end of key loop |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
} # end of clearalldblines |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
sub getdblineindexes { |
294
|
|
|
|
|
|
|
my ($fname) = @_; |
295
|
|
|
|
|
|
|
local (*dbline) = $main::{'_<' . $fname}; |
296
|
|
|
|
|
|
|
return keys %dbline; |
297
|
|
|
|
|
|
|
} # end of getdblineindexes |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
# |
300
|
|
|
|
|
|
|
# Return list of breakpoints from files which are add as arguments |
301
|
|
|
|
|
|
|
# |
302
|
|
|
|
|
|
|
sub getbreakpoints { |
303
|
|
|
|
|
|
|
my (@fnames) = @_; |
304
|
|
|
|
|
|
|
my ($fname, @retList); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
foreach $fname (@fnames) { |
307
|
|
|
|
|
|
|
next unless $main::{'_<' . $fname}; |
308
|
|
|
|
|
|
|
local (*dbline) = $main::{'_<' . $fname}; |
309
|
|
|
|
|
|
|
push @retList, values %dbline; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
return @retList; |
312
|
|
|
|
|
|
|
} # end of getbreakpoints |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
# |
315
|
|
|
|
|
|
|
# Return filename from param and remove _< character from begin |
316
|
|
|
|
|
|
|
# |
317
|
|
|
|
|
|
|
sub retfilename { |
318
|
|
|
|
|
|
|
my $f = shift; |
319
|
|
|
|
|
|
|
$f =~ s/^_/; |
320
|
|
|
|
|
|
|
return $f; |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# |
324
|
|
|
|
|
|
|
# Construct a hash of the files |
325
|
|
|
|
|
|
|
# that have breakpoints to save |
326
|
|
|
|
|
|
|
# |
327
|
|
|
|
|
|
|
sub breakpoints_to_save { |
328
|
|
|
|
|
|
|
my %brkList = (); |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
foreach my $file (keys %main::) { # file loop |
331
|
|
|
|
|
|
|
next unless $file =~ /^_ && exists $main::{$file}; |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
#my @k = getdblineindexes(retfilename($file)); |
334
|
|
|
|
|
|
|
local (*dbline) = $main::{$file}; |
335
|
|
|
|
|
|
|
my @a = (); |
336
|
|
|
|
|
|
|
while (my ($k, $d) = each %dbline) { |
337
|
|
|
|
|
|
|
push(@a, {'line' => $k, 'breakpoint' => $d}) if ($d); |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
$brkList{$file} = \@a if (scalar(@a)); |
340
|
|
|
|
|
|
|
} # end of file loop |
341
|
|
|
|
|
|
|
return \%brkList; |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
} # end of breakpoints_to_save |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
# |
346
|
|
|
|
|
|
|
# When we restore breakpoints from a state file |
347
|
|
|
|
|
|
|
# they've often 'moved' because the file |
348
|
|
|
|
|
|
|
# has been editted. |
349
|
|
|
|
|
|
|
# |
350
|
|
|
|
|
|
|
# We search for the line starting with the original line number, |
351
|
|
|
|
|
|
|
# then we walk it back 20 lines, then with line right after the |
352
|
|
|
|
|
|
|
# orginal line number and walk forward 20 lines. |
353
|
|
|
|
|
|
|
# |
354
|
|
|
|
|
|
|
# NOTE: dbline is expected to be 'local' |
355
|
|
|
|
|
|
|
# when called |
356
|
|
|
|
|
|
|
# |
357
|
|
|
|
|
|
|
sub fix_breakpoints { |
358
|
|
|
|
|
|
|
my (@brkPts) = @_; |
359
|
|
|
|
|
|
|
my ($startLine, $endLine, $nLines, $brkPt); |
360
|
|
|
|
|
|
|
my (@retList); |
361
|
|
|
|
|
|
|
local ($^W) = 0; |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
$nLines = scalar @dbline; |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
foreach $brkPt (@brkPts) { |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
#$startLine = $brkPt->{'line'} > 20 ? $brkPt->{'line'} - 20 : 0 ; |
368
|
|
|
|
|
|
|
#$endLine = $brkPt->{'line'} < $nLines - 20 ? $brkPt->{'line'} + 20 : $nLines ; |
369
|
|
|
|
|
|
|
# |
370
|
|
|
|
|
|
|
#for( (reverse $startLine..$brkPt->{'line'}), $brkPt->{'line'} + 1 .. $endLine ) { |
371
|
|
|
|
|
|
|
# next unless $brkPt->{'text'} eq $dbline[$_] ; |
372
|
|
|
|
|
|
|
# $brkPt->{'line'} = $_ ; |
373
|
|
|
|
|
|
|
# push @retList, $brkPt ; |
374
|
|
|
|
|
|
|
# last ; |
375
|
|
|
|
|
|
|
#} |
376
|
|
|
|
|
|
|
push @retList, $brkPt; |
377
|
|
|
|
|
|
|
} # end of breakpoint list |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
return @retList; |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
} # end of fix_breakpoints |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub set_breakpoints { |
384
|
|
|
|
|
|
|
my ($fname, $newList) = @_; |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
local (*dbline) = $main::{$fname}; |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
my $offset = 0; |
389
|
|
|
|
|
|
|
$offset = 1 if $dbline[1] =~ /use\s+.*Devel::_?PDB/; |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
foreach my $brkPt (@$newList) { |
392
|
|
|
|
|
|
|
if (!checkdbline(retfilename($fname), $brkPt->{'line'} + $offset)) { |
393
|
|
|
|
|
|
|
print_error("Breakpoint $fname:$brkPt->{'line'} in config file is not breakable."); |
394
|
|
|
|
|
|
|
next; |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
#$dbline{$brkPt->{'line'}} = { %$brkPt } ; # make a fresh copy |
398
|
|
|
|
|
|
|
$dbline{$brkPt->{'line'}} = exists($brkPt->{'breakpoint'}) ? $brkPt->{'breakpoint'} : 1; |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
my %postponed_file = (); |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
# |
406
|
|
|
|
|
|
|
# Restore breakpoints saved above |
407
|
|
|
|
|
|
|
# |
408
|
|
|
|
|
|
|
sub restore_breakpoints_from_save { |
409
|
|
|
|
|
|
|
my ($brkList) = @_; |
410
|
|
|
|
|
|
|
my ($key, $list, @newList); |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
while (($key, $list) = each %$brkList) { # reinsert loop |
413
|
|
|
|
|
|
|
$postponed_file{$key} = $list; |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
next unless exists $main::{$key}; |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
@newList = fix_breakpoints(@$list); |
418
|
|
|
|
|
|
|
set_breakpoints($key, \@newList); |
419
|
|
|
|
|
|
|
} # end of reinsert loop |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
} # end of restore_breakpoints_from_save ; |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
# |
424
|
|
|
|
|
|
|
# Loading watches and breakpoint from state file(it is param) |
425
|
|
|
|
|
|
|
# |
426
|
|
|
|
|
|
|
sub load_state_file { |
427
|
|
|
|
|
|
|
my ($fName) = @_; |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
if (-e $fName && -r $fName) { |
430
|
|
|
|
|
|
|
no strict; |
431
|
|
|
|
|
|
|
local ($files, $expr_list); |
432
|
|
|
|
|
|
|
do $fName; |
433
|
|
|
|
|
|
|
if ($@) { |
434
|
|
|
|
|
|
|
print_error($@); |
435
|
|
|
|
|
|
|
} |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
%postponed_file = (); |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
restore_breakpoints_from_save($files); |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
# Don't load saved watches against |
442
|
|
|
|
|
|
|
my %h = map { $_->{name} => 1 } @watch_exprs; |
443
|
|
|
|
|
|
|
foreach $rh (@$expr_list) { |
444
|
|
|
|
|
|
|
push @watch_exprs, {name => $rh->{name}} unless exists($h{$rh->{name}}); |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
$update_watch_list = 1; |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
if ($current_source) { |
449
|
|
|
|
|
|
|
my $view = $current_source->view; |
450
|
|
|
|
|
|
|
$view->intellidraw if (defined $view); |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
} # end of Restore State |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
# |
456
|
|
|
|
|
|
|
# Save watches and breakpoints to state filename(it is param) |
457
|
|
|
|
|
|
|
# |
458
|
|
|
|
|
|
|
sub save_state_file { |
459
|
|
|
|
|
|
|
my ($fname) = @_; |
460
|
|
|
|
|
|
|
my ($files, $d, $saveStr); |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
$files = breakpoints_to_save(); |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
$d = Data::Dumper->new([$files, \@watch_exprs], [qw(files expr_list)]); |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
$d->Indent(1); |
467
|
|
|
|
|
|
|
$d->Purity(1); |
468
|
|
|
|
|
|
|
$d->Terse(0); |
469
|
|
|
|
|
|
|
if (Data::Dumper->can('Dumpxs')) { |
470
|
|
|
|
|
|
|
$saveStr = $d->Dumpxs(); |
471
|
|
|
|
|
|
|
} else { |
472
|
|
|
|
|
|
|
$saveStr = $d->Dump(); |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
local (*F); |
476
|
|
|
|
|
|
|
open F, ">$fname" || die "Couldn't open file $fname"; |
477
|
|
|
|
|
|
|
print F $saveStr || die "Couldn't write file"; |
478
|
|
|
|
|
|
|
close F; |
479
|
|
|
|
|
|
|
} # end of save_state_file |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
my $_log_opened = 0; |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
# |
484
|
|
|
|
|
|
|
# Internal method for printing anything to file |
485
|
|
|
|
|
|
|
# 1. name of text |
486
|
|
|
|
|
|
|
# 2. variable |
487
|
|
|
|
|
|
|
# |
488
|
|
|
|
|
|
|
sub log_dumper { |
489
|
|
|
|
|
|
|
my ($name, $a) = @_; |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
my $fDUMP = config_file("dump"); |
492
|
|
|
|
|
|
|
local (*W); |
493
|
|
|
|
|
|
|
open(W, ($_log_opened ? ">" : "") . ">$fDUMP") |
494
|
|
|
|
|
|
|
or die "Can't open dump file : $fDUMP\n"; |
495
|
|
|
|
|
|
|
$_log_opened = 1; |
496
|
|
|
|
|
|
|
print W "$name"; |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
if ($a) { |
499
|
|
|
|
|
|
|
local $Data::Dumper::Purity = 0; |
500
|
|
|
|
|
|
|
local $Data::Dumper::Terse = 0; |
501
|
|
|
|
|
|
|
local $Data::Dumper::Indent = 2; |
502
|
|
|
|
|
|
|
local $Data::Dumper::Sortkeys = 1; |
503
|
|
|
|
|
|
|
print W Dumper($a); |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
print W "\n"; |
506
|
|
|
|
|
|
|
close(W); |
507
|
|
|
|
|
|
|
} |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
# |
510
|
|
|
|
|
|
|
# UI for exiting |
511
|
|
|
|
|
|
|
# |
512
|
|
|
|
|
|
|
sub ui_db_quit { |
513
|
|
|
|
|
|
|
return |
514
|
|
|
|
|
|
|
if not $cui->dialog( |
515
|
|
|
|
|
|
|
-title => 'Quit Debugger', |
516
|
|
|
|
|
|
|
-buttons => ['yes', 'no'], |
517
|
|
|
|
|
|
|
-message => 'Do you really want to quit?', |
518
|
|
|
|
|
|
|
window_style(), |
519
|
|
|
|
|
|
|
); |
520
|
|
|
|
|
|
|
save_state_file(config_file("conf.rc")); |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
$single = 0; |
523
|
|
|
|
|
|
|
for (my $i = 0; $i <= $stack_depth; ++$i) { |
524
|
|
|
|
|
|
|
$stack[$i] = 0; |
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
$db_exit = 1; |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
#print(STDERR $_, "\n") foreach (@compiled); |
530
|
|
|
|
|
|
|
exit(0); |
531
|
|
|
|
|
|
|
} |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
sub db_cont { |
534
|
|
|
|
|
|
|
$new_single = 0; |
535
|
|
|
|
|
|
|
for (my $i = 0; $i <= $stack_depth; ++$i) { |
536
|
|
|
|
|
|
|
$stack[$i] &= ~1; |
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
$yield = 1; |
539
|
|
|
|
|
|
|
} |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
# |
542
|
|
|
|
|
|
|
# Key for step into method |
543
|
|
|
|
|
|
|
# |
544
|
|
|
|
|
|
|
sub db_step_in { |
545
|
|
|
|
|
|
|
$new_single = 1; |
546
|
|
|
|
|
|
|
$yield = 1; |
547
|
|
|
|
|
|
|
} |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
# |
550
|
|
|
|
|
|
|
# Key for step over - next step |
551
|
|
|
|
|
|
|
# |
552
|
|
|
|
|
|
|
sub db_step_over { |
553
|
|
|
|
|
|
|
$new_single = 2; |
554
|
|
|
|
|
|
|
$yield = 1; |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
# |
558
|
|
|
|
|
|
|
# Key for step from given method |
559
|
|
|
|
|
|
|
# |
560
|
|
|
|
|
|
|
sub db_step_out { |
561
|
|
|
|
|
|
|
$new_single = 0; |
562
|
|
|
|
|
|
|
$stack[-1] &= ~1; |
563
|
|
|
|
|
|
|
$yield = 1; |
564
|
|
|
|
|
|
|
} |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
# |
567
|
|
|
|
|
|
|
# $code is 0 or 1 and $r is ref to error string |
568
|
|
|
|
|
|
|
# 0 - Set breakpoint, If breakpoint exist on given line, than remove |
569
|
|
|
|
|
|
|
# 1 - Set breakpoint with condition |
570
|
|
|
|
|
|
|
# StringRef - Problem with condition in breakpoint, that reedit |
571
|
|
|
|
|
|
|
# |
572
|
|
|
|
|
|
|
sub db_toggle_break { |
573
|
|
|
|
|
|
|
my ($code, $r) = shift; |
574
|
|
|
|
|
|
|
local (*dbline) = $main::{'_<' . $current_source->filename}; |
575
|
|
|
|
|
|
|
$current_source->toggle_break($code, $r); |
576
|
|
|
|
|
|
|
} |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
# |
579
|
|
|
|
|
|
|
# Add watch expression |
580
|
|
|
|
|
|
|
# |
581
|
|
|
|
|
|
|
sub db_add_watch_expr { |
582
|
|
|
|
|
|
|
my $text = shift; |
583
|
|
|
|
|
|
|
my $expr = $cui->question( |
584
|
|
|
|
|
|
|
-question => "Please enter an expression to watches\n" |
585
|
|
|
|
|
|
|
. "Global variables must be set as '\$main::varname'\n" |
586
|
|
|
|
|
|
|
. 'Array or Hash must set as Reference like \@a, otherwise show size', |
587
|
|
|
|
|
|
|
-title => "Add watch expresion", |
588
|
|
|
|
|
|
|
(defined($text) && length($text) ? (-answer => $text) : ()), |
589
|
|
|
|
|
|
|
window_style(), |
590
|
|
|
|
|
|
|
); |
591
|
|
|
|
|
|
|
if (defined($text) && length($text)) { |
592
|
|
|
|
|
|
|
my $pos = -1; |
593
|
|
|
|
|
|
|
for (my $i = 0; $pos == -1 && $i < scalar(@watch_exprs); $i++) { |
594
|
|
|
|
|
|
|
$pos = $i if ($watch_exprs[$i]->{name} eq $text); |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
splice(@watch_exprs, $pos, 1, {name => $expr}) if ($expr && $pos >= 0); |
597
|
|
|
|
|
|
|
} else { |
598
|
|
|
|
|
|
|
return if !$expr; |
599
|
|
|
|
|
|
|
push @watch_exprs, {name => $expr}; |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
$update_watch_list = 1; |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
sub db_edit_watch_expr { |
605
|
|
|
|
|
|
|
my $watch_list = shift; |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
my $id = $watch_list->get_active_id; |
608
|
|
|
|
|
|
|
my $item = $watch_list->{-named_list}->[$id]; |
609
|
|
|
|
|
|
|
db_add_watch_expr($item->{name}); |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
# |
613
|
|
|
|
|
|
|
# List breapoints |
614
|
|
|
|
|
|
|
# |
615
|
|
|
|
|
|
|
sub ui_list_breakpoints { |
616
|
|
|
|
|
|
|
my @a = (); |
617
|
|
|
|
|
|
|
foreach my $file (keys %main::) { # file loop |
618
|
|
|
|
|
|
|
next unless $file =~ /^_ && exists $main::{$file}; |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
local (*dbline) = $main::{$file}; |
621
|
|
|
|
|
|
|
while (my ($k, $d) = each %dbline) { |
622
|
|
|
|
|
|
|
next unless ($d); |
623
|
|
|
|
|
|
|
my $str = retfilename($file) . " line:$k "; |
624
|
|
|
|
|
|
|
if ($d =~ /\0/) { |
625
|
|
|
|
|
|
|
my ($s, $action) = split(/\0/, $d); |
626
|
|
|
|
|
|
|
$str .= "test ( $action )"; |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
push(@a, $str); |
629
|
|
|
|
|
|
|
} |
630
|
|
|
|
|
|
|
} # end of file loop |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
my $filename = $cui->tempdialog( |
633
|
|
|
|
|
|
|
'Devel::PDB::Dialog::FileBrowser', |
634
|
|
|
|
|
|
|
-title => "List all breakpoints", |
635
|
|
|
|
|
|
|
-files => \@a, |
636
|
|
|
|
|
|
|
-its_breakpoints => 1, |
637
|
|
|
|
|
|
|
window_style(), |
638
|
|
|
|
|
|
|
); |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
if ($filename) { |
641
|
|
|
|
|
|
|
my @a1 = split(" ", $filename); |
642
|
|
|
|
|
|
|
my @a2 = split(":", $a1[1]); |
643
|
|
|
|
|
|
|
my $source = $current_source = get_source($a1[0]); |
644
|
|
|
|
|
|
|
if ($source) { |
645
|
|
|
|
|
|
|
$sv->source($source); |
646
|
|
|
|
|
|
|
$sv->goto(int($a2[1]) + 1); |
647
|
|
|
|
|
|
|
} |
648
|
|
|
|
|
|
|
$sv->intellidraw; |
649
|
|
|
|
|
|
|
} else { |
650
|
|
|
|
|
|
|
clearalldblines (); |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
my %h = (); |
653
|
|
|
|
|
|
|
foreach (@a) { |
654
|
|
|
|
|
|
|
my @a1 = split(" "); |
655
|
|
|
|
|
|
|
my @a2 = split(":", $a1[1]); |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
my $fname = '_<' . $a1[0]; |
658
|
|
|
|
|
|
|
$h{$fname} = [] if (!exists($h{$fname})); |
659
|
|
|
|
|
|
|
push(@{$h{$fname}}, {line => $a2[1]}); |
660
|
|
|
|
|
|
|
} |
661
|
|
|
|
|
|
|
restore_breakpoints_from_save(\%h); |
662
|
|
|
|
|
|
|
$update_watch_list = 1; |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
my $view = $current_source->view; |
665
|
|
|
|
|
|
|
$view->intellidraw if (defined $view); |
666
|
|
|
|
|
|
|
} |
667
|
|
|
|
|
|
|
} |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
sub refresh_stack_menu { |
670
|
|
|
|
|
|
|
my ($str, $name, $i, $sub_offset, $subStack); |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
# |
673
|
|
|
|
|
|
|
# CAUTION: In the effort to 'rationalize' the code |
674
|
|
|
|
|
|
|
# are moving some of this function down from DB::DB |
675
|
|
|
|
|
|
|
# to here. $sub_offset represents how far 'down' |
676
|
|
|
|
|
|
|
# we are from DB::DB. The $DB::subroutine_depth is |
677
|
|
|
|
|
|
|
# tracked in such a way that while we are 'in' the debugger |
678
|
|
|
|
|
|
|
# it will not be incremented, and thus represents the stack depth |
679
|
|
|
|
|
|
|
# of the target program. |
680
|
|
|
|
|
|
|
# |
681
|
|
|
|
|
|
|
$sub_offset = 1; |
682
|
|
|
|
|
|
|
$subStack = []; |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
# clear existing entries |
685
|
|
|
|
|
|
|
for ($i = 0; $i <= ($DB::subroutine_depth || 0); $i++) { |
686
|
|
|
|
|
|
|
my @a = caller $i + $sub_offset; |
687
|
|
|
|
|
|
|
my ($package, $filename, $line, $subName) = caller $i + $sub_offset; |
688
|
|
|
|
|
|
|
last if !$subName; |
689
|
|
|
|
|
|
|
push @$subStack, {'name' => $subName, 'pck' => $package, 'filename' => $filename, 'line' => $line}; |
690
|
|
|
|
|
|
|
} |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
#$self->{stack_menu}->menu->delete(0, 'last') ; # delete existing menu items |
693
|
|
|
|
|
|
|
#for( $i = 0 ; $subStack->[$i] ; $i++ ) { |
694
|
|
|
|
|
|
|
# $str = defined $subStack->[$i+1] ? "$subStack->[$i+1]->{name}" : "MAIN" ; |
695
|
|
|
|
|
|
|
# my ($f, $line) = ($subStack->[$i]->{filename}, $subStack->[$i]->{line}) ; # make copies of the values for use in 'sub' |
696
|
|
|
|
|
|
|
# $self->{stack_menu}->command(-label => $str, -command => sub { $self->goto_sub_from_stack($f, $line) ; } ) ; |
697
|
|
|
|
|
|
|
#} |
698
|
|
|
|
|
|
|
} # end of refresh_stack_menu |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
# dump_trace(skip[,count]) |
701
|
|
|
|
|
|
|
# |
702
|
|
|
|
|
|
|
# Actually collect the traceback information available via C. It does |
703
|
|
|
|
|
|
|
# some filtering and cleanup of the data, but mostly it just collects it to |
704
|
|
|
|
|
|
|
# make C's job easier. |
705
|
|
|
|
|
|
|
# |
706
|
|
|
|
|
|
|
# C defines the number of stack frames to be skipped, working backwards |
707
|
|
|
|
|
|
|
# from the most current. C determines the total number of frames to |
708
|
|
|
|
|
|
|
# be returned; all of them (well, the first 10^9) are returned if C |
709
|
|
|
|
|
|
|
# is omitted. |
710
|
|
|
|
|
|
|
# |
711
|
|
|
|
|
|
|
# This routine returns a list of hashes, from most-recent to least-recent |
712
|
|
|
|
|
|
|
# stack frame. Each has the following keys and values: |
713
|
|
|
|
|
|
|
sub dump_trace { |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
# How many levels to skip. |
716
|
|
|
|
|
|
|
my $skip = shift; |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
# How many levels to show. (1e9 is a cheap way of saying "all of them"; |
719
|
|
|
|
|
|
|
# it's unlikely that we'll have more than a billion stack frames. If you |
720
|
|
|
|
|
|
|
# do, you've got an awfully big machine...) |
721
|
|
|
|
|
|
|
my $count = shift || 1e9; |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
# We increment skip because caller(1) is the first level *back* from |
724
|
|
|
|
|
|
|
# the current one. Add $skip to the count of frames so we have a |
725
|
|
|
|
|
|
|
# simple stop criterion, counting from $skip to $count+$skip. |
726
|
|
|
|
|
|
|
$skip++; |
727
|
|
|
|
|
|
|
$count += $skip; |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
# These variables are used to capture output from caller(); |
730
|
|
|
|
|
|
|
my ($p, $file, $line, $sub, $h, $context); |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
my ($e, $r, @a, @sub, $args); |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
#..... |
735
|
|
|
|
|
|
|
my @args = (); |
736
|
|
|
|
|
|
|
our $frame = 0; |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
# XXX Okay... why'd we do that? |
739
|
|
|
|
|
|
|
my $nothard = not $frame & 8; |
740
|
|
|
|
|
|
|
local $frame = 0; |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
# Do not want to trace this. |
743
|
|
|
|
|
|
|
my $otrace = $trace; |
744
|
|
|
|
|
|
|
$trace = 0; |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
# Start out at the skip count. |
747
|
|
|
|
|
|
|
# If we haven't reached the number of frames requested, and caller() is |
748
|
|
|
|
|
|
|
# still returning something, stay in the loop. (If we pass the requested |
749
|
|
|
|
|
|
|
# number of stack frames, or we run out - caller() returns nothing - we |
750
|
|
|
|
|
|
|
# quit. |
751
|
|
|
|
|
|
|
# Up the stack frame index to go back one more level each time. |
752
|
|
|
|
|
|
|
for (my $i = $skip; $i < $count and ($p, $file, $line, $sub, $h, $context, $e, $r) = caller($i); $i++) { |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
# Go through the arguments and save them for later. |
755
|
|
|
|
|
|
|
@a = (); |
756
|
|
|
|
|
|
|
for my $arg (@args) { |
757
|
|
|
|
|
|
|
my $type; |
758
|
|
|
|
|
|
|
if (not defined $arg) { # undefined parameter |
759
|
|
|
|
|
|
|
push @a, "undef"; |
760
|
|
|
|
|
|
|
} |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
elsif ($nothard and tied $arg) { # tied parameter |
763
|
|
|
|
|
|
|
push @a, "tied"; |
764
|
|
|
|
|
|
|
} elsif ($nothard and $type = ref $arg) { # reference |
765
|
|
|
|
|
|
|
push @a, "ref($type)"; |
766
|
|
|
|
|
|
|
} else { # can be stringified |
767
|
|
|
|
|
|
|
local $_ = "$arg"; # Safe to stringify now - should not call f(). |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
# Backslash any single-quotes or backslashes. |
770
|
|
|
|
|
|
|
s/([\'\\])/\\$1/g; |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
# Single-quote it unless it's a number or a colon-separated |
773
|
|
|
|
|
|
|
# name. |
774
|
|
|
|
|
|
|
s/(.*)/'$1'/s |
775
|
|
|
|
|
|
|
unless /^(?: -?[\d.]+ | \*[\w:]* )$/x; |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
# Turn high-bit characters into meta-whatever. |
778
|
|
|
|
|
|
|
s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg; |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
# Turn control characters into ^-whatever. |
781
|
|
|
|
|
|
|
s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg; |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
push(@a, $_); |
784
|
|
|
|
|
|
|
} ## end else [ if (not defined $arg) |
785
|
|
|
|
|
|
|
} ## end for $arg (@args) |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
# If context is true, this is array (@)context. |
788
|
|
|
|
|
|
|
# If context is false, this is scalar ($) context. |
789
|
|
|
|
|
|
|
# If neither, context isn't defined. (This is apparently a 'can't |
790
|
|
|
|
|
|
|
# happen' trap.) |
791
|
|
|
|
|
|
|
$context = $context ? '@' : (defined $context ? "\$" : '.'); |
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
# if the sub has args ($h true), make an anonymous array of the |
794
|
|
|
|
|
|
|
# dumped args. |
795
|
|
|
|
|
|
|
$args = $h ? [@a] : undef; |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
# remove trailing newline-whitespace-semicolon-end of line sequence |
798
|
|
|
|
|
|
|
# from the eval text, if any. |
799
|
|
|
|
|
|
|
$e =~ s/\n\s*\;\s*\Z// if $e; |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
# Escape backslashed single-quotes again if necessary. |
802
|
|
|
|
|
|
|
$e =~ s/([\\\'])/\\$1/g if $e; |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
# if the require flag is true, the eval text is from a require. |
805
|
|
|
|
|
|
|
if ($r) { |
806
|
|
|
|
|
|
|
$sub = "require '$e'"; |
807
|
|
|
|
|
|
|
} |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
# if it's false, the eval text is really from an eval. |
810
|
|
|
|
|
|
|
elsif (defined $r) { |
811
|
|
|
|
|
|
|
$sub = "eval '$e'"; |
812
|
|
|
|
|
|
|
} |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
# If the sub is '(eval)', this is a block eval, meaning we don't |
815
|
|
|
|
|
|
|
# know what the eval'ed text actually was. |
816
|
|
|
|
|
|
|
elsif ($sub eq '(eval)') { |
817
|
|
|
|
|
|
|
$sub = "eval {...}"; |
818
|
|
|
|
|
|
|
} |
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
# Stick the collected information into @sub as an anonymous hash. |
821
|
|
|
|
|
|
|
push( |
822
|
|
|
|
|
|
|
@sub, |
823
|
|
|
|
|
|
|
{ context => $context, |
824
|
|
|
|
|
|
|
sub => $sub, |
825
|
|
|
|
|
|
|
args => $args, |
826
|
|
|
|
|
|
|
file => $file, |
827
|
|
|
|
|
|
|
line => $line |
828
|
|
|
|
|
|
|
}); |
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
# Stop processing frames if the user hit control-C. |
831
|
|
|
|
|
|
|
last if $signal; |
832
|
|
|
|
|
|
|
} ## end for ($i = $skip ; $i < ... |
833
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
# Restore the trace value again. |
835
|
|
|
|
|
|
|
$trace = $otrace; |
836
|
|
|
|
|
|
|
@sub; |
837
|
|
|
|
|
|
|
} ## end sub dump_trace |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
# |
840
|
|
|
|
|
|
|
# List of stack - methods call |
841
|
|
|
|
|
|
|
# |
842
|
|
|
|
|
|
|
sub ui_view_stack { |
843
|
|
|
|
|
|
|
my $rev = shift; |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
my $i = -1; |
846
|
|
|
|
|
|
|
my @a = (); |
847
|
|
|
|
|
|
|
my %h = (); |
848
|
|
|
|
|
|
|
my %h_ret = (); |
849
|
|
|
|
|
|
|
foreach my $rh (dump_trace(2)) { |
850
|
|
|
|
|
|
|
if ($rh->{'sub'} =~ /DB::DB/) { |
851
|
|
|
|
|
|
|
$i = 1; |
852
|
|
|
|
|
|
|
next; |
853
|
|
|
|
|
|
|
} elsif ($i < 0) { |
854
|
|
|
|
|
|
|
next; |
855
|
|
|
|
|
|
|
} |
856
|
|
|
|
|
|
|
push(@a, $i); |
857
|
|
|
|
|
|
|
$h{$i} = |
858
|
|
|
|
|
|
|
$rh->{'sub'} . "(" |
859
|
|
|
|
|
|
|
. (ref($rh->{args}) eq "ARRAY" ? join(",", @{$rh->{args}}) : "") |
860
|
|
|
|
|
|
|
. ") in file " |
861
|
|
|
|
|
|
|
. $rh->{file} . ":" |
862
|
|
|
|
|
|
|
. $rh->{line}; |
863
|
|
|
|
|
|
|
$h_ret{$i} = $rh; |
864
|
|
|
|
|
|
|
$i++; |
865
|
|
|
|
|
|
|
} |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
@a = reverse @a; |
868
|
|
|
|
|
|
|
my $win = $cui->add( |
869
|
|
|
|
|
|
|
'winstackwindow', 'Window', |
870
|
|
|
|
|
|
|
-padtop => 1, |
871
|
|
|
|
|
|
|
-border => 0, |
872
|
|
|
|
|
|
|
-centered => 1, |
873
|
|
|
|
|
|
|
-title => 'Stack', |
874
|
|
|
|
|
|
|
window_style(), |
875
|
|
|
|
|
|
|
); |
876
|
|
|
|
|
|
|
my $listbox = $win->add( |
877
|
|
|
|
|
|
|
'StackWindow', 'Listbox', |
878
|
|
|
|
|
|
|
-title => "Stack window", |
879
|
|
|
|
|
|
|
-y => 0, |
880
|
|
|
|
|
|
|
-border => 1, |
881
|
|
|
|
|
|
|
-padbottom => 1, |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
#-width => $cui->canvaswidth, |
884
|
|
|
|
|
|
|
-vscrollbar => 1, |
885
|
|
|
|
|
|
|
-values => \@a, |
886
|
|
|
|
|
|
|
-labels => \%h, |
887
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
#-onselchange => \&on_file_active, |
889
|
|
|
|
|
|
|
window_style(), |
890
|
|
|
|
|
|
|
); |
891
|
|
|
|
|
|
|
$win->add( |
892
|
|
|
|
|
|
|
"help", "Label", |
893
|
|
|
|
|
|
|
-y => -1, |
894
|
|
|
|
|
|
|
-width => -1, |
895
|
|
|
|
|
|
|
-reverse => 1, |
896
|
|
|
|
|
|
|
-paddingspaces => 1, |
897
|
|
|
|
|
|
|
-text => " Ctrl+Q|Ctrl+C|F10|ESC - Exit | Ctrl+R|F2 - Reverse | Return - jump to given function " |
898
|
|
|
|
|
|
|
); |
899
|
|
|
|
|
|
|
$listbox->set_routine( |
900
|
|
|
|
|
|
|
'option-select', |
901
|
|
|
|
|
|
|
sub { |
902
|
|
|
|
|
|
|
my $this = shift; |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
#$this->{-id_value} = $this->get_active_value; |
905
|
|
|
|
|
|
|
$this->loose_focus; |
906
|
|
|
|
|
|
|
}); |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
$listbox->set_binding(sub { shift->loose_focus; }, "\cQ", "\cC", KEY_F(10), CUI_ESCAPE()); |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
$listbox->set_binding(sub { my $this = shift; my @ar = reverse @a; $this->values(\@ar); }, "\cR", KEY_F(2)); |
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
my $sel = $listbox->modalfocus(); |
913
|
|
|
|
|
|
|
my $ia = $sel ? $sel->get_active_value() : undef; |
914
|
|
|
|
|
|
|
$win->delete("StackWindow"); |
915
|
|
|
|
|
|
|
$cui->delete("winstackwindow"); |
916
|
|
|
|
|
|
|
|
917
|
|
|
|
|
|
|
if ($ia) { |
918
|
|
|
|
|
|
|
my $source = $current_source = get_source($h_ret{$ia}->{file}); |
919
|
|
|
|
|
|
|
$sv->source($source) if $source; |
920
|
|
|
|
|
|
|
$sv->intellidraw; |
921
|
|
|
|
|
|
|
$sv->goto($h_ret{$ia}->{line} + 1); |
922
|
|
|
|
|
|
|
} |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
$sv_win->focus; |
925
|
|
|
|
|
|
|
} |
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
# |
928
|
|
|
|
|
|
|
# UI export information |
929
|
|
|
|
|
|
|
# |
930
|
|
|
|
|
|
|
sub ui_db_export { |
931
|
|
|
|
|
|
|
my $win = $cui->add( |
932
|
|
|
|
|
|
|
'winexportwindow', 'Window', |
933
|
|
|
|
|
|
|
-border => 1, |
934
|
|
|
|
|
|
|
-centered => 1, |
935
|
|
|
|
|
|
|
-title => 'Export information from actuall position to file', |
936
|
|
|
|
|
|
|
-height => 14, |
937
|
|
|
|
|
|
|
window_style(), |
938
|
|
|
|
|
|
|
); |
939
|
|
|
|
|
|
|
|
940
|
|
|
|
|
|
|
$win->add("ExportLabel_1", 'Label', -y => 1, -x => 2, -text => 'Number of lines : ', -bold => 1); |
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
my $lines = 10; |
943
|
|
|
|
|
|
|
$win->add( |
944
|
|
|
|
|
|
|
"ExportNumber", "TextEntry", |
945
|
|
|
|
|
|
|
-y => 1, |
946
|
|
|
|
|
|
|
-x => 20, |
947
|
|
|
|
|
|
|
-width => 20, |
948
|
|
|
|
|
|
|
-text => $lines, |
949
|
|
|
|
|
|
|
-regexp => '/^\d*$/', |
950
|
|
|
|
|
|
|
-onchange => sub { $lines = shift->get(); }, |
951
|
|
|
|
|
|
|
); |
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
$win->add("ExportLabel_2", 'Label', -y => 3, -x => 2, -text => 'Filename : ', -bold => 1); |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
my $filename = undef; |
956
|
|
|
|
|
|
|
$win->add( |
957
|
|
|
|
|
|
|
"ExportFilename", "TextEntry", |
958
|
|
|
|
|
|
|
-y => 3, |
959
|
|
|
|
|
|
|
-x => 14, |
960
|
|
|
|
|
|
|
-width => 30, |
961
|
|
|
|
|
|
|
-onchange => sub { $filename = shift->get(); }, |
962
|
|
|
|
|
|
|
); |
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
$win->add( |
965
|
|
|
|
|
|
|
"ExportLabel_3", 'Label', |
966
|
|
|
|
|
|
|
-y => 5, |
967
|
|
|
|
|
|
|
-x => 2, |
968
|
|
|
|
|
|
|
-text => 'Variables separated by space or export everything : ', |
969
|
|
|
|
|
|
|
-bold => 1, |
970
|
|
|
|
|
|
|
); |
971
|
|
|
|
|
|
|
my $variables = undef; |
972
|
|
|
|
|
|
|
$win->add( |
973
|
|
|
|
|
|
|
"ExportVariables", "TextEntry", |
974
|
|
|
|
|
|
|
-y => 6, |
975
|
|
|
|
|
|
|
-x => 2, |
976
|
|
|
|
|
|
|
-width => 30, |
977
|
|
|
|
|
|
|
-onchange => sub { $variables = shift->get(); }, |
978
|
|
|
|
|
|
|
); |
979
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
my $use_watches = 0; |
981
|
|
|
|
|
|
|
$win->add( |
982
|
|
|
|
|
|
|
'ExportWatches', 'Checkbox', |
983
|
|
|
|
|
|
|
-label => "Export all variables from watch tables", |
984
|
|
|
|
|
|
|
-y => 8, |
985
|
|
|
|
|
|
|
-x => 2, |
986
|
|
|
|
|
|
|
-onchange => sub { $use_watches = shift->get(); }, |
987
|
|
|
|
|
|
|
window_style(), |
988
|
|
|
|
|
|
|
); |
989
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
my $exit = 1; |
991
|
|
|
|
|
|
|
$win->add( |
992
|
|
|
|
|
|
|
'ExportButtons', |
993
|
|
|
|
|
|
|
'Buttonbox', |
994
|
|
|
|
|
|
|
-buttons => [{ |
995
|
|
|
|
|
|
|
-label => '< Ok >', |
996
|
|
|
|
|
|
|
-shortcut => 'o', |
997
|
|
|
|
|
|
|
-onpress => sub { $exit = 0; $win->loose_focus; } |
998
|
|
|
|
|
|
|
}, |
999
|
|
|
|
|
|
|
{ -label => '< Cancel >', |
1000
|
|
|
|
|
|
|
-shortcut => 'c', |
1001
|
|
|
|
|
|
|
-onpress => sub { |
1002
|
|
|
|
|
|
|
$win->loose_focus; |
1003
|
|
|
|
|
|
|
} |
1004
|
|
|
|
|
|
|
} |
1005
|
|
|
|
|
|
|
], |
1006
|
|
|
|
|
|
|
-y => 10, |
1007
|
|
|
|
|
|
|
-x => 2, |
1008
|
|
|
|
|
|
|
); |
1009
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
$win->set_binding(sub { shift->loose_focus; }, "\cQ", "\cC", KEY_F(10), CUI_ESCAPE()); |
1011
|
|
|
|
|
|
|
my $sel = $win->modalfocus(); |
1012
|
|
|
|
|
|
|
$cui->delete("winexportwindow"); |
1013
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
local *W; |
1015
|
|
|
|
|
|
|
if ($exit) { |
1016
|
|
|
|
|
|
|
} elsif (!$filename || !length($filename)) { |
1017
|
|
|
|
|
|
|
print_error("Filename must be set"); |
1018
|
|
|
|
|
|
|
} elsif (!open(W, ">$filename")) { |
1019
|
|
|
|
|
|
|
print_error("Can't open file $filename : $!"); |
1020
|
|
|
|
|
|
|
} else { |
1021
|
|
|
|
|
|
|
local (*dbline) = $main::{'_<' . $current_source->filename}; |
1022
|
|
|
|
|
|
|
|
1023
|
|
|
|
|
|
|
my $current_line = $current_source->current_line; |
1024
|
|
|
|
|
|
|
my $from = $current_line - $lines; |
1025
|
|
|
|
|
|
|
$from = 0 if ($from < 0); |
1026
|
|
|
|
|
|
|
my $to = $current_line + $lines; |
1027
|
|
|
|
|
|
|
my $l = length(sprintf("%d", $to)); |
1028
|
|
|
|
|
|
|
|
1029
|
|
|
|
|
|
|
print W "----- Filename : " . $current_source->filename . "----------\n"; |
1030
|
|
|
|
|
|
|
for my $i ($from .. $to) { |
1031
|
|
|
|
|
|
|
last unless exists $dbline[$i]; |
1032
|
|
|
|
|
|
|
if ($i == 0 && $dbline[$i] =~ /use\s+.*Devel::_?PDB/) { |
1033
|
|
|
|
|
|
|
$to++; |
1034
|
|
|
|
|
|
|
next; |
1035
|
|
|
|
|
|
|
} |
1036
|
|
|
|
|
|
|
printf W "%s%*d %s", $i == $current_line ? '*' : ' ', $l, $i, $dbline[$i]; |
1037
|
|
|
|
|
|
|
} |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
sub print_variables { |
1040
|
|
|
|
|
|
|
my ($rh) = @_; |
1041
|
|
|
|
|
|
|
print W $rh->{name} . " -> " . $rh->{long_value} . "\n"; |
1042
|
|
|
|
|
|
|
} |
1043
|
|
|
|
|
|
|
print W "----- Stack : -------------\n"; |
1044
|
|
|
|
|
|
|
my %h = (); |
1045
|
|
|
|
|
|
|
%h = map { $_ => 1 } split(" ", $variables) if (length($variables)); |
1046
|
|
|
|
|
|
|
foreach my $rh (@padlist_disp) { |
1047
|
|
|
|
|
|
|
print_variables($rh) if (!keys(%h) || exists($h{$rh->{name}})); |
1048
|
|
|
|
|
|
|
} |
1049
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
if ($use_watches) { |
1051
|
|
|
|
|
|
|
print W "----- Watches : -----------\n"; |
1052
|
|
|
|
|
|
|
foreach my $rh (@watch_exprs) { |
1053
|
|
|
|
|
|
|
print_variables($rh); |
1054
|
|
|
|
|
|
|
} |
1055
|
|
|
|
|
|
|
} |
1056
|
|
|
|
|
|
|
|
1057
|
|
|
|
|
|
|
close(W); |
1058
|
|
|
|
|
|
|
} |
1059
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
$sv_win->focus; |
1061
|
|
|
|
|
|
|
} |
1062
|
|
|
|
|
|
|
|
1063
|
|
|
|
|
|
|
# |
1064
|
|
|
|
|
|
|
# UI open file |
1065
|
|
|
|
|
|
|
# |
1066
|
|
|
|
|
|
|
sub ui_open_file { |
1067
|
|
|
|
|
|
|
my ($title, $files) = @_; |
1068
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
my $filename = $cui->tempdialog( |
1070
|
|
|
|
|
|
|
'Devel::PDB::Dialog::FileBrowser', |
1071
|
|
|
|
|
|
|
-title => $title, |
1072
|
|
|
|
|
|
|
-files => $files, |
1073
|
|
|
|
|
|
|
window_style(), |
1074
|
|
|
|
|
|
|
); |
1075
|
|
|
|
|
|
|
if ($filename) { |
1076
|
|
|
|
|
|
|
my $source = $current_source = get_source($filename); |
1077
|
|
|
|
|
|
|
$sv->source($source) if $source; |
1078
|
|
|
|
|
|
|
$sv->intellidraw; |
1079
|
|
|
|
|
|
|
} |
1080
|
|
|
|
|
|
|
} |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
# |
1083
|
|
|
|
|
|
|
# UI view STD[OUT|ERR] files |
1084
|
|
|
|
|
|
|
# |
1085
|
|
|
|
|
|
|
sub db_view_std_files { |
1086
|
|
|
|
|
|
|
my ($use_exit) = @_; |
1087
|
|
|
|
|
|
|
my @ab = ({ |
1088
|
|
|
|
|
|
|
-label => '< STDOUT >', |
1089
|
|
|
|
|
|
|
-value => 1, |
1090
|
|
|
|
|
|
|
-shortcut => 'o' |
1091
|
|
|
|
|
|
|
}, |
1092
|
|
|
|
|
|
|
{ -label => '< STDERR >', |
1093
|
|
|
|
|
|
|
-value => 2, |
1094
|
|
|
|
|
|
|
-shortcut => 'e' |
1095
|
|
|
|
|
|
|
}); |
1096
|
|
|
|
|
|
|
unshift( |
1097
|
|
|
|
|
|
|
@ab, |
1098
|
|
|
|
|
|
|
{ -label => '< Exit >', |
1099
|
|
|
|
|
|
|
-value => -1, |
1100
|
|
|
|
|
|
|
-shortcut => 'x' |
1101
|
|
|
|
|
|
|
}) if ($use_exit); |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
my $t = $cui->dialog( |
1104
|
|
|
|
|
|
|
-title => 'Open STD* files', |
1105
|
|
|
|
|
|
|
-buttons => \@ab, |
1106
|
|
|
|
|
|
|
-message => 'Choose which STD* file to open it?', |
1107
|
|
|
|
|
|
|
window_style(), |
1108
|
|
|
|
|
|
|
); |
1109
|
|
|
|
|
|
|
return if ($t == -1); |
1110
|
|
|
|
|
|
|
|
1111
|
|
|
|
|
|
|
my $text = ""; |
1112
|
|
|
|
|
|
|
if (open F, "<" . config_file($t == 2 ? "stderr" : "stdout")) { |
1113
|
|
|
|
|
|
|
while () { $text .= $_ } |
1114
|
|
|
|
|
|
|
close F; |
1115
|
|
|
|
|
|
|
} else { |
1116
|
|
|
|
|
|
|
$cui->error(-message => "Cannot read file " . config_file($t == 2 ? "stderr" : "stdout") . ":\n$!"); |
1117
|
|
|
|
|
|
|
exit(127); |
1118
|
|
|
|
|
|
|
} |
1119
|
|
|
|
|
|
|
my $win = $cui->add( |
1120
|
|
|
|
|
|
|
'winmytextviewer', 'Window', |
1121
|
|
|
|
|
|
|
-border => 0, |
1122
|
|
|
|
|
|
|
-title => 'Source', |
1123
|
|
|
|
|
|
|
window_style(), |
1124
|
|
|
|
|
|
|
); |
1125
|
|
|
|
|
|
|
my $textviewer = $win->add( |
1126
|
|
|
|
|
|
|
"mytextviewer", "TextViewer", |
1127
|
|
|
|
|
|
|
-homeonblur => 1, # cursor to homepos on blur? |
1128
|
|
|
|
|
|
|
-fg => -1, |
1129
|
|
|
|
|
|
|
-bg => -1, |
1130
|
|
|
|
|
|
|
-cursor => 1, |
1131
|
|
|
|
|
|
|
-border => 1, |
1132
|
|
|
|
|
|
|
-padtop => 0, |
1133
|
|
|
|
|
|
|
-padbottom => 1, |
1134
|
|
|
|
|
|
|
-showlines => 0, |
1135
|
|
|
|
|
|
|
-sbborder => 0, |
1136
|
|
|
|
|
|
|
-vscrollbar => 1, |
1137
|
|
|
|
|
|
|
-hscrollbar => 1, |
1138
|
|
|
|
|
|
|
-showhardreturns => 0, |
1139
|
|
|
|
|
|
|
-wrapping => 0, # wrapping slows down the editor :-( |
1140
|
|
|
|
|
|
|
-text => $text, |
1141
|
|
|
|
|
|
|
-title => " Viewing file STD" . ($t == 2 ? "ERR" : "OUT") . " : " . config_file($t == 2 ? "stderr" : "stdout"), |
1142
|
|
|
|
|
|
|
window_style(), |
1143
|
|
|
|
|
|
|
); |
1144
|
|
|
|
|
|
|
$win->add( |
1145
|
|
|
|
|
|
|
"help", "Label", |
1146
|
|
|
|
|
|
|
-y => -1, |
1147
|
|
|
|
|
|
|
-width => -1, |
1148
|
|
|
|
|
|
|
-reverse => 1, |
1149
|
|
|
|
|
|
|
-paddingspaces => 1, |
1150
|
|
|
|
|
|
|
-text => " Ctrl+Q|Ctrl+C|F10|ESC - Return " |
1151
|
|
|
|
|
|
|
); |
1152
|
|
|
|
|
|
|
$textviewer->set_binding(sub { shift->loose_focus; }, "\cQ", "\cC", KEY_F(10), CUI_ESCAPE()); |
1153
|
|
|
|
|
|
|
$textviewer->modalfocus(); |
1154
|
|
|
|
|
|
|
$win->delete("mytextviewer"); |
1155
|
|
|
|
|
|
|
$cui->delete("winmytextviewer"); |
1156
|
|
|
|
|
|
|
} |
1157
|
|
|
|
|
|
|
|
1158
|
|
|
|
|
|
|
# |
1159
|
|
|
|
|
|
|
# Change vertical size of windows. This change size of windows between Source and Watches+Stack |
1160
|
|
|
|
|
|
|
# 1 - decrease Source window |
1161
|
|
|
|
|
|
|
# -1 - increase Source window |
1162
|
|
|
|
|
|
|
# |
1163
|
|
|
|
|
|
|
sub ui_adjust_vert_parts { |
1164
|
|
|
|
|
|
|
my $delta = shift; |
1165
|
|
|
|
|
|
|
return |
1166
|
|
|
|
|
|
|
if $delta > 0 && $sv_win->{-padbottom} >= $cui->{-height} - $sv_win->{-padtop} - 5 |
1167
|
|
|
|
|
|
|
or $delta < 0 && $lower_win->{-height} <= 5; |
1168
|
|
|
|
|
|
|
$sv_win->{-padbottom} += $delta; |
1169
|
|
|
|
|
|
|
$lower_win->{-height} += $delta; |
1170
|
|
|
|
|
|
|
$cui->layout_contained_objects; |
1171
|
|
|
|
|
|
|
} |
1172
|
|
|
|
|
|
|
|
1173
|
|
|
|
|
|
|
# |
1174
|
|
|
|
|
|
|
# Change horizontal size of windows. This change size of windows between Watches expresion and Stack |
1175
|
|
|
|
|
|
|
# 1 - increasing Watches window |
1176
|
|
|
|
|
|
|
# -1 - decreasing Watches window |
1177
|
|
|
|
|
|
|
# |
1178
|
|
|
|
|
|
|
sub ui_adjust_hori_parts { |
1179
|
|
|
|
|
|
|
my $delta = shift; |
1180
|
|
|
|
|
|
|
return |
1181
|
|
|
|
|
|
|
if $delta > 0 && $auto_win->{-width} >= $cui->{-width} - 15 |
1182
|
|
|
|
|
|
|
or $delta < 0 && $auto_win->{-width} <= 15; |
1183
|
|
|
|
|
|
|
$auto_win->{-width} += $delta; |
1184
|
|
|
|
|
|
|
$watch_win->{-padleft} += $delta; |
1185
|
|
|
|
|
|
|
$cui->layout_contained_objects; |
1186
|
|
|
|
|
|
|
} |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
# |
1189
|
|
|
|
|
|
|
# Return name for config file |
1190
|
|
|
|
|
|
|
# |
1191
|
|
|
|
|
|
|
sub config_file { |
1192
|
|
|
|
|
|
|
my $name = shift; |
1193
|
|
|
|
|
|
|
my $file_name = File::Basename::basename($Devel::PDB::scriptName); |
1194
|
|
|
|
|
|
|
my $dir_name = File::Basename::dirname(Cwd::abs_path($Devel::PDB::scriptName)); |
1195
|
|
|
|
|
|
|
if ($ENV{PDB_use_HOME} && exists($ENV{HOME})) { |
1196
|
|
|
|
|
|
|
$dir_name = $ENV{HOME} . "/.PDB"; |
1197
|
|
|
|
|
|
|
mkdir($dir_name) unless (-d $dir_name); |
1198
|
|
|
|
|
|
|
} |
1199
|
|
|
|
|
|
|
return $dir_name . "/.$file_name" . "-" . $name; |
1200
|
|
|
|
|
|
|
} |
1201
|
|
|
|
|
|
|
|
1202
|
|
|
|
|
|
|
my $keys_binded = undef; |
1203
|
|
|
|
|
|
|
my @keys_global = (); |
1204
|
|
|
|
|
|
|
my %keys_hash = (); |
1205
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
# |
1207
|
|
|
|
|
|
|
# Set key |
1208
|
|
|
|
|
|
|
# 1 - CodeRef for appened action |
1209
|
|
|
|
|
|
|
# 2 - nickname for given action |
1210
|
|
|
|
|
|
|
# 3 - Text which will be printed |
1211
|
|
|
|
|
|
|
# 4 and others are keys for binding |
1212
|
|
|
|
|
|
|
# |
1213
|
|
|
|
|
|
|
sub set_key_binding($$@) { |
1214
|
|
|
|
|
|
|
my $rf = shift; |
1215
|
|
|
|
|
|
|
my $name = shift; |
1216
|
|
|
|
|
|
|
my $text = shift; |
1217
|
|
|
|
|
|
|
my @keys = @_; |
1218
|
|
|
|
|
|
|
|
1219
|
|
|
|
|
|
|
if (!defined($keys_binded)) { |
1220
|
|
|
|
|
|
|
if (open(my $fh, $ENV{HOME} . "/.PDB.keys")) { |
1221
|
|
|
|
|
|
|
while (<$fh>) { |
1222
|
|
|
|
|
|
|
chomp; |
1223
|
|
|
|
|
|
|
my @a = split("="); |
1224
|
|
|
|
|
|
|
next if (scalar(@a) < 2); |
1225
|
|
|
|
|
|
|
my @akeys = (); |
1226
|
|
|
|
|
|
|
foreach my $r (split(",", $a[1])) { |
1227
|
|
|
|
|
|
|
if ($r =~ /F/) { |
1228
|
|
|
|
|
|
|
$r =~ s/F//; |
1229
|
|
|
|
|
|
|
$r = KEY_F(int($r)); |
1230
|
|
|
|
|
|
|
} elsif ($r =~ /Control-/) { |
1231
|
|
|
|
|
|
|
$r =~ s/Control-//; |
1232
|
|
|
|
|
|
|
$r = chr(ord(uc($r)) & 0x1F); |
1233
|
|
|
|
|
|
|
} elsif ($r =~ /KEY_/) { |
1234
|
|
|
|
|
|
|
no strict; |
1235
|
|
|
|
|
|
|
$r = $Curses::{$r} ? &{"Curses::" . $r}() : undef; |
1236
|
|
|
|
|
|
|
} |
1237
|
|
|
|
|
|
|
push(@akeys, $r) if ($r); |
1238
|
|
|
|
|
|
|
} |
1239
|
|
|
|
|
|
|
$keys_binded->{$a[0]} = \@akeys; |
1240
|
|
|
|
|
|
|
} |
1241
|
|
|
|
|
|
|
close($fh); |
1242
|
|
|
|
|
|
|
} else { |
1243
|
|
|
|
|
|
|
$keys_binded = {}; |
1244
|
|
|
|
|
|
|
} |
1245
|
|
|
|
|
|
|
} |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
push(@keys_global, {name => $text, key => \@keys}); |
1248
|
|
|
|
|
|
|
$cui->set_binding($rf, exists($keys_binded->{$name}) ? @{$keys_binded->{$name}} : @keys); |
1249
|
|
|
|
|
|
|
|
1250
|
|
|
|
|
|
|
$text .= " "; |
1251
|
|
|
|
|
|
|
foreach my $k (exists($keys_binded->{$name}) ? @{$keys_binded->{$name}} : @keys) { |
1252
|
|
|
|
|
|
|
my $key = $cui->key_to_ascii($k); |
1253
|
|
|
|
|
|
|
$text .= $key . " "; |
1254
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
# Add duplicity |
1256
|
|
|
|
|
|
|
$keys_hash{$key} = [] unless (exists($keys_hash{$key})); |
1257
|
|
|
|
|
|
|
my $ra = $keys_hash{$key}; |
1258
|
|
|
|
|
|
|
push(@$ra, $name); |
1259
|
|
|
|
|
|
|
} |
1260
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
return {-value => $rf, -label => $text}; |
1262
|
|
|
|
|
|
|
} |
1263
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
sub val_unctrl { |
1265
|
|
|
|
|
|
|
local ($_) = @_; |
1266
|
|
|
|
|
|
|
|
1267
|
|
|
|
|
|
|
return \$_ if ref \$_ eq "GLOB"; |
1268
|
|
|
|
|
|
|
if (ord('A') == 193) { # EBCDIC. |
1269
|
|
|
|
|
|
|
# EBCDIC has no concept of "\cA" or "A" being related |
1270
|
|
|
|
|
|
|
# to each other by a linear/boolean mapping. |
1271
|
|
|
|
|
|
|
} else { |
1272
|
|
|
|
|
|
|
s/([\001-\037\177])/'^'.pack('c',ord($1)^64)/eg; |
1273
|
|
|
|
|
|
|
} |
1274
|
|
|
|
|
|
|
$_; |
1275
|
|
|
|
|
|
|
} |
1276
|
|
|
|
|
|
|
|
1277
|
|
|
|
|
|
|
# |
1278
|
|
|
|
|
|
|
# Window wieving or editing |
1279
|
|
|
|
|
|
|
# 1 - Editing program params |
1280
|
|
|
|
|
|
|
# 2 - Editing enviroment |
1281
|
|
|
|
|
|
|
# 3 - Viewing Perl special variables |
1282
|
|
|
|
|
|
|
# |
1283
|
|
|
|
|
|
|
sub ui_text_editor { |
1284
|
|
|
|
|
|
|
my $type = shift; |
1285
|
|
|
|
|
|
|
|
1286
|
|
|
|
|
|
|
my @rows = (); |
1287
|
|
|
|
|
|
|
my $str_title = ""; |
1288
|
|
|
|
|
|
|
my $str_label = ""; |
1289
|
|
|
|
|
|
|
my $use_editor = 1; |
1290
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
if ($type == 1) { |
1292
|
|
|
|
|
|
|
@rows = @Devel::PDB::script_args; |
1293
|
|
|
|
|
|
|
$str_title = 'Edit program params'; |
1294
|
|
|
|
|
|
|
$str_label = " Enter => Save "; |
1295
|
|
|
|
|
|
|
} elsif ($type == 2) { |
1296
|
|
|
|
|
|
|
$str_title = 'Edit enviroments'; |
1297
|
|
|
|
|
|
|
$str_label = " F2 => Save "; |
1298
|
|
|
|
|
|
|
foreach my $k (sort keys %ENV) { |
1299
|
|
|
|
|
|
|
push(@rows, $k . "=" . $ENV{$k}); |
1300
|
|
|
|
|
|
|
} |
1301
|
|
|
|
|
|
|
} elsif ($type == 3) { |
1302
|
|
|
|
|
|
|
$str_title = 'View special variables'; |
1303
|
|
|
|
|
|
|
$use_editor = 0; |
1304
|
|
|
|
|
|
|
|
1305
|
|
|
|
|
|
|
sub rep_dumper { |
1306
|
|
|
|
|
|
|
my $s = shift; |
1307
|
|
|
|
|
|
|
$s =~ s/^\$//; |
1308
|
|
|
|
|
|
|
chomp($s); |
1309
|
|
|
|
|
|
|
return $s; |
1310
|
|
|
|
|
|
|
} |
1311
|
|
|
|
|
|
|
|
1312
|
|
|
|
|
|
|
no strict; |
1313
|
|
|
|
|
|
|
*stab = *{"main::"}; |
1314
|
|
|
|
|
|
|
foreach my $key (sort keys %stab) { |
1315
|
|
|
|
|
|
|
next if ($key =~ /^_); |
1316
|
|
|
|
|
|
|
local (*entry) = $stab{$key}; |
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
my $fileno; |
1319
|
|
|
|
|
|
|
|
1320
|
|
|
|
|
|
|
local $Data::Dumper::Purity = 0; |
1321
|
|
|
|
|
|
|
local $Data::Dumper::Terse = 0; |
1322
|
|
|
|
|
|
|
local $Data::Dumper::Indent = 2; |
1323
|
|
|
|
|
|
|
local $Data::Dumper::Sortkeys = 1; |
1324
|
|
|
|
|
|
|
if (defined $entry) { |
1325
|
|
|
|
|
|
|
push(@rows, '$' . &val_unctrl($key) . " = " . $entry); |
1326
|
|
|
|
|
|
|
} elsif (@entry) { |
1327
|
|
|
|
|
|
|
local $Data::Dumper::Varname = "\@$key"; |
1328
|
|
|
|
|
|
|
push(@rows, &rep_dumper(Dumper(@entry))); |
1329
|
|
|
|
|
|
|
} elsif ($key ne "main::" |
1330
|
|
|
|
|
|
|
&& $key ne "DB::" |
1331
|
|
|
|
|
|
|
&& %entry |
1332
|
|
|
|
|
|
|
&& $key !~ /::$/ |
1333
|
|
|
|
|
|
|
&& !($package eq "dumpvar" and $key eq "stab")) { |
1334
|
|
|
|
|
|
|
local $Data::Dumper::Varname = "\%$key"; |
1335
|
|
|
|
|
|
|
push(@rows, &rep_dumper(Dumper(%entry))); |
1336
|
|
|
|
|
|
|
} |
1337
|
|
|
|
|
|
|
} |
1338
|
|
|
|
|
|
|
} |
1339
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
my $row = scalar(@rows) || 1; |
1341
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
my $win = $cui->add( |
1343
|
|
|
|
|
|
|
'winChangeParams', 'Window', |
1344
|
|
|
|
|
|
|
-border => 1, |
1345
|
|
|
|
|
|
|
|
1346
|
|
|
|
|
|
|
#-y => int(($LINES - ($row + 3)) / 2), # Buggy |
1347
|
|
|
|
|
|
|
#-height => $row + 3, |
1348
|
|
|
|
|
|
|
-centered => 1, |
1349
|
|
|
|
|
|
|
-title => $str_title, |
1350
|
|
|
|
|
|
|
window_style(), |
1351
|
|
|
|
|
|
|
); |
1352
|
|
|
|
|
|
|
my $x = $win->add( |
1353
|
|
|
|
|
|
|
"ChangeParams", $use_editor ? "TextEditor" : "TextViewer", |
1354
|
|
|
|
|
|
|
-homeonblur => 1, # cursor to homepos on blur? |
1355
|
|
|
|
|
|
|
-fg => -1, |
1356
|
|
|
|
|
|
|
-bg => -1, |
1357
|
|
|
|
|
|
|
-cursor => 1, |
1358
|
|
|
|
|
|
|
-padbottom => 1, |
1359
|
|
|
|
|
|
|
-text => join("\n", @rows), |
1360
|
|
|
|
|
|
|
); |
1361
|
|
|
|
|
|
|
$win->add( |
1362
|
|
|
|
|
|
|
"help", "Label", |
1363
|
|
|
|
|
|
|
-y => -1, |
1364
|
|
|
|
|
|
|
-width => -1, |
1365
|
|
|
|
|
|
|
-reverse => 1, |
1366
|
|
|
|
|
|
|
-paddingspaces => 1, |
1367
|
|
|
|
|
|
|
-text => " Ctrl+Q|Ctrl+C|F10|ESC -> Return " . $str_label, |
1368
|
|
|
|
|
|
|
); |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
# Setup bindings. |
1371
|
|
|
|
|
|
|
$x->clear_binding('loose-focus'); |
1372
|
|
|
|
|
|
|
$x->set_binding(sub { shift->loose_focus; }, "\cQ", "\cC", KEY_F(10), CUI_ESCAPE()); |
1373
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
if ($type == 1) { |
1375
|
|
|
|
|
|
|
$x->set_binding( |
1376
|
|
|
|
|
|
|
sub { |
1377
|
|
|
|
|
|
|
my $this = shift; |
1378
|
|
|
|
|
|
|
@Devel::PDB::script_args = (); |
1379
|
|
|
|
|
|
|
foreach my $s (split("\n", $this->get())) { |
1380
|
|
|
|
|
|
|
my $x = $s; |
1381
|
|
|
|
|
|
|
$x =~ s/ //g; |
1382
|
|
|
|
|
|
|
push(@Devel::PDB::script_args, $s) if (length($x)); |
1383
|
|
|
|
|
|
|
} |
1384
|
|
|
|
|
|
|
$this->loose_focus; |
1385
|
|
|
|
|
|
|
}, |
1386
|
|
|
|
|
|
|
KEY_ENTER(), |
1387
|
|
|
|
|
|
|
KEY_BTAB(), |
1388
|
|
|
|
|
|
|
CUI_TAB()); |
1389
|
|
|
|
|
|
|
} elsif ($type == 2) { |
1390
|
|
|
|
|
|
|
$x->set_binding( |
1391
|
|
|
|
|
|
|
sub { |
1392
|
|
|
|
|
|
|
my $this = shift; |
1393
|
|
|
|
|
|
|
%ENV = (); |
1394
|
|
|
|
|
|
|
foreach my $s (split("\n", $this->get())) { |
1395
|
|
|
|
|
|
|
my $x = $s; |
1396
|
|
|
|
|
|
|
$x =~ s/ //g; |
1397
|
|
|
|
|
|
|
if (length($x)) { |
1398
|
|
|
|
|
|
|
my @a = split("=", $s); |
1399
|
|
|
|
|
|
|
$ENV{$a[0]} = $a[1] if (scalar(@a) == 2); |
1400
|
|
|
|
|
|
|
} |
1401
|
|
|
|
|
|
|
} |
1402
|
|
|
|
|
|
|
$this->loose_focus; |
1403
|
|
|
|
|
|
|
}, |
1404
|
|
|
|
|
|
|
KEY_F(2)); |
1405
|
|
|
|
|
|
|
} elsif ($type == 3) { |
1406
|
|
|
|
|
|
|
} |
1407
|
|
|
|
|
|
|
|
1408
|
|
|
|
|
|
|
$x->modalfocus(); |
1409
|
|
|
|
|
|
|
$win->delete('ChangeParams'); |
1410
|
|
|
|
|
|
|
$cui->delete('winChangeParams'); |
1411
|
|
|
|
|
|
|
$sv_win->focus; |
1412
|
|
|
|
|
|
|
} |
1413
|
|
|
|
|
|
|
|
1414
|
|
|
|
|
|
|
# |
1415
|
|
|
|
|
|
|
# Print helping keys association |
1416
|
|
|
|
|
|
|
# |
1417
|
|
|
|
|
|
|
sub ui_db_help { |
1418
|
|
|
|
|
|
|
my @a = (); |
1419
|
|
|
|
|
|
|
push(@a, "Global"); |
1420
|
|
|
|
|
|
|
foreach my $rh (@keys_global) { |
1421
|
|
|
|
|
|
|
my $s = " "; |
1422
|
|
|
|
|
|
|
foreach (@{$rh->{key}}) { |
1423
|
|
|
|
|
|
|
$s .= $cui->key_to_ascii($_) . " "; |
1424
|
|
|
|
|
|
|
} |
1425
|
|
|
|
|
|
|
push(@a, $s . "\t" . $rh->{name}); |
1426
|
|
|
|
|
|
|
} |
1427
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
push(@a, "Source Code Window"); |
1429
|
|
|
|
|
|
|
push(@a, " UP/DOWN/LEFT/RIGHT/PAGE UP/PAGE DOWN\tMove the cursor"); |
1430
|
|
|
|
|
|
|
push(@a, " H/J/K/L/Ctrl+F/Ctrl+B\tIf you use VI, you will know"); |
1431
|
|
|
|
|
|
|
push(@a, " /\tSearch using a RegEx in the current opened file"); |
1432
|
|
|
|
|
|
|
push(@a, " n\tSearch Next"); |
1433
|
|
|
|
|
|
|
push(@a, " N\tSearch Previous"); |
1434
|
|
|
|
|
|
|
push(@a, " Ctrl+G\tGoto a specific line"); |
1435
|
|
|
|
|
|
|
|
1436
|
|
|
|
|
|
|
push(@a, "Lexical Variable Window / Watch Window"); |
1437
|
|
|
|
|
|
|
push(@a, " UP/DOWN\tMove the cursor"); |
1438
|
|
|
|
|
|
|
push(@a, " ENTER\tShow the Data::Dumper output of the highlighted item in a scrollable dialog"); |
1439
|
|
|
|
|
|
|
push(@a, " DEL\tRemove the highlighted expression (Watch Window only)"); |
1440
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
push(@a, "Compiled File Dialog / Opened File Dialog"); |
1442
|
|
|
|
|
|
|
push(@a, " TAB\tToggle the focus between the file list and the filter"); |
1443
|
|
|
|
|
|
|
push(@a, " ENTER\tSelect the highlighted file or apply the filter to the file list"); |
1444
|
|
|
|
|
|
|
push(@a, "Other"); |
1445
|
|
|
|
|
|
|
push(@a, " Esc,F10\tBack,Exit function"); |
1446
|
|
|
|
|
|
|
push(@a, " Ctrl+S,Ctrl+L,F6\tExporting to file"); |
1447
|
|
|
|
|
|
|
|
1448
|
|
|
|
|
|
|
if (keys %keys_hash) { |
1449
|
|
|
|
|
|
|
my @ad = (); |
1450
|
|
|
|
|
|
|
foreach my $k (sort %keys_hash) { |
1451
|
|
|
|
|
|
|
next if (ref($k)); |
1452
|
|
|
|
|
|
|
my $ra = $keys_hash{$k}; |
1453
|
|
|
|
|
|
|
next if (scalar(@$ra) <= 1); |
1454
|
|
|
|
|
|
|
push(@ad, $k); |
1455
|
|
|
|
|
|
|
push(@ad, map { $_ } @$ra); |
1456
|
|
|
|
|
|
|
} |
1457
|
|
|
|
|
|
|
push(@a, " ", " ", "Duplicity in keys", " ", @ad) if (@ad); |
1458
|
|
|
|
|
|
|
} |
1459
|
|
|
|
|
|
|
|
1460
|
|
|
|
|
|
|
dialog_message( |
1461
|
|
|
|
|
|
|
-title => "Help Keys", |
1462
|
|
|
|
|
|
|
-message => join("\n", @a), |
1463
|
|
|
|
|
|
|
); |
1464
|
|
|
|
|
|
|
} |
1465
|
|
|
|
|
|
|
|
1466
|
|
|
|
|
|
|
# |
1467
|
|
|
|
|
|
|
# Create dialog message window with binded key F2 for saving text |
1468
|
|
|
|
|
|
|
# |
1469
|
|
|
|
|
|
|
sub dialog_message { |
1470
|
|
|
|
|
|
|
my %args = @_; |
1471
|
|
|
|
|
|
|
Devel::PDB::Dialog::Message->run(%args, window_style()); |
1472
|
|
|
|
|
|
|
} |
1473
|
|
|
|
|
|
|
|
1474
|
|
|
|
|
|
|
# |
1475
|
|
|
|
|
|
|
# Exporting to file |
1476
|
|
|
|
|
|
|
# |
1477
|
|
|
|
|
|
|
sub export_to_file { |
1478
|
|
|
|
|
|
|
my ($name, $title, $rh_str) = @_; |
1479
|
|
|
|
|
|
|
|
1480
|
|
|
|
|
|
|
return unless $cui; |
1481
|
|
|
|
|
|
|
$name ||= "Title"; |
1482
|
|
|
|
|
|
|
my $fname = $cui->question(-question => 'Add filename to export', DB::window_style()) || return; |
1483
|
|
|
|
|
|
|
if (open(my $fh, ">", $fname)) { |
1484
|
|
|
|
|
|
|
print $fh "----- $name : " . $title . " ----------\n" if ($title); |
1485
|
|
|
|
|
|
|
print $fh $$rh_str; |
1486
|
|
|
|
|
|
|
print $fh "\n"; |
1487
|
|
|
|
|
|
|
close($fh); |
1488
|
|
|
|
|
|
|
} else { |
1489
|
|
|
|
|
|
|
DB::print_error("Can't open file $fname : $!"); |
1490
|
|
|
|
|
|
|
} |
1491
|
|
|
|
|
|
|
} |
1492
|
|
|
|
|
|
|
|
1493
|
|
|
|
|
|
|
# |
1494
|
|
|
|
|
|
|
# Activate window |
1495
|
|
|
|
|
|
|
# |
1496
|
|
|
|
|
|
|
sub set_active_window { |
1497
|
|
|
|
|
|
|
my $win = shift; |
1498
|
|
|
|
|
|
|
|
1499
|
|
|
|
|
|
|
if ($win == 2) { |
1500
|
|
|
|
|
|
|
$ui_window_focused = 1; |
1501
|
|
|
|
|
|
|
$auto_win->focus; |
1502
|
|
|
|
|
|
|
} elsif ($win == 3) { |
1503
|
|
|
|
|
|
|
$ui_window_focused = 2; |
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
#ui_update_watch_list(); |
1506
|
|
|
|
|
|
|
$watch_win->focus; |
1507
|
|
|
|
|
|
|
} else { |
1508
|
|
|
|
|
|
|
$ui_window_focused = 0; |
1509
|
|
|
|
|
|
|
$sv_win->focus; |
1510
|
|
|
|
|
|
|
} |
1511
|
|
|
|
|
|
|
} |
1512
|
|
|
|
|
|
|
|
1513
|
|
|
|
|
|
|
# |
1514
|
|
|
|
|
|
|
# Initialize ncurses methods |
1515
|
|
|
|
|
|
|
# |
1516
|
|
|
|
|
|
|
sub init { |
1517
|
|
|
|
|
|
|
|
1518
|
|
|
|
|
|
|
# Set own colours |
1519
|
|
|
|
|
|
|
if (open(my $fh, $ENV{HOME} . "/.PDB.colours")) { |
1520
|
|
|
|
|
|
|
my %h; |
1521
|
|
|
|
|
|
|
while (<$fh>) { |
1522
|
|
|
|
|
|
|
chomp; |
1523
|
|
|
|
|
|
|
my @a = split(/\s+/); |
1524
|
|
|
|
|
|
|
$h{$a[0]} = $a[1]; |
1525
|
|
|
|
|
|
|
} |
1526
|
|
|
|
|
|
|
close($fh); |
1527
|
|
|
|
|
|
|
window_style(%h); |
1528
|
|
|
|
|
|
|
} |
1529
|
|
|
|
|
|
|
|
1530
|
|
|
|
|
|
|
# can anybody tell me why $win->notimeout(1) doesn't work? |
1531
|
|
|
|
|
|
|
$ENV{ESCDELAY} = '0'; |
1532
|
|
|
|
|
|
|
|
1533
|
|
|
|
|
|
|
$cui = new Curses::UI( |
1534
|
|
|
|
|
|
|
-clear_on_exit => 1, |
1535
|
|
|
|
|
|
|
-color_support => 1, |
1536
|
|
|
|
|
|
|
-mouse_support => 1, |
1537
|
|
|
|
|
|
|
); |
1538
|
|
|
|
|
|
|
|
1539
|
|
|
|
|
|
|
if ($Curses::UI::VERSION > 0.9602) { |
1540
|
|
|
|
|
|
|
|
1541
|
|
|
|
|
|
|
# In version 0.9603 has ben removed rootobject, but we need in this modules : |
1542
|
|
|
|
|
|
|
# - PDB/SourceView.pm |
1543
|
|
|
|
|
|
|
# - PDB/Dialog/Message.pm |
1544
|
|
|
|
|
|
|
$Curses::UI::rootobject = $cui; |
1545
|
|
|
|
|
|
|
} |
1546
|
|
|
|
|
|
|
|
1547
|
|
|
|
|
|
|
if ($Curses::UI::color_support) { |
1548
|
|
|
|
|
|
|
my $old_draw = \&Curses::UI::Widget::draw; |
1549
|
|
|
|
|
|
|
no warnings; |
1550
|
|
|
|
|
|
|
*Curses::UI::Widget::draw = sub (;$) { |
1551
|
|
|
|
|
|
|
my ($this) = @_; |
1552
|
|
|
|
|
|
|
if (defined $this->{-fg} && defined $this->{-bg}) { |
1553
|
|
|
|
|
|
|
my $canvas = |
1554
|
|
|
|
|
|
|
defined $this->{-borderscr} |
1555
|
|
|
|
|
|
|
? $this->{-borderscr} |
1556
|
|
|
|
|
|
|
: $this->{-canvasscr}; |
1557
|
|
|
|
|
|
|
$canvas->bkgdset(COLOR_PAIR($Curses::UI::color_object->get_color_pair($this->{-fg}, $this->{-bg}))); |
1558
|
|
|
|
|
|
|
} |
1559
|
|
|
|
|
|
|
&$old_draw(@_); |
1560
|
|
|
|
|
|
|
}; |
1561
|
|
|
|
|
|
|
} |
1562
|
|
|
|
|
|
|
|
1563
|
|
|
|
|
|
|
my $lower_height = int($cui->{-height} * 0.25); |
1564
|
|
|
|
|
|
|
my $half_width = int($cui->{-width} * 0.5); |
1565
|
|
|
|
|
|
|
|
1566
|
|
|
|
|
|
|
$sv_win = $cui->add( |
1567
|
|
|
|
|
|
|
'sv_win', 'Window', |
1568
|
|
|
|
|
|
|
-padtop => 1, |
1569
|
|
|
|
|
|
|
-padbottom => $lower_height, |
1570
|
|
|
|
|
|
|
-border => 0, |
1571
|
|
|
|
|
|
|
-ipad => 0, |
1572
|
|
|
|
|
|
|
-title => 'Source', |
1573
|
|
|
|
|
|
|
); |
1574
|
|
|
|
|
|
|
$sv = $sv_win->add( |
1575
|
|
|
|
|
|
|
'sv', 'Devel::PDB::SourceView', |
1576
|
|
|
|
|
|
|
-border => 1, |
1577
|
|
|
|
|
|
|
|
1578
|
|
|
|
|
|
|
#-padbottom => 3, |
1579
|
|
|
|
|
|
|
window_style(), |
1580
|
|
|
|
|
|
|
); |
1581
|
|
|
|
|
|
|
|
1582
|
|
|
|
|
|
|
$lower_win = $cui->add( |
1583
|
|
|
|
|
|
|
'lower_win', 'Window', |
1584
|
|
|
|
|
|
|
-border => 0, |
1585
|
|
|
|
|
|
|
-y => -1, |
1586
|
|
|
|
|
|
|
-height => $lower_height, |
1587
|
|
|
|
|
|
|
window_style(), |
1588
|
|
|
|
|
|
|
); |
1589
|
|
|
|
|
|
|
|
1590
|
|
|
|
|
|
|
$auto_win = $lower_win->add( |
1591
|
|
|
|
|
|
|
'auto_win', 'Window', |
1592
|
|
|
|
|
|
|
-border => 1, |
1593
|
|
|
|
|
|
|
-y => -1, |
1594
|
|
|
|
|
|
|
-width => $half_width, |
1595
|
|
|
|
|
|
|
-title => 'Auto', |
1596
|
|
|
|
|
|
|
window_style(), |
1597
|
|
|
|
|
|
|
); |
1598
|
|
|
|
|
|
|
$padvar_list = $auto_win->add( |
1599
|
|
|
|
|
|
|
'padvar_list', 'Devel::PDB::NamedListbox', |
1600
|
|
|
|
|
|
|
-readonly => 1, |
1601
|
|
|
|
|
|
|
-sort_key => 'name', |
1602
|
|
|
|
|
|
|
-named_list => \@padlist_disp, |
1603
|
|
|
|
|
|
|
); |
1604
|
|
|
|
|
|
|
$padvar_list->userdata($cui); |
1605
|
|
|
|
|
|
|
|
1606
|
|
|
|
|
|
|
$watch_win = $lower_win->add( |
1607
|
|
|
|
|
|
|
'watch_win', 'Window', |
1608
|
|
|
|
|
|
|
-border => 1, |
1609
|
|
|
|
|
|
|
-x => -1, |
1610
|
|
|
|
|
|
|
-y => -1, |
1611
|
|
|
|
|
|
|
-padleft => $half_width, |
1612
|
|
|
|
|
|
|
-title => 'Watch', |
1613
|
|
|
|
|
|
|
window_style(), |
1614
|
|
|
|
|
|
|
); |
1615
|
|
|
|
|
|
|
$watch_list = $watch_win->add( |
1616
|
|
|
|
|
|
|
'watch_list', 'Devel::PDB::NamedListbox', |
1617
|
|
|
|
|
|
|
|
1618
|
|
|
|
|
|
|
# -sort_key => 'name', # For sorting by name |
1619
|
|
|
|
|
|
|
-named_list => \@watch_exprs, |
1620
|
|
|
|
|
|
|
); |
1621
|
|
|
|
|
|
|
|
1622
|
|
|
|
|
|
|
my $fConfig = config_file("conf"); |
1623
|
|
|
|
|
|
|
|
1624
|
|
|
|
|
|
|
my @aFile = (); |
1625
|
|
|
|
|
|
|
my @aEdit = (); |
1626
|
|
|
|
|
|
|
my @aView = (); |
1627
|
|
|
|
|
|
|
my @aExecution = (); |
1628
|
|
|
|
|
|
|
my @aBreakpoint = (); |
1629
|
|
|
|
|
|
|
my @aSettings = (); |
1630
|
|
|
|
|
|
|
|
1631
|
|
|
|
|
|
|
set_key_binding(\&ui_db_help, "Keys", "Keys help", "\cK"); |
1632
|
|
|
|
|
|
|
set_key_binding(sub { shift->getobj('menu')->focus }, "Menu", "Main menu", KEY_F(10)); |
1633
|
|
|
|
|
|
|
|
1634
|
|
|
|
|
|
|
# Submenu - File |
1635
|
|
|
|
|
|
|
push(@aFile, set_key_binding(sub { db_view_std_files(0); $sv_win->focus; }, "ViewSTDFiles", "View STD* files", KEY_F(4))); |
1636
|
|
|
|
|
|
|
|
1637
|
|
|
|
|
|
|
push( |
1638
|
|
|
|
|
|
|
@aFile, |
1639
|
|
|
|
|
|
|
set_key_binding( |
1640
|
|
|
|
|
|
|
sub { |
1641
|
|
|
|
|
|
|
if ($ui_window_focused == 2) { |
1642
|
|
|
|
|
|
|
$update_watch_list = 1; |
1643
|
|
|
|
|
|
|
return; |
1644
|
|
|
|
|
|
|
} |
1645
|
|
|
|
|
|
|
|
1646
|
|
|
|
|
|
|
my $ret = $cui->dialog( |
1647
|
|
|
|
|
|
|
-title => 'Restarting program', |
1648
|
|
|
|
|
|
|
-buttons => [{ |
1649
|
|
|
|
|
|
|
-label => '< Save config first >', |
1650
|
|
|
|
|
|
|
-value => 1, |
1651
|
|
|
|
|
|
|
-shortcut => 's' |
1652
|
|
|
|
|
|
|
}, |
1653
|
|
|
|
|
|
|
{ -label => '< Restart only >', |
1654
|
|
|
|
|
|
|
-value => 2, |
1655
|
|
|
|
|
|
|
-shortcut => 'r' |
1656
|
|
|
|
|
|
|
}, |
1657
|
|
|
|
|
|
|
{ -label => '< Exit - Return >', |
1658
|
|
|
|
|
|
|
-value => 0, |
1659
|
|
|
|
|
|
|
-shortcut => 'x' |
1660
|
|
|
|
|
|
|
}, |
1661
|
|
|
|
|
|
|
], |
1662
|
|
|
|
|
|
|
-message => 'Choose option to restarting program', |
1663
|
|
|
|
|
|
|
window_style(), |
1664
|
|
|
|
|
|
|
); |
1665
|
|
|
|
|
|
|
if ($ret) { |
1666
|
|
|
|
|
|
|
save_state_file($fConfig) if ($ret == 1); |
1667
|
|
|
|
|
|
|
$db_exit = 1; |
1668
|
|
|
|
|
|
|
DoRestart(); |
1669
|
|
|
|
|
|
|
} |
1670
|
|
|
|
|
|
|
}, |
1671
|
|
|
|
|
|
|
"Restart", |
1672
|
|
|
|
|
|
|
"Restart program", |
1673
|
|
|
|
|
|
|
"\cR" |
1674
|
|
|
|
|
|
|
)); |
1675
|
|
|
|
|
|
|
push( |
1676
|
|
|
|
|
|
|
@aFile, |
1677
|
|
|
|
|
|
|
set_key_binding( |
1678
|
|
|
|
|
|
|
sub { |
1679
|
|
|
|
|
|
|
my $filename = $cui->filebrowser( |
1680
|
|
|
|
|
|
|
-title => "Find and load Perl module from file ", |
1681
|
|
|
|
|
|
|
-mask => [['\.p[lm]$', 'Perl modules']], |
1682
|
|
|
|
|
|
|
DB::window_style(), |
1683
|
|
|
|
|
|
|
); |
1684
|
|
|
|
|
|
|
if ($filename) { |
1685
|
|
|
|
|
|
|
if (!exists($main::{"_<$filename"})) { |
1686
|
|
|
|
|
|
|
|
1687
|
|
|
|
|
|
|
# Delete dir from modules in actuall directory |
1688
|
|
|
|
|
|
|
my $dir = getcwd(); |
1689
|
|
|
|
|
|
|
if ($dir) { |
1690
|
|
|
|
|
|
|
$dir .= "/"; |
1691
|
|
|
|
|
|
|
$filename =~ s/$dir//; |
1692
|
|
|
|
|
|
|
} |
1693
|
|
|
|
|
|
|
require $filename; |
1694
|
|
|
|
|
|
|
} |
1695
|
|
|
|
|
|
|
my $source = $current_source = get_source($filename); |
1696
|
|
|
|
|
|
|
$sv->source($source) if $source; |
1697
|
|
|
|
|
|
|
$sv->intellidraw; |
1698
|
|
|
|
|
|
|
} |
1699
|
|
|
|
|
|
|
$sv_win->focus; |
1700
|
|
|
|
|
|
|
}, |
1701
|
|
|
|
|
|
|
"Filebrowser", |
1702
|
|
|
|
|
|
|
"Find and load Perl module via browser", |
1703
|
|
|
|
|
|
|
"\cF" |
1704
|
|
|
|
|
|
|
)); |
1705
|
|
|
|
|
|
|
push( |
1706
|
|
|
|
|
|
|
@aFile, |
1707
|
|
|
|
|
|
|
set_key_binding( |
1708
|
|
|
|
|
|
|
sub { ui_open_file('Compiled Files', \@compiled); }, |
1709
|
|
|
|
|
|
|
"FilesCompiled", "Show 'Compiled Files' Dialog", |
1710
|
|
|
|
|
|
|
KEY_F(11))); |
1711
|
|
|
|
|
|
|
push( |
1712
|
|
|
|
|
|
|
@aFile, |
1713
|
|
|
|
|
|
|
set_key_binding( |
1714
|
|
|
|
|
|
|
sub { ui_open_file('Opened Files', [keys(%sources)]); }, |
1715
|
|
|
|
|
|
|
"FilesOpened", "Show 'Opened Files' Dialog", |
1716
|
|
|
|
|
|
|
KEY_F(12))); |
1717
|
|
|
|
|
|
|
push(@aFile, set_key_binding(\&ui_db_export, "Export", "Export information", "\cY")); |
1718
|
|
|
|
|
|
|
push( |
1719
|
|
|
|
|
|
|
@aFile, |
1720
|
|
|
|
|
|
|
set_key_binding( |
1721
|
|
|
|
|
|
|
sub { |
1722
|
|
|
|
|
|
|
redrawwin($stdscr); |
1723
|
|
|
|
|
|
|
ui_update_watch_list(); |
1724
|
|
|
|
|
|
|
refresh_stack_menu(); |
1725
|
|
|
|
|
|
|
$cui->draw; |
1726
|
|
|
|
|
|
|
}, |
1727
|
|
|
|
|
|
|
"Refresh", |
1728
|
|
|
|
|
|
|
"Refresh windows", |
1729
|
|
|
|
|
|
|
"\cN" |
1730
|
|
|
|
|
|
|
)); |
1731
|
|
|
|
|
|
|
push(@aFile, set_key_binding(\&ui_db_quit, "Quit", "Quit the debugger", "\cQ", "\cC")); |
1732
|
|
|
|
|
|
|
|
1733
|
|
|
|
|
|
|
# Submenu - Execution |
1734
|
|
|
|
|
|
|
push(@aExecution, set_key_binding(\&db_cont, "Continue", "Run|Continue execution", KEY_F(5))); |
1735
|
|
|
|
|
|
|
push(@aExecution, set_key_binding(\&db_step_out, "StepOut", "Step Out", KEY_F(6))); |
1736
|
|
|
|
|
|
|
push(@aExecution, set_key_binding(\&db_step_in, "StepIn", "Step In", KEY_F(7))); |
1737
|
|
|
|
|
|
|
push(@aExecution, set_key_binding(\&db_step_over, "StepOver", "Step Over", KEY_F(8))); |
1738
|
|
|
|
|
|
|
push( |
1739
|
|
|
|
|
|
|
@aExecution, |
1740
|
|
|
|
|
|
|
set_key_binding( |
1741
|
|
|
|
|
|
|
sub { |
1742
|
|
|
|
|
|
|
if ($ui_window_focused == 2) { |
1743
|
|
|
|
|
|
|
db_edit_watch_expr($watch_list); |
1744
|
|
|
|
|
|
|
} else { |
1745
|
|
|
|
|
|
|
ui_text_editor(1); |
1746
|
|
|
|
|
|
|
} |
1747
|
|
|
|
|
|
|
}, |
1748
|
|
|
|
|
|
|
"ArgumentsEdit", |
1749
|
|
|
|
|
|
|
"Edit program paramaters or watched variable", |
1750
|
|
|
|
|
|
|
"\cE" |
1751
|
|
|
|
|
|
|
)); |
1752
|
|
|
|
|
|
|
push(@aExecution, set_key_binding(sub { ui_text_editor(2); }, "EnviromentsEdit", "Edit enviroment paramaters", "\cM")); |
1753
|
|
|
|
|
|
|
push( |
1754
|
|
|
|
|
|
|
@aExecution, |
1755
|
|
|
|
|
|
|
set_key_binding( |
1756
|
|
|
|
|
|
|
sub { |
1757
|
|
|
|
|
|
|
my $ret = $cui->question( |
1758
|
|
|
|
|
|
|
-title => 'Command Execution', |
1759
|
|
|
|
|
|
|
-question => 'Please enter an command to enter', |
1760
|
|
|
|
|
|
|
DB::window_style(), |
1761
|
|
|
|
|
|
|
); |
1762
|
|
|
|
|
|
|
$usercontext = $ret if ($ret); |
1763
|
|
|
|
|
|
|
}, |
1764
|
|
|
|
|
|
|
"RunCommand", |
1765
|
|
|
|
|
|
|
"Run perl command", |
1766
|
|
|
|
|
|
|
"\cP" |
1767
|
|
|
|
|
|
|
)); |
1768
|
|
|
|
|
|
|
|
1769
|
|
|
|
|
|
|
# Submenu - Breakpoint |
1770
|
|
|
|
|
|
|
push(@aBreakpoint, |
1771
|
|
|
|
|
|
|
set_key_binding(sub { set_active_window(1); db_toggle_break(0, undef) }, "Breakpoint", "Toggle Breakpoint", KEY_F(9))); |
1772
|
|
|
|
|
|
|
push( |
1773
|
|
|
|
|
|
|
@aBreakpoint, |
1774
|
|
|
|
|
|
|
set_key_binding( |
1775
|
|
|
|
|
|
|
sub { set_active_window(1); db_toggle_break(1, undef) }, |
1776
|
|
|
|
|
|
|
"BreakpointCode", "Toggle Breakpoint Code", "\cO" |
1777
|
|
|
|
|
|
|
)); |
1778
|
|
|
|
|
|
|
push(@aBreakpoint, set_key_binding(sub { db_add_watch_expr(undef) }, "WatchExpression", "Add watch expression", "\cW")); |
1779
|
|
|
|
|
|
|
push(@aBreakpoint, set_key_binding(\&ui_list_breakpoints, "ListBreakpoints", "List all breakpoints", "\cB")); |
1780
|
|
|
|
|
|
|
push(@aBreakpoint, set_key_binding(\&clearalldblines, "ClearBreakpoints", "Clear all breakpoints")); |
1781
|
|
|
|
|
|
|
push(@aBreakpoint, |
1782
|
|
|
|
|
|
|
set_key_binding(sub { @watch_exprs = (); $update_watch_list = 1; }, "ClearWatches", "Clear all watches")); |
1783
|
|
|
|
|
|
|
push( |
1784
|
|
|
|
|
|
|
@aBreakpoint, |
1785
|
|
|
|
|
|
|
set_key_binding( |
1786
|
|
|
|
|
|
|
sub { &clearalldblines(); @watch_exprs = (); $update_watch_list = 1; }, |
1787
|
|
|
|
|
|
|
"ClearAll", "Clear all settings", "\cX" |
1788
|
|
|
|
|
|
|
)); |
1789
|
|
|
|
|
|
|
|
1790
|
|
|
|
|
|
|
# Submenu - Settings |
1791
|
|
|
|
|
|
|
push( |
1792
|
|
|
|
|
|
|
@aSettings, |
1793
|
|
|
|
|
|
|
set_key_binding( |
1794
|
|
|
|
|
|
|
sub { |
1795
|
|
|
|
|
|
|
my $ret = $cui->dialog( |
1796
|
|
|
|
|
|
|
-title => 'Load saved config files', |
1797
|
|
|
|
|
|
|
-buttons => [{ |
1798
|
|
|
|
|
|
|
-label => '< User conf >', |
1799
|
|
|
|
|
|
|
-value => 1, |
1800
|
|
|
|
|
|
|
-shortcut => 'u' |
1801
|
|
|
|
|
|
|
}, |
1802
|
|
|
|
|
|
|
{ -label => '< Default conf >', |
1803
|
|
|
|
|
|
|
-value => 2, |
1804
|
|
|
|
|
|
|
-shortcut => 'd' |
1805
|
|
|
|
|
|
|
}, |
1806
|
|
|
|
|
|
|
{ -label => '< Exit >', |
1807
|
|
|
|
|
|
|
-value => 0, |
1808
|
|
|
|
|
|
|
-shortcut => 'x' |
1809
|
|
|
|
|
|
|
}, |
1810
|
|
|
|
|
|
|
], |
1811
|
|
|
|
|
|
|
-message => 'Do you really want load config?', |
1812
|
|
|
|
|
|
|
window_style(), |
1813
|
|
|
|
|
|
|
); |
1814
|
|
|
|
|
|
|
if ($ret) { |
1815
|
|
|
|
|
|
|
load_state_file($fConfig, ($ret == 2 ? ".rc" : "")); |
1816
|
|
|
|
|
|
|
$user_conf_readed = $ret == 1 ? 1 : 0; |
1817
|
|
|
|
|
|
|
} |
1818
|
|
|
|
|
|
|
}, |
1819
|
|
|
|
|
|
|
"ConfigLoad", |
1820
|
|
|
|
|
|
|
"Load config file", |
1821
|
|
|
|
|
|
|
"\cL" |
1822
|
|
|
|
|
|
|
)); |
1823
|
|
|
|
|
|
|
push( |
1824
|
|
|
|
|
|
|
@aSettings, |
1825
|
|
|
|
|
|
|
set_key_binding( |
1826
|
|
|
|
|
|
|
sub { |
1827
|
|
|
|
|
|
|
save_state_file($fConfig) |
1828
|
|
|
|
|
|
|
if $cui->dialog( |
1829
|
|
|
|
|
|
|
-title => 'Save config file', |
1830
|
|
|
|
|
|
|
-buttons => ['yes', 'no'], |
1831
|
|
|
|
|
|
|
-message => 'Do you really want save config?', |
1832
|
|
|
|
|
|
|
window_style(), |
1833
|
|
|
|
|
|
|
); |
1834
|
|
|
|
|
|
|
}, |
1835
|
|
|
|
|
|
|
"ConfigSave", |
1836
|
|
|
|
|
|
|
"Save config file", |
1837
|
|
|
|
|
|
|
"\cS" |
1838
|
|
|
|
|
|
|
)); |
1839
|
|
|
|
|
|
|
|
1840
|
|
|
|
|
|
|
# Submenu - View |
1841
|
|
|
|
|
|
|
push( |
1842
|
|
|
|
|
|
|
@aView, |
1843
|
|
|
|
|
|
|
set_key_binding( |
1844
|
|
|
|
|
|
|
sub { |
1845
|
|
|
|
|
|
|
my $text; |
1846
|
|
|
|
|
|
|
local $Data::Dumper::Purity = 0; |
1847
|
|
|
|
|
|
|
local $Data::Dumper::Terse = 1; |
1848
|
|
|
|
|
|
|
local $Data::Dumper::Indent = 2; |
1849
|
|
|
|
|
|
|
local $Data::Dumper::Sortkeys = 1; |
1850
|
|
|
|
|
|
|
$text = (scalar(@Devel::PDB::script_args) ? Dumper(@Devel::PDB::script_args) : "Not arguments putted"); |
1851
|
|
|
|
|
|
|
dialog_message( |
1852
|
|
|
|
|
|
|
-title => "Arguments", |
1853
|
|
|
|
|
|
|
-message => $text |
1854
|
|
|
|
|
|
|
); |
1855
|
|
|
|
|
|
|
|
1856
|
|
|
|
|
|
|
}, |
1857
|
|
|
|
|
|
|
"Arguments", |
1858
|
|
|
|
|
|
|
"View program parameters", |
1859
|
|
|
|
|
|
|
"\cA" |
1860
|
|
|
|
|
|
|
)); |
1861
|
|
|
|
|
|
|
push(@aView, set_key_binding(sub { set_active_window(1) }, "WindowSource", "Switch to the Source Code Window", KEY_F(1))); |
1862
|
|
|
|
|
|
|
push(@aView, |
1863
|
|
|
|
|
|
|
set_key_binding(sub { set_active_window(2) }, "WindowLexical", "Switch to the Lexical Variable Window", KEY_F(2))); |
1864
|
|
|
|
|
|
|
push(@aView, set_key_binding(sub { set_active_window(3) }, "WindowWatches", "Switch to the Watch Window", KEY_F(3))); |
1865
|
|
|
|
|
|
|
push(@aView, set_key_binding(sub { ui_view_stack(0) }, "WindowStack", "View Stack Window", "\cT")); |
1866
|
|
|
|
|
|
|
push(@aView, set_key_binding(sub { ui_text_editor(3) }, "ViewVariables", "View special variables", "\cU")); |
1867
|
|
|
|
|
|
|
|
1868
|
|
|
|
|
|
|
push(@aView, |
1869
|
|
|
|
|
|
|
set_key_binding(sub { ui_adjust_vert_parts(1) }, "VerticalPartsMin", "Vertical window(Source file) minimize", '{')); |
1870
|
|
|
|
|
|
|
push(@aView, |
1871
|
|
|
|
|
|
|
set_key_binding(sub { ui_adjust_vert_parts(-1) }, "VerticalPartsMax", "Vertical window(Source file) maximize", '}')); |
1872
|
|
|
|
|
|
|
push(@aView, |
1873
|
|
|
|
|
|
|
set_key_binding(sub { ui_adjust_hori_parts(-1) }, "HorizontalPartsMin", "Horizontal window(Stack) minimize", '[')); |
1874
|
|
|
|
|
|
|
push(@aView, |
1875
|
|
|
|
|
|
|
set_key_binding(sub { ui_adjust_hori_parts(1) }, "HorizontalPartsMin", "Horizontal window(Stack) maximize", ']')); |
1876
|
|
|
|
|
|
|
|
1877
|
|
|
|
|
|
|
$cui->add( |
1878
|
|
|
|
|
|
|
'menu', |
1879
|
|
|
|
|
|
|
'Menubar', |
1880
|
|
|
|
|
|
|
-menu => [{ |
1881
|
|
|
|
|
|
|
-label => 'File', |
1882
|
|
|
|
|
|
|
-submenu => \@aFile, |
1883
|
|
|
|
|
|
|
}, |
1884
|
|
|
|
|
|
|
{ -label => 'View', |
1885
|
|
|
|
|
|
|
-submenu => \@aView, |
1886
|
|
|
|
|
|
|
}, |
1887
|
|
|
|
|
|
|
{ -label => 'Execution', |
1888
|
|
|
|
|
|
|
-submenu => \@aExecution, |
1889
|
|
|
|
|
|
|
}, |
1890
|
|
|
|
|
|
|
{ -label => 'Breakpoint', |
1891
|
|
|
|
|
|
|
-submenu => \@aBreakpoint, |
1892
|
|
|
|
|
|
|
}, |
1893
|
|
|
|
|
|
|
{ -label => 'Settings', |
1894
|
|
|
|
|
|
|
-submenu => \@aSettings, |
1895
|
|
|
|
|
|
|
}, |
1896
|
|
|
|
|
|
|
{ -label => 'Help', |
1897
|
|
|
|
|
|
|
-submenu => [{ |
1898
|
|
|
|
|
|
|
-label => 'Keys', |
1899
|
|
|
|
|
|
|
-value => \&ui_db_help, |
1900
|
|
|
|
|
|
|
}, |
1901
|
|
|
|
|
|
|
{ -label => 'About', |
1902
|
|
|
|
|
|
|
-value => sub { |
1903
|
|
|
|
|
|
|
dialog_message( |
1904
|
|
|
|
|
|
|
-title => "About", |
1905
|
|
|
|
|
|
|
-message => <
|
1906
|
|
|
|
|
|
|
Devel::PDB - A simple Curses-based Perl DeBugger in version $VERSION |
1907
|
|
|
|
|
|
|
|
1908
|
|
|
|
|
|
|
PerlDeBugger is a Curses-based Perl debugger with most of the essential functions such as monitoring windows for paddlist, |
1909
|
|
|
|
|
|
|
call stack, custom watch expressions, etc. |
1910
|
|
|
|
|
|
|
Suitable for debugging or tracing complicated Perl applications on the spot. |
1911
|
|
|
|
|
|
|
|
1912
|
|
|
|
|
|
|
AUTHORS |
1913
|
|
|
|
|
|
|
Ivan Yat-Cheung Wong |
1914
|
|
|
|
|
|
|
Igor Bujna |
1915
|
|
|
|
|
|
|
|
1916
|
|
|
|
|
|
|
MODULES |
1917
|
|
|
|
|
|
|
Curses - $Curses::VERSION |
1918
|
|
|
|
|
|
|
Curses:UI - $Curses::UI::VERSION |
1919
|
|
|
|
|
|
|
|
1920
|
|
|
|
|
|
|
EOF |
1921
|
|
|
|
|
|
|
, |
1922
|
|
|
|
|
|
|
DB::window_style(), |
1923
|
|
|
|
|
|
|
); |
1924
|
|
|
|
|
|
|
}, |
1925
|
|
|
|
|
|
|
}, |
1926
|
|
|
|
|
|
|
] |
1927
|
|
|
|
|
|
|
}, |
1928
|
|
|
|
|
|
|
], |
1929
|
|
|
|
|
|
|
window_style(), |
1930
|
|
|
|
|
|
|
); |
1931
|
|
|
|
|
|
|
|
1932
|
|
|
|
|
|
|
#open my $fd0, '>stdout'; |
1933
|
|
|
|
|
|
|
#open my $fd1, '>stderr'; |
1934
|
|
|
|
|
|
|
#open STDOUT, ">&$fd0"; |
1935
|
|
|
|
|
|
|
#open STDERR, ">&$fd1"; |
1936
|
|
|
|
|
|
|
#open STDOUT, ">stdout"; |
1937
|
|
|
|
|
|
|
|
1938
|
|
|
|
|
|
|
unlink config_file($_) foreach ('stderr', 'stdout'); |
1939
|
|
|
|
|
|
|
open STDERR, ">>" . config_file("stderr"); |
1940
|
|
|
|
|
|
|
open $output, ">>" . config_file("stdout"); |
1941
|
|
|
|
|
|
|
open $stdout, ">>&STDOUT"; |
1942
|
|
|
|
|
|
|
|
1943
|
|
|
|
|
|
|
select(STDERR); |
1944
|
|
|
|
|
|
|
$| = 1; |
1945
|
|
|
|
|
|
|
select(STDOUT); |
1946
|
|
|
|
|
|
|
$| = 1; |
1947
|
|
|
|
|
|
|
|
1948
|
|
|
|
|
|
|
$inited = 1; |
1949
|
|
|
|
|
|
|
|
1950
|
|
|
|
|
|
|
# Load actual breakpoints and watches |
1951
|
|
|
|
|
|
|
load_state_file(config_file("conf.rc")); |
1952
|
|
|
|
|
|
|
} |
1953
|
|
|
|
|
|
|
|
1954
|
|
|
|
|
|
|
# |
1955
|
|
|
|
|
|
|
# Return for given filename which find or creater for given param |
1956
|
|
|
|
|
|
|
# |
1957
|
|
|
|
|
|
|
sub get_source { |
1958
|
|
|
|
|
|
|
my $filename = shift; |
1959
|
|
|
|
|
|
|
my $source = $sources{$filename}; |
1960
|
|
|
|
|
|
|
|
1961
|
|
|
|
|
|
|
if (!defined $source) { |
1962
|
|
|
|
|
|
|
local (*dbline) = $main::{"_<$filename"}; |
1963
|
|
|
|
|
|
|
$sources{$filename} = $source = new Devel::PDB::Source( |
1964
|
|
|
|
|
|
|
filename => $filename, |
1965
|
|
|
|
|
|
|
lines => \@dbline, |
1966
|
|
|
|
|
|
|
breaks => \%dbline, |
1967
|
|
|
|
|
|
|
); |
1968
|
|
|
|
|
|
|
} |
1969
|
|
|
|
|
|
|
|
1970
|
|
|
|
|
|
|
return $source; |
1971
|
|
|
|
|
|
|
} |
1972
|
|
|
|
|
|
|
|
1973
|
|
|
|
|
|
|
# |
1974
|
|
|
|
|
|
|
# Updating watch list in Watches window |
1975
|
|
|
|
|
|
|
# |
1976
|
|
|
|
|
|
|
sub ui_update_watch_list { |
1977
|
|
|
|
|
|
|
local $Data::Dumper::Terse = 1; |
1978
|
|
|
|
|
|
|
local $Data::Dumper::Maxdepth; |
1979
|
|
|
|
|
|
|
local $Data::Dumper::Indent; |
1980
|
|
|
|
|
|
|
local $Data::Dumper::Sortkeys = 1; |
1981
|
|
|
|
|
|
|
|
1982
|
|
|
|
|
|
|
foreach my $expr (@watch_exprs) { |
1983
|
|
|
|
|
|
|
$evalarg = $expr->{name}; |
1984
|
|
|
|
|
|
|
my $res = &DB::eval; |
1985
|
|
|
|
|
|
|
$Data::Dumper::Indent = 0; |
1986
|
|
|
|
|
|
|
$Data::Dumper::Maxdepth = 2; |
1987
|
|
|
|
|
|
|
$expr->{value} = Dumper $res; |
1988
|
|
|
|
|
|
|
$Data::Dumper::Indent = 1; |
1989
|
|
|
|
|
|
|
$Data::Dumper::Maxdepth = 0; |
1990
|
|
|
|
|
|
|
$expr->{long_value} = Dumper $res; |
1991
|
|
|
|
|
|
|
} |
1992
|
|
|
|
|
|
|
|
1993
|
|
|
|
|
|
|
$watch_list->update; |
1994
|
|
|
|
|
|
|
} |
1995
|
|
|
|
|
|
|
|
1996
|
|
|
|
|
|
|
# |
1997
|
|
|
|
|
|
|
# Perl Debugger methods |
1998
|
|
|
|
|
|
|
# |
1999
|
|
|
|
|
|
|
my @saved; |
2000
|
|
|
|
|
|
|
|
2001
|
|
|
|
|
|
|
sub save { |
2002
|
|
|
|
|
|
|
@saved = ($@, $!, $,, $/, $\, $^W); |
2003
|
|
|
|
|
|
|
$, = ''; |
2004
|
|
|
|
|
|
|
$/ = "\n"; |
2005
|
|
|
|
|
|
|
$\ = ''; |
2006
|
|
|
|
|
|
|
$^W = 0; |
2007
|
|
|
|
|
|
|
} |
2008
|
|
|
|
|
|
|
|
2009
|
|
|
|
|
|
|
sub eval { |
2010
|
|
|
|
|
|
|
($@, $!, $,, $/, $\, $^W) = @saved; |
2011
|
|
|
|
|
|
|
my $res = eval "package $package; $evalarg"; |
2012
|
|
|
|
|
|
|
|
2013
|
|
|
|
|
|
|
#my $res = eval 'no strict;($@, $!, $^E, $,, $/, $\, $^W) = @saved;' . "package $package;$evalarg ;"; |
2014
|
|
|
|
|
|
|
|
2015
|
|
|
|
|
|
|
save; |
2016
|
|
|
|
|
|
|
$res; |
2017
|
|
|
|
|
|
|
} |
2018
|
|
|
|
|
|
|
|
2019
|
|
|
|
|
|
|
# Main method which is load when program started, stopped or step in position where is breakpoint |
2020
|
|
|
|
|
|
|
sub DB { |
2021
|
|
|
|
|
|
|
return if $exit; |
2022
|
|
|
|
|
|
|
save; |
2023
|
|
|
|
|
|
|
init if !$inited; |
2024
|
|
|
|
|
|
|
|
2025
|
|
|
|
|
|
|
RESTART: |
2026
|
|
|
|
|
|
|
open STDOUT, ">>&", $stdout; |
2027
|
|
|
|
|
|
|
|
2028
|
|
|
|
|
|
|
($package, $filename, $line) = caller; |
2029
|
|
|
|
|
|
|
|
2030
|
|
|
|
|
|
|
my $scope = $current_sub ? $current_sub : $package; |
2031
|
|
|
|
|
|
|
my $renew = !defined $padlist_scope || $scope ne $padlist_scope; |
2032
|
|
|
|
|
|
|
if ($renew) { |
2033
|
|
|
|
|
|
|
%padlist = (); |
2034
|
|
|
|
|
|
|
@padlist_disp = (); |
2035
|
|
|
|
|
|
|
$padlist_scope = $scope; |
2036
|
|
|
|
|
|
|
} |
2037
|
|
|
|
|
|
|
|
2038
|
|
|
|
|
|
|
# BUGS: |
2039
|
|
|
|
|
|
|
# compadlist not return, not defined variables. |
2040
|
|
|
|
|
|
|
# Variables must be defined via (my,our,....etc) or 'use strict;' on yours script |
2041
|
|
|
|
|
|
|
{ |
2042
|
|
|
|
|
|
|
my ($names, $vals) = |
2043
|
|
|
|
|
|
|
$scope eq 'main' |
2044
|
|
|
|
|
|
|
? comppadlist->ARRAY |
2045
|
|
|
|
|
|
|
: svref_2object(\&$scope)->PADLIST->ARRAY; |
2046
|
|
|
|
|
|
|
my @names = $names->ARRAY; |
2047
|
|
|
|
|
|
|
my @vals = $vals->ARRAY; |
2048
|
|
|
|
|
|
|
my $count = @names; |
2049
|
|
|
|
|
|
|
|
2050
|
|
|
|
|
|
|
refresh_stack_menu(); |
2051
|
|
|
|
|
|
|
|
2052
|
|
|
|
|
|
|
local $Data::Dumper::Terse = 1; |
2053
|
|
|
|
|
|
|
local $Data::Dumper::Maxdepth; |
2054
|
|
|
|
|
|
|
local $Data::Dumper::Indent; |
2055
|
|
|
|
|
|
|
local $Data::Dumper::Sortkeys = 1; |
2056
|
|
|
|
|
|
|
|
2057
|
|
|
|
|
|
|
my %h_pd = map { $_->{name} => $_ } @padlist_disp; |
2058
|
|
|
|
|
|
|
|
2059
|
|
|
|
|
|
|
for (my ($i, $j) = (0, 0); $i < $count; $i++) { |
2060
|
|
|
|
|
|
|
my $sv = $names[$i]; |
2061
|
|
|
|
|
|
|
next if class($sv) eq 'SPECIAL'; |
2062
|
|
|
|
|
|
|
my $name = $sv->PVX; |
2063
|
|
|
|
|
|
|
$Data::Dumper::Indent = 0; |
2064
|
|
|
|
|
|
|
$Data::Dumper::Maxdepth = 2; |
2065
|
|
|
|
|
|
|
my $val = Dumper $vals[$i]->object_2svref; |
2066
|
|
|
|
|
|
|
$val =~ s/^\\// if class($sv) ne 'RV'; |
2067
|
|
|
|
|
|
|
$Data::Dumper::Indent = 1; |
2068
|
|
|
|
|
|
|
$Data::Dumper::Maxdepth = 0; |
2069
|
|
|
|
|
|
|
my $long_val = Dumper $vals[$i]->object_2svref; |
2070
|
|
|
|
|
|
|
$long_val =~ s/^\\// if class($sv) ne 'RV'; |
2071
|
|
|
|
|
|
|
|
2072
|
|
|
|
|
|
|
if ($renew || $val ne $padlist{$name}) { |
2073
|
|
|
|
|
|
|
my $rh = {name => $name, value => $val, long_value => $long_val}; |
2074
|
|
|
|
|
|
|
$padlist_disp[$j] = $rh; |
2075
|
|
|
|
|
|
|
$padlist{$name} = $val; |
2076
|
|
|
|
|
|
|
$h_pd{$name} = $rh; |
2077
|
|
|
|
|
|
|
} |
2078
|
|
|
|
|
|
|
++$j; |
2079
|
|
|
|
|
|
|
} |
2080
|
|
|
|
|
|
|
|
2081
|
|
|
|
|
|
|
# Sorting values in stack by name |
2082
|
|
|
|
|
|
|
@padlist_disp = (); |
2083
|
|
|
|
|
|
|
@padlist_disp = sort { $a->{name} cmp $b->{name} } values %h_pd; |
2084
|
|
|
|
|
|
|
|
2085
|
|
|
|
|
|
|
$padvar_list->update($renew); |
2086
|
|
|
|
|
|
|
} |
2087
|
|
|
|
|
|
|
|
2088
|
|
|
|
|
|
|
#local (*dbline) = $main::{"_<$filename"}; |
2089
|
|
|
|
|
|
|
$sv->source($current_source = get_source($filename)); |
2090
|
|
|
|
|
|
|
$current_source->current_line($line); |
2091
|
|
|
|
|
|
|
|
2092
|
|
|
|
|
|
|
ui_update_watch_list; |
2093
|
|
|
|
|
|
|
|
2094
|
|
|
|
|
|
|
$yield = 0; |
2095
|
|
|
|
|
|
|
|
2096
|
|
|
|
|
|
|
# Breakpoint with action |
2097
|
|
|
|
|
|
|
my $brkp = $current_source->ret_line_breakpoint(); |
2098
|
|
|
|
|
|
|
my ($stop, $action) = $brkp ? split(/\0/, $brkp) : (); |
2099
|
|
|
|
|
|
|
if ($action) { |
2100
|
|
|
|
|
|
|
my $res = eval "return 1 if ($action); return 0;\n"; |
2101
|
|
|
|
|
|
|
if ($@) { |
2102
|
|
|
|
|
|
|
my $str = $@; |
2103
|
|
|
|
|
|
|
db_toggle_break(1, \$str); |
2104
|
|
|
|
|
|
|
} |
2105
|
|
|
|
|
|
|
$yield = 1 unless ($res); |
2106
|
|
|
|
|
|
|
} |
2107
|
|
|
|
|
|
|
|
2108
|
|
|
|
|
|
|
$new_single = $single; |
2109
|
|
|
|
|
|
|
$cui->focus(undef, 1); |
2110
|
|
|
|
|
|
|
$cui->draw; |
2111
|
|
|
|
|
|
|
$update_watch_list = 0; |
2112
|
|
|
|
|
|
|
while (!$yield) { |
2113
|
|
|
|
|
|
|
|
2114
|
|
|
|
|
|
|
# Wait for any key |
2115
|
|
|
|
|
|
|
$cui->do_one_event; |
2116
|
|
|
|
|
|
|
if ($update_watch_list) { |
2117
|
|
|
|
|
|
|
ui_update_watch_list; |
2118
|
|
|
|
|
|
|
$cui->draw; |
2119
|
|
|
|
|
|
|
} |
2120
|
|
|
|
|
|
|
|
2121
|
|
|
|
|
|
|
if ($usercontext) { # User eval |
2122
|
|
|
|
|
|
|
#my $usc = 'no strict;($@, $!, $^E, $,, $/, $\, $^W) = @saved;' . "package $package;"; |
2123
|
|
|
|
|
|
|
#my $arg = "\$^D = \$^D | \$DB::db_stop;\n$usercontext"; |
2124
|
|
|
|
|
|
|
#eval "$usc $arg;\n"; |
2125
|
|
|
|
|
|
|
eval "$usercontext;\n"; |
2126
|
|
|
|
|
|
|
print_error($@) if ($@); |
2127
|
|
|
|
|
|
|
$usercontext = undef; |
2128
|
|
|
|
|
|
|
goto RESTART; |
2129
|
|
|
|
|
|
|
} |
2130
|
|
|
|
|
|
|
} |
2131
|
|
|
|
|
|
|
$single = $new_single; |
2132
|
|
|
|
|
|
|
|
2133
|
|
|
|
|
|
|
open STDOUT, ">>&", $output; |
2134
|
|
|
|
|
|
|
($@, $!, $,, $/, $\, $^W) = @saved; |
2135
|
|
|
|
|
|
|
} |
2136
|
|
|
|
|
|
|
|
2137
|
|
|
|
|
|
|
sub sub { |
2138
|
|
|
|
|
|
|
my ($ret, @ret); |
2139
|
|
|
|
|
|
|
|
2140
|
|
|
|
|
|
|
local $current_sub = $sub; |
2141
|
|
|
|
|
|
|
local $stack_depth = $stack_depth + 1; |
2142
|
|
|
|
|
|
|
$#stack = $stack_depth; |
2143
|
|
|
|
|
|
|
$stack[-1] = $single; |
2144
|
|
|
|
|
|
|
$single &= 1; |
2145
|
|
|
|
|
|
|
|
2146
|
|
|
|
|
|
|
if (wantarray) { |
2147
|
|
|
|
|
|
|
no strict; |
2148
|
|
|
|
|
|
|
@ret = &$sub; |
2149
|
|
|
|
|
|
|
use strict; |
2150
|
|
|
|
|
|
|
$single |= $stack[$stack_depth--]; |
2151
|
|
|
|
|
|
|
@ret; |
2152
|
|
|
|
|
|
|
} else { |
2153
|
|
|
|
|
|
|
if (defined wantarray) { |
2154
|
|
|
|
|
|
|
no strict; |
2155
|
|
|
|
|
|
|
$ret = &$sub; |
2156
|
|
|
|
|
|
|
use strict; |
2157
|
|
|
|
|
|
|
} else { |
2158
|
|
|
|
|
|
|
no strict; |
2159
|
|
|
|
|
|
|
&$sub; |
2160
|
|
|
|
|
|
|
use strict; |
2161
|
|
|
|
|
|
|
undef $ret; |
2162
|
|
|
|
|
|
|
} |
2163
|
|
|
|
|
|
|
|
2164
|
|
|
|
|
|
|
$single |= $stack[$stack_depth--]; |
2165
|
|
|
|
|
|
|
$ret; |
2166
|
|
|
|
|
|
|
} |
2167
|
|
|
|
|
|
|
} |
2168
|
|
|
|
|
|
|
|
2169
|
|
|
|
|
|
|
sub postponed { |
2170
|
|
|
|
|
|
|
my $file = shift; |
2171
|
|
|
|
|
|
|
push @compiled, $$file; |
2172
|
|
|
|
|
|
|
|
2173
|
|
|
|
|
|
|
my $key = "_<" . $$file; |
2174
|
|
|
|
|
|
|
return if (!exists($postponed_file{$key})); |
2175
|
|
|
|
|
|
|
|
2176
|
|
|
|
|
|
|
set_breakpoints($key, $postponed_file{$key}); |
2177
|
|
|
|
|
|
|
delete($postponed_file{$key}); |
2178
|
|
|
|
|
|
|
|
2179
|
|
|
|
|
|
|
} |
2180
|
|
|
|
|
|
|
|
2181
|
|
|
|
|
|
|
package Devel::PDB; |
2182
|
|
|
|
|
|
|
|
2183
|
|
|
|
|
|
|
1; |
2184
|
|
|
|
|
|
|
|
2185
|
|
|
|
|
|
|
__END__ |