#!/usr/bin/perl

use strict;
use warnings;

use File::Basename;
use File::Copy;
use File::Temp qw/ tempdir /;
use File::Slurp;

my $tmpd = tempdir("header_check_XXXXXX", TMPDIR => 1, CLEANUP => 1);
#print "$tmpd\n";

my %candidates;
my $candidate_file = shift
    or die "use: $0 candidate_file <file1.c> <file2.c> ...";

open(my $fh, '<', $candidate_file)
    or die "unable to open $candidate_file";
while (<$fh>) {
    chomp;
    my ($cfile, $hfile) = split;
    push @{$candidates{$cfile}}, $hfile;
}


for (sort @ARGV) {
    do_file($_);
}

sub do_file {
    my $cfile = shift;
    my $ofile = $cfile;
    $ofile =~ s/\.c/.o/;
    my $cmdfile = dirname($ofile) . '/.' . basename($ofile) . '.cmd';
    my $bofile = basename($ofile);
    my $bcmdfile = basename($cmdfile);
    my $origsrc = read_file($cfile);

    make($ofile);
    if ($? != 0) {
	printf STDERR "initial make of ${ofile} failed\n";
	return;
    }
    copy($ofile, $tmpd);
    my $dep_len = wc_l($cmdfile);

    for my $h (@{$candidates{$cfile}}) {
	my $src = $origsrc;
	if (not $src =~ s@^(\s*#\s*include\s+[<"]${h}[">])@// $1@gm) {
	    printf STDERR "%s apparently not included from %s ??\n", $h, $cfile;
	    next;
	}
	write_file($cfile, $src);
	make($ofile);
	if ($?) {
	    printf "%s\t%s\tfalse positive\n", $cfile, $h;
	    next;
	}
	my $cmp_obj = compare_object_files("${tmpd}/$bofile", $ofile);
	my $cmp_dep = $dep_len - wc_l($cmdfile);
	printf "%s\t%s\t%s\t%d\n", $cfile, $h, $cmp_obj, $cmp_dep;
    }

    write_file($cfile, $origsrc);
}


sub make {
    my $tgt = shift;
    unlink($tgt);
    system("make ${tgt} > /dev/null 2> /dev/null");
}

sub compare_object_files {
    my $o1 = shift;
    my $o2 = shift;
    system("cmp -s -- $o1 $o2");
    return 'byte-identical' if ($? == 0);
    system("/bin/bash -c 'cmp -s <(objdump -d $o1 | grep -v \"file format\") <(objdump -d $o2 | grep -v \"file format\") '");
    return 'objdump-identical' if ($? == 0);
    return 'different object-code';
}

sub wc_l {
    my $f = shift;
    return scalar (() = read_file($f));
}