<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">#!/usr/bin/perl

$VERSION='1.0';

use Getopt::Std;
use Algorithm::Diff qw(traverse_sequences);

getopts('ucbtw');

undef $opt_c if $opt_u;

while(1) {
  # skip garbage
  while(1) {
    if(/^[-*]{3} /)
    {
      $_.=&lt;&gt;;
      last if /^\*\*\* .*\n--- / || /^--- .*\n\+\+\+ /;
    }
    print;
    exit 0 unless $_=&lt;&gt;;
  };
  # print header
  if($opt_c) {
    s/^... /*** /; s/\n... /\n--- /;
  } else {
    s/^... /--- /; s/\n... /\n+++ /;
  }
  $output=$_;
  while(1) {
    # get hunk
    $_=&lt;&gt;;
    if(/^@@ -(\d+),(\d+) \+(\d+),(\d+) @@\n$/) {
      #unified hunk
      $S='';
      ($os, $ol, $ns, $nl)=($1,$2,$3,$4);
      $oe=$os+$ol-1;
      $ne=$ns+$nl-1;
      @o=@n=();
      while($ol &gt; @o || $nl &gt; @n) {
        $a=expand($_=getln());
        push @o, $a if /^[- ]/;
        push @n, $a if /^[+ ]/;
      }
      die "Corrupted diff 1 ($#o,$#n): $. =&gt; $_" unless $ol == @o &amp;&amp; $nl == @n;
    } elsif($_ eq "***************\n") {
      # context hunk
      $S=' ';
      die "Corrupted diff 2: $. =&gt; $_" unless $_=&lt;&gt;;
      die "Corrupted diff 3: $. =&gt; $_" unless /^\*\*\* (\d+),(\d+) \*\*\*\*\n/;
      ($os,$oe)=($1,$2);
      $ol=$oe-$os;
      @o=();
      push @o, expand($_=getln()) while($ol &gt; $#o);
      die "Corrupted diff 4: $. =&gt; $_" unless $_=&lt;&gt;;
      die "Corrupted diff 5: $. =&gt; $_" unless /^--- (\d+),(\d+) ----\n/;
      ($ns,$ne)=($1,$2);
      $nl=$ne-$ns;
      @n=();
      push @n, expand($_=getln()) while($nl &gt; $#n);
    } else {
      last;
    }
    # output
    @retval=();
    $hunk=[], $m=0;

sub discard { unless ($m) { $m=1; push @retval, $hunk; $hunk=[]; } push @$hunk, ['-', $_[1]] }
sub add     { unless ($m) { $m=1; push @retval, $hunk; $hunk=[]; } push @$hunk, ['+', $_[1]] }
sub match   { if     ($m) { $m=0; push @retval, $hunk; $hunk=[]; } push @$hunk, [' ', $_[1]] }

    traverse_sequences( \@o, \@n,
            { MATCH =&gt; \&amp;match, DISCARD_A =&gt; \&amp;discard, DISCARD_B =&gt; \&amp;add },
            \&amp;diffpack );
    push @retval, $hunk;

# use Data::Dumper;
# $Data::Dumper::Terse=1;
# $Data::Dumper::Indent=1;
# print Dumper(\@retval);
    
    $hunks='';
    
    for $N (0..$#retval) {
      my $hunk=@retval[$N];
      my $hl=$#$hunk;
      my $a=$hunk-&gt;[0]-&gt;[0];
      my $b=$hunk-&gt;[$hl]-&gt;[0];
      $type=($a eq ' ' ? ' ' :
             $a eq '+' ? '+' :
             $b eq '-' ? '-' : '!');
      if ($type eq ' ') {
        print_lines(@$hunk[0..2]) if $N;
        ($N &amp;&amp; $hl &lt; 8)
        ? print_lines(@$hunk[3..$hl])
        : open_hunk(@$hunk[-3..-1]) if $N &lt; $#retval;
      } else {
        $N ? print_lines(@$hunk) : open_hunk(@$hunk);
      }
    }
    open_hunk();
  }
  print $output;
}

sub open_hunk {
  if ($hunks) {
    # closing previous hunk first
    if ($opt_c) {
      $output.= sprintf "***************\n*** %d,%d ****\n", $hos, $hos+$hol-1;
      $output.= $hunks;
      $output.= sprintf "--- %d,%d ----\n", $hns, $hns+$hnl-1;
      $output.= $hunks2;
    } else {
      $output.= sprintf "@@ -%d,%d +%d,%d @@\n", $hos, $hol, $hns, $hnl;
      $output.= $hunks;
    }
  }
  $hos=$hns=$hol=$hnl=0;
  $hunks=$hunks2='';
  for (reverse @_) {
    $hos=$_-&gt;[1] if $_-&gt;[0] ne '+';
    $hns=$_-&gt;[1] if $_-&gt;[0] ne '-';
  }
  $hos+=$os;
  $hns+=$ns;
  print_lines(@_);
}

sub print_lines {
  for (@_) {
    next unless $_;
         if ($_-&gt;[0] eq '+') {
      if ($opt_c) {
        $hunks2.="$type ".@n[$_-&gt;[1]];
      } else {
        $hunks.='+'.@n[$_-&gt;[1]];
      }
      $hnl++;
      unshift @o, "&lt;&lt;EOF&gt;&gt;\n";
    } elsif ($_-&gt;[0] eq '-') {
      if ($opt_c) {
        $hunks.="$type ".@o[$_-&gt;[1]];
      } else {
        $hunks.='-'.@o[$_-&gt;[1]];
      }
      shift @o;
      $hol++;
    } else {
      if ($opt_c) {
        $hunks.='  '.@o[$_-&gt;[1]];
        $hunks2.='  '.@o[$_-&gt;[1]];
      } else {
        $hunks.=' '.@o[$_-&gt;[1]];
      }
      $hol++;
      $hnl++;
    }
  }
}

sub expand {
  local $_=shift;
  die "Corrupted diff 6: $. =&gt; $_" unless s/^[-!+ ]$S//;
  if ($opt_t)
  {
    1 while s/^([^\t]*)(\t+)/$1.(" "x(length($2)*8-length($1)%8))/e;
  }
  $_;
}

sub diffpack {
  local $_=shift;
  if ($opt_b) {
    s/\s+/ /g;
    s/^ //;
    s/ $//;
  }
  s/\s//g if $opt_w;
  $_;
}

sub getln {
  local $_=&lt;&gt;;
  $_=" $S\n" if /^\n?$/;
  $_;
}

=head1 NAME

rediff - Diff format converted (unified &lt;-&gt; context).

=head1 README

Diff format converted (unified &lt;-&gt; context).
This script takes context or unified diff, and produces a diff,
that would be created by C&lt;diff&gt; program if it would be run with command-line
options passed to this script. C&lt;-c&gt;, C&lt;-u&gt;, C&lt;-b&gt;, C&lt;-w&gt;, C&lt;-t&gt; options are
supported. E.g. convert to unified diff with tabs expanded:

  rediff -ut &lt;old_diff &gt;new_diff

=head1 PREREQUISITES

Algorithm::Diff

=head1 SCRIPT CATEGORIES

UNIX/System_administration
VersionControl/CVS

=cut


</pre></body></html>