Generate Perl modules defining prototypes for exported functions.
diff --git a/tools/winapi/winapi_extract b/tools/winapi/winapi_extract
index efae0ed..88cebeb 100755
--- a/tools/winapi/winapi_extract
+++ b/tools/winapi/winapi_extract
@@ -28,30 +28,58 @@
use winapi_parser;
use winapi qw(@winapis);
+my %module2entries;
my %module2spec_file;
my %module2type;
-if($options->spec_files) {
+my %module2filename;
+if($options->spec_files || $options->winetest) {
local $_;
foreach my $spec_file (get_spec_files("winelib")) {
+ my $entries = [];
+
my $module;
my $type;
open(IN, "< $wine_dir/$spec_file");
- while(<IN>) {
+
+ my $header = 1;
+ my $lookahead = 0;
+ while($lookahead || defined($_ = <IN>)) {
+ $lookahead = 0;
+
s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begining and end of line
s/^(.*?)\s*#.*$/$1/; # remove comments
/^$/ && next; # skip empty lines
- if(/^name\s+(.*?)$/) {
- $module = $1;
- $module2spec_file{$module} = $spec_file;
- } elsif(/^type\s+(.*?)$/) {
- $type = $1;
- $module2type{$module} = $type;
+ if($header) {
+ if(/^name\s+(.*?)$/) {
+ $module = $1;
+ $module2spec_file{$module} = $spec_file;
+ } elsif(/^file\s+(.*?)$/) {
+ my $filename = $1;
+ $module2filename{$module} = $filename;
+ } elsif(/^type\s+(.*?)$/) {
+ $type = $1;
+ $module2type{$module} = $type;
+ } elsif(/^\d+|@/) {
+ $header = 0;
+ $lookahead = 1;
+ }
+ next;
+ }
+
+ if(/^(@|\d+)\s+stdcall\s+(\w+)\s*\(\s*([^\)]*)\s*\)/) {
+ my $ordinal = $1;
+ my $name = $2;
+ my @args = split(/\s+/, $3);
+
+ push @$entries, [$name, "undef", \@args];
}
}
close(IN);
+
+ $module2entries{$module} = $entries;
}
}
@@ -177,7 +205,7 @@
my $calling_convention = $function->calling_convention;
my $statements = $function->statements;
- if($options->spec_files) {
+ if($options->spec_files || $options->winetest) {
documentation_specifications($function);
}
@@ -377,3 +405,106 @@
}
}
+if($options->winetest) {
+ foreach my $module (sort(keys(%specifications))) {
+ my $type = $module2type{$module};
+ my $filename = $module2filename{$module} || $module;
+ my $modulename = $filename;
+ $modulename =~ s/\./_/g;
+
+ next unless $type eq "win32";
+
+ my @entries;
+
+ foreach my $external_name (sort(keys(%{$specifications{$module}{unknown}}))) {
+ my $entry = $specifications{$module}{unknown}{$external_name};
+ push @entries, $entry;
+ }
+
+ foreach my $ordinal (sort {$a <=> $b} keys(%{$specifications{$module}{fixed}})) {
+ my $entry = $specifications{$module}{fixed}{$ordinal};
+ push @entries, $entry;
+ }
+
+ foreach my $external_name (sort(keys(%{$specifications{$module}{unfixed}}))) {
+ my $entry = $specifications{$module}{unfixed}{$external_name};
+ push @entries, $entry;
+ }
+
+ my $n = 0;
+ foreach my $entry (@entries) {
+ my $external_name = $entry->{external_name};
+ my $ordinal = $entry->{ordinal};
+ my $function = $entry->{function};
+
+ my $return_kind;
+ my $calling_convention;
+ my $refargument_kinds;
+ if($type eq "win16") {
+ $return_kind = $function->return_kind16 || "undef";
+ $calling_convention = $function->calling_convention16 || "undef";
+ $refargument_kinds = $function->argument_kinds16;
+ } elsif($type eq "win32") {
+ $return_kind = $function->return_kind32 || "undef";
+ $calling_convention = $function->calling_convention32 || "undef";
+ $refargument_kinds = $function->argument_kinds32;
+ }
+
+ my @argument_kinds;
+ if(defined($refargument_kinds)) {
+ @argument_kinds = map { $_ || "undef"; } @$refargument_kinds;
+ }
+
+ next if $calling_convention ne "stdcall";
+ next if $external_name eq "\@";
+
+ if($n == 0) {
+ open(OUT, "> $wine_dir/programs/winetest/include/${modulename}.pm");
+
+ print OUT "package ${modulename};\n";
+ print OUT "\n";
+
+ print OUT "use strict;\n";
+ print OUT "\n";
+
+ print OUT "require Exporter;\n";
+ print OUT "\n";
+
+ print OUT "use wine;\n";
+ print OUT "use vars qw(\@ISA \@EXPORT \@EXPORT_OK);\n";
+ print OUT "\n";
+
+ print OUT "\@ISA = qw(Exporter);\n";
+ print OUT "\@EXPORT = qw();\n";
+ print OUT "\@EXPORT_OK = qw();\n";
+ print OUT "\n";
+
+ print OUT "my \$module_declarations = {\n";
+ } elsif($n > 0) {
+ print OUT ",\n";
+ }
+
+ print OUT " \"\Q$external_name\E\" => [\"$return_kind\", [";
+ my $m = 0;
+ foreach my $argument_kind (@argument_kinds) {
+ if($m > 0) {
+ print OUT ", ";
+ }
+ print OUT "\"$argument_kind\"";
+ $m++;
+ }
+ print OUT "]]";
+ $n++;
+ }
+
+ if($n > 0) {
+ print OUT "\n";
+ print OUT "};\n";
+ print OUT "\n";
+ print OUT "&wine::declare(\"$filename\",\%\$module_declarations);\n";
+ print OUT "push \@EXPORT, map { \"&\" . \$_; } sort(keys(\%\$module_declarations));\n";
+ print OUT "1;\n";
+ close(OUT);
+ }
+ }
+}
diff --git a/tools/winapi/winapi_extract_options.pm b/tools/winapi/winapi_extract_options.pm
index 3d29621..6a5d4eb 100644
--- a/tools/winapi/winapi_extract_options.pm
+++ b/tools/winapi/winapi_extract_options.pm
@@ -25,8 +25,9 @@
"local" => { default => 1, description => "local extraction" },
"global" => { default => 1, description => "global extraction" },
- "spec-files" => { default => 1, parent => "global", description => "spec files extraction" },
+ "spec-files" => { default => 0, parent => "global", description => "spec files extraction" },
"stub-statistics" => { default => 1, parent => "global", description => "stub statistics" },
+ "winetest" => { default => 1, parent => "global", description => "winetest extraction" },
);
my %options_short = (