File Coverage

blib/lib/Log/Report/Util.pm
Criterion Covered Total %
statement 53 74 71.6
branch 29 56 51.7
condition 8 40 20.0
subroutine 13 19 68.4
pod 13 15 86.6
total 116 204 56.8


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