| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#!/usr/bin/perl |
|
2
|
|
|
|
|
|
|
# vim:ts=4:sw=4 |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Text::Flowed; |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
$VERSION = '0.14'; |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
require Exporter; |
|
9
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
|
10
|
|
|
|
|
|
|
@EXPORT = qw(); |
|
11
|
|
|
|
|
|
|
@EXPORT_OK = qw(reformat quote quote_fixed); |
|
12
|
|
|
|
|
|
|
|
|
13
|
2
|
|
|
2
|
|
139106
|
use strict; |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
66
|
|
|
14
|
2
|
|
|
2
|
|
10
|
use vars qw($MAX_LENGTH $OPT_LENGTH); |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
1892
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# MAX_LENGTH: This is the maximum length that a line is allowed to be |
|
17
|
|
|
|
|
|
|
# (unless faced with a word that is unreasonably long). This module will |
|
18
|
|
|
|
|
|
|
# re-wrap a line if it exceeds this length. |
|
19
|
|
|
|
|
|
|
$MAX_LENGTH = 79; |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# OPT_LENGTH: When this module wraps a line, the newly created lines |
|
22
|
|
|
|
|
|
|
# will be split at this length. |
|
23
|
|
|
|
|
|
|
$OPT_LENGTH = 72; |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# reformat($text, [\%args]) |
|
26
|
|
|
|
|
|
|
# Reformats $text, where $text is format=flowed plain text as described |
|
27
|
|
|
|
|
|
|
# in RFC 2646. |
|
28
|
|
|
|
|
|
|
# |
|
29
|
|
|
|
|
|
|
# $args->{quote}: Add a level of quoting to the beginning of each line. |
|
30
|
|
|
|
|
|
|
# $args->{fixed}: Interpret unquoted/all lines as format=fixed. |
|
31
|
|
|
|
|
|
|
# $args->{max_length}: The maximum length of any line. |
|
32
|
|
|
|
|
|
|
# $args->{opt_length}: The maximum length of wrapped lines. |
|
33
|
|
|
|
|
|
|
sub reformat { |
|
34
|
3
|
|
|
3
|
1
|
18
|
my @input = split("\n", $_[0]); |
|
35
|
3
|
|
|
|
|
5
|
my $args = $_[1]; |
|
36
|
3
|
|
33
|
|
|
17
|
$args->{max_length} ||= $MAX_LENGTH; |
|
37
|
3
|
|
33
|
|
|
13
|
$args->{opt_length} ||= $OPT_LENGTH; |
|
38
|
3
|
|
|
|
|
4
|
my @output = (); |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# Process message line by line |
|
41
|
3
|
|
|
|
|
8
|
while (@input) { |
|
42
|
|
|
|
|
|
|
# Count and strip quote levels |
|
43
|
3
|
|
|
|
|
8
|
my $line = shift(@input); |
|
44
|
3
|
|
|
|
|
6
|
my $num_quotes = _num_quotes($line); |
|
45
|
3
|
|
|
|
|
7
|
$line = _unquote($line); |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
# Should we interpret this line as flowed? |
|
48
|
3
|
50
|
33
|
|
|
20
|
if (!$args->{fixed} || |
|
|
|
|
66
|
|
|
|
|
|
49
|
|
|
|
|
|
|
($args->{fixed} == 1 && $num_quotes)) { |
|
50
|
3
|
|
|
|
|
9
|
$line = _unstuff($line); |
|
51
|
|
|
|
|
|
|
# While line is flowed, and there is a next line, and the |
|
52
|
|
|
|
|
|
|
# next line has the same quote depth |
|
53
|
3
|
|
66
|
|
|
9
|
while (_flowed($line) && @input && |
|
|
|
|
66
|
|
|
|
|
|
54
|
|
|
|
|
|
|
_num_quotes($input[0]) == $num_quotes) { |
|
55
|
|
|
|
|
|
|
# Join the next line |
|
56
|
1
|
|
|
|
|
4
|
$line .= _unstuff(_unquote(shift(@input))); |
|
57
|
|
|
|
|
|
|
} |
|
58
|
|
|
|
|
|
|
} |
|
59
|
|
|
|
|
|
|
# Ensure line is fixed, since we joined all flowed lines |
|
60
|
3
|
|
|
|
|
9
|
$line = _trim($line); |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# Increment quote depth if we're quoting |
|
63
|
3
|
100
|
|
|
|
10
|
$num_quotes++ if $args->{quote}; |
|
64
|
|
|
|
|
|
|
|
|
65
|
3
|
50
|
|
|
|
13
|
if (!$line) { |
|
|
|
50
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# Line is empty |
|
67
|
0
|
|
|
|
|
0
|
push(@output, '>' x $num_quotes); |
|
68
|
|
|
|
|
|
|
} elsif (length($line) + $num_quotes <= $args->{max_length} - 1) { |
|
69
|
|
|
|
|
|
|
# Line does not require rewrapping |
|
70
|
3
|
|
|
|
|
11
|
push(@output, '>' x $num_quotes . _stuff($line, $num_quotes)); |
|
71
|
|
|
|
|
|
|
} else { |
|
72
|
|
|
|
|
|
|
# Rewrap this paragraph |
|
73
|
0
|
|
|
|
|
0
|
while ($line) { |
|
74
|
|
|
|
|
|
|
# Stuff and re-quote the line |
|
75
|
0
|
|
|
|
|
0
|
$line = '>' x $num_quotes . _stuff($line, $num_quotes); |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# Set variables used in regexps |
|
78
|
0
|
|
|
|
|
0
|
my $min = $num_quotes + 1; |
|
79
|
0
|
|
|
|
|
0
|
my $opt1 = $args->{opt_length} - 1; |
|
80
|
0
|
|
|
|
|
0
|
my $max1 = $args->{max_length} - 1; |
|
81
|
0
|
0
|
0
|
|
|
0
|
if (length($line) <= $args->{opt_length}) { |
|
|
|
0
|
0
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# Remaining section of line is short enough |
|
83
|
0
|
|
|
|
|
0
|
push(@output, $line); |
|
84
|
0
|
|
|
|
|
0
|
last; |
|
85
|
|
|
|
|
|
|
} elsif ($line =~ /^(.{$min,$opt1}) (.*)/ || |
|
86
|
|
|
|
|
|
|
$line =~ /^(.{$min,$max1}) (.*)/ || |
|
87
|
|
|
|
|
|
|
$line =~ /^(.{$min,})? (.*)/) { |
|
88
|
|
|
|
|
|
|
# 1. Try to find a string as long as opt_length. |
|
89
|
|
|
|
|
|
|
# 2. Try to find a string as long as max_length. |
|
90
|
|
|
|
|
|
|
# 3. Take the first word. |
|
91
|
0
|
|
|
|
|
0
|
push(@output, "$1 "); |
|
92
|
0
|
|
|
|
|
0
|
$line = $2; |
|
93
|
|
|
|
|
|
|
} else { |
|
94
|
|
|
|
|
|
|
# One excessively long word left on line |
|
95
|
0
|
|
|
|
|
0
|
push(@output, $line); |
|
96
|
0
|
|
|
|
|
0
|
last; |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
} |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
|
|
102
|
3
|
|
|
|
|
23
|
return join("\n", @output)."\n"; |
|
103
|
|
|
|
|
|
|
} |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# quote() |
|
106
|
|
|
|
|
|
|
# A convenience wrapper for reformat(, {quote => 1}). |
|
107
|
|
|
|
|
|
|
sub quote { |
|
108
|
0
|
|
|
0
|
1
|
0
|
return reformat($_[0], {quote => 1}); |
|
109
|
|
|
|
|
|
|
} |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# quote_fixed() |
|
112
|
|
|
|
|
|
|
# A convenience wrapper for reformat(, {quote => 1, fixed => 1}). |
|
113
|
|
|
|
|
|
|
sub quote_fixed { |
|
114
|
1
|
|
|
1
|
1
|
7
|
return reformat($_[0], {quote => 1, fixed => 1}); |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# _num_quotes() |
|
118
|
|
|
|
|
|
|
# Returns the number of leading '>' characters in . |
|
119
|
|
|
|
|
|
|
sub _num_quotes { |
|
120
|
8
|
|
|
8
|
|
31
|
$_[0] =~ /^(>*)/; |
|
121
|
8
|
|
|
|
|
38
|
return length($1); |
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# _unquote() |
|
125
|
|
|
|
|
|
|
# Removes all leading '>' characters from . |
|
126
|
|
|
|
|
|
|
sub _unquote { |
|
127
|
8
|
|
|
8
|
|
14
|
my $line = shift; |
|
128
|
8
|
|
|
|
|
21
|
$line =~ s/^(>+)//g; |
|
129
|
8
|
|
|
|
|
23
|
return $line; |
|
130
|
|
|
|
|
|
|
} |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# _flowed() |
|
133
|
|
|
|
|
|
|
# Returns 1 if is flowed; 0 otherwise. |
|
134
|
|
|
|
|
|
|
sub _flowed { |
|
135
|
6
|
|
|
6
|
|
7
|
my $line = shift; |
|
136
|
|
|
|
|
|
|
# Lines with only spaces in them are not considered flowed |
|
137
|
|
|
|
|
|
|
# (heuristic to recover from sloppy user input) |
|
138
|
6
|
50
|
|
|
|
25
|
return 0 if $line =~ /^ *$/; |
|
139
|
6
|
|
|
|
|
62
|
return $line =~ / $/; |
|
140
|
|
|
|
|
|
|
} |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# _trim() |
|
143
|
|
|
|
|
|
|
# Removes all trailing ' ' characters from . |
|
144
|
|
|
|
|
|
|
sub _trim { |
|
145
|
5
|
|
|
5
|
|
9
|
$_ = shift; |
|
146
|
5
|
|
|
|
|
13
|
$_ =~ s/ +$//g; |
|
147
|
5
|
|
|
|
|
24
|
return $_; |
|
148
|
|
|
|
|
|
|
} |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# _stuff(, ) |
|
151
|
|
|
|
|
|
|
# Space-stuffs if it starts with " " or ">" or "From ", or if |
|
152
|
|
|
|
|
|
|
# quote depth is non-zero (for aesthetic reasons so that there is a |
|
153
|
|
|
|
|
|
|
# space after the ">"). |
|
154
|
|
|
|
|
|
|
sub _stuff { |
|
155
|
6
|
|
|
6
|
|
12
|
my ($text, $num_quotes) = @_; |
|
156
|
6
|
100
|
33
|
|
|
67
|
if ($text =~ /^ / || $text =~ /^>/ || $text =~ /^From / || |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
157
|
|
|
|
|
|
|
$num_quotes > 0) { |
|
158
|
3
|
|
|
|
|
15
|
return " $text"; |
|
159
|
|
|
|
|
|
|
} |
|
160
|
3
|
|
|
|
|
14
|
return $text; |
|
161
|
|
|
|
|
|
|
} |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# _unstuff() |
|
164
|
|
|
|
|
|
|
# If starts with a space, remove it. |
|
165
|
|
|
|
|
|
|
sub _unstuff { |
|
166
|
6
|
|
|
6
|
|
9
|
$_ = shift; |
|
167
|
6
|
|
|
|
|
20
|
$_ =~ s/^ //; |
|
168
|
6
|
|
|
|
|
16
|
return $_; |
|
169
|
|
|
|
|
|
|
} |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
1; |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
__END__ |