File Coverage

blib/lib/Log/Report/Util.pm
Criterion Covered Total %
statement 58 79 73.4
branch 31 58 53.4
condition 8 40 20.0
subroutine 14 20 70.0
pod 13 15 86.6
total 124 212 58.4


line stmt bran cond sub pod time code
1             # Copyrights 2013-2017 by [Mark Overmeer].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.02.
5              
6 5     5   125939 use warnings;
  5         24  
  5         168  
7 5     5   28 use strict;
  5         11  
  5         161  
8              
9             package Log::Report::Util;
10 5     5   26 use vars '$VERSION';
  5         8  
  5         234  
11             $VERSION = '1.04';
12              
13 5     5   29 use base 'Exporter';
  5         11  
  5         703  
14              
15 5     5   1205 use String::Print qw(printi);
  5         266715  
  5         42  
16              
17             our @EXPORT = qw/
18             @reasons is_reason is_fatal use_errno
19             mode_number expand_reasons mode_accepts
20             must_show_location must_show_stack
21             escape_chars unescape_chars to_html
22             parse_locale
23             pkg2domain
24             /;
25             # [0.994 parse_locale deprecated, but kept hidden]
26              
27             our @EXPORT_OK = qw/%reason_code/;
28              
29             #use Log::Report 'log-report';
30 5     5 0 30 sub N__w($) { split ' ', $_[0] }
31              
32             # ordered!
33             our @reasons = N__w('TRACE ASSERT INFO NOTICE WARNING
34             MISTAKE ERROR FAULT ALERT FAILURE PANIC');
35             our %reason_code; { my $i=1; %reason_code = map +($_ => $i++), @reasons }
36              
37             my @user = qw/MISTAKE ERROR/;
38             my @program = qw/TRACE ASSERT INFO NOTICE WARNING PANIC/;
39             my @system = qw/FAULT ALERT FAILURE/;
40              
41             my %is_fatal = map +($_ => 1), qw/ERROR FAULT FAILURE PANIC/;
42             my %use_errno = map +($_ => 1), qw/FAULT ALERT FAILURE/;
43              
44             my %modes = (NORMAL => 0, VERBOSE => 1, ASSERT => 2, DEBUG => 3
45             , 0 => 0, 1 => 1, 2 => 2, 3 => 3);
46             my @mode_accepts = ('NOTICE-', 'INFO-', 'ASSERT-', 'ALL');
47              
48             # horrible mutual dependency with Log::Report(::Minimal)
49             sub error__x($%)
50 0 0   0 0 0 { if(Log::Report::Minimal->can('error')) # loaded the ::Mimimal version
51 0         0 { Log::Report::Minimal::error(Log::Report::Minimal::__x(@_)) }
52 0         0 else { Log::Report::error(Log::Report::__x(@_)) }
53             }
54              
55              
56             sub expand_reasons($)
57 13     13 1 5049 { my $reasons = shift;
58 13         29 my %r;
59 13         46 foreach my $r (split m/\,/, $reasons)
60 15 100       106 { if($r =~ m/^([a-z]*)\-([a-z]*)/i )
    100          
    100          
    100          
    100          
    50          
61 7   100     53 { my $begin = $reason_code{$1 || 'TRACE'};
62 7   100     56 my $end = $reason_code{$2 || 'PANIC'};
63 7 0 33     49 $begin && $end
    50          
64             or error__x "unknown reason {which} in '{reasons}'"
65             , which => ($begin ? $2 : $1), reasons => $reasons;
66              
67 7 50       43 error__x"reason '{begin}' more serious than '{end}' in '{reasons}"
68             , begin => $1, end => $2, reasons => $reasons
69             if $begin >= $end;
70              
71 7         72 $r{$_}++ for $begin..$end;
72             }
73 3         10 elsif($reason_code{$r}) { $r{$reason_code{$r}}++ }
74 2         11 elsif($r eq 'USER') { $r{$reason_code{$_}}++ for @user }
75 1         11 elsif($r eq 'PROGRAM') { $r{$reason_code{$_}}++ for @program }
76 1         7 elsif($r eq 'SYSTEM') { $r{$reason_code{$_}}++ for @system }
77 1         9 elsif($r eq 'ALL') { $r{$reason_code{$_}}++ for @reasons }
78             else
79 0         0 { error__x"unknown reason {which} in '{reasons}'"
80             , which => $r, reasons => $reasons;
81             }
82             }
83 13         83 (undef, @reasons)[sort {$a <=> $b} keys %r];
  133         303  
84             }
85              
86              
87 2     2 1 7 sub is_reason($) { $reason_code{$_[0]} }
88 2     2 1 7 sub is_fatal($) { $is_fatal{$_[0]} }
89 2     2 1 6 sub use_errno($) { $use_errno{$_[0]} }
90              
91             #--------------------------
92              
93 0     0 1 0 sub mode_number($) { $modes{$_[0]} }
94              
95              
96 4     4 1 23 sub mode_accepts($) { $mode_accepts[$modes{$_[0]}] }
97              
98              
99             sub must_show_location($$)
100 0     0 1 0 { my ($mode, $reason) = @_;
101             $reason eq 'ASSERT'
102             || $reason eq 'PANIC'
103             || ($mode==2 && $reason_code{$reason} >= $reason_code{WARNING})
104 0 0 0     0 || ($mode==3 && $reason_code{$reason} >= $reason_code{MISTAKE});
      0        
      0        
      0        
105             }
106              
107              
108             sub must_show_stack($$)
109 0     0 1 0 { my ($mode, $reason) = @_;
110             $reason eq 'PANIC'
111             || ($mode==2 && $reason_code{$reason} >= $reason_code{ALERT})
112 0 0 0     0 || ($mode==3 && $reason_code{$reason} >= $reason_code{ERROR});
      0        
      0        
113             }
114              
115             #-------------------------
116              
117             my %unescape =
118             ( '\a' => "\a", '\b' => "\b", '\f' => "\f", '\n' => "\n"
119             , '\r' => "\r", '\t' => "\t", '\"' => '"', '\\\\' => '\\'
120             , '\e' => "\x1b", '\v' => "\x0b"
121             );
122             my %escape = reverse %unescape;
123              
124             sub escape_chars($)
125 0     0 1 0 { my $str = shift;
126 0 0       0 $str =~ s/([\x00-\x1F\x7F"\\])/$escape{$1} || '?'/ge;
  0         0  
127 0         0 $str;
128             }
129              
130             sub unescape_chars($)
131 0     0 1 0 { my $str = shift;
132 0 0       0 $str =~ s/(\\.)/$unescape{$1} || $1/ge;
  0         0  
133 0         0 $str;
134             }
135              
136              
137             my %tohtml = qw/ > gt < lt " quot & amp /;
138              
139             sub to_html($)
140 1     1 1 461 { my $s = shift;
141 1         15 $s =~ s/([<>"&])/\&${tohtml{$1}};/g;
142 1         6 $s;
143             }
144              
145              
146             sub parse_locale($)
147 11     11 1 15688 { my $locale = shift;
148 11 100 66     56 defined $locale && length $locale
149             or return;
150              
151 10 50       69 if($locale !~
152             m/^ ([a-z_]+)
153             (?: \. ([\w-]+) )? # codeset
154             (?: \@ (\S+) )? # modifier
155             $/ix)
156             { # Windows Finnish_Finland.1252?
157 0         0 $locale =~ s/.*\.//;
158 0 0       0 return wantarray ? ($locale) : { language => $locale };
159             }
160              
161 10         33 my ($lang, $codeset, $modifier) = ($1, $2, $3);
162              
163 10         36 my @subtags = split /[_-]/, $lang;
164 10         23 my $primary = lc shift @subtags;
165              
166 10 0 0     49 my $language
    0 0        
    50          
    100          
    100          
167             = $primary eq 'c' ? 'C'
168             : $primary eq 'posix' ? 'POSIX'
169             : $primary =~ m/^[a-z]{2,3}$/ ? $primary # ISO639-1 and -2
170             : $primary eq 'i' && @subtags ? lc(shift @subtags) # IANA
171             : $primary eq 'x' && @subtags ? lc(shift @subtags) # Private
172             : error__x"unknown locale language in locale `{locale}'"
173             , locale => $locale;
174              
175 10         13 my $script;
176 10 50 33     26 $script = ucfirst lc shift @subtags
177             if @subtags > 1 && length $subtags[0] > 3;
178              
179 10 100       22 my $territory = @subtags ? uc(shift @subtags) : undef;
180              
181 10 50       40 return ($language, $territory, $codeset, $modifier)
182             if wantarray;
183              
184 0         0 +{ language => $language
185             , script => $script
186             , territory => $territory
187             , codeset => $codeset
188             , modifier => $modifier
189             , variant => join('-', @subtags)
190             };
191             }
192              
193              
194             my %pkg2domain;
195             sub pkg2domain($;$$$)
196 8     8 1 20 { my $pkg = shift;
197 8         19 my $d = $pkg2domain{$pkg};
198 8 50       41 @_ or return $d ? $d->[0] : 'default';
    100          
199              
200 5         14 my ($domain, $fn, $line) = @_;
201 5 100       26 if($d)
202             { # registration already exists
203 1 50       5 return $domain if $d->[0] eq $domain;
204 0         0 printi "conflict: package {pkg} in {domain1} in {file1} line {line1}, but in {domain2} in {file2} line {line2}"
205             , pkg => $pkg
206             , domain1 => $domain, file1 => $fn, line1 => $line
207             , domain2 => $d->[0], file2 => $d->[1], line2 => $d->[2];
208             }
209              
210             # new registration
211 4         18 $pkg2domain{$pkg} = [$domain, $fn, $line];
212 4         15 $domain;
213             }
214              
215             1;