diff --git a/tools/winapi/config.pm b/tools/winapi/config.pm
index 852ef8b82140bd7149c64a345ad1fccbc3b5abbb..3d950e6c442b3275fa370a913f49ec622f2d1c7f 100644
--- a/tools/winapi/config.pm
+++ b/tools/winapi/config.pm
@@ -10,9 +10,10 @@ require Exporter;
 @ISA = qw(Exporter);
 @EXPORT = qw(
     &file_absolutize &file_normalize
+    &file_directory
     &file_type &files_filter
-    &file_skip &files_skip 
-    &get_c_files &get_h_files &get_spec_files
+    &file_skip &files_skip
+    &get_api_files &get_c_files &get_h_files &get_spec_files
 );
 @EXPORT_OK = qw(
     $current_dir $wine_dir $winapi_dir $winapi_check_dir
@@ -22,6 +23,8 @@ use vars qw($current_dir $wine_dir $winapi_dir $winapi_check_dir);
 
 use output qw($output);
 
+use File::Find;
+
 sub file_type {
     local $_ = shift;
 
@@ -30,7 +33,7 @@ sub file_type {
     m%^(?:libtest|rc|server|tests|tools)/% && return "";
     m%^(?:programs|debugger|miscemu)/% && return "wineapp";
     m%^(?:library|tsx11|unicode)/% && return "library";
-    m%^windows/x11drv/wineclipsrv.c% && return "application";
+    m%^windows/x11drv/wineclipsrv\.c$% && return "application";
 
     return "winelib";
 }
@@ -56,8 +59,9 @@ sub file_skip {
     m%^(?:libtest|programs|rc|server|tests|tools)/% && return 1;
     m%^(?:debugger|miscemu|tsx11|server|unicode)/% && return 1;
     m%^dlls/wineps/data/% && return 1;
-    m%^windows/x11drv/wineclipsrv.c% && return 1;
-    m%^dlls/winmm/wineoss/midipatch.c% && return 1;
+    m%^windows/x11drv/wineclipsrv\.c$% && return 1;
+    m%^dlls/winmm/wineoss/midipatch\.c$% && return 1;
+    m%(?:glue|spec)\.c$% && return 1;
 
     return 0;
 }
@@ -98,25 +102,57 @@ sub file_normalize {
     return $_;
 }
 
+sub file_directory {
+    my $file = shift;
+    $file =~ s%^./%%;
+
+    my $dir = $file;
+    $dir =~ s%/?[^/]*$%%;
+    if(!$dir) {
+	$dir = ".";
+    }
+  
+    return $dir;
+}
+
 sub _get_files {
     my $extension = shift;
     my $type = shift;
+    my $dir = shift;
 
     $output->progress("$wine_dir: searching for *.$extension");
 
-    my @files = map {
-	s%^\./%%;
-	s%^$wine_dir/%%;
-	if(file_type($_) eq $type) {
-	    $_;
-	} else {
-	    ();
+    if(!defined($dir)) {
+	$dir = $wine_dir;
+    }
+
+    my @files;
+
+    my @dirs = ($dir);
+    while(defined(my $dir = shift @dirs)) {
+	opendir(DIR, $dir);
+	my @entries= readdir(DIR);
+	closedir(DIR);
+	foreach (@entries) {
+	    $_ = "$dir/$_";    
+	    if(/\.\.?$/) {
+		# Nothing
+	    } elsif(-d $_) {
+		push @dirs, $_;
+	    } elsif(/\.$extension$/ && (!defined($type) || file_type($_) eq $type)) {
+		s%^$wine_dir/%%;
+		push @files, $_;
+	    }
 	}
-    } split(/\n/, `find $wine_dir -name \\*.$extension`);
+    }
 
     return @files;
 }
 
+sub get_api_files { 
+    my $name = shift; 
+    return _get_files("api", undef, "$winapi_check_dir/$name");
+}
 sub get_c_files { return _get_files("c", @_); }
 sub get_h_files { return _get_files("h", @_); }
 sub get_spec_files { return _get_files("spec", @_); }
diff --git a/tools/winapi/make_filter b/tools/winapi/make_filter
new file mode 100755
index 0000000000000000000000000000000000000000..03c6aac34c5b3741818fcf78445e2fa23fe81612
--- /dev/null
+++ b/tools/winapi/make_filter
@@ -0,0 +1,70 @@
+#! /usr/bin/perl -w
+
+use strict;
+
+BEGIN {
+    $0 =~ m%^(.*?/?tools)/winapi/make_filter$%;
+    require "$1/winapi/setup.pm";
+}
+
+use config qw($current_dir $wine_dir);
+use output qw($output);
+use make_filter_options qw($options);
+
+use make_parser;
+
+if($options->progress) {
+    $output->enable_progress;
+} else {
+    $output->disable_progress;
+}
+
+########################################################################
+# main
+########################################################################
+
+my $command = join(" ", $options->arguments);
+open(IN, "($command) 2>&1 |");
+
+while(<IN>) {    
+    chomp;
+
+    if(!&make_parser::line($_)) {
+	next;
+    }
+
+    my $directory = &make_parser::directory();
+    my $file = &make_parser::file_name();
+    my $line = &make_parser::file_line();
+    my $message = &make_parser::message();
+
+    if(&make_parser::tool() eq "make") {
+	if($directory && $directory ne ".") {
+	    $output->progress("$directory: make");
+	}
+    } elsif($message) {
+	if($file && $line) {
+	    if($directory) {
+		$output->write("$directory/$file:$line: $message\n");
+	    } else {
+		$output->write("$file:$line: $message\n");
+	    }
+	} elsif($file) {
+	    if($directory) {
+		$output->write("$directory/$file: $message\n");
+	    } else {
+		$output->write("$file: $message\n");
+	    }
+	} else {
+	    if($directory) {
+		$output->write("$directory: " . &make_parser::tool() . ": $message\n");
+	    } else {
+		$output->write(".: " . &make_parser::tool() . ": $message\n");
+	    }
+	}
+    }
+}
+
+close(IN);
+
+$output->hide_progress();
diff --git a/tools/winapi/make_filter_options.pm b/tools/winapi/make_filter_options.pm
new file mode 100644
index 0000000000000000000000000000000000000000..ceecd77bf9583c2ff6691271568feec310201f1d
--- /dev/null
+++ b/tools/winapi/make_filter_options.pm
@@ -0,0 +1,35 @@
+package make_filter_options;
+use base qw(options);
+
+use strict;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
+require Exporter;
+
+@ISA = qw(Exporter);
+@EXPORT = qw();
+@EXPORT_OK = qw($options);
+
+use options qw($options &parse_comma_list);
+
+my %options_long = (
+    "debug" => { default => 0, description => "debug mode" },
+    "help" => { default => 0, description => "help mode" },
+    "verbose" => { default => 0, description => "verbose mode" },
+
+    "progress" => { default => 1, description => "show progress" },
+
+    "pedantic" => { default => 0, description => "be pedantic" },
+);
+
+my %options_short = (
+    "d" => "debug",
+    "?" => "help",
+    "v" => "verbose"
+);
+
+my $options_usage = "usage: make_filter [--help]\n";
+
+$options = '_options'->new(\%options_long, \%options_short, $options_usage);
+
+1;
diff --git a/tools/winapi/make_parser.pm b/tools/winapi/make_parser.pm
new file mode 100644
index 0000000000000000000000000000000000000000..63037d9bef429c5e2fc8e78c147c913123a1b617
--- /dev/null
+++ b/tools/winapi/make_parser.pm
@@ -0,0 +1,664 @@
+package make_parser;
+
+use strict;
+
+use output qw($output);
+
+########################################################################
+# global
+########################################################################
+
+my $current; 
+my $tool;
+my $directory;
+my $file;
+my $line;
+my $function;
+my $message;
+
+sub directory { return $directory; }
+sub tool { return $tool; }
+sub file_name { return $file; }
+sub file_line { return $line; }
+sub message { return $message; }
+
+########################################################################
+# error
+########################################################################
+
+sub error {
+    $output->write("make_filter: $tool: can't parse output: '$current'\n");
+    exit 1;
+}
+
+########################################################################
+# line
+########################################################################
+
+sub line {
+    local $_ = shift;
+
+    $file = "";
+    $line = "";
+    $message = "";
+
+    $current = $_;
+
+    my ($new_tool, $read_files, $write_files, $remove_files) = command($_);
+    if(defined($new_tool)) {
+	$tool = $new_tool;
+
+	$function = "";
+
+	my $progress = "$directory: $tool: ";
+	if($#$read_files >= 0) {
+	    $progress .= "read[" . join(" ", @{$read_files}) . "]";
+	}
+	if($#$write_files >= 0) {
+	    if($#$read_files >= 0) {
+		$progress .= ", ";
+	    }	       
+	    $progress .= "write[" . join(" ", @{$write_files}) . "]";
+	}
+	if($#$remove_files >= 0) {
+	    if($#$read_files >= 0 || $#$write_files >= 0) {
+		$progress .= ", ";
+	    }	       
+	    $progress .= "remove[" . join(" ", @{$remove_files}) . "]";
+	}
+
+	if($tool =~ /^cd|make$/) {
+	    # Nothing
+	} elsif($tool =~ /^ld$/) {
+	    $progress =~ s/read\[.*?\]/read[*.o]/; # FIXME: Kludge
+	    $output->progress($progress)
+	} else {
+	    $output->progress($progress)
+	}
+
+	return 0;
+    }
+
+    if(/^Wine build complete\.$/) {
+	# Nothing
+    } elsif(s/^make\[(\d+)\]:\s*//) {
+	$tool = "make";
+	make_output($1, $_);
+    } elsif($tool eq "bison" && /^conflicts:\s+\d+\s+shift\/reduce$/) {
+	# Nothing
+    } elsif($tool eq "gcc" && /^In file included from (.+?):(\d+):$/) {
+	# Nothing
+    } elsif($tool =~ /^gcc|ld$/ && s/^(.+?\.o(?:\(.*?\))?):\s*//) {
+	ld_output($1, $_)
+    } elsif($tool eq "gcc" && s/^(.+?\.[chly]):\s*//) {
+	gcc_output($1, $_);
+    } elsif($tool eq "winebuild" && s/^(.+?\.spec):\s*//) {
+	winebuild_output($1, $_);
+    } elsif($tool eq "wmc" && s/^(.+?\.mc):\s*//) {
+        wmc_output($1, $_);
+    } elsif($tool eq "wrc" && s/^(.+?\.rc):\s*//) {
+	wrc_output($1, $_);
+    } elsif($tool eq "cd" && s/^\/bin\/sh:\s*cd:\s*//) {
+	parse_cd_output($_);
+    } else {
+	error($_)
+    }
+    
+    $file =~ s/^\.\///;
+
+    return 1;
+}
+
+########################################################################
+# make_output
+########################################################################
+
+sub make_output {
+    my $level = shift;
+    local $_ = shift;
+
+    $file = "";
+    $message = "";
+
+    if(0) {
+	# Nothing
+    } elsif(/^\*\*\* \[(.*?)\] Error (\d+)$/) {
+	# Nothing
+    } elsif(/^\*\*\* Warning:\s+/) { # 
+	if(/^File \`(.+?)\' has modification time in the future \((.+?) > \(.+?\)\)$/) {
+	    # Nothing
+	} else {
+	    error();
+	}
+    } elsif(/^\`(.*?)\' is up to date.$/) {
+	# Nothing
+    } elsif(/^\[(.*?)\] Error (\d+) \(ignored\)$/) {
+	# Nothing
+    } elsif(/^(Entering|Leaving) directory \`(.*?)\'$/) {
+	if($1 eq "Entering") {
+	    $directory = $2;
+	} else {
+	    $directory = "";
+	}
+
+	my @components;
+	foreach my $component (split(/\//, $directory)) {
+	    if($component eq "wine") {
+		@components = ();
+	    } else {
+		push @components, $component;
+	    }
+	}
+	$directory = join("/", @components);
+    } elsif(/^Nothing to be done for \`(.*?)\'.$/) {
+	# Nothing
+    } elsif(s/^warning:\s+//) {
+	if(/^Clock skew detected.  Your build may be incomplete.$/) {
+	    # Nothing
+	} else {
+	    error();
+	}
+    } else {
+	error();
+    }
+
+}
+
+########################################################################
+# command
+########################################################################
+
+sub command {
+    local $_ = shift;
+
+    my $tool;
+    my $file;
+    my $read_files = ["<???>"];
+    my $write_files = ["<???>"];
+    my $remove_files = [];
+
+    s/^\s*(.*?)\s*$/$1/;
+
+    if(s/^\[\s+-d\s+(.*?)\s+\]\s+\|\|\s+//) {
+	# Nothing
+    }
+
+    if(s/^ar\s*//) {
+	$tool = "ar";
+	($read_files, $write_files) = ar_command($_);
+    } elsif(s/^as\s*//) {
+	$tool = "as";
+	($read_files, $write_files) = as_command($_);
+    } elsif(s/^bison\s*//) {
+	$tool = "bison";
+	($read_files, $write_files) = bison_command($_);
+    } elsif(s/^cd\s*//) {
+	$tool = "cd";
+	($read_files, $write_files) = cd_command($_);
+    } elsif(s/^flex\s*//) {
+	$tool = "flex";
+	($read_files, $write_files) = flex_command($_);
+    } elsif(s/^for\s*//) {
+	$tool = "for";
+	($read_files, $write_files) = for_command($_);
+    } elsif(s/^\/usr\/bin\/install\s*//) {
+	$tool = "install";
+	($read_files, $write_files) = install_command($_);
+    } elsif(s/^ld\s*//) {
+	$tool = "ld";
+	($read_files, $write_files) = ld_command($_);
+    } elsif(s/^\/sbin\/ldconfig\s*//) {
+	$tool = "ldconfig";
+	($read_files, $write_files) = ldconfig_command();
+    } elsif(s/^gcc\s*//) {
+	$tool = "gcc";
+	($read_files, $write_files) = gcc_command($_);
+    } elsif(s/^(?:(?:\.\.\/)+|\.\/)tools\/makedep\s*//) {
+	$tool = "makedep";
+	($read_files, $write_files) = makedep_command($_);
+    } elsif(s/^mkdir\s*//) {
+	$tool = "mkdir";
+	($read_files, $write_files) = mkdir_command($_);
+    } elsif(s/^ranlib\s*//) {
+	$tool = "ranlib";
+	($read_files, $write_files) = ranlib_command($_);
+    } elsif(s/^rm\s*//) {
+	$tool = "rm";
+	($read_files, $write_files, $remove_files) = rm_command($_);
+    } elsif(s/^sed\s*//) {
+	$tool = "sed";
+	($read_files, $write_files) = sed_command($_);
+    } elsif(s/^strip\s*//) {
+	$tool = "sed";
+	($read_files, $write_files) = strip_command($_);
+    } elsif(s/^LD_LIBRARY_PATH="(?:(?:\.\.\/)*unicode)?:\$LD_LIBRARY_PATH"\s+(?:\.\.\/)*tools\/winebuild\/winebuild\s*//) {
+	$tool = "winebuild";
+	($read_files, $write_files) = winebuild_command($_);
+    } elsif(s/^LD_LIBRARY_PATH="(?:(?:\.\.\/)*unicode)?:\$LD_LIBRARY_PATH"\s+(?:\.\.\/)*tools\/wmc\/wmc\s*//) {
+	$tool = "wmc";
+	($read_files, $write_files) = wmc_command($_);
+    } elsif(s/^LD_LIBRARY_PATH="(?:(?:\.\.\/)*unicode)?:\$LD_LIBRARY_PATH"\s+(?:\.\.\/)*tools\/wrc\/wrc\s*//) {
+	$tool = "wrc";
+	($read_files, $write_files) = wrc_command($_);
+    }
+
+    return ($tool, $read_files, $write_files, $remove_files);
+}
+
+########################################################################
+# ar_command
+########################################################################
+
+sub ar_command {
+    local $_ = shift;
+
+    my $read_files;
+    my $write_files;
+
+    if(/rc\s+(\S+)(\s+\S+)+$/) {
+	$write_files = [$1];
+	$read_files = $2;
+	$read_files =~ s/^\s*//;
+	$read_files = [split(/\s+/, $read_files)];
+    } else {
+	error();
+    }
+
+    return ($read_files, $write_files);
+}
+
+########################################################################
+# as_command
+########################################################################
+
+sub as_command {
+    local $_ = shift;
+
+    my $read_files;
+    my $write_files;
+
+    if(/-o\s+(\S+)\s+(\S+)$/) {
+	$write_files = [$1];
+	$read_files = [$2];
+    } else {
+	error();
+    }
+
+    return ($read_files, $write_files);
+}
+
+########################################################################
+# bision_command
+########################################################################
+
+sub bison_command {
+    local $_ = shift;
+
+    return ([], []);
+}
+
+########################################################################
+# cd_command
+########################################################################
+
+sub cd_command {
+    local $_ = shift;
+
+    return ([], []);
+}
+
+########################################################################
+# cd_output
+########################################################################
+
+sub cd_output {
+    local $_ = shift;
+
+    if(/^(.*?): No such file or directory/) {
+	$message = "directory '$1' doesn't exist";
+    }
+}
+
+########################################################################
+# flex_command
+########################################################################
+
+sub flex_command {
+    local $_ = shift;
+
+    return ([], []);
+}
+
+########################################################################
+# for_command
+########################################################################
+
+sub for_command {
+    local $_ = shift;
+
+    return ([], []);
+}
+
+########################################################################
+# gcc_command
+########################################################################
+
+sub gcc_command {
+    my $read_files;
+    my $write_files;
+
+    if(/-o\s+(\S+)\s+(\S+)$/) {
+	$write_files = [$1];
+	$read_files = [$2];
+    } elsif(/-o\s+(\S+)/) {
+	$write_files = [$1];
+	$read_files = ["<???>"];
+    } elsif(/^-shared.*?-o\s+(\S+)/) {
+	$write_files = [$1];
+	$read_files = ["<???>"];
+    } else {
+	error();
+    }
+
+    return ($read_files, $write_files);
+}
+
+########################################################################
+# gcc_output
+########################################################################
+
+sub gcc_output {
+    $file = shift;
+    local $_ = shift;
+
+    if(s/^(\d+):\s+//) {
+	$line = $1;
+	if(s/^warning:\s+//) {
+	    my $supress = 0;
+
+	    if(0) {
+		# Nothing
+	    } elsif(/^\(near initialization for \`(.*?)\'\)$/) {
+		$supress = 0;
+	    } elsif(/^\`(.*?)\' defined but not used$/) {
+		$supress = 0;
+	    } elsif(/^\`(.*?)\' is not at beginning of declaration$/) {
+		$supress = 0;
+	    } elsif(/^\`%x\' yields only last 2 digits of year in some locales$/) {
+		$supress = 1;
+	    } elsif(/^(.*?) format, different type arg \(arg (\d+)\)$/) {
+		$supress = 0;
+	    } elsif(/^assignment from incompatible pointer type$/) {
+		$supress = 0;
+	    } elsif(/^comparison between signed and unsigned$/) {
+		$supress = 0;
+	    } elsif(/^comparison of unsigned expression < 0 is always false$/) {
+		$supress = 0;
+	    } elsif(/^comparison of unsigned expression >= 0 is always true$/) {
+		$supress = 0;
+	    } elsif(/^conflicting types for built-in function \`(.*?)\'$/) {
+		$supress = 0;
+	    } elsif(/^empty body in an if-statement$/) {
+		$supress = 0;
+	    } elsif(/^empty body in an else-statement$/) {
+		$supress = 0;
+	    } elsif(/^implicit declaration of function \`(.*?)\'$/) {
+		$supress = 0;
+	    } elsif(/^initialization from incompatible pointer type$/) {
+		$supress = 0;
+	    } elsif(/^missing initializer$/) {
+		$supress = 0;
+	    } elsif(/^ordered comparison of pointer with integer zero$/) {
+		$supress = 0;
+	    } elsif(/^passing arg (\d+) of pointer to function from incompatible pointer type$/) {
+		$supress = 0;
+	    } elsif(/^passing arg (\d+) of \`(\S+)\' from incompatible pointer type$/) {
+		$supress = 0;
+	    } elsif(/^passing arg (\d+) of \`(\S+)\' makes integer from pointer without a cast$/) {
+		$supress = 0;
+	    } elsif(/^type of \`(.*?)\' defaults to \`(.*?)\'$/) {
+		$supress = 0;
+	    } else {
+		error();
+	    }
+
+	    if(!$supress) {
+		if($function) {
+		    $message = "function $function: $_";
+		} else {
+		    $message = "$_";
+		}
+	    } else {
+		$message = "";
+	    }
+	} elsif(/^\`(.*?)\' undeclared \(first use in this function\)$/) {
+	    $message = "$_";
+	} elsif(/^\(Each undeclared identifier is reported only once$/) {
+	    $message = "$_";
+	} elsif(/^for each function it appears in.\)$/) {
+	    $message = "$_";
+	} elsif(/^parse error before `(.*?)'$/) {
+	    $message = "$_";
+	} elsif(/^$/) {
+	    $message = "$_";
+	} else {
+	    error();
+	}
+    } elsif(/^In function \`(.*?)\':$/) {
+	$function = $1;
+    } elsif(/^At top level:$/) {
+	$function = "";
+    } else {
+	error();
+    }
+}
+
+########################################################################
+# install_command
+########################################################################
+
+sub install_command {
+    local $_ = shift;
+
+    return ([], []);
+}
+
+########################################################################
+# ld_command
+########################################################################
+
+sub ld_command {
+    local $_ = shift;
+
+    my $read_files;
+    my $write_files;
+
+    if(/-r\s+(.*?)\s+-o\s+(\S+)$/) {
+	$write_files = [$2];
+	$read_files = [split(/\s+/, $1)];
+    } else {
+	error();
+    }
+
+    return ($read_files, $write_files);
+}
+
+########################################################################
+# ld_output
+########################################################################
+
+sub ld_output {
+    $file = shift;
+    local $_ = shift;
+
+    if(/^the use of \`(.+?)\' is dangerous, better use \`(.+?)\'$/) {
+	# nothing
+    }
+}
+
+########################################################################
+# ldconfig_command
+########################################################################
+
+sub ldconfig_command {
+    local $_ = shift;
+
+    return ([], []);
+}
+
+########################################################################
+# makedep_command
+########################################################################
+
+sub makedep_command {
+    local $_ = shift;
+
+    return ([], []);
+}
+
+########################################################################
+# mkdir_command
+########################################################################
+
+sub mkdir_command {
+    local $_ = shift;
+
+    return ([], []);
+}
+
+########################################################################
+# ranlib_command
+########################################################################
+
+sub ranlib_command {
+    local $_ = shift;
+
+    my $read_files;
+    my $write_files;
+
+    $read_files = [split(/\s+/)];
+    $write_files = [];
+
+    return ($read_files, $write_files);
+}
+
+########################################################################
+# rm_command
+########################################################################
+
+sub rm_command {
+    local $_ = shift;
+    s/^-f\s*//;
+    return ([], [], [split(/\s+/, $_)]);
+}
+
+########################################################################
+# sed_command
+########################################################################
+
+sub sed_command {
+    local $_ = shift;
+
+    return ([], []);
+}
+
+########################################################################
+# strip_command
+########################################################################
+
+sub strip_command {
+    local $_ = shift;
+
+    return ([], []);
+}
+
+########################################################################
+# winebuild_command
+########################################################################
+
+sub winebuild_command {
+    local $_ = shift;
+
+    return ([], []);
+}
+
+########################################################################
+# winebuild_output
+########################################################################
+
+sub winebuild_output {
+    $file = shift;
+    local $_ = shift;
+
+    $message = $_;
+}
+
+########################################################################
+# wmc_command
+########################################################################
+
+sub wmc_command {
+    local $_ = shift;
+
+    my $read_files;
+    my $write_files;
+
+    if(/\s+(\S+)$/) {
+	my $mc_file = $1;
+
+	my $rc_file = $mc_file;
+	$rc_file =~ s/\.mc$/.rc/;
+
+	$write_files = [$rc_file];
+	$read_files = [$mc_file];
+    } else {
+	error();
+    }
+
+    return ($read_files, $write_files);
+}
+
+########################################################################
+# wmc_output
+########################################################################
+
+sub wmc_output {
+    $file = shift;
+    local $_ = shift;
+}
+
+########################################################################
+# wrc_command
+########################################################################
+
+sub wrc_command {
+    local $_ = shift;
+
+    my $read_files;
+    my $write_files;
+
+    if(/\s+(\S+)$/) {
+	my $rc_file = $1;
+
+	my $o_file = $rc_file;
+	$o_file =~ s/\.rc$/.o/;
+
+	$write_files = [$o_file];
+	$read_files = [$rc_file];
+    } else {
+	error();
+    }
+
+    return ($read_files, $write_files);
+}
+
+########################################################################
+# wrc_output
+########################################################################
+
+sub wrc_output {
+    $file = shift;
+    local $_ = shift;
+}
+
+1;
diff --git a/tools/winapi/options.pm b/tools/winapi/options.pm
index 6ff005fd90d711b721233799917c5933928e4080..ac6d061703687dfbe314631f53548a9f03915139 100644
--- a/tools/winapi/options.pm
+++ b/tools/winapi/options.pm
@@ -40,9 +40,9 @@ sub new {
     my $self  = {};
     bless ($self, $class);
 
-    my $options_long = \%{$self->{OPTIONS_LONG}};
-    my $options_short = \%{$self->{OPTIONS_SHORT}};
-    my $options_usage = \${$self->{OPTIONS_USAGE}};
+    my $options_long = \%{$self->{_OPTIONS_LONG}};
+    my $options_short = \%{$self->{_OPTIONS_SHORT}};
+    my $options_usage = \${$self->{_OPTIONS_USAGE}};
 
     my $refoptions_long = shift;
     my $refoptions_short = shift;
@@ -53,12 +53,16 @@ sub new {
 
     $self->options_set("default");
 
-    my $c_files = \@{$self->{C_FILES}};
-    my $h_files = \@{$self->{H_FILES}};
-    my @files;
+    my $arguments = \@{$self->{_ARGUMENTS}};
 
+    my $end_of_options = 0;
     while(defined($_ = shift @ARGV)) {
-	if(/^--(all|none)$/) {
+	if(/^--$/) {
+	    $end_of_options = 1;
+	    next;
+	} elsif($end_of_options) {
+	    # Nothing
+	} elsif(/^--(all|none)$/) {
 	    $self->options_set("$1");
 	    next;
 	} elsif(/^-([^=]*)(=(.*))?$/) {
@@ -143,17 +147,12 @@ sub new {
 	    }
 	}
 	
-	if(/^-(.*)$/) {
+	if(!$end_of_options && /^-(.*)$/) {
 	    $output->write("unknown option: $_\n"); 
 	    $output->write($$options_usage);
 	    exit 1;
 	} else {
-	    if(!-e $_) {
-		$output->write("$_: no such file or directory\n");
-		exit 1;
-	    }
-
-	    push @files, $_;
+	    push @$arguments, $_;
 	}
     }
 
@@ -163,6 +162,33 @@ sub new {
 	exit 0;
     }
 
+    return $self;
+}
+
+sub DESTROY {
+}
+
+sub parse_files {
+    my $self = shift;
+
+    my $arguments = \@{$self->{_ARGUMENTS}};
+    my $c_files = \@{$self->{_C_FILES}};
+    my $h_files = \@{$self->{_H_FILES}};
+
+    my $error = 0;
+    my @files = ();
+    foreach (@$arguments) {
+	if(!-e $_) {
+	    $output->write("$_: no such file or directory\n");
+	    $error = 1;
+	} else {
+	    push @files, $_;
+	}
+    }
+    if($error) {
+	exit 1;
+    }
+
     my @paths = ();
     my @c_files = ();
     my @h_files = ();
@@ -186,7 +212,7 @@ sub new {
 	my %found;
 	@$c_files = sort(map {
 	    s/^\.\/(.*)$/$1/;
-	    if(defined($found{$_}) || /glue\.c|spec\.c$/) {
+	    if(defined($found{$_})) {
 		();
 	    } else {
 		$found{$_}++;
@@ -209,18 +235,13 @@ sub new {
 	    }
 	} split(/\n/, `$h_command`));
     }
-
-    return $self;
-}
-
-sub DESTROY {
 }
 
 sub options_set {
     my $self = shift;
 
-    my $options_long = \%{$self->{OPTIONS_LONG}};
-    my $options_short = \%{$self->{OPTIONS_SHORT}};
+    my $options_long = \%{$self->{_OPTIONS_LONG}};
+    my $options_short = \%{$self->{_OPTIONS_SHORT}};
 
     local $_ = shift;
     for my $name (sort(keys(%$options_long))) {
@@ -255,8 +276,8 @@ sub options_set {
 sub show_help {
     my $self = shift;
 
-    my $options_long = \%{$self->{OPTIONS_LONG}};
-    my $options_short = \%{$self->{OPTIONS_SHORT}};
+    my $options_long = \%{$self->{_OPTIONS_LONG}};
+    my $options_short = \%{$self->{_OPTIONS_SHORT}};
 
     my $maxname = 0;
     for my $name (sort(keys(%$options_long))) {
@@ -329,8 +350,36 @@ sub AUTOLOAD {
     }
 }
 
-sub c_files { my $self = shift; return @{$self->{C_FILES}}; }
+sub arguments { 
+    my $self = shift;
+
+    my $arguments = \@{$self->{_ARGUMENTS}};
+
+    return @$arguments; 
+}
+
+sub c_files {
+    my $self = shift; 
+
+    my $c_files = \@{$self->{_C_FILES}};
+
+    if(!defined(@$c_files)) {
+	$self->parse_files;
+    }
+
+    return @$c_files;
+}
+
+sub h_files { 
+    my $self = shift; 
+
+    my $h_files = \@{$self->{_H_FILES}};
 
-sub h_files { my $self = shift; return @{$self->{H_FILES}}; }
+    if(!defined(@$h_files)) {
+	$self->parse_files;
+    }
+
+    return @$h_files;
+}
 
 1;
diff --git a/tools/winapi/output.pm b/tools/winapi/output.pm
index 7c9bf0d427cbeb1667f418c97eec77a7abd93177..018d63f3e3f7a3deb1154d4bf2510cb488e7b002 100644
--- a/tools/winapi/output.pm
+++ b/tools/winapi/output.pm
@@ -26,6 +26,7 @@ sub new {
     my $self  = {};
     bless ($self, $class);
 
+    my $progress_enabled = \${$self->{PROGRESS_ENABLED}};
     my $progress = \${$self->{PROGRESS}};
     my $last_progress = \${$self->{LAST_PROGRESS}};
     my $last_time = \${$self->{LAST_TIME}};
@@ -33,6 +34,7 @@ sub new {
     my $prefix = \${$self->{PREFIX}};
     my $prefix_callback = \${$self->{PREFIX_CALLBACK}};
 
+    $$progress_enabled = 1;
     $$progress = "";
     $$last_progress = "";
     $$last_time = 0;
@@ -43,62 +45,91 @@ sub new {
     return $self;
 }
 
+sub DESTROY {
+    my $self = shift;
+
+    $self->hide_progress;
+}
+
+sub enable_progress {
+    my $self = shift;
+    my $progress_enabled = \${$self->{PROGRESS_ENABLED}};
+
+    $$progress_enabled = 1;
+}
+
+sub disable_progress {
+    my $self = shift;
+    my $progress_enabled = \${$self->{PROGRESS_ENABLED}};
+
+    $$progress_enabled = 0;
+}
+
 sub show_progress {
     my $self = shift;
+    my $progress_enabled = \${$self->{PROGRESS_ENABLED}};
     my $progress = \${$self->{PROGRESS}};
     my $last_progress = \${$self->{LAST_PROGRESS}};
     my $progress_count = \${$self->{PROGRESS_COUNT}};
 
     $$progress_count++;
 
-    if($$progress_count > 0 && $$progress && $stderr_isatty) {
-	print STDERR $$progress;
-	$$last_progress = $$progress;
+    if($$progress_enabled) {
+	if($$progress_count > 0 && $$progress && $stderr_isatty) {
+	    print STDERR $$progress;
+	    $$last_progress = $$progress;
+	}
     }
 }
 
 sub hide_progress  {
     my $self = shift;
+    my $progress_enabled = \${$self->{PROGRESS_ENABLED}};
     my $progress = \${$self->{PROGRESS}};
     my $last_progress = \${$self->{LAST_PROGRESS}};
     my $progress_count = \${$self->{PROGRESS_COUNT}};
 
     $$progress_count--;
 
-    if($$last_progress && $stderr_isatty) {
-	my $message;
-	for (1..length($$last_progress)) {
-	    $message .= " ";
+    if($$progress_enabled) {
+	if($$last_progress && $stderr_isatty) {
+	    my $message;
+	    for (1..length($$last_progress)) {
+		$message .= " ";
+	    }
+	    print STDERR $message;
+	    undef $$last_progress;
 	}
-	print STDERR $message;
-	undef $$last_progress;
     }
 }
 
 sub update_progress {
     my $self = shift;
+    my $progress_enabled = \${$self->{PROGRESS_ENABLED}};
     my $progress = \${$self->{PROGRESS}};
     my $last_progress = \${$self->{LAST_PROGRESS}};
     
-    my $prefix = "";
-    my $suffix = "";
-    if($$last_progress) {
-	for (1..length($$last_progress)) {
-	    $prefix .= "";
-	}
-	
-	my $diff = length($$last_progress)-length($$progress);
-	if($diff > 0) {
-	    for (1..$diff) {
-		$suffix .= " ";
+    if($$progress_enabled) {
+	my $prefix = "";
+	my $suffix = "";
+	if($$last_progress) {
+	    for (1..length($$last_progress)) {
+		$prefix .= "";
 	    }
-	    for (1..$diff) {
-		$suffix .= "";
+	    
+	    my $diff = length($$last_progress)-length($$progress);
+	    if($diff > 0) {
+		for (1..$diff) {
+		    $suffix .= " ";
+		}
+		for (1..$diff) {
+		    $suffix .= "";
+		}
 	    }
 	}
+	print STDERR $prefix . $$progress . $suffix;
+	$$last_progress = $$progress;
     }
-    print STDERR $prefix . $$progress . $suffix;
-    $$last_progress = $$progress;
 }
 
 sub progress {
diff --git a/tools/winapi/type.pm b/tools/winapi/type.pm
new file mode 100644
index 0000000000000000000000000000000000000000..3608355e7bca55d0ec696d27d381ce21835d7831
--- /dev/null
+++ b/tools/winapi/type.pm
@@ -0,0 +1,14 @@
+package type;
+
+use strict;
+
+sub new {
+    my $proto = shift;
+    my $class = ref($proto) || $proto;
+    my $self  = {};
+    bless ($self, $class);
+
+    return $self;
+}
+
+1;
diff --git a/tools/winapi/winapi_check_options.pm b/tools/winapi/winapi_check_options.pm
index 22d5e8a466fa2dc862641dd8195ff525d0bf203c..88dab8c317b95319fc4df7b72298561cce54901c 100644
--- a/tools/winapi/winapi_check_options.pm
+++ b/tools/winapi/winapi_check_options.pm
@@ -127,16 +127,10 @@ my %options_short = (
     "v" => "verbose"
 );
 
-my $options_usage = "usage: winapi_fixup [--help] [<files>]\n";
+my $options_usage = "usage: winapi_check [--help] [<files>]\n";
 
 $options = '_winapi_check_options'->new(\%options_long, \%options_short, $options_usage);
 
-my $global = \${$options->{GLOBAL}};
-
-if($wine_dir ne ".") {
-    $$global = 0;
-}
-
 package _winapi_check_options;
 use base qw(_options);
 
diff --git a/tools/winapi/winapi_extract b/tools/winapi/winapi_extract
index c93c1e29e20a89f73a2363ff686a6e1528a2a5bf..842383698d4f2e712eacbd39a8c64954a86eaac6 100755
--- a/tools/winapi/winapi_extract
+++ b/tools/winapi/winapi_extract
@@ -13,18 +13,18 @@ use config qw(
     &file_type &files_skip &files_filter &get_spec_files
     $current_dir $wine_dir $winapi_dir $winapi_check_dir
 );
-use modules;
-use nativeapi;
 use output qw($output);
-use options;
-use winapi;
+use winapi_extract_options qw($options);
+
+use function;
+use type;
 use winapi_function;
 use winapi_parser;
-use winapi_extract_options qw($options);
+use winapi qw(@winapis);
 
 my %module2spec_file;
 my %module2type;
-{
+if($options->spec_files) {
     local $_;
 
     foreach my $spec_file (get_spec_files("winelib")) {
@@ -49,22 +49,6 @@ my %module2type;
     }
 }
 
-my $modules = 'modules'->new($options, $output, $wine_dir, $current_dir, \&file_type, "$winapi_check_dir/modules.dat");
-
-my $win16api = 'winapi'->new($options, $output, "win16", "$winapi_check_dir/win16");
-my $win32api = 'winapi'->new($options, $output, "win32", "$winapi_check_dir/win32");
-my @winapis = ($win16api, $win32api);
-
-if($wine_dir eq ".") {
-    'winapi'->read_all_spec_files($modules, $wine_dir, $current_dir, \&file_type, $win16api, $win32api);
-} else {
-    my @spec_files = $modules->allowed_spec_files($wine_dir, $current_dir);
-    'winapi'->read_spec_files($modules, $wine_dir, $current_dir, \@spec_files, $win16api, $win32api);
-}
-
-my $nativeapi = 'nativeapi'->new($options, $output, "$winapi_check_dir/nativeapi.dat", 
-				 "$wine_dir/configure.in", "$wine_dir/include/config.h.in");
-
 my %specifications;
 
 sub documentation_specifications {
@@ -164,6 +148,14 @@ foreach my $file (@c_files) {
 	$output->progress("$file: file $progress_current of $progress_max");
     }
 
+    my $create_function = sub {
+	if($options->stub_statistics) {
+	    return 'winapi_function'->new;
+	} else {
+	    return 'function'->new;
+	}
+    };
+
     my $found_function = sub {
 	my $function = shift;
 
@@ -191,12 +183,20 @@ foreach my $file (@c_files) {
 	$output->prefix("");
     };
 
+    my $create_type = sub {
+	return 'type'->new;
+    };
+
+    my $found_type = sub {
+	my $type = shift;
+    };
+
     my $found_preprocessor = sub {
 	my $directive = shift;
 	my $argument = shift;
     };
 
-    &winapi_parser::parse_c_file($options, $file, $found_function, $found_preprocessor);
+    &winapi_parser::parse_c_file($file, $create_function, $found_function, $create_type, $found_type, $found_preprocessor);
 
     my @internal_names = keys(%functions);
     if($#internal_names < 0) {
@@ -342,7 +342,7 @@ if($options->stub_statistics) {
 	
 	foreach my $internal_name ($winapi->all_internal_functions,$winapi->all_functions_stub) {
 	    foreach my $module (split(/ \& /, $winapi->function_internal_module($internal_name))) {
-		if($winapi->function_stub($internal_name)) {
+		if($winapi->is_function_stub_in_module($module, $internal_name)) {
 		    $module_stub_count{$module}++;
 		}
 		$module_total_count{$module}++;
@@ -372,4 +372,3 @@ if($options->stub_statistics) {
     } 
 }
 
-$output->hide_progress;
diff --git a/tools/winapi/winapi_extract_options.pm b/tools/winapi/winapi_extract_options.pm
index 0e4e978200004d6bd4b5e9e886186fdf1129e0bb..3d296213c05fc8b68aff9c67eead8594c6281021 100644
--- a/tools/winapi/winapi_extract_options.pm
+++ b/tools/winapi/winapi_extract_options.pm
@@ -26,7 +26,7 @@ my %options_long = (
     "global" => { default => 1, description => "global extraction" },
 
     "spec-files" => { default => 1, parent => "global", description => "spec files extraction" },
-    "stub-statistics" => { default => 0, parent => "global", description => "stub statistics" },
+    "stub-statistics" => { default => 1, parent => "global", description => "stub statistics" },
 );
 
 my %options_short = (
diff --git a/tools/winapi/winapi_fixup b/tools/winapi/winapi_fixup
index 4a87ba222652afc2b883458aabe33b97bcabc455..f04313842a269c3f7a05e944f5db114b3fb2bee7 100755
--- a/tools/winapi/winapi_fixup
+++ b/tools/winapi/winapi_fixup
@@ -17,24 +17,14 @@ use config qw(
     $current_dir $wine_dir $winapi_dir $winapi_check_dir
 );
 use output qw($output);
-use modules;
-use util;
-use winapi;
-use winapi_parser;
 use winapi_fixup_options qw($options);
+use modules qw($modules);
+use winapi qw($win16api $win32api @winapis);
 
-my $modules = 'modules'->new($options, $output, $wine_dir, $current_dir, \&file_type, "$winapi_check_dir/modules.dat");
-
-my $win16api = 'winapi'->new($options, $output, "win16", "$winapi_check_dir/win16");
-my $win32api = 'winapi'->new($options, $output, "win32", "$winapi_check_dir/win32");
-my @winapis = ($win16api, $win32api);
-
-if($wine_dir eq ".") {
-    'winapi'->read_all_spec_files($modules, $wine_dir, $current_dir, \&file_type, $win16api, $win32api);
-} else {
-    my @spec_files = $modules->allowed_spec_files($wine_dir, $current_dir);
-    'winapi'->read_spec_files($modules, $wine_dir, $current_dir, \@spec_files, $win16api, $win32api);
-}
+use type;
+use util;
+use winapi_function;
+use winapi_parser;
 
 my @c_files = $options->c_files;
 @c_files = files_skip(@c_files);
@@ -58,6 +48,10 @@ foreach my $file (@c_files) {
 
     my %documentation_line_used;
 
+    my $create_function = sub {
+	return 'winapi_function'->new;
+    };
+
     my $found_function = sub {
 	my $function = shift;
 	
@@ -434,12 +428,21 @@ foreach my $file (@c_files) {
 	$output->prefix("");
     };
 
+
+    my $create_type = sub {
+	return 'type'->new;
+    };
+
+    my $found_type = sub {
+	my $type = shift;
+    };
+
     my $found_preprocessor = sub {
 	my $directive = shift;
 	my $argument = shift;
     };
 
-    &winapi_parser::parse_c_file($options, $file, $found_function, $found_preprocessor);
+    &winapi_parser::parse_c_file($file, $create_function, $found_function, $create_type, $found_type, $found_preprocessor);
 
     my $editor = sub {
 	local *IN = shift;
@@ -598,4 +601,3 @@ foreach my $file (@c_files) {
     }
 }
 
-$output->hide_progress;
diff --git a/tools/winapi_check/modules.dat b/tools/winapi_check/modules.dat
index eb72aba5dca707d6dab5deac1d6588d435c51609..706a32e6dae8d822705b47246ca06584590e40db 100644
--- a/tools/winapi_check/modules.dat
+++ b/tools/winapi_check/modules.dat
@@ -344,7 +344,6 @@ dlls/user
 % dlls/user/user.spec
 
 controls
-dlls/kernel
 dlls/user
 misc
 windows
diff --git a/tools/winapi_check/modules.pm b/tools/winapi_check/modules.pm
index 34f338e3db25b6baf398c12ca57d74247d8cedc8..357e8504dfbf741e31add91f7edeaf0460e8b86b 100644
--- a/tools/winapi_check/modules.pm
+++ b/tools/winapi_check/modules.pm
@@ -11,30 +11,33 @@ require Exporter;
 
 use vars qw($modules);
 
+use config qw(
+    &file_type &files_skip
+    &file_directory
+    &get_c_files 
+    $current_dir $wine_dir
+    $winapi_check_dir
+);
+use options qw($options);
+use output qw($output);
+
+$modules = 'modules'->new;
+
 sub new {
     my $proto = shift;
     my $class = ref($proto) || $proto;
     my $self  = {};
     bless ($self, $class);
 
-    my $options = \${$self->{OPTIONS}};
-    my $output = \${$self->{OUTPUT}};
     my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
     my $spec_file2dir = \%{$self->{SPEC_FILE2DIR}};
     my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
 
-    $$options = shift;
-    $$output = shift;
-    my $wine_dir = shift;
-    my $current_dir = shift;
-    my $file_type = shift;    
-    my $module_file = shift;
-
-    $module_file =~ s/^\.\///;
+    my $module_file = "$winapi_check_dir/modules.dat";
 
     my @all_spec_files = map {
 	s/^.\/(.*)$/$1/;
-	if(&$file_type($_) eq "winelib") {
+	if(file_type($_) eq "winelib") {
 	    $_;
 	} else {
 	    ();
@@ -46,8 +49,8 @@ sub new {
 	$all_spec_files{$file}++ ;
     }
 
-    if($$options->progress) {
-	$$output->progress("modules.dat");
+    if($options->progress) {
+	$output->progress("modules.dat");
     }
 
     my $allowed_dir;
@@ -64,7 +67,7 @@ sub new {
 	    $spec_file = $1;
 	   
 	    if(!-f "$wine_dir/$spec_file") {
-		$$output->write("modules.dat: $spec_file: file ($spec_file) doesn't exist or is no file\n");
+		$output->write("modules.dat: $spec_file: file ($spec_file) doesn't exist or is no file\n");
 	    } 
 
 	    if($wine_dir eq ".") {
@@ -81,14 +84,14 @@ sub new {
 	$$dir2spec_file{$allowed_dir}{$spec_file}++;
 
 	if(!-d "$wine_dir/$allowed_dir") {
-	    $$output->write("modules.dat: $spec_file: directory ($allowed_dir) doesn't exist or is no directory\n");
+	    $output->write("modules.dat: $spec_file: directory ($allowed_dir) doesn't exist or is no directory\n");
 	} 
     }
     close(IN);
 
     foreach my $spec_file (sort(keys(%all_spec_files))) {
 	if($all_spec_files{$spec_file} > 0) {
-	    $$output->write("modules.dat: $spec_file: exists but is not specified\n");
+	    $output->write("modules.dat: $spec_file: exists but is not specified\n");
 	}
     }
 
@@ -105,6 +108,44 @@ sub all_modules {
     return sort(keys(%$module2spec_file));
 }
 
+sub complete_modules {
+    my $self = shift;
+
+    my $c_files = shift;
+
+    my %dirs;
+
+    foreach my $file (@$c_files) {
+	my $dir = file_directory("$current_dir/$file");
+	$dirs{$dir}++;
+    }
+
+    my @c_files = get_c_files("winelib");
+    @c_files = files_skip(@c_files);
+    foreach my $file (@c_files) {
+	my $dir = file_directory($file);
+	if(exists($dirs{$dir})) {
+	    $dirs{$dir}--;
+	}
+    }
+
+    my @complete_modules = ();
+    foreach my $module ($self->all_modules) {
+	my $index = -1;
+	my @dirs = $self->allowed_dirs_for_module($module);
+	foreach my $dir (@dirs) {
+	    if(exists($dirs{$dir}) && $dirs{$dir} == 0) { 
+		$index++;
+	    }
+	}
+	if($index == $#dirs) {
+	    push @complete_modules, $module;
+	}
+    }
+
+    return @complete_modules;
+}
+
 sub spec_file_module {
     my $self = shift;
 
@@ -183,13 +224,8 @@ sub allowed_dirs_for_module {
 sub allowed_spec_files {
     my $self = shift;
 
-    my $options = \${$self->{OPTIONS}};
-    my $output = \${$self->{OUTPUT}};
     my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
 
-    my $wine_dir = shift;
-    my $current_dir = shift;
-
     my @dirs = map {
 	s/^\.\/(.*)$/$1/;
 	if(/^\.$/) {
@@ -227,7 +263,6 @@ sub found_module_in_dir {
 sub global_report {
     my $self = shift;
 
-    my $output = \${$self->{OUTPUT}};
     my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
     my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
     my $used_module_dirs = \%{$self->{USED_MODULE_DIRS}};
@@ -244,7 +279,7 @@ sub global_report {
     }
 
     foreach my $message (sort(@messages)) {
-	$$output->write($message);
+	$output->write($message);
     }
 }
 
diff --git a/tools/winapi_check/nativeapi.pm b/tools/winapi_check/nativeapi.pm
index e73a6ca713649d764224531f910f791586da253b..dc5bf38d349383cf237eb4add115cd4220c7f2ba 100644
--- a/tools/winapi_check/nativeapi.pm
+++ b/tools/winapi_check/nativeapi.pm
@@ -11,31 +11,33 @@ require Exporter;
 
 use vars qw($nativeapi);
 
+use config qw(&file_type $current_dir $wine_dir $winapi_check_dir);
+use options qw($options);
+use output qw($output);
+
+$nativeapi = 'nativeapi'->new;
+
 sub new {
     my $proto = shift;
     my $class = ref($proto) || $proto;
     my $self  = {};
     bless ($self, $class);
 
-    my $options = \${$self->{OPTIONS}};
-    my $output = \${$self->{OUTPUT}};
     my $functions = \%{$self->{FUNCTIONS}};
     my $conditionals = \%{$self->{CONDITIONALS}};
     my $conditional_headers = \%{$self->{CONDITIONAL_HEADERS}};
     my $conditional_functions = \%{$self->{CONDITIONAL_FUNCTIONS}};
 
-    $$options = shift;
-    $$output = shift;
-    my $api_file = shift;
-    my $configure_in_file = shift;
-    my $config_h_in_file = shift;
+    my $api_file = "$winapi_check_dir/nativeapi.dat";
+    my $configure_in_file = "$wine_dir/configure.in";
+    my $config_h_in_file = "$wine_dir/include/config.h.in";
 
     $api_file =~ s/^\.\///;
     $configure_in_file =~ s/^\.\///;
     $config_h_in_file =~ s/^\.\///;
 
-    if($$options->progress) {
-	$$output->progress("$api_file");
+    if($options->progress) {
+	$output->progress("$api_file");
     }
 
     open(IN, "< $api_file");
@@ -49,8 +51,8 @@ sub new {
     }
     close(IN);
 
-    if($$options->progress) {
-	$$output->progress("$configure_in_file");
+    if($options->progress) {
+	$output->progress("$configure_in_file");
     }
 
     my $again = 0;
@@ -100,8 +102,8 @@ sub new {
     }
     close(IN);
 
-    if($$options->progress) {
-	$$output->progress("$config_h_in_file");
+    if($options->progress) {
+	$output->progress("$config_h_in_file");
     }
 
     open(IN, "< $config_h_in_file");
@@ -186,7 +188,7 @@ sub global_report {
     }
 
     foreach my $message (sort(@messages)) {
-	$$output->write($message);
+	$output->write($message);
     }
 }
 
diff --git a/tools/winapi_check/winapi.pm b/tools/winapi_check/winapi.pm
index e58e1fe6f5d403e2603d8ce65afd8768ce053816..813aa6ad7ef23fe49482a2d162de48a1221c2103 100644
--- a/tools/winapi_check/winapi.pm
+++ b/tools/winapi_check/winapi.pm
@@ -11,49 +11,53 @@ require Exporter;
 
 use vars qw($win16api $win32api @winapis);
 
+use config qw(
+    &file_type
+    &get_api_files &get_spec_files
+    $current_dir $wine_dir
+);
+use modules qw($modules);
+use options qw($options);
+use output qw($output);
+
+$win16api = 'winapi'->new("win16");
+$win32api = 'winapi'->new("win32");
+@winapis = ($win16api, $win32api);
+
+my @spec_files = get_spec_files("winelib");
+foreach my $file (@spec_files) {
+    (my $type, my $module) = 'winapi'->get_spec_file_type("$wine_dir/$file");
+    $modules->spec_file_module($file, $module);
+}
+
+if($wine_dir eq ".") {
+    'winapi'->read_spec_files(\@spec_files);
+} else {
+    @spec_files = $modules->allowed_spec_files;
+    'winapi'->read_spec_files(\@spec_files);
+}
+
 sub new {
     my $proto = shift;
     my $class = ref($proto) || $proto;
     my $self  = {};
     bless ($self, $class);
 
-    my $options = \${$self->{OPTIONS}};
-    my $output = \${$self->{OUTPUT}};
     my $name = \${$self->{NAME}};
 
-    $$options = shift;
-    $$output = shift;
     $$name = shift;
-    my $path = shift;
-
-    if($$options->progress) {
-	$$output->progress("$path: searching for *.api");
-    }
 
-    my @files = map {
-	s%^\./%%;
-	$_; 
-    } split(/\n/, `find $path -name \\*.api`);
-  
-    foreach my $file (@files) {
+    foreach my $file (get_api_files($$name)) {
 	my $module = $file;
 
-	if($$options->progress) {
-	    $$output->lazy_progress("$file");
+	if($options->progress) {
+	    $output->lazy_progress("$file");
 	}
 
 	$module =~ s/.*?\/([^\/]*?)\.api$/$1/;
 	$self->parse_api_file($file,$module);
     }   
 
-    if($$name eq "win16") {
-	$win16api = $self;
-    } elsif($$name eq "win32") {
-	$win32api = $self;
-    }
-
-    push @winapis, $self;
-
     return $self;
 }
 
@@ -68,8 +72,6 @@ sub win32api {
 sub parse_api_file {
     my $self = shift;
 
-    my $options = \${$self->{OPTIONS}};
-    my $output = \${$self->{OUTPUT}};
     my $allowed_kind = \%{$self->{ALLOWED_KIND}};
     my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
     my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
@@ -85,11 +87,11 @@ sub parse_api_file {
     my $extension = 0;
     my $forbidden = 0;
 
-    if($$options->progress) {
-	$$output->progress("$file");
+    if($options->progress) {
+	$output->progress("$file");
     }
 
-    open(IN, "< $file") || die "$file: $!\n";
+    open(IN, "< $wine_dir/$file") || die "$wine_dir/$file: $!\n";
     $/ = "\n";
     while(<IN>) {
 	s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begin and end of line
@@ -143,12 +145,12 @@ sub parse_api_file {
 	    if(!$forbidden) {
 		if(defined($module)) {
 		    if($$allowed_modules_unlimited{$type}) {
-			$$output->write("$file: type ($type) already specificed as an unlimited type\n");
+			$output->write("$file: type ($type) already specificed as an unlimited type\n");
 		    } elsif(!$$allowed_modules{$type}{$module}) {
 			$$allowed_modules{$type}{$module} = 1;
 			$$allowed_modules_limited{$type} = 1;
 		    } else {
-			$$output->write("$file: type ($type) already specificed\n");
+			$output->write("$file: type ($type) already specificed\n");
 		    }
 		} else {
 		    $$allowed_modules_unlimited{$type} = 1;
@@ -157,14 +159,14 @@ sub parse_api_file {
 		$$allowed_modules_limited{$type} = 1;
 	    }
 	    if(defined($$translate_argument{$type}) && $$translate_argument{$type} ne $kind) {
-		$$output->write("$file: type ($type) respecified as different kind ($kind != $$translate_argument{$type})\n");
+		$output->write("$file: type ($type) respecified as different kind ($kind != $$translate_argument{$type})\n");
 	    } else {
 		$$translate_argument{$type} = $kind;
 	    }
 		
 	    $$type_format{$module}{$type} = $format;
 	} else {
-	    $$output->write("$file: file must begin with %<type> statement\n");
+	    $output->write("$file: file must begin with %<type> statement\n");
 	    exit 1;
 	}
     }
@@ -201,16 +203,10 @@ sub read_spec_files {
     my $proto = shift;
     my $class = ref($proto) || $proto;
 
-    my $modules = shift;
-    my $wine_dir = shift;
-    my $current_dir = shift;
     my $files = shift;
-    my $win16api = shift;
-    my $win32api = shift;
 
     foreach my $file (@$files) {
 	(my $type, my $module) = 'winapi'->get_spec_file_type("$wine_dir/$file");
-	$modules->spec_file_module($file, $module);
 	if($type eq "win16") {
 	    $win16api->parse_spec_file("$wine_dir/$file");
 	} elsif($type eq "win32") {
@@ -246,34 +242,9 @@ sub read_spec_files {
     }
 }
 
-sub read_all_spec_files {
-    my $proto = shift;
-    my $class = ref($proto) || $proto;
-
-    my $modules = shift;    
-    my $wine_dir = shift;
-    my $current_dir = shift;
-    my $file_type = shift;
-    my $win16api = shift;
-    my $win32api = shift;
-
-    my @files = map {
-	s%^$wine_dir/%%;
-	if(&$file_type($_) eq "winelib") {
-	    $_;
-	} else {
-	    ();
-	}
-    } split(/\n/, `find $wine_dir -name \\*.spec`);
-    
-    'winapi'->read_spec_files($modules, $wine_dir, $current_dir, \@files, $win16api, $win32api); 
-}
-
 sub parse_spec_file {
     my $self = shift;
 
-    my $options = \${$self->{OPTIONS}};
-    my $output = \${$self->{OUTPUT}};
     my $function_internal_arguments = \%{$self->{FUNCTION_INTERNAL_ARGUMENTS}};
     my $function_external_arguments = \%{$self->{FUNCTION_EXTERNAL_ARGUMENTS}};
     my $function_internal_ordinal = \%{$self->{FUNCTION_INTERNAL_ORDINAL}};
@@ -297,8 +268,8 @@ sub parse_spec_file {
     my $module;
     my $module_file;
 
-    if($$options->progress) {
-	$$output->lazy_progress("$file");
+    if($options->progress) {
+	$output->lazy_progress("$file");
     }
 
     open(IN, "< $file") || die "$file: $!\n";
@@ -366,10 +337,10 @@ sub parse_spec_file {
 		$$function_external_module{$external_name} .= " & $module";
 	    }
 
-	    if(0 && $$options->spec_mismatch) {
+	    if(0 && $options->spec_mismatch) {
 		if($external_name eq "@") {
 		    if($internal_name !~ /^\U$module\E_$ordinal$/) {
-			$$output->write("$file: $external_name: the internal name ($internal_name) mismatch\n");
+			$output->write("$file: $external_name: the internal name ($internal_name) mismatch\n");
 		    }
 		} else {
 		    my $name = $external_name;
@@ -393,7 +364,7 @@ sub parse_spec_file {
 		    if(uc($internal_name) ne uc($external_name) &&
 		       $internal_name !~ /(\Q$name\E|\Q$name1\E|\Q$name2\E|\Q$name3\E|\Q$name4\E|\Q$name5\E)/)
 		    {
-			$$output->write("$file: $external_name: internal name ($internal_name) mismatch\n");
+			$output->write("$file: $external_name: internal name ($internal_name) mismatch\n");
 		    }
 		}
 	    }
@@ -466,7 +437,7 @@ sub parse_spec_file {
 	
 	if(defined($ordinal)) {
 	    if($ordinal ne "@" && $ordinals{$ordinal}) {
-		$$output->write("$file: ordinal redefined: $_\n");
+		$output->write("$file: ordinal redefined: $_\n");
 	    }
 	    $ordinals{$ordinal}++;
 	}
@@ -556,7 +527,6 @@ sub types_not_used {
 sub types_unlimited_used_in_modules {
     my $self = shift;
 
-    my $output = \${$self->{OUTPUT}};
     my $used_modules = \%{$self->{USED_MODULES}};
     my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
     my $allowed_modules_unlimited = \%{$self->{ALLOWED_MODULES_UNLIMITED}};
diff --git a/tools/winapi_check/winapi_check b/tools/winapi_check/winapi_check
index 0c64082ee2ff2b8ead914ee8c3417863328d0a19..f327cd56656bdbb26c688d6fc578b91de12e3f90 100755
--- a/tools/winapi_check/winapi_check
+++ b/tools/winapi_check/winapi_check
@@ -20,38 +20,25 @@ BEGIN {
 }
 
 use config qw(
-    &file_type &files_filter &files_skip
-    &get_h_files	      
-    $current_dir $wine_dir $winapi_dir $winapi_check_dir
+    &files_filter &files_skip
+    &get_h_files
+    $current_dir $wine_dir
 );
-use modules;
-use nativeapi;
 use output qw($output);
+use winapi_check_options qw($options);
+use modules qw($modules);
+use nativeapi qw($nativeapi);
+use winapi qw($win16api $win32api @winapis);
+
 use preprocessor;
+use type;
 use util qw(&is_subset);
-use winapi;
 use winapi_documentation;
 use winapi_function;
 use winapi_local;
 use winapi_global;
-use winapi_check_options qw($options);
 use winapi_parser;
 
-my $modules = 'modules'->new($options, $output, $wine_dir, $current_dir, \&file_type, "$winapi_check_dir/modules.dat");
-
-my $win16api = 'winapi'->new($options, $output, "win16", "$winapi_check_dir/win16");
-my $win32api = 'winapi'->new($options, $output, "win32", "$winapi_check_dir/win32");
-my @winapis = ($win16api, $win32api);
-
-if($options->global) {
-    'winapi'->read_all_spec_files($modules, $wine_dir, $current_dir, \&file_type, $win16api, $win32api);
-} else {
-    my @spec_files = $modules->allowed_spec_files($wine_dir, $current_dir);
-    'winapi'->read_spec_files($modules, $wine_dir, $current_dir, \@spec_files, $win16api, $win32api);
-}
-
-my $nativeapi = 'nativeapi'->new($options, $output, "$winapi_check_dir/nativeapi.dat", "$wine_dir/configure.in", "$wine_dir/include/config.h.in");
-
 my %declared_functions;
 
 my %include2info;
@@ -125,6 +112,10 @@ if($options->headers) {
 	    $output->progress("$file: file $progress_current of $progress_max");
 	}
 
+	my $create_function = sub {
+	    return 'winapi_function'->new;
+	};
+
 	my $found_function = sub {
 	    my $function = shift;
 
@@ -156,6 +147,15 @@ if($options->headers) {
 		    $output->write("duplicate declaration (first declaration at $file:$function_line)\n");
 		}
 	    }
+	    $output->prefix("");
+	};
+
+	my $create_type = sub {
+	    return 'type'->new;
+	};
+
+	my $found_type = sub {
+	    my $type = shift;
 	};
 
 	my $found_preprocessor = sub {
@@ -163,7 +163,7 @@ if($options->headers) {
 	    my $argument = shift;
 	};
 
-        &winapi_parser::parse_c_file($options, $file, $found_function, $found_preprocessor);
+        &winapi_parser::parse_c_file($file, $create_function, $found_function, $create_type, $found_type, $found_preprocessor);
     }
 }
 
@@ -188,6 +188,10 @@ foreach my $file (@c_files) {
     if(!($file_dir =~ s/(.*?)\/[^\/]*$/$1/)) {
 	$file_dir = ".";
     }
+
+    my $create_function = sub {
+	return 'winapi_function'->new;
+    };
    
     my $found_function = sub {
 	my $function = shift;
@@ -273,19 +277,19 @@ foreach my $file (@c_files) {
 	    }
 	}
 
-	if($options->local && $options->argument) {
+	if($options->local && $options->argument && defined($statements)) {
 	    &winapi_local::check_function($function);
 	}
 	
-	if($options->local && $options->statements) {
+	if($options->local && $options->statements && defined($statements)) {
 	    &winapi_local::check_statements(\%functions, $function);
 	}
 	
 	if($options->local && $options->documentation &&
 	   (defined($module16) || defined($module32)) &&
-	   $linkage ne "static" && ($linkage ne "" || defined($statements)))
+	   $linkage eq "" && defined($statements))
 	{
-	    &winapi_documentation::check_documentation($function);
+	    # &winapi_documentation::check_documentation($function);
 	}
 
 	if(1) {
@@ -386,6 +390,15 @@ foreach my $file (@c_files) {
 	    }
 	}
     };
+
+    my $create_type = sub {
+	return 'type'->new;
+    };
+    
+    my $found_type = sub {
+	my $type = shift;
+    };
+
     my $preprocessor = 'preprocessor'->new($found_include, $found_conditional);
     my $found_preprocessor = sub {
 	my $directive = shift;
@@ -511,7 +524,7 @@ foreach my $file (@c_files) {
 	}
     };
   
-    &winapi_parser::parse_c_file($options, $file, $found_function, $found_preprocessor);
+    &winapi_parser::parse_c_file($file, $create_function, $found_function, $create_type, $found_type, $found_preprocessor);
     
     if($options->config_unnessary) {
 	if($config && $conditional == 0) {
@@ -522,74 +535,69 @@ foreach my $file (@c_files) {
     &winapi_local::check_file($file, \%functions);
 }
 
-$output->hide_progress;
+if($options->global) {
+    my @complete_modules = $modules->complete_modules(\@c_files);
+    my %complete_module;
 
-if($options->declared) {
-    my %dirs;
-    foreach my $file (@c_files) {
-	my $dir = $file;
-	$dir =~ s%/?[^/]*$%%;
-	if($dir) {
-	    if($current_dir ne ".") {
-		$dir = "$current_dir/$dir";
-	    }
-	} else {
-	    $dir = "$current_dir"; 
-	}
-	$dirs{$dir}++;
+    foreach my $module (@complete_modules) {
+	$complete_module{$module}++;
     }
 
-    foreach my $module ($modules->all_modules) {
-	my $incomplete = 0;
-	foreach my $module_dir ($modules->allowed_dirs_for_module($module)) {    
-	    my $found = 0;
-	    foreach my $dir (sort(keys(%dirs))) {
-		if($module_dir eq $dir) {
-		    $found = 1;
-		    last;
-		}
-	    }
-	    if(!$found) {
-		$incomplete = 1;
-	    }
-	}
-	if(!$incomplete) {
-	    if($options->declared) {
-		foreach my $winapi (@winapis) {
-		    if(!$winapi->is_module($module)) { next; }
-		    my $functions = $module2functions{$module};
-		    foreach my $internal_name ($winapi->all_internal_functions_in_module($module)) {
-			my $function = $functions->{$internal_name};
-			if(!defined($function) && !$nativeapi->is_function($internal_name) &&
-			   !($module eq "user" && $internal_name =~
-			     /^(?:GlobalAddAtomA|GlobalDeleteAtom|GlobalFindAtomA|
-				GlobalGetAtomNameA|lstrcmpiA)$/x))
-			{
-			    $output->write("*.c: $module: $internal_name: " .
-					   "function declared but not implemented or declared external\n");
-			}
+    if($options->declared) {
+	foreach my $module (@complete_modules) {
+	    foreach my $winapi (@winapis) {
+		if(!$winapi->is_module($module)) { next; }
+		my $functions = $module2functions{$module};
+		foreach my $internal_name ($winapi->all_internal_functions_in_module($module)) {
+		    my $function = $functions->{$internal_name};
+		    if(!defined($function) && !$nativeapi->is_function($internal_name) &&
+		       !($module eq "user" && $internal_name =~
+			 /^(?:GlobalAddAtomA|GlobalDeleteAtom|GlobalFindAtomA|
+			    GlobalGetAtomNameA|lstrcmpiA)$/x))
+		    {
+			$output->write("*.c: $module: $internal_name: " .
+				       "function declared but not implemented or declared external\n");
 		    }
 		}
 	    }
 	}
     }
-}
-
-if($options->global) {
-    &winapi_documentation::report_documentation;
 
-    if($options->headers_unused) {
-	foreach my $name (sort(keys(%include2info))) {
-	    if(!$include2info{$name}{used}) {
-		if($options->include) {
-		    $output->write("*.c: $name: include file is never used\n");
+    if($options->argument && $options->argument_forbidden) {
+	foreach my $winapi (@winapis) {
+	    my $types_not_used = $winapi->types_not_used;
+	    foreach my $module (sort(keys(%$types_not_used))) {
+		if(!$complete_module{$module}) { next; }
+		foreach my $type (sort(keys(%{$$types_not_used{$module}}))) {
+		    $output->write("*.c: $module: type ($type) not used\n");
 		}
 	    }
 	}
     }
 
-    &winapi_global::check(\%type_found);
+    my $all_modules = 1;
+    foreach my $module ($modules->all_modules) {
+	if(!$complete_module{$module}) {
+	    $all_modules = 0;
+	}
+    }
+    if($all_modules) {
+	&winapi_documentation::report_documentation;
+	
+	if($options->headers_unused) {
+	    foreach my $name (sort(keys(%include2info))) {
+		if(!$include2info{$name}{used}) {
+		    if($options->include) {
+			$output->write("*.c: $name: include file is never used\n");
+		    }
+		}
+	    }
+	}
+	
+	&winapi_global::check(\%type_found);
 
-    $modules->global_report;
-    $nativeapi->global_report;
+	$modules->global_report;
+	$nativeapi->global_report;
+    }
 }
+
diff --git a/tools/winapi_check/winapi_global.pm b/tools/winapi_check/winapi_global.pm
index bb302e5141cfc268113266ede80cdb964671058e..d58b2849e2c75ed10632b0fdd08f366c6f203158 100644
--- a/tools/winapi_check/winapi_global.pm
+++ b/tools/winapi_check/winapi_global.pm
@@ -35,14 +35,6 @@ sub _check {
     }
 
     if($options->argument && $options->argument_forbidden) {
-	my $not_used = $winapi->types_not_used;
-
-	foreach my $module (sort(keys(%$not_used))) {
-	    foreach my $type (sort(keys(%{$$not_used{$module}}))) {
-		$output->write("*.c: $module: type ($type) not used\n");
-	    }
-	}
-
 	my $types_used = $winapi->types_unlimited_used_in_modules;
 
 	foreach my $type (sort(keys(%$types_used))) {
diff --git a/tools/winapi_check/winapi_parser.pm b/tools/winapi_check/winapi_parser.pm
index 077ce10bae6967c22361c7f31cc69025b9b8035e..5aa3b3ad690bb5cf01a3033e185e9e51ebfadbf9 100644
--- a/tools/winapi_check/winapi_parser.pm
+++ b/tools/winapi_check/winapi_parser.pm
@@ -3,93 +3,131 @@ package winapi_parser;
 use strict;
 
 use output qw($output);
-use winapi_function;
+use options qw($options);
 
 sub parse_c_file {
-    my $options = shift;
     my $file = shift;
+    my $function_create_callback = shift;
     my $function_found_callback = shift;
+    my $type_create_callback = shift;
+    my $type_found_callback = shift;
     my $preprocessor_found_callback = shift;
 
     # global
     my $debug_channels = [];
 
-    # local
-    my $documentation_line;
-    my $documentation;
-    my $function_line;
-    my $linkage;
-    my $return_type;
-    my $calling_convention;
-    my $internal_name = "";
-    my $argument_types;
-    my $argument_names;
-    my $argument_documentations;
-    my $statements;
-
-    my $function_begin = sub {
-	$documentation_line = shift;
-	$documentation = shift;
-	$function_line = shift;
-	$linkage = shift;
-	$return_type= shift;
-	$calling_convention = shift;
-	$internal_name = shift;
-	$argument_types = shift;
-	$argument_names = shift;
-	$argument_documentations = shift;
-
-	if(defined($argument_names) && defined($argument_types) &&
-	   $#$argument_names == -1)
-	{
-	    foreach my $n (0..$#$argument_types) {
-		push @$argument_names, "";
+    my $in_function = 0;
+    my $function_begin;
+    my $function_end;
+    {
+	my $documentation_line;
+	my $documentation;
+	my $function_line;
+	my $linkage;
+	my $return_type;
+	my $calling_convention;
+	my $internal_name = "";
+	my $argument_types;
+	my $argument_names;
+	my $argument_documentations;
+	my $statements;
+	
+	$function_begin = sub {
+	    $documentation_line = shift;
+	    $documentation = shift;
+	    $function_line = shift;
+	    $linkage = shift;
+	    $return_type= shift;
+	    $calling_convention = shift;
+	    $internal_name = shift;
+	    $argument_types = shift;
+	    $argument_names = shift;
+	    $argument_documentations = shift;
+	    
+	    if(defined($argument_names) && defined($argument_types) &&
+	       $#$argument_names == -1)
+	    {
+		foreach my $n (0..$#$argument_types) {
+		    push @$argument_names, "";
+		}
 	    }
-	}
+	    
+	    if(defined($argument_documentations) &&
+	       $#$argument_documentations == -1)
+	    {
+		foreach my $n (0..$#$argument_documentations) {
+		    push @$argument_documentations, "";
+		}
+	    }
+	    
+	    $in_function = 1;
+	};
 
-	if(defined($argument_documentations) &&
-	   $#$argument_documentations == -1)
-	{
-	    foreach my $n (0..$#$argument_documentations) {
-		push @$argument_documentations, "";
+	$function_end = sub {
+	    $statements = shift;
+
+	    my $function = &$function_create_callback();
+	    
+	    if(!defined($documentation_line)) {
+		$documentation_line = 0;
 	    }
-	}
+	    
+	    $function->file($file);
+	    $function->debug_channels([@$debug_channels]);
+	    $function->documentation_line($documentation_line);
+	    $function->documentation($documentation);
+	    $function->function_line($function_line);
+	    $function->linkage($linkage);
+	    $function->return_type($return_type); 
+	    $function->calling_convention($calling_convention);
+	    $function->internal_name($internal_name);
+	    if(defined($argument_types)) {
+		$function->argument_types([@$argument_types]);
+	    }
+	    if(defined($argument_names)) {
+		$function->argument_names([@$argument_names]);
+	    }
+	    if(defined($argument_documentations)) {
+		$function->argument_documentations([@$argument_documentations]);
+	    }
+	    $function->statements($statements);
+	    
+	    &$function_found_callback($function);
 
-	$statements = undef;
-    };
-    my $function_end = sub {
-	my $function = 'winapi_function'->new;
+	    $in_function = 0;
+	};
+    }
 
-	if(!defined($documentation_line)) {
-	    $documentation_line = 0;
-	}
+    my $in_type = 0;
+    my $type_begin;
+    my $type_end;
+    {
+	my $type;
 
-	$function->file($file);
-	$function->debug_channels([@$debug_channels]);
-	$function->documentation_line($documentation_line);
-	$function->documentation($documentation);
-	$function->function_line($function_line);
-	$function->linkage($linkage);
-	$function->return_type($return_type); 
-	$function->calling_convention($calling_convention);
-	$function->internal_name($internal_name);
-	if(defined($argument_types)) {
-	    $function->argument_types([@$argument_types]);
-	}
-	if(defined($argument_names)) {
-	    $function->argument_names([@$argument_names]);
-	}
-	if(defined($argument_documentations)) {
-	    $function->argument_documentations([@$argument_documentations]);
-	}
-	$function->statements($statements);
+	$type_begin = sub {
+	    $type = shift;
+	    $in_type = 1;
+	};
+
+	$type_end = sub {
+	    my $names = shift;
+
+	    foreach my $name (@$names) {
+		if($type =~ /^(?:struct|enum)/) {
+		    # $output->write("typedef $type {\n");
+		    # $output->write("} $name;\n");
+		} else {
+		    # $output->write("typedef $type $name;\n");
+		}
+	    }
+	    $in_type = 0;
+	};
+    }
 
-	&$function_found_callback($function);
-	$internal_name = "";
-    };
     my %regs_entrypoints;
     my @comment_lines = ();
     my @comments = ();
+    my $statements;
     my $level = 0;
     my $extern_c = 0;
     my $again = 0;
@@ -263,8 +301,20 @@ sub parse_c_file {
 		$statements .= "$line\n";
 	    }
 
-	    if($internal_name && $level == 0) {
-		&$function_end;
+	    if($level == 0) {
+		if($in_function) {
+		    &$function_end($statements);
+		    $statements = undef;
+		} elsif($in_type) {
+		    if(/^\s*(?:WINE_PACKED\s+)?((?:\*\s*)?\w+\s*(?:\s*,\s*(?:\*+\s*)?\w+)*\s*);/s) {
+			my @parts = split(/\s*,\s*/, $1);
+			&$type_end([@parts]);
+		    } elsif(/;/s) {
+			die "$file: $.: syntax error: '$_'\n";
+		    } else {
+			$lookahead = 1;
+		    }
+		}
 	    }
 	    next;
 	} elsif(/(extern\s+|static\s+)?((struct\s+|union\s+|enum\s+|signed\s+|unsigned\s+)?\w+((\s*\*)+\s*|\s+))
@@ -358,7 +408,8 @@ sub parse_c_file {
 			     $function_line, $linkage, $return_type, $calling_convention, $name,
 			     \@argument_types,\@argument_names,\@argument_documentations);
 	    if($level == 0) {
-		&$function_end;
+		&$function_end($statements);
+		$statements = undef;
 	    }
 	} elsif(/__ASM_GLOBAL_FUNC\(\s*(.*?)\s*,/s) {
 	    my @lines = split(/\n/, $&);
@@ -368,95 +419,20 @@ sub parse_c_file {
 
 	    &$function_begin($documentation_line, $documentation,
 			     $function_line, "", "void", "__asm", $1);
-	    $statements = "";
-	    &$function_end;
-	} elsif(/DC_(GET_X_Y_16|GET_VAL_16)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s){ 
-	    my @lines = split(/\n/, $&);
-	    my $function_line = $. - scalar(@lines) + 1;
-
-	    $_ = $'; $again = 1;
-
-	    my $return16 = $2 . "16";
-	    my $name16 = $3 . "16";
-
-	    $return16 =~ s/^(COLORREF|DWORD)16$/$1/;
-
-	    my @arguments = ("HDC16");
-	    &$function_begin($documentation_line, $documentation,
-			     $function_line, "", $return16, "WINAPI", $name16, \@arguments);
-	    $statements = "";
-	    &$function_end;
-	} elsif(/DC_(GET_VAL_32)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,.*?\)/s) {
-	    my @lines = split(/\n/, $&);
-	    my $function_line = $. - scalar(@lines) + 1;
-
-	    $_ = $'; $again = 1;
-
-	    my $return32 = $2;
-	    my $name32 = $3;
-	    my @arguments32 = ("HDC");
-
-	    &$function_end;
-	    &$function_begin($documentation_line, $documentation,
-			     $function_line, "", $return32, "WINAPI", $name32, \@arguments32);
-	    $statements = "";
-	    &$function_end;
-	} elsif(/DC_(GET_VAL_EX_16)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
-	    my @lines = split(/\n/, $&);
-	    my $function_line = $. - scalar(@lines) + 1;
-
-	    $_ = $'; $again = 1;
-
-	    my @arguments16 = ("HDC16", "LP" . $5 . "16");
-	    &$function_begin($documentation_line, $documentation,
-			     $function_line, "", "BOOL16", "WINAPI", $2 . "16", \@arguments16);
-	    $statements = "";
-	    &$function_end;
-	} elsif(/DC_(GET_VAL_EX_32)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
-	    my @lines = split(/\n/, $&);
-	    my $function_line = $. - scalar(@lines) + 1;
-
-	    $_ = $'; $again = 1;
-
-	    my @arguments32 = ("HDC", "LP" . $5);
-	    &$function_begin($documentation_line, $documentation,
-			     $function_line, "", "BOOL", "WINAPI", $2, \@arguments32);
-	    $statements = "";
-	    &$function_end;
-	} elsif(/DC_(SET_MODE_16)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
-	    my @lines = split(/\n/, $&);
-	    my $function_line = $. - scalar(@lines) + 1;
-
-	    $_ = $'; $again = 1;
-
-	    my @arguments16 = ("HDC16", "INT16");
-	    &$function_begin($documentation_line, $documentation,
-			     $function_line, "", "INT16", "WINAPI", $2 . "16", \@arguments16);
-	    $statements = "";
-	    &$function_end;
-	} elsif(/DC_(SET_MODE_32)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
+	    &$function_end("");
+	} elsif(/WAVEIN_SHORTCUT_0\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
 	    my @lines = split(/\n/, $&);
 	    my $function_line = $. - scalar(@lines) + 1;
 
-	    $_ = $'; $again = 1;
-
-	    my @arguments32 = ("HDC", "INT");
-	    &$function_begin($documentation_line, $documentation,
-			     $function_line, "", "INT", "WINAPI", $2, \@arguments32);
-	    $statements = "";
-	    &$function_end;
-	} elsif(/WAVEIN_SHORTCUT_0\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
 	    $_ = $'; $again = 1;
 	    my @arguments16 = ("HWAVEIN16");
 	    my @arguments32 = ("HWAVEIN");
 	    &$function_begin($documentation_line, $documentation,
 			     $function_line,  "", "UINT16", "WINAPI", "waveIn" . $1 . "16", \@arguments16);
-	    $statements = "";
-	    &$function_end;
+	    &$function_end("");
 	    &$function_begin($documentation_line, $documentation,
 			     $function_line, "", "UINT", "WINAPI", "waveIn" . $1, \@arguments32);
-	    $statements = "";
-	    &$function_end;	    
+	    &$function_end("");
 	} elsif(/WAVEOUT_SHORTCUT_0\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
 	    my @lines = split(/\n/, $&);
 	    my $function_line = $. - scalar(@lines) + 1;
@@ -467,11 +443,10 @@ sub parse_c_file {
 	    my @arguments32 = ("HWAVEOUT");
 	    &$function_begin($documentation_line, $documentation,
 			     $function_line, "", "UINT16", "WINAPI", "waveOut" . $1 . "16", \@arguments16);
-	    $statements = "";
-	    &$function_end;
+	    &$function_end("");
 	    &$function_begin($documentation_line, $documentation,
 			     $function_line, "", "UINT", "WINAPI", "waveOut" . $1, \@arguments32);	    
-	    &$function_end;
+	    &$function_end("");
 	} elsif(/WAVEOUT_SHORTCUT_(1|2)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
 	    my @lines = split(/\n/, $&);
 	    my $function_line = $. - scalar(@lines) + 1;
@@ -483,21 +458,19 @@ sub parse_c_file {
 		my @arguments32 = ("HWAVEOUT", $4);
 		&$function_begin($documentation_line, $documentation,
 				 $function_line, "", "UINT16", "WINAPI", "waveOut" . $2 . "16", \@arguments16);
-		$statements = "";
-		&$function_end;
+		&$function_end("");
 		&$function_begin($documentation_line, $documentation,
 				 $function_line, "", "UINT", "WINAPI", "waveOut" . $2, \@arguments32);
-		&$function_end;
+		&$function_end("");
 	    } elsif($1 eq 2) {
 		my @arguments16 = ("UINT16", $4);
 		my @arguments32 = ("UINT", $4);
 		&$function_begin($documentation_line, $documentation,
 				 $function_line, "", "UINT16", "WINAPI", "waveOut". $2 . "16", \@arguments16);
-		$statements = "";
-		&$function_end;
+		&$function_end("");
 		&$function_begin($documentation_line, $documentation, 
 				 $function_line, "", "UINT", "WINAPI", "waveOut" . $2, \@arguments32);
-		&$function_end;
+		&$function_end("");
 	    }
         } elsif(/DEFINE_REGS_ENTRYPOINT_\d+\(\s*(\S*)\s*,\s*([^\s,\)]*).*?\)/s) {
 	    $_ = $'; $again = 1;
@@ -508,6 +481,74 @@ sub parse_c_file {
 	} elsif(/(DEFAULT|DECLARE)_DEBUG_CHANNEL\s*\((\S+)\)/s) {
 	    $_ = $'; $again = 1;
 	    push @$debug_channels, $1;
+	} elsif(/typedef\s+(enum|struct|union)(?:\s+(\w+))?\s*\{/s) {
+	    $_ = $'; $again = 1;
+	    $level++;
+	    my $type = $1;
+	    if(defined($2)) {
+	       $type .= " $2";
+	    }
+	    &$type_begin($type);
+	} elsif(/typedef\s+
+		((?:const\s+|enum\s+|long\s+|signed\s+|short\s+|struct\s+|union\s+|unsigned\s+)*?)
+		(\w+)
+		(?:\s+const)?
+		((?:\s*\*+\s*|\s+)\w+\s*(?:\[[^\]]*\])?
+		(?:\s*,\s*(?:\s*\*+\s*|\s+)\w+\s*(?:\[[^\]]*\])?)*)
+		\s*;/sx) 
+	{
+	    $_ = $'; $again = 1;
+
+	    my $type = "$1 $2";
+
+	    my @names;
+	    my @parts = split(/\s*,\s*/, $2);
+	    foreach my $part (@parts) {
+		if($part =~ /(?:\s*(\*+)\s*|\s+)(\w+)\s*(\[[^\]]*\])?/) {
+		    my $name = $2;
+		    if(defined($1)) {
+			$name = "$1$2";
+		    }
+		    if(defined($3)) {
+			$name .= $3;
+		    }
+		    push @names, $name;
+		}
+	    }
+	    &$type_begin($type);
+	    &$type_end([@names]);
+	} elsif(/typedef\s+
+		(?:(?:const\s+|enum\s+|long\s+|signed\s+|short\s+|struct\s+|union\s+|unsigned\s+)*?)
+		(\w+)\s+
+		(?:(\w+)\s*)?
+		\((?:(\w+)\s+)?\s*\*\s*(\w+)\s*\)\s*
+		(?:\(([^\)]*)\)|\[([^\]]*)\])\s*;/sx) 
+	{
+	    $_ = $'; $again = 1;	   
+	    my $type;
+	    if(defined($2) || defined($3)) {
+		my $cc = $2 || $3;
+		if(defined($5)) {
+		    $type = "$1 ($cc *)($5)";
+		} else {
+		    $type = "$1 ($cc *)[$6]";
+		}
+	    } else {
+		if(defined($5)) {
+		    $type = "$1 (*)($5)";
+		} else {
+		    $type = "$1 (*)[$6]";
+		}
+	    }
+	    my $name = $4;
+	    &$type_begin($type);
+	    &$type_end([$name]);
+	} elsif(/typedef[^\{;]*;/s) {
+	    $_ = $'; $again = 1;
+	    $output->write("$file: $.: can't parse: '$&'\n");
+	} elsif(/typedef[^\{]*\{[^\}]*\}[^;];/s) {
+	    $_ = $'; $again = 1;
+	    $output->write("$file: $.: can't parse: '$&'\n");
 	} elsif(/\'[^\']*\'/s) {
 	    $_ = $'; $again = 1;
 	} elsif(/\"[^\"]*\"/s) {