fixup.cc5711424b7ae36276a40c06ede5d95f87ca20f0
[git/dscho.git] / my-un-cvs-damage-diff.perl
blobe042c2df038c2829aef37200040d43eeb3336734
1 #!/usr/bin/perl
3 # This is a simple state machine.
5 # There is the state of the current file; its header is stored
6 # in $current_file to avoid outputting it when all hunks were
7 # culled. It is only printed before the first hunk, and then
8 # set to "" to avoid outputting it twice.
10 # There are the states of the current hunk, stored in
11 # * $current_hunk (possibly modified hunk)
12 # * $start_minus, $start_plus (from the original)
13 # * $plus, $minus, $space (the current count of the respective lines)
14 # a hunk is only printed (in flush_hunk) if any '+' or '-' lines
15 # are left after filtering.
17 # For $Log..$, there is the state $skip_logs, which is set to 1
18 # after seeing such a line, and set to 0 when the first line
19 # was seen which does not begin with '+'.
21 # A particularly nasty special case is when a single "*" was
22 # misattributed by the diff to be _inserted before_ a $Log, instead
23 # of _appended after_ a $Log.
24 # This is the purpose of the $before_log and $after_log variables:
25 # if not empty, the state machine expects the next line to begin
26 # with '+' or '-', respectively, and followed by a $Log. If this
27 # expectation is not met, the variable is output.
29 # The variable $plus_minus_adjust contains the number of lines which
30 # were skipped from the "+" side, so that the correct offset is shown.
33 # This function gets a hunk header.
35 # It initializes the state variables described above
37 sub init_hunk {
38 my $line = $_[0];
39 $current_hunk = "";
40 ($start_minus, $dummy, $start_plus, $dummy) =
41 ($line =~ /^\@\@ -(\d+)(,\d+|) \+(\d+)(,\d+|) \@\@/);
42 $plus = $minus = $space = 0;
43 $skip_logs = 0;
44 $before_log = '';
45 $after_log = '';
47 # we prefer /dev/null as original file name when a file is new
48 if ($start_minus eq 0) {
49 $current_file =~ s/\n--- .*\n/\n--- \/dev\/null\n/;
50 } elsif ($start_plus eq 0) {
51 $current_file =~ s/\n\+\+\+ .*\n/\n+++ \/dev\/null\n/;
55 # This function is called whenever there is possibly a hunk to print.
56 # Nothing is printed if no '+' or '-' lines are left.
57 # Otherwise, if the file header was not yet shown, it does so now.
59 sub flush_hunk {
60 if (($plus > 0 || $minus > 0) && $current_hunk ne '') {
61 if ($current_file ne "") {
62 print $current_file;
63 $current_file = "";
65 $minus += $space;
66 $plus += $space;
67 print "\@\@ -$start_minus,$minus "
68 . "+" . ($start_plus - $start_plus_adjust)
69 . ",$plus \@\@\n";
70 print $current_hunk;
71 $current_hunk = '';
75 # This adds a line to the current hunk and updates $space, $plus or $minus
77 sub add_line {
78 my $line = $_[0];
79 $current_hunk .= $line;
80 if ($line =~ /^ /) {
81 $space++;
82 } elsif ($line =~ /^\+/) {
83 $plus++;
84 } elsif ($line =~ /^-/) {
85 $minus++;
86 } elsif ($line =~ /^\\/) {
87 # do nothing
88 } else {
89 die "Unexpected line: $line";
93 # This function splits the current hunk into the part before the current
94 # line, and the part after the current line.
96 sub skip_line {
97 my $line = $_[0];
99 if ($start_minus == 0) {
100 # This patch adds a new file, just ignore that line
101 return;
102 } elsif ($start_plus == 0) {
103 # This patch removes a file, so include the line nevertheless
104 add_line $_;
105 return;
108 flush_hunk;
109 if ($line =~ /^-/) {
110 $minus++;
111 } elsif ($line =~ /^\+/) {
112 $plus++;
113 $start_plus_adjust++;
115 init_hunk "@@ -" . ($start_minus + $minus + $space)
116 . " +" . ($start_plus + $plus + $space)
117 . " @@\n";
120 $simple_keyword = "Id|Revision|Author|Date|Source|Header";
122 # This is the main loop
124 sub check_file {
125 $_ = $_[0];
126 $current_file = $_;
127 $start_plus_adjust = 0;
128 while (<>) {
129 if (/^\@\@/) {
130 last;
132 $current_file .= $_;
135 init_hunk $_;
137 # check hunks
138 while (<>) {
139 if ($before_log) {
140 if (!/\+.*\$Log.*\$/) {
141 add_line $before_log;
142 } else {
143 skip_line $before_log;
145 $before_log = '';
148 if ($after_log) {
149 if (!/-.*\$Log.*\$/) {
150 add_line $after_log;
151 } else {
152 skip_line $after_log;
154 $after_log = '';
157 if ($skip_logs) {
158 if (/^\+/) {
159 skip_line $_;
160 $skip_logs = 1;
161 } else {
162 $skip_logs = 0;
163 if (/^ *\*$/) {
164 $after_log = $_;
167 } elsif (/^\+.*\$($simple_keyword).*\$/) {
168 skip_line $_;
169 } elsif (/^\@\@.*/) {
170 flush_hunk;
171 init_hunk $_;
172 } elsif (/^diff/) {
173 flush_hunk;
174 return;
175 } elsif (/^-.*\$($simple_keyword).*\$/) {
176 # fake new hunk
177 skip_line $_;
178 } elsif (/^\+ *\*$/) {
179 $before_log = $_;
180 } elsif (/^([- \+]).*\$Log.*\$/) {
181 skip_line $_;
182 $skip_logs = 1;
183 } else {
184 add_line $_;
189 # This loop just shows everything before the first diff, and then hands
190 # over to check_file whenever it sees a line beginning with "diff".
192 while (<>) {
193 if (/^diff/) {
194 do {
195 check_file $_;
196 } while(/^diff/);
197 } else {
198 printf $_;
201 flush_hunk;