xref: /openbmc/linux/scripts/cleanfile (revision 64c70b1c)
1#!/usr/bin/perl -w
2#
3# Clean a text file -- or directory of text files -- of stealth whitespace.
4# WARNING: this can be a highly destructive operation.  Use with caution.
5#
6
7use bytes;
8use File::Basename;
9
10#
11# Clean up space-tab sequences, either by removing spaces or
12# replacing them with tabs.
13sub clean_space_tabs($)
14{
15    no bytes;			# Tab alignment depends on characters
16
17    my($li) = @_;
18    my($lo) = '';
19    my $pos = 0;
20    my $nsp = 0;
21    my($i, $c);
22
23    for ($i = 0; $i < length($li); $i++) {
24	$c = substr($li, $i, 1);
25	if ($c eq "\t") {
26	    my $npos = ($pos+$nsp+8) & ~7;
27	    my $ntab = ($npos >> 3) - ($pos >> 3);
28	    $lo .= "\t" x $ntab;
29	    $pos = $npos;
30	    $nsp = 0;
31	} elsif ($c eq "\n" || $c eq "\r") {
32	    $lo .= " " x $nsp;
33	    $pos += $nsp;
34	    $nsp = 0;
35	    $lo .= $c;
36	    $pos = 0;
37	} elsif ($c eq " ") {
38	    $nsp++;
39	} else {
40	    $lo .= " " x $nsp;
41	    $pos += $nsp;
42	    $nsp = 0;
43	    $lo .= $c;
44	    $pos++;
45	}
46    }
47    $lo .= " " x $nsp;
48    return $lo;
49}
50
51$name = basename($0);
52
53foreach $f ( @ARGV ) {
54    print STDERR "$name: $f\n";
55
56    if (! -f $f) {
57	print STDERR "$f: not a file\n";
58	next;
59    }
60
61    if (!open(FILE, '+<', $f)) {
62	print STDERR "$name: Cannot open file: $f: $!\n";
63	next;
64    }
65
66    binmode FILE;
67
68    # First, verify that it is not a binary file; consider any file
69    # with a zero byte to be a binary file.  Is there any better, or
70    # additional, heuristic that should be applied?
71    $is_binary = 0;
72
73    while (read(FILE, $data, 65536) > 0) {
74	if ($data =~ /\0/) {
75	    $is_binary = 1;
76	    last;
77	}
78    }
79
80    if ($is_binary) {
81	print STDERR "$name: $f: binary file\n";
82	next;
83    }
84
85    seek(FILE, 0, 0);
86
87    $in_bytes = 0;
88    $out_bytes = 0;
89    $blank_bytes = 0;
90
91    @blanks = ();
92    @lines  = ();
93
94    while ( defined($line = <FILE>) ) {
95	$in_bytes += length($line);
96	$line =~ s/[ \t\r]*$//;		# Remove trailing spaces
97	$line = clean_space_tabs($line);
98
99	if ( $line eq "\n" ) {
100	    push(@blanks, $line);
101	    $blank_bytes += length($line);
102	} else {
103	    push(@lines, @blanks);
104	    $out_bytes += $blank_bytes;
105	    push(@lines, $line);
106	    $out_bytes += length($line);
107	    @blanks = ();
108	    $blank_bytes = 0;
109	}
110    }
111
112    # Any blanks at the end of the file are discarded
113
114    if ($in_bytes != $out_bytes) {
115	# Only write to the file if changed
116	seek(FILE, 0, 0);
117	print FILE @lines;
118
119	if ( !defined($where = tell(FILE)) ||
120	     !truncate(FILE, $where) ) {
121	    die "$name: Failed to truncate modified file: $f: $!\n";
122	}
123    }
124
125    close(FILE);
126}
127