line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Devel::Comments; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
######## use section ######## |
4
|
25
|
|
|
25
|
|
133911
|
use 5.008; |
|
25
|
|
|
|
|
90
|
|
|
25
|
|
|
|
|
1497
|
|
5
|
25
|
|
|
25
|
|
133
|
use strict; |
|
25
|
|
|
|
|
45
|
|
|
25
|
|
|
|
|
1132
|
|
6
|
25
|
|
|
25
|
|
128
|
use warnings; |
|
25
|
|
|
|
|
144
|
|
|
25
|
|
|
|
|
943
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# Please see the file VERSIONS. |
9
|
25
|
|
|
25
|
|
32766
|
use version 0.77; our $VERSION = qv('1.1.4'); |
|
25
|
|
|
|
|
117115
|
|
|
25
|
|
|
|
|
196
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# original S::C (originally used here) |
12
|
25
|
|
|
25
|
|
2813
|
use Carp; |
|
25
|
|
|
|
|
49
|
|
|
25
|
|
|
|
|
3722
|
|
13
|
25
|
|
|
25
|
|
149
|
use List::Util qw(sum); |
|
25
|
|
|
|
|
47
|
|
|
25
|
|
|
|
|
4343
|
|
14
|
25
|
|
|
25
|
|
38171
|
use Filter::Simple; |
|
25
|
|
|
|
|
1157472
|
|
|
25
|
|
|
|
|
205
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# collected S::C (originally distributed in code) |
17
|
|
|
|
|
|
|
use Text::Balanced # Extract delimited text sequences from strings |
18
|
25
|
|
|
25
|
|
1661
|
qw( extract_variable extract_multiple ); |
|
25
|
|
|
|
|
73
|
|
|
25
|
|
|
|
|
2072
|
|
19
|
|
|
|
|
|
|
|
20
|
25
|
|
|
25
|
|
31593
|
use Data::Dumper 'Dumper'; |
|
25
|
|
|
|
|
283862
|
|
|
25
|
|
|
|
|
56013
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# debug only |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
#~ $DB::single=1; #~ |
25
|
|
|
|
|
|
|
#~ use feature 'say'; # disable in production #~ |
26
|
|
|
|
|
|
|
#~ use Smart::Comments '###'; # playing with fire; debug only #~ |
27
|
|
|
|
|
|
|
#~ use Smart::Comments '####'; # playing with fire; debug only #~ |
28
|
|
|
|
|
|
|
#~ use Smart::Comments '#####'; # playing with fire; debug only #~ |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
######## / use ######## |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
#~ say '---| Devel::Comments at line ', __LINE__; #~ |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
######## pseudo-constants section ######## |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
# time and space constants |
37
|
|
|
|
|
|
|
my $maxwidth = 69; # Maximum width of display |
38
|
|
|
|
|
|
|
my $showwidth = 35; # How wide to make the indicator |
39
|
|
|
|
|
|
|
my $showstarttime = 6; # How long before showing time-remaining estimate |
40
|
|
|
|
|
|
|
my $showmaxtime = 10; # Don't start estimate if less than this to go |
41
|
|
|
|
|
|
|
my $whilerate = 30; # Controls the rate at which while indicator grows |
42
|
|
|
|
|
|
|
my $minfillwidth = 5; # Fill area must be at least this wide |
43
|
|
|
|
|
|
|
my $average_over = 5; # Number of time-remaining estimates to average |
44
|
|
|
|
|
|
|
my $minfillreps = 2; # Minimum size of a fill and fill cap indicator |
45
|
|
|
|
|
|
|
my $forupdatequantum = 0.01; # Only update every 1% of elapsed distance |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
# Synonyms for asserts and requirements... |
48
|
|
|
|
|
|
|
my $require = qr/require|ensure|assert|insist/; |
49
|
|
|
|
|
|
|
my $check = qr/check|verify|confirm/; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# Horizontal whitespace... |
52
|
|
|
|
|
|
|
my $hws = qr/[^\S\n]/; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# Optional colon... |
55
|
|
|
|
|
|
|
my $optcolon = qr/$hws*;?/; |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
# Automagic debugging as well... (perl -d debugger) |
58
|
|
|
|
|
|
|
# Someone has to tell me why *two* assignments here (??) |
59
|
|
|
|
|
|
|
my $DBX = '$DB::single = $DB::single = 1;'; |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# Recognize progress bars... |
62
|
|
|
|
|
|
|
my @progress_pats = ( |
63
|
|
|
|
|
|
|
# left extending end marker of bar right |
64
|
|
|
|
|
|
|
# anchor bar ("fill") | gap after bar anchor |
65
|
|
|
|
|
|
|
# ====== ======================= === ================= ==== |
66
|
|
|
|
|
|
|
qr{^(\s*.*?) (\[\]\[\]) () \s* (\S?.*)}x, |
67
|
|
|
|
|
|
|
qr{^(\s*.*?) (\(\)\(\)) () \s* (\S?.*)}x, |
68
|
|
|
|
|
|
|
qr{^(\s*.*?) (\{\}\{\}) () \s* (\S?.*)}x, |
69
|
|
|
|
|
|
|
qr{^(\s*.*?) (\<\>\<\>) () \s* (\S?.*)}x, |
70
|
|
|
|
|
|
|
qr{^(\s*.*?) (?>(\S)\2{$minfillreps,}) (\S+) \s{$minfillreps,} (\S.*)}x, |
71
|
|
|
|
|
|
|
qr{^(\s*.*?) (?>(\S)\2{$minfillreps,}) () \s{$minfillreps,} (\S.*)}x, |
72
|
|
|
|
|
|
|
qr{^(\s*.*?) (?>(\S)\2{$minfillreps,}) (\S*) (?=\s*$)}x, |
73
|
|
|
|
|
|
|
qr{^(\s*.*?) () () () \s*$ }x, |
74
|
|
|
|
|
|
|
); |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# new with DC |
77
|
|
|
|
|
|
|
my $join_up = qq{ }; # used to join replacement code strings |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
######## / pseudo-constants ######## |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
######## pseudo-global variables section ######## |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
## original S::C stuff |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# Unique ID assigned to each loop; incremented when assigned |
86
|
|
|
|
|
|
|
# See: for_progress, while_progress |
87
|
|
|
|
|
|
|
my $ID = 0; |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# See: for_progress |
90
|
|
|
|
|
|
|
my %started ; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# See: _moving_average |
93
|
|
|
|
|
|
|
my %moving ; |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# State information for various progress bars... |
96
|
|
|
|
|
|
|
# See: for_progress, while_progress |
97
|
|
|
|
|
|
|
my (%count, %max, %prev_elapsed, %prev_fraction, %showing); |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# See: while_progress |
100
|
|
|
|
|
|
|
my $prev_length = -1; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
## new with DC |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# Unique ID assigned to each use of DC |
106
|
|
|
|
|
|
|
# (strictly, per-import) |
107
|
|
|
|
|
|
|
# |
108
|
|
|
|
|
|
|
# Note that since source filtering is applied from use line down to EOF |
109
|
|
|
|
|
|
|
# or (perhaps) 'no Devel::Comments;', a given filtering action is neither |
110
|
|
|
|
|
|
|
# strictly per-package nor per-file. |
111
|
|
|
|
|
|
|
# |
112
|
|
|
|
|
|
|
# See _get_new_caller_id() |
113
|
|
|
|
|
|
|
# |
114
|
|
|
|
|
|
|
my $new_caller_id = 1; # Will be assigned to "this" use |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# Store per-use (per-fileish) state info |
117
|
|
|
|
|
|
|
# for access by external routines called by replacement code |
118
|
|
|
|
|
|
|
my %state_of ; |
119
|
|
|
|
|
|
|
# SomeCaller => { # $caller_id is primary key |
120
|
|
|
|
|
|
|
# -outfh # desired output filehandle |
121
|
|
|
|
|
|
|
# -tell => { # stored tell() of... |
122
|
|
|
|
|
|
|
# -outfh # ... $outfh |
123
|
|
|
|
|
|
|
# -stdout # ... *STDOUT |
124
|
|
|
|
|
|
|
# }, |
125
|
|
|
|
|
|
|
# -caller => { # stored caller()... |
126
|
|
|
|
|
|
|
# -name # ...[0] (= 'SomeCaller') |
127
|
|
|
|
|
|
|
# -file # ...[1] |
128
|
|
|
|
|
|
|
# -line # ...[2] |
129
|
|
|
|
|
|
|
# }, |
130
|
|
|
|
|
|
|
# }, |
131
|
|
|
|
|
|
|
# AnotherCaller... |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
######## / pseudo-global variables ######## |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
#----------------------------------------------------------------------------# |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
######## INTERNAL ROUTINE ######## |
139
|
|
|
|
|
|
|
# |
140
|
|
|
|
|
|
|
# my $caller_id = _get_new_caller_id(); # unique per-use |
141
|
|
|
|
|
|
|
# |
142
|
|
|
|
|
|
|
# Purpose : Assign a unique ID to each filtering operation |
143
|
|
|
|
|
|
|
# Parms : none |
144
|
|
|
|
|
|
|
# Reads : $new_caller_id |
145
|
|
|
|
|
|
|
# Returns : $caller_id scalar integer |
146
|
|
|
|
|
|
|
# Writes : $new_caller_id |
147
|
|
|
|
|
|
|
# Throws : never |
148
|
|
|
|
|
|
|
# See also : %state_of |
149
|
|
|
|
|
|
|
# |
150
|
|
|
|
|
|
|
# Called once per use line by _prefilter(). Thereafter, $caller_id is either |
151
|
|
|
|
|
|
|
# passed along or interpolated and inserted into client code. |
152
|
|
|
|
|
|
|
# Strictly, $caller_id is unique neither to calling package nor file; |
153
|
|
|
|
|
|
|
# it is assigned whenever Filter::Simple::FILTER calls _prefilter(), |
154
|
|
|
|
|
|
|
# which should happen once per use. So, its scope within client code is: |
155
|
|
|
|
|
|
|
# from: use Devel::Comments |
156
|
|
|
|
|
|
|
# to: no Devel::Comments |
157
|
|
|
|
|
|
|
# ...possibly crossing package boundaries. |
158
|
|
|
|
|
|
|
# |
159
|
|
|
|
|
|
|
sub _get_new_caller_id { |
160
|
25
|
|
|
25
|
|
95
|
return $new_caller_id++; |
161
|
|
|
|
|
|
|
}; |
162
|
|
|
|
|
|
|
######## /_get_new_caller_id ######## |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
######## INTERNAL ROUTINE ######## |
165
|
|
|
|
|
|
|
# |
166
|
|
|
|
|
|
|
# my $outfh = _get_outfh($caller_id); # retrieve from %state_of |
167
|
|
|
|
|
|
|
# |
168
|
|
|
|
|
|
|
# Purpose : Retrieve output filehandle associated with some caller |
169
|
|
|
|
|
|
|
# Parms : $caller_id |
170
|
|
|
|
|
|
|
# Reads : %state_of |
171
|
|
|
|
|
|
|
# Returns : stored filehandle for all smart output |
172
|
|
|
|
|
|
|
# Writes : none |
173
|
|
|
|
|
|
|
# Throws : dies if no arg passed |
174
|
|
|
|
|
|
|
# See also : _put_outfh(), _get_new_caller_id() |
175
|
|
|
|
|
|
|
# |
176
|
|
|
|
|
|
|
sub _get_outfh { |
177
|
284
|
50
|
|
284
|
|
725
|
my $caller_id = shift |
178
|
|
|
|
|
|
|
or die q{Devel::Comments: } # called with no arg |
179
|
|
|
|
|
|
|
, q{Internal error: } |
180
|
|
|
|
|
|
|
, q{_get_outfh called with no or false arg. } |
181
|
|
|
|
|
|
|
, $! |
182
|
|
|
|
|
|
|
; |
183
|
284
|
50
|
|
|
|
4768
|
defined $state_of{$caller_id} |
184
|
|
|
|
|
|
|
or die q{Devel::Comments: } # called with bad id |
185
|
|
|
|
|
|
|
, q{Internal error: } |
186
|
|
|
|
|
|
|
, qq{$caller_id not defined in } |
187
|
|
|
|
|
|
|
, q{%state_of. } |
188
|
|
|
|
|
|
|
, $! |
189
|
|
|
|
|
|
|
; |
190
|
|
|
|
|
|
|
|
191
|
284
|
50
|
|
|
|
1037
|
defined $state_of{$caller_id}{-outfh} |
192
|
|
|
|
|
|
|
or die q{Devel::Comments: } # no $outfh found |
193
|
|
|
|
|
|
|
, q{Internal error: } |
194
|
|
|
|
|
|
|
, q{No output filehandle found in %state_of } |
195
|
|
|
|
|
|
|
, qq{for $caller_id. } |
196
|
|
|
|
|
|
|
, $! |
197
|
|
|
|
|
|
|
; |
198
|
|
|
|
|
|
|
|
199
|
284
|
|
|
|
|
987
|
return $state_of{$caller_id}{-outfh}; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
}; |
202
|
|
|
|
|
|
|
######## /_do_ ######## |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
######## INTERNAL ROUTINE ######## |
205
|
|
|
|
|
|
|
# |
206
|
|
|
|
|
|
|
# _init_state({ # initialize $state_of this caller |
207
|
|
|
|
|
|
|
# -outfh => $outfh, |
208
|
|
|
|
|
|
|
# -caller_id => $caller_id, |
209
|
|
|
|
|
|
|
# }); |
210
|
|
|
|
|
|
|
# |
211
|
|
|
|
|
|
|
# Purpose : Initialize state; store $outfh and avoid warnings later |
212
|
|
|
|
|
|
|
# Parms : hashref |
213
|
|
|
|
|
|
|
# : -caller_id $caller_id |
214
|
|
|
|
|
|
|
# : -outfh $outfh |
215
|
|
|
|
|
|
|
# Reads : none |
216
|
|
|
|
|
|
|
# Returns : 1 |
217
|
|
|
|
|
|
|
# Writes : %state_of |
218
|
|
|
|
|
|
|
# Throws : never |
219
|
|
|
|
|
|
|
# See also : _prefilter(), _put_state() |
220
|
|
|
|
|
|
|
# |
221
|
|
|
|
|
|
|
# Call once per use from _prefilter() only. |
222
|
|
|
|
|
|
|
# This is important, lest we get confused about which stack frame is wanted. |
223
|
|
|
|
|
|
|
# |
224
|
|
|
|
|
|
|
sub _init_state { |
225
|
25
|
|
|
25
|
|
55
|
my $href = shift; |
226
|
|
|
|
|
|
|
|
227
|
25
|
50
|
|
|
|
141
|
my $caller_id = $href->{-caller_id} |
228
|
|
|
|
|
|
|
or die q{Devel::Comments: } # called with no -caller_id |
229
|
|
|
|
|
|
|
, q{Internal error: } |
230
|
|
|
|
|
|
|
, q{-caller_id not passed in call to _init_state(). } |
231
|
|
|
|
|
|
|
, $! |
232
|
|
|
|
|
|
|
; |
233
|
|
|
|
|
|
|
|
234
|
25
|
50
|
|
|
|
167
|
my $outfh = $href->{-outfh} |
235
|
|
|
|
|
|
|
or die q{Devel::Comments: } # called with no -outfh |
236
|
|
|
|
|
|
|
, q{Internal error: } |
237
|
|
|
|
|
|
|
, q{-outfh not passed in call to _init_state(). } |
238
|
|
|
|
|
|
|
, $! |
239
|
|
|
|
|
|
|
; |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# frame |
242
|
|
|
|
|
|
|
# 0 _prefilter |
243
|
|
|
|
|
|
|
# 1 FILTER |
244
|
|
|
|
|
|
|
# 2 Filter::Simple |
245
|
|
|
|
|
|
|
# 3 actual use-line caller |
246
|
25
|
|
|
|
|
49
|
my $frame = 3; |
247
|
25
|
|
|
|
|
180
|
my @caller = caller($frame); |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# my $caller_name = $caller[0]; |
250
|
25
|
|
|
|
|
72
|
my $caller_file = $caller[1]; |
251
|
25
|
|
|
|
|
46
|
my $caller_line = $caller[2]; |
252
|
25
|
|
|
|
|
52
|
my $caller_sub = $caller[3]; # TODO?: Test if we have the right caller... |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
# Stash $outfh as $caller_id-dependent state info |
255
|
25
|
|
|
|
|
121
|
$state_of{$caller_id}{-outfh} = $outfh; |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# It may not matter *what* you initialize these to... |
258
|
25
|
|
|
|
|
175
|
$state_of{$caller_id}{-tell}{-outfh} = tell $outfh; |
259
|
25
|
|
|
|
|
131
|
$state_of{$caller_id}{-tell}{-stdout} = tell (*STDOUT); |
260
|
25
|
|
|
|
|
210
|
$state_of{$caller_id}{-caller}{-file} = $caller_file; |
261
|
25
|
|
|
|
|
93
|
$state_of{$caller_id}{-caller}{-line} = $caller_line; |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
#~ ### ...Leaving _init_state()... #~ |
264
|
|
|
|
|
|
|
#~ ### %state_of #~ |
265
|
|
|
|
|
|
|
|
266
|
25
|
|
|
|
|
115
|
return 1; |
267
|
|
|
|
|
|
|
}; |
268
|
|
|
|
|
|
|
######## /_init_state ######## |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
######## INTERNAL ROUTINE ######## |
271
|
|
|
|
|
|
|
# |
272
|
|
|
|
|
|
|
# $prefilter = _prefilter(@_); # Handle arguments to FILTER |
273
|
|
|
|
|
|
|
# |
274
|
|
|
|
|
|
|
# Purpose : Handle arguments and do pseudo-global and per-use setup |
275
|
|
|
|
|
|
|
# Parms : @_ |
276
|
|
|
|
|
|
|
# Reads : %ENV |
277
|
|
|
|
|
|
|
# Returns : hashref (or 0 to abort filtering entirely) |
278
|
|
|
|
|
|
|
# : -intro $intro |
279
|
|
|
|
|
|
|
# : -caller_id $caller_id |
280
|
|
|
|
|
|
|
# Writes : %state_of |
281
|
|
|
|
|
|
|
# Throws : carp() if passed a bad arg in @_ |
282
|
|
|
|
|
|
|
# See also : ____ |
283
|
|
|
|
|
|
|
# |
284
|
|
|
|
|
|
|
# Don't want to be fussy about the order of args passed on the use line, |
285
|
|
|
|
|
|
|
# so each bit roots through all of them looking for what it wants. |
286
|
|
|
|
|
|
|
# |
287
|
|
|
|
|
|
|
sub _prefilter { |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
#~ say '---| Devel::Comments at line ', __LINE__; #~ |
290
|
|
|
|
|
|
|
|
291
|
25
|
|
|
25
|
|
56
|
shift; # Don't need our own package name |
292
|
25
|
|
|
|
|
113
|
s/\r\n/\n/g; # Handle win32 line endings |
293
|
|
|
|
|
|
|
|
294
|
25
|
|
|
|
|
107
|
my $caller_id = _get_new_caller_id(); # unique per-use |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# Default introducer pattern... |
297
|
25
|
|
|
|
|
109
|
my $intro = qr/#{3,}/; |
298
|
25
|
|
|
|
|
56
|
my @intros ; |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# Get filehandle |
301
|
|
|
|
|
|
|
|
302
|
25
|
|
|
|
|
54
|
my $fh_seen = 0; # no filehandle seen yet |
303
|
25
|
|
|
|
|
56
|
my $outfh = undef; # don't assign it first; see open() |
304
|
25
|
|
|
|
|
152
|
my $out_filename = "$0.log"; # default |
305
|
25
|
|
|
|
|
48
|
my $arg ; # trial from @_ |
306
|
|
|
|
|
|
|
my %packed_args ; # possible args packed into a hashref |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# Dig through the args to see if one is a hashref |
309
|
|
|
|
|
|
|
GETHREF: |
310
|
25
|
|
|
|
|
134
|
for my $i ( 0..$#_ ) { # will need the index in a bit |
311
|
8
|
|
|
|
|
23
|
$arg = $_[$i]; # look but don't take |
312
|
|
|
|
|
|
|
|
313
|
8
|
100
|
|
|
|
37
|
if ( ref $arg ) { # some kind of reference |
314
|
1
|
|
|
|
|
6
|
my $stringy = sprintf $arg; |
315
|
1
|
50
|
|
|
|
8
|
if ( $stringy =~ /HASH/ ) { # looks like a hash ref |
316
|
1
|
|
|
|
|
5
|
%packed_args = %$arg; |
317
|
1
|
50
|
|
|
|
7
|
if ( defined $packed_args{-file} ) { |
318
|
1
|
|
|
|
|
4
|
$out_filename = $packed_args{-file}; |
319
|
|
|
|
|
|
|
}; # else if undef, use default |
320
|
1
|
|
|
|
|
3
|
splice @_, $i; # remove the parsed arg |
321
|
|
|
|
|
|
|
#~ say '$out_filename: ', $out_filename; ~# |
322
|
1
|
50
|
|
|
|
147
|
open $outfh, '>', $out_filename |
323
|
|
|
|
|
|
|
or die "Devel::Comments: " |
324
|
|
|
|
|
|
|
, "Can't open $out_filename to write." |
325
|
|
|
|
|
|
|
, $! |
326
|
|
|
|
|
|
|
; |
327
|
|
|
|
|
|
|
# Autoflush $outfh |
328
|
1
|
|
|
|
|
6
|
my $prev_fh = select $outfh; |
329
|
1
|
|
|
|
|
6
|
local $| = 1; # autoflush |
330
|
1
|
|
|
|
|
8
|
select $prev_fh; |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
#~ say $outfh '... Just after opening $outfh ...'; #~ |
335
|
|
|
|
|
|
|
#~ say $outfh '$outfh: ', $outfh; #~ |
336
|
|
|
|
|
|
|
}; |
337
|
|
|
|
|
|
|
}; |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
#~ return 0; #~ |
340
|
|
|
|
|
|
|
}; # /GETHREF |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
# Dig through the args to see if one is a filehandle |
343
|
|
|
|
|
|
|
SETFH: |
344
|
25
|
|
|
|
|
85
|
for my $i ( 0..$#_ ) { # will need the index in a bit |
345
|
7
|
|
|
|
|
13
|
$arg = $_[$i]; # look but don't take |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
# Is $arg defined by vanilla Smart::Comments? |
348
|
7
|
50
|
66
|
|
|
46
|
if ( $arg eq '-ENV' || (substr $arg, 0, 1) eq '#' ) { |
349
|
7
|
|
|
|
|
23
|
next SETFH; # no, keep looking |
350
|
|
|
|
|
|
|
}; |
351
|
|
|
|
|
|
|
#~ print 'Mine: >', $arg, "<\n"; #~ |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# Vanilla doesn't want to see it, so remove from @_ |
354
|
0
|
|
|
|
|
0
|
splice @_, $i; |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
# Is it a writable filehandle? |
357
|
0
|
0
|
|
|
|
0
|
if ( not -w $arg ) { |
358
|
0
|
|
|
|
|
0
|
carp q{Not a writable filehandle: } |
359
|
|
|
|
|
|
|
. qq{$arg} |
360
|
|
|
|
|
|
|
. q{ in call to 'use Devel::Comments'.} |
361
|
|
|
|
|
|
|
; |
362
|
|
|
|
|
|
|
} # and keep looking |
363
|
|
|
|
|
|
|
else { |
364
|
0
|
|
|
|
|
0
|
$outfh = $arg; |
365
|
0
|
|
|
|
|
0
|
last SETFH; # found, so we're done looking |
366
|
|
|
|
|
|
|
}; |
367
|
|
|
|
|
|
|
}; # /SETFH |
368
|
|
|
|
|
|
|
|
369
|
25
|
100
|
|
|
|
125
|
if (!$outfh) { |
370
|
24
|
|
|
|
|
101
|
$outfh = *STDERR; # default |
371
|
|
|
|
|
|
|
}; |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
#~ say STDERR '... About to _init_state() ...'; #~ |
374
|
|
|
|
|
|
|
#~ say STDERR '$outfh: ', $outfh; #~ |
375
|
25
|
|
|
|
|
203
|
_init_state({ # initialize $state_of this caller |
376
|
|
|
|
|
|
|
-outfh => $outfh, |
377
|
|
|
|
|
|
|
-caller_id => $caller_id, |
378
|
|
|
|
|
|
|
}); |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
#### ...In prefilter()... |
381
|
|
|
|
|
|
|
#### %state_of |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
## done with the new-for-DC setup |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
# Handle intros and env args... |
387
|
25
|
|
|
|
|
136
|
while (@_) { |
388
|
9
|
|
|
|
|
77
|
my $arg = shift @_; |
389
|
|
|
|
|
|
|
|
390
|
9
|
100
|
|
|
|
31
|
if ($arg eq '-ENV') { |
391
|
4
|
|
|
|
|
12
|
my $env_filters = _handle_env(); |
392
|
4
|
100
|
|
|
|
17
|
return 0 if !$env_filters; # i.e. if no filtering ABORT |
393
|
3
|
|
|
|
|
6
|
unshift @_, @{$env_filters}; |
|
3
|
|
|
|
|
14
|
|
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
else { |
396
|
5
|
|
|
|
|
14
|
push @intros, $arg; |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
24
|
50
|
|
|
|
121
|
if (my @unknowns = grep {!/$intro/} @intros) { |
|
5
|
|
|
|
|
51
|
|
401
|
0
|
|
|
|
|
0
|
croak "Incomprehensible arguments: @unknowns\n", |
402
|
|
|
|
|
|
|
"in call to 'use Devel::Comments'"; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
# Make non-default introducer pattern... |
406
|
24
|
100
|
|
|
|
269
|
if (@intros) { |
407
|
2
|
|
|
|
|
11
|
$intro = '(?-x:'.join('|',@intros).')(?!\#)'; |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
#~ say $outfh '... Leaving _prefilter() ...'; #~ |
411
|
|
|
|
|
|
|
return { |
412
|
24
|
|
|
|
|
159
|
-intro => $intro, |
413
|
|
|
|
|
|
|
-caller_id => $caller_id, |
414
|
|
|
|
|
|
|
}; |
415
|
|
|
|
|
|
|
}; |
416
|
|
|
|
|
|
|
######## /_prefilter ######## |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
######## INTERNAL ROUTINE ######## |
419
|
|
|
|
|
|
|
# _handle_env |
420
|
|
|
|
|
|
|
# |
421
|
|
|
|
|
|
|
# Purpose : Deal with environment variables |
422
|
|
|
|
|
|
|
# Params : *none* |
423
|
|
|
|
|
|
|
# Reads : %ENV |
424
|
|
|
|
|
|
|
# Returns : nothing => no environment variable set |
425
|
|
|
|
|
|
|
# : array ref => a list of things to put onto |
426
|
|
|
|
|
|
|
# the "intros" array. |
427
|
|
|
|
|
|
|
sub _handle_env { |
428
|
|
|
|
|
|
|
# First look to see if the Devel_Comments variable is set, if so |
429
|
|
|
|
|
|
|
# process it and return. |
430
|
4
|
|
|
4
|
|
12
|
my $dc_env = $ENV{Devel_Comments}; |
431
|
4
|
100
|
|
|
|
14
|
if ($dc_env) { |
432
|
1
|
|
|
|
|
3
|
return _handle_dc_env($dc_env); |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
# Now check the multitude of smart comments environment variables. |
435
|
3
|
|
33
|
|
|
28
|
my $sc_env = |
436
|
|
|
|
|
|
|
$ENV{Smart_Comments} |
437
|
|
|
|
|
|
|
|| $ENV{SMART_COMMENTS} |
438
|
|
|
|
|
|
|
|| $ENV{SmartComments} |
439
|
|
|
|
|
|
|
|| $ENV{SMARTCOMMENTS}; |
440
|
3
|
100
|
|
|
|
13
|
if ($sc_env) { |
441
|
2
|
|
|
|
|
9
|
return _handle_sc_env($sc_env); |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
|
444
|
1
|
|
|
|
|
2
|
return; |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
######## /_handle_env ######## |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
######## INTERNAL ROUTINE ######## |
449
|
|
|
|
|
|
|
# _handle_dc_env |
450
|
|
|
|
|
|
|
# |
451
|
|
|
|
|
|
|
# Purpose : To process the devel comments environment variable. |
452
|
|
|
|
|
|
|
# Params : A scalar containing the value of the environment variable |
453
|
|
|
|
|
|
|
# Returns : An array ref containing 0 or more ???s |
454
|
|
|
|
|
|
|
# - if the env var just contains a 1 a ref to an empty |
455
|
|
|
|
|
|
|
# array is returned. |
456
|
|
|
|
|
|
|
# - otherwise the variable is split on space or (space |
457
|
|
|
|
|
|
|
# surrounded) colons. |
458
|
|
|
|
|
|
|
sub _handle_dc_env { |
459
|
1
|
|
|
1
|
|
2
|
my $env = shift; |
460
|
|
|
|
|
|
|
# For now we can just do the same thing as for a smart comments |
461
|
|
|
|
|
|
|
# env variable. In future it would be possible to handle devel |
462
|
|
|
|
|
|
|
# comments environment variables differently. |
463
|
1
|
|
|
|
|
2
|
return _handle_sc_env($env); |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
######## /_handle_dc_env ######## |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
######## INTERNAL ROUTINE ######## |
469
|
|
|
|
|
|
|
# _handle_sc_env |
470
|
|
|
|
|
|
|
# |
471
|
|
|
|
|
|
|
# Purpose : To process the devel comments environment variable. |
472
|
|
|
|
|
|
|
# Params : A scalar containing the value of the environment variable |
473
|
|
|
|
|
|
|
# Returns : An array ref containing 0 or more ???s |
474
|
|
|
|
|
|
|
# - if the env var just contains a 1 a ref to an empty |
475
|
|
|
|
|
|
|
# array is returned. |
476
|
|
|
|
|
|
|
# - otherwise the variable is split on space or (space |
477
|
|
|
|
|
|
|
# surrounded) colons. |
478
|
|
|
|
|
|
|
sub _handle_sc_env { |
479
|
3
|
|
|
3
|
|
5
|
my $env = shift; |
480
|
3
|
100
|
|
|
|
21
|
if ( $env !~ m{\A \s* 1 \s* \Z}xms ) { |
481
|
1
|
|
|
|
|
12
|
return [ split m{\s+|\s*:\s*}xms, $env ]; |
482
|
|
|
|
|
|
|
} |
483
|
2
|
|
|
|
|
9
|
return []; |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
######## /_handle_sc_env ######## |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
sub import; # FORWARD |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
######## EXTERNAL SUB CALL ######## |
491
|
|
|
|
|
|
|
# |
492
|
|
|
|
|
|
|
# Purpose : Rewrite caller's smart comments into code |
493
|
|
|
|
|
|
|
# Parms : @_ : The split use line, with $_[0] being *this* package |
494
|
|
|
|
|
|
|
# : $_ : Caller's entire source code to be filtered |
495
|
|
|
|
|
|
|
# Reads : %ENV, %state_of |
496
|
|
|
|
|
|
|
# Returns : $_ : Filtered code |
497
|
|
|
|
|
|
|
# Writes : %state_of |
498
|
|
|
|
|
|
|
# Throws : never |
499
|
|
|
|
|
|
|
# See also : Filter::Simple, _prefilter() |
500
|
|
|
|
|
|
|
# |
501
|
|
|
|
|
|
|
# Implement comments-to-code source filter. |
502
|
|
|
|
|
|
|
# |
503
|
|
|
|
|
|
|
# This is not a subroutine but a call to Filter::Simple::FILTER |
504
|
|
|
|
|
|
|
# with its single argument being its following block. |
505
|
|
|
|
|
|
|
# |
506
|
|
|
|
|
|
|
# The block may be thought of as an import routine |
507
|
|
|
|
|
|
|
# which is passed @_ and $_ and must return the filtered code in $_ |
508
|
|
|
|
|
|
|
# |
509
|
|
|
|
|
|
|
# Note (if our module is invoked properly via use): |
510
|
|
|
|
|
|
|
# From caller's viewpoint, use operates as a BEGIN block, |
511
|
|
|
|
|
|
|
# including all our-module inline code and this call to FILTER; |
512
|
|
|
|
|
|
|
# while filtered-in calls to our-module subs take place at run time. |
513
|
|
|
|
|
|
|
# From our viewpoint, our inline code, including FILTER, |
514
|
|
|
|
|
|
|
# is run after any BEGIN or use in our module; |
515
|
|
|
|
|
|
|
# and filtered-in subs may be viewed |
516
|
|
|
|
|
|
|
# as if they were externally called subs in a normal module. |
517
|
|
|
|
|
|
|
# Because FILTER is called as part of a constructed import routine, |
518
|
|
|
|
|
|
|
# it executes every time our module is use()-ed, |
519
|
|
|
|
|
|
|
# although other inline code in our module only executes one time only, |
520
|
|
|
|
|
|
|
# when first use()-ed. |
521
|
|
|
|
|
|
|
# |
522
|
|
|
|
|
|
|
# See "How it works" in Filter::Simple's POD. |
523
|
|
|
|
|
|
|
# |
524
|
0
|
|
|
0
|
0
|
0
|
sub FILTERx {}; # dummy sub only to appear in editor's symbol table |
525
|
|
|
|
|
|
|
# |
526
|
|
|
|
|
|
|
FILTER { |
527
|
|
|
|
|
|
|
##### |--- Start of filter ---| |
528
|
|
|
|
|
|
|
##### @_ |
529
|
|
|
|
|
|
|
##### $_ |
530
|
|
|
|
|
|
|
#~ say "---| Source to be filtered:\n", $_, '|--- END SOURCE CODE'; #~ |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
my $prefilter = _prefilter(@_); # Handle arguments to FILTER |
533
|
|
|
|
|
|
|
return 0 if !$prefilter; # i.e. if no filtering ABORT |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
my $intro = $prefilter->{-intro}; # introducer pattern |
536
|
|
|
|
|
|
|
my $caller_id = $prefilter->{-caller_id}; # unique per-use |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
# Preserve DATA handle if any... |
539
|
|
|
|
|
|
|
if (s{ ^ __DATA__ \s* $ (.*) \z }{}xms) { |
540
|
25
|
|
|
25
|
|
667
|
no strict qw< refs >; |
|
25
|
|
|
|
|
51
|
|
|
25
|
|
|
|
|
125620
|
|
541
|
|
|
|
|
|
|
my $DATA = $1; |
542
|
|
|
|
|
|
|
open *{caller(1).'::DATA'}, '<', \$DATA or die "Internal error: DATA. $!"; |
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
#~ say '---| Devel::Comments at line ', __LINE__; #~ |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
# Progress bar on a for loop... |
548
|
|
|
|
|
|
|
# Calls _decode_for() |
549
|
|
|
|
|
|
|
s{ ^ $hws* ( (?: [^\W\d]\w*: \s*)? for(?:each)? \s* (?:my)? \s* (?:\$ [^\W\d]\w*)? \s* ) \( ([^;\n]*?) \) \s* \{ |
550
|
|
|
|
|
|
|
[ \t]* $intro \s (.*) \s* $ |
551
|
|
|
|
|
|
|
} |
552
|
|
|
|
|
|
|
{ _decode_for($caller_id, $1, $2, $3) }egmx; |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
# Progress bar on a while loop... |
555
|
|
|
|
|
|
|
# Calls _decode_while() |
556
|
|
|
|
|
|
|
s{ ^ $hws* ( (?: [^\W\d]\w*: \s*)? (?:while|until) \s* \( .*? \) \s* ) \{ |
557
|
|
|
|
|
|
|
[ \t]* $intro \s (.*) \s* $ |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
{ _decode_while($caller_id, $1, $2) }egmx; |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
# Progress bar on a C-style for loop... |
562
|
|
|
|
|
|
|
# Calls _decode_while() |
563
|
|
|
|
|
|
|
s{ ^ $hws* ( (?: [^\W\d]\w*: \s*)? for \s* \( .*? ; .*? ; .*? \) \s* ) \{ |
564
|
|
|
|
|
|
|
$hws* $intro $hws (.*) $hws* $ |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
{ _decode_while($caller_id, $1, $2) }egmx; |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
# Requirements... |
569
|
|
|
|
|
|
|
# Calls _decode_assert() |
570
|
|
|
|
|
|
|
s{ ^ $hws* $intro [ \t] $require : \s* (.*?) $optcolon $hws* $ } |
571
|
|
|
|
|
|
|
{ _decode_assert($caller_id, $1,"fatal") }egmx; |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
# Assertions... |
574
|
|
|
|
|
|
|
# Calls _decode_assert() |
575
|
|
|
|
|
|
|
s{ ^ $hws* $intro [ \t] $check : \s* (.*?) $optcolon $hws* $ } |
576
|
|
|
|
|
|
|
{ _decode_assert($caller_id, $1) }egmx; |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
# Any other smart comment is a simple dump. |
579
|
|
|
|
|
|
|
# The replacement code in each case consists mainly |
580
|
|
|
|
|
|
|
# of a call to Dump_for(). |
581
|
|
|
|
|
|
|
# But WATCH OUT for subtle differences! |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
# Dump a raw scalar (the varname is used as the label)... |
584
|
|
|
|
|
|
|
s{ ^ $hws* $intro [ \t]+ (\$ [\w:]* \w) $optcolon $hws* $ } |
585
|
|
|
|
|
|
|
{ join $join_up, |
586
|
|
|
|
|
|
|
qq* Devel::Comments::Dump_for( *, |
587
|
|
|
|
|
|
|
qq* -caller_id => $caller_id, *, |
588
|
|
|
|
|
|
|
qq* -prefix => q{$1:}, *, |
589
|
|
|
|
|
|
|
qq* -varref => [$1], *, |
590
|
|
|
|
|
|
|
qq* );$DBX *, |
591
|
|
|
|
|
|
|
}egmx; |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
# Dump a labelled scalar... |
594
|
|
|
|
|
|
|
s{ ^ $hws* $intro [ \t] (.+ :) [ \t]* (\$ [\w:]* \w) $optcolon $hws* $ } |
595
|
|
|
|
|
|
|
{ join $join_up, |
596
|
|
|
|
|
|
|
qq* Devel::Comments::Dump_for( *, |
597
|
|
|
|
|
|
|
qq* -caller_id => $caller_id, *, |
598
|
|
|
|
|
|
|
qq* -prefix => q{$1}, *, |
599
|
|
|
|
|
|
|
qq* -varref => [$2], *, |
600
|
|
|
|
|
|
|
qq* );$DBX *, |
601
|
|
|
|
|
|
|
}egmx; |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
# Dump a raw hash or array (the varname is used as the label)... |
604
|
|
|
|
|
|
|
s{ ^ $hws* $intro [ \t]+ ([\@%] [\w:]* \w) $optcolon $hws* $ } |
605
|
|
|
|
|
|
|
{ join $join_up, |
606
|
|
|
|
|
|
|
qq* Devel::Comments::Dump_for( *, |
607
|
|
|
|
|
|
|
qq* -caller_id => $caller_id, *, |
608
|
|
|
|
|
|
|
qq* -prefix => q{$1:}, *, |
609
|
|
|
|
|
|
|
qq* -varref => [\\$1], *, |
610
|
|
|
|
|
|
|
qq* );$DBX *, |
611
|
|
|
|
|
|
|
}egmx; |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
# Dump a labelled hash or array... |
614
|
|
|
|
|
|
|
s{ ^ $hws* $intro [ \t]+ (.+ :) [ \t]* ([\@%] [\w:]* \w) $optcolon $hws* $ } |
615
|
|
|
|
|
|
|
{ join $join_up, |
616
|
|
|
|
|
|
|
qq* Devel::Comments::Dump_for( *, |
617
|
|
|
|
|
|
|
qq* -caller_id => $caller_id, *, |
618
|
|
|
|
|
|
|
qq* -prefix => q{$1}, *, |
619
|
|
|
|
|
|
|
qq* -varref => [\\$2], *, |
620
|
|
|
|
|
|
|
qq* );$DBX *, |
621
|
|
|
|
|
|
|
}egmx; |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
# Dump a labelled expression... |
624
|
|
|
|
|
|
|
s{ ^ $hws* $intro [ \t]+ (.+ :) (.+) } |
625
|
|
|
|
|
|
|
{ join $join_up, |
626
|
|
|
|
|
|
|
qq* Devel::Comments::Dump_for( *, |
627
|
|
|
|
|
|
|
qq* -caller_id => $caller_id, *, |
628
|
|
|
|
|
|
|
qq* -prefix => q{$1}, *, |
629
|
|
|
|
|
|
|
qq* -varref => [$2], *, |
630
|
|
|
|
|
|
|
qq* );$DBX *, |
631
|
|
|
|
|
|
|
}egmx; |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
# Dump an 'in progress' message |
634
|
|
|
|
|
|
|
s{ ^ $hws* $intro $hws* (.+ [.]{3}) $hws* $ } |
635
|
|
|
|
|
|
|
{ join $join_up, |
636
|
|
|
|
|
|
|
qq* Devel::Comments::Dump_for( *, |
637
|
|
|
|
|
|
|
qq* -caller_id => $caller_id, *, |
638
|
|
|
|
|
|
|
qq* -prefix => qq{$1}, *, |
639
|
|
|
|
|
|
|
qq* );$DBX *, |
640
|
|
|
|
|
|
|
}egmx; |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
# Dump an unlabelled expression (the expression is used as the label)... |
643
|
|
|
|
|
|
|
# Note inserted call to quiet_eval() |
644
|
|
|
|
|
|
|
s{ ^ $hws* $intro $hws* (.*) $optcolon $hws* $ } |
645
|
|
|
|
|
|
|
{ join $join_up, |
646
|
|
|
|
|
|
|
qq* Devel::Comments::Dump_for( *, |
647
|
|
|
|
|
|
|
qq* -caller_id => $caller_id, *, |
648
|
|
|
|
|
|
|
qq* -prefix => q{$1:}, *, |
649
|
|
|
|
|
|
|
qq* -varref => Devel::Comments::quiet_eval( q{[$1]} ), *, |
650
|
|
|
|
|
|
|
qq* );$DBX *, |
651
|
|
|
|
|
|
|
}egmx; |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
# This doesn't work as expected, don't know why |
654
|
|
|
|
|
|
|
# It can't help to warn instead of print |
655
|
|
|
|
|
|
|
# # An empty comment dumps an empty line... |
656
|
|
|
|
|
|
|
# # Inserts call to warn() |
657
|
|
|
|
|
|
|
# s{ ^ $hws* $intro [ \t]+ $ } |
658
|
|
|
|
|
|
|
# {warn qq{\n};}gmx; |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
# This is never needed; for some reason it's caught by "unlabeled expression" |
661
|
|
|
|
|
|
|
# Strictly speaking, it's an undocumented feature |
662
|
|
|
|
|
|
|
# # Anything else is a literal string to be printed... |
663
|
|
|
|
|
|
|
# # Inserts call to Dump_for() |
664
|
|
|
|
|
|
|
# s{ ^ $hws* $intro $hws* (.*) } |
665
|
|
|
|
|
|
|
# {Devel::Comments::Dump_for(-prefix=>q{$1});$DBX}gmx; |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
##### |--- End of filter ---| |
668
|
|
|
|
|
|
|
##### @_ |
669
|
|
|
|
|
|
|
##### $_ |
670
|
|
|
|
|
|
|
#~ say "---| Source after filtering:\n", $_, '|--- END SOURCE CODE'; #~ |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
}; |
673
|
|
|
|
|
|
|
######## /FILTER ######## |
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
######## IMPORT ROUTINE ######## |
676
|
|
|
|
|
|
|
# |
677
|
|
|
|
|
|
|
# Purpose : dummy for now |
678
|
|
|
|
|
|
|
# Parms : ____ |
679
|
|
|
|
|
|
|
# Reads : ____ |
680
|
|
|
|
|
|
|
# Returns : ____ |
681
|
|
|
|
|
|
|
# Writes : ____ |
682
|
|
|
|
|
|
|
# Throws : ____ |
683
|
|
|
|
|
|
|
# See also : ____ |
684
|
|
|
|
|
|
|
# |
685
|
|
|
|
|
|
|
# The "normal" import routine must be declared |
686
|
|
|
|
|
|
|
# *before* the call to FILTER. |
687
|
|
|
|
|
|
|
# However, Filter::Simple will call import() |
688
|
|
|
|
|
|
|
# *after* applying FILTER to caller's source code. |
689
|
|
|
|
|
|
|
# |
690
|
|
|
|
|
|
|
sub import { |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
#~ say '---| Devel::Comments at line ', __LINE__; #~ |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
}; |
695
|
|
|
|
|
|
|
######## /import ######## |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
#============================================================================# |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
######## EXTERNAL ROUTINE ######## |
700
|
|
|
|
|
|
|
# |
701
|
|
|
|
|
|
|
# $return = quiet_eval($codestring); # string eval, no errors |
702
|
|
|
|
|
|
|
# |
703
|
|
|
|
|
|
|
# Purpose : String eval some code and suppress any errors |
704
|
|
|
|
|
|
|
# Parms : $codestring : Arbitrary client code |
705
|
|
|
|
|
|
|
# Reads, Returns, Writes : Whatever client code does |
706
|
|
|
|
|
|
|
# Throws : never, ever |
707
|
|
|
|
|
|
|
# See also : FILTER # Dump an unlabelled expression |
708
|
|
|
|
|
|
|
# |
709
|
|
|
|
|
|
|
sub quiet_eval { |
710
|
0
|
|
|
0
|
0
|
0
|
local $SIG{__WARN__} = sub{}; |
|
0
|
|
|
0
|
|
0
|
|
711
|
0
|
|
|
|
|
0
|
return scalar eval shift; |
712
|
|
|
|
|
|
|
}; |
713
|
|
|
|
|
|
|
######## /quiet_eval ######## |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
######## INTERNAL ROUTINE ######## |
716
|
|
|
|
|
|
|
# |
717
|
|
|
|
|
|
|
# $quantity = _uniq(@list); # short |
718
|
|
|
|
|
|
|
# |
719
|
|
|
|
|
|
|
# Purpose : ____ |
720
|
|
|
|
|
|
|
# Parms : any @list |
721
|
|
|
|
|
|
|
# Reads : none |
722
|
|
|
|
|
|
|
# Returns : scalar quantity of unique elements |
723
|
|
|
|
|
|
|
# Writes : none |
724
|
|
|
|
|
|
|
# Throws : never |
725
|
|
|
|
|
|
|
# See also : _decode_assert() |
726
|
|
|
|
|
|
|
# |
727
|
|
|
|
|
|
|
# |
728
|
|
|
|
|
|
|
sub _uniq { |
729
|
21
|
|
|
21
|
|
11885
|
my %seen; |
730
|
21
|
|
|
|
|
45
|
grep { !$seen{$_}++ } @_ |
|
28
|
|
|
|
|
148
|
|
731
|
|
|
|
|
|
|
}; |
732
|
|
|
|
|
|
|
######## /_uniq ######## |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
######## REPLACEMENT CODE GENERATOR ######## |
735
|
|
|
|
|
|
|
# |
736
|
|
|
|
|
|
|
# $codestring = _decode_assert( $caller_id, $assertion, $signal_flag); |
737
|
|
|
|
|
|
|
# |
738
|
|
|
|
|
|
|
# Purpose : Converts an assertion to the equivalent Perl code. |
739
|
|
|
|
|
|
|
# Parms : $caller_id |
740
|
|
|
|
|
|
|
# : $assertion : text of assertion |
741
|
|
|
|
|
|
|
# : $signal_flag : TRUE to die |
742
|
|
|
|
|
|
|
# Reads : %state_of |
743
|
|
|
|
|
|
|
# Returns : Replacement code string |
744
|
|
|
|
|
|
|
# Writes : none |
745
|
|
|
|
|
|
|
# Throws : never itself but generated code may die |
746
|
|
|
|
|
|
|
# See also : FILTER # Requirements, # Assertions |
747
|
|
|
|
|
|
|
# |
748
|
|
|
|
|
|
|
# Generates three snippets of code (in reverse order): |
749
|
|
|
|
|
|
|
# $signal_code # real die or sim warn |
750
|
|
|
|
|
|
|
# @vardump_code_lines # Dumped variable(s) |
751
|
|
|
|
|
|
|
# $report_code # entire replacement codestring, |
752
|
|
|
|
|
|
|
# including previous two and $assertion |
753
|
|
|
|
|
|
|
# |
754
|
|
|
|
|
|
|
sub _decode_assert { |
755
|
21
|
|
|
21
|
|
40
|
my $caller_id = shift; |
756
|
21
|
|
|
|
|
69
|
my $assertion = shift; |
757
|
21
|
|
|
|
|
32
|
my $signal_flag = shift; |
758
|
|
|
|
|
|
|
|
759
|
21
|
|
|
|
|
43
|
my $frame = 0; # replacement code calls Warn_for() directly |
760
|
|
|
|
|
|
|
|
761
|
21
|
|
|
|
|
34
|
my $Dump_for = 'Devel::Comments::Dump_for'; |
762
|
21
|
|
|
|
|
32
|
my $Print_for = 'Devel::Comments::Print_for'; |
763
|
21
|
|
|
|
|
29
|
my $Warn_for = 'Devel::Comments::Warn_for'; |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
# Choose the right signalling mechanism |
766
|
|
|
|
|
|
|
# after Warn_for()... |
767
|
21
|
100
|
|
|
|
73
|
my $signal_code |
768
|
|
|
|
|
|
|
= $signal_flag |
769
|
|
|
|
|
|
|
? q* die "\n" * # ...then real die |
770
|
|
|
|
|
|
|
: qq* $Print_for( $caller_id, "\n" ) * # ...then newline |
771
|
|
|
|
|
|
|
; |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
# Extract variables from assertion and enreference any arrays or hashes... |
774
|
|
|
|
|
|
|
my @vardump_code_lines |
775
|
28
|
50
|
|
|
|
1603
|
= map { |
776
|
21
|
|
|
|
|
137
|
/^$hws*[%\@]/ # sigil found |
777
|
|
|
|
|
|
|
? join $join_up, |
778
|
|
|
|
|
|
|
qq* $Dump_for( *, |
779
|
|
|
|
|
|
|
qq* -caller_id => $caller_id, *, |
780
|
|
|
|
|
|
|
qq* -prefix => q{ $_ was:}, *, |
781
|
|
|
|
|
|
|
qq* -varref => [\\$_], *, # enreference |
782
|
|
|
|
|
|
|
qq* -no_newline => 1 *, |
783
|
|
|
|
|
|
|
qq* ); *, |
784
|
|
|
|
|
|
|
: join $join_up, |
785
|
|
|
|
|
|
|
qq* $Dump_for( *, |
786
|
|
|
|
|
|
|
qq* -caller_id => $caller_id, *, |
787
|
|
|
|
|
|
|
qq* -prefix => q{ $_ was:}, *, |
788
|
|
|
|
|
|
|
qq* -varref => [$_], *, # don't enref |
789
|
|
|
|
|
|
|
qq* -no_newline => 1 *, |
790
|
|
|
|
|
|
|
qq* ); *, |
791
|
|
|
|
|
|
|
; |
792
|
|
|
|
|
|
|
} |
793
|
|
|
|
|
|
|
_uniq extract_multiple($assertion, [\&extract_variable], undef, 1) |
794
|
|
|
|
|
|
|
## end of map expression |
795
|
|
|
|
|
|
|
; |
796
|
|
|
|
|
|
|
## end of assignment |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
# Generate the test-and-report code... |
799
|
21
|
|
|
|
|
237
|
my $report_code = join $join_up, |
800
|
|
|
|
|
|
|
qq* unless($assertion) { *, |
801
|
|
|
|
|
|
|
qq* $Warn_for( *, |
802
|
|
|
|
|
|
|
qq* $caller_id, *, # $caller_id |
803
|
|
|
|
|
|
|
qq* $frame, *, # $frame |
804
|
|
|
|
|
|
|
qq* "\\n", *, # @text to print |
805
|
|
|
|
|
|
|
qq* q{### $assertion was not true} *, # more @text |
806
|
|
|
|
|
|
|
qq* ); *, |
807
|
|
|
|
|
|
|
qq* @vardump_code_lines; *, # call Dump_for |
808
|
|
|
|
|
|
|
qq* $signal_code *, # maybe die |
809
|
|
|
|
|
|
|
qq* } *, |
810
|
|
|
|
|
|
|
; |
811
|
|
|
|
|
|
|
## end of assignment |
812
|
|
|
|
|
|
|
#~ $DB::single=1; #~ |
813
|
21
|
|
|
|
|
498
|
return $report_code; |
814
|
|
|
|
|
|
|
}; |
815
|
|
|
|
|
|
|
######## /_decode_assert ######## |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
######## REPLACEMENT CODE GENERATOR ######## |
818
|
|
|
|
|
|
|
# |
819
|
|
|
|
|
|
|
# $codestring = _decode_for($for, $range, $mesg); |
820
|
|
|
|
|
|
|
# |
821
|
|
|
|
|
|
|
# Purpose : Generate progress-bar code for a Perlish for loop. |
822
|
|
|
|
|
|
|
# Parms : $for : |
823
|
|
|
|
|
|
|
# : $range : |
824
|
|
|
|
|
|
|
# : $mesg : |
825
|
|
|
|
|
|
|
# Reads : ____ |
826
|
|
|
|
|
|
|
# Returns : Replacement code string |
827
|
|
|
|
|
|
|
# Writes : $ID |
828
|
|
|
|
|
|
|
# Throws : never |
829
|
|
|
|
|
|
|
# See also : for_progress() |
830
|
|
|
|
|
|
|
# |
831
|
|
|
|
|
|
|
sub _decode_for { |
832
|
5
|
|
|
5
|
|
15
|
my $caller_id = shift; |
833
|
5
|
|
|
|
|
20
|
my $for = shift; |
834
|
5
|
|
|
|
|
16
|
my $range = shift; |
835
|
5
|
|
|
|
|
17
|
my $mesg = shift; |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
# Give the loop a unique ID... |
838
|
5
|
|
|
|
|
10
|
$ID++; |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
# Rewrite the loop with a progress bar as its first statement... |
841
|
5
|
|
|
|
|
67
|
my $report_code = join qq{\n}, |
842
|
|
|
|
|
|
|
qq* my \$not_first__$ID; *, |
843
|
|
|
|
|
|
|
qq* $for (my \@SmartComments__range__$ID = $range) { *, |
844
|
|
|
|
|
|
|
qq* Devel::Comments::for_progress( $caller_id, *, |
845
|
|
|
|
|
|
|
qq* qq{$mesg}, *, |
846
|
|
|
|
|
|
|
qq* \$not_first__$ID, *, |
847
|
|
|
|
|
|
|
qq* \\\@SmartComments__range__$ID *, |
848
|
|
|
|
|
|
|
qq* ); *, |
849
|
|
|
|
|
|
|
# closing brace found somewhere in client code |
850
|
|
|
|
|
|
|
; |
851
|
|
|
|
|
|
|
## end of assignment |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
### _decode_for code : $report_code |
854
|
5
|
|
|
|
|
155
|
return $report_code; |
855
|
|
|
|
|
|
|
}; |
856
|
|
|
|
|
|
|
######## /_decode_for ######## |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
######## REPLACEMENT CODE GENERATOR ######## |
859
|
|
|
|
|
|
|
# |
860
|
|
|
|
|
|
|
# _decode_while($while, $mesg); # short |
861
|
|
|
|
|
|
|
# |
862
|
|
|
|
|
|
|
# Purpose : Generate progress-bar code for a Perlish while loop. |
863
|
|
|
|
|
|
|
# Parms : $while : |
864
|
|
|
|
|
|
|
# : $mesg : |
865
|
|
|
|
|
|
|
# Reads : ____ |
866
|
|
|
|
|
|
|
# Returns : Replacement code string |
867
|
|
|
|
|
|
|
# Writes : $ID |
868
|
|
|
|
|
|
|
# Throws : ____ |
869
|
|
|
|
|
|
|
# See also : while_progress() |
870
|
|
|
|
|
|
|
# |
871
|
|
|
|
|
|
|
sub _decode_while { |
872
|
3
|
|
|
3
|
|
7
|
my $caller_id = shift; |
873
|
3
|
|
|
|
|
14
|
my $while = shift; |
874
|
3
|
|
|
|
|
10
|
my $mesg = shift; |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
# Give the loop a unique ID... |
877
|
3
|
|
|
|
|
7
|
$ID++; |
878
|
|
|
|
|
|
|
|
879
|
|
|
|
|
|
|
# Rewrite the loop with a progress bar as its first statement... |
880
|
3
|
|
|
|
|
37
|
my $report_code = join qq{\n}, |
881
|
|
|
|
|
|
|
qq* my \$not_first__$ID; *, |
882
|
|
|
|
|
|
|
qq* $while { *, |
883
|
|
|
|
|
|
|
qq* Devel::Comments::while_progress( $caller_id, *, |
884
|
|
|
|
|
|
|
qq* qq{$mesg}, *, |
885
|
|
|
|
|
|
|
qq* \\\$not_first__$ID *, |
886
|
|
|
|
|
|
|
qq* ); *, |
887
|
|
|
|
|
|
|
# closing brace found somewhere in client code |
888
|
|
|
|
|
|
|
; |
889
|
|
|
|
|
|
|
## end of assignment |
890
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
### _decode_while code : $report_code |
892
|
3
|
|
|
|
|
33
|
return $report_code; |
893
|
|
|
|
|
|
|
}; |
894
|
|
|
|
|
|
|
######## /_decode_while ######## |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
######## INTERNAL ROUTINE ######## |
897
|
|
|
|
|
|
|
# |
898
|
|
|
|
|
|
|
# _desc_time(); # short |
899
|
|
|
|
|
|
|
# |
900
|
|
|
|
|
|
|
# Purpose : ____ |
901
|
|
|
|
|
|
|
# Parms : ____ |
902
|
|
|
|
|
|
|
# Reads : ____ |
903
|
|
|
|
|
|
|
# Returns : ____ |
904
|
|
|
|
|
|
|
# Writes : ____ |
905
|
|
|
|
|
|
|
# Throws : ____ |
906
|
|
|
|
|
|
|
# See also : ____ |
907
|
|
|
|
|
|
|
# |
908
|
|
|
|
|
|
|
# Generate approximate time descriptions... |
909
|
|
|
|
|
|
|
# |
910
|
|
|
|
|
|
|
sub _desc_time { |
911
|
0
|
|
|
0
|
|
0
|
my ($seconds) = @_; |
912
|
0
|
|
|
|
|
0
|
my $hours = int($seconds/3600); $seconds -= 3600*$hours; |
|
0
|
|
|
|
|
0
|
|
913
|
0
|
|
|
|
|
0
|
my $minutes = int($seconds/60); $seconds -= 60*$minutes; |
|
0
|
|
|
|
|
0
|
|
914
|
0
|
|
|
|
|
0
|
my $remaining; |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
# Describe hours to the nearest half-hour (and say how close to it)... |
917
|
0
|
0
|
|
|
|
0
|
if ($hours) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
918
|
0
|
0
|
|
|
|
0
|
$remaining = |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
919
|
|
|
|
|
|
|
$minutes < 5 ? "about $hours hour".($hours==1?"":"s") |
920
|
|
|
|
|
|
|
: $minutes < 25 ? "less than $hours.5 hours" |
921
|
|
|
|
|
|
|
: $minutes < 35 ? "about $hours.5 hours" |
922
|
|
|
|
|
|
|
: $minutes < 55 ? "less than ".($hours+1)." hours" |
923
|
|
|
|
|
|
|
: "about ".($hours+1)." hours"; |
924
|
|
|
|
|
|
|
} |
925
|
|
|
|
|
|
|
# Describe minutes to the nearest minute |
926
|
|
|
|
|
|
|
elsif ($minutes) { |
927
|
0
|
|
|
|
|
0
|
$remaining = "about $minutes minutes"; |
928
|
0
|
0
|
|
|
|
0
|
chop $remaining if $minutes == 1; |
929
|
|
|
|
|
|
|
} |
930
|
|
|
|
|
|
|
# Describe tens of seconds to the nearest ten seconds... |
931
|
|
|
|
|
|
|
elsif ($seconds > 10) { |
932
|
0
|
|
|
|
|
0
|
$seconds = int(($seconds+5)/10); |
933
|
0
|
|
|
|
|
0
|
$remaining = "about ${seconds}0 seconds"; |
934
|
|
|
|
|
|
|
} |
935
|
|
|
|
|
|
|
# Never be more accurate than ten seconds... |
936
|
|
|
|
|
|
|
else { |
937
|
0
|
|
|
|
|
0
|
$remaining = "less than 10 seconds"; |
938
|
|
|
|
|
|
|
} |
939
|
0
|
|
|
|
|
0
|
return $remaining; |
940
|
|
|
|
|
|
|
}; |
941
|
|
|
|
|
|
|
######## /_desc_time ######## |
942
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
######## INTERNAL ROUTINE ######## |
944
|
|
|
|
|
|
|
# |
945
|
|
|
|
|
|
|
# _moving_average(); # short |
946
|
|
|
|
|
|
|
# |
947
|
|
|
|
|
|
|
# Purpose : ____ |
948
|
|
|
|
|
|
|
# Parms : ____ |
949
|
|
|
|
|
|
|
# Reads : ____ |
950
|
|
|
|
|
|
|
# Returns : ____ |
951
|
|
|
|
|
|
|
# Writes : ____ |
952
|
|
|
|
|
|
|
# Throws : ____ |
953
|
|
|
|
|
|
|
# See also : ____ |
954
|
|
|
|
|
|
|
# |
955
|
|
|
|
|
|
|
# Update the moving average of a series given the newest measurement... |
956
|
|
|
|
|
|
|
# |
957
|
|
|
|
|
|
|
sub _moving_average { |
958
|
29
|
|
|
29
|
|
40
|
my ($context, $next) = @_; |
959
|
29
|
|
100
|
|
|
98
|
my $moving = $moving{$context} ||= []; |
960
|
29
|
|
|
|
|
41
|
push @$moving, $next; |
961
|
29
|
100
|
|
|
|
76
|
if (@$moving >= $average_over) { |
962
|
4
|
|
|
|
|
9
|
splice @$moving, 0, $#$moving-$average_over; |
963
|
|
|
|
|
|
|
} |
964
|
29
|
|
|
|
|
179
|
return sum(@$moving)/@$moving; |
965
|
|
|
|
|
|
|
}; |
966
|
|
|
|
|
|
|
######## /_moving_average ######## |
967
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
######## INTERNAL ROUTINE ######## |
969
|
|
|
|
|
|
|
# |
970
|
|
|
|
|
|
|
# _prog_pat(); # short |
971
|
|
|
|
|
|
|
# |
972
|
|
|
|
|
|
|
# Purpose : ____ |
973
|
|
|
|
|
|
|
# Parms : ____ |
974
|
|
|
|
|
|
|
# Reads : ____ |
975
|
|
|
|
|
|
|
# Returns : ____ |
976
|
|
|
|
|
|
|
# Writes : ____ |
977
|
|
|
|
|
|
|
# Throws : ____ |
978
|
|
|
|
|
|
|
# See also : ____ |
979
|
|
|
|
|
|
|
# |
980
|
|
|
|
|
|
|
# Clean up components of progress bar (inserting defaults)... |
981
|
|
|
|
|
|
|
# |
982
|
|
|
|
|
|
|
sub _prog_pat { |
983
|
334
|
|
|
334
|
|
484
|
for my $pat (@progress_pats) { |
984
|
1590
|
100
|
|
|
|
13568
|
$_[0] =~ $pat or next; |
985
|
334
|
|
50
|
|
|
3195
|
return ($1, $2||"", $3||"", $4||""); |
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
986
|
|
|
|
|
|
|
} |
987
|
0
|
|
|
|
|
0
|
return; |
988
|
|
|
|
|
|
|
}; |
989
|
|
|
|
|
|
|
######## /_prog_pat ######## |
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
######## EXTERNAL ROUTINE ######## |
992
|
|
|
|
|
|
|
# |
993
|
|
|
|
|
|
|
# for_progress(); # short |
994
|
|
|
|
|
|
|
# |
995
|
|
|
|
|
|
|
# Purpose : ____ |
996
|
|
|
|
|
|
|
# Parms : ____ |
997
|
|
|
|
|
|
|
# Reads : ____ |
998
|
|
|
|
|
|
|
# Returns : ____ |
999
|
|
|
|
|
|
|
# Writes : $_[2] ($not_first__$ID in caller's code |
1000
|
|
|
|
|
|
|
# Throws : ____ |
1001
|
|
|
|
|
|
|
# See also : _decode_for |
1002
|
|
|
|
|
|
|
# |
1003
|
|
|
|
|
|
|
# Animate the progress bar of a for loop... |
1004
|
|
|
|
|
|
|
# |
1005
|
|
|
|
|
|
|
sub for_progress { |
1006
|
|
|
|
|
|
|
### ...In for_progress... |
1007
|
|
|
|
|
|
|
|
1008
|
34
|
|
|
34
|
0
|
23671
|
my $caller_id = $_[0]; # per-use id of this caller |
1009
|
34
|
|
|
|
|
56
|
my $mesg = $_[1]; # |
1010
|
34
|
|
|
|
|
66
|
my $not_first = $_[2]; # will be altered so don't shift it off |
1011
|
34
|
|
|
|
|
41
|
my $data = $_[3]; # |
1012
|
|
|
|
|
|
|
|
1013
|
34
|
|
|
|
|
40
|
my $at ; # |
1014
|
|
|
|
|
|
|
my $max ; # |
1015
|
0
|
|
|
|
|
0
|
my $elapsed ; # |
1016
|
0
|
|
|
|
|
0
|
my $remaining ; # |
1017
|
0
|
|
|
|
|
0
|
my $fraction ; # |
1018
|
|
|
|
|
|
|
|
1019
|
|
|
|
|
|
|
# Update progress bar... |
1020
|
34
|
100
|
|
|
|
71
|
if ($not_first) { |
1021
|
|
|
|
|
|
|
### for_progress- if not first |
1022
|
|
|
|
|
|
|
# One more iteration towards the maximum... |
1023
|
29
|
|
|
|
|
64
|
$at = ++$count{$data}; |
1024
|
29
|
|
|
|
|
56
|
$max = $max{$data}; |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
# How long now (both absolute and relative)... |
1027
|
29
|
|
|
|
|
56
|
$elapsed = time - $started{$data}; |
1028
|
29
|
50
|
|
|
|
75
|
$fraction = $max>0 ? $at/$max : 1; |
1029
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
# How much change occurred... |
1031
|
29
|
|
|
|
|
49
|
my $motion = $fraction - $prev_fraction{$data}; |
1032
|
|
|
|
|
|
|
|
1033
|
|
|
|
|
|
|
# Don't update if count wrapped (unlikely) or if finished |
1034
|
|
|
|
|
|
|
# or if no visible change... |
1035
|
29
|
50
|
66
|
|
|
209
|
return unless $not_first < 0 |
|
|
|
66
|
|
|
|
|
1036
|
|
|
|
|
|
|
|| $at == $max |
1037
|
|
|
|
|
|
|
|| $motion > $forupdatequantum; |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
# Guestimate how long still to go... |
1040
|
29
|
50
|
|
|
|
104
|
$remaining = _moving_average $data, |
1041
|
|
|
|
|
|
|
$fraction ? $elapsed/$fraction-$elapsed |
1042
|
|
|
|
|
|
|
: 0; |
1043
|
|
|
|
|
|
|
} |
1044
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
# If first iteration... |
1046
|
|
|
|
|
|
|
else { |
1047
|
|
|
|
|
|
|
### for_progress- else first |
1048
|
|
|
|
|
|
|
# Start at the beginning... |
1049
|
5
|
|
|
|
|
28
|
$at = $count{$data} = 0; |
1050
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
# Work out where the end will be... |
1052
|
5
|
|
|
|
|
19
|
$max = $max{$data} = $#$data; |
1053
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
# Start the clock... |
1055
|
5
|
|
|
|
|
48
|
$started{$data} = time; |
1056
|
5
|
|
|
|
|
11
|
$elapsed = 0; |
1057
|
5
|
|
|
|
|
5
|
$fraction = 0; |
1058
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
# After which, it will no longer be the first iteration. |
1060
|
5
|
|
|
|
|
13
|
$_[2] = 1; # $not_first |
1061
|
|
|
|
|
|
|
} |
1062
|
|
|
|
|
|
|
|
1063
|
|
|
|
|
|
|
# Remember the previous increment fraction... |
1064
|
34
|
|
|
|
|
72
|
$prev_fraction{$data} = $fraction; |
1065
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
# Now draw the progress bar (if it's a valid one)... |
1067
|
34
|
50
|
|
|
|
72
|
if (my ($left, $fill, $leader, $right) = _prog_pat($mesg)) { |
1068
|
|
|
|
|
|
|
# Insert the percentage progress in place of a '%'... |
1069
|
34
|
|
|
|
|
132
|
s/%/int(100*$fraction).'%'/ge for ($left, $leader, $right); |
|
10
|
|
|
|
|
39
|
|
1070
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
# Work out how much space is available for the bar itself... |
1072
|
34
|
|
|
|
|
74
|
my $fillwidth = $showwidth - length($left) - length($right); |
1073
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
# But no less than the prespecified minimum please... |
1075
|
34
|
50
|
|
|
|
74
|
$fillwidth = $minfillwidth if $fillwidth < $minfillwidth; |
1076
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
# Make enough filler... |
1078
|
34
|
|
|
|
|
123
|
my $totalfill = $fill x $fillwidth; |
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
# How big is the end of the bar... |
1081
|
34
|
|
|
|
|
42
|
my $leaderwidth = length($leader); |
1082
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
# Truncate where? |
1084
|
34
|
100
|
|
|
|
87
|
my $fillend = $at==$max ? $fillwidth |
1085
|
|
|
|
|
|
|
: $fillwidth*$fraction-$leaderwidth; |
1086
|
34
|
100
|
|
|
|
73
|
$fillend = 0 if $fillend < 0; |
1087
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
# Now draw the bar, using carriage returns to overwrite it... |
1089
|
34
|
|
|
|
|
210
|
Print_for( $caller_id, |
1090
|
|
|
|
|
|
|
qq{\r}, |
1091
|
|
|
|
|
|
|
q{ } x $maxwidth, |
1092
|
|
|
|
|
|
|
qq{\r}, |
1093
|
|
|
|
|
|
|
$left, |
1094
|
|
|
|
|
|
|
sprintf("%-${fillwidth}s", |
1095
|
|
|
|
|
|
|
substr($totalfill, 0, $fillend) |
1096
|
|
|
|
|
|
|
. $leader), |
1097
|
|
|
|
|
|
|
$right, |
1098
|
|
|
|
|
|
|
); |
1099
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
# Work out whether to show an ETA estimate... |
1101
|
34
|
0
|
33
|
|
|
131
|
if ( |
|
|
|
0
|
|
|
|
|
|
|
|
33
|
|
|
|
|
1102
|
|
|
|
|
|
|
$elapsed >= $showstarttime |
1103
|
|
|
|
|
|
|
&& $at < $max |
1104
|
|
|
|
|
|
|
&& ($showing{$data} || $remaining && $remaining >= $showmaxtime) |
1105
|
|
|
|
|
|
|
) { |
1106
|
0
|
|
|
|
|
0
|
Print_for( $caller_id, |
1107
|
|
|
|
|
|
|
q{ (}, |
1108
|
|
|
|
|
|
|
_desc_time($remaining), |
1109
|
|
|
|
|
|
|
q{ remaining)}, |
1110
|
|
|
|
|
|
|
); |
1111
|
0
|
|
|
|
|
0
|
$showing{$data} = 1; |
1112
|
|
|
|
|
|
|
} |
1113
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
# Close off the line, if we're finished... |
1115
|
34
|
100
|
|
|
|
140
|
Print_for( $caller_id, |
1116
|
|
|
|
|
|
|
qq{\r}, |
1117
|
|
|
|
|
|
|
q{ } x $maxwidth, |
1118
|
|
|
|
|
|
|
qq{\n}, |
1119
|
|
|
|
|
|
|
) if $at >= $max; |
1120
|
|
|
|
|
|
|
} |
1121
|
|
|
|
|
|
|
}; |
1122
|
|
|
|
|
|
|
######## /for_progress ######## |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
######## EXTERNAL ROUTINE ######## |
1125
|
|
|
|
|
|
|
# |
1126
|
|
|
|
|
|
|
# while_progress(); # short |
1127
|
|
|
|
|
|
|
# |
1128
|
|
|
|
|
|
|
# Purpose : ____ |
1129
|
|
|
|
|
|
|
# Parms : ____ |
1130
|
|
|
|
|
|
|
# Reads : ____ |
1131
|
|
|
|
|
|
|
# Returns : ____ |
1132
|
|
|
|
|
|
|
# Writes : ____ |
1133
|
|
|
|
|
|
|
# Throws : ____ |
1134
|
|
|
|
|
|
|
# See also : ____ |
1135
|
|
|
|
|
|
|
# |
1136
|
|
|
|
|
|
|
# Animate the progress bar of a while loop... |
1137
|
|
|
|
|
|
|
# |
1138
|
|
|
|
|
|
|
sub while_progress { |
1139
|
300
|
|
|
300
|
0
|
5832
|
my $caller_id = shift; # per-use id of this caller |
1140
|
300
|
|
|
|
|
362
|
my $mesg = shift; # |
1141
|
300
|
|
|
|
|
334
|
my $not_first_ref = shift; # |
1142
|
|
|
|
|
|
|
|
1143
|
300
|
|
|
|
|
284
|
my $at ; # |
1144
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
# If we've looped this one before, recover the current iteration count... |
1146
|
300
|
100
|
|
|
|
488
|
if ($$not_first_ref) { |
1147
|
297
|
|
|
|
|
627
|
$at = ++$count{$not_first_ref}; |
1148
|
|
|
|
|
|
|
} |
1149
|
|
|
|
|
|
|
# Otherwise set the iteration count to zero... |
1150
|
|
|
|
|
|
|
else { |
1151
|
3
|
|
|
|
|
10
|
$at = $count{$not_first_ref} = 0; |
1152
|
3
|
|
|
|
|
8
|
$$not_first_ref = 1; |
1153
|
|
|
|
|
|
|
} |
1154
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
# Extract the components of the progress bar... |
1156
|
300
|
50
|
|
|
|
556
|
if (my ($left, $fill, $leader, $right) = _prog_pat($mesg)) { |
1157
|
|
|
|
|
|
|
# Replace any '%' with the current iteration count... |
1158
|
300
|
|
|
|
|
1044
|
s/%/$at/ge for ($left, $leader, $right); |
|
200
|
|
|
|
|
673
|
|
1159
|
|
|
|
|
|
|
|
1160
|
|
|
|
|
|
|
# How much space is there for the progress bar? |
1161
|
300
|
|
|
|
|
508
|
my $fillwidth = $showwidth - length($left) - length($right); |
1162
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
# Make it at least the prespecified minimum amount... |
1164
|
300
|
50
|
|
|
|
686
|
$fillwidth = $minfillwidth if $fillwidth < $minfillwidth; |
1165
|
|
|
|
|
|
|
|
1166
|
|
|
|
|
|
|
# How big is the end of the bar? |
1167
|
300
|
|
|
|
|
321
|
my $leaderwidth = length($leader); |
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
# How big does that make the bar itself (use reciprocal growth)... |
1170
|
300
|
|
|
|
|
624
|
my $length = int(($fillwidth-$leaderwidth) |
1171
|
|
|
|
|
|
|
*(1-$whilerate/($whilerate+$at))+0.000000000001); |
1172
|
|
|
|
|
|
|
|
1173
|
|
|
|
|
|
|
# Don't update if the picture would look the same... |
1174
|
|
|
|
|
|
|
return |
1175
|
300
|
100
|
66
|
|
|
1652
|
if length $fill && $prev_length == $length; |
1176
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
# Otherwise, remember where we got to... |
1178
|
34
|
|
|
|
|
39
|
$prev_length = $length; |
1179
|
|
|
|
|
|
|
|
1180
|
|
|
|
|
|
|
# And print the bar... |
1181
|
34
|
|
|
|
|
221
|
Print_for( $caller_id, |
1182
|
|
|
|
|
|
|
qq{\r}, |
1183
|
|
|
|
|
|
|
q{ } x $maxwidth, |
1184
|
|
|
|
|
|
|
qq{\r}, |
1185
|
|
|
|
|
|
|
$left, |
1186
|
|
|
|
|
|
|
sprintf("%-${fillwidth}s", |
1187
|
|
|
|
|
|
|
substr($fill x $fillwidth, 0, $length) |
1188
|
|
|
|
|
|
|
. $leader), |
1189
|
|
|
|
|
|
|
$right, |
1190
|
|
|
|
|
|
|
); |
1191
|
|
|
|
|
|
|
} |
1192
|
|
|
|
|
|
|
}; |
1193
|
|
|
|
|
|
|
######## /while_progress ######## |
1194
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
######## EXTERNAL ROUTINE ######## |
1196
|
|
|
|
|
|
|
# |
1197
|
|
|
|
|
|
|
# Print_for( $caller_id, @args ); # short |
1198
|
|
|
|
|
|
|
# |
1199
|
|
|
|
|
|
|
# Purpose : Print @args to caller's chosen $outfh |
1200
|
|
|
|
|
|
|
# Parms : $caller_id : identify which caller |
1201
|
|
|
|
|
|
|
# : $frame : we may be called directly or by proxy |
1202
|
|
|
|
|
|
|
# : @args : any printable list |
1203
|
|
|
|
|
|
|
# Reads : %state_of |
1204
|
|
|
|
|
|
|
# Returns : 1 |
1205
|
|
|
|
|
|
|
# Writes : to $outfh |
1206
|
|
|
|
|
|
|
# Throws : dies if print fails |
1207
|
|
|
|
|
|
|
# See also : _get_new_caller_id(), Warn_for(), _decode_assert(), Dump() |
1208
|
|
|
|
|
|
|
# |
1209
|
|
|
|
|
|
|
# Call this only from within replacement code. |
1210
|
|
|
|
|
|
|
# If called by another our-module routine, it will get the wrong stack frame. |
1211
|
|
|
|
|
|
|
# |
1212
|
|
|
|
|
|
|
sub Print_for { |
1213
|
158
|
|
|
158
|
0
|
234
|
my $caller_id = shift; |
1214
|
158
|
|
|
|
|
356
|
my $outfh = _get_outfh($caller_id); # get from %state_of |
1215
|
|
|
|
|
|
|
|
1216
|
158
|
50
|
|
|
|
272
|
print {$outfh} @_ |
|
158
|
|
|
|
|
1032
|
|
1217
|
|
|
|
|
|
|
or die q{Devel::Comments: } # print failure |
1218
|
|
|
|
|
|
|
, q{Filesystem IO error: } |
1219
|
|
|
|
|
|
|
, qq{Failed to print to output filehandle for $caller_id } |
1220
|
|
|
|
|
|
|
, $! |
1221
|
|
|
|
|
|
|
; |
1222
|
|
|
|
|
|
|
|
1223
|
158
|
|
|
|
|
421
|
return 1; |
1224
|
|
|
|
|
|
|
}; |
1225
|
|
|
|
|
|
|
######## /Print_for ######## |
1226
|
|
|
|
|
|
|
|
1227
|
|
|
|
|
|
|
######## EXTERNAL ROUTINE ######## |
1228
|
|
|
|
|
|
|
# |
1229
|
|
|
|
|
|
|
# Warn_for( $caller_id, $frame, @args ); # short |
1230
|
|
|
|
|
|
|
# |
1231
|
|
|
|
|
|
|
# Purpose : Print @args *and* $file, $line to caller's chosen $outfh |
1232
|
|
|
|
|
|
|
# : as if it were warn(). |
1233
|
|
|
|
|
|
|
# Parms : $caller_id : identify which caller |
1234
|
|
|
|
|
|
|
# : $frame : we may be called directly or by proxy |
1235
|
|
|
|
|
|
|
# : @args : any printable list |
1236
|
|
|
|
|
|
|
# Reads : %state_of |
1237
|
|
|
|
|
|
|
# Returns : 1 |
1238
|
|
|
|
|
|
|
# Writes : to $outfh |
1239
|
|
|
|
|
|
|
# Throws : dies if print fails |
1240
|
|
|
|
|
|
|
# See also : _get_new_caller_id(), Print_for(), _decode_assert() |
1241
|
|
|
|
|
|
|
# |
1242
|
|
|
|
|
|
|
# This can be called from within replacement code or from S::C; |
1243
|
|
|
|
|
|
|
# but either way, $frame must be passed in. |
1244
|
|
|
|
|
|
|
sub Warn_for { |
1245
|
14
|
|
|
14
|
0
|
29585
|
my $caller_id = shift; |
1246
|
14
|
|
|
|
|
25
|
my $frame = shift; |
1247
|
|
|
|
|
|
|
|
1248
|
|
|
|
|
|
|
### In Warn_for(): |
1249
|
|
|
|
|
|
|
### $caller_id |
1250
|
|
|
|
|
|
|
### $frame |
1251
|
|
|
|
|
|
|
|
1252
|
14
|
|
|
|
|
90
|
my @caller = caller($frame); |
1253
|
|
|
|
|
|
|
### @caller |
1254
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
# my $caller_name = $caller[0]; |
1256
|
14
|
|
|
|
|
31
|
my $caller_file = $caller[1]; |
1257
|
14
|
|
|
|
|
31
|
my $caller_line = $caller[2]; |
1258
|
|
|
|
|
|
|
|
1259
|
14
|
|
|
|
|
78
|
Print_for( $caller_id, @_, " at $caller_file line $caller_line.\n" ); |
1260
|
14
|
|
|
|
|
48
|
return 1; |
1261
|
|
|
|
|
|
|
}; |
1262
|
|
|
|
|
|
|
######## /Warn_for ######## |
1263
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
######## INTERNAL ROUTINE ######## |
1265
|
|
|
|
|
|
|
# |
1266
|
|
|
|
|
|
|
# _put_state( $caller_id, @caller ); # short |
1267
|
|
|
|
|
|
|
# |
1268
|
|
|
|
|
|
|
# Purpose : Store current state info |
1269
|
|
|
|
|
|
|
# Parms : $caller_id : to put %state_of previous state |
1270
|
|
|
|
|
|
|
# : @caller : current state (maybe) |
1271
|
|
|
|
|
|
|
# Reads : %state_of |
1272
|
|
|
|
|
|
|
# Returns : 1 |
1273
|
|
|
|
|
|
|
# Writes : %state_of |
1274
|
|
|
|
|
|
|
# Throws : dies if called with unknown caller |
1275
|
|
|
|
|
|
|
# See also : _spacer_required(), Dump_for() |
1276
|
|
|
|
|
|
|
# |
1277
|
|
|
|
|
|
|
# This stores not $outfh itself |
1278
|
|
|
|
|
|
|
# but the initial state of output to it, sort of. |
1279
|
|
|
|
|
|
|
# |
1280
|
|
|
|
|
|
|
sub _put_state { |
1281
|
49
|
|
|
49
|
|
83
|
my $caller_id = shift; |
1282
|
49
|
|
|
|
|
127
|
my @caller = @_; |
1283
|
49
|
|
|
|
|
121
|
my $caller_name = $caller[0]; |
1284
|
49
|
|
|
|
|
73
|
my $caller_file = $caller[1]; |
1285
|
49
|
|
|
|
|
66
|
my $caller_line = $caller[2]; |
1286
|
|
|
|
|
|
|
|
1287
|
49
|
50
|
|
|
|
150
|
die "Devel::Comments: Fatal Error (_put_state): ", |
1288
|
|
|
|
|
|
|
"No state_of $caller_id.", |
1289
|
|
|
|
|
|
|
$! if ( !defined $state_of{$caller_id} ); |
1290
|
|
|
|
|
|
|
|
1291
|
49
|
|
|
|
|
141
|
my $outfh = _get_outfh($caller_id); |
1292
|
|
|
|
|
|
|
|
1293
|
49
|
|
|
|
|
186
|
$state_of{$caller_id}{-tell}{-outfh} = tell $outfh; |
1294
|
49
|
|
|
|
|
148
|
$state_of{$caller_id}{-tell}{-stdout} = tell (*STDOUT); |
1295
|
49
|
|
|
|
|
173
|
$state_of{$caller_id}{-caller}{-file} = $caller_file; |
1296
|
49
|
|
|
|
|
118
|
$state_of{$caller_id}{-caller}{-line} = $caller_line; |
1297
|
|
|
|
|
|
|
|
1298
|
49
|
|
|
|
|
147
|
return 1; |
1299
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
}; |
1301
|
|
|
|
|
|
|
######## /_put_state ######## |
1302
|
|
|
|
|
|
|
|
1303
|
|
|
|
|
|
|
######## INTERNAL ROUTINE ######## |
1304
|
|
|
|
|
|
|
# |
1305
|
|
|
|
|
|
|
# $flag = _spacer_required( $caller_id, @caller ); # newline before? |
1306
|
|
|
|
|
|
|
# |
1307
|
|
|
|
|
|
|
# Purpose : Ensure the smart output starts flush left. |
1308
|
|
|
|
|
|
|
# Parms : $caller_id : key %state_of for previous state |
1309
|
|
|
|
|
|
|
# : @caller : current state (maybe) |
1310
|
|
|
|
|
|
|
# Reads : %state_of |
1311
|
|
|
|
|
|
|
# Returns : Boolean: TRUE to prepend a newline to output |
1312
|
|
|
|
|
|
|
# Writes : ____ |
1313
|
|
|
|
|
|
|
# Throws : ____ |
1314
|
|
|
|
|
|
|
# See also : Dump_for(), %state_of |
1315
|
|
|
|
|
|
|
# |
1316
|
|
|
|
|
|
|
# Vanilla S::C compared both previous tell()-s of STDOUT and STDERR |
1317
|
|
|
|
|
|
|
# before deciding to print a prophylactic newline, even though Vanilla |
1318
|
|
|
|
|
|
|
# only ever printed to STDERR. One might assume Conway does this |
1319
|
|
|
|
|
|
|
# on *his* assumption that both are connected to the same output device, |
1320
|
|
|
|
|
|
|
# namely a terminal window or console. |
1321
|
|
|
|
|
|
|
# This may or may not be wise but we preserve the exact Vanilla behavior; |
1322
|
|
|
|
|
|
|
# while output to disk files contains fewer newlines. |
1323
|
|
|
|
|
|
|
# Since we make no explicit check of which or what kind of filehandle, |
1324
|
|
|
|
|
|
|
# I cannot explain why this is so. |
1325
|
|
|
|
|
|
|
# The missing newlines are not going to STDOUT, STDERR, or the screen anyway. |
1326
|
|
|
|
|
|
|
# |
1327
|
|
|
|
|
|
|
# TODO: Vanilla outputs a gratuitous newline |
1328
|
|
|
|
|
|
|
# if $caller_line has changed by more than one line. |
1329
|
|
|
|
|
|
|
# This may result in rather "loose" output. |
1330
|
|
|
|
|
|
|
# TODO: Accept a "tighten" arg in use line. |
1331
|
|
|
|
|
|
|
# |
1332
|
|
|
|
|
|
|
sub _spacer_required { |
1333
|
28
|
|
|
28
|
|
45
|
my $caller_id = shift; |
1334
|
28
|
|
|
|
|
66
|
my @caller = @_; |
1335
|
28
|
|
|
|
|
52
|
my $caller_name = $caller[0]; |
1336
|
28
|
|
|
|
|
46
|
my $caller_file = $caller[1]; |
1337
|
28
|
|
|
|
|
35
|
my $caller_line = $caller[2]; |
1338
|
|
|
|
|
|
|
|
1339
|
28
|
|
|
|
|
59
|
my $outfh = _get_outfh($caller_id); # retrieve from %state_of |
1340
|
|
|
|
|
|
|
|
1341
|
|
|
|
|
|
|
#say '$outfh: ', $outfh; |
1342
|
28
|
|
|
|
|
104
|
my $prev_tell_outfh = $state_of{$caller_id}{-tell}{-outfh}; |
1343
|
28
|
|
|
|
|
77
|
my $prev_tell_stdout = $state_of{$caller_id}{-tell}{-stdout}; |
1344
|
28
|
|
|
|
|
90
|
my $prev_caller_file = $state_of{$caller_id}{-caller}{-file}; |
1345
|
28
|
|
|
|
|
486
|
my $prev_caller_line = $state_of{$caller_id}{-caller}{-line}; |
1346
|
|
|
|
|
|
|
|
1347
|
28
|
|
|
|
|
36
|
my $flag ; |
1348
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
# This test is *not* needed, oddly enough! |
1350
|
|
|
|
|
|
|
# Intent was to preserve Vanilla behavior by requiring newline |
1351
|
|
|
|
|
|
|
# if tell STDOUT had changed when printing to STDERR. |
1352
|
|
|
|
|
|
|
# But with this paragraph disabled, Vanilla is preserved |
1353
|
|
|
|
|
|
|
# and also 'use Devel::Comments *STDOUT' yields the same output. |
1354
|
|
|
|
|
|
|
# Yet when given a hard disk $fh, fewer gratuitous newlines are output, |
1355
|
|
|
|
|
|
|
# which is desired. |
1356
|
|
|
|
|
|
|
# I cannot figure out why. Let us consider this a blessing. |
1357
|
|
|
|
|
|
|
# |
1358
|
|
|
|
|
|
|
# # You might not think you can compare filehandles, but you can... |
1359
|
|
|
|
|
|
|
# # ... but only if they're identical, not if they're equivalent... |
1360
|
|
|
|
|
|
|
# # ... *STDERR ne \*STDERR # although most io routines will accept either |
1361
|
|
|
|
|
|
|
# if ( $outfh eq *STDERR ) { # STDERR chosen, vanilla behavior |
1362
|
|
|
|
|
|
|
# # newline if STDOUT has been printed to since last smart output |
1363
|
|
|
|
|
|
|
# $flag ||= $prev_tell_stdout != tell(*STDOUT); |
1364
|
|
|
|
|
|
|
#say 'I Vanillaed.'; |
1365
|
|
|
|
|
|
|
# }; |
1366
|
|
|
|
|
|
|
|
1367
|
|
|
|
|
|
|
# newline if $outfh has been printed to |
1368
|
28
|
|
66
|
|
|
178
|
$flag ||= $prev_tell_outfh != tell $outfh; |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
# newline if $caller_file has changed (???) |
1371
|
28
|
|
66
|
|
|
124
|
$flag ||= $prev_caller_file ne $caller_file; |
1372
|
|
|
|
|
|
|
|
1373
|
|
|
|
|
|
|
# TODO: if $tighten do not... |
1374
|
|
|
|
|
|
|
# newline if $caller_line has changed by more or less than 1 |
1375
|
28
|
|
100
|
|
|
130
|
$flag ||= $prev_caller_line != $caller_line -1; |
1376
|
|
|
|
|
|
|
|
1377
|
|
|
|
|
|
|
#~ say 'Doing the newline.' if $flag; #~ |
1378
|
|
|
|
|
|
|
#~ return 0; # never do the newline #~ |
1379
|
28
|
|
|
|
|
129
|
return $flag; |
1380
|
|
|
|
|
|
|
}; |
1381
|
|
|
|
|
|
|
######## /_spacer_required ######## |
1382
|
|
|
|
|
|
|
|
1383
|
|
|
|
|
|
|
######## EXTERNAL ROUTINE ######## |
1384
|
|
|
|
|
|
|
# |
1385
|
|
|
|
|
|
|
# Dump_for(); # short |
1386
|
|
|
|
|
|
|
# |
1387
|
|
|
|
|
|
|
# Purpose : Dump a variable (any variable?) |
1388
|
|
|
|
|
|
|
# Parms : flat list (assigned to hash) |
1389
|
|
|
|
|
|
|
# Reads : ____ |
1390
|
|
|
|
|
|
|
# Returns : ____ |
1391
|
|
|
|
|
|
|
# Writes : ____ |
1392
|
|
|
|
|
|
|
# Throws : ____ |
1393
|
|
|
|
|
|
|
# See also : Data::Dumper, FILTER # Any other smart comment is a simple dump |
1394
|
|
|
|
|
|
|
# |
1395
|
|
|
|
|
|
|
# Dump a variable and then reformat the resulting string more prettily... |
1396
|
|
|
|
|
|
|
# |
1397
|
|
|
|
|
|
|
sub Dump_for { |
1398
|
|
|
|
|
|
|
|
1399
|
49
|
|
|
49
|
0
|
212218
|
my %hash = @_; |
1400
|
49
|
50
|
|
|
|
251
|
my $caller_id = $hash{-caller_id} |
1401
|
|
|
|
|
|
|
or die q{Devel::Comments: } # called with no -caller_id |
1402
|
|
|
|
|
|
|
, q{Replacement code error: } |
1403
|
|
|
|
|
|
|
, q{-caller_id not passed in call to Dump(). } |
1404
|
|
|
|
|
|
|
, $! |
1405
|
|
|
|
|
|
|
; |
1406
|
|
|
|
|
|
|
|
1407
|
49
|
|
|
|
|
116
|
my $prefix = $hash{-prefix}; |
1408
|
|
|
|
|
|
|
#~ my $exists_varref = exists $hash{-varref}; # save test #~ |
1409
|
49
|
|
|
|
|
121
|
my $defined_varref = defined $hash{-varref}; # save test |
1410
|
49
|
|
|
|
|
99
|
my $varref = $hash{-varref}; |
1411
|
49
|
|
|
|
|
102
|
my $no_newline = $hash{-no_newline}; |
1412
|
|
|
|
|
|
|
|
1413
|
49
|
|
|
|
|
202
|
my @caller = caller; # called by replacement code |
1414
|
|
|
|
|
|
|
# my $caller_name = $caller[0]; |
1415
|
49
|
|
|
|
|
97
|
my $caller_file = $caller[1]; |
1416
|
49
|
|
|
|
|
69
|
my $caller_line = $caller[2]; |
1417
|
49
|
|
|
|
|
134
|
my $outfh = _get_outfh($caller_id); # retrieve from %state_of |
1418
|
|
|
|
|
|
|
|
1419
|
49
|
|
|
|
|
84
|
my $spacer_required ; # TRUE to prepend a newline to output |
1420
|
|
|
|
|
|
|
|
1421
|
|
|
|
|
|
|
#~ say $outfh '... Entering Dump_for() ...'; #~ |
1422
|
|
|
|
|
|
|
#~ ### ... Entering Dump_for() #~ |
1423
|
|
|
|
|
|
|
#~ ### %state_of #~ |
1424
|
|
|
|
|
|
|
|
1425
|
|
|
|
|
|
|
# Handle timestamps... |
1426
|
49
|
|
|
|
|
111
|
$prefix =~ s/<(?:now|time|when)>/scalar localtime()/ge; |
|
0
|
|
|
|
|
0
|
|
1427
|
49
|
|
|
|
|
103
|
$prefix =~ s/<(?:here|place|where)>/"$caller_file", line $caller_line/g; |
1428
|
|
|
|
|
|
|
|
1429
|
|
|
|
|
|
|
# Add a newline? |
1430
|
49
|
100
|
|
|
|
124
|
if ($no_newline) { |
1431
|
21
|
|
|
|
|
35
|
$spacer_required = 0; |
1432
|
|
|
|
|
|
|
} |
1433
|
|
|
|
|
|
|
else { |
1434
|
28
|
|
|
|
|
238
|
$spacer_required = _spacer_required( $caller_id, @caller ); |
1435
|
|
|
|
|
|
|
}; |
1436
|
|
|
|
|
|
|
#~ ### $spacer_required #~ |
1437
|
|
|
|
|
|
|
|
1438
|
|
|
|
|
|
|
#~ print $outfh 'defined_varref: ', $defined_varref, ' '; #~ |
1439
|
|
|
|
|
|
|
# Handle a prefix with no actual variable... |
1440
|
49
|
100
|
66
|
|
|
335
|
if ($prefix && !$defined_varref) { |
1441
|
14
|
|
|
|
|
31
|
$prefix =~ s/:$//; |
1442
|
14
|
100
|
|
|
|
58
|
Print_for( $caller_id, "\n" ) if $spacer_required; |
1443
|
14
|
|
|
|
|
53
|
Print_for( $caller_id, "### $prefix\n" ); |
1444
|
14
|
|
|
|
|
41
|
_put_state( $caller_id, @caller ); |
1445
|
14
|
|
|
|
|
68
|
return 1; # ...abort if not defined $varref |
1446
|
|
|
|
|
|
|
} |
1447
|
|
|
|
|
|
|
|
1448
|
|
|
|
|
|
|
# or continue... |
1449
|
|
|
|
|
|
|
|
1450
|
|
|
|
|
|
|
# Set Data::Dumper up for a tidy dump and do the dump... |
1451
|
35
|
|
|
|
|
66
|
local $Data::Dumper::Quotekeys = 0; |
1452
|
35
|
|
|
|
|
64
|
local $Data::Dumper::Sortkeys = 1; |
1453
|
35
|
|
|
|
|
50
|
local $Data::Dumper::Indent = 2; |
1454
|
35
|
|
|
|
|
162
|
my $dumped = Dumper $varref; |
1455
|
|
|
|
|
|
|
|
1456
|
|
|
|
|
|
|
# Clean up the results... |
1457
|
|
|
|
|
|
|
|
1458
|
|
|
|
|
|
|
#~ say $outfh q{}; #~ |
1459
|
|
|
|
|
|
|
#~ say $outfh q{-----}; #~ |
1460
|
|
|
|
|
|
|
#~ my $gotstuff = join '', @{$varref}; #~ |
1461
|
|
|
|
|
|
|
#~ say $outfh '@{varref}: >' . $gotstuff . '<'; #~ |
1462
|
|
|
|
|
|
|
#~ say $outfh 'dumped before: >' . $dumped . '<'; #~ |
1463
|
|
|
|
|
|
|
#~ say $outfh 'exists: (', $exists_varref, ')'; #~ |
1464
|
|
|
|
|
|
|
|
1465
|
|
|
|
|
|
|
# report 'null' for "return;" -- see RT#69712 |
1466
|
35
|
|
|
|
|
2952
|
$dumped =~ s/\$VAR1 = \[];\n/\$VAR1 = \[\n null\n];\n/; |
1467
|
|
|
|
|
|
|
|
1468
|
35
|
|
|
|
|
135
|
$dumped =~ s/\$VAR1 = \[\n//; |
1469
|
35
|
|
|
|
|
391
|
$dumped =~ s/\s*\];\s*$//; |
1470
|
|
|
|
|
|
|
#~ my $len_1; #~ |
1471
|
|
|
|
|
|
|
#~ $len_1 = length $1; #~ |
1472
|
|
|
|
|
|
|
#~ say $outfh '$1: ', $1, 'length: ', $len_1; #~ |
1473
|
35
|
|
|
|
|
145
|
$dumped =~ s/\A(\s*)//; |
1474
|
|
|
|
|
|
|
#~ $len_1 = length $1; #~ |
1475
|
|
|
|
|
|
|
#~ say $outfh '$1: ', $1, 'length: ', $len_1; #~ |
1476
|
|
|
|
|
|
|
#~ |
1477
|
|
|
|
|
|
|
#~ say $outfh 'dumped after: >' . $dumped . '<'; #~ |
1478
|
|
|
|
|
|
|
|
1479
|
|
|
|
|
|
|
# How much to shave off and put back on each line... |
1480
|
35
|
|
|
|
|
99
|
my $indent = length $1; |
1481
|
35
|
|
|
|
|
106
|
my $outdent = q{ } x (length($prefix) + 1); |
1482
|
|
|
|
|
|
|
#~ say $outfh 'indent: ', $indent, ' outdent: >', $outdent, '<'; #~ |
1483
|
|
|
|
|
|
|
# Report "inside-out" and "flyweight" objects more cleanly... |
1484
|
35
|
|
|
|
|
65
|
$dumped =~ s{bless[(] do[{]\\[(]my \$o = undef[)][}], '([^']+)' [)]} |
1485
|
|
|
|
|
|
|
{}g; |
1486
|
|
|
|
|
|
|
|
1487
|
|
|
|
|
|
|
# Adjust the indents... |
1488
|
35
|
|
|
|
|
485
|
$dumped =~ s/^[ ]{$indent}([ ]*)/### $outdent$1/gm; |
1489
|
|
|
|
|
|
|
#~ say $outfh 'dumped later: >' . $dumped . '<'; #~ |
1490
|
|
|
|
|
|
|
|
1491
|
|
|
|
|
|
|
# Print the message... |
1492
|
35
|
100
|
|
|
|
154
|
Print_for( $caller_id, "\n" ) if $spacer_required; |
1493
|
35
|
|
|
|
|
134
|
Print_for( $caller_id, "### $prefix $dumped\n" ); |
1494
|
35
|
|
|
|
|
107
|
_put_state( $caller_id, @caller ); |
1495
|
|
|
|
|
|
|
|
1496
|
35
|
|
|
|
|
197
|
return 1; |
1497
|
|
|
|
|
|
|
}; |
1498
|
|
|
|
|
|
|
######## /Dump_for ######## |
1499
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
#~ say '---| Devel::Comments at line ', __LINE__; #~ |
1501
|
|
|
|
|
|
|
|
1502
|
|
|
|
|
|
|
############################# |
1503
|
|
|
|
|
|
|
######## END MODULE ######### |
1504
|
|
|
|
|
|
|
1; |
1505
|
|
|
|
|
|
|
__END__ |