1*0Sstevel@tonic-gatepackage Text::Wrap; 2*0Sstevel@tonic-gate 3*0Sstevel@tonic-gaterequire Exporter; 4*0Sstevel@tonic-gate 5*0Sstevel@tonic-gate@ISA = qw(Exporter); 6*0Sstevel@tonic-gate@EXPORT = qw(wrap fill); 7*0Sstevel@tonic-gate@EXPORT_OK = qw($columns $break $huge); 8*0Sstevel@tonic-gate 9*0Sstevel@tonic-gate$VERSION = 2001.09291; 10*0Sstevel@tonic-gate 11*0Sstevel@tonic-gateuse vars qw($VERSION $columns $debug $break $huge $unexpand $tabstop 12*0Sstevel@tonic-gate $separator); 13*0Sstevel@tonic-gateuse strict; 14*0Sstevel@tonic-gate 15*0Sstevel@tonic-gateBEGIN { 16*0Sstevel@tonic-gate $columns = 76; # <= screen width 17*0Sstevel@tonic-gate $debug = 0; 18*0Sstevel@tonic-gate $break = '\s'; 19*0Sstevel@tonic-gate $huge = 'wrap'; # alternatively: 'die' or 'overflow' 20*0Sstevel@tonic-gate $unexpand = 1; 21*0Sstevel@tonic-gate $tabstop = 8; 22*0Sstevel@tonic-gate $separator = "\n"; 23*0Sstevel@tonic-gate} 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gateuse Text::Tabs qw(expand unexpand); 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gatesub wrap 28*0Sstevel@tonic-gate{ 29*0Sstevel@tonic-gate my ($ip, $xp, @t) = @_; 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate local($Text::Tabs::tabstop) = $tabstop; 32*0Sstevel@tonic-gate my $r = ""; 33*0Sstevel@tonic-gate my $tail = pop(@t); 34*0Sstevel@tonic-gate my $t = expand(join("", (map { /\s+\z/ ? ( $_ ) : ($_, ' ') } @t), $tail)); 35*0Sstevel@tonic-gate my $lead = $ip; 36*0Sstevel@tonic-gate my $ll = $columns - length(expand($ip)) - 1; 37*0Sstevel@tonic-gate $ll = 0 if $ll < 0; 38*0Sstevel@tonic-gate my $nll = $columns - length(expand($xp)) - 1; 39*0Sstevel@tonic-gate my $nl = ""; 40*0Sstevel@tonic-gate my $remainder = ""; 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate use re 'taint'; 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate pos($t) = 0; 45*0Sstevel@tonic-gate while ($t !~ /\G\s*\Z/gc) { 46*0Sstevel@tonic-gate if ($t =~ /\G([^\n]{0,$ll})($break|\z)/xmgc) { 47*0Sstevel@tonic-gate $r .= $unexpand 48*0Sstevel@tonic-gate ? unexpand($nl . $lead . $1) 49*0Sstevel@tonic-gate : $nl . $lead . $1; 50*0Sstevel@tonic-gate $remainder = $2; 51*0Sstevel@tonic-gate } elsif ($huge eq 'wrap' && $t =~ /\G([^\n]{$ll})/gc) { 52*0Sstevel@tonic-gate $r .= $unexpand 53*0Sstevel@tonic-gate ? unexpand($nl . $lead . $1) 54*0Sstevel@tonic-gate : $nl . $lead . $1; 55*0Sstevel@tonic-gate $remainder = $separator; 56*0Sstevel@tonic-gate } elsif ($huge eq 'overflow' && $t =~ /\G([^\n]*?)($break|\z)/xmgc) { 57*0Sstevel@tonic-gate $r .= $unexpand 58*0Sstevel@tonic-gate ? unexpand($nl . $lead . $1) 59*0Sstevel@tonic-gate : $nl . $lead . $1; 60*0Sstevel@tonic-gate $remainder = $2; 61*0Sstevel@tonic-gate } elsif ($huge eq 'die') { 62*0Sstevel@tonic-gate die "couldn't wrap '$t'"; 63*0Sstevel@tonic-gate } else { 64*0Sstevel@tonic-gate die "This shouldn't happen"; 65*0Sstevel@tonic-gate } 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate $lead = $xp; 68*0Sstevel@tonic-gate $ll = $nll; 69*0Sstevel@tonic-gate $nl = $separator; 70*0Sstevel@tonic-gate } 71*0Sstevel@tonic-gate $r .= $remainder; 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate print "-----------$r---------\n" if $debug; 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate print "Finish up with '$lead'\n" if $debug; 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate $r .= $lead . substr($t, pos($t), length($t)-pos($t)) 78*0Sstevel@tonic-gate if pos($t) ne length($t); 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate print "-----------$r---------\n" if $debug;; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate return $r; 83*0Sstevel@tonic-gate} 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gatesub fill 86*0Sstevel@tonic-gate{ 87*0Sstevel@tonic-gate my ($ip, $xp, @raw) = @_; 88*0Sstevel@tonic-gate my @para; 89*0Sstevel@tonic-gate my $pp; 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate for $pp (split(/\n\s+/, join("\n",@raw))) { 92*0Sstevel@tonic-gate $pp =~ s/\s+/ /g; 93*0Sstevel@tonic-gate my $x = wrap($ip, $xp, $pp); 94*0Sstevel@tonic-gate push(@para, $x); 95*0Sstevel@tonic-gate } 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate # if paragraph_indent is the same as line_indent, 98*0Sstevel@tonic-gate # separate paragraphs with blank lines 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate my $ps = ($ip eq $xp) ? "\n\n" : "\n"; 101*0Sstevel@tonic-gate return join ($ps, @para); 102*0Sstevel@tonic-gate} 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate1; 105*0Sstevel@tonic-gate__END__ 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate=head1 NAME 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gateText::Wrap - line wrapping to form simple paragraphs 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate=head1 SYNOPSIS 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gateB<Example 1> 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate use Text::Wrap 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate $initial_tab = "\t"; # Tab before first line 118*0Sstevel@tonic-gate $subsequent_tab = ""; # All other lines flush left 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate print wrap($initial_tab, $subsequent_tab, @text); 121*0Sstevel@tonic-gate print fill($initial_tab, $subsequent_tab, @text); 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate @lines = wrap($initial_tab, $subsequent_tab, @text); 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate @paragraphs = fill($initial_tab, $subsequent_tab, @text); 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gateB<Example 2> 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate use Text::Wrap qw(wrap $columns $huge); 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate $columns = 132; # Wrap at 132 characters 132*0Sstevel@tonic-gate $huge = 'die'; 133*0Sstevel@tonic-gate $huge = 'wrap'; 134*0Sstevel@tonic-gate $huge = 'overflow'; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gateB<Example 3> 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate use Text::Wrap 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate $Text::Wrap::columns = 72; 141*0Sstevel@tonic-gate print wrap('', '', @text); 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate=head1 DESCRIPTION 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gateC<Text::Wrap::wrap()> is a very simple paragraph formatter. It formats a 146*0Sstevel@tonic-gatesingle paragraph at a time by breaking lines at word boundries. 147*0Sstevel@tonic-gateIndentation is controlled for the first line (C<$initial_tab>) and 148*0Sstevel@tonic-gateall subsequent lines (C<$subsequent_tab>) independently. Please note: 149*0Sstevel@tonic-gateC<$initial_tab> and C<$subsequent_tab> are the literal strings that will 150*0Sstevel@tonic-gatebe used: it is unlikley you would want to pass in a number. 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gateText::Wrap::fill() is a simple multi-paragraph formatter. It formats 153*0Sstevel@tonic-gateeach paragraph separately and then joins them together when it's done. It 154*0Sstevel@tonic-gatewill destory any whitespace in the original text. It breaks text into 155*0Sstevel@tonic-gateparagraphs by looking for whitespace after a newline. In other respects 156*0Sstevel@tonic-gateit acts like wrap(). 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate=head1 OVERRIDES 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gateC<Text::Wrap::wrap()> has a number of variables that control its behavior. 161*0Sstevel@tonic-gateBecause other modules might be using C<Text::Wrap::wrap()> it is suggested 162*0Sstevel@tonic-gatethat you leave these variables alone! If you can't do that, then 163*0Sstevel@tonic-gateuse C<local($Text::Wrap::VARIABLE) = YOURVALUE> when you change the 164*0Sstevel@tonic-gatevalues so that the original value is restored. This C<local()> trick 165*0Sstevel@tonic-gatewill not work if you import the variable into your own namespace. 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gateLines are wrapped at C<$Text::Wrap::columns> columns. C<$Text::Wrap::columns> 168*0Sstevel@tonic-gateshould be set to the full width of your output device. In fact, 169*0Sstevel@tonic-gateevery resulting line will have length of no more than C<$columns - 1>. 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gateIt is possible to control which characters terminate words by 172*0Sstevel@tonic-gatemodifying C<$Text::Wrap::break>. Set this to a string such as 173*0Sstevel@tonic-gateC<'[\s:]'> (to break before spaces or colons) or a pre-compiled regexp 174*0Sstevel@tonic-gatesuch as C<qr/[\s']/> (to break before spaces or apostrophes). The 175*0Sstevel@tonic-gatedefault is simply C<'\s'>; that is, words are terminated by spaces. 176*0Sstevel@tonic-gate(This means, among other things, that trailing punctuation such as 177*0Sstevel@tonic-gatefull stops or commas stay with the word they are "attached" to.) 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gateBeginner note: In example 2, above C<$columns> is imported into 180*0Sstevel@tonic-gatethe local namespace, and set locally. In example 3, 181*0Sstevel@tonic-gateC<$Text::Wrap::columns> is set in its own namespace without importing it. 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gateC<Text::Wrap::wrap()> starts its work by expanding all the tabs in its 184*0Sstevel@tonic-gateinput into spaces. The last thing it does it to turn spaces back 185*0Sstevel@tonic-gateinto tabs. If you do not want tabs in your results, set 186*0Sstevel@tonic-gateC<$Text::Wrap::unexapand> to a false value. Likewise if you do not 187*0Sstevel@tonic-gatewant to use 8-character tabstops, set C<$Text::Wrap::tabstop> to 188*0Sstevel@tonic-gatethe number of characters you do want for your tabstops. 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gateIf you want to separate your lines with something other than C<\n> 191*0Sstevel@tonic-gatethen set C<$Text::Wrap::seporator> to your preference. 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gateWhen words that are longer than C<$columns> are encountered, they 194*0Sstevel@tonic-gateare broken up. C<wrap()> adds a C<"\n"> at column C<$columns>. 195*0Sstevel@tonic-gateThis behavior can be overridden by setting C<$huge> to 196*0Sstevel@tonic-gate'die' or to 'overflow'. When set to 'die', large words will cause 197*0Sstevel@tonic-gateC<die()> to be called. When set to 'overflow', large words will be 198*0Sstevel@tonic-gateleft intact. 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gateHistorical notes: 'die' used to be the default value of 201*0Sstevel@tonic-gateC<$huge>. Now, 'wrap' is the default value. 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate=head1 EXAMPLE 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate print wrap("\t","","This is a bit of text that forms 206*0Sstevel@tonic-gate a normal book-style paragraph"); 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate=head1 AUTHOR 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gateDavid Muir Sharnoff <muir@idiom.com> with help from Tim Pierce and 211*0Sstevel@tonic-gatemany many others. 212*0Sstevel@tonic-gate 213