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