#!/usr/bin/perl -w

use strict;

sub rpmq {
  my $rpm = shift;
  my @stags = @_;
  my %stags = map {0+$_ => $_} @stags; 

  my ($magic, $sigtype, $headmagic, $cnt, $cntdata, $lead, $head, $index, $data, $tag, $type, $offset, $count);

  local *RPM;
  if (ref($rpm) eq 'GLOB') {
    *RPM = $rpm;
  } elsif (!open(RPM, '<', $rpm)) {
    warn("$rpm: $!\n");
    return ();
  }
  if (read(RPM, $lead, 96) != 96) {
    warn("Bad rpm $rpm\n");
    close RPM;
    return ();
  }
  ($magic, $sigtype) = unpack('N@78n', $lead);
  if ($magic != 0xedabeedb || $sigtype != 5) {
    warn("Bad rpm $rpm\n");
    close RPM;
    return ();
  }
  if (read(RPM, $head, 16) != 16) {
    warn("Bad rpm $rpm\n");
    close RPM;
    return ();
  }
  ($headmagic, $cnt, $cntdata) = unpack('N@8NN', $head);
  if ($headmagic != 0x8eade801) {
    warn("Bad rpm $rpm\n");
    close RPM;
    return ();
  }
  if (read(RPM, $index, $cnt * 16) != $cnt * 16) {
    warn("Bad rpm $rpm\n");
    close RPM;
    return ();
  }
  $cntdata = ($cntdata + 7) & ~7;
  if (read(RPM, $data, $cntdata) != $cntdata) {
    warn("Bad rpm $rpm\n");
    close RPM;
    return ();
  }
  if (read(RPM, $head, 16) != 16) {
    warn("Bad rpm $rpm\n");
    close RPM;
    return ();
  }
  ($headmagic, $cnt, $cntdata) = unpack('N@8NN', $head);
  if ($headmagic != 0x8eade801) {
    warn("Bad rpm $rpm\n");
    close RPM;
    return ();
  }
  if (read(RPM, $index, $cnt * 16) != $cnt * 16) {
    warn("Bad rpm $rpm\n");
    close RPM;
    return ();
  }
  if (read(RPM, $data, $cntdata) != $cntdata) {
    warn("Bad rpm $rpm\n");
    close RPM;
    return ();
  }
  close RPM;
  my %res = ();
  while($cnt-- > 0) {
    ($tag, $type, $offset, $count, $index) = unpack('N4a*', $index);
    $tag = 0+$tag;
    if ($stags{$tag}) {
      eval {
        my $otag = $stags{$tag};
        if ($type == 0) {
          $res{$otag} = [ '' ];
        } elsif ($type == 1) {
          $res{$otag} = [ unpack("\@${offset}c$count", $data) ];
        } elsif ($type == 2) {
          $res{$otag} = [ unpack("\@${offset}c$count", $data) ];
        } elsif ($type == 3) {
          $res{$otag} = [ unpack("\@${offset}n$count", $data) ];
        } elsif ($type == 4) {
          $res{$otag} = [ unpack("\@${offset}N$count", $data) ];
        } elsif ($type == 5) {
          $res{$otag} = [ undef ];
        } elsif ($type == 6) {
          $res{$otag} = [ unpack("\@${offset}Z*", $data) ];
        } elsif ($type == 7) {
          $res{$otag} = [ unpack("\@${offset}a$count", $data) ];
        } elsif ($type == 8 || $type == 9) {
          my $d = unpack("\@${offset}a*", $data);
          my @res = split("\0", $d, $count + 1);
          $res{$otag} = [ splice @res, 0, $count ];
        } else {
          $res{$otag} = [ undef ];
        }
      };
      if ($@) {
        warn("Bad rpm $rpm: $@\n");
        return ();
      }
    }
  }
  return %res;
}

sub rpmq_add_flagsvers {
  my $res = shift;
  my $name = shift;
  my $flags = shift;
  my $vers = shift;

  return unless $res;
  my @flags = @{$res->{$flags} || []};
  my @vers = @{$res->{$vers} || []};
  for (@{$res->{$name}}) {
    if (@flags && ($flags[0] & 0xe) && @vers) {
      $_ .= ' ';
      $_ .= '<' if $flags[0] & 2;
      $_ .= '>' if $flags[0] & 4;
      $_ .= '=' if $flags[0] & 8;
      $_ .= " $vers[0]";
    }
    shift @flags;
    shift @vers;
  }
}

######################################################################

my $rpmdepfile = $ARGV[0];

my %oldp;
my %oldr;
if (defined($rpmdepfile) && open(F, '<', $rpmdepfile)) {
  while (<F>) {
    chomp;
    if (/^P:([^ ]): /) {
      $oldp{$1} = $_;
    } elsif (/^R:([^ ]): /) {
      $oldr{$1} = $_;
    }
  }
  close F;
}

my $redo = 1;
while ($redo) {
  $redo = 0;
  my $packages;
  my @known;
  my %known2fn;
  my %known2path;
  my %fnsize2id;
  while (<STDIN>) {
    chomp;
    if ($_ eq '') {
      # next block;
      $redo = 1;
      last;
    }
    if (/\/packages$/) {
      $packages = $_;
      next;
    }
    next unless /^(\d+\/\d+\/\d+) (.*)$/;
    my $id = $1;
    my $path = $2;
    next unless $path =~ /\.rpm$/;
    my $fn = $path;
    $fn =~ s/.*\///;
    next if $fn =~ /\.(?:patch|delta)\.rpm$/;
    my ($r, $arch);
    if ($fn =~ /^(.*)-[^-]+-[^-]+\.([^\. ]+)\.rpm$/) {
      $r = $1;
      $arch = $2;
    } elsif ($path =~ /^(?:.*\/)?([^\/ ]+)\/([^\/ ]+)\.rpm$/) {
      #next if $1 eq '.';
      $r = $2;
      $arch = $1;
    } else {
      next;
    }
    next if $arch eq 'src' || $arch eq 'nosrc';
    push @known, "$r.$arch-$id";
    $known2fn{"$r.$arch-$id"} = $fn;
    $known2path{"$r.$arch-$id"} = $path;
    my $size = (split('/', $id))[1];
    $fnsize2id{"$fn-$size"} = $id;
  }

  my %newp;
  my %newr;
  for (@known) {
    $newp{$_} = $oldp{$_} if $oldp{$_};
    $newr{$_} = $oldr{$_} if $oldr{$_};
  }

  my @todo = grep {!($newp{$_} && $newr{$_})} @known;
  if (@todo && $packages && open(F, '<', $packages)) {
    my ($pack, $vers, $rel, $btime, $arch, $loc, $id, $size);
    my ($req, $prv);
    while (<F>) {
      chomp;
      next unless /^[=+]/;
      my ($tag, $data);
      if (/^\+(.*)$/) {
	$tag = $1;
	$data = '';
	while (<F>) {
	  chomp;
	  last if $_ eq "-$tag";
	  $data .= "$_\n";
	}
	chop $data;
      } else {
	($tag, $data) = split(' ', $_, 2);
	$tag = substr($tag, 1);
      }
      if ($tag eq 'Pkg:') {
	if ($pack && $loc && $size) {
	  my $id = $fnsize2id{"$loc-$size"};
	  if ($id && $known2path{"$pack.$arch-$id"}) {
	    $prv = "$pack = $vers-$rel" unless defined $prv;
	    $req = '' unless defined $req;
	    $newp{"$pack.$arch-$id"} = "P:$pack.$arch-$id: $prv";
	    $newr{"$pack.$arch-$id"} = "R:$pack.$arch-$id: $req";
	  }
	}
	($pack, $vers, $rel, $arch) = split(' ', $data);
	undef $req;
	undef $prv;
	undef $btime;
	undef $size;
	undef $loc;
	undef $pack if $arch && ($arch eq 'src' || $arch eq 'nosrc');
      } elsif ($tag eq 'Req:') {
	next unless $pack;
	$data =~ s/\n/ /gs;
	$req = $data;
      } elsif ($tag eq 'Prv:') {
	next unless $pack;
	# add self provides for old rpm versions
	$data = "$pack = $vers-$rel\n$data" unless "\n$data" =~ /\n\Q$pack\E =/s;
	$data =~ s/\n/ /gs;
	$prv = $data;
      } elsif ($tag eq 'Tim:') {
	$btime = $data;
      } elsif ($tag eq 'Loc:') {
	my @data = split(' ', $data);
	$loc = $data[1];
      } elsif ($tag eq 'Siz:') {
	my @data = split(' ', $data);
	$size = $data[0];
      }
    }
    close F;
    if ($pack && $loc && $size) {
      my $id = $fnsize2id{"$loc-$size"};
      if ($id && $known2path{"$pack.$arch-$id"}) {
	$newp{"$pack.$arch-$id"} = "P:$pack.$arch-$id: $prv";
	$newr{"$pack.$arch-$id"} = "R:$pack.$arch-$id: $req";
      }
    }
    @todo = grep {!($newp{$_} && $newr{$_})} @known;
  }
  if (@todo) {
    for my $known (@todo) {
      my $path = $known2path{$known};
      my %res = rpmq($path, 1000, 1022, 1047, 1049, 1048, 1050, 1112, 1113);
      next unless %res;
      rpmq_add_flagsvers(\%res, 1047, 1112, 1113);
      rpmq_add_flagsvers(\%res, 1049, 1048, 1050);
      my $id = $known;
      $id =~ s/.*-//;
      if ($known ne "$res{1000}->[0].$res{1022}->[0]-$id") {
	$known = "$res{1000}->[0].$res{1022}->[0]-$id";
	if (!$known2path{$known}) {
	  push @known, $known;
	  $known2path{$known} = $path;
	}
      }
      $newp{$known} = "P:$known: ".join(' ', @{$res{1047} || []});
      $newr{$known} = "R:$known: ".join(' ', @{$res{1049} || []});
    }
  }
  @known = grep {$newp{$_} && $newr{$_}} @known;
  for (@known) {
    print "F:$_: $known2path{$_}\n";
    print "$newp{$_}\n";
    print "$newr{$_}\n";
  }
}
