xref: /utopia/UTPA2-700.0.x/projects/build/scripts/cleanpatch (revision 53ee8cc121a030b8d368113ac3e966b4705770ef)
1*53ee8cc1Swenshuai.xi#!/usr/bin/perl -w
2*53ee8cc1Swenshuai.xi#
3*53ee8cc1Swenshuai.xi# Clean a patch file -- or directory of patch files -- of stealth whitespace.
4*53ee8cc1Swenshuai.xi# WARNING: this can be a highly destructive operation.  Use with caution.
5*53ee8cc1Swenshuai.xi#
6*53ee8cc1Swenshuai.xi
7*53ee8cc1Swenshuai.xiuse bytes;
8*53ee8cc1Swenshuai.xiuse File::Basename;
9*53ee8cc1Swenshuai.xi
10*53ee8cc1Swenshuai.xi# Default options
11*53ee8cc1Swenshuai.xi$max_width = 79;
12*53ee8cc1Swenshuai.xi
13*53ee8cc1Swenshuai.xi# Clean up space-tab sequences, either by removing spaces or
14*53ee8cc1Swenshuai.xi# replacing them with tabs.
15*53ee8cc1Swenshuai.xisub clean_space_tabs($)
16*53ee8cc1Swenshuai.xi{
17*53ee8cc1Swenshuai.xi    no bytes;			# Tab alignment depends on characters
18*53ee8cc1Swenshuai.xi
19*53ee8cc1Swenshuai.xi    my($li) = @_;
20*53ee8cc1Swenshuai.xi    my($lo) = '';
21*53ee8cc1Swenshuai.xi    my $pos = 0;
22*53ee8cc1Swenshuai.xi    my $nsp = 0;
23*53ee8cc1Swenshuai.xi    my($i, $c);
24*53ee8cc1Swenshuai.xi
25*53ee8cc1Swenshuai.xi    for ($i = 0; $i < length($li); $i++) {
26*53ee8cc1Swenshuai.xi	$c = substr($li, $i, 1);
27*53ee8cc1Swenshuai.xi	if ($c eq "\t") {
28*53ee8cc1Swenshuai.xi	    my $npos = ($pos+$nsp+8) & ~7;
29*53ee8cc1Swenshuai.xi	    my $ntab = ($npos >> 3) - ($pos >> 3);
30*53ee8cc1Swenshuai.xi	    $lo .= "\t" x $ntab;
31*53ee8cc1Swenshuai.xi	    $pos = $npos;
32*53ee8cc1Swenshuai.xi	    $nsp = 0;
33*53ee8cc1Swenshuai.xi	} elsif ($c eq "\n" || $c eq "\r") {
34*53ee8cc1Swenshuai.xi	    $lo .= " " x $nsp;
35*53ee8cc1Swenshuai.xi	    $pos += $nsp;
36*53ee8cc1Swenshuai.xi	    $nsp = 0;
37*53ee8cc1Swenshuai.xi	    $lo .= $c;
38*53ee8cc1Swenshuai.xi	    $pos = 0;
39*53ee8cc1Swenshuai.xi	} elsif ($c eq " ") {
40*53ee8cc1Swenshuai.xi	    $nsp++;
41*53ee8cc1Swenshuai.xi	} else {
42*53ee8cc1Swenshuai.xi	    $lo .= " " x $nsp;
43*53ee8cc1Swenshuai.xi	    $pos += $nsp;
44*53ee8cc1Swenshuai.xi	    $nsp = 0;
45*53ee8cc1Swenshuai.xi	    $lo .= $c;
46*53ee8cc1Swenshuai.xi	    $pos++;
47*53ee8cc1Swenshuai.xi	}
48*53ee8cc1Swenshuai.xi    }
49*53ee8cc1Swenshuai.xi    $lo .= " " x $nsp;
50*53ee8cc1Swenshuai.xi    return $lo;
51*53ee8cc1Swenshuai.xi}
52*53ee8cc1Swenshuai.xi
53*53ee8cc1Swenshuai.xi# Compute the visual width of a string
54*53ee8cc1Swenshuai.xisub strwidth($) {
55*53ee8cc1Swenshuai.xi    no bytes;			# Tab alignment depends on characters
56*53ee8cc1Swenshuai.xi
57*53ee8cc1Swenshuai.xi    my($li) = @_;
58*53ee8cc1Swenshuai.xi    my($c, $i);
59*53ee8cc1Swenshuai.xi    my $pos = 0;
60*53ee8cc1Swenshuai.xi    my $mlen = 0;
61*53ee8cc1Swenshuai.xi
62*53ee8cc1Swenshuai.xi    for ($i = 0; $i < length($li); $i++) {
63*53ee8cc1Swenshuai.xi	$c = substr($li,$i,1);
64*53ee8cc1Swenshuai.xi	if ($c eq "\t") {
65*53ee8cc1Swenshuai.xi	    $pos = ($pos+8) & ~7;
66*53ee8cc1Swenshuai.xi	} elsif ($c eq "\n") {
67*53ee8cc1Swenshuai.xi	    $mlen = $pos if ($pos > $mlen);
68*53ee8cc1Swenshuai.xi	    $pos = 0;
69*53ee8cc1Swenshuai.xi	} else {
70*53ee8cc1Swenshuai.xi	    $pos++;
71*53ee8cc1Swenshuai.xi	}
72*53ee8cc1Swenshuai.xi    }
73*53ee8cc1Swenshuai.xi
74*53ee8cc1Swenshuai.xi    $mlen = $pos if ($pos > $mlen);
75*53ee8cc1Swenshuai.xi    return $mlen;
76*53ee8cc1Swenshuai.xi}
77*53ee8cc1Swenshuai.xi
78*53ee8cc1Swenshuai.xi$name = basename($0);
79*53ee8cc1Swenshuai.xi
80*53ee8cc1Swenshuai.xi@files = ();
81*53ee8cc1Swenshuai.xi
82*53ee8cc1Swenshuai.xiwhile (defined($a = shift(@ARGV))) {
83*53ee8cc1Swenshuai.xi    if ($a =~ /^-/) {
84*53ee8cc1Swenshuai.xi	if ($a eq '-width' || $a eq '-w') {
85*53ee8cc1Swenshuai.xi	    $max_width = shift(@ARGV)+0;
86*53ee8cc1Swenshuai.xi	} else {
87*53ee8cc1Swenshuai.xi	    print STDERR "Usage: $name [-width #] files...\n";
88*53ee8cc1Swenshuai.xi	    exit 1;
89*53ee8cc1Swenshuai.xi	}
90*53ee8cc1Swenshuai.xi    } else {
91*53ee8cc1Swenshuai.xi	push(@files, $a);
92*53ee8cc1Swenshuai.xi    }
93*53ee8cc1Swenshuai.xi}
94*53ee8cc1Swenshuai.xi
95*53ee8cc1Swenshuai.xiforeach $f ( @files ) {
96*53ee8cc1Swenshuai.xi    print STDERR "$name: $f\n";
97*53ee8cc1Swenshuai.xi
98*53ee8cc1Swenshuai.xi    if (! -f $f) {
99*53ee8cc1Swenshuai.xi	print STDERR "$f: not a file\n";
100*53ee8cc1Swenshuai.xi	next;
101*53ee8cc1Swenshuai.xi    }
102*53ee8cc1Swenshuai.xi
103*53ee8cc1Swenshuai.xi    if (!open(FILE, '+<', $f)) {
104*53ee8cc1Swenshuai.xi	print STDERR "$name: Cannot open file: $f: $!\n";
105*53ee8cc1Swenshuai.xi	next;
106*53ee8cc1Swenshuai.xi    }
107*53ee8cc1Swenshuai.xi
108*53ee8cc1Swenshuai.xi    binmode FILE;
109*53ee8cc1Swenshuai.xi
110*53ee8cc1Swenshuai.xi    # First, verify that it is not a binary file; consider any file
111*53ee8cc1Swenshuai.xi    # with a zero byte to be a binary file.  Is there any better, or
112*53ee8cc1Swenshuai.xi    # additional, heuristic that should be applied?
113*53ee8cc1Swenshuai.xi    $is_binary = 0;
114*53ee8cc1Swenshuai.xi
115*53ee8cc1Swenshuai.xi    while (read(FILE, $data, 65536) > 0) {
116*53ee8cc1Swenshuai.xi	if ($data =~ /\0/) {
117*53ee8cc1Swenshuai.xi	    $is_binary = 1;
118*53ee8cc1Swenshuai.xi	    last;
119*53ee8cc1Swenshuai.xi	}
120*53ee8cc1Swenshuai.xi    }
121*53ee8cc1Swenshuai.xi
122*53ee8cc1Swenshuai.xi    if ($is_binary) {
123*53ee8cc1Swenshuai.xi	print STDERR "$name: $f: binary file\n";
124*53ee8cc1Swenshuai.xi	next;
125*53ee8cc1Swenshuai.xi    }
126*53ee8cc1Swenshuai.xi
127*53ee8cc1Swenshuai.xi    seek(FILE, 0, 0);
128*53ee8cc1Swenshuai.xi
129*53ee8cc1Swenshuai.xi    $in_bytes = 0;
130*53ee8cc1Swenshuai.xi    $out_bytes = 0;
131*53ee8cc1Swenshuai.xi    $lineno = 0;
132*53ee8cc1Swenshuai.xi
133*53ee8cc1Swenshuai.xi    @lines  = ();
134*53ee8cc1Swenshuai.xi
135*53ee8cc1Swenshuai.xi    $in_hunk = 0;
136*53ee8cc1Swenshuai.xi    $err = 0;
137*53ee8cc1Swenshuai.xi
138*53ee8cc1Swenshuai.xi    while ( defined($line = <FILE>) ) {
139*53ee8cc1Swenshuai.xi	$lineno++;
140*53ee8cc1Swenshuai.xi	$in_bytes += length($line);
141*53ee8cc1Swenshuai.xi
142*53ee8cc1Swenshuai.xi	if (!$in_hunk) {
143*53ee8cc1Swenshuai.xi	    if ($line =~
144*53ee8cc1Swenshuai.xi		/^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@/) {
145*53ee8cc1Swenshuai.xi		$minus_lines = $2;
146*53ee8cc1Swenshuai.xi		$plus_lines = $4;
147*53ee8cc1Swenshuai.xi		if ($minus_lines || $plus_lines) {
148*53ee8cc1Swenshuai.xi		    $in_hunk = 1;
149*53ee8cc1Swenshuai.xi		    @hunk_lines = ($line);
150*53ee8cc1Swenshuai.xi		}
151*53ee8cc1Swenshuai.xi	    } else {
152*53ee8cc1Swenshuai.xi		push(@lines, $line);
153*53ee8cc1Swenshuai.xi		$out_bytes += length($line);
154*53ee8cc1Swenshuai.xi	    }
155*53ee8cc1Swenshuai.xi	} else {
156*53ee8cc1Swenshuai.xi	    # We're in a hunk
157*53ee8cc1Swenshuai.xi
158*53ee8cc1Swenshuai.xi	    if ($line =~ /^\+/) {
159*53ee8cc1Swenshuai.xi		$plus_lines--;
160*53ee8cc1Swenshuai.xi
161*53ee8cc1Swenshuai.xi		$text = substr($line, 1);
162*53ee8cc1Swenshuai.xi		$text =~ s/[ \t\r]*$//;		# Remove trailing spaces
163*53ee8cc1Swenshuai.xi		$text = clean_space_tabs($text);
164*53ee8cc1Swenshuai.xi
165*53ee8cc1Swenshuai.xi		$l_width = strwidth($text);
166*53ee8cc1Swenshuai.xi		if ($max_width && $l_width > $max_width) {
167*53ee8cc1Swenshuai.xi		    print STDERR
168*53ee8cc1Swenshuai.xi			"$f:$lineno: adds line exceeds $max_width ",
169*53ee8cc1Swenshuai.xi			"characters ($l_width)\n";
170*53ee8cc1Swenshuai.xi		}
171*53ee8cc1Swenshuai.xi
172*53ee8cc1Swenshuai.xi		push(@hunk_lines, '+'.$text);
173*53ee8cc1Swenshuai.xi	    } elsif ($line =~ /^\-/) {
174*53ee8cc1Swenshuai.xi		$minus_lines--;
175*53ee8cc1Swenshuai.xi		push(@hunk_lines, $line);
176*53ee8cc1Swenshuai.xi	    } elsif ($line =~ /^ /) {
177*53ee8cc1Swenshuai.xi		$plus_lines--;
178*53ee8cc1Swenshuai.xi		$minus_lines--;
179*53ee8cc1Swenshuai.xi		push(@hunk_lines, $line);
180*53ee8cc1Swenshuai.xi	    } else {
181*53ee8cc1Swenshuai.xi		print STDERR "$name: $f: malformed patch\n";
182*53ee8cc1Swenshuai.xi		$err = 1;
183*53ee8cc1Swenshuai.xi		last;
184*53ee8cc1Swenshuai.xi	    }
185*53ee8cc1Swenshuai.xi
186*53ee8cc1Swenshuai.xi	    if ($plus_lines < 0 || $minus_lines < 0) {
187*53ee8cc1Swenshuai.xi		print STDERR "$name: $f: malformed patch\n";
188*53ee8cc1Swenshuai.xi		$err = 1;
189*53ee8cc1Swenshuai.xi		last;
190*53ee8cc1Swenshuai.xi	    } elsif ($plus_lines == 0 && $minus_lines == 0) {
191*53ee8cc1Swenshuai.xi		# End of a hunk.  Process this hunk.
192*53ee8cc1Swenshuai.xi		my $i;
193*53ee8cc1Swenshuai.xi		my $l;
194*53ee8cc1Swenshuai.xi		my @h = ();
195*53ee8cc1Swenshuai.xi		my $adj = 0;
196*53ee8cc1Swenshuai.xi		my $done = 0;
197*53ee8cc1Swenshuai.xi
198*53ee8cc1Swenshuai.xi		for ($i = scalar(@hunk_lines)-1; $i > 0; $i--) {
199*53ee8cc1Swenshuai.xi		    $l = $hunk_lines[$i];
200*53ee8cc1Swenshuai.xi		    if (!$done && $l eq "+\n") {
201*53ee8cc1Swenshuai.xi			$adj++; # Skip this line
202*53ee8cc1Swenshuai.xi		    } elsif ($l =~ /^[ +]/) {
203*53ee8cc1Swenshuai.xi			$done = 1;
204*53ee8cc1Swenshuai.xi			unshift(@h, $l);
205*53ee8cc1Swenshuai.xi		    } else {
206*53ee8cc1Swenshuai.xi			unshift(@h, $l);
207*53ee8cc1Swenshuai.xi		    }
208*53ee8cc1Swenshuai.xi		}
209*53ee8cc1Swenshuai.xi
210*53ee8cc1Swenshuai.xi		$l = $hunk_lines[0];  # Hunk header
211*53ee8cc1Swenshuai.xi		undef @hunk_lines;    # Free memory
212*53ee8cc1Swenshuai.xi
213*53ee8cc1Swenshuai.xi		if ($adj) {
214*53ee8cc1Swenshuai.xi		    die unless
215*53ee8cc1Swenshuai.xi			($l =~ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@(.*)$/);
216*53ee8cc1Swenshuai.xi		    my $mstart = $1;
217*53ee8cc1Swenshuai.xi		    my $mlin = $2;
218*53ee8cc1Swenshuai.xi		    my $pstart = $3;
219*53ee8cc1Swenshuai.xi		    my $plin = $4;
220*53ee8cc1Swenshuai.xi		    my $tail = $5; # doesn't include the final newline
221*53ee8cc1Swenshuai.xi
222*53ee8cc1Swenshuai.xi		    $l = sprintf("@@ -%d,%d +%d,%d @@%s\n",
223*53ee8cc1Swenshuai.xi				 $mstart, $mlin, $pstart, $plin-$adj,
224*53ee8cc1Swenshuai.xi				 $tail);
225*53ee8cc1Swenshuai.xi		}
226*53ee8cc1Swenshuai.xi		unshift(@h, $l);
227*53ee8cc1Swenshuai.xi
228*53ee8cc1Swenshuai.xi		# Transfer to the output array
229*53ee8cc1Swenshuai.xi		foreach $l (@h) {
230*53ee8cc1Swenshuai.xi		    $out_bytes += length($l);
231*53ee8cc1Swenshuai.xi		    push(@lines, $l);
232*53ee8cc1Swenshuai.xi		}
233*53ee8cc1Swenshuai.xi
234*53ee8cc1Swenshuai.xi		$in_hunk = 0;
235*53ee8cc1Swenshuai.xi	    }
236*53ee8cc1Swenshuai.xi	}
237*53ee8cc1Swenshuai.xi    }
238*53ee8cc1Swenshuai.xi
239*53ee8cc1Swenshuai.xi    if ($in_hunk) {
240*53ee8cc1Swenshuai.xi	print STDERR "$name: $f: malformed patch\n";
241*53ee8cc1Swenshuai.xi	$err = 1;
242*53ee8cc1Swenshuai.xi    }
243*53ee8cc1Swenshuai.xi
244*53ee8cc1Swenshuai.xi    if (!$err) {
245*53ee8cc1Swenshuai.xi	if ($in_bytes != $out_bytes) {
246*53ee8cc1Swenshuai.xi	    # Only write to the file if changed
247*53ee8cc1Swenshuai.xi	    seek(FILE, 0, 0);
248*53ee8cc1Swenshuai.xi	    print FILE @lines;
249*53ee8cc1Swenshuai.xi
250*53ee8cc1Swenshuai.xi	    if ( !defined($where = tell(FILE)) ||
251*53ee8cc1Swenshuai.xi		 !truncate(FILE, $where) ) {
252*53ee8cc1Swenshuai.xi		die "$name: Failed to truncate modified file: $f: $!\n";
253*53ee8cc1Swenshuai.xi	    }
254*53ee8cc1Swenshuai.xi	}
255*53ee8cc1Swenshuai.xi    }
256*53ee8cc1Swenshuai.xi
257*53ee8cc1Swenshuai.xi    close(FILE);
258*53ee8cc1Swenshuai.xi}
259