blob: 023fbf5fa0527b0939965f51f41d88c3b188edbd [file] [log] [blame]
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00001#
2# Copyright 1999, 2000, 2001 Patrik Stridvall
3#
4# This library is free software; you can redistribute it and/or
5# modify it under the terms of the GNU Lesser General Public
6# License as published by the Free Software Foundation; either
7# version 2.1 of the License, or (at your option) any later version.
8#
9# This library is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12# Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public
15# License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020016# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000017#
18
Patrik Stridvall659fcd81999-10-31 02:08:38 +000019package winapi_function;
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +000020use base qw(function);
Patrik Stridvall659fcd81999-10-31 02:08:38 +000021
22use strict;
23
Patrik Stridvallb59a9c72001-07-12 22:22:05 +000024use config qw($current_dir $wine_dir);
Francois Gouget493d60f2004-10-07 18:53:56 +000025use util qw(normalize_set);
Patrik Stridvalla40a4f72002-10-01 18:10:54 +000026
27my $import = 0;
28use vars qw($modules $win16api $win32api @winapis);
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +000029
30########################################################################
31# constructor
32#
33
Francois Gouget493d60f2004-10-07 18:53:56 +000034sub new($) {
Patrik Stridvall659fcd81999-10-31 02:08:38 +000035 my $proto = shift;
36 my $class = ref($proto) || $proto;
37 my $self = {};
38 bless ($self, $class);
39
Patrik Stridvalla40a4f72002-10-01 18:10:54 +000040 if (!$import) {
41 require modules;
42 import modules qw($modules);
43
44 require winapi;
45 import winapi qw($win16api $win32api @winapis);
46
47 $import = 1;
48 }
Patrik Stridvall659fcd81999-10-31 02:08:38 +000049 return $self;
50}
51
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +000052########################################################################
Patrik Stridvalld07a6462001-07-18 20:09:12 +000053# is_win
54#
55
Francois Gouget493d60f2004-10-07 18:53:56 +000056sub is_win16($) { my $self = shift; return defined($self->_module($win16api, @_)); }
57sub is_win32($) { my $self = shift; return defined($self->_module($win32api, @_)); }
Patrik Stridvalld07a6462001-07-18 20:09:12 +000058
59########################################################################
Patrik Stridvallb59a9c72001-07-12 22:22:05 +000060# external_name
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +000061#
Patrik Stridvall659fcd81999-10-31 02:08:38 +000062
Francois Gouget493d60f2004-10-07 18:53:56 +000063sub _external_name($$) {
Patrik Stridvall659fcd81999-10-31 02:08:38 +000064 my $self = shift;
Patrik Stridvallb59a9c72001-07-12 22:22:05 +000065 my $winapi = shift;
66
67 my $file = $self->file;
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +000068 my $internal_name = $self->internal_name;
Patrik Stridvall659fcd81999-10-31 02:08:38 +000069
Patrik Stridvallb59a9c72001-07-12 22:22:05 +000070 my $external_name = $winapi->function_external_name($internal_name);
71 my $module = $winapi->function_internal_module($internal_name);
72
73 if(!defined($external_name) && !defined($module)) {
74 return undef;
75 }
76
77 my @external_names = split(/\s*&\s*/, $external_name);
78 my @modules = split(/\s*&\s*/, $module);
Alexandre Julliard7cae5582002-06-01 02:55:48 +000079
Patrik Stridvallb59a9c72001-07-12 22:22:05 +000080 my @external_names2;
81 while(defined(my $external_name = shift @external_names) &&
82 defined(my $module = shift @modules))
83 {
84 if($modules->is_allowed_module_in_file($module, "$current_dir/$file")) {
85 push @external_names2, $external_name;
86 }
87 }
88
89 return join(" & ", @external_names2);
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +000090}
Patrik Stridvall659fcd81999-10-31 02:08:38 +000091
Francois Gouget493d60f2004-10-07 18:53:56 +000092sub _external_names($$) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +000093 my $self = shift;
Patrik Stridvallb59a9c72001-07-12 22:22:05 +000094 my $winapi = shift;
95
96 my $external_name = $self->_external_name($winapi);
Alexandre Julliard7cae5582002-06-01 02:55:48 +000097
Patrik Stridvallb59a9c72001-07-12 22:22:05 +000098 if(defined($external_name)) {
99 return split(/\s*&\s*/, $external_name);
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000100 } else {
101 return ();
102 }
Patrik Stridvall0d974812000-05-23 23:37:51 +0000103}
104
Francois Gouget493d60f2004-10-07 18:53:56 +0000105sub external_name($) {
Patrik Stridvall1c61b3b2001-07-23 23:20:56 +0000106 my $self = shift;
107
108 foreach my $winapi (@winapis) {
109 my $external_name = $self->_external_name($winapi, @_);
110
111 if(defined($external_name)) {
112 return $external_name;
113 }
114 }
115
116 return undef;
117}
118
Francois Gouget493d60f2004-10-07 18:53:56 +0000119sub external_name16($) { my $self = shift; return $self->_external_name($win16api, @_); }
120sub external_name32($) { my $self = shift; return $self->_external_name($win32api, @_); }
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000121
Francois Gouget493d60f2004-10-07 18:53:56 +0000122sub external_names16($) { my $self = shift; return $self->_external_names($win16api, @_); }
123sub external_names32($) { my $self = shift; return $self->_external_names($win32api, @_); }
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000124
Francois Gouget493d60f2004-10-07 18:53:56 +0000125sub external_names($) { my $self = shift; return ($self->external_names16, $self->external_names32); }
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000126
127########################################################################
128# module
129#
130
Francois Gouget493d60f2004-10-07 18:53:56 +0000131sub _module($$) {
Patrik Stridvall0d974812000-05-23 23:37:51 +0000132 my $self = shift;
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000133 my $winapi = shift;
134
135 my $file = $self->file;
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000136 my $internal_name = $self->internal_name;
Patrik Stridvall0d974812000-05-23 23:37:51 +0000137
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000138 my $module = $winapi->function_internal_module($internal_name);
139 if(!defined($module)) {
140 return undef;
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000141 }
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000142
Patrik Stridvall14fa6592002-11-11 19:55:11 +0000143 if(!defined($file)) {
144 return undef;
145 }
146
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000147 my @modules;
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000148 foreach my $module (split(/\s*&\s*/, $module)) {
149 if($modules->is_allowed_module_in_file($module, "$current_dir/$file")) {
150 push @modules, $module;
151 }
152 }
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000153
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000154 return join(" & ", @modules);
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000155}
156
Francois Gouget493d60f2004-10-07 18:53:56 +0000157sub _modules($$) {
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000158 my $self = shift;
159 my $winapi = shift;
160
161 my $module = $self->_module($winapi);
Alexandre Julliard7cae5582002-06-01 02:55:48 +0000162
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000163 if(defined($module)) {
164 return split(/\s*&\s*/, $module);
165 } else {
166 return ();
167 }
168}
169
Francois Gouget493d60f2004-10-07 18:53:56 +0000170sub module16($) { my $self = shift; return $self->_module($win16api, @_); }
171sub module32($) { my $self = shift; return $self->_module($win32api, @_); }
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000172
Francois Gouget493d60f2004-10-07 18:53:56 +0000173sub module($) { my $self = shift; return join (" & ", $self->modules); }
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000174
Francois Gouget493d60f2004-10-07 18:53:56 +0000175sub modules16($) { my $self = shift; return $self->_modules($win16api, @_); }
176sub modules32($) { my $self = shift; return $self->_modules($win32api, @_); }
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000177
Francois Gouget493d60f2004-10-07 18:53:56 +0000178sub modules($) { my $self = shift; return ($self->modules16, $self->modules32); }
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000179
180########################################################################
181# ordinal
182#
183
Francois Gouget493d60f2004-10-07 18:53:56 +0000184sub _ordinal($$) {
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000185 my $self = shift;
186 my $winapi = shift;
187
188 my $file = $self->file;
189 my $internal_name = $self->internal_name;
190
191 my $ordinal = $winapi->function_internal_ordinal($internal_name);
192 my $module = $winapi->function_internal_module($internal_name);
193
194 if(!defined($ordinal) && !defined($module)) {
195 return undef;
196 }
197
198 my @ordinals = split(/\s*&\s*/, $ordinal);
199 my @modules = split(/\s*&\s*/, $module);
Alexandre Julliard7cae5582002-06-01 02:55:48 +0000200
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000201 my @ordinals2;
202 while(defined(my $ordinal = shift @ordinals) &&
203 defined(my $module = shift @modules))
204 {
205 if($modules->is_allowed_module_in_file($module, "$current_dir/$file")) {
206 push @ordinals2, $ordinal;
207 }
208 }
209
210 return join(" & ", @ordinals2);
211}
212
Francois Gouget493d60f2004-10-07 18:53:56 +0000213sub _ordinals($$) {
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000214 my $self = shift;
215 my $winapi = shift;
216
217 my $ordinal = $self->_ordinal($winapi);
Alexandre Julliard7cae5582002-06-01 02:55:48 +0000218
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000219 if(defined($ordinal)) {
220 return split(/\s*&\s*/, $ordinal);
221 } else {
222 return ();
223 }
224}
225
Francois Gouget493d60f2004-10-07 18:53:56 +0000226sub ordinal16($) { my $self = shift; return $self->_ordinal($win16api, @_); }
227sub ordinal32($) { my $self = shift; return $self->_ordinal($win32api, @_); }
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000228
Francois Gouget493d60f2004-10-07 18:53:56 +0000229sub ordinal($) { my $self = shift; return join (" & ", $self->ordinals); }
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000230
Francois Gouget493d60f2004-10-07 18:53:56 +0000231sub ordinals16($) { my $self = shift; return $self->_ordinals($win16api, @_); }
232sub ordinals32($) { my $self = shift; return $self->_ordinals($win32api, @_); }
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000233
Francois Gouget493d60f2004-10-07 18:53:56 +0000234sub ordinals($) { my $self = shift; return ($self->ordinals16, $self->ordinals32); }
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000235
236########################################################################
237# prefix
238#
239
Francois Gouget493d60f2004-10-07 18:53:56 +0000240sub prefix($) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000241 my $self = shift;
242 my $module16 = $self->module16;
243 my $module32 = $self->module32;
244
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000245 my $file = $self->file;
Patrik Stridvalld07a6462001-07-18 20:09:12 +0000246 my $function_line = $self->function_line;
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000247 my $return_type = $self->return_type;
248 my $internal_name = $self->internal_name;
249 my $calling_convention = $self->calling_convention;
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000250
Patrik Stridvall1c61b3b2001-07-23 23:20:56 +0000251 my $refargument_types = $self->argument_types;
252 my @argument_types = ();
253 if(defined($refargument_types)) {
254 @argument_types = @$refargument_types;
255 if($#argument_types < 0) {
256 @argument_types = ("void");
257 }
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000258 }
259
260 my $prefix = "";
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000261
262 my @modules = ();
263 my %used;
264 foreach my $module ($self->modules) {
265 if($used{$module}) { next; }
266 push @modules, $module;
267 $used{$module}++;
268 }
Patrik Stridvalld07a6462001-07-18 20:09:12 +0000269 $prefix .= "$file:";
270 if(defined($function_line)) {
271 $prefix .= "$function_line: ";
272 } else {
273 $prefix .= "<>: ";
274 }
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000275 if($#modules >= 0) {
276 $prefix .= join(" & ", @modules) . ": ";
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000277 } else {
278 $prefix .= "<>: ";
279 }
280 $prefix .= "$return_type ";
281 $prefix .= "$calling_convention " if $calling_convention;
282 $prefix .= "$internal_name(" . join(",", @argument_types) . "): ";
283
284 return $prefix;
285}
286
Patrik Stridvallb59a9c72001-07-12 22:22:05 +0000287########################################################################
288# calling_convention
289#
290
Francois Gouget493d60f2004-10-07 18:53:56 +0000291sub calling_convention16($) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000292 my $self = shift;
293 my $return_kind16 = $self->return_kind16;
294
295 my $suffix;
296 if(!defined($return_kind16)) {
297 $suffix = undef;
298 } elsif($return_kind16 =~ /^(?:void|s_word|word)$/) {
299 $suffix = "16";
300 } elsif($return_kind16 =~ /^(?:long|ptr|segptr|segstr|str|wstr)$/) {
301 $suffix = "";
302 } else {
303 $suffix = undef;
304 }
305
306 local $_ = $self->calling_convention;
Francois Gougetb4df2412004-10-22 19:55:42 +0000307 if($_ eq "__cdecl") {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000308 return "cdecl";
Francois Gougetb4df2412004-10-22 19:55:42 +0000309 } elsif(/^(?:VFWAPIV|WINAPIV)$/) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000310 if(!defined($suffix)) { return undef; }
311 return "pascal$suffix"; # FIXME: Is this correct?
Vincent Béron74ce0d32005-11-30 12:03:03 +0100312 } elsif(/^(?:__stdcall|__RPC_STUB|__RPC_USER|NET_API_FUNCTION|RPC_ENTRY|VFWAPI|WINAPI|CALLBACK)$/) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000313 if(!defined($suffix)) { return undef; }
314 return "pascal$suffix";
Francois Gougetb4df2412004-10-22 19:55:42 +0000315 } elsif($_ eq "__asm") {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000316 return "asm";
317 } else {
318 return "cdecl";
319 }
320}
321
Francois Gouget493d60f2004-10-07 18:53:56 +0000322sub calling_convention32($) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000323 my $self = shift;
324
325 local $_ = $self->calling_convention;
Francois Gougetb4df2412004-10-22 19:55:42 +0000326 if($_ eq "__cdecl") {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000327 return "cdecl";
Francois Gougetb4df2412004-10-22 19:55:42 +0000328 } elsif(/^(?:VFWAPIV|WINAPIV)$/) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000329 return "varargs";
Vincent Béron74ce0d32005-11-30 12:03:03 +0100330 } elsif(/^(?:__stdcall|__RPC_STUB|__RPC_USER|NET_API_FUNCTION|RPC_ENTRY|VFWAPI|WINAPI|CALLBACK)$/) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000331 return "stdcall";
Francois Gougetb4df2412004-10-22 19:55:42 +0000332 } elsif($_ eq "__asm") {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000333 return "asm";
334 } else {
335 return "cdecl";
336 }
337}
338
Francois Gouget493d60f2004-10-07 18:53:56 +0000339sub get_all_module_ordinal16($) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000340 my $self = shift;
341 my $internal_name = $self->internal_name;
342
343 return winapi::get_all_module_internal_ordinal16($internal_name);
344}
345
Francois Gouget493d60f2004-10-07 18:53:56 +0000346sub get_all_module_ordinal32($) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000347 my $self = shift;
348 my $internal_name = $self->internal_name;
349
350 return winapi::get_all_module_internal_ordinal32($internal_name);
351}
352
Francois Gouget493d60f2004-10-07 18:53:56 +0000353sub get_all_module_ordinal($) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000354 my $self = shift;
355 my $internal_name = $self->internal_name;
356
357 return winapi::get_all_module_internal_ordinal($internal_name);
358}
359
Francois Gouget493d60f2004-10-07 18:53:56 +0000360sub _return_kind($$) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000361 my $self = shift;
362 my $winapi = shift;
363 my $return_type = $self->return_type;
364
365 return $winapi->translate_argument($return_type);
366}
367
Francois Gouget493d60f2004-10-07 18:53:56 +0000368sub return_kind16($) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000369 my $self = shift; return $self->_return_kind($win16api, @_);
370}
371
Francois Gouget493d60f2004-10-07 18:53:56 +0000372sub return_kind32($) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000373 my $self = shift; return $self->_return_kind($win32api, @_);
374}
375
Francois Gouget493d60f2004-10-07 18:53:56 +0000376sub _argument_kinds($$) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000377 my $self = shift;
378 my $winapi = shift;
Patrik Stridvall1c61b3b2001-07-23 23:20:56 +0000379 my $refargument_types = $self->argument_types;
380
381 if(!defined($refargument_types)) {
382 return undef;
383 }
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000384
385 my @argument_kinds;
Patrik Stridvall1c61b3b2001-07-23 23:20:56 +0000386 foreach my $argument_type (@$refargument_types) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000387 my $argument_kind = $winapi->translate_argument($argument_type);
388
389 if(defined($argument_kind) && $argument_kind eq "longlong") {
Francois Gouget97148022005-09-26 09:52:09 +0000390 push @argument_kinds, "double";
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000391 } else {
392 push @argument_kinds, $argument_kind;
393 }
394 }
395
396 return [@argument_kinds];
397}
398
Francois Gouget493d60f2004-10-07 18:53:56 +0000399sub argument_kinds16($) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000400 my $self = shift; return $self->_argument_kinds($win16api, @_);
401}
402
Francois Gouget493d60f2004-10-07 18:53:56 +0000403sub argument_kinds32($) {
Patrik Stridvallc3e8ac32001-07-11 17:27:45 +0000404 my $self = shift; return $self->_argument_kinds($win32api, @_);
405}
406
407##############################################################################
408# Accounting
409#
410
Francois Gouget493d60f2004-10-07 18:53:56 +0000411sub function_called($$) {
Patrik Stridvall659fcd81999-10-31 02:08:38 +0000412 my $self = shift;
413 my $called_function_names = \%{$self->{CALLED_FUNCTION_NAMES}};
414
415 my $name = shift;
416
417 $$called_function_names{$name}++;
418}
419
Francois Gouget493d60f2004-10-07 18:53:56 +0000420sub function_called_by($$) {
Patrik Stridvall659fcd81999-10-31 02:08:38 +0000421 my $self = shift;
422 my $called_by_function_names = \%{$self->{CALLED_BY_FUNCTION_NAMES}};
423
424 my $name = shift;
425
426 $$called_by_function_names{$name}++;
427}
428
Francois Gouget493d60f2004-10-07 18:53:56 +0000429sub called_function_names($) {
Patrik Stridvall659fcd81999-10-31 02:08:38 +0000430 my $self = shift;
431 my $called_function_names = \%{$self->{CALLED_FUNCTION_NAMES}};
432
433 return sort(keys(%$called_function_names));
434}
435
Francois Gouget493d60f2004-10-07 18:53:56 +0000436sub called_by_function_names($) {
Patrik Stridvall659fcd81999-10-31 02:08:38 +0000437 my $self = shift;
438 my $called_by_function_names = \%{$self->{CALLED_BY_FUNCTION_NAMES}};
439
440 return sort(keys(%$called_by_function_names));
441}
442
443
4441;