File Coverage

blib/lib/Text/Wrap.pm
Criterion Covered Total %
statement 65 67 97.0
branch 30 36 83.3
condition 8 9 88.8
subroutine 11 11 100.0
pod 0 2 0.0
total 114 125 91.2


line stmt bran cond sub pod time code
1 18     18   16641 use strict; use warnings;
  18     18   122  
  18         481  
  18         91  
  18         33  
  18         839  
2              
3             package Text::Wrap;
4              
5 18     18   108 use warnings::register;
  18         35  
  18         3676  
6              
7 18     18   119 BEGIN { require Exporter; *import = \&Exporter::import }
  18         2107  
8              
9             our @EXPORT = qw( wrap fill );
10             our @EXPORT_OK = qw( $columns $break $huge );
11              
12             our $VERSION = '2023.0511';
13             our $SUBVERSION = 'modern'; # back-compat vestige
14              
15 18     18   4172 BEGIN { eval sprintf 'sub REGEXPS_USE_BYTES () { %d }', scalar( pack('U*', 0x80) =~ /\xc2/ ) }
16              
17             my $brkspc = "\x{a0}\x{202f}" =~ /\s/ ? '[^\x{a0}\x{202f}\S]' : '\s';
18              
19             our $columns = 76; # <= screen width
20             our $break = '(?>\n|\r\n|'.$brkspc.'\pM*)';
21             our $huge = 'wrap'; # alternatively: 'die' or 'overflow'
22             our $unexpand = 1;
23             our $tabstop = 8;
24             our $separator = "\n";
25             our $separator2 = undef;
26              
27 17     17   10839 sub _xlen { $_[0] =~ /^\pM/ + ( () = $_[0] =~ /\PM/g ) }
  17     221   241  
  17         289  
  221         891  
28              
29 18     18   382758 use Text::Tabs qw(expand unexpand);
  18         44  
  18         4569  
30              
31             sub wrap
32             {
33 110 100   110 0 9071 my ($ip, $xp, @t) = map +( defined $_ ? $_ : '' ), @_;
34              
35 110         245 local($Text::Tabs::tabstop) = $tabstop;
36 110         175 my $r = "";
37 110         171 my $tail = pop(@t);
38 110 100       2403 my $t = expand(join("", (map { /\s+\z/ ? ( $_ ) : ($_, ' ') } @t), $tail));
  57         272  
39 110         343 my $lead = $ip;
40 110         262 my $nll = $columns - _xlen(expand($xp)) - 1;
41 110 100 100     323 if ($nll <= 0 && $xp ne '') {
42 1         4 my $nc = _xlen(expand($xp)) + 2;
43 1         263 warnings::warnif "Increasing \$Text::Wrap::columns from $columns to $nc to accommodate length of subsequent tab";
44 1         9 $columns = $nc;
45 1         2 $nll = 1;
46             }
47 110         240 my $ll = $columns - _xlen(expand($ip)) - 1;
48 110 100       349 $ll = 0 if $ll < 0;
49 110         172 my $nl = "";
50 110         174 my $remainder = "";
51              
52 18     18   133 use re 'taint';
  18         34  
  18         9381  
53              
54 110         5599 pos($t) = 0;
55 110         1495 while ($t !~ /\G(?:$break)*\Z/gc) {
56 395 100 100     9481 if ($t =~ /\G((?>(?!\n)\PM\pM*|(?
    100 66        
    100          
    50          
    50          
57 355 50       126932 $r .= $unexpand
58             ? unexpand($nl . $lead . $1)
59             : $nl . $lead . $1;
60 355         800 $remainder = $2;
61             } elsif ($huge eq 'wrap' && $t =~ /\G((?>(?!\n)\PM\pM*|(?
62 27 50       15796 $r .= $unexpand
63             ? unexpand($nl . $lead . $1)
64             : $nl . $lead . $1;
65 27 100       90 $remainder = defined($separator2) ? $separator2 : $separator;
66             } elsif ($huge eq 'overflow' && $t =~ /\G([^\n]*?)(?!(?
67 12 50       2406 $r .= $unexpand
68             ? unexpand($nl . $lead . $1)
69             : $nl . $lead . $1;
70 12         30 $remainder = $2;
71             } elsif ($huge eq 'die') {
72 0         0 die "couldn't wrap '$t'";
73             } elsif ($columns < 2) {
74 1         259 warnings::warnif "Increasing \$Text::Wrap::columns from $columns to 2";
75 1         12 $columns = 2;
76 1         10 return @_;
77             } else {
78 0         0 die "This shouldn't happen";
79             }
80            
81 394         1122 $lead = $xp;
82 394         546 $ll = $nll;
83 394 100       2447 $nl = defined($separator2)
    100          
84             ? ($remainder eq "\n"
85             ? "\n"
86             : $separator2)
87             : $separator;
88             }
89 109         436 $r .= $remainder;
90              
91 109 50       367 $r .= $lead . substr($t, pos($t), length($t) - pos($t))
92             if pos($t) ne length($t);
93              
94             # the 5.6 regexp engine ignores the UTF8 flag, so using capture buffers acts as an implicit _utf8_off
95             # that means on 5.6 we now have to manually set UTF8=on on the output if the input had it, for which
96             # we extract just the UTF8 flag from the input and check if it forces chr(0x80) to become multibyte
97 109         448 return REGEXPS_USE_BYTES && (substr($t,0,0)."\x80") =~ /\xc2/ ? pack('U0a*', $r) : $r;
98             }
99              
100             sub fill
101             {
102 2 100   2 0 72 my ($ip, $xp, @raw) = map +( defined $_ ? $_ : '' ), @_;
103 2         6 my @para;
104             my $pp;
105              
106 2         24 for $pp (split(/\n\s+/, join("\n",@raw))) {
107 11         139 $pp =~ s/\s+/ /g;
108 11         30 my $x = wrap($ip, $xp, $pp);
109 11         28 push(@para, $x);
110             }
111              
112             # if paragraph_indent is the same as line_indent,
113             # separate paragraphs with blank lines
114              
115 2 100       14 my $ps = ($ip eq $xp) ? "\n\n" : "\n";
116 2         14 return join ($ps, @para);
117             }
118              
119             1;
120              
121             __END__