#!/usr/bin/perl

sub usage() {
	print "Usage: struct2savevm structname prefix < filewithstruct\n";
	exit;
}

$struct=shift(@ARGV);

if($struct eq "") {
	print "No struct specified!\n";
	usage();
}

$prefix=shift(@ARGV);

if($prefix eq "") {
	print "No prefix specified!\n";
	usage();
}

$savefunc='
static void ' . $prefix . '_save(QEMUFile* f,void* opaque)
{
	' . $struct . '* s=(' . $struct . '*)opaque;

';

$loadfunc='
static int ' . $prefix . '_load(QEMUFile* f,void* opaque,int version_id)
{
	' .  $struct . '* s=(' . $struct . '*)opaque;

	if (version_id != 1)
            return -EINVAL;

';

$state="find struct";
while(<>) {
	if($state eq "find struct" && /struct\s+$struct\s*{/) {
		$state="found struct";
	} elsif($state eq "found struct") {
		if(/^\}/) {
			$state="finished";
		} else {
			if(/^\s*(uint(8|16|32|64)_t|int|char)\s+([A-Za-z0-9_]+)(\[\S+\])?;/) {
				if($1 eq "int") {
					$type="be32s";
					$width=4;
				} elsif($1 eq "char") {
					$type="8s";
					$width=1;
				} else {
					if($2 eq "8") {
						$type=$2 . "s";
					} else {
						$type="be" . $2 . "s";
					}
					$width=($2/8);
				}
				$name=$3;
				if($4 ne "") {
					$size=substr($4,1,length($4)-2);
					if($width ne "1") {
						$size.="*" . $width;
					}
					$cmd="_buffer(f, s->" . $name . ", " . $size . ");\n";
				} else {
					$cmd="_" . $type . "(f, &s->" . $name . ");\n";
				}

				$savefunc.="	qemu_put" . $cmd;
				$loadfunc.="	qemu_get" . $cmd;
			}
		}
	}
}

$savefunc.="}\n";
$loadfunc.="\n	return 0;\n}\n";

print $savefunc . $loadfunc 
. "\nregister_savevm(\"" . $prefix . "\", 0, 1, "
  . $prefix . "_save, " . $prefix . "_load, s);\n\n";

