#!/usr/bin/perl -w

# Copyright 2000 James Manning, <jmm@computer.org>
# Licensed under the GNU General Public License, version 2.

use strict;
undef $/; # entire files at a time

my $file=$ARGV[0]; # we can foreach later, but call as find -exec for now
my %element_map;
# elements of the structs we'd like to convert to gcc syntax
@{$element_map{'file_operations'}} = qw(llseek read write readdir poll ioctl mmap open flush release fsync fasync lock readv writev);
my @cleanup_structs = sort keys %element_map;

# get contents, convert to gcc syntax, write back out
print "Processing $file ... ";
open(IN,"$file") or die "$file"; my $contents=<IN>; close(IN);
&gccify(\$contents);
open(OUT,"> $file") or die "> $file"; print OUT $contents; close(OUT);
print "done\n";

sub gccify {
	my $ref_content = shift(@_);
	for my $struct (@cleanup_structs) {
		$$ref_content =~ s|
			(struct\s+)($struct)(\s+)  # preamble for this struct
			(\S+)                      # struct name
			(\s*=\s*{)(.*?)(?=})       # postamble
			|                          # replace with
			$1 . $2 . $3 . $4 . $5 .   # same for these fields
			&gccify_contents($2,$4,$6) # convert the contents
			|gsex; # GNU sex?
	}
}

sub gccify_contents {
	my $struct_type = shift(@_);
	my $struct_name = shift(@_);
	my $struct_contents = shift(@_);
	my $orig_contents = $struct_contents;
	if($struct_contents =~ m/\n\s*(\w+)\s*:\s*(\&?\w+).*$/m) {
		# already gcc syntax, at least partially
		return $struct_contents;
	}
	if($struct_contents =~ m/#ifdef/m) {
		print "Not modifying $file:$struct_name with ifdef\n";
		return $struct_contents;
	}
	$struct_contents =~ s/^\s+//g; # kill leading whitespace
	$struct_contents =~ s#/\*.*?\*/##gs; # kill c style comments
	$struct_contents =~ s#//.*##g; # kill c++ style comments
	return $orig_contents
		unless $struct_contents =~ m/\w/; # basically empty
	my @members=split(/[,\s]+/,$struct_contents);
	my $return_contents="\n";
	for my $index (0..$#members) {
		if($members[$index] !~ m/NULL/ &&
		   $members[$index] =~ m/\w/) {
			my $element=$element_map{$struct_type}[$index];
			$return_contents .= 
				"\t$element:" .
				"\t" x (2 - int(2+length($element))/8) .
				"\t$members[$index],\n";
		}
	}
	return $return_contents;
}

