-#
-# expand and unexpand tabs as per the unix expand and
-# unexpand programs.
-#
-# expand and unexpand operate on arrays of lines. Do not
-# feed strings that contain newlines to them.
-#
-# David Muir Sharnoff <muir@idiom.com>
-#
-# Version: 9/21/95
-#
-
-=head1 NAME
-
-Text::Tabs -- expand and unexpand tabs
-
-=head1 SYNOPSIS
-
- use Text::Tabs;
-
- #$tabstop = 8; # Defaults
- print expand("Hello\tworld");
- print unexpand("Hello, world");
- $tabstop = 4;
- print join("\n",expand(split(/\n/,
- "Hello\tworld,\nit's a nice day.\n"
- )));
-
-=head1 DESCRIPTION
-
-This module expands and unexpands tabs into spaces, as per the unix expand
-and unexpand programs. Either function should be passed an array of strings
-(newlines may I<not> be included, and should be used to split an incoming
-string into separate elements.) which will be processed and returned.
-
-=head1 AUTHOR
-
-David Muir Sharnoff <muir@idiom.com>
-
-=cut
package Text::Tabs;
require Exporter;
-@ISA = (Exporter);
+@ISA = qw(Exporter);
@EXPORT = qw(expand unexpand $tabstop);
-$tabstop = 8;
+use vars qw($VERSION $tabstop $debug);
+$VERSION = 2007.0711_01;
-sub expand
-{
- my @l = @_;
- for $_ (@l) {
- 1 while s/^([^\t]*)(\t+)/
- $1 . (" " x
- ($tabstop * length($2)
- - (length($1) % $tabstop)))
- /e;
+use strict;
+
+BEGIN {
+ $tabstop = 8;
+ $debug = 0;
+}
+
+sub expand {
+ my @l;
+ my $pad;
+ for ( @_ ) {
+ my $s = '';
+ for (split(/^/m, $_, -1)) {
+ my $offs = 0;
+ s{\t}{
+ $pad = $tabstop - (pos() + $offs) % $tabstop;
+ $offs += $pad - 1;
+ " " x $pad;
+ }eg;
+ $s .= $_;
+ }
+ push(@l, $s);
}
return @l if wantarray;
- return @l[0];
+ return $l[0];
}
sub unexpand
{
- my @l = &expand(@_);
+ my (@l) = @_;
my @e;
+ my $x;
+ my $line;
+ my @lines;
+ my $lastbit;
+ my $ts_as_space = " "x$tabstop;
for $x (@l) {
- @e = split(/(.{$tabstop})/,$x);
- for $_ (@e) {
- s/ +$/\t/;
+ @lines = split("\n", $x, -1);
+ for $line (@lines) {
+ $line = expand($line);
+ @e = split(/(.{$tabstop})/,$line,-1);
+ $lastbit = pop(@e);
+ $lastbit = ''
+ unless defined $lastbit;
+ $lastbit = "\t"
+ if $lastbit eq $ts_as_space;
+ for $_ (@e) {
+ if ($debug) {
+ my $x = $_;
+ $x =~ s/\t/^I\t/gs;
+ print "sub on '$x'\n";
+ }
+ s/ +$/\t/;
+ }
+ $line = join('',@e, $lastbit);
}
- $x = join('',@e);
+ $x = join("\n", @lines);
}
return @l if wantarray;
- return @l[0];
+ return $l[0];
}
1;
+__END__
+
+sub expand
+{
+ my (@l) = @_;
+ for $_ (@l) {
+ 1 while s/(^|\n)([^\t\n]*)(\t+)/
+ $1. $2 . (" " x
+ ($tabstop * length($3)
+ - (length($2) % $tabstop)))
+ /sex;
+ }
+ return @l if wantarray;
+ return $l[0];
+}
+
+
+=head1 NAME
+
+Text::Tabs -- expand and unexpand tabs per the unix expand(1) and unexpand(1)
+
+=head1 SYNOPSIS
+
+ use Text::Tabs;
+
+ $tabstop = 4; # default = 8
+ @lines_without_tabs = expand(@lines_with_tabs);
+ @lines_with_tabs = unexpand(@lines_without_tabs);
+
+=head1 DESCRIPTION
+
+Text::Tabs does about what the unix utilities expand(1) and unexpand(1)
+do. Given a line with tabs in it, expand will replace the tabs with
+the appropriate number of spaces. Given a line with or without tabs in
+it, unexpand will add tabs when it can save bytes by doing so (just
+like C<unexpand -a>). Invisible compression with plain ASCII!
+
+=head1 EXAMPLE
+
+ #!perl
+ # unexpand -a
+ use Text::Tabs;
+
+ while (<>) {
+ print unexpand $_;
+ }
+
+Instead of the C<expand> comand, use:
+
+ perl -MText::Tabs -n -e 'print expand $_'
+
+Instead of the C<unexpand -a> command, use:
+
+ perl -MText::Tabs -n -e 'print unexpand $_'
+
+=head1 BUGS
+
+expand doesn't handle newlines very quickly -- do not feed it an
+entire document in one string. Instead feed it an array of lines.
+
+=head1 LICENSE
+
+Copyright (C) 1996-2002,2005,2006 David Muir Sharnoff.
+Copyright (C) 2005 Aristotle Pagaltzis
+This module may be modified, used, copied, and redistributed at your own risk.
+Publicly redistributed modified versions must use a different name.
+