File Coverage

blib/lib/Log/Report/Util.pm
Criterion Covered Total %
statement 56 77 72.7
branch 29 56 51.7
condition 8 40 20.0
subroutine 14 20 70.0
pod 13 15 86.6
total 120 208 57.6


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