1 2package Text::Tabs; 3 4require Exporter; 5 6@ISA = (Exporter); 7@EXPORT = qw(expand unexpand $tabstop); 8 9use vars qw($VERSION $SUBVERSION $tabstop $debug); 10$VERSION = 2012.0818; 11$SUBVERSION = 'modern'; 12 13use strict; 14 15use 5.010_000; 16 17BEGIN { 18 $tabstop = 8; 19 $debug = 0; 20} 21 22my $CHUNK = qr/\X/; 23 24sub _xlen (_) { scalar(() = $_[0] =~ /$CHUNK/g) } 25sub _xpos (_) { _xlen( substr( $_[0], 0, pos($_[0]) ) ) } 26 27sub expand { 28 my @l; 29 my $pad; 30 for ( @_ ) { 31 my $s = ''; 32 for (split(/^/m, $_, -1)) { 33 my $offs = 0; 34 s{\t}{ 35 # this works on both 5.10 and 5.11 36 $pad = $tabstop - (_xlen(${^PREMATCH}) + $offs) % $tabstop; 37 # this works on 5.11, but fails on 5.10 38 #XXX# $pad = $tabstop - (_xpos() + $offs) % $tabstop; 39 $offs += $pad - 1; 40 " " x $pad; 41 }peg; 42 $s .= $_; 43 } 44 push(@l, $s); 45 } 46 return @l if wantarray; 47 return $l[0]; 48} 49 50sub unexpand 51{ 52 my (@l) = @_; 53 my @e; 54 my $x; 55 my $line; 56 my @lines; 57 my $lastbit; 58 my $ts_as_space = " " x $tabstop; 59 for $x (@l) { 60 @lines = split("\n", $x, -1); 61 for $line (@lines) { 62 $line = expand($line); 63 @e = split(/(${CHUNK}{$tabstop})/,$line,-1); 64 $lastbit = pop(@e); 65 $lastbit = '' 66 unless defined $lastbit; 67 $lastbit = "\t" 68 if $lastbit eq $ts_as_space; 69 for $_ (@e) { 70 if ($debug) { 71 my $x = $_; 72 $x =~ s/\t/^I\t/gs; 73 print "sub on '$x'\n"; 74 } 75 s/ +$/\t/; 76 } 77 $line = join('',@e, $lastbit); 78 } 79 $x = join("\n", @lines); 80 } 81 return @l if wantarray; 82 return $l[0]; 83} 84 851; 86__END__ 87 88sub expand 89{ 90 my (@l) = @_; 91 for $_ (@l) { 92 1 while s/(^|\n)([^\t\n]*)(\t+)/ 93 $1. $2 . (" " x 94 ($tabstop * length($3) 95 - (length($2) % $tabstop))) 96 /sex; 97 } 98 return @l if wantarray; 99 return $l[0]; 100} 101 102 103=head1 NAME 104 105Text::Tabs - expand and unexpand tabs like unix expand(1) and unexpand(1) 106 107=head1 SYNOPSIS 108 109 use Text::Tabs; 110 111 $tabstop = 4; # default = 8 112 @lines_without_tabs = expand(@lines_with_tabs); 113 @lines_with_tabs = unexpand(@lines_without_tabs); 114 115=head1 DESCRIPTION 116 117Text::Tabs does most of what the unix utilities expand(1) and unexpand(1) 118do. Given a line with tabs in it, C<expand> replaces those tabs with 119the appropriate number of spaces. Given a line with or without tabs in 120it, C<unexpand> adds tabs when it can save bytes by doing so, 121like the C<unexpand -a> command. 122 123Unlike the old unix utilities, this module correctly accounts for 124any Unicode combining characters (such as diacriticals) that may occur 125in each line for both expansion and unexpansion. These are overstrike 126characters that do not increment the logical position. Make sure 127you have the appropriate Unicode settings enabled. 128 129=head1 EXPORTS 130 131The following are exported: 132 133=over 4 134 135=item expand 136 137=item unexpand 138 139=item $tabstop 140 141The C<$tabstop> variable controls how many column positions apart each 142tabstop is. The default is 8. 143 144Please note that C<local($tabstop)> doesn't do the right thing and if you want 145to use C<local> to override C<$tabstop>, you need to use 146C<local($Text::Tabs::tabstop)>. 147 148=back 149 150=head1 EXAMPLE 151 152 #!perl 153 # unexpand -a 154 use Text::Tabs; 155 156 while (<>) { 157 print unexpand $_; 158 } 159 160Instead of the shell's C<expand> comand, use: 161 162 perl -MText::Tabs -n -e 'print expand $_' 163 164Instead of the shell's C<unexpand -a> command, use: 165 166 perl -MText::Tabs -n -e 'print unexpand $_' 167 168=head1 SUBVERSION 169 170This module comes in two flavors: one for modern perls (5.10 and above) 171and one for ancient obsolete perls. The version for modern perls has 172support for Unicode. The version for old perls does not. You can tell 173which version you have installed by looking at C<$Text::Tabs::SUBVERSION>: 174it is C<old> for obsolete perls and C<modern> for current perls. 175 176This man page is for the version for modern perls and so that's probably 177what you've got. 178 179=head1 BUGS 180 181Text::Tabs handles only tabs (C<"\t">) and combining characters (C</\pM/>). It doesn't 182count backwards for backspaces (C<"\t">), omit other non-printing control characters (C</\pC/>), 183or otherwise deal with any other zero-, half-, and full-width characters. 184 185=head1 LICENSE 186 187Copyright (C) 1996-2002,2005,2006 David Muir Sharnoff. 188Copyright (C) 2005 Aristotle Pagaltzis 189Copyright (C) 2012 Google, Inc. 190This module may be modified, used, copied, and redistributed at your own risk. 191Publicly redistributed modified versions must use a different name. 192 193