############################################################################### # 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. # Parser object for reading the output for a perforce diff command, such # as: # # p4 diff -du # package Codestriker::FileParser::PerforceDiff; use strict; use Codestriker::FileParser::UnidiffUtils; sub _make_chunk ($); sub _retrieve_file ($$); # Return the array of filenames, revision number, linenumber, whether its # binary or not, and the diff text. # Return () if the file can't be parsed, meaning it is in another format. sub parse ($$$) { my ($type, $fh, $repository) = @_; # Skip initial whitespace. my $line = <$fh>; while (defined($line) && $line =~ /^\s*$/) { $line = <$fh>; } # Array of results found. my @result = (); # Assume the repository matches this diff, unless we find evidence to # the contrary. my $repmatch = 1; # Now read the actual diff chunks. while (defined($line)) { if ($line =~ /^==== (.*)\#(\d+) \- .* ==== \((.*)\)$/) { my $filename = $1; my $revision = $2; my $file_type = $3; if ($file_type eq "ubinary" || $file_type eq "xbinary" || $file_type eq "binary") { # Binary file, skip the next line and add the record in. $line = <$fh>; my $chunk = {}; $chunk->{filename} = $filename; $chunk->{revision} = $revision; $chunk->{old_linenumber} = -1; $chunk->{new_linenumber} = -1; $chunk->{binary} = 1; $chunk->{text} = ""; $chunk->{description} = ""; $chunk->{repmatch} = $repmatch; push @result, $chunk; } elsif ($file_type eq "text") { # Note there may be an optional '---' and '+++' lines # before the chunk. my $lastpos = tell $fh; if (<$fh> !~ /^\-\-\-/ || <$fh> !~ /^\+\+\+/) { # Move the file pointer back. seek $fh, $lastpos, 0; } my @file_diffs = Codestriker::FileParser::UnidiffUtils-> read_unidiff_text($fh, $filename, $revision, $repmatch); push @result, @file_diffs; } else { # Got knows what this is, can't parse it. return (); } } elsif ($line =~ /^==== (.*)\#(\d+) \-/) { my $filename = $1; my $revision = $2; # Now read the entire diff chunk (it may be empty if the # user hasn't actually modified the file). Note there # may be an optional '---' and '+++' lines before the # chunk. my $lastpos = tell $fh; if (<$fh> !~ /^\-\-\-/ || <$fh> !~ /^\+\+\+/) { # Move the file pointer back. seek $fh, $lastpos, 0; } my @file_diffs = Codestriker::FileParser::UnidiffUtils-> read_unidiff_text($fh, $filename, $revision, $repmatch); push @result, @file_diffs; } else { # Can't parse this file. return (); } # Now read the next chunk. $line = <$fh> if defined $line; } # Return the found diff chunks. return @result; } 1;