File Coverage

blib/lib/warnings/DynamicScope.pm
Criterion Covered Total %
statement 113 128 88.2
branch 37 52 71.1
condition 3 3 100.0
subroutine 23 27 85.1
pod 0 2 0.0
total 176 212 83.0


line stmt bran cond sub pod time code
1             #!perl -w
2             # -*- coding: utf-8-unix; tab-width: 4; -*-
3             package warnings::DynamicScope;
4              
5             # DynamicScope.pm
6             # ------------------------------------------------------------------------
7             # Revision: $Id: DynamicScope.pm,v 1.14 2005/08/15 15:53:59 kay Exp $
8             # Written by Keitaro Miyazaki
9             # Copyright 2005 Keitaro Miyazaki All Rights Reserved.
10              
11             # HISTORY
12             # ------------------------------------------------------------------------
13             # 2005-08-15 Version 1.04
14             # 2005-08-10 Version 1.03
15             # - Fixed a bug the value of $^W was not set properly in
16             # BEGIN block.
17             # 2005-08-07 Version 1.02
18             # - Defined new package variable named "$DYNAMIC_W_BITS".
19             # The tied hash "%^W" no longer accesses to the variable
20             # "${^WARNING_BITS}" unless it is accessed in BEGIN block.
21             # - Now the variable "%^W" accepts keyword "FATAL" as value.
22             # If the value is set to "FATAL", it returns 2 as value.
23             # - Added "DEAD BIT", "BEGIN BLOCK", and "$^W AND %W" item
24             # in POD document.
25             # - Improved handling of the variable "$^W". It's value is
26             # always synchronized with the value of "$^W{all}".
27             # - Made "%^W" realize "-W" and "-X" command line switches.
28             # 2005-08-04 Version 1.01
29             # - Modified POD document.
30             # - Added a few tests.
31             # 2005-08-04 Version 1.00
32             # - Initial version.
33              
34 1     1   62046 use 5.008;
  1         4  
  1         44  
35 1     1   6 use strict;
  1         3  
  1         32  
36 1     1   5 use warnings;
  1         7  
  1         245  
37              
38             our $VERSION = '1.04';
39             our $REVISION = '$Id: DynamicScope.pm,v 1.14 2005/08/15 15:53:59 kay Exp $';
40             our $DEBUG = 0;
41              
42 1     1   1209 use Symbol::Values 'symbol';
  1         13511  
  1         187  
43              
44             #-------------------------------------------------------------------------
45             # Functions
46             #
47             sub in_begin_block {
48 562     562 0 651 my($func, $i);
49            
50 562         2628 for ($i=2; $func = (caller($i))[3]; ++$i) {
51 185 100       9791 return 1 if $func =~ /^(?:.*::)?BEGIN$/o;
52 156 50       415 next if $func eq '(eval)';
53 156         323 return 0;
54             }
55 377         11092 0
56             }
57              
58              
59             #-------------------------------------------------------------------------
60             # Base module(Tied Hash)
61             #-------------------------------------------------------------------------
62             package warnings::DynamicScope::WARNINGS_HASH;
63 1     1   1395 use Tie::Hash;
  1         1138  
  1         34  
64 1     1   8 use base "Tie::Hash";
  1         2  
  1         172  
65 1     1   6 use Symbol::Values 'symbol';
  1         2  
  1         119  
66              
67             #-------------------------------------------------------------------------
68             # Variables
69             #
70             our (
71             $r_WARNINGS, # original value of $^W
72             $LEXICAL_W_BITS, # alias of ${^WARNING_BITS}
73             $DYNAMIC_W_BITS, # Warning bits in dynamic scope.
74             %Bits, # bitmask on/off
75             %DeadBits, # bitmask if fatal or not.
76             %Offsets, # bit offset beggining from the string.
77             $W_FLAG, # if command line switch "-W" is on
78             $X_FLAG, # if command line switch "-X" is on
79             );
80              
81             #-------------------------------------------------------------------------
82             # Some aliases
83             #
84             BEGIN {
85 1     1   5 no warnings 'Symbol::Values';
  1         2  
  1         123  
86 1     1   6 symbol('LEXICAL_W_BITS')->glob = *{^WARNING_BITS}; # $LEXICAL_W_BITS
87 1         132 symbol('bits')->code = *warnings::bits; # bits()
88 1         501 symbol('in_begin_block')->code = *warnings::DynamicScope::in_begin_block;
89 1         245 symbol('Bits')->hash_ref = *warnings::Bits; # %Bits
90 1         82 symbol('DeadBits')->hash_ref = *warnings::DeadBits; # %DeadBits # Fatal?
91 1         59 symbol('Offsets')->hash_ref = *warnings::Offsets; # %Offsets
92 1         948 $DYNAMIC_W_BITS = "";
93             }
94              
95             #-------------------------------------------------------------------------
96             # Code
97             #
98             sub TIEHASH {
99 1     1   2 my $self;
100 1         3 my $init_val = $_[1];
101 1         7 __PACKAGE__->STORE('all', $init_val);
102 1         4 bless \$self
103             }
104              
105             sub FETCH {
106 373     373   5515 my ($self, $key) = @_;
107 373 50       1122 return undef unless exists $Bits{$key};
108              
109 373         332 my $mask;
110 373 100       649 if (in_begin_block) {
111 14         35 $mask = (caller(0))[9];
112             } else {
113 359         596 $mask = $DYNAMIC_W_BITS;
114             }
115            
116 373         923 my $flag = vec($mask, $Offsets{$key}, 1);
117 373         625 my $fatal = vec($mask, $Offsets{$key}+1, 1);
118            
119 373 0       757 $DEBUG && printf(STDERR "FETCH(%s): %s = %s (FATAL = %s)\n",
    50          
120             in_begin_block() ? 'lex' : 'dyn',
121             $key, $flag, $fatal);
122            
123 373 100       11538 $flag = 0 if $X_FLAG; # Always false if "-X" switch is on.
124 373 100       571 $flag = 1 if $W_FLAG; # Always true if "-W" switch is on.
125             # NOTE: "-W" switch have a priority.
126              
127 373 100       3598 $flag
    100          
128             ? $fatal ? 2 : 1
129             : 0
130             }
131              
132             sub STORE {
133 190     190   28929 my ($self, $key, $value) = @_;
134            
135 190 100       470 unless (exists $Bits{$key})
136 1         31 { warnings::Croaker("Unknown warning category '$key'")}
137            
138 189         311 my $is_pragma = in_begin_block();
139 189 100       1883 my $mask = $is_pragma ? $LEXICAL_W_BITS : $DYNAMIC_W_BITS;
140 189         235 my $fatal = 0;
141 189         178 my $no_fatal = 0;
142            
143 189 0       325 $DEBUG && printf(STDERR "STORE(%s): %s = %s\n",
    50          
144             in_begin_block() ? 'lex' : 'dyn',
145             $key, $value);
146              
147             # Check if category will be set FATAL error.
148             #
149 189 100 100     603 if ($value && $value eq 'FATAL') {
150 3         3 $fatal = 1;
151             }
152              
153             # Set value
154             #
155 189 100       293 if ($value) {
156 80         136 $mask |= $Bits{$key};
157              
158             # Set DeadBits
159 80 100       124 if ($fatal) {
160 3         6 $mask |= $DeadBits{$key};
161             } else {
162 77         143 $mask &= ~$DeadBits{$key};
163             }
164            
165             # Unet value
166             #
167             } else {
168 109 100       151 if ($is_pragma) {
169             # this is just for compatibility...
170 6         26 $mask &= ~($Bits{$key} | $DeadBits{$key} | $warnings::All);
171             } else {
172 103         350 $mask &= ~($Bits{$key} | $DeadBits{$key});
173             }
174             }
175              
176             # Set value of $^W if necessary.
177             #
178 189 100       568 if ($key eq 'all') {
179 76 100       550 ${$r_WARNINGS} = $value ? 1 : 0;
  76         148  
180             }
181              
182 189 100       369 if ($is_pragma) {
183 15         143 $LEXICAL_W_BITS = $mask;
184             } else {
185 174         369 $DYNAMIC_W_BITS = $mask;
186             }
187            
188 189         1803 return vec($mask, $Offsets{$key}, 2)
189             }
190              
191             sub FIRSTKEY {
192 2     2   15 my $self = shift;
193 2         12 scalar each %Bits
194             }
195              
196             sub NEXTKEY {
197 146     146   152 my($self, $lastkey) = @_;
198 146         480 scalar each %Bits
199             }
200              
201             sub EXISTS {
202 40     40   270 my($self, $key) = @_;
203 40         542 exists $Bits{$key}
204             }
205              
206             sub DELETE {
207 0     0   0 my($self, $key) = @_;
208              
209 0 0       0 unless (exists $Bits{$key})
210 0         0 { warnings::Croaker("Unknown warning category '$key'")}
211              
212             # currently, delete $^W{key} will only disables the value.
213 0         0 vec($LEXICAL_W_BITS, $Offsets{$key}, 1) = 0
214             }
215              
216             sub CLEAR {
217 0     0   0 my $self = shift;
218              
219             # set all bits and dead bets to 0
220 0         0 $LEXICAL_W_BITS = $warnings::NONE;
221              
222             undef
223 0         0 }
224              
225             sub SCALAR {
226 0     0   0 my $self = shift;
227              
228             # this value has no meaning,
229             # exists only for compatibility...
230 0         0 scalar %Bits
231             }
232              
233             #-------------------------------------------------------------------------
234             # $^W
235             #-------------------------------------------------------------------------
236             package warnings::DynamicScope::WARNINGS_SCALAR;
237 1     1   7 use Tie::Scalar ();
  1         2  
  1         19  
238 1     1   5 use Symbol::Values 'symbol';
  1         2  
  1         63  
239 1     1   5 use base "Tie::Scalar";
  1         2  
  1         331  
240              
241             sub TIESCALAR {
242 1     1   1 my $dummy;
243 1         3 bless \$dummy;
244             }
245              
246             sub FETCH {
247 57     57   3994 push(@_, 'all');
248 57         206 goto &warnings::DynamicScope::WARNINGS_HASH::FETCH;
249             }
250              
251             sub STORE {
252 54     54   23674 splice(@_, 1, 0, 'all');
253 54         194 goto &warnings::DynamicScope::WARNINGS_HASH::STORE;
254             }
255              
256             #-------------------------------------------------------------------------
257             # Initialize
258             #-------------------------------------------------------------------------
259             package warnings::DynamicScope;
260              
261             my $loaded = 0;
262              
263             BEGIN {
264 1 50   1   6 unless ($loaded) {
265 1         3 my $init_value = $^W;
266              
267             # Test if "-W" or "-X" flag was passed.
268             #
269 1         2 $W_FLAG = $X_FLAG = 0;
270              
271 1 50       1 $^W = 0; $^W && ($W_FLAG = 1);
  1         5  
272 1 50       2 $^W = 1; $^W || ($X_FLAG = 1);
  1         3  
273              
274 1         2 $^W = $init_value;
275            
276             # Save original $^W
277             #
278 1         4 $r_WARNINGS = symbol('^W')->scalar_ref;
279 1         178 my $new_val;
280 1         4 symbol('^W')->scalar_ref = \$new_val;
281            
282             # Tie $^W and %^W
283             #
284 1         22492 tie %^W, "warnings::DynamicScope::WARNINGS_HASH", $init_value;
285 1         8 tie $^W, "warnings::DynamicScope::WARNINGS_SCALAR";
286              
287 1         336 $loaded = 1;
288             }
289             }
290              
291              
292             # This is private function
293             sub report {
294 0     0 0   my $pkg = shift;
295 0           printf("ALL: %d, ^W: %d\n",
296             length($Bits{all}),
297             length(${^WARNING_BITS})
298             );
299 0 0         if ($pkg) {
300 0           printf("Value for \"%s\" = %d(in Bits: %d, %d/in all: %d, %d)\n",
301             $pkg,
302             $^W{$pkg},
303             vec($Bits{$pkg}, $Offsets{$pkg}, 1),
304             vec($DeadBits{$pkg}, $Offsets{$pkg}+1, 1),
305             vec($Bits{all}, $Offsets{$pkg}, 1),
306             vec($DeadBits{all}, $Offsets{$pkg}+1, 1)
307             );
308              
309             }
310 0           foreach my $package (keys %Offsets) {
311 0           printf("%15s[%3d] = %d, bits(%d, %d), bitsin all(%d, %d)\n",
312             $package,
313             $Offsets{$package},
314             $^W{$package},
315             vec($Bits{$package}, $Offsets{$package}, 1),
316             vec($DeadBits{$package}, $Offsets{$package}+1, 1),
317             vec($Bits{all}, $Offsets{$package}, 1),
318             vec($DeadBits{all}, $Offsets{$package}+1, 1)
319             );
320             }
321             }
322              
323             1;
324             __END__