3 # Copyright 2001 Patrik Stridvall
8 $0 =~ m%^(.*?/?tools)/winapi/winapi_fixup$%;
9 require "$1/winapi/setup.pm";
13 &file_type &files_filter
14 &file_skip &files_skip
17 &translate_calling_convention16 &translate_calling_convention32
18 $current_dir $wine_dir $winapi_dir $winapi_check_dir
27 my $output = output->new;
30 "debug" => { default => 0, description => "debug mode" },
31 "help" => { default => 0, description => "help mode" },
32 "verbose" => { default => 0, description => "verbose mode" },
34 "progress" => { default => 1, description => "show progress" },
36 "win16" => { default => 1, description => "Win16 fixup" },
37 "win32" => { default => 1, description => "Win32 fixup" },
39 "local" => { default => 1, description => "local fixup" },
40 "documentation" => { default => 1, parent => "local", description => "documentation fixup" },
41 "documentation-ordinal" => { default => 0, parent => "documentation", description => "documentation ordinal fixup" },
42 "documentation-missing" => { default => 0, parent => "documentation", description => "documentation missing fixup" },
43 "documentation-name" => { default => 1, parent => "documentation", description => "documentation name fixup" },
44 "stub" => { default => 0, parent => "local", description => "stub fixup" },
46 "global" => { default => 1, description => "global fixup" },
48 "modify" => { default => 0, description => "actually perform the fixups" },
57 my $options_usage = "usage: winapi_fixup [--help] [<files>]\n";
59 my $options = options->new(\%options_long, \%options_short, $options_usage);
61 my $modules = modules->new($options, $output, $wine_dir, $current_dir, \&file_type, "$winapi_check_dir/modules.dat");
63 my $win16api = winapi->new($options, $output, "win16", "$winapi_check_dir/win16");
64 my $win32api = winapi->new($options, $output, "win32", "$winapi_check_dir/win32");
65 my @winapis = ($win16api, $win32api);
67 if($wine_dir eq ".") {
68 winapi->read_all_spec_files($modules, $wine_dir, $current_dir, \&file_type, $win16api, $win32api);
70 my @spec_files = $modules->allowed_spec_files($wine_dir, $current_dir);
71 winapi->read_spec_files($modules, $wine_dir, $current_dir, \@spec_files, $win16api, $win32api);
74 sub get_all_module_internal_ordinal {
75 my $internal_name = shift;
78 foreach my $winapi (@winapis) {
80 my $module = $winapi->function_internal_module($internal_name);
81 if(defined($module)) {
82 @module = split(/ & /, $module);
86 my $ordinal = $winapi->function_internal_ordinal($internal_name);
87 if(defined($ordinal)) {
88 @ordinal = split(/ & /, $ordinal);
94 while(defined($module = shift @module) && defined($ordinal = shift @ordinal)) {
95 push @entries, [$module, $ordinal];
102 sub get_all_module_external_ordinal {
103 my $external_name = shift;
106 foreach my $winapi (@winapis) {
108 my $name = $winapi->function_external_name($external_name);
110 @name = split(/ & /, $name);
114 my $module = $winapi->function_external_module($external_name);
115 if(defined($module)) {
116 @module = split(/ & /, $module);
120 my $ordinal = $winapi->function_external_ordinal($external_name);
121 if(defined($ordinal)) {
122 @ordinal = split(/ & /, $ordinal);
129 while(# defined($name = shift @name) &&
130 defined($module = shift @module) &&
131 defined($ordinal = shift @ordinal))
133 push @entries, [$name, $module, $ordinal];
148 foreach my $key (split(/\s*&\s*/)) {
152 return join(" & ", sort(keys(%hash)));
155 my @c_files = options->c_files;
156 @c_files = files_skip(@c_files);
157 @c_files = files_filter("winelib", @c_files);
160 my $progress_current = 0;
161 my $progress_max = scalar(@c_files);
163 foreach my $file (@c_files) {
170 if(options->progress) {
171 output->progress("$file: file $progress_current of $progress_max");
174 my $found_function = sub {
176 my $refdebug_channels = shift;
177 my @debug_channels = @$refdebug_channels;
178 my $documentation = shift;
180 my $return_type = shift;
181 my $calling_convention = shift;
182 my $internal_name = shift;
183 my $refargument_types = shift;
184 my @argument_types = @$refargument_types;
185 my $refargument_names = shift;
186 my @argument_names = @$refargument_names;
187 my $refargument_documentations = shift;
188 my @argument_documentations = @$refargument_documentations;
189 my $statements = shift;
191 if($linkage eq "static" || $linkage eq "extern") {
195 my $module16 = $win16api->function_internal_module($internal_name);
196 my $module32 = $win32api->function_internal_module($internal_name);
199 $prefix .= "$file: ";
200 if(defined($module16) && !defined($module32)) {
201 $prefix .= normalize_set($module16) . ": ";
202 } elsif(!defined($module16) && defined($module32)) {
203 $prefix .= normalize_set($module32) . ": ";
204 } elsif(defined($module16) && defined($module32)) {
205 $prefix .= normalize_set($module16) . " & " . normalize_set($module32) . ": ";
209 $prefix .= "$return_type ";
210 $prefix .= "$calling_convention " if $calling_convention;
211 $prefix .= "$internal_name(" . join(",", @argument_types) . "): ";
212 $output->prefix($prefix);
214 my $calling_convention16 = translate_calling_convention16($calling_convention);
215 my $calling_convention32 = translate_calling_convention32($calling_convention);
217 my @external_names = ();
218 foreach my $winapi (@winapis) {
219 my $external_names = $winapi->function_external_name($internal_name);
220 if(defined($external_names)) {
221 push @external_names, split(/\s*&\s*/, $external_names);
225 if(options->documentation_ordinal && $documentation) {
227 foreach (split(/\n/, $documentation)) {
228 if(/^(\s*\*\s*(\w+)\s*)(\s*(?:[\(\[]\s*\w+(?:\s*\.\s*\S*\s*)?[\)\]])+)(.*?)$/m) {
230 my $external_name = $2;
237 while($part3 =~ s/^\s*([\(\[]\s*(\w+)(?:\s*\.\s*(\S*)\s*)?[\)\]])//) {
238 push @entries, [$1, lc($2), $3];
243 foreach my $entry (@entries) {
244 (my $part, my $module, my $ordinal) = @$entry;
245 foreach my $entry2 (get_all_module_external_ordinal($external_name)) {
246 (my $external_name2, my $module2, my $ordinal2) = @$entry2;
248 if(defined($module2) && $module eq $module2 &&
249 (!defined($ordinal) || (defined($ordinal2) && $ordinal ne $ordinal2)))
251 if(defined($ordinal)) {
252 if($part =~ s/\U$module\E\s*.\s*\Q$ordinal\E/\U$module2\E.$ordinal2/) {
256 if($part =~ s/\U$module\E/\U$module2\E.$ordinal2/) {
262 if($replace) { $replace .= "\n"; }
263 $replace .= "$part1$part$part4";
267 $substitute_line{$_}{search} = "^\Q$_\E\$";
268 $substitute_line{$_}{replace} = "$replace";
270 } elsif(/^(\s*\*\s*)(\w+)\s*$/m) {
272 my $external_name = $2;
273 if($internal_name eq $external_name) {
274 foreach my $entry (get_all_module_external_ordinal($external_name)) {
275 (my $external_name2, my $module, my $ordinal) = @$entry;
278 $substitute_line{$_}{search} = "^\Q$_\E\$";
279 $substitute_line{$_}{replace} = "$part1$external_name (\U$module\E.$ordinal)";
286 if(options->documentation_name && $documentation) {
290 foreach (split(/\n/, $documentation)) {
291 if(/^(\s*\*\s*(\w+)\s*)(\s*(?:[\(\[]\s*\w+(?:\s*\.\s*\S+\s*)?[\)\]])+)(.*?)$/m) {
293 my $external_name2 = $2;
299 push @entries, [$part1, $external_name2, $part3, $part4];
303 my @missing_external_names = ();
304 foreach my $external_name (@external_names) {
306 foreach my $entry (@entries) {
307 my $part1 = $entry->[0];
308 my $external_name2 = $entry->[1];
309 my $part3 = $entry->[2];
310 my $part4 = $entry->[3];
312 if($external_name eq $external_name2) {
317 push @missing_external_names, $external_name;
321 foreach my $external_name (@missing_external_names) {
322 my $internal_name2 = $internal_name;
323 my $external_name2 = $external_name;
325 if($internal_name =~ /^(.*?)$external_name(.*?)$/) {
334 foreach my $entry (@entries) {
335 $part1 = $entry->[0];
336 $external_name2 = $entry->[1];
337 $part3 = $entry->[2];
338 $part4 = $entry->[3];
340 if($internal_name =~ /^(.*?)$external_name(.*?)$/) {
345 foreach (split(/\n/, $documentation)) {
346 if(/\Q$external_name\E/) {
347 if($suffix =~ /^16$/) {
348 $substitute_line{$_}{search} = "\Q$internal_name\E";
349 $substitute_line{$_}{replace} = "$external_name";
351 } elsif($suffix =~ /^[AW]$/) {
352 $substitute_line{$_}{search} = "^\Q$_\E\$";
357 $part3 =~ /^\s*[\(\[]\s*(\w+)(?:\s*\.\s*(\S*)\s*)?[\)\]]/;
361 foreach my $entry2 (get_all_module_external_ordinal($external_name)) {
362 (my $external_name2, my $module2, my $ordinal2) = @$entry2;
365 $part12 =~ s/[AW](\s*)$/ $1/;
369 if($module ne $module2 || $ordinal ne $ordinal2) {
370 $part32 =~ s/\U$module\E\s*.\s*\Q$ordinal\E/\U$module2\E.$ordinal2/;
371 $replace = "$part12$part32$part4";
376 $replace .= "\n$part1$part3$part4";
377 $substitute_line{$_}{replace} = $replace;
386 output->write("$external_name missing\n");
391 if(options->documentation_missing && !$documentation) {
397 foreach my $winapi (@winapis) {
398 $external_name = ($winapi->function_external_name($internal_name) || $external_name);
399 $module = ($winapi->function_internal_module($internal_name) || $module);
400 $ordinal = ($winapi->function_internal_ordinal($internal_name) || $ordinal);
401 if(defined($external_name) || defined($module) || defined($ordinal)) { last; }
404 if(defined($external_name) && defined($module) && defined($ordinal)) {
405 $insert_line{$line} =
406 "/" . "*" x 71 . "\n" .
407 " *\t\t$external_name (\U$module\E.$ordinal)\n" .
414 foreach my $winapi (@winapis) {
415 if($winapi->function_stub($internal_name)) {
416 my $module = $winapi->function_internal_module($internal_name);
417 my $ordinal = $winapi->function_internal_ordinal($internal_name);
419 my $external_name = $internal_name;
420 if($winapi->name eq "win16") {
421 $external_name =~ s/(?:_)?16([AW]?)$//;
423 $external_name .= $1;
429 my @argument_kinds = map {
431 my $kind = "unknown";
432 $winapi->type_used_in_module($type, $module);
433 if(!defined($kind = $winapi->translate_argument($type))) {
434 output->write("no translation defined: " . $type . "\n");
438 if(defined($kind) && $kind eq "longlong") {
441 } elsif(defined($kind)) {
452 $substitute->{search} = "^\\s*$ordinal\\s+stub\\s+$external_name\\s*(?:#.*?)?\$";
454 if($winapi->name eq "win16") {
455 $substitute->{replace} = "$ordinal $calling_convention16 $external_name(@argument_kinds) $internal_name";
457 $substitute->{replace} = "$ordinal $calling_convention32 $external_name(@argument_kinds) $internal_name";
460 if(!defined($spec_file{$module})) {
461 $spec_file{$module} = [];
465 push @{$spec_file{$module}}, $substitute;
473 my $found_preprocessor = sub {
474 my $directive = shift;
475 my $argument = shift;
478 winapi_parser::parse_c_file $options, $output, $file, $found_function, $found_preprocessor;
488 my $line = $insert_line{$.};
490 if(options->modify) {
494 output->write("$file: $.: insert : '$line'\n");
498 my $search = $substitute_line{$_}{search};
499 my $replace = $substitute_line{$_}{replace};
501 if(defined($search) && defined($replace)) {
503 if(options->modify) {
504 if(s/$search/$replace/) {
510 if(!options->modify || !$modified2) {
513 if(options->modify && !$modified2) {
514 $search2 = "unmatched search";
515 $replace2 = "unmatched replace";
518 $replace2 = "replace";
520 output->write("$file: $.: $search2 : '$search'\n");
522 my @replace2 = split(/\n/, $replace);
524 output->write("$file: $.: $replace2: \\\n");
525 foreach my $replace2 (@replace2) {
526 output->write("'$replace2'\n");
529 output->write("$file: $.: $replace2: '$replace'\n");
539 my $n = 0; while(defined(each %substitute_line)) { $n++; }
541 edit_file($file, $editor);
544 foreach my $module (sort(keys(%spec_file))) {
546 foreach my $winapi (@winapis) {
547 $file = ($winapi->module_file($module) || $file);
551 $file = file_normalize($file);
554 my @substitutes = @{$spec_file{$module}};
564 my @substitutes2 = ();
565 foreach my $substitute (@substitutes) {
566 my $search = $substitute->{search};
567 my $replace = $substitute->{replace};
569 if(s/$search/$replace/) {
570 if(options->modify) {
573 output->write("$file: search : '$search'\n");
574 output->write("$file: replace: '$replace'\n");
578 push @substitutes2, $substitute;
581 @substitutes = @substitutes2;
590 edit_file($file, $editor);
592 output->write("$module: doesn't have any spec file\n");
595 if($#substitutes >= 0) {
596 foreach my $substitute (@substitutes) {
597 my $search = $substitute->{search};
598 my $replace = $substitute->{replace};
600 output->write("$file: unmatched search : '$search'\n");
601 output->write("$file: unmatched replace: '$replace'\n");
608 output->hide_progress;