#! /usr/bin/perl

while ($ARGV[0] =~ /(\w+):(\w+)(:\w+)?/) {
	$bitname{$2} = $1;
	$power2{$2} = $3;
	push @prefix, $2;
	shift;
}

open(FH, $ARGV[0]) || die "$ARGV[0]: $!\n";
if (defined $ARGV[1]) {
	open(FOUT, ">$ARGV[1]");
	select FOUT;
}

print "/* auto generated by bitname scirpt */\n";
while (<FH>) {
 top:
	if (/^#(if|else|elif|endif)/) {
		if (!$HEAD && /^#ifndef\s+(\w+)/) {
			$def = $1;
			$_ = <FH>;
			if (/^#define\s+(\w+)/ && $def eq $1) {
				print "#if 1 /*$def*/\n";
				$HEAD = $def;
			} else {
				print "#ifndef $def\n";
				goto top;
			}
		} elsif (/^#ifdef *__KERNEL__\b/) {
			print "#if 1 /*__KERNEL__*/\n";
		} elsif (/^#ifndef *__KERNEL__\b/) {
			print "#if 0 /*!__KERNEL__*/\n";
		} else {
			s/defined\(__KERNEL__\)/1/;
			s/\b__KERNEL__\b/1/;
			print;
		}
		next;
	}

	chomp;
	s#/\*.*\*/##;
	s#\s+$##;
	if (/^(typedef\s+)?enum\s+(\w+)\s*{?\s*(\/\*.*\*\/)?$/) {
		$name = $2;
		print "\n#ifdef __KERNEL__\n";
		print "static const struct bitname ${name}_bitname[] = {\n";
		while (<FH>) {
			if (/^#(if|else|elif|endif)/) {
				print;
				next;
			}
			if (/^\s*([A-Za-z_]\w*)\s*(.)/) {
				$tmp = $id = $1;
				$n = $2;
				$tmp =~ s/^[^_]+_// || $tmp =~ s/^_[^_]{1,5}//;
				$tmp =~ tr/A-Z/a-z/;
				if ($n eq '=') {
					print "\t{ $id,\t\"", $tmp, "\" },\n";
				} else {
					print "\t{ 1<<$id,\t\"", $tmp, "\" },\n";
				}
			} elsif (/}/) {
				last;
			}
		}
		print "\t{ 0,\tNULL }\n};\n";
		print "#endif /*__KERNEL*/\n";

	} elsif (/^#define\s+(\w+)\s+(0x[0-9a-fA-F]+|\d+|\([<>\w]+\))[uUlL]*/) {
		$id = $1;
		$v = $2;
		foreach $prefix (@prefix) {
			if ($id =~ /^$prefix/) {
				if ($power2{$prefix}) {
					$list{$prefix} .= $id . " ";
					last;
				}
				$v = eval $v;
				for ($i = 0; $i < 64; $i++) {
					if ($v == 1<<$i) {
						$list{$prefix} .= $id . " ";
						last;
					}
				}
				last;
			}
		}
	} elsif (/^(typedef\s+)?struct\s+(\w+)(\s+{)?$/) {
		$name = $2;
		while (<FH>) {
			if (/^#(if|else|elif|endif)/) {
				print;
				next;
			}
			chomp;
			s#/\*.*\*/##;	# cut comment
			s#^\s+##;	# cut top white space
			s#\s+$##;	# cut last white space
			if (/^}/) {
				last;
			} elsif (/(\w+)\s*,\s*\*?(\w+);/) {
				print "#define _", $name, "_has_$1\n";
				print "#define _", $name, "_has_$2\n";
			} elsif (/(\w+)(:\d+|\[.+\])?;/) {
				print "#define _", $name, "_has_$1\n";
			} elsif (/^[\w\s*]+\(\*(\w+)\)\s*\(/) {
				#function
				print "#define _", $name, "_has_$1\n";
			}
		}
	}
}

if (!defined @prefix) {
	exit 0;
}

print "\n#ifdef __KERNEL__\n";
foreach $prefix (@prefix) {
	if ($list{$prefix}) {
		print "\nstatic const struct bitname ",
			$bitname{$prefix}, "[] = {\n";
		foreach (split / /, $list{$prefix}) {
			printf("#ifdef $_\n");
			($tmp = substr($_, length $prefix)) =~ tr/A-Z/a-z/;
			if ($power2{$prefix}) {
				print "\t{ 1<<$_,\t\"$tmp\" },\n";
			} else {
				print "\t{ $_,\t\"$tmp\" },\n";
			}
			printf("#endif\n");
		}
		print "\t{ 0,\tNULL }\n};\n";
	}
}
print "#endif /*__KERNEL__*/\n";
