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}};
29 if($$options->progress) {
30 $$output->progress("$path: searching for *.api");
36 } split(/\n/, `find $path -name \\*.api`);
38 foreach my $file (@files) {
41 if($$options->progress) {
42 $$output->lazy_progress("$file");
45 $module =~ s/.*?\/([^\/]*?)\.api$/$1/;
46 $self->parse_api_file($file,$module);
49 if($$name eq "win16") {
51 } elsif($$name eq "win32") {
71 my $options = \${$self->{OPTIONS}};
72 my $output = \${$self->{OUTPUT}};
73 my $allowed_kind = \%{$self->{ALLOWED_KIND}};
74 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
75 my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
76 my $allowed_modules_unlimited = \%{$self->{ALLOWED_MODULES_UNLIMITED}};
77 my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
78 my $type_format = \%{$self->{TYPE_FORMAT}};
88 if($$options->progress) {
89 $$output->progress("$file");
92 open(IN, "< $file") || die "$file: $!\n";
95 s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begin and end of line
96 s/^(.*?)\s*#.*$/$1/; # remove comments
97 /^$/ && next; # skip empty lines
105 $$allowed_kind{$kind} = 1;
108 } elsif(/^--extension/) {
110 } elsif(/^--format=(\".*?\"|\S*)/) {
112 $format =~ s/^\"(.*?)\"$/$1/;
115 if(!defined($format)) {
116 if($kind eq "long") {
117 $format = "%d|%u|%x|%X|";
118 $format .= "%hd|%hu|%hx|%hX|";
119 $format .= "%ld|%lu|%lx|%lX|";
120 $format .= "%04x|%04X|0x%04x|0x%04X|";
121 $format .= "%08x|%08X|0x%08x|0x%08X|";
122 $format .= "%08lx|%08lX|0x%08lx|0x%08lX";
123 } elsif($kind eq "longlong") {
125 } elsif($kind eq "ptr") {
127 } elsif($kind eq "segptr") {
129 } elsif($kind eq "str") {
131 } elsif($kind eq "wstr") {
133 } elsif($kind eq "word") {
134 $format = "%d|%u|%x|%X|";
135 $format .= "%hd|%hu|%hx|%hX|";
136 $format .= "%04x|%04X|0x%04x|0x%04X";
138 $format = "<unknown>";
141 } elsif(defined($kind)) {
144 if(defined($module)) {
145 if($$allowed_modules_unlimited{$type}) {
146 $$output->write("$file: type ($type) already specificed as an unlimited type\n");
147 } elsif(!$$allowed_modules{$type}{$module}) {
148 $$allowed_modules{$type}{$module} = 1;
149 $$allowed_modules_limited{$type} = 1;
151 $$output->write("$file: type ($type) already specificed\n");
154 $$allowed_modules_unlimited{$type} = 1;
157 $$allowed_modules_limited{$type} = 1;
159 if(defined($$translate_argument{$type}) && $$translate_argument{$type} ne $kind) {
160 $$output->write("$file: type ($type) respecified as different kind ($kind != $$translate_argument{$type})\n");
162 $$translate_argument{$type} = $kind;
165 $$type_format{$module}{$type} = $format;
167 $$output->write("$file: file must begin with %<type> statement\n");
174 sub get_spec_file_type {
176 my $class = ref($proto) || $proto;
183 open(IN, "< $file") || die "$file: $!\n";
190 if(/^name\s*(\S*)/) { $module = $1; }
191 if(/^type\s*(\w+)/) { $type = $1; }
193 if(defined($module) && defined($type)) { last; }
197 return ($type, $module);
200 sub read_spec_files {
202 my $class = ref($proto) || $proto;
205 my $wine_dir = shift;
206 my $current_dir = shift;
208 my $win16api = shift;
209 my $win32api = shift;
211 foreach my $file (@$files) {
212 (my $type, my $module) = 'winapi'->get_spec_file_type("$wine_dir/$file");
213 $modules->spec_file_module($file, $module);
214 if($type eq "win16") {
215 $win16api->parse_spec_file("$wine_dir/$file");
216 } elsif($type eq "win32") {
217 $win32api->parse_spec_file("$wine_dir/$file");
221 foreach my $self ($win16api, $win32api) {
222 my $function_forward = \%{$self->{FUNCTION_FORWARD}};
223 my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}};
224 my $function_module = \%{$self->{FUNCTION_MODULE}};
226 foreach my $forward_name (sort(keys(%$function_forward))) {
227 $$function_forward{$forward_name} =~ /^(\S*):(\S*)\.(\S*)$/;
228 (my $from_module, my $to_module, my $external_name) = ($1, $2, $3);
229 my $internal_name = $$function_internal_name{$external_name};
230 if(defined($internal_name)) {
231 $$function_module{$internal_name} .= " & $from_module";
236 for my $internal_name ($win32api->all_internal_functions) {
237 my $module16 = $win16api->function_internal_module($internal_name);
238 my $module32 = $win16api->function_internal_module($internal_name);
239 if(defined($module16) &&
240 !$win16api->is_function_stub_in_module($module16, $internal_name) &&
241 !$win32api->is_function_stub_in_module($module32, $internal_name))
243 $win16api->found_shared_internal_function($internal_name);
244 $win32api->found_shared_internal_function($internal_name);
249 sub read_all_spec_files {
251 my $class = ref($proto) || $proto;
254 my $wine_dir = shift;
255 my $current_dir = shift;
256 my $file_type = shift;
257 my $win16api = shift;
258 my $win32api = shift;
262 if(&$file_type($_) eq "winelib") {
267 } split(/\n/, `find $wine_dir -name \\*.spec`);
269 'winapi'->read_spec_files($modules, $wine_dir, $current_dir, \@files, $win16api, $win32api);
272 sub parse_spec_file {
275 my $options = \${$self->{OPTIONS}};
276 my $output = \${$self->{OUTPUT}};
277 my $function_internal_arguments = \%{$self->{FUNCTION_INTERNAL_ARGUMENTS}};
278 my $function_external_arguments = \%{$self->{FUNCTION_EXTERNAL_ARGUMENTS}};
279 my $function_internal_ordinal = \%{$self->{FUNCTION_INTERNAL_ORDINAL}};
280 my $function_external_ordinal = \%{$self->{FUNCTION_EXTERNAL_ORDINAL}};
281 my $function_internal_calling_convention = \%{$self->{FUNCTION_INTERNAL_CALLING_CONVENTION}};
282 my $function_external_calling_convention = \%{$self->{FUNCTION_EXTERNAL_CALLING_CONVENTION}};
283 my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}};
284 my $function_external_name = \%{$self->{FUNCTION_EXTERNAL_NAME}};
285 my $function_stub = \%{$self->{FUNCTION_STUB}};
286 my $function_forward = \%{$self->{FUNCTION_FORWARD}};
287 my $function_internal_module = \%{$self->{FUNCTION_INTERNAL_MODULE}};
288 my $function_external_module = \%{$self->{FUNCTION_EXTERNAL_MODULE}};
289 my $modules = \%{$self->{MODULES}};
290 my $module_files = \%{$self->{MODULE_FILES}};
300 if($$options->progress) {
301 $$output->lazy_progress("$file");
304 open(IN, "< $file") || die "$file: $!\n";
308 while($lookahead || defined($_ = <IN>)) {
315 if(/^name\s*(\S*)/) { $module = $1; }
316 if(/^file\s*(\S*)/) { $module_file = $1; }
317 if(/^type\s*(\w+)/) { $type = $1; }
318 if(/^\d+|@/) { $header = 0; $lookahead = 1; }
324 (pascal|pascal16|stdcall|cdecl|register|interrupt|varargs)
325 (?:\s+(?:-noimport|-norelay|-i386|-ret64))*\s+(\S+)\s*\(\s*(.*?)\s*\)\s*(\S+)$/x)
327 my $calling_convention = $2;
328 my $external_name = $3;
330 my $internal_name = $5;
334 if(!$$function_internal_name{$external_name}) {
335 $$function_internal_name{$external_name} = $internal_name;
337 $$function_internal_name{$external_name} .= " & $internal_name";
339 if(!$$function_external_name{$internal_name}) {
340 $$function_external_name{$internal_name} = $external_name;
342 $$function_external_name{$internal_name} .= " & $external_name";
344 $$function_internal_arguments{$internal_name} = $arguments;
345 $$function_external_arguments{$external_name} = $arguments;
346 if(!$$function_internal_ordinal{$internal_name}) {
347 $$function_internal_ordinal{$internal_name} = $ordinal;
349 $$function_internal_ordinal{$internal_name} .= " & $ordinal";
351 if(!$$function_external_ordinal{$external_name}) {
352 $$function_external_ordinal{$external_name} = $ordinal;
354 $$function_external_ordinal{$external_name} .= " & $ordinal";
356 $$function_internal_calling_convention{$internal_name} = $calling_convention;
357 $$function_external_calling_convention{$external_name} = $calling_convention;
358 if(!$$function_internal_module{$internal_name}) {
359 $$function_internal_module{$internal_name} = "$module";
361 $$function_internal_module{$internal_name} .= " & $module";
363 if(!$$function_external_module{$external_name}) {
364 $$function_external_module{$external_name} = "$module";
366 $$function_external_module{$external_name} .= " & $module";
369 if(0 && $$options->spec_mismatch) {
370 if($external_name eq "@") {
371 if($internal_name !~ /^\U$module\E_$ordinal$/) {
372 $$output->write("$file: $external_name: the internal name ($internal_name) mismatch\n");
375 my $name = $external_name;
381 $name2 =~ s/^(?:_|Rtl|k32|K32)//;
384 $name3 =~ s/^INT_Int[0-9a-f]{2}Handler$/BUILTIN_DefaultIntHandler/;
387 $name4 =~ s/^(VxDCall)\d$/$1/;
389 # FIXME: This special case is becuase of a very ugly kludge that should be fixed IMHO
391 $name5 =~ s/^(.*?16)_(.*?)$/$1_fn$2/;
393 if(uc($internal_name) ne uc($external_name) &&
394 $internal_name !~ /(\Q$name\E|\Q$name1\E|\Q$name2\E|\Q$name3\E|\Q$name4\E|\Q$name5\E)/)
396 $$output->write("$file: $external_name: internal name ($internal_name) mismatch\n");
400 } elsif(/^(\d+|@)\s+stub(?:\s+(?:-noimport|-norelay|-i386|-ret64))?\s+(\S+)$/) {
401 my $external_name = $2;
406 if(0 && $type eq "win16") {
407 if($external_name =~ /\d$/) {
408 $internal_name = $external_name . "_16";
410 $internal_name = $external_name . "16";
413 $internal_name = $external_name;
416 $$function_stub{$module}{$external_name} = 1;
417 if(!$$function_internal_name{$external_name}) {
418 $$function_internal_name{$external_name} = $internal_name;
420 $$function_internal_name{$external_name} .= " & $internal_name";
422 if(!$$function_external_name{$internal_name}) {
423 $$function_external_name{$internal_name} = $external_name;
425 $$function_external_name{$internal_name} .= " & $external_name";
427 if(!$$function_internal_ordinal{$internal_name}) {
428 $$function_internal_ordinal{$internal_name} = $ordinal;
430 $$function_internal_ordinal{$internal_name} .= " & $ordinal";
432 if(!$$function_external_ordinal{$external_name}) {
433 $$function_external_ordinal{$external_name} = $ordinal;
435 $$function_external_ordinal{$external_name} .= " & $ordinal";
437 if(!$$function_internal_module{$internal_name}) {
438 $$function_internal_module{$internal_name} = "$module";
439 } else { # if($$function_internal_module{$internal_name} !~ /$module/) {
440 $$function_internal_module{$internal_name} .= " & $module";
442 if(!$$function_external_module{$external_name}) {
443 $$function_external_module{$external_name} = "$module";
444 } else { # if($$function_external_module{$external_name} !~ /$module/) {
445 $$function_external_module{$external_name} .= " & $module";
447 } elsif(/^(\d+|@)\s+forward(?:\s+(?:-noimport|-norelay|-i386|-ret64))?\s+(\S+)\s+(\S+)\.(\S+)$/) {
450 my $external_name = $2;
451 my $forward_module = lc($3);
452 my $forward_name = $4;
454 $$function_forward{$external_name} = "$module:$forward_module.$forward_name";
455 } elsif(/^(\d+|@)\s+(equate|extern|variable)/) {
458 my $next_line = <IN>;
459 if(!defined($next_line) || $next_line =~ /^\s*\d|@/) {
460 die "$file: $.: syntax error: '$_'\n";
467 if(defined($ordinal)) {
468 if($ordinal ne "@" && $ordinals{$ordinal}) {
469 $$output->write("$file: ordinal redefined: $_\n");
471 $ordinals{$ordinal}++;
476 $$modules{$module}++;
478 $$module_files{$module} = $file;
483 my $name = \${$self->{NAME}};
488 sub is_allowed_kind {
490 my $allowed_kind = \%{$self->{ALLOWED_KIND}};
494 return $$allowed_kind{$kind};
500 sub is_limited_type {
502 my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
506 return $$allowed_modules_limited{$type};
509 sub allowed_type_in_module {
511 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
512 my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
515 my @modules = split(/ \& /, shift);
517 if(!$$allowed_modules_limited{$type}) { return 1; }
519 foreach my $module (@modules) {
520 if($$allowed_modules{$type}{$module}) { return 1; }
526 sub type_used_in_module {
528 my $used_modules = \%{$self->{USED_MODULES}};
531 my @modules = split(/ \& /, shift);
533 foreach my $module (@modules) {
534 $$used_modules{$type}{$module} = 1;
542 my $used_modules = \%{$self->{USED_MODULES}};
543 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
546 foreach my $type (sort(keys(%$allowed_modules))) {
547 foreach my $module (sort(keys(%{$$allowed_modules{$type}}))) {
548 if(!$$used_modules{$type}{$module}) {
549 $$not_used{$module}{$type} = 1;
556 sub types_unlimited_used_in_modules {
559 my $output = \${$self->{OUTPUT}};
560 my $used_modules = \%{$self->{USED_MODULES}};
561 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
562 my $allowed_modules_unlimited = \%{$self->{ALLOWED_MODULES_UNLIMITED}};
565 foreach my $type (sort(keys(%$allowed_modules_unlimited))) {
568 foreach my $module (sort(keys(%{$$used_modules{$type}}))) {
570 push @modules, $module;
573 foreach my $module (@modules) {
574 $$used_types{$type}{$module} = 1;
581 sub translate_argument {
583 my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
585 my $argument = shift;
587 return $$translate_argument{$argument};
590 sub all_declared_types {
592 my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
594 return sort(keys(%$translate_argument));
597 sub is_allowed_type_format {
599 my $type_format = \%{$self->{TYPE_FORMAT}};
607 if(defined($module) && defined($type)) {
609 foreach (split(/ & /, $module)) {
610 if(defined($formats)) {
615 if(defined($$type_format{$_}{$type})) {
616 $formats .= $$type_format{$_}{$type};
621 if(defined($formats)) {
623 foreach (split(/\|/, $formats)) {
635 my $modules = \%{$self->{MODULES}};
637 return sort(keys(%$modules));
642 my $modules = \%{$self->{MODULES}};
646 return $$modules{$name};
654 my $module_files = \%{$self->{MODULE_FILES}};
656 return $$module_files{$module};
659 sub all_internal_functions {
661 my $function_internal_calling_convention = \%{$self->{FUNCTION_INTERNAL_CALLING_CONVENTION}};
663 return sort(keys(%$function_internal_calling_convention));
666 sub all_internal_functions_in_module {
668 my $function_internal_calling_convention = \%{$self->{FUNCTION_INTERNAL_CALLING_CONVENTION}};
669 my $function_internal_module = \%{$self->{FUNCTION_INTERNAL_MODULE}};
674 foreach my $name (keys(%$function_internal_calling_convention)) {
675 if($$function_internal_module{$name} eq $module) {
683 sub all_external_functions {
685 my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}};
687 return sort(keys(%$function_internal_name));
690 sub all_external_functions_in_module {
692 my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}};
693 my $function_external_module = \%{$self->{FUNCTION_EXTERNAL_MODULE}};
698 foreach my $name (keys(%$function_internal_name)) {
699 if($$function_external_module{$name} eq $module) {
707 sub all_functions_stub {
709 my $function_stub = \%{$self->{FUNCTION_STUB}};
710 my $modules = \%{$self->{MODULES}};
713 foreach my $module (keys(%$modules)) {
714 push @stubs, keys(%{$$function_stub{$module}});
719 sub all_functions_stub_in_module {
721 my $function_stub = \%{$self->{FUNCTION_STUB}};
725 return sort(keys(%{$$function_stub{$module}}));
728 sub function_internal_ordinal {
730 my $function_internal_ordinal = \%{$self->{FUNCTION_INTERNAL_ORDINAL}};
734 return $$function_internal_ordinal{$name};
737 sub function_external_ordinal {
739 my $function_external_ordinal = \%{$self->{FUNCTION_EXTERNAL_ORDINAL}};
743 return $$function_external_ordinal{$name};
746 sub function_internal_calling_convention {
748 my $function_internal_calling_convention = \%{$self->{FUNCTION_INTERNAL_CALLING_CONVENTION}};
752 return $$function_internal_calling_convention{$name};
755 sub function_external_calling_convention {
757 my $function_external_calling_convention = \%{$self->{FUNCTION_EXTERNAL_CALLING_CONVENTION}};
761 return $$function_external_calling_convention{$name};
764 sub function_internal_name {
766 my $function_internal_name = \%{$self->{FUNCTION_INTERNAL_NAME}};
770 return $$function_internal_name{$name};
773 sub function_external_name {
775 my $function_external_name = \%{$self->{FUNCTION_EXTERNAL_NAME}};
779 return $$function_external_name{$name};
784 my $function_internal_calling_convention = \%{$self->{FUNCTION_INTERNAL_CALLING_CONVENTION}};
788 return $$function_internal_calling_convention{$name};
791 sub all_shared_internal_functions {
793 my $function_shared = \%{$self->{FUNCTION_SHARED}};
795 return sort(keys(%$function_shared));
798 sub is_shared_internal_function {
800 my $function_shared = \%{$self->{FUNCTION_SHARED}};
804 return $$function_shared{$name};
807 sub found_shared_internal_function {
809 my $function_shared = \%{$self->{FUNCTION_SHARED}};
813 $$function_shared{$name} = 1;
816 sub function_internal_arguments {
818 my $function_internal_arguments = \%{$self->{FUNCTION_INTERNAL_ARGUMENTS}};
822 return $$function_internal_arguments{$name};
825 sub function_external_arguments {
827 my $function_external_arguments = \%{$self->{FUNCTION_EXTERNAL_ARGUMENTS}};
831 return $$function_external_arguments{$name};
834 sub function_internal_module {
836 my $function_internal_module = \%{$self->{FUNCTION_INTERNAL_MODULE}};
840 return $$function_internal_module{$name};
843 sub function_external_module {
845 my $function_external_module = \%{$self->{FUNCTION_EXTERNAL_MODULE}};
849 return $$function_external_module{$name};
852 sub is_function_stub {
854 my $function_stub = \%{$self->{FUNCTION_STUB}};
855 my $modules = \%{$self->{MODULES}};
860 foreach my $module (keys(%$modules)) {
861 if($$function_stub{$module}{$name}) {
869 sub is_function_stub_in_module {
871 my $function_stub = \%{$self->{FUNCTION_STUB}};
876 return $$function_stub{$module}{$name};
879 ########################################################################
883 sub _get_all_module_internal_ordinal {
885 my $internal_name = shift;
890 my $name = $winapi->function_external_name($internal_name);
892 @name = split(/ & /, $name);
897 my $module = $winapi->function_internal_module($internal_name);
898 if(defined($module)) {
899 @module = split(/ & /, $module);
904 my $ordinal = $winapi->function_internal_ordinal($internal_name);
905 if(defined($ordinal)) {
906 @ordinal = split(/ & /, $ordinal);
913 while(defined($name = shift @name) &&
914 defined($module = shift @module) &&
915 defined($ordinal = shift @ordinal))
917 push @entries, [$name, $module, $ordinal];
923 sub get_all_module_internal_ordinal16 {
924 return _get_all_module_internal_ordinal($win16api, @_);
927 sub get_all_module_internal_ordinal32 {
928 return _get_all_module_internal_ordinal($win32api, @_);
931 sub get_all_module_internal_ordinal {
933 foreach my $winapi (@winapis) {
934 push @entries, _get_all_module_internal_ordinal($winapi, @_);
940 sub _get_all_module_external_ordinal {
942 my $external_name = shift;
947 my $name = $winapi->function_internal_name($external_name);
949 @name = split(/ & /, $name);
954 my $module = $winapi->function_external_module($external_name);
955 if(defined($module)) {
956 @module = split(/ & /, $module);
961 my $ordinal = $winapi->function_external_ordinal($external_name);
962 if(defined($ordinal)) {
963 @ordinal = split(/ & /, $ordinal);
970 while(defined($name = shift @name) &&
971 defined($module = shift @module) &&
972 defined($ordinal = shift @ordinal))
974 push @entries, [$name, $module, $ordinal];
980 sub get_all_module_external_ordinal16 {
981 return _get_all_module_external_ordinal($win16api, @_);
984 sub get_all_module_external_ordinal32 {
985 return _get_all_module_external_ordinal($win32api, @_);
988 sub get_all_module_external_ordinal {
990 foreach my $winapi (@winapis) {
991 push @entries, _get_all_module_external_ordinal($winapi, @_);