diff --git a/tools/winapi/config.pm b/tools/winapi/config.pm index 91493179c8a..086f442ed2d 100644 --- a/tools/winapi/config.pm +++ b/tools/winapi/config.pm @@ -9,7 +9,11 @@ require Exporter; @ISA = qw(Exporter); @EXPORT = qw( - &file_type &file_skip &files_skip &get_spec_files + &file_type + &file_skip &files_skip + &file_normalize + &get_spec_files + &translate_calling_convention16 &translate_calling_convention32 ); @EXPORT_OK = qw( $current_dir $wine_dir $winapi_dir $winapi_check_dir @@ -65,6 +69,19 @@ sub files_skip { return @files; } +sub file_normalize { + local $_ = shift; + + foreach my $dir (split(m%/%, $current_dir)) { + s%^(\.\./)*\.\./$dir/%%; + if(defined($1)) { + $_ = "$1$_"; + } + } + + return $_; +} + sub get_spec_files { output->progress("$wine_dir: searching for *.spec"); @@ -80,4 +97,36 @@ sub get_spec_files { return @spec_files; } +sub translate_calling_convention16 { + local $_ = shift; + + if(/^__cdecl$/) { + return "cdecl"; + } elsif(/^VFWAPIV|WINAPIV$/) { + return "varargs"; + } elsif(/^__stdcall|VFWAPI|WINAPI|CALLBACK$/) { + return "pascal"; + } elsif(/^__asm$/) { + return "asm"; + } else { + return "cdecl"; + } +} + +sub translate_calling_convention32 { + local $_ = shift; + + if(/^__cdecl$/) { + return "cdecl"; + } elsif(/^VFWAPIV|WINAPIV$/) { + return "varargs"; + } elsif(/^__stdcall|VFWAPI|WINAPI|CALLBACK$/) { + return "stdcall"; + } elsif(/^__asm$/) { + return "asm"; + } else { + return "cdecl"; + } +} + 1; diff --git a/tools/winapi/winapi_extract b/tools/winapi/winapi_extract index 71a77edb359..1fb61901eb4 100755 --- a/tools/winapi/winapi_extract +++ b/tools/winapi/winapi_extract @@ -119,24 +119,26 @@ foreach my $file (@files) { local $_; foreach (split(/\n/, $documentation)) { if(/^ \*\s*(\w+)\s*[\(\[]\s*(\w+)\.\s*(\@|\d+)\s*[\)\]]/m) { - my $name = $1; + my $external_name = $1; my $module = lc($2); my $ordinal = $3; if($ordinal eq "@") { - $specifications{$module}{unfixed}{$name}{debug_channels} = [@debug_channels]; - $specifications{$module}{unfixed}{$name}{name} = $name; - $specifications{$module}{unfixed}{$name}{ordinal} = $ordinal; - $specifications{$module}{unfixed}{$name}{arguments} = [@argument_types]; + $specifications{$module}{unfixed}{$external_name}{debug_channels} = [@debug_channels]; + $specifications{$module}{unfixed}{$external_name}{internal_name} = $internal_name; + $specifications{$module}{unfixed}{$external_name}{external_name} = $external_name; + $specifications{$module}{unfixed}{$external_name}{ordinal} = $ordinal; + $specifications{$module}{unfixed}{$external_name}{arguments} = [@argument_types]; } else { $specifications{$module}{fixed}{$ordinal}{debug_channels} = [@debug_channels]; $specifications{$module}{fixed}{$ordinal}{ordinal} = $ordinal; - $specifications{$module}{fixed}{$ordinal}{name} = $name; + $specifications{$module}{fixed}{$ordinal}{internal_name} = $internal_name; + $specifications{$module}{fixed}{$ordinal}{external_name} = $external_name; $specifications{$module}{fixed}{$ordinal}{arguments} = [@argument_types]; } if($options->debug) { - output->write("$file: $name ($module.$ordinal)\n"); + output->write("$file: $external_name ($module.$ordinal)\n"); } } } @@ -160,7 +162,8 @@ sub output_function { my $type = shift; my $function = shift; - my $name = $function->{name}; + my $internal_name = $function->{internal_name}; + my $external_name = $function->{external_name}; my $ordinal = $function->{ordinal}; my @arguments = @{$function->{arguments}}; @@ -175,13 +178,18 @@ sub output_function { if(!defined($argument2)) { $argument2 = "undef"; } - push @arguments2, $argument2; + + if($argument2 eq "longlong") { + push @arguments2, ("long", "long"); + } else { + push @arguments2, $argument2; + } } if($type eq "win16") { - print OUT "$ordinal pascal $name(@arguments2) $name\n"; + print OUT "$ordinal pascal $external_name(@arguments2) $internal_name\n"; } else { - print OUT "$ordinal stdcall $name(@arguments2) $name\n"; + print OUT "$ordinal stdcall $external_name(@arguments2) $internal_name\n"; } } diff --git a/tools/winapi/winapi_fixup b/tools/winapi/winapi_fixup index 6f0e1a30cec..047da6fcab0 100755 --- a/tools/winapi/winapi_fixup +++ b/tools/winapi/winapi_fixup @@ -10,7 +10,9 @@ BEGIN { } use config qw( - &file_type &file_skip &files_skip &get_spec_files + &file_type &file_skip &files_skip &file_normalize + &get_spec_files + &translate_calling_convention16 &translate_calling_convention32 $current_dir $wine_dir $winapi_dir $winapi_check_dir ); use output; @@ -33,9 +35,12 @@ my %options_long = ( "win32" => { default => 1, description => "Win32 fixup" }, "local" => { default => 1, description => "local fixup" }, + "documentation" => { default => 0, parent => "local", description => "documentation fixup" }, + "ordinal" => { default => 0, parent => "local", description => "ordinal fixup" }, + "stub" => { default => 0, parent => "local", description => "stub fixup" }, "global" => { default => 1, description => "global fixup" }, - "modify" => { default => 0, description => "global fixup" }, + "modify" => { default => 0, description => "global fixup" }, ); my %options_short = ( @@ -61,8 +66,52 @@ if($wine_dir eq ".") { winapi->read_spec_files($modules, $wine_dir, $current_dir, \@spec_files, $win16api, $win32api); } -my %substitute; -my %insert_line; +sub get_all_module_ordinal { + my $internal_name = shift; + my $external_name = shift; + + my @entries = (); + foreach my $winapi (@winapis) { + my @module2 = (); { + my $module2 = $winapi->function_internal_module($internal_name); + if(defined($module2)) { + @module2 = split(/ & /, $module2); + } + } + + foreach my $module2 (@module2) { + my $ordinal2; + + my @external_module = (); { + my $external_module = $winapi->function_external_module($external_name); + if(defined($external_module)) { + @external_module = split(/ & /, $external_module); + } + } + foreach my $external_module (@external_module) { + if(!defined($ordinal2) && $module2 eq $external_module) { + $ordinal2 = $winapi->function_external_ordinal($external_name); + } + } + + my @internal_module = (); { + my $internal_module = $winapi->function_internal_module($internal_name); + if(defined($internal_module)) { + @internal_module = split(/ & /, $internal_module); + } + } + foreach my $internal_module (@internal_module) { + if(!defined($ordinal2) && $module2 eq $internal_module) { + $ordinal2 = $winapi->function_internal_ordinal($internal_name); + } + } + + push @entries, [$module2, $ordinal2]; + } + } + + return @entries; +} my @c_files = files_skip(options->c_files); @@ -71,6 +120,11 @@ my $progress_current = 0; my $progress_max = scalar(@c_files); foreach my $file (@c_files) { + my %substitute_line; + my %insert_line; + + my %spec_file; + $progress_current++; if(options->progress) { output->progress("$file: file $progress_current of $progress_max"); @@ -97,51 +151,131 @@ foreach my $file (@c_files) { return; } - if($documentation) { + my $module16 = $win16api->function_internal_module($internal_name); + my $module32 = $win32api->function_internal_module($internal_name); + + my $prefix = ""; + $prefix .= "$file: "; + if(defined($module16) && !defined($module32)) { + $prefix .= "$module16: "; + } elsif(!defined($module16) && defined($module32)) { + $prefix .= "$module32: "; + } elsif(defined($module16) && defined($module32)) { + $prefix .= "$module16 & $module32: "; + } else { + $prefix .= "<>: "; + } + $prefix .= "$return_type "; + $prefix .= "$calling_convention " if $calling_convention; + $prefix .= "$internal_name(" . join(",", @argument_types) . "): "; + $output->prefix($prefix); + + my $calling_convention16 = translate_calling_convention16($calling_convention); + my $calling_convention32 = translate_calling_convention32($calling_convention); + + + if(options->ordinal && $documentation) { local $_; foreach (split(/\n/, $documentation)) { if(/^(\s*\*\s*\w+\s*)([\(\[]\s*\w+\.\s*(?:\@|\d+)\s*[\)\]])\s*([\(\[]\s*\w+\.\s*(?:\@|\d+)\s*[\)\]])/m) { - $substitute{$_}{search} = $_; - $substitute{$_}{replace} = "$1$2\n$1$3"; + $substitute_line{$_}{search} = $_; + $substitute_line{$_}{replace} = "$1$2\n$1$3"; + } elsif(/^\s*\*\s*(\w+)\s*$/m) { + my $external_name = $1; + if($internal_name eq $external_name) { + foreach my $entry (get_all_module_ordinal($internal_name, $external_name)) { + (my $module, my $ordinal) = @$entry; + + $substitute_line{$_}{search} = "$external_name"; + $substitute_line{$_}{replace} = "$external_name (\U$module\E.$ordinal)"; + } + } } elsif(/^\s*\*\s*(\w+)\s*[\(\[]\s*(\w+)\.\s*(\@|\d+)\s*[\)\]]/m) { - my $name = $1; - my $module = $2; + my $external_name = $1; + my $module = lc($2); my $ordinal = $3; - my $module2; - my $ordinal2; - foreach my $winapi (@winapis) { - $module2 = ($winapi->function_module($internal_name) || $module2); - $ordinal2 = ($winapi->function_ordinal($internal_name) || $ordinal2); - if(defined($module2) || defined($ordinal2)) { last; } - } - - if(!defined($module2) || !defined($ordinal2)) { - output->write("$file: $internal_name: unknown error\n"); - } elsif(lc($module) eq $module2 && $ordinal ne $ordinal2) { - $substitute{$_}{search} = "$module.$ordinal"; - $substitute{$_}{replace} = "\U$module2\E.$ordinal2"; + foreach my $entry (get_all_module_ordinal($internal_name, $external_name)) { + (my $module2, my $ordinal2) = @$entry; + if(!defined($module2) || !defined($ordinal2)) { + if(defined($module2)) { + output->write("$file: $internal_name: unknown error (\U$module2\E.?)\n"); + } elsif(defined($module2)) { + output->write("$file: $internal_name: unknown error (?.$ordinal2)\n"); + } else { + output->write("$file: $internal_name: unknown error\n"); + } + } elsif($module eq $module2 && $ordinal ne $ordinal2) { + $substitute_line{$_}{search} = "\U$module\E.$ordinal"; + $substitute_line{$_}{replace} = "\U$module2\E.$ordinal2"; + } } } } - } elsif(0) { - my $name; + } + + if(options->documentation && !$documentation) { + my $external_name; my $module; my $ordinal; foreach my $winapi (@winapis) { - $name = ($winapi->function_external_name($internal_name) || $name); - $module = ($winapi->function_module($internal_name) || $module); - $ordinal = ($winapi->function_ordinal($internal_name) || $ordinal); - if(defined($name) || defined($module) || defined($ordinal)) { last; } + $external_name = ($winapi->function_external_name($internal_name) || $external_name); + $module = ($winapi->function_internal_module($internal_name) || $module); + $ordinal = ($winapi->function_internal_ordinal($internal_name) || $ordinal); + if(defined($external_name) || defined($module) || defined($ordinal)) { last; } } - if(defined($name) && defined($module) && defined($ordinal)) { + if(defined($external_name) && defined($module) && defined($ordinal)) { $insert_line{$line} = "/" . "*" x 71 . "\n" . - " *\t\t$name (\U$module\E.$ordinal)\n" . + " *\t\t$external_name (\U$module\E.$ordinal)\n" . " */\n"; } } + + if(options->stub) { + foreach my $winapi (@winapis) { + if($winapi->function_stub($internal_name)) { + my $module = $winapi->function_internal_module($internal_name); + my $ordinal = $winapi->function_internal_ordinal($internal_name); + + my $n; + my @argument_kinds = map { + my $type = $_; + my $kind = "unknown"; + $winapi->type_used_in_module($type, $module); + if(!defined($kind = $winapi->translate_argument($type))) { + output->write("no translation defined: " . $type . "\n"); + } + + # FIXME: Kludge + if(defined($kind) && $kind eq "longlong") { + $n += 2; + ("long", "long"); + } else { + $n++; + $kind; + } + } @argument_types; + + my $substitute = {}; + $substitute->{search} = "^$ordinal\\s+stub\\s+$internal_name\\s*(?:#.*?)?\$"; + + if($winapi->name eq "win16") { + $substitute->{replace} = "$ordinal $calling_convention16 $internal_name(@argument_kinds) $internal_name"; + } else { + $substitute->{replace} = "$ordinal $calling_convention32 $internal_name(@argument_kinds) $internal_name"; + } + + if(!defined($spec_file{$module})) { + $spec_file{$module} = []; + } + + push @{$spec_file{$module}}, $substitute; + } + } + } + $output->prefix(""); }; my $found_preprocessor = sub { @@ -169,8 +303,8 @@ foreach my $file (@c_files) { } } - my $search = $substitute{$_}{search}; - my $replace = $substitute{$_}{replace}; + my $search = $substitute_line{$_}{search}; + my $replace = $substitute_line{$_}{replace}; if(defined($search) && defined($replace)) { if(options->modify) { @@ -188,7 +322,59 @@ foreach my $file (@c_files) { return $modified; }; - edit_file($file, $editor); + my $n = 0; while(defined(each %substitute_line)) { $n++; } + if($n > 0) { + edit_file($file, $editor); + } + + foreach my $module (sort(keys(%spec_file))) { + my $file; + foreach my $winapi (@winapis) { + $file = ($winapi->module_file($module) || $file); + } + + if(defined($file)) { + $file = file_normalize($file); + } + + my @substitutes = @{$spec_file{$module}}; + + my $editor = sub { + local *IN = shift; + local *OUT = shift; + + my $modified = 0; + while() { + chomp; + + foreach my $substitute (@substitutes) { + my $search = $substitute->{search}; + my $replace = $substitute->{replace}; + + if(s/$search/$replace/) { + if(options->modify) { + $modified = 1; + } else { + output->write("$file: search : '$search'\n"); + output->write("$file: replace: '$replace'\n"); + } + } + } + + print OUT "$_\n"; + } + + return $modified; + }; + + if(defined($file)) { + edit_file($file, $editor); + } else { + output->write("$module: doesn't have any spec file\n"); + } + } } output->hide_progress; + +