diff --git a/tools/winapi/Makefile.in b/tools/winapi/Makefile.in index 4c33b881949..c9ad9e161e5 100644 --- a/tools/winapi/Makefile.in +++ b/tools/winapi/Makefile.in @@ -14,11 +14,13 @@ install:: $(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 a487026d6e9..9e97d4c9882 100644 --- a/tools/winapi/c_parser.pm +++ b/tools/winapi/c_parser.pm @@ -776,6 +776,7 @@ sub parse_c_file { 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 @@ sub parse_c_file { $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 @@ sub parse_c_typedef { 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 @@ sub parse_c_typedef { { 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 @@ sub parse_c_variable { 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 @@ sub parse_c_variable { } 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 @@ sub parse_c_variable { # $output->write("$type: $name: '$_'\n"); - if(1) { + if(1 || $finished) { # Nothing } elsif($self->_parse_c('(?:struct\s+)?ICOM_VTABLE\s*\(.*?\)', \$_, \$line, \$column, \$match)) { $type = ""; @@ -1906,29 +1957,28 @@ sub parse_c_variable { $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 = ""; - } - $$refcurrent = $_; $$refline = $line; $$refcolumn = $column; diff --git a/tools/winapi/c_type.pm b/tools/winapi/c_type.pm index 2780f42278c..ac099e8535f 100644 --- a/tools/winapi/c_type.pm +++ b/tools/winapi/c_type.pm @@ -59,7 +59,14 @@ sub name { 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 @@ sub fields { 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 @@ sub field_types { 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 00000000000..4bf46f7a040 --- /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 00000000000..e745d791ccd --- /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() { + 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 fe82e08a277..ab4b5cf1f1f 100644 --- a/tools/winapi/winapi.pm +++ b/tools/winapi/winapi.pm @@ -30,30 +30,41 @@ require Exporter; 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 2f61703697a..2918a656255 100755 --- a/tools/winapi/winapi_cleanup +++ b/tools/winapi/winapi_cleanup @@ -28,37 +28,14 @@ use config qw($current_dir $wine_dir); use output qw($output); use winapi_cleanup_options qw($options); +use util qw(edit_file); + if($options->progress) { $output->enable_progress; } else { $output->disable_progress; } -######################################################################## -# 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 diff --git a/tools/winapi/winapi_extract b/tools/winapi/winapi_extract index c66b2c91063..7216349836c 100755 --- a/tools/winapi/winapi_extract +++ b/tools/winapi/winapi_extract @@ -41,10 +41,15 @@ use c_parser; 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 @@ foreach my $file (@h_files, @c_files) { 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 @@ foreach my $file (@h_files, @c_files) { 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 00000000000..f014bbc3598 --- /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; + $_ = ; + 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 \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 00000000000..a93921b7a4c --- /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 1904ff37db7..82ac2e42c0e 100644 --- a/tools/winapi_check/modules.pm +++ b/tools/winapi_check/modules.pm @@ -39,7 +39,13 @@ use config qw( 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 @@ sub new { 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 @@ sub new { $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 @@ sub new { } 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 @@ sub new { } 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 96da183e3ce..4564d4390cf 100644 --- a/tools/winapi_check/winapi_function.pm +++ b/tools/winapi_check/winapi_function.pm @@ -22,9 +22,10 @@ use base qw(function); 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 @@ sub new { 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; }