blob: 7cab3f64f81a2a69fa7061cd63178d69c20b0d62 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001#!/usr/bin/perl
2
3use strict;
4use File::Find;
5use File::Temp qw/ tempfile tempdir /;
6use Getopt::Std;
7use Pod::Usage;
8use Text::Tabs;
9
10=head1 NAME
11
12B<sed-sources> -- Performs multiple sed commands on files with the ability to expand or unexpand tabs.
13
14=head1 SYNOPSIS
15
16B<sed-sources> [options] [file dir ...]
17
18=head1 DESCRIPTION
19
20Performs multiple sed commands (modify builtin %seds hash) on source files
21or any sources in directories. If no arguments are given, STDIN will be used
22as the source. If source files or directories are specified as arguments,
23all files will be transformed and overwritten with new versions. Use the B<-p>
24option to preview changes to STDOUT, or use the B<-b> option to make a backup
25or the original files.
26
27=head1 OPTIONS
28
29=over
30
31=item B<-b>
32
33Backup original source file by appending ".bak" before overwriting with the
34newly transformed file.
35
36=item B<-g>
37
38Display verbose debug logging.
39
40=item B<-e>
41
42Expand tabs to spaces (in addition to doing sed substitutions).
43
44=item B<-u>
45
46Unexpand spaces to tabs (in addition to doing sed substitutions).
47
48=item B<-p>
49
50Preview changes to STDOUT without modifying original source files.
51
52=item B<-r>
53
54Skip variants when doing multiple files (no _profile or _debug variants).
55
56=item B<-t N>
57
58Set the number of spaces per tab (default is 4) to use when expanding or
59unexpanding.
60
61=back
62
63=head1 EXAMPLES
64
65# Recursively process all source files in the current working directory
66# and and subdirectories and also expand tabs to spaces. All source files
67# will be overwritten with the newly transformed source files.
68
69% sed-sources -e $cwd
70
71# Recursively process all source files in the current working directory
72# and and subdirectories and also unexpand spaces to tabs and preview the
73# results to STDOUT
74
75% sed-sources -p -u $cwd
76
77# Same as above except use 8 spaces per tab.
78
79% sed-sources -p -u -t8 $cwd
80
81=cut
82
83
84our $opt_b = 0; # Backup original file?
85our $opt_g = 0; # Verbose debug output?
86our $opt_e = 0; # Expand tabs to spaces?
87our $opt_h = 0; # Show help?
88our $opt_m = 0; # Show help manpage style?
89our $opt_p = 0; # Preview changes to STDOUT?
90our $opt_t = 4; # Number of spaces per tab?
91our $opt_u = 0; # Unexpand spaces to tabs?
92getopts('eghmpt:u');
93
94$opt_m and show_manpage();
95$opt_h and help();
96
97our %seds = (
98 '\s+$' => "\n", # Get rid of spaces at the end of a line
99 '^\s+$' => "\n", # Get rid spaces on lines that are all spaces
Chris Lattner24943d22010-06-08 16:52:24 +0000100);
101
102
103sub show_manpage { exit pod2usage( verbose => 2 ); };
104sub help { exit pod2usage( verbose => 3, noperldoc => 1 ); };
105
106
107#----------------------------------------------------------------------
108# process_opened_file_handle
109#----------------------------------------------------------------------
110sub process_opened_file_handle
111{
112 my $in_fh = shift;
113 my $out_fh = shift;
114
115 # Set the number of spaces per tab for expand/unexpand
116 $tabstop = $opt_t;
117
118 while (my $line = <$in_fh>)
119 {
120 foreach my $key (keys %seds)
121 {
122 my $value = $seds{"$key"};
123 $line =~ s/$key/$value/g;
124 }
125 if ($opt_e) {
126 print $out_fh expand $line;
127 } elsif ($opt_u) {
128 print $out_fh unexpand $line;
129 } else {
130 print $out_fh $line;
131 }
132 }
133}
134
135#----------------------------------------------------------------------
136# process_file
137#----------------------------------------------------------------------
138sub process_file
139{
140 my $in_path = shift;
141 if (-T $in_path)
142 {
143 my $out_fh;
144 my $out_path;
145 if ($opt_p)
146 {
147 # Preview to STDOUT
148 $out_fh = *STDOUT;
149 print "#---------------------------------------------------------------------- \n";
150 print "# BEGIN: '$in_path'\n";
151 print "#---------------------------------------------------------------------- \n";
152 }
153 else
154 {
155 ($out_fh, $out_path) = tempfile();
156 $opt_g and print "temporary for '$in_path' is '$out_path'\n";
157 }
158 open (IN, "<$in_path") or die "error: can't open '$in_path' for reading: $!";
159 process_opened_file_handle (*IN, $out_fh);
160
161
162 # Close our input file
163 close (IN);
164
165 if ($opt_p)
166 {
167 print "#---------------------------------------------------------------------- \n";
168 print "# END: '$in_path'\n";
169 print "#---------------------------------------------------------------------- \n";
170 print "\n\n";
171 }
172 else
173 {
174 # Close the output file if it wasn't STDOUT
175 close ($out_fh);
176
177 # Backup file if requested
178 if ($opt_b)
179 {
180 my $backup_command = "cp '$in_path' '$in_path.bak'";
181 $opt_g and print "\% $backup_command\n";
182 system ($backup_command);
183 }
184
185 # Copy temp file over original
186 my $copy_command = "cp '$out_path' '$in_path'";
187 $opt_g and print "\% $copy_command\n";
188 system ($copy_command);
189 }
190 }
191}
192
193our @valid_extensions = ( "h", "cpp", "c", "m", "mm" );
194
195#----------------------------------------------------------------------
196# find_callback
197#----------------------------------------------------------------------
198sub find_callback
199{
200 my $file = $_;
201 my $fullpath = $File::Find::name;
202
203 foreach my $ext (@valid_extensions)
204 {
205 my $ext_regex = "\\.$ext\$";
206 if ($fullpath =~ /$ext_regex/i)
207 {
208 print "processing: '$fullpath'\n";
209 process_file ($fullpath);
210 return;
211 }
212 }
213 print " ignoring: '$fullpath'\n";
214}
215
216
217#----------------------------------------------------------------------
218# main
219#----------------------------------------------------------------------
220sub main
221{
222 if (@ARGV == 0)
223 {
224 # no args, take from STDIN and put to STDOUT
225 process_opened_file_handle (*STDIN, *STDOUT);
226 }
227 else
228 {
229 # Got args, any files we run into parse them, any directories
230 # we run into, search them for files
231 my $path;
232 foreach $path (@ARGV)
233 {
234 if (-f $path)
235 {
236 print "processing: '$path'\n";
237 process_file ($path);
238 }
239 else
240 {
241 print " searching: '$path'\n";
242 find(\&find_callback, $path);
243 }
244 }
245 }
246}
247
248
249
250# call the main function
251main();