############################################################################### # Codestriker: Copyright (c) 2001, 2002, 2003 David Sitsky. # All rights reserved. # sits@users.sourceforge.net # # This program is free software; you can redistribute it and modify it under # the terms of the GPL. # Utility object for reading basic diffs. package Codestriker::FileParser::BasicDiffUtils; use strict; # Read from the file the next basic diff chunk, and return it. sub read_diff_text($$$$$$) { my ($type, $fh, $first_line, $filename, $revision, $repmatch) = @_; my $line = $first_line; # For this chunk, determine how many old lines and new lines are in # the chunk. my $old_linenumber = 0; my $new_linenumber = 0; my $old_length = 0; my $new_length = 0; if ($line =~ /^(\d+)a(\d+),(\d+)$/o || $line =~ /^\-\-\-\-\-\[after (\d+) inserted(?:\/moved)? (\d+)\-(\d+)(?: \(was at [\d\-]+\))?\]\-\-\-\-\-\s*$/o) { # Added multiple lines of text. $old_linenumber = $1+1; $new_linenumber = $2; $new_length = $3 - $2 + 1; } elsif ($line =~ /^(\d+)a(\d+)$/o || $line =~ /^\-\-\-\-\-\[after (\d+) inserted(?:\/moved)? (\d+)(?: \(was at [\d\-]+\))?\]\-\-\-\-\-\s*$/o) { # Added a single line of text. $old_linenumber = $1+1; $new_linenumber = $2; $new_length = 1; } elsif ($line =~ /^(\d+),(\d+)d(\d+)$/o || $line =~ /^\-\-\-\-\-\[deleted(?:\/moved)? (\d+)\-(\d+) after (\d+)(?: \(now at [\d\-]+\))?\]\-\-\-\-\-\s*$/o) { # Multiple lines deleted. $old_linenumber = $1; $new_linenumber = $3+1; $old_length = $2 - $1 + 1; } elsif ($line =~ /^(\d+)d(\d+)$/o || $line =~ /^\-\-\-\-\-\[deleted(?:\/moved)? (\d+) after (\d+)(?: \(now at [\d\-]+\))?\]\-\-\-\-\-\s*$/o) { # Single line deleted. $old_linenumber = $1; $new_linenumber = $2+1; $old_length = 1; } elsif ($line =~ /^(\d+),(\d+)c(\d+),(\d+)$/o || $line =~ /^\-\-\-\-\-\[(\d+)\-(\d+) changed to (\d+)\-(\d+)\]\-\-\-\-\-\s*$/o) { # Multiple text lines changed. $old_linenumber = $1; $new_linenumber = $3; $old_length = $2 - $1 + 1; $new_length = $4 - $3 + 1; } elsif ($line =~ /^(\d+)c(\d+),(\d+)$/o || $line =~ /^\-\-\-\-\-\[(\d+) changed to (\d+)\-(\d+)\]\-\-\-\-\-\s*$/o) { # Multiple source lines changed to single line. $old_linenumber = $1; $new_linenumber = $2; $old_length = 1; $new_length = $3 - $2 + 1; } elsif ($line =~ /^(\d+),(\d+)c(\d+)$/o || $line =~ /^\-\-\-\-\-\[(\d+)\-(\d+) changed to (\d+)\]\-\-\-\-\-\s*$/o) { # Single source line changed to multiple lines. $old_linenumber = $1; $new_linenumber = $3; $old_length = $2 - $1 + 1; $new_length = 1; } elsif ($line =~ /^(\d+)c(\d+)$/o || $line =~ /^\-\-\-\-\-\[(\d+) changed to (\d+)\]\-\-\-\-\-\s*$/o) { # Single line changed to another line. $old_linenumber = $1; $new_linenumber = $2; $old_length = 1; $new_length = 1; } else { # Some other file format. return undef; } # The chunk in unidiff format. my $chunk_text = ""; # First read the old lines, if any. for (my $i = 0; $i < $old_length; $i++) { $line = <$fh>; if (defined $line && $line =~ /^\< (.*)$/) { $chunk_text .= "-${1}\n"; } else { # Some other format. return undef; } } # If there is both old and new text, read the separator line. # Note bloody VSS for some versions will put the --- at the end of # the previous line rather than on a new line! if ($old_length > 0 && $new_length > 0) { my $previous_line = $line; my $pos = $fh->getpos; $line = <$fh>; return undef unless defined $line; if ($line !~ /^\-\-\-$/o && $chunk_text =~ /^(.*)\-\-\-$/os) { # Stupid VSS diff format, chop off the seperator characters # and move the file pointer back. $chunk_text = "$1\n"; $fh->setpos($pos); } elsif ($line !~ /^\-\-\-$/o) { # Didn't match standard separator, some other format. return undef; } } # Now read the new lines, if any. for (my $i = 0; $i < $new_length; $i++) { $line = <$fh>; if (defined $line && $line =~ /^\> (.*)$/) { $chunk_text .= "+${1}\n"; } else { # Some other format. return undef; } } # Now create the chunk object, and return it. my $chunk = {}; $chunk->{filename} = $filename; $chunk->{revision} = $revision; $chunk->{old_linenumber} = $old_linenumber; $chunk->{new_linenumber} = $new_linenumber; $chunk->{binary} = 0; $chunk->{text} = $chunk_text; $chunk->{description} = ""; $chunk->{repmatch} = $repmatch; return $chunk; } 1;