5 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
10 @EXPORT_OK = qw($win16api $win32api @winapis);
12 use vars qw($win16api $win32api @winapis);
16 my $class = ref($proto) || $proto;
18 bless ($self, $class);
20 my $options = \${$self->{OPTIONS}};
21 my $output = \${$self->{OUTPUT}};
22 my $name = \${$self->{NAME}};
32 } split(/\n/, `find $path -name \\*.api`);
34 foreach my $file (@files) {
36 $module =~ s/.*?\/([^\/]*?)\.api$/$1/;
37 $self->parse_api_file($file,$module);
40 if($$name eq "win16") {
42 } elsif($$name eq "win32") {
62 my $options = \${$self->{OPTIONS}};
63 my $output = \${$self->{OUTPUT}};
64 my $allowed_kind = \%{$self->{ALLOWED_KIND}};
65 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
66 my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
67 my $allowed_modules_unlimited = \%{$self->{ALLOWED_MODULES_UNLIMITED}};
68 my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
69 my $type_format = \%{$self->{TYPE_FORMAT}};
79 if($$options->progress) {
80 $$output->progress("$file");
83 open(IN, "< $file") || die "$file: $!\n";
86 s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begin and end of line
87 s/^(.*?)\s*#.*$/$1/; # remove comments
88 /^$/ && next; # skip empty lines
96 $$allowed_kind{$kind} = 1;
99 } elsif(/^--extension/) {
101 } elsif(/^--format=(\".*?\"|\S*)/) {
103 $format =~ s/^\"(.*?)\"$/$1/;
106 if(!defined($format)) {
107 if($kind eq "long") {
108 $format = "%d|%u|%x|%X|";
109 $format .= "%hd|%hu|%hx|%hX|";
110 $format .= "%ld|%lu|%lx|%lX|";
111 $format .= "%04x|%04X|0x%04x|0x%04X|";
112 $format .= "%08x|%08X|0x%08x|0x%08X|";
113 $format .= "%08lx|%08lX|0x%08lx|0x%08lX";
114 } elsif($kind eq "longlong") {
116 } elsif($kind eq "ptr") {
118 } elsif($kind eq "segptr") {
120 } elsif($kind eq "str") {
122 } elsif($kind eq "wstr") {
124 } elsif($kind eq "word") {
125 $format = "%d|%u|%x|%X|";
126 $format .= "%hd|%hu|%hx|%hX|";
127 $format .= "%04x|%04X|0x%04x|0x%04X";
129 $format = "<unknown>";
132 } elsif(defined($kind)) {
135 if(defined($module)) {
136 if($$allowed_modules_unlimited{$type}) {
137 $$output->write("$file: type ($type) already specificed as an unlimited type\n");
138 } elsif(!$$allowed_modules{$type}{$module}) {
139 $$allowed_modules{$type}{$module} = 1;
140 $$allowed_modules_limited{$type} = 1;
142 $$output->write("$file: type ($type) already specificed\n");
145 $$allowed_modules_unlimited{$type} = 1;
148 $$allowed_modules_limited{$type} = 1;
150 if(defined($$translate_argument{$type}) && $$translate_argument{$type} ne $kind) {
151 $$output->write("$file: type ($type) respecified as different kind ($kind != $$translate_argument{$type})\n");
153 $$translate_argument{$type} = $kind;
156 $$type_format{$module}{$type} = $format;
158 $$output->write("$file: file must begin with %<type> statement\n");
165 sub get_spec_file_type {
167 my $class = ref($proto) || $proto;
174 open(IN, "< $file") || die "$file: $!\n";
181 if(/^name\s*(\S*)/) { $module = $1; }
182 if(/^type\s*(\w+)/) { $type = $1; }
184 if(defined($module) && defined($type)) { last; }
188 return ($type, $module);
191 sub read_spec_files {
193 my $class = ref($proto) || $proto;
196 my $wine_dir = shift;
197 my $current_dir = shift;
199 my $win16api = shift;
200 my $win32api = shift;
202 foreach my $file (@$files) {
203 (my $type, my $module) = 'winapi'->get_spec_file_type("$wine_dir/$file");
204 $modules->spec_file_module($file, $module);
205 if($type eq "win16") {
206 $win16api->parse_spec_file("$wine_dir/$file");
207 } elsif($type eq "win32") {
208 $win32api->parse_spec_file("$wine_dir/$file");
212 foreach my $self ($win16api, $win32api) {
213 my $function_forward = \%{$self->{FUNCTION_FORWARD}};
214 my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}};
215 my $function_module = \%{$self->{FUNCTION_MODULE}};
217 foreach my $forward_name (sort(keys(%$function_forward))) {
218 $$function_forward{$forward_name} =~ /^(\S*):(\S*)\.(\S*)$/;
219 (my $from_module, my $to_module, my $external_name) = ($1, $2, $3);
220 my $internal_name = $$function_internal_name{$external_name};
221 if(defined($internal_name)) {
222 $$function_module{$internal_name} .= " & $from_module";
227 for my $internal_name ($win32api->all_internal_functions) {
228 my $module16 = $win16api->function_internal_module($internal_name);
229 my $module32 = $win16api->function_internal_module($internal_name);
230 if(defined($module16) &&
231 !$win16api->is_function_stub_in_module($module16, $internal_name) &&
232 !$win32api->is_function_stub_in_module($module32, $internal_name))
234 $win16api->found_shared_internal_function($internal_name);
235 $win32api->found_shared_internal_function($internal_name);
240 sub read_all_spec_files {
242 my $class = ref($proto) || $proto;
245 my $wine_dir = shift;
246 my $current_dir = shift;
247 my $file_type = shift;
248 my $win16api = shift;
249 my $win32api = shift;
253 if(&$file_type($_) eq "winelib") {
258 } split(/\n/, `find $wine_dir -name \\*.spec`);
260 'winapi'->read_spec_files($modules, $wine_dir, $current_dir, \@files, $win16api, $win32api);
263 sub parse_spec_file {
266 my $options = \${$self->{OPTIONS}};
267 my $output = \${$self->{OUTPUT}};
268 my $function_internal_arguments = \%{$self->{FUNCTION_INTERNAL_ARGUMENTS}};
269 my $function_external_arguments = \%{$self->{FUNCTION_EXTERNAL_ARGUMENTS}};
270 my $function_internal_ordinal = \%{$self->{FUNCTION_INTERNAL_ORDINAL}};
271 my $function_external_ordinal = \%{$self->{FUNCTION_EXTERNAL_ORDINAL}};
272 my $function_internal_calling_convention = \%{$self->{FUNCTION_INTERNAL_CALLING_CONVENTION}};
273 my $function_external_calling_convention = \%{$self->{FUNCTION_EXTERNAL_CALLING_CONVENTION}};
274 my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}};
275 my $function_external_name = \%{$self->{FUNCTION_EXTERNAL_NAME}};
276 my $function_stub = \%{$self->{FUNCTION_STUB}};
277 my $function_forward = \%{$self->{FUNCTION_FORWARD}};
278 my $function_internal_module = \%{$self->{FUNCTION_INTERNAL_MODULE}};
279 my $function_external_module = \%{$self->{FUNCTION_EXTERNAL_MODULE}};
280 my $modules = \%{$self->{MODULES}};
281 my $module_files = \%{$self->{MODULE_FILES}};
291 if($$options->progress) {
292 $$output->progress("$file");
295 open(IN, "< $file") || die "$file: $!\n";
299 while($lookahead || defined($_ = <IN>)) {
306 if(/^name\s*(\S*)/) { $module = $1; }
307 if(/^file\s*(\S*)/) { $module_file = $1; }
308 if(/^type\s*(\w+)/) { $type = $1; }
309 if(/^\d+|@/) { $header = 0; $lookahead = 1; }
315 (pascal|pascal16|stdcall|cdecl|register|interrupt|varargs)
316 (?:\s+(?:-noimport|-norelay|-i386|-ret64))*\s+(\S+)\s*\(\s*(.*?)\s*\)\s*(\S+)$/x)
318 my $calling_convention = $2;
319 my $external_name = $3;
321 my $internal_name = $5;
325 if(!$$function_internal_name{$external_name}) {
326 $$function_internal_name{$external_name} = $internal_name;
328 $$function_internal_name{$external_name} .= " & $internal_name";
330 if(!$$function_external_name{$internal_name}) {
331 $$function_external_name{$internal_name} = $external_name;
333 $$function_external_name{$internal_name} .= " & $external_name";
335 $$function_internal_arguments{$internal_name} = $arguments;
336 $$function_external_arguments{$external_name} = $arguments;
337 if(!$$function_internal_ordinal{$internal_name}) {
338 $$function_internal_ordinal{$internal_name} = $ordinal;
340 $$function_internal_ordinal{$internal_name} .= " & $ordinal";
342 if(!$$function_external_ordinal{$external_name}) {
343 $$function_external_ordinal{$external_name} = $ordinal;
345 $$function_external_ordinal{$external_name} .= " & $ordinal";
347 $$function_internal_calling_convention{$internal_name} = $calling_convention;
348 $$function_external_calling_convention{$external_name} = $calling_convention;
349 if(!$$function_internal_module{$internal_name}) {
350 $$function_internal_module{$internal_name} = "$module";
352 $$function_internal_module{$internal_name} .= " & $module";
354 if(!$$function_external_module{$external_name}) {
355 $$function_external_module{$external_name} = "$module";
357 $$function_external_module{$external_name} .= " & $module";
360 if(0 && $$options->spec_mismatch) {
361 if($external_name eq "@") {
362 if($internal_name !~ /^\U$module\E_$ordinal$/) {
363 $$output->write("$file: $external_name: the internal name ($internal_name) mismatch\n");
366 my $name = $external_name;
372 $name2 =~ s/^(?:_|Rtl|k32|K32)//;
375 $name3 =~ s/^INT_Int[0-9a-f]{2}Handler$/BUILTIN_DefaultIntHandler/;
378 $name4 =~ s/^(VxDCall)\d$/$1/;
380 # FIXME: This special case is becuase of a very ugly kludge that should be fixed IMHO
382 $name5 =~ s/^(.*?16)_(.*?)$/$1_fn$2/;
384 if(uc($internal_name) ne uc($external_name) &&
385 $internal_name !~ /(\Q$name\E|\Q$name1\E|\Q$name2\E|\Q$name3\E|\Q$name4\E|\Q$name5\E)/)
387 $$output->write("$file: $external_name: internal name ($internal_name) mismatch\n");
391 } elsif(/^(\d+|@)\s+stub(?:\s+(?:-noimport|-norelay|-i386|-ret64))?\s+(\S+)$/) {
392 my $external_name = $2;
397 if(0 && $type eq "win16") {
398 if($external_name =~ /\d$/) {
399 $internal_name = $external_name . "_16";
401 $internal_name = $external_name . "16";
404 $internal_name = $external_name;
407 $$function_stub{$module}{$external_name} = 1;
408 if(!$$function_internal_name{$external_name}) {
409 $$function_internal_name{$external_name} = $internal_name;
411 $$function_internal_name{$external_name} .= " & $internal_name";
413 if(!$$function_external_name{$internal_name}) {
414 $$function_external_name{$internal_name} = $external_name;
416 $$function_external_name{$internal_name} .= " & $external_name";
418 if(!$$function_internal_ordinal{$internal_name}) {
419 $$function_internal_ordinal{$internal_name} = $ordinal;
421 $$function_internal_ordinal{$internal_name} .= " & $ordinal";
423 if(!$$function_external_ordinal{$external_name}) {
424 $$function_external_ordinal{$external_name} = $ordinal;
426 $$function_external_ordinal{$external_name} .= " & $ordinal";
428 if(!$$function_internal_module{$internal_name}) {
429 $$function_internal_module{$internal_name} = "$module";
430 } else { # if($$function_internal_module{$internal_name} !~ /$module/) {
431 $$function_internal_module{$internal_name} .= " & $module";
433 if(!$$function_external_module{$external_name}) {
434 $$function_external_module{$external_name} = "$module";
435 } else { # if($$function_external_module{$external_name} !~ /$module/) {
436 $$function_external_module{$external_name} .= " & $module";
438 } elsif(/^(\d+|@)\s+forward(?:\s+(?:-noimport|-norelay|-i386|-ret64))?\s+(\S+)\s+(\S+)\.(\S+)$/) {
441 my $external_name = $2;
442 my $forward_module = lc($3);
443 my $forward_name = $4;
445 $$function_forward{$external_name} = "$module:$forward_module.$forward_name";
446 } elsif(/^(\d+|@)\s+(equate|extern|variable)/) {
449 my $next_line = <IN>;
450 if(!defined($next_line) || $next_line =~ /^\s*\d|@/) {
451 die "$file: $.: syntax error: '$_'\n";
458 if(defined($ordinal)) {
459 if($ordinal ne "@" && $ordinals{$ordinal}) {
460 $$output->write("$file: ordinal redefined: $_\n");
462 $ordinals{$ordinal}++;
467 $$modules{$module}++;
469 $$module_files{$module} = $file;
474 my $name = \${$self->{NAME}};
479 sub is_allowed_kind {
481 my $allowed_kind = \%{$self->{ALLOWED_KIND}};
485 return $$allowed_kind{$kind};
491 sub is_limited_type {
493 my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
497 return $$allowed_modules_limited{$type};
500 sub allowed_type_in_module {
502 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
503 my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
506 my @modules = split(/ \& /, shift);
508 if(!$$allowed_modules_limited{$type}) { return 1; }
510 foreach my $module (@modules) {
511 if($$allowed_modules{$type}{$module}) { return 1; }
517 sub type_used_in_module {
519 my $used_modules = \%{$self->{USED_MODULES}};
522 my @modules = split(/ \& /, shift);
524 foreach my $module (@modules) {
525 $$used_modules{$type}{$module} = 1;
533 my $used_modules = \%{$self->{USED_MODULES}};
534 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
537 foreach my $type (sort(keys(%$allowed_modules))) {
538 foreach my $module (sort(keys(%{$$allowed_modules{$type}}))) {
539 if(!$$used_modules{$type}{$module}) {
540 $$not_used{$module}{$type} = 1;
547 sub types_unlimited_used_in_modules {
550 my $output = \${$self->{OUTPUT}};
551 my $used_modules = \%{$self->{USED_MODULES}};
552 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
553 my $allowed_modules_unlimited = \%{$self->{ALLOWED_MODULES_UNLIMITED}};
556 foreach my $type (sort(keys(%$allowed_modules_unlimited))) {
559 foreach my $module (sort(keys(%{$$used_modules{$type}}))) {
561 push @modules, $module;
564 foreach my $module (@modules) {
565 $$used_types{$type}{$module} = 1;
572 sub translate_argument {
574 my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
576 my $argument = shift;
578 return $$translate_argument{$argument};
581 sub all_declared_types {
583 my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
585 return sort(keys(%$translate_argument));
590 my $type_found = \%{$self->{TYPE_FOUND}};
594 $$type_found{$name}++;
599 my $type_found= \%{$self->{TYPE_FOUND}};
603 return $$type_found{$name};
606 sub is_allowed_type_format {
608 my $type_format = \%{$self->{TYPE_FORMAT}};
616 if(defined($module) && defined($type)) {
618 foreach (split(/ & /, $module)) {
619 if(defined($formats)) {
624 if(defined($$type_format{$_}{$type})) {
625 $formats .= $$type_format{$_}{$type};
630 if(defined($formats)) {
632 foreach (split(/\|/, $formats)) {
644 my $modules = \%{$self->{MODULES}};
646 return sort(keys(%$modules));
651 my $modules = \%{$self->{MODULES}};
655 return $$modules{$name};
663 my $module_files = \%{$self->{MODULE_FILES}};
665 return $$module_files{$module};
668 sub all_internal_functions {
670 my $function_internal_calling_convention = \%{$self->{FUNCTION_INTERNAL_CALLING_CONVENTION}};
672 return sort(keys(%$function_internal_calling_convention));
675 sub all_internal_functions_in_module {
677 my $function_internal_calling_convention = \%{$self->{FUNCTION_INTERNAL_CALLING_CONVENTION}};
678 my $function_internal_module = \%{$self->{FUNCTION_INTERNAL_MODULE}};
683 foreach my $name (keys(%$function_internal_calling_convention)) {
684 if($$function_internal_module{$name} eq $module) {
692 sub all_external_functions {
694 my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}};
696 return sort(keys(%$function_internal_name));
699 sub all_external_functions_in_module {
701 my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}};
702 my $function_external_module = \%{$self->{FUNCTION_EXTERNAL_MODULE}};
707 foreach my $name (keys(%$function_internal_name)) {
708 if($$function_external_module{$name} eq $module) {
716 sub all_functions_stub {
718 my $function_stub = \%{$self->{FUNCTION_STUB}};
719 my $modules = \%{$self->{MODULES}};
722 foreach my $module (keys(%$modules)) {
723 push @stubs, keys(%{$$function_stub{$module}});
728 sub all_functions_stub_in_module {
730 my $function_stub = \%{$self->{FUNCTION_STUB}};
734 return sort(keys(%{$$function_stub{$module}}));
737 sub all_internal_functions_found {
739 my $function_found = \%{$self->{FUNCTION_FOUND}};
741 return sort(keys(%$function_found));
744 sub function_internal_ordinal {
746 my $function_internal_ordinal = \%{$self->{FUNCTION_INTERNAL_ORDINAL}};
750 return $$function_internal_ordinal{$name};
753 sub function_external_ordinal {
755 my $function_external_ordinal = \%{$self->{FUNCTION_EXTERNAL_ORDINAL}};
759 return $$function_external_ordinal{$name};
762 sub function_internal_calling_convention {
764 my $function_internal_calling_convention = \%{$self->{FUNCTION_INTERNAL_CALLING_CONVENTION}};
768 return $$function_internal_calling_convention{$name};
771 sub function_external_calling_convention {
773 my $function_external_calling_convention = \%{$self->{FUNCTION_EXTERNAL_CALLING_CONVENTION}};
777 return $$function_external_calling_convention{$name};
780 sub function_internal_name {
782 my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}};
786 return $$function_internal_name{$name};
789 sub function_external_name {
791 my $function_external_name = \%{$self->{FUNCTION_EXTERNAL_NAME}};
795 return $$function_external_name{$name};
800 my $function_internal_calling_convention = \%{$self->{FUNCTION_INTERNAL_CALLING_CONVENTION}};
804 return $$function_internal_calling_convention{$name};
807 sub all_shared_internal_functions {
809 my $function_shared = \%{$self->{FUNCTION_SHARED}};
811 return sort(keys(%$function_shared));
814 sub is_shared_internal_function {
816 my $function_shared = \%{$self->{FUNCTION_SHARED}};
820 return $$function_shared{$name};
823 sub found_shared_internal_function {
825 my $function_shared = \%{$self->{FUNCTION_SHARED}};
829 $$function_shared{$name} = 1;
832 sub function_internal_arguments {
834 my $function_internal_arguments = \%{$self->{FUNCTION_INTERNAL_ARGUMENTS}};
838 return $$function_internal_arguments{$name};
841 sub function_external_arguments {
843 my $function_external_arguments = \%{$self->{FUNCTION_EXTERNAL_ARGUMENTS}};
847 return $$function_external_arguments{$name};
850 sub function_internal_module {
852 my $function_internal_module = \%{$self->{FUNCTION_INTERNAL_MODULE}};
856 return $$function_internal_module{$name};
859 sub function_external_module {
861 my $function_external_module = \%{$self->{FUNCTION_EXTERNAL_MODULE}};
865 return $$function_external_module{$name};
868 sub is_function_stub {
870 my $function_stub = \%{$self->{FUNCTION_STUB}};
871 my $modules = \%{$self->{MODULES}};
876 foreach my $module (keys(%$modules)) {
877 if($$function_stub{$module}{$name}) {
885 sub is_function_stub_in_module {
887 my $function_stub = \%{$self->{FUNCTION_STUB}};
892 return $$function_stub{$module}{$name};
895 sub found_internal_function {
897 my $function_found = \%{$self->{FUNCTION_FOUND}};
901 $$function_found{$name}++;
904 sub internal_function_found {
906 my $function_found = \%{$self->{FUNCTION_FOUND}};
910 return $$function_found{$name};
913 ########################################################################
917 sub _get_all_module_internal_ordinal {
919 my $internal_name = shift;
924 my $name = $winapi->function_external_name($internal_name);
926 @name = split(/ & /, $name);
931 my $module = $winapi->function_internal_module($internal_name);
932 if(defined($module)) {
933 @module = split(/ & /, $module);
938 my $ordinal = $winapi->function_internal_ordinal($internal_name);
939 if(defined($ordinal)) {
940 @ordinal = split(/ & /, $ordinal);
947 while(defined($name = shift @name) &&
948 defined($module = shift @module) &&
949 defined($ordinal = shift @ordinal))
951 push @entries, [$name, $module, $ordinal];
957 sub get_all_module_internal_ordinal16 {
958 return _get_all_module_internal_ordinal($win16api, @_);
961 sub get_all_module_internal_ordinal32 {
962 return _get_all_module_internal_ordinal($win32api, @_);
965 sub get_all_module_internal_ordinal {
967 foreach my $winapi (@winapis) {
968 push @entries, _get_all_module_internal_ordinal($winapi, @_);
974 sub _get_all_module_external_ordinal {
976 my $external_name = shift;
981 my $name = $winapi->function_internal_name($external_name);
983 @name = split(/ & /, $name);
988 my $module = $winapi->function_external_module($external_name);
989 if(defined($module)) {
990 @module = split(/ & /, $module);
995 my $ordinal = $winapi->function_external_ordinal($external_name);
996 if(defined($ordinal)) {
997 @ordinal = split(/ & /, $ordinal);
1004 while(defined($name = shift @name) &&
1005 defined($module = shift @module) &&
1006 defined($ordinal = shift @ordinal))
1008 push @entries, [$name, $module, $ordinal];
1014 sub get_all_module_external_ordinal16 {
1015 return _get_all_module_external_ordinal($win16api, @_);
1018 sub get_all_module_external_ordinal32 {
1019 return _get_all_module_external_ordinal($win32api, @_);
1022 sub get_all_module_external_ordinal {
1024 foreach my $winapi (@winapis) {
1025 push @entries, _get_all_module_external_ordinal($winapi, @_);