#!/usr/bin/perl -w

# Michael got bored and wrote this script

# extracts offsets from config_t in global.h and generates 
# page table for megatune ini-file. The input is an xml file.


use bin::ParseStruct;
use XML::Simple qw(:strict);
use File::Copy;

if (@ARGV != 3) {
    print "usage:\n";
    print "\t $0 global.h xml-file ini-file\n\n";
	print "Example: $0 global.h doc/megatune/config.xml doc/megatune/vemsv3.ini\n\n";
    exit;
}

my $headerfilename = $ARGV[0];

$psobj = ParseStruct->new();
$psobj->wantedstructs( 'config_t' );
$psobj->datasource( $headerfilename );
$psobj->readstructs();
my $vars = $psobj->getstructvars( 'config_t' );

$p = XMLin("$ARGV[1]", forcearray => 1, keyattr => []);

# open the files, and a revision file to be copied over the original later
my $inifile = $ARGV[2];
chomp $inifile;
open(INIFILE,"$inifile");
open(INIFILE2, ">$inifile.$$");

my $foundmarker=0;
foreach(<INIFILE>){
	if($foundmarker == 0){
		print INIFILE2 $_;
		if($_ =~ /^\s+page = 1/){
			$foundmarker = 1;
			print_ini(); # print the new section for page 1
		}
	} else {
		if($_ =~ /\;-----------+/){
			print INIFILE2 $_;
			$foundmarker = 0; # reset since the section is over
		}
	}
}
close INIFILE;
close INIFILE2;

foreach $n (sort keys %$vars) {
    if (!defined($visited{$n})) {
	# maybe it was an array, strip the []
	if ($n =~ /(\w+)\[\d+\]/) {
	    my $s = $1;
	    if (!defined($visited{$s})) {  # last chance...
		print STDERR "WARNING: variable \"$n\" in config_t not found in \"$ARGV[1]\"\n";
	    }
	} else {
	    print STDERR "WARNING: variable \"$n\" in config_t not found in \"$ARGV[1]\"\n";
	}
    }
} 

my $result = copy("$inifile.$$","$inifile");
if($result == 1){
	# Copy was a success
	unlink("$inifile.$$");
} else {
	print "There was an error in the file copy. The file is kept as $inifile.$$\n";
}

sub print_ini {
	foreach $c (@{$p->{config}}) {
	
	# Megatune formats:
	#  name       = bits,   type, offset, bits
	#  name       = array,  type, offset, shape, units,     scale, translate,    lo,      hi, digits
	#  name       = scalar, type, offset,        units,     scale, translate,    lo,      hi, digits
	
		my $offset = getoffset($c);
		if ($offset == -1) {
			next; # something is wrong, next element please
		}
		
		my $array = $c->{array};
		print INIFILE2 "\t$c->{name}\t= $array,\t$c->{type},\t$offset,\t";
		
		if ($array eq "scalar") {
			print INIFILE2 "\"$c->{units}\",\t$c->{scale},\t$c->{translate},\t$c->{lo},\t$c->{hi},\t$c->{digits}\n\r";
		} elsif ($array eq "array") {
			print INIFILE2 "[$c->{shape}],\t\"$c->{units}\",\t$c->{scale},\t$c->{translate},\t$c->{lo},\t$c->{hi},\t$c->{digits}\n\r";
		} elsif ($array eq "bits") {
			print INIFILE2 "$c->{bits}";
			if (defined($c->{bitval})) {
				@bitvals = split /, /, $c->{bitval};
				foreach $v (@bitvals) {
					print INIFILE2 ",\t\"$v\"";
				}
			}
			print INIFILE2 "\n\r";
		}
	}
}

sub getoffset {
    my $c = shift;
    my $varname = $c->{name};
    my $array = $c->{array};

#    print "$varname\t$array\n";
    $visited{$varname} = 1;

    if ($array eq "scalar") {
	if (defined($vars->{$varname})) {
	    return $vars->{$varname};
	} else {  # oops, variable not found
	    printf STDERR "ERROR: Variable '$varname' not found in config_t, skipping\n";
	    return -1;
	}
    } elsif ($array eq "array") {
	my $arrayname = $varname . "[0]";  # get address of first element in array
	if (defined($vars->{$arrayname})) {
	    return $vars->{$arrayname};
	} else {  # oops, variable not found
	    print STDERR "ERROR: Variable '$arrayname' not found in config_t, skipping\n";
	    return -1;
	}
    } elsif ($array eq "bits") {
	my $realname = $c->{realname};
	if (defined($vars->{$realname})) {
	    return $vars->{$realname};
	} else {  # oops, variable not found
	    printf STDERR "ERROR: Variable '$varname' not found in config_t, skipping\n";
	    return -1;
	}
    } else {
	print STDERR "ERROR: Can't understand '$array'\n";
	return -1;
    }
};

