- 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;
}