#!/usr/bin/env perl
use File::Basename;
use Cwd 'realpath';

sub setup{
    $script_home=dirname  $0;
    $script_name=basename $0;

    $debug=0;
    $debug=1 if($script_name eq 'c-scriptd');
    $debug=2 if($script_name eq 'c-scriptddd');


    if($debug){
	for(@ARGV){
	    if( -f $_){
		$in=$_;
		last;
	    }
	}
    }else{
	$in=realpath(shift @ARGV);
    }


    $run_dir=dirname $in;
    $home=$ENV{HOME}."/.c-script";
}

sub getlib{
    my $path=shift;
    my @g=glob($path);
    my $g=$g[0];
    if(! -f $g){
	return "";
    }else{
	$g=basename $g;
	$g=~ s/^lib//g;
	$g=~ s/\.so$//g;
	$g=~ s/\.a$//g;
	return "-l".$g."\n";
    }
}

sub eval_init{
    if(-e "$home/init.pl"){
	do "$home/init.pl";
    }else{
	do "$script_home/init.pl";
    }

    $normal_opt =~ s/\n/ /g;
    $debug_opt =~ s/\n/ /g;
    $opt =~ s/\n/ /g;
    $libs =~ s/\n/ /g;
    
    if($debug){
	$opt=$debug_opt.' '.$opt;
    }else{
	$opt=$normal_opt.' '.$opt;
    }
}

sub modtime{
    my $filepath=shift;
    my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,
	$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($filepath);
    return $mtime;
}


sub gen_exe{
    my ($in,$inc,$src)=@_;
    my ($s)=split ' ',`echo $in $inc $src | md5sum `;
    my ($suffix)=($in =~ /(\.[^.]*$)/);
    my $h=$home."/cache";
    `mkdir -p $h` if( ! -e $h);
    return ($h.'/'.$s.$debug,$suffix);
}

sub gen_exename{
    my ($exe,$suffix)=gen_exe $in,$inc,$src;
    
    if($debug){
	for(@ARGV){
	    if( -f $_){
		$_=$exe;
		last;
	    }
	}
    }

    return ($exe.$suffix,$exe);
}

sub gen_src{
    my ($in,$mod_in)=@_;
    my $line;
    open IN,"<$in";
    open OUT,">$mod_in";
    print OUT "#include <c-script.h>\n";
    print OUT "#line 1  \"$in\"\n";
    while(<IN>){
	if(/^#!.*/){
	    print OUT "\n";
	}elsif(/^#pragma\s+c-script.*$/){
	    print OUT "\n";
	}else{
	    print OUT $_;
	}
    }
    close OUT;
}

sub getparam{
    my $file=shift;
    local *IN;
    open IN,"<$file";
    while(<IN>){
	if(/^#pragma\s+c-script:src\s+(.*)/){
	    $src.=" ".realpath($1);
	}elsif(/^#pragma\s+c-script:opt\s+(.*)/){
	    $opt.=" ".$1;
	}elsif(/^#pragma\s+c-script:cc\s+(.*)/){
	    $cc=$1;
	}elsif(/^#pragma\s+c-script:libs\s+(.*)/){
	    $libs.=" ".$1;
	}elsif(/^#include\s+"([^"]+)/){
	    $inc.=" ".realpath($1);
	}
    }
    close IN;
}


sub compile{
#    print "cd $run_dir ;$cc $opt -o $exe $mod_in $src $libs";
    `cd $run_dir ;$cc $opt -o $exe $mod_in $src $libs`;
    unlink "$mod_in";
    my $exit_value = $? >> 8;
    exit if($exit_value!=0);
    `chmod +x $exe`;
}


sub run{
    if($debug == 1){
	exec 'gdb',@ARGV;
    }elsif($debug  == 2){
	exec 'ddd',@ARGV;
    }else{
	exec $exe,@ARGV;
    }
}

sub compilep{
    my ($exe,$in,$src,$inc)=@_;
    my $c=0;
    if(! -e $exe){
	$c=1;
    }else{
	my @files;
	my $t=modtime( $exe);
	push @files,$in;
	push @files,(split ' ',$src);
	push @files,(split ' ',$inc);
	
	for(@files){
	    if($t < modtime($_)){
		$c=1;
		last;
	    }
	}
    }
    return $c;
}

setup();

eval_init();

getparam($in);

($mod_in,$exe)=gen_exename();

gen_src($in,$mod_in);

compile() if compilep($exe,$in,$src,$inc);

run();

