line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Text::Autoformat::Hang; |
2
|
|
|
|
|
|
|
$Text::Autoformat::Hang::VERSION = '1.75'; |
3
|
5
|
|
|
5
|
|
91
|
use 5.006; |
|
5
|
|
|
|
|
18
|
|
4
|
5
|
|
|
5
|
|
27
|
use strict; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
102
|
|
5
|
5
|
|
|
5
|
|
23
|
use warnings; |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
3764
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
# ROMAN NUMERALS |
8
|
|
|
|
|
|
|
|
9
|
20
|
|
|
20
|
0
|
43
|
sub inv($@) { my ($k, %inv)=shift; for(0..$#_) {$inv{$_[$_]}=$_*$k} %inv } |
|
20
|
|
|
|
|
53
|
|
|
170
|
|
|
|
|
340
|
|
|
20
|
|
|
|
|
153
|
|
10
|
|
|
|
|
|
|
my @unit= ( "" , qw ( I II III IV V VI VII VIII IX )); |
11
|
|
|
|
|
|
|
my @ten = ( "" , qw ( X XX XXX XL L LX LXX LXXX XC )); |
12
|
|
|
|
|
|
|
my @hund= ( "" , qw ( C CC CCC CD D DC DCC DCCC CM )); |
13
|
|
|
|
|
|
|
my @thou= ( "" , qw ( M MM MMM )); |
14
|
|
|
|
|
|
|
my %rval= (inv(1,@unit),inv(10,@ten),inv(100,@hund),inv(1000,@thou)); |
15
|
|
|
|
|
|
|
my $rbpat= join ")(",join("|",reverse @thou), join("|",reverse @hund), join("|",reverse @ten), join("|",reverse @unit); |
16
|
|
|
|
|
|
|
my $rpat= join ")(?:",join("|",reverse @thou), join("|",reverse @hund), join("|",reverse @ten), join("|",reverse @unit); |
17
|
|
|
|
|
|
|
my $rom = qq/(?:(?=[MDCLXVI])(?:$rpat))/; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $abbrev = join '|', qw{ etc[.] pp[.] ph[.]?d[.] }, |
20
|
|
|
|
|
|
|
"(?!$rom)(?:[A-Z][A-Za-z]+[.])+", |
21
|
|
|
|
|
|
|
'(?:[A-Z][.])(?:[A-Z][.])+'; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub fromRoman($) |
24
|
|
|
|
|
|
|
{ |
25
|
3
|
50
|
|
3
|
0
|
95
|
return 0 unless $_[0] =~ /^.*?($rbpat).*$/i; |
26
|
3
|
|
|
|
|
27
|
return $rval{uc $1} + $rval{uc $2} + $rval{uc $3} + $rval{uc $4}; |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub toRoman($$) |
30
|
|
|
|
|
|
|
{ |
31
|
0
|
|
|
0
|
0
|
0
|
my ($num,$example) = @_; |
32
|
0
|
0
|
|
|
|
0
|
return '' unless $num =~ /^([0-3]??)(\d??)(\d??)(\d)$/; |
33
|
0
|
|
0
|
|
|
0
|
my $roman = $thou[$1||0] . $hund[$2||0] . $ten[$3||0] . $unit[$4||0]; |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
34
|
0
|
0
|
|
|
|
0
|
return $example=~/[A-Z]/ ? uc $roman : lc $roman; |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# BITS OF A NUMERIC VALUE |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
my $num = q/(?:[0-9]{1,3}\b(?!:[0-9][0-9]\b))/; # Ignore 8:20 etc. |
40
|
|
|
|
|
|
|
my $let = q/[A-Za-z]/; |
41
|
|
|
|
|
|
|
my $pbr = q/[[(<]/; |
42
|
|
|
|
|
|
|
my $sbr = q/])>/; |
43
|
|
|
|
|
|
|
my $ows = q/[ \t]*/; |
44
|
|
|
|
|
|
|
my %close = ( '[' => ']', '(' => ')', '<' => '>', "" => '' ); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
my $hangPS = qq{(?i:ps:|(?:p\\.?)+s\\b\\.?(?:[ \\t]*:)?)}; |
47
|
|
|
|
|
|
|
my $hangNB = qq{(?i:n\\.?b\\.?(?:[ \\t]*:)?)}; |
48
|
|
|
|
|
|
|
my $hangword = qq{(?:(?:Note)[ \\t]*:)}; |
49
|
|
|
|
|
|
|
my $hangbullet = qq{[*.+-]}; |
50
|
|
|
|
|
|
|
my $hang = qq{(?:(?i)(?:$hangNB|$hangword|$hangbullet)(?=[ \t]))}; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# IMPLEMENTATION |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
sub new { |
55
|
30
|
|
|
30
|
0
|
74
|
my ($class, $orig, $lists_mode) = @_; |
56
|
30
|
50
|
|
|
|
63
|
return Text::Autoformat::NullHang->new() if !$lists_mode; |
57
|
|
|
|
|
|
|
|
58
|
30
|
|
|
|
|
49
|
my $origlen = length $orig; |
59
|
30
|
|
|
|
|
44
|
my @vals; |
60
|
30
|
50
|
66
|
|
|
400
|
if ($_[1] =~ s#\A($hangPS)##) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
61
|
0
|
|
|
|
|
0
|
@vals = { type => 'ps', val => $1 } |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
elsif ($lists_mode =~ /1|bullet/i && $_[1] =~ s#\A($hang)##) { |
64
|
0
|
|
|
|
|
0
|
@vals = { type => 'bul', val => $1 } |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
elsif ($_[1] =~ m#\A\([^\s)]+\s#) { |
67
|
0
|
|
|
|
|
0
|
@vals = (); |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
else { |
70
|
5
|
|
|
5
|
|
39
|
no warnings "all"; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
2917
|
|
71
|
30
|
|
|
|
|
6692
|
my $cut; |
72
|
30
|
|
|
|
|
68
|
while (length $_[1]) { |
73
|
31
|
0
|
0
|
|
|
418
|
last if $_[1] =~ m#\A($ows)($abbrev)# |
|
|
|
33
|
|
|
|
|
74
|
|
|
|
|
|
|
&& (length $1 || !@vals); # ws-separated or first |
75
|
|
|
|
|
|
|
|
76
|
31
|
50
|
|
|
|
196
|
last if $_[1] =~ m{\A $ows $pbr [^$sbr \t]* \s}xms; |
77
|
|
|
|
|
|
|
|
78
|
31
|
|
|
|
|
50
|
$cut = $origlen - length $_[1]; |
79
|
31
|
50
|
|
|
|
159
|
my $pre = $_[1] =~ s#\A($ows$pbr$ows)## ? $1 : ""; |
80
|
31
|
50
|
66
|
|
|
560
|
my $val |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
81
|
|
|
|
|
|
|
= ($lists_mode =~ /1|number/i && $_[1] =~ s#\A($num)##) |
82
|
|
|
|
|
|
|
? { type=>'num', val=>$1 } |
83
|
|
|
|
|
|
|
: ($lists_mode =~ /1|roman/i && $_[1] =~ s#\A($rom)\b##i) |
84
|
|
|
|
|
|
|
? { type=>'rom', val=>$1, nval=>fromRoman($1) } |
85
|
|
|
|
|
|
|
: ($lists_mode =~ /1|alpha/i && $_[1] =~ s#\A($let(?!$let))##i) |
86
|
|
|
|
|
|
|
? { type=>'let', val=>$1 } |
87
|
|
|
|
|
|
|
: { val => "", type => "" }; |
88
|
31
|
100
|
50
|
|
|
164
|
$_[1] = $pre.$_[1] and last unless length $val->{val}; |
89
|
6
|
|
100
|
|
|
106
|
$val->{post} = $pre && $_[1] =~ s#\A($ows()[.:/]?[$close{$pre}][.:/]?)## && $1 |
90
|
|
|
|
|
|
|
|| $_[1] =~ s#\A($ows()[$sbr.:/])## && $1 |
91
|
|
|
|
|
|
|
|| ""; |
92
|
6
|
|
|
|
|
16
|
$val->{pre} = $pre; |
93
|
6
|
|
|
|
|
10
|
$val->{cut} = $cut; |
94
|
6
|
|
|
|
|
22
|
push @vals, $val; |
95
|
|
|
|
|
|
|
} |
96
|
30
|
|
100
|
|
|
96
|
while (@vals && !$vals[-1]{post}) { |
97
|
2
|
|
|
|
|
13
|
$_[1] = substr($orig,pop(@vals)->{cut}); |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# check for orphaned years or unlikely Roman numerals... |
102
|
30
|
50
|
66
|
|
|
97
|
if (@vals==1 && defined $vals[0]->{post} && $vals[0]->{post} =~ /[\.>)]/) { |
|
|
|
66
|
|
|
|
|
103
|
4
|
|
|
|
|
8
|
my $v = $vals[0]; |
104
|
4
|
50
|
33
|
|
|
20
|
if ($v->{type} eq 'num' && $v->{val} >= 1000) { |
105
|
0
|
|
|
|
|
0
|
$_[1] = substr($orig,pop(@vals)->{cut}); |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
30
|
100
|
|
|
|
102
|
return Text::Autoformat::NullHang->new if !@vals; |
110
|
4
|
|
|
|
|
18
|
bless \@vals, $class; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub incr { |
114
|
5
|
|
|
5
|
|
48
|
no warnings "all"; |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
2120
|
|
115
|
4
|
|
|
4
|
0
|
12
|
my ($self, $prev, $prevsig) = @_; |
116
|
4
|
|
|
|
|
7
|
my $level; |
117
|
|
|
|
|
|
|
# check compatibility |
118
|
|
|
|
|
|
|
|
119
|
4
|
100
|
66
|
|
|
15
|
return unless $prev && !$prev->empty; |
120
|
|
|
|
|
|
|
|
121
|
2
|
50
|
|
|
|
10
|
for $level (0..(@$self<@$prev ? $#$self : $#$prev)) { |
122
|
2
|
50
|
|
|
|
7
|
if ($self->[$level]{type} ne $prev->[$level]{type}) { |
123
|
0
|
0
|
|
|
|
0
|
return if @$self<=@$prev; # no incr if going up |
124
|
0
|
|
|
|
|
0
|
$prev = $prevsig; |
125
|
0
|
|
|
|
|
0
|
last; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
} |
128
|
2
|
50
|
33
|
|
|
8
|
return unless $prev && !$prev->empty; |
129
|
2
|
50
|
|
|
|
11
|
if ($self->[0]{type} eq 'ps') { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
130
|
0
|
|
|
|
|
0
|
my $count = 1 + $prev->[0]{val} =~ s/(p[.]?)/$1/gi; |
131
|
0
|
|
|
|
|
0
|
$prev->[0]{val} =~ /^(p[.]?).*(s[.]?[:]?)/; |
132
|
0
|
|
|
|
|
0
|
$self->[0]{val} = $1 x $count . $2; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
elsif ($self->[0]{type} eq 'bul') { |
135
|
|
|
|
|
|
|
# do nothing |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
elsif (@$self>@$prev) { # going down level(s) |
138
|
0
|
|
|
|
|
0
|
for $level (0..$#$prev) { |
139
|
0
|
|
|
|
|
0
|
@{$self->[$level]}{'val','nval'} = @{$prev->[$level]}{'val','nval'}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
140
|
|
|
|
|
|
|
} |
141
|
0
|
|
|
|
|
0
|
for $level (@$prev..$#$self) { |
142
|
0
|
|
|
|
|
0
|
_reset($self->[$level]); |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
else # same level or going up |
146
|
|
|
|
|
|
|
{ |
147
|
2
|
|
|
|
|
6
|
for $level (0..$#$self) { |
148
|
2
|
|
|
|
|
3
|
@{$self->[$level]}{'val','nval'} = @{$prev->[$level]}{'val','nval'}; |
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
6
|
|
149
|
|
|
|
|
|
|
} |
150
|
2
|
|
|
|
|
7
|
_incr($self->[-1]) |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
sub _incr { |
155
|
5
|
|
|
5
|
|
37
|
no warnings "all"; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
754
|
|
156
|
2
|
50
|
|
2
|
|
6
|
if ($_[0]{type} eq 'rom') { |
157
|
0
|
|
|
|
|
0
|
$_[0]{val} = toRoman(++$_[0]{nval},$_[0]{val}); |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
else { |
160
|
2
|
50
|
33
|
|
|
12
|
$_[0]{val}++ unless $_[0]{type} eq 'let' && $_[0]{val}=~/Z/i; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub _reset { |
165
|
5
|
|
|
5
|
|
35
|
no warnings "all"; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
959
|
|
166
|
0
|
0
|
|
0
|
|
0
|
if ($_[0]{type} eq 'rom') { |
|
|
0
|
|
|
|
|
|
167
|
0
|
|
|
|
|
0
|
$_[0]{val} = toRoman($_[0]{nval}=1,$_[0]{val}); |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
elsif ($_[0]{type} eq 'let') { |
170
|
0
|
0
|
|
|
|
0
|
$_[0]{val} = $_[0]{val} =~ /[A-Z]/ ? 'A' : 'a'; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
else { |
173
|
0
|
|
|
|
|
0
|
$_[0]{val} = 1; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub stringify { |
178
|
8
|
|
|
8
|
0
|
14
|
my ($self) = @_; |
179
|
8
|
|
|
|
|
15
|
my ($str, $level) = (""); |
180
|
8
|
|
|
|
|
15
|
for $level (@$self) { |
181
|
5
|
|
|
5
|
|
33
|
no warnings "all"; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
1081
|
|
182
|
8
|
|
|
|
|
13
|
$str .= join "", @{$level}{'pre','val','post'}; |
|
8
|
|
|
|
|
24
|
|
183
|
|
|
|
|
|
|
} |
184
|
8
|
|
|
|
|
24
|
return $str; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub val { |
188
|
0
|
|
|
0
|
0
|
0
|
my ($self, $i) = @_; |
189
|
0
|
|
|
|
|
0
|
return $self->[$i]{val}; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
2
|
|
|
2
|
0
|
6
|
sub fields { return scalar @{$_[0]} } |
|
2
|
|
|
|
|
10
|
|
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub field { |
195
|
0
|
|
|
0
|
0
|
0
|
my ($self, $i, $newval) = @_; |
196
|
0
|
0
|
|
|
|
0
|
$self->[$i]{type} = $newval if @_>2; |
197
|
0
|
|
|
|
|
0
|
return $self->[$i]{type}; |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub signature { |
201
|
5
|
|
|
5
|
|
34
|
no warnings "all"; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
1420
|
|
202
|
8
|
|
|
8
|
0
|
14
|
my ($self) = @_; |
203
|
8
|
|
|
|
|
16
|
my ($str, $level) = (""); |
204
|
8
|
|
|
|
|
13
|
for $level (@$self) { |
205
|
8
|
|
50
|
|
|
18
|
$level->{type} ||= ""; |
206
|
|
|
|
|
|
|
$str .= join "", $level->{pre}, |
207
|
|
|
|
|
|
|
($level->{type} =~ /rom|let/ ? "romlet" : $level->{type}), |
208
|
8
|
50
|
|
|
|
51
|
$level->{post}; |
209
|
|
|
|
|
|
|
} |
210
|
8
|
|
|
|
|
26
|
return $str; |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub length { |
214
|
4
|
|
|
4
|
0
|
15
|
length $_[0]->stringify |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
14
|
|
|
14
|
0
|
45
|
sub empty { 0 } |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
1; |
220
|
|
|
|
|
|
|
|