- A few more bug fixes
- Reorganization continues
- New tool (make_filter) for filtering make output added

diff --git a/tools/winapi/config.pm b/tools/winapi/config.pm
index 852ef8b..3d950e6 100644
--- a/tools/winapi/config.pm
+++ b/tools/winapi/config.pm
@@ -10,9 +10,10 @@
 @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 output qw($output);
 
+use File::Find;
+
 sub file_type {
     local $_ = shift;
 
@@ -30,7 +33,7 @@
     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 @@
     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 @@
     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 0000000..03c6aac
--- /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 0000000..ceecd77
--- /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 0000000..63037d9
--- /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 6ff005f..ac6d061 100644
--- a/tools/winapi/options.pm
+++ b/tools/winapi/options.pm
@@ -40,9 +40,9 @@
     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 @@
 
     $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 @@
 	    }
 	}
 	
-	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 @@
 	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 @@
 	my %found;
 	@$c_files = sort(map {
 	    s/^\.\/(.*)$/$1/;
-	    if(defined($found{$_}) || /glue\.c|spec\.c$/) {
+	    if(defined($found{$_})) {
 		();
 	    } else {
 		$found{$_}++;
@@ -209,18 +235,13 @@
 	    }
 	} 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 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 c_files { my $self = shift; return @{$self->{C_FILES}}; }
+sub arguments { 
+    my $self = shift;
 
-sub h_files { my $self = shift; return @{$self->{H_FILES}}; }
+    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}};
+
+    if(!defined(@$h_files)) {
+	$self->parse_files;
+    }
+
+    return @$h_files;
+}
 
 1;
diff --git a/tools/winapi/output.pm b/tools/winapi/output.pm
index 7c9bf0d..018d63f 100644
--- a/tools/winapi/output.pm
+++ b/tools/winapi/output.pm
@@ -26,6 +26,7 @@
     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 @@
     my $prefix = \${$self->{PREFIX}};
     my $prefix_callback = \${$self->{PREFIX_CALLBACK}};
 
+    $$progress_enabled = 1;
     $$progress = "";
     $$last_progress = "";
     $$last_time = 0;
@@ -43,62 +45,91 @@
     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 0000000..3608355
--- /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 22d5e8a..88dab8c 100644
--- a/tools/winapi/winapi_check_options.pm
+++ b/tools/winapi/winapi_check_options.pm
@@ -127,16 +127,10 @@
     "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 c93c1e2..8423836 100755
--- a/tools/winapi/winapi_extract
+++ b/tools/winapi/winapi_extract
@@ -13,18 +13,18 @@
     &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 $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 @@
 	$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 @@
 	$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 @@
 	
 	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 @@
     } 
 }
 
-$output->hide_progress;
diff --git a/tools/winapi/winapi_extract_options.pm b/tools/winapi/winapi_extract_options.pm
index 0e4e978..3d29621 100644
--- a/tools/winapi/winapi_extract_options.pm
+++ b/tools/winapi/winapi_extract_options.pm
@@ -26,7 +26,7 @@
     "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 4a87ba2..f043138 100755
--- a/tools/winapi/winapi_fixup
+++ b/tools/winapi/winapi_fixup
@@ -17,24 +17,14 @@
     $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 @@
 
     my %documentation_line_used;
 
+    my $create_function = sub {
+	return 'winapi_function'->new;
+    };
+
     my $found_function = sub {
 	my $function = shift;
 	
@@ -434,12 +428,21 @@
 	$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 @@
     }
 }
 
-$output->hide_progress;