1eac174f2Safresh1use strict; use warnings; 2eac174f2Safresh1 3b39c5158Smillertpackage Text::Tabs; 4b39c5158Smillert 5eac174f2Safresh1BEGIN { require Exporter; *import = \&Exporter::import } 6b39c5158Smillert 7eac174f2Safresh1our @EXPORT = qw( expand unexpand $tabstop ); 8b39c5158Smillert 9*3d61058aSafresh1our $VERSION = '2024.001'; 10eac174f2Safresh1our $SUBVERSION = 'modern'; # back-compat vestige 11b39c5158Smillert 12eac174f2Safresh1our $tabstop = 8; 1391f110e0Safresh1 14b39c5158Smillertsub expand { 15b39c5158Smillert my @l; 16b39c5158Smillert my $pad; 17b39c5158Smillert for ( @_ ) { 18eac174f2Safresh1 defined or do { push @l, ''; next }; 19b39c5158Smillert my $s = ''; 20b39c5158Smillert for (split(/^/m, $_, -1)) { 21eac174f2Safresh1 my $offs; 22eac174f2Safresh1 for (split(/\t/, $_, -1)) { 23eac174f2Safresh1 if (defined $offs) { 24eac174f2Safresh1 $pad = $tabstop - $offs % $tabstop; 25eac174f2Safresh1 $s .= " " x $pad; 26eac174f2Safresh1 } 27b39c5158Smillert $s .= $_; 28*3d61058aSafresh1 $offs = /^\pM/ + ( () = /\PM/g ); 29eac174f2Safresh1 } 30b39c5158Smillert } 31b39c5158Smillert push(@l, $s); 32b39c5158Smillert } 33b39c5158Smillert return @l if wantarray; 34b39c5158Smillert return $l[0]; 35b39c5158Smillert} 36b39c5158Smillert 37b39c5158Smillertsub unexpand 38b39c5158Smillert{ 39b39c5158Smillert my (@l) = @_; 40b39c5158Smillert my @e; 41b39c5158Smillert my $x; 42b39c5158Smillert my $line; 43b39c5158Smillert my @lines; 44b39c5158Smillert my $lastbit; 45b39c5158Smillert my $ts_as_space = " " x $tabstop; 46b39c5158Smillert for $x (@l) { 47eac174f2Safresh1 defined $x or next; 48b39c5158Smillert @lines = split("\n", $x, -1); 49b39c5158Smillert for $line (@lines) { 50b39c5158Smillert $line = expand($line); 51*3d61058aSafresh1 @e = split(/((?:\PM\pM*|^\pM+){$tabstop})/,$line,-1); 52b39c5158Smillert $lastbit = pop(@e); 53b39c5158Smillert $lastbit = '' 54b39c5158Smillert unless defined $lastbit; 55b39c5158Smillert $lastbit = "\t" 56b39c5158Smillert if $lastbit eq $ts_as_space; 57b39c5158Smillert for $_ (@e) { 58b39c5158Smillert s/ +$/\t/; 59b39c5158Smillert } 60b39c5158Smillert $line = join('',@e, $lastbit); 61b39c5158Smillert } 62b39c5158Smillert $x = join("\n", @lines); 63b39c5158Smillert } 64b39c5158Smillert return @l if wantarray; 65b39c5158Smillert return $l[0]; 66b39c5158Smillert} 67b39c5158Smillert 68b39c5158Smillert1; 69eac174f2Safresh1 70b39c5158Smillert__END__ 71b39c5158Smillert 72b39c5158Smillert=head1 NAME 73b39c5158Smillert 7491f110e0Safresh1Text::Tabs - expand and unexpand tabs like unix expand(1) and unexpand(1) 75b39c5158Smillert 76b39c5158Smillert=head1 SYNOPSIS 77b39c5158Smillert 78b39c5158Smillert use Text::Tabs; 79b39c5158Smillert 80b39c5158Smillert $tabstop = 4; # default = 8 81b39c5158Smillert @lines_without_tabs = expand(@lines_with_tabs); 82b39c5158Smillert @lines_with_tabs = unexpand(@lines_without_tabs); 83b39c5158Smillert 84b39c5158Smillert=head1 DESCRIPTION 85b39c5158Smillert 8691f110e0Safresh1Text::Tabs does most of what the unix utilities expand(1) and unexpand(1) 8791f110e0Safresh1do. Given a line with tabs in it, C<expand> replaces those tabs with 88b39c5158Smillertthe appropriate number of spaces. Given a line with or without tabs in 8991f110e0Safresh1it, C<unexpand> adds tabs when it can save bytes by doing so, 9091f110e0Safresh1like the C<unexpand -a> command. 9191f110e0Safresh1 9291f110e0Safresh1Unlike the old unix utilities, this module correctly accounts for 9391f110e0Safresh1any Unicode combining characters (such as diacriticals) that may occur 9491f110e0Safresh1in each line for both expansion and unexpansion. These are overstrike 9591f110e0Safresh1characters that do not increment the logical position. Make sure 9691f110e0Safresh1you have the appropriate Unicode settings enabled. 9791f110e0Safresh1 9891f110e0Safresh1=head1 EXPORTS 9991f110e0Safresh1 10091f110e0Safresh1The following are exported: 10191f110e0Safresh1 10291f110e0Safresh1=over 4 10391f110e0Safresh1 10491f110e0Safresh1=item expand 10591f110e0Safresh1 10691f110e0Safresh1=item unexpand 10791f110e0Safresh1 10891f110e0Safresh1=item $tabstop 10991f110e0Safresh1 11091f110e0Safresh1The C<$tabstop> variable controls how many column positions apart each 11191f110e0Safresh1tabstop is. The default is 8. 11291f110e0Safresh1 11391f110e0Safresh1Please note that C<local($tabstop)> doesn't do the right thing and if you want 11491f110e0Safresh1to use C<local> to override C<$tabstop>, you need to use 11591f110e0Safresh1C<local($Text::Tabs::tabstop)>. 11691f110e0Safresh1 11791f110e0Safresh1=back 118b39c5158Smillert 119b39c5158Smillert=head1 EXAMPLE 120b39c5158Smillert 121b39c5158Smillert #!perl 122b39c5158Smillert # unexpand -a 123b39c5158Smillert use Text::Tabs; 124b39c5158Smillert 125b39c5158Smillert while (<>) { 126b39c5158Smillert print unexpand $_; 127b39c5158Smillert } 128b39c5158Smillert 129e9ce3842Safresh1Instead of the shell's C<expand> command, use: 130b39c5158Smillert 131b39c5158Smillert perl -MText::Tabs -n -e 'print expand $_' 132b39c5158Smillert 13391f110e0Safresh1Instead of the shell's C<unexpand -a> command, use: 134b39c5158Smillert 135b39c5158Smillert perl -MText::Tabs -n -e 'print unexpand $_' 136b39c5158Smillert 13791f110e0Safresh1=head1 BUGS 13891f110e0Safresh1 13991f110e0Safresh1Text::Tabs handles only tabs (C<"\t">) and combining characters (C</\pM/>). It doesn't 14091f110e0Safresh1count backwards for backspaces (C<"\t">), omit other non-printing control characters (C</\pC/>), 14191f110e0Safresh1or otherwise deal with any other zero-, half-, and full-width characters. 14291f110e0Safresh1 143b39c5158Smillert=head1 LICENSE 144b39c5158Smillert 145b39c5158SmillertCopyright (C) 1996-2002,2005,2006 David Muir Sharnoff. 146b39c5158SmillertCopyright (C) 2005 Aristotle Pagaltzis 147e9ce3842Safresh1Copyright (C) 2012-2013 Google, Inc. 148b39c5158SmillertThis module may be modified, used, copied, and redistributed at your own risk. 149e9ce3842Safresh1Although allowed by the preceding license, please do not publicly 150e9ce3842Safresh1redistribute modified versions of this code with the name "Text::Tabs" 151e9ce3842Safresh1unless it passes the unmodified Text::Tabs test suite. 152