/
unexpand
executable file
·185 lines (140 loc) · 3.98 KB
/
unexpand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/usr/bin/perl
=begin metadata
Name: unexpand
Description: convert spaces to tabs
Author: Thierry Bezecourt, thbzcrt@worldnet.fr
License: perl
=end metadata
=cut
#
# A Perl implementation of expand(1) and unexpand(1) for the Perl Power
# Tools project by Thierry Bezecourt <thbzcrt@worldnet.fr>.
#
# I don't use Text::Tabs, because :
# - it cannot be used to implement the -a option
# - it doesn't recognize backspace characters
#
# Please see the pod documentation at the end of this file.
#
# 99/03/10 : first version
#
use strict;
use File::Basename qw(basename);
use constant EX_SUCCESS => 0;
use constant EX_FAILURE => 1;
my $Program = basename($0);
my $tabstop = 8;
my $opt_a = 0;
my @tabstops;
my @files;
while (@ARGV && $ARGV[0] =~ /\A\-(.+)/) {
my $val = $1;
if ($val eq '-') { # '--' terminator
shift @ARGV;
last;
}
if ($val eq 'a') {
$opt_a = 1;
} else {
@tabstops = split /,/, $val;
usage() if grep /\D/, @tabstops;
}
shift @ARGV;
}
@files = @ARGV;
# $tabstop is used only if multiple tab stops have not been defined
$tabstop = $tabstops[0] if scalar @tabstops == 1;
for my $file (@files) {
my $in;
unless (open $in, '<', $file) {
warn "$Program: couldn't open '$file' for reading: $!'\n";
exit EX_FAILURE;
}
while (<$in>) {
unexpand_line($_);
}
close $in;
}
unless (@files) {
while (<>) {
unexpand_line($_);
}
}
exit EX_SUCCESS;
sub usage {
warn "usage: $Program [-a] [-tabstop] [-tab1, tab2, ...] [file ...]\n";
exit EX_FAILURE;
}
sub is_tab {
return (grep {$_ eq $_[0]} @tabstops) if scalar @tabstops >= 2;
return ($_[0] % $tabstop == 0);
}
sub unexpand_line {
my $line = shift;
my $cumul = "";
my $curs = 0;
my @a = split //, $line;
my $c;
while($c = shift @a) {
if(is_tab($curs)) {
if($cumul =~ /^(.*?) +$/) {
print "$1\t";
} else {
print $cumul;
}
$cumul = "";
}
# Print everything after the first non-space character,
# unless we use the -a option
$cumul .= $c.join("", @a), last
if !$opt_a and $c ne " " and $curs > 0;
# Increment the cursor unless the character is a backspace.
if($c eq "\010") {
$curs-- if $curs > 0;
} else {
$curs++;
}
$cumul .= $c;
}
print $cumul;
}
__END__
=head1 NAME
unexpand - convert spaces to tabs
=head1 SYNOPSIS
unexpand [B<-a>] [B<-tabstop>] [B<-tab1, tab2, ...>] [B<file> ...]
=head1 DESCRIPTION
I<expand> processes the named files or the standard input writing the
standard output with tabs changed into blanks. Backspace characters
are preserved into the output and decrement the column count for tab
calculations. I<expand> is useful for pre-processing character files
(before sorting, looking at specific columns, etc.) that contain tabs.
If a single B<tabstop> argument is given, tabs are set B<tabstop> spaces
apart instead of the default 8. If multiple tabstops are given then
the tabs are set at those specific columns.
I<unexpand> puts tabs back into the data from the standard input or the
named files and writes the result on the standard output.
=head1 OPTIONS
=over 4
=item -a
By default, only leading blanks and tabs are reconverted to maximal
strings of tabs. If the B<-a> option is given, tabs are inserted
whenever they would compress the resultant file by replacing two or
more characters.
=back
=head1 AUTHOR
=for html
The Perl implementation was written by <A
href="mailto:thbzcrt@worldnet.fr">Thierry Bézecourt</A> for the
<A href="http://language.perl.com/ppt/">Perl Power Tools project</A>,
March 1999.
=for html <!--
The Perl implementation was written by Thierry Bezecourt,
I<thbzcrt@worldnet.fr>. Perl Power Tools project, March 1999.
=for html -->
This documentation comes from the BSD expand(1) man page.
=head1 COPYRIGHT and LICENSE
This program is free and open software. You may use, modify, distribute,
and sell this program (and any modified variants) in any way you wish,
provided you do not restrict others from doing the same.
=cut