#!/usr/bin/perl -w

=head1 NAME

import.pl

=head1 SYNOPSIS

import.pl [options] /path/to/xen

Options:

    -h,--help		Display brief help message
    -v,--verbose	Increase verbosity
    -q,--quiet		Decrease verbosity

=cut

use File::Spec::Functions qw ( :ALL );
use File::Find;
use File::Path;
use Getopt::Long;
use Pod::Usage;
use FindBin;
use strict;
use warnings;

my $verbosity = 0;

sub try_import_file {
  my $ipxedir = shift;
  my $xendir = shift;
  my $filename = shift;

  # Skip everything except headers
  return unless $filename =~ /\.h$/;

  # Search for importable header
  ( undef, my $subdir, undef ) = splitpath ( $filename );
  my $outfile = catfile ( $ipxedir, $filename );
  my $infile = catfile ( $xendir, "xen/include/public", $filename );
  die "$infile does not exist\n" unless -e $infile;

  # Import header file
  print "$filename <- ".catfile ( $xendir, $filename )."\n"
      if $verbosity >= 1;
  open my $infh, "<", $infile or die "Could not open $infile: $!\n";
  mkpath ( catdir ( $xendir, $subdir ) );
  open my $outfh, ">", $outfile or die "Could not open $outfile: $!\n";
  my @dependencies = ();
  my $maybe_guard;
  my $guard;
  while ( <$infh> ) {
    # Strip CR and trailing whitespace
    s/\r//g;
    s/\s*$//g;
    chomp;
    # Update include lines, and record included files
    if ( /^\#include\s+[<\"](\S+)[>\"]/ ) {
      push @dependencies, catfile ( $subdir, $1 );
    }
    # Patch "Unsupported architecture" line
    if ( /^\#error\s+"Unsupported\sarchitecture"/ ) {
      $_ = "#include <bits/xen.h>"
    }
    # Write out line
    print $outfh "$_\n";
    # Apply FILE_LICENCE() immediately after include guard
    if ( defined $maybe_guard ) {
      if ( /^\#define\s+_+${maybe_guard}_H_*$/ ) {
	die "Duplicate header guard detected in $infile\n" if $guard;
	$guard = $maybe_guard;
	print $outfh "\nFILE_LICENCE ( MIT );\n";
      }
      undef $maybe_guard;
    }
    if ( /^#ifndef\s+_+(\S+)_H_*$/ ) {
      $maybe_guard = $1;
    }
  }
  close $outfh;
  close $infh;
  # Warn if no header guard was detected
  warn "Cannot detect header guard in $infile\n" unless $guard;
  # Recurse to handle any included files that we don't already have
  foreach my $dependency ( @dependencies ) {
    if ( ! -e catfile ( $ipxedir, $dependency ) ) {
      print "...following dependency on $dependency\n" if $verbosity >= 1;
      try_import_file ( $ipxedir, $xendir, $dependency );
    }
  }
  return;
}

# Parse command-line options
Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
GetOptions (
  'verbose|v+' => sub { $verbosity++; },
  'quiet|q+' => sub { $verbosity--; },
  'help|h' => sub { pod2usage ( 1 ); },
) or die "Could not parse command-line options\n";
pod2usage ( 1 ) unless @ARGV == 1;
my $xendir = shift;

# Identify Xen import directory
die "Directory \"$xendir\" does not appear to contain the Xen source tree\n"
    unless -e catfile ( $xendir, "xen/include/public/xen.h" );

# Identify iPXE Xen includes directory
my $ipxedir = $FindBin::Bin;
die "Directory \"$ipxedir\" does not appear to contain the iPXE Xen includes\n"
    unless -e catfile ( $ipxedir, "../../include/ipxe" );

print "Importing Xen headers into $ipxedir\nfrom $xendir\n"
    if $verbosity >= 1;

# Import headers
find ( { wanted => sub {
  try_import_file ( $ipxedir, $xendir, abs2rel ( $_, $ipxedir ) );
}, no_chdir => 1 }, $ipxedir );
