Alien-wxWidgets
view release on metacpan or search on metacpan
inc/bin/patch view on Meta::CPAN
while (<$in>) {
s/\s+/ /g if $self->{'ignore-whitespace'};
if ($_ eq $match->[0]) {
my $fail;
for (1..$#$match) {
my $line = <$in>;
$line =~ s/\s+/ /g if $self->{'ignore-whitespace'};
$line eq $match->[$_] or $fail++, last;
}
if ($fail) {
seek $in, $tell, 0 or throw "Couldn't seek INFILE: $!";
<$in>;
} else {
return ($tell, $line);
}
}
$line++;
$tell = tell $in;
}
return;
CATCH: $self->note($@), return;
}
package Patch::Context;
BEGIN { Patch->import }
# Convert hunk to unified diff, then apply.
sub apply {
my ($self, $i_start, $o_start, $i_hunk, $o_hunk) = @_;
my @hunk;
my @i_hunk = @$i_hunk;
my @o_hunk = @$o_hunk;
s/^(.) /$1/ for @i_hunk, @o_hunk;
while (@i_hunk and @o_hunk) {
my ($i, $o) = (shift @i_hunk, shift @o_hunk);
if ($i eq $o) {
push @hunk, $i;
next;
}
while ($i =~ s/^[!-]/-/) {
push @hunk, $i;
$i = shift @i_hunk;
}
while ($o =~ s/^[!+]/+/) {
push @hunk, $o;
$o = shift @o_hunk;
}
push @hunk, $i;
}
push @hunk, @i_hunk, @o_hunk;
$self->SUPER::apply($i_start, $o_start, @hunk);
}
# Check for filename in diff header, then in 'Index:' line.
sub rummage {
my ($self, $garbage) = @_;
my @files = grep -e, map $self->strip,
map /^\s*(?:\*\*\*|---) (\S+)/, @$garbage[-1, -2];
my $file =
@files == 1 ? $files[0] :
@files == 2 ? $files[length $files[0] > length $files[1]] :
$self->SUPER::rummage($garbage);
return $file;
}
package Patch::Ed;
BEGIN { Patch->import }
# Pipe ed script to ed or try to manually process.
sub apply {
my ($self, @cmd) = @_;
$self->{skip} and throw 'SKIP...ignore this patch';
my $out = $self->{o_fh};
$self->{check} and goto PLAN_J;
# We start out by adding a magic line to our output. If this line
# is still there after piping to ed, then ed failed. We do this
# because win32 will silently fail if there is no ed program.
my $magic = "#!/i/want/a/moogle/stuffy\n";
print $out $magic;
# Pipe to ed.
eval {
local $SIG{PIPE} = sub { die 'Pipe broke...' };
local $SIG{CHLD} = sub { die 'Bad child...' };
open ED, "| ed - -s $self->{i_file}" or die "Couldn't fork ed: $!";
print ED map @$_, @cmd or die "Couldn't print ed: $!";
print ED "1,\$w $self->{o_file}" or die "Couldn't print ed: $!";
close ED or die "Couldn't close ed: $?";
};
# Did pipe to ed work?
unless ($@ or <$out> ne $magic) {
$self->note("Hunk #$self->{hunk} succeeded at 1.\n");
return 1;
}
# Erase any trace of magic line.
truncate $out, 0 or throw "Couldn't truncate OUT: $!";
seek $out, 0, 0 or throw "Couldn't seek OUT: $!";
# Try to apply ed script by hand.
$self->note("Pipe to ed failed. Switching to Plan J...\n");
PLAN_J:
# Pre-process each ed command. Ed diffs are reversed (so that each
# command doesn't end up changing the line numbers of subsequent
# commands). But we need to apply diffs in a forward direction because
# our filehandles are oriented that way. So we calculate the @offset
# in line number that this will cause as we go.
my @offset;
for (my $i = 0; $i < @cmd; $i++) {
my @hunk = @{$cmd[$i]};
inc/bin/patch view on Meta::CPAN
print $def "#ifndef $ifdef\n";
print $def scalar <$in> for $start..$end;
print $def "#else\n";
print $out @$hunk;
$self->{i_lines} = $end;
}
print $def "#endif /* $ifdef */\n";
}
# Output any lines left in input handle.
print $out readline $in;
# Report success to user.
for (my $i = 0; $i < @cmd; $i++) {
$self->note(
'Hunk #', $i+1, ' succeeded at ',
$cmd[$i - not ref $cmd[$i]][0], "\n",
);
}
return 1;
# Or report failure.
CATCH:
$self->{skip}++ if $@ =~ /^SKIP/;
$self->note( $self->{skip}
? "Hunk #$self->{hunk} ignored at 1.\n"
: "Hunk #$self->{hunk} failed--$@"
);
return;
}
# End of patch clean up. $self->print_tail is omitted because ed diffs are
# applied all at once rather than one hunk at a time.
sub end {
my $self = shift;
return if $self->{skip};
$self->print_rejects;
$self->remove_empty_files;
}
package Patch::Normal;
BEGIN { Patch->import }
# Convert hunk to unified diff, then apply.
sub apply {
my ($self, $i_start, $o_start, $cmd, $d_hunk, $a_hunk) = @_;
$i_start++ if $cmd eq 'a';
$o_start++ if $cmd eq 'd';
my @hunk;
push @hunk, map "-$_", @$d_hunk;
push @hunk, map "+$_", @$a_hunk;
$self->SUPER::apply($i_start, $o_start, @hunk);
}
package Patch::Unified;
BEGIN { Patch->import }
# Check for filename in diff header, then in 'Index:' line.
sub rummage {
my ($self, $garbage) = @_;
my @files = grep -e, map $self->strip,
map /^\s*(?:---|\+\+\+) (\S+)/, @$garbage[-1, -2];
my $file =
@files == 1 ? $files[0] :
@files == 2 ? $files[length $files[0] > length $files[1]] :
$self->SUPER::rummage($garbage);
return $file;
}
package Pushback;
# Create filehandles that can unread or push lines back into queue.
sub TIEHANDLE {
my ($class, $file) = @_;
local *FH;
open *FH, "< $file" or return;
binmode FH;
bless [*FH], $class;
}
sub READLINE {
my $self = shift;
@$self == 1 ? readline $self->[0] : pop @$self;
}
sub PRINT {
my $self = shift;
$self->[1] = shift;
}
sub CLOSE {
my $self = shift;
$self = undef;
}
package Dev::Null;
# Create filehandles that go nowhere.
sub TIEHANDLE { bless \my $null }
sub PRINT {}
sub PRINTF {}
sub WRITE {}
sub READLINE {''}
sub READ {''}
sub GETC {''}
__END__
=head1 NAME
patch - apply a diff file to an original
=head1 SYNOPSIS
( run in 2.491 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )