cb77f0d623ff3 (Kamil Rytarowski 2017-05-07 23:25:26 +0200 1) #!/usr/bin/env perl
b24413180f560 (Greg Kroah-Hartman 2017-11-01 15:07:57 +0100 2) # SPDX-License-Identifier: GPL-2.0
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 3) #
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 4) # Clean a text file -- or directory of text files -- of stealth whitespace.
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 5) # WARNING: this can be a highly destructive operation. Use with caution.
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 6) #
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 7)
cb77f0d623ff3 (Kamil Rytarowski 2017-05-07 23:25:26 +0200 8) use warnings;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 9) use bytes;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 10) use File::Basename;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 11)
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 12) # Default options
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 13) $max_width = 79;
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 14)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 15) # Clean up space-tab sequences, either by removing spaces or
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 16) # replacing them with tabs.
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 17) sub clean_space_tabs($)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 18) {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 19) no bytes; # Tab alignment depends on characters
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 20)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 21) my($li) = @_;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 22) my($lo) = '';
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 23) my $pos = 0;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 24) my $nsp = 0;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 25) my($i, $c);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 26)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 27) for ($i = 0; $i < length($li); $i++) {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 28) $c = substr($li, $i, 1);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 29) if ($c eq "\t") {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 30) my $npos = ($pos+$nsp+8) & ~7;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 31) my $ntab = ($npos >> 3) - ($pos >> 3);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 32) $lo .= "\t" x $ntab;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 33) $pos = $npos;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 34) $nsp = 0;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 35) } elsif ($c eq "\n" || $c eq "\r") {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 36) $lo .= " " x $nsp;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 37) $pos += $nsp;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 38) $nsp = 0;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 39) $lo .= $c;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 40) $pos = 0;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 41) } elsif ($c eq " ") {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 42) $nsp++;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 43) } else {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 44) $lo .= " " x $nsp;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 45) $pos += $nsp;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 46) $nsp = 0;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 47) $lo .= $c;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 48) $pos++;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 49) }
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 50) }
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 51) $lo .= " " x $nsp;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 52) return $lo;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 53) }
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 54)
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 55) # Compute the visual width of a string
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 56) sub strwidth($) {
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 57) no bytes; # Tab alignment depends on characters
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 58)
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 59) my($li) = @_;
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 60) my($c, $i);
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 61) my $pos = 0;
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 62) my $mlen = 0;
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 63)
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 64) for ($i = 0; $i < length($li); $i++) {
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 65) $c = substr($li,$i,1);
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 66) if ($c eq "\t") {
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 67) $pos = ($pos+8) & ~7;
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 68) } elsif ($c eq "\n") {
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 69) $mlen = $pos if ($pos > $mlen);
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 70) $pos = 0;
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 71) } else {
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 72) $pos++;
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 73) }
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 74) }
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 75)
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 76) $mlen = $pos if ($pos > $mlen);
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 77) return $mlen;
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 78) }
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 79)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 80) $name = basename($0);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 81)
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 82) @files = ();
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 83)
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 84) while (defined($a = shift(@ARGV))) {
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 85) if ($a =~ /^-/) {
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 86) if ($a eq '-width' || $a eq '-w') {
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 87) $max_width = shift(@ARGV)+0;
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 88) } else {
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 89) print STDERR "Usage: $name [-width #] files...\n";
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 90) exit 1;
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 91) }
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 92) } else {
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 93) push(@files, $a);
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 94) }
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 95) }
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 96)
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 97) foreach $f ( @files ) {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 98) print STDERR "$name: $f\n";
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 99)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 100) if (! -f $f) {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 101) print STDERR "$f: not a file\n";
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 102) next;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 103) }
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 104)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 105) if (!open(FILE, '+<', $f)) {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 106) print STDERR "$name: Cannot open file: $f: $!\n";
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 107) next;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 108) }
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 109)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 110) binmode FILE;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 111)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 112) # First, verify that it is not a binary file; consider any file
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 113) # with a zero byte to be a binary file. Is there any better, or
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 114) # additional, heuristic that should be applied?
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 115) $is_binary = 0;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 116)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 117) while (read(FILE, $data, 65536) > 0) {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 118) if ($data =~ /\0/) {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 119) $is_binary = 1;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 120) last;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 121) }
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 122) }
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 123)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 124) if ($is_binary) {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 125) print STDERR "$name: $f: binary file\n";
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 126) next;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 127) }
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 128)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 129) seek(FILE, 0, 0);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 130)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 131) $in_bytes = 0;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 132) $out_bytes = 0;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 133) $blank_bytes = 0;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 134)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 135) @blanks = ();
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 136) @lines = ();
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 137) $lineno = 0;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 138)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 139) while ( defined($line = <FILE>) ) {
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 140) $lineno++;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 141) $in_bytes += length($line);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 142) $line =~ s/[ \t\r]*$//; # Remove trailing spaces
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 143) $line = clean_space_tabs($line);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 144)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 145) if ( $line eq "\n" ) {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 146) push(@blanks, $line);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 147) $blank_bytes += length($line);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 148) } else {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 149) push(@lines, @blanks);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 150) $out_bytes += $blank_bytes;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 151) push(@lines, $line);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 152) $out_bytes += length($line);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 153) @blanks = ();
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 154) $blank_bytes = 0;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 155) }
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 156)
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 157) $l_width = strwidth($line);
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 158) if ($max_width && $l_width > $max_width) {
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 159) print STDERR
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 160) "$f:$lineno: line exceeds $max_width characters ($l_width)\n";
cb3ed5b7e09c6 (H. Peter Anvin 2007-05-25 17:58:26 -0700 161) }
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 162) }
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 163)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 164) # Any blanks at the end of the file are discarded
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 165)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 166) if ($in_bytes != $out_bytes) {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 167) # Only write to the file if changed
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 168) seek(FILE, 0, 0);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 169) print FILE @lines;
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 170)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 171) if ( !defined($where = tell(FILE)) ||
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 172) !truncate(FILE, $where) ) {
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 173) die "$name: Failed to truncate modified file: $f: $!\n";
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 174) }
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 175) }
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 176)
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 177) close(FILE);
12b315603a1eb (H. Peter Anvin 2007-03-12 12:16:30 -0700 178) }