- Added a new tool winapi_test for generating tests.
- Added a data structure packing test to winapi_test.
- Reorganized and optimized a few things.

diff --git a/tools/winapi/Makefile.in b/tools/winapi/Makefile.in
index 4c33b88..c9ad9e1 100644
--- a/tools/winapi/Makefile.in
+++ b/tools/winapi/Makefile.in
@@ -14,11 +14,13 @@
 	$(INSTALL_SCRIPT) $(SRCDIR)/trampoline $(bindir)/winapi_cleanup
 	$(INSTALL_SCRIPT) $(SRCDIR)/trampoline $(bindir)/winapi_extract
 	$(INSTALL_SCRIPT) $(SRCDIR)/trampoline $(bindir)/winapi_fixup
+	$(INSTALL_SCRIPT) $(SRCDIR)/trampoline $(bindir)/winapi_test
 
 uninstall::
 	$(RM) $(bindir)/make_filter
 	$(RM) $(bindir)/winapi_check
 	$(RM) $(bindir)/winapi_extract
 	$(RM) $(bindir)/winapi_fixup
+	$(RM) $(bindir)/winapi_test
 
 ### Dependencies:
diff --git a/tools/winapi/c_parser.pm b/tools/winapi/c_parser.pm
index a487026..9e97d4c 100644
--- a/tools/winapi/c_parser.pm
+++ b/tools/winapi/c_parser.pm
@@ -776,6 +776,7 @@
     my $previous_line = 0;
     my $previous_column = -1;
 
+    my $preprocessor_condition;
     my $if = 0;
     my $if0 = 0;
     my $extern_c = 0;
@@ -902,19 +903,40 @@
 		    $preprocessor .= $1;
 		}
 
-		if($if0 && $preprocessor =~ /^\#\s*endif/) {
+
+		if (0) {
+		    # Nothing
+		} elsif($preprocessor =~ /^\#\s*if/) {
+		    if($preprocessor =~ /^\#\s*if\s*0/) {
+			$if0++;
+		    } elsif($if0 > 0) {
+			$if++;
+		    } else {
+			if($preprocessor =~ /^\#\s*ifdef\s+WORDS_BIGENDIAN$/) {
+			    $preprocessor_condition = "defined(WORD_BIGENDIAN)";
+			    # $output->write("'$preprocessor_condition':'$declaration'\n")
+			} else {
+			    $preprocessor_condition = "";
+			}
+		    }
+		} elsif($preprocessor =~ /^\#\s*else/) {
+		    if ($preprocessor_condition ne "") {
+			$preprocessor_condition =~ "!$preprocessor_condition";
+			$preprocessor_condition =~ s/^!!/!/;
+			# $output->write("'$preprocessor_condition':'$declaration'\n")
+		    }
+		} elsif($preprocessor =~ /^\#\s*endif/) {
 		    if($if0 > 0) {
 			if($if > 0) {
 			    $if--;
 			} else {
 			    $if0--;
 			}
-		    }
-	        } elsif($preprocessor =~ /^\#\s*if/) {
-		    if($preprocessor =~ /^\#\s*if\s*0/) {
-			$if0++;
-		    } elsif($if0 > 0) {
-			$if++;
+		    } else {
+			if ($preprocessor_condition ne "") {
+			    # $output->write("'$preprocessor_condition':'$declaration'\n");
+			    $preprocessor_condition = "";
+			}
 		    }
 		}
 
@@ -1606,6 +1628,7 @@
 
     my $create_type = \${$self->{CREATE_TYPE}};
     my $found_type = \${$self->{FOUND_TYPE}};
+    my $preprocessor_condition = \${$self->{PREPROCESSOR_CONDITION}};
 
     my $refcurrent = shift;
     my $refline = shift;
@@ -1639,14 +1662,16 @@
 	    {
 		my $field_linkage;
 		my $field_type;
-		my $field_name;		
+		my $field_name;
 
 		if ($self->parse_c_variable(\$match, \$line, \$column, \$field_linkage, \$field_type, \$field_name)) {
 		    $field_type =~ s/\s+/ /g;
-
+		    
 		    push @field_types, $field_type;
 		    push @field_names, $field_name;
 		    # $output->write("$kind:$_name:$field_type:$field_name\n");
+		} elsif ($match) {
+		    $self->_parse_c_error($_, $line, $column, "typedef $kind: '$match'");
 		}
 
 		if ($self->_parse_c(';', \$_, \$line, \$column)) {
@@ -1799,12 +1824,43 @@
 
     if($finished) {
 	# Nothing
-    } elsif(s/^((?:enum\s+|struct\s+|union\s+)?\w+\s*(?:\*\s*)*)(\w+)$//s) {
-	$type = $self->_format_c_type($1);
+    } elsif(s/^(enum|struct|union)(?:\s+(\w+))?\s*\{//s) {
+	my $kind = $1;
+	my $_name = $2;
+	$self->_update_c_position($&, \$line, \$column);
+
+	if(defined($_name)) {
+	    $type = "$kind $_name { }";
+	} else {
+	    $type = "$kind { }";
+	}
+
+	$finished = 1;
+    } elsif(s/^((?:enum\s+|struct\s+|union\s+)?\w+(?:\s*\*)*)\s*(\w+)\s*(\[.*?\]$|:\s*(\d+)$|\{)?//s) {
+	$type = $1;
+	$name = $2;
+
+	if (defined($3)) {
+	    my $bits = $4;
+	    local $_ = $3;
+	    if (/^\[/) {
+		$type .= $_;
+	    } elsif (/^:/) {
+		$type .= ":$bits";
+	    } elsif (/^\{/) {
+		# Nothing
+	    }
+	}
+
+	$type = $self->_format_c_type($type);
+
+	$finished = 1;
+    } elsif(s/^((?:enum\s+|struct\s+|union\s+)?\w+(?:\s*\*)*\s*\(\s*(?:\*\s*)*)(\w+)\s*(\)\(.*?\))$//s) {
+	$type = $self->_format_c_type("$1$3");
 	$name = $2;
 
 	$finished = 1;
-    } elsif(s/^((?:enum\s+|struct\s+|union\s+)?\w+\s*(?:\*\s*)*\(\s*(?:\*\s*)*)(\w+)\s*(\)\(.*?\))$//s) {
+
 	$type = $self->_format_c_type("$1$3");
 	$name = $2;
 
@@ -1827,21 +1883,16 @@
     } elsif($self->_parse_c('(?:struct\s+)?ICOM_VTABLE\s*\(\w+\)', \$_, \$line, \$column, \$match)) {
 	$type = $match;
 	$finished = 1;
-    } elsif(s/^(?:enum\s+|struct\s+|union\s+)(\w+)?\s*\{.*?\}\s*//s) {
+    } elsif(s/^(enum|struct|union)(?:\s+(\w+))?\s*\{.*?\}\s*//s) {
+	my $kind = $1;
+	my $_name = $2;
 	$self->_update_c_position($&, \$line, \$column);
 
-	if(defined($1)) {
-	    $type = "struct $1 { }";
+	if(defined($_name)) {
+	    $type = "struct $_name { }";
 	} else {
 	    $type = "struct { }";
 	}
-	if(defined($2)) {
-	    my $stars = $2;
-	    $stars =~ s/\s//g;
-	    if($stars) {
-		$type .= " $type";
-	    }
-	}
     } elsif(s/^((?:enum\s+|struct\s+|union\s+)?\w+)\s*(?:\*\s*)*//s) {
 	$type = $&;
 	$type =~ s/\s//g;
@@ -1889,7 +1940,7 @@
 
     # $output->write("$type: $name: '$_'\n");
 
-    if(1) {
+    if(1 || $finished) {
 	# Nothing
     } elsif($self->_parse_c('(?:struct\s+)?ICOM_VTABLE\s*\(.*?\)', \$_, \$line, \$column, \$match)) {
 	$type = "<type>";
@@ -1906,29 +1957,28 @@
 
 	$type =~ s/\s//g;
 	$type =~ s/^struct/struct /;
-    } elsif(/^(?:enum|struct|union)(?:\s+(\w+))?\s*\{.*?\}\s*((?:\*\s*)*)(\w+)\s*(?:=|$)/s) {
+    } elsif(/^(enum|struct|union)(?:\s+(\w+))?\s*\{.*?\}\s*((?:\*\s*)*)(\w+)\s*(?:=|$)/s) {
 	$self->_update_c_position($&, \$line, \$column);
 
-	if(defined($1)) {
-	    $type = "struct $1 { }";
+	my $kind = $1;
+	my $_name= $2;
+	my $stars = $3;
+	$name = $4;
+
+	if(defined($_name)) {
+	    $type = "struct $_name { }";
 	} else {
 	    $type = "struct { }";
 	}
-	my $stars = $2;
+
 	$stars =~ s/\s//g;
 	if($stars) {
 	    $type .= " $type";
 	}
-
-	$name = $3;
     } else {
 	return 0;
     }
 
-    if(!$name) {
-        $name = "<name>";
-    }
-
     $$refcurrent = $_;
     $$refline = $line;
     $$refcolumn = $column;
diff --git a/tools/winapi/c_type.pm b/tools/winapi/c_type.pm
index 2780f42..ac099e8 100644
--- a/tools/winapi/c_type.pm
+++ b/tools/winapi/c_type.pm
@@ -59,7 +59,14 @@
 
     if(defined($_)) { $$name = $_; }
 
-    return $$name;
+    if($$name) {
+	return $$name;
+    } else {
+	my $kind = \${$self->{KIND}};
+	my $_name = \${$self->{_NAME}};
+
+	return "$$kind $$_name";
+    }
 }
 
 sub fields {
@@ -77,6 +84,16 @@
     return @fields;
 }
 
+sub field_names {
+    my $self = shift;
+    my $field_names = \${$self->{FIELD_NAMES}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$field_names = $_; }
+
+    return $$field_names;
+}
 
 sub field_types {
     my $self = shift;
@@ -89,15 +106,4 @@
     return $$field_types;
 }
 
-sub field_names {
-    my $self = shift;
-    my $field_names = \${$self->{FIELD_NAMES}};
-
-    local $_ = shift;
-
-    if(defined($_)) { $$field_names = $_; }
-
-    return $$field_names;
-}
-
 1;
diff --git a/tools/winapi/tests.dat b/tools/winapi/tests.dat
new file mode 100644
index 0000000..4bf46f7
--- /dev/null
+++ b/tools/winapi/tests.dat
@@ -0,0 +1,54 @@
+%%%dlls/kernel/tests
+
+%%pack
+
+%description
+
+Unit tests for data structure packing
+
+%include
+
+winbase.h
+
+%struct
+
+BY_HANDLE_FILE_INFORMATION
+COMMCONFIG
+COMMPROP
+COMMTIMEOUTS
+COMSTAT
+CREATE_PROCESS_DEBUG_INFO
+CREATE_THREAD_DEBUG_INFO
+DCB
+# DEBUG_EVENT
+EXCEPTION_DEBUG_INFO
+EXIT_PROCESS_DEBUG_INFO
+EXIT_THREAD_DEBUG_INFO
+# FILETIME
+# HW_PROFILE_INFOA
+LDT_ENTRY
+LOAD_DLL_DEBUG_INFO
+MEMORYSTATUS
+# OFSTRUCT
+OSVERSIONINFOA
+OSVERSIONINFOEXA
+OSVERSIONINFOEXW
+OSVERSIONINFOW
+OUTPUT_DEBUG_STRING_INFO
+OVERLAPPED
+# PROCESS_HEAP_ENTRY
+PROCESS_INFORMATION
+RIP_INFO
+SECURITY_ATTRIBUTES
+STARTUPINFOA
+STARTUPINFOW
+SYSLEVEL
+SYSTEMTIME
+SYSTEM_INFO
+SYSTEM_POWER_STATUS
+TIME_ZONE_INFORMATION
+UNLOAD_DLL_DEBUG_INFO
+WIN32_FILE_ATTRIBUTE_DATA
+WIN32_FIND_DATAA
+WIN32_FIND_DATAW
+WIN32_STREAM_ID
diff --git a/tools/winapi/tests.pm b/tools/winapi/tests.pm
new file mode 100644
index 0000000..e745d79
--- /dev/null
+++ b/tools/winapi/tests.pm
@@ -0,0 +1,150 @@
+#
+# Copyright 2002 Patrik Stridvall
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+package tests;
+
+use strict;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
+require Exporter;
+
+@ISA = qw(Exporter);
+@EXPORT = qw();
+@EXPORT_OK = qw($tests);
+
+use vars qw($tests);
+
+use config qw($current_dir $wine_dir $winapi_dir);
+use options qw($options);
+use output qw($output);
+
+sub import {
+    $Exporter::ExportLevel++;
+    &Exporter::import(@_);
+    $Exporter::ExportLevel--;
+
+    $tests = 'tests'->new;
+}
+
+sub new {
+    my $proto = shift;
+    my $class = ref($proto) || $proto;
+    my $self  = {};
+    bless ($self, $class);
+
+    $self->parse_tests_file();
+
+    return $self;
+}
+
+sub parse_tests_file {
+    my $self = shift;
+
+    my $file = "tests.dat";
+
+    my $tests = \%{$self->{TESTS}};
+
+    $output->lazy_progress($file);
+
+    my $test_dir;
+    my $test;
+    my $section;
+
+    open(IN, "< $winapi_dir/$file") || die "$winapi_dir/$file: $!\n";
+    while(<IN>) {
+	s/^\s*?(.*?)\s*$/$1/; # remove whitespace at beginning and end of line
+	s/^(.*?)\s*#.*$/$1/;  # remove comments
+	/^$/ && next;         # skip empty lines
+
+	if (/^%%%\s*(\S+)$/) {
+	    $test_dir = $1;
+	} elsif (/^%%\s*(\w+)$/) {
+	    $test = $1;
+	} elsif (/^%\s*(\w+)$/) {
+	    $section = $1;
+	} elsif (!/^%/) {
+	    if (!exists($$tests{$test_dir}{$test}{$section})) {
+		$$tests{$test_dir}{$test}{$section} = [];
+	    }
+	    push @{$$tests{$test_dir}{$test}{$section}}, $_;
+	} else {
+	    $output->write("$file:$.: parse error: '$_'\n");
+	    exit 1;
+	}
+    }
+    close(IN);
+}
+
+sub get_tests {
+    my $self = shift;
+
+    my $tests = \%{$self->{TESTS}};
+
+    my $test_dir = shift;
+
+    my %tests = ();
+    if (defined($test_dir)) {
+	foreach my $test (sort(keys(%{$$tests{$test_dir}}))) {
+	    $tests{$test}++;
+	}
+    } else {
+	foreach my $test_dir (sort(keys(%$tests))) {
+	    foreach my $test (sort(keys(%{$$tests{$test_dir}}))) {
+		$tests{$test}++;
+	    }
+	}
+    }
+    return sort(keys(%tests));
+}
+
+sub get_test_dirs {
+    my $self = shift;
+
+    my $tests = \%{$self->{TESTS}};
+
+    my $test = shift;
+
+    my %test_dirs = ();    
+    if (defined($test)) {
+	foreach my $test_dir (sort(keys(%$tests))) {
+	    if (exists($$tests{$test_dir}{$test})) {
+		$test_dirs{$test_dir}++;
+	    }
+	}
+    } else {
+	foreach my $test_dir (sort(keys(%$tests))) {
+	    $test_dirs{$test_dir}++;
+	}
+    }
+
+    return sort(keys(%test_dirs));
+}
+
+sub get_section {
+    my $self = shift;
+
+    my $tests = \%{$self->{TESTS}};
+
+    my $test_dir = shift;
+    my $test = shift;
+    my $section = shift;
+
+    return @{$$tests{$test_dir}{$test}{$section}};
+}
+
+1;
diff --git a/tools/winapi/winapi.pm b/tools/winapi/winapi.pm
index fe82e08..ab4b5cf 100644
--- a/tools/winapi/winapi.pm
+++ b/tools/winapi/winapi.pm
@@ -30,30 +30,41 @@
 use vars qw($win16api $win32api @winapis);
 
 use config qw($current_dir $wine_dir $winapi_dir);
-use modules qw($modules);
 use options qw($options);
 use output qw($output);
 
-my @spec_files16 = $modules->allowed_spec_files16;
-$win16api = 'winapi'->new("win16", \@spec_files16);
+use vars qw($modules);
 
-my @spec_files32 = $modules->allowed_spec_files32;
-$win32api = 'winapi'->new("win32", \@spec_files32);
+sub import {
+    $Exporter::ExportLevel++;
+    &Exporter::import(@_);
+    $Exporter::ExportLevel--;
 
-@winapis = ($win16api, $win32api);
+    require modules;
+    import modules qw($modules);
 
-for my $internal_name ($win32api->all_internal_functions) {
-    my $module16 = $win16api->function_internal_module($internal_name);
-    my $module32 = $win16api->function_internal_module($internal_name);
-    if(defined($module16) &&
-       !$win16api->is_function_stub_in_module($module16, $internal_name) &&
-       !$win32api->is_function_stub_in_module($module32, $internal_name))
-    {
-	$win16api->found_shared_internal_function($internal_name);
-	$win32api->found_shared_internal_function($internal_name);
+    my @spec_files16 = $modules->allowed_spec_files16;
+    $win16api = 'winapi'->new("win16", \@spec_files16);
+    
+    my @spec_files32 = $modules->allowed_spec_files32;
+    $win32api = 'winapi'->new("win32", \@spec_files32);
+    
+    @winapis = ($win16api, $win32api);
+
+    for my $internal_name ($win32api->all_internal_functions) {
+	my $module16 = $win16api->function_internal_module($internal_name);
+	my $module32 = $win16api->function_internal_module($internal_name);
+	if(defined($module16) &&
+	   !$win16api->is_function_stub_in_module($module16, $internal_name) &&
+	   !$win32api->is_function_stub_in_module($module32, $internal_name))
+	{
+	    $win16api->found_shared_internal_function($internal_name);
+	    $win32api->found_shared_internal_function($internal_name);
+	}
     }
 }
 
+
 sub new {
     my $proto = shift;
     my $class = ref($proto) || $proto;
diff --git a/tools/winapi/winapi_cleanup b/tools/winapi/winapi_cleanup
index 2f61703..2918a65 100755
--- a/tools/winapi/winapi_cleanup
+++ b/tools/winapi/winapi_cleanup
@@ -28,6 +28,8 @@
 use output qw($output);
 use winapi_cleanup_options qw($options);
 
+use util qw(edit_file);
+
 if($options->progress) {
     $output->enable_progress;
 } else {
@@ -35,31 +37,6 @@
 }
 
 ########################################################################
-# edit_file
-
-sub edit_file {
-    my $filename = shift;
-    my $function = shift;
-
-    open(IN, "< $filename") || die "Can't open file '$filename'";
-    open(OUT, "> $filename.tmp") || die "Can't open file '$filename.tmp'";
-
-    my $result = &$function(\*IN, \*OUT, @_);
-
-    close(IN);
-    close(OUT);
-
-    if($result) {
-        unlink($filename);
-        rename("$filename.tmp", $filename);
-    } else {
-        unlink("$filename.tmp");
-    }
-
-    return $result;
-}
-
-########################################################################
 # cleanup_file
 
 sub cleanup_file {
diff --git a/tools/winapi/winapi_extract b/tools/winapi/winapi_extract
index c66b2c9..7216349 100755
--- a/tools/winapi/winapi_extract
+++ b/tools/winapi/winapi_extract
@@ -41,10 +41,15 @@
 use function;
 use type;
 
-use winapi qw($win16api $win32api @winapis);
 use winapi_c_parser;
 use winapi_function;
 
+use vars qw($win16api $win32api @winapis);
+if ($options->spec_files || $options->winetest) {
+    require winapi;
+    import winapi qw($win16api $win32api @winapis);
+}
+
 my %module2entries;
 my %module2spec_file;
 if($options->spec_files || $options->winetest) {
@@ -257,7 +262,9 @@
 	my $name = $function->name;
 	$functions{$name} = $function;
 
-	&$update_output();
+	if ($function->statements) {
+	    &$update_output();
+	}
 
 	my $old_function;
 	if($options->stub_statistics) {
@@ -295,11 +302,22 @@
 	    statements_stub($old_function);
 	}
 
-	$function = undef;
-	&$update_output();
+	if ($function->statements) {
+	    $function = undef;
+	    &$update_output();
+	} else {
+	    $function = undef;
+	}
     };
     $parser->set_found_function_callback($found_function);
 
+    my $found_line = sub {
+	$line = shift;
+
+	&$update_output;
+    };
+    $parser->set_found_line_callback($found_line);
+
     my $found_type = sub {
 	my $type = shift;
 
diff --git a/tools/winapi/winapi_test b/tools/winapi/winapi_test
new file mode 100755
index 0000000..f014bbc
--- /dev/null
+++ b/tools/winapi/winapi_test
@@ -0,0 +1,304 @@
+#!/usr/bin/perl -w
+
+# Copyright 2002 Patrik Stridvall
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+use strict;
+
+BEGIN {
+    $0 =~ m%^(.*?/?tools)/winapi/winapi_test$%;
+    require "$1/winapi/setup.pm";
+}
+
+use config qw(
+    &file_type &files_skip &files_filter
+    $current_dir $wine_dir $winapi_dir $winapi_check_dir
+);
+use output qw($output);
+use winapi_test_options qw($options);
+
+if($options->progress) {
+    $output->enable_progress;
+} else {
+    $output->disable_progress;
+}
+
+use c_parser;
+use tests qw($tests);
+use type;
+use util qw(replace_file);
+
+my @tests = ();
+if ($options->pack) {
+    push @tests, "pack";
+}
+
+my @files = ();
+{
+    my %files;    
+
+    my %test_dirs;
+    foreach my $test (@tests) {
+	my @test_dirs = $tests->get_test_dirs($test);
+	foreach my $test_dir (@test_dirs) {
+	    my @includes = $tests->get_section($test_dir, $test, "include");
+	    foreach my $include (@includes) {
+		$files{"include/$include"}++;
+	    }
+	}
+    }
+    @files = sort(keys(%files));
+}
+
+my %file2types;
+
+my $progress_output;
+my $progress_current = 0;
+my $progress_max = scalar(@files);
+
+foreach my $file (@files) {
+    $progress_current++;
+
+    {
+	open(IN, "< $wine_dir/$file");
+	local $/ = undef;
+	$_ = <IN>;
+	close(IN);
+    }
+
+    my $max_line = 0;
+    {
+      local $_ = $_;
+      while(s/^.*?\n//) { $max_line++; }
+      if($_) { $max_line++; }
+    }
+
+    my $parser = new c_parser($file);
+
+    my $line;
+    my $type;
+
+    my $update_output = sub {
+	my $progress = "";
+	my $prefix = "";
+
+	$progress .= "$file (file $progress_current of $progress_max)";
+	$prefix .= "$file: ";
+
+	if(defined($line)) {
+	    $progress .= ": line $line of $max_line";
+	}
+
+	$output->progress($progress);
+	$output->prefix($prefix);
+    };
+
+    &$update_output();
+
+    my $found_line = sub {
+	$line = shift;
+
+	&$update_output;
+    };
+    $parser->set_found_line_callback($found_line);
+
+    my $found_type = sub {
+	$type = shift;
+
+	my $name = $type->name;
+	$file2types{$file}{$name} = $type;
+
+	&$update_output();
+
+	return 1;
+    };
+    $parser->set_found_type_callback($found_type);
+
+    {
+	my $line = 1;
+	my $column = 0;
+	if(!$parser->parse_c_file(\$_, \$line, \$column)) {
+	    $output->write("can't parse file\n");
+	}
+    }
+
+    $output->prefix("");
+}
+
+sub output_header {
+    local *OUT = shift; 
+
+    my $test_dir = shift;
+    my $test = shift;
+
+    print OUT "/* File generated automatically from $wine_dir/tools/winapi/test.dat; do not edit! */\n";
+    print OUT "/* This file can be copied, modified and distributed without restriction. */\n";
+    print OUT "\n";
+
+    print OUT "/*\n";
+    my @description = $tests->get_section($test_dir, $test, "description");
+    foreach my $description (@description) {
+	print OUT " * $description\n";
+    }
+    print OUT " */\n";
+
+    print OUT "\n";
+    print OUT "#include <stdio.h>\n";
+    print OUT "\n";
+    print OUT "#include \"wine/test.h\"\n";
+    my @includes = $tests->get_section($test_dir, $test, "include");
+    foreach my $include (@includes) {
+	print OUT "#include \"$include\"\n";
+    }
+    print OUT "\n";
+
+    print OUT "START_TEST(generated_$test)\n";
+    print OUT "{\n";
+}
+
+sub output_footer {
+    local *OUT = shift; 
+
+    my $test_dir = shift;
+    my $test = shift;
+
+    print OUT "}\n";
+}
+
+sub field_size {
+    my $name = shift;
+    my $field_type = shift;
+    my $field_name = shift;
+
+    local $_ = $field_type;
+
+    my $count;
+    my $bits;
+    if (s/^(.*?)\s*(?:\[\s*(.*?)\s*\]|:(\d+))?$/$1/) {
+	$count = $2;
+	$bits = $3;
+    }
+
+    my $size;
+    if(/^(?:(?:signed\s+|unsigned\s+)?char|CHAR|BYTE|UCHAR)$/) {
+	$size = 1;
+    } elsif (/^(?:(?:signed\s+|unsigned\s+)?short|UWORD|WCHAR|WORD)$/) {
+	$size = 2;
+    } elsif (/^(?:FILETIME|LARGE_INTEGER|LONGLONG|ULONGLONG)$/) {
+	$size = 8;
+    } elsif (/^(?:SYSTEMTIME)$/) {
+	$size = 16;
+    } elsif (/^(?:CRITICAL_SECTION)$/) {
+	$size = 24;
+    } elsif (/^(?:DCB)$/) {
+	$size = 28;
+    } elsif (/^(?:EXCEPTION_RECORD)$/) {
+	$size = 80;
+    } elsif (/^(?:struct|union)$/) {
+	$output->write("$name:$field_name: can't parse type '$field_type'\n");
+	$size = 4;
+    } else {
+	$size = 4;
+    }
+
+    if (defined($count)) {
+	if ($count =~ /^\d+$/) {
+	    return $size * int($count);
+	} elsif ($count =~ /^ANYSIZE_ARRAY$/) {
+	    return $size;
+	} else {
+	    $output->write("$name:$field_name: can't parse type '$field_type'\n");
+	    return $size; # Not correct.
+	}
+    } elsif (defined($bits)) {
+	return -$bits;
+    } else {
+	return $size;
+    }
+}
+
+########################################################################
+# output_file
+
+sub output_file {
+    local *OUT = shift;
+
+    my $test_dir = shift;
+    my $test = shift;
+
+    output_header(\*OUT, $test_dir, $test);
+    
+    my @includes = $tests->get_section($test_dir, $test, "include");
+    my @type_names = $tests->get_section($test_dir, $test, "struct");
+    
+    foreach my $include (@includes) {
+	my $types = $file2types{"include/$include"};
+	
+	foreach my $type_name (@type_names) {
+	    my $pack = 4; # FIXME: Not always correct
+	    
+	    my $type = $$types{$type_name};
+	    
+	    my $offset = 0;
+	    my $offset_bits = 0;
+	    
+	    print OUT "    /* $type_name */\n";
+	    foreach my $field ($type->fields) {
+		(my $field_type, my $field_name) = @$field;
+		
+		my $field_size = field_size($type_name, $field_type, $field_name);
+		if ($field_size >= 0) {
+		    if ($offset_bits) {
+			$offset += $pack * int(($offset_bits + 8 * $pack - 1 ) / (8 * $pack));
+			$offset_bits = 0;
+		    }
+		    
+		    my $field_offset = $offset;
+		    if ($field_name ne "") {
+			print OUT "    ok(FIELD_OFFSET($type_name, $field_name) == $field_offset,\n";
+			print OUT "       \"FIELD_OFFSET($type_name, $field_name) == %ld (expected $field_offset)\",\n";
+			print OUT "       FIELD_OFFSET($type_name, $field_name)); /* $field_type */\n";
+		    }
+		    
+		    $offset += $field_size;
+		} else {
+		    $offset_bits += -$field_size;
+		}
+	    }
+	    
+	    my $type_size = $offset;
+	    if ($type_size % $pack != 0) {
+		$type_size = (int($type_size / $pack) + 1) * $pack;
+	    }
+	    
+	    print OUT "    ok(sizeof($type_name) == $type_size, ";
+	    print OUT "\"sizeof($type_name) == %d (expected $type_size)\", ";
+	    print OUT "sizeof($type_name));\n";
+	    print OUT "\n";
+	}
+    }
+
+    output_footer(\*OUT, $test_dir, $test);
+}
+
+foreach my $test (@tests) {
+    my @test_dirs = $tests->get_test_dirs($test);
+    foreach my $test_dir (@test_dirs) {
+	my $file = "$wine_dir/$test_dir/generated_$test.c";
+	replace_file($file, \&output_file, $test_dir, $test);
+    }
+}
diff --git a/tools/winapi/winapi_test_options.pm b/tools/winapi/winapi_test_options.pm
new file mode 100644
index 0000000..a93921b
--- /dev/null
+++ b/tools/winapi/winapi_test_options.pm
@@ -0,0 +1,53 @@
+#
+# Copyright 2002 Patrik Stridvall
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+package winapi_test_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" },
+
+    "pack" => { default => 1, description => "generate data structures packing tests" },
+);
+
+my %options_short = (
+    "d" => "debug",
+    "?" => "help",
+    "v" => "verbose"
+);
+
+my $options_usage = "usage: winapi_test [--help]\n";
+
+$options = '_options'->new(\%options_long, \%options_short, $options_usage);
+
+1;
diff --git a/tools/winapi_check/modules.pm b/tools/winapi_check/modules.pm
index 1904ff3..82ac2e4 100644
--- a/tools/winapi_check/modules.pm
+++ b/tools/winapi_check/modules.pm
@@ -39,7 +39,13 @@
 use options qw($options);
 use output qw($output);
 
-$modules = 'modules'->new;
+sub import {
+    $Exporter::ExportLevel++;
+    &Exporter::import(@_);
+    $Exporter::ExportLevel--;
+
+    $modules = 'modules'->new;
+}
 
 sub get_spec_file_type {
     my $file = shift;
@@ -85,18 +91,23 @@
     my $self  = {};
     bless ($self, $class);
 
-    my $spec_files16 = \@{$self->{SPEC_FILES16}};
-    my $spec_files32 = \@{$self->{SPEC_FILES32}};
+    my $spec_file_found = $self->read_module_file();
+    $self->read_spec_files($spec_file_found);
+
+    return $self;
+}
+
+sub read_module_file {
+    my $self = shift;
+
     my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
     my $spec_file2dir = \%{$self->{SPEC_FILE2DIR}};
-    my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
-    my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}};
 
     my $module_file = "$winapi_check_dir/modules.dat";
 
     $output->progress("modules.dat");
 
-    my %spec_file_found;
+    my $spec_file_found = {};
     my $allowed_dir;
     my $spec_file;
 
@@ -114,7 +125,7 @@
 		$output->write("modules.dat: $spec_file: file ($spec_file) doesn't exist or is no file\n");
 	    }
 
-	    $spec_file_found{$spec_file}++;
+	    $$spec_file_found{$spec_file}++;
 	    $$spec_file2dir{$spec_file} = {};
 	    next;
 	} else {
@@ -129,6 +140,20 @@
     }
     close(IN);
 
+    return $spec_file_found;
+}
+
+sub read_spec_files {
+    my $self = shift;
+    
+    my $spec_file_found = shift;
+
+    my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
+    my $spec_files16 = \@{$self->{SPEC_FILES16}};
+    my $spec_files32 = \@{$self->{SPEC_FILES32}};
+    my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
+    my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}};
+
     my @spec_files;
     if($wine_dir eq ".") {
 	@spec_files = get_spec_files("winelib");
@@ -162,14 +187,10 @@
     }
 
     foreach my $spec_file (@spec_files) {
-	if(!$spec_file_found{$spec_file} && $spec_file !~ m%tests/[^/]+$%) {
+	if(!$$spec_file_found{$spec_file} && $spec_file !~ m%tests/[^/]+$%) {
 	    $output->write("modules.dat: $spec_file: exists but is not specified\n");
 	}
     }
-
-    $modules = $self;
-
-    return $self;
 }
 
 sub all_modules {
diff --git a/tools/winapi_check/winapi_function.pm b/tools/winapi_check/winapi_function.pm
index 96da183..4564d43 100644
--- a/tools/winapi_check/winapi_function.pm
+++ b/tools/winapi_check/winapi_function.pm
@@ -22,9 +22,10 @@
 use strict;
 
 use config qw($current_dir $wine_dir);
-use modules qw($modules);
 use util qw(&normalize_set);
-use winapi qw($win16api $win32api @winapis);
+
+my $import = 0;
+use vars qw($modules $win16api $win32api @winapis);
 
 ########################################################################
 # constructor
@@ -36,6 +37,15 @@
     my $self  = {};
     bless ($self, $class);
 
+    if (!$import) {
+	require modules;
+	import modules qw($modules);
+	
+	require winapi;
+	import winapi qw($win16api $win32api @winapis);
+
+	$import = 1;
+    }
     return $self;
 }