Temporarily implemented the LCMAP_SORTKEY flag in the LCMapStringW()
[wine/multimedia.git] / tools / winapi_check / winapi.pm
blob450ae7b37da8a8e90250ab7b92ddd631ebd39832
1 package winapi;
3 use strict;
5 sub new {
6 my $proto = shift;
7 my $class = ref($proto) || $proto;
8 my $self = {};
9 bless ($self, $class);
11 my $output = \${$self->{OUTPUT}};
12 my $name = \${$self->{NAME}};
14 $$output = shift;
15 $$name = shift;
16 my $path = shift;
18 my @files = map {
19 s/^.\/(.*)$/$1/;
20 $_;
21 } split(/\n/, `find $path -name \\*.api`);
23 foreach my $file (@files) {
24 my $module = $file;
25 $module =~ s/.*?\/([^\/]*?)\.api$/$1/;
26 $self->parse_api_file($file,$module);
29 return $self;
32 sub parse_api_file {
33 my $self = shift;
34 my $output = \${$self->{OUTPUT}};
35 my $allowed_kind = \%{$self->{ALLOWED_KIND}};
36 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
37 my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
38 my $allowed_modules_unlimited = \%{$self->{ALLOWED_MODULES_UNLIMITED}};
39 my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
41 my $file = shift;
42 my $module = shift;
44 my $kind;
45 my $extension = 0;
46 my $forbidden = 0;
48 $$output->progress("$file");
50 open(IN, "< $file") || die "$file: $!\n";
51 $/ = "\n";
52 while(<IN>) {
53 s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begin and end of line
54 s/^(.*?)\s*#.*$/$1/; # remove comments
55 /^$/ && next; # skip empty lines
57 if(s/^%(\S+)\s*//) {
58 $kind = $1;
59 $forbidden = 0;
60 $extension = 0;
62 $$allowed_kind{$kind} = 1;
63 if(/^--forbidden/) {
64 $forbidden = 1;
65 } elsif(/^--extension/) {
66 $extension = 1;
68 } elsif(defined($kind)) {
69 my $type = $_;
70 if(!$forbidden) {
71 if(defined($module)) {
72 if($$allowed_modules_unlimited{$type}) {
73 $$output->write("$file: type ($type) already specificed as an unlimited type\n");
74 } elsif(!$$allowed_modules{$type}{$module}) {
75 $$allowed_modules{$type}{$module} = 1;
76 $$allowed_modules_limited{$type} = 1;
77 } else {
78 $$output->write("$file: type ($type) already specificed\n");
80 } else {
81 $$allowed_modules_unlimited{$type} = 1;
83 } else {
84 $$allowed_modules_limited{$type} = 1;
86 if(defined($$translate_argument{$type}) && $$translate_argument{$type} ne $kind) {
87 $$output->write("$file: type ($type) respecified as different kind ($kind != $$translate_argument{$type})\n");
88 } else {
89 $$translate_argument{$type} = $kind;
91 } else {
92 $$output->write("$file: file must begin with %<type> statement\n");
93 exit 1;
96 close(IN);
99 sub get_spec_file_type {
100 my $proto = shift;
101 my $class = ref($proto) || $proto;
103 my $file = shift;
105 my $type;
107 open(IN, "< $file") || die "$file: $!\n";
108 $/ = "\n";
109 while(<IN>) {
110 if(/^type\s*(\w+)/) {
111 $type = $1;
112 last;
115 close(IN);
117 return $type;
120 sub read_spec_files {
121 my $proto = shift;
122 my $class = ref($proto) || $proto;
124 my $path = shift;
125 my $win16api = shift;
126 my $win32api = shift;
128 my @files = map {
129 s/^.\/(.*)$/$1/;
130 $_;
131 } split(/\n/, `find $path -name \\*.spec`);
133 foreach my $file (@files) {
134 my $type = 'winapi'->get_spec_file_type($file);
135 if($type eq "win16") {
136 $win16api->parse_spec_file($file);
137 } elsif($type eq "win32") {
138 $win32api->parse_spec_file($file);
143 sub parse_spec_file {
144 my $self = shift;
146 my $output = \${$self->{OUTPUT}};
147 my $function_arguments = \%{$self->{FUNCTION_ARGUMENTS}};
148 my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};
149 my $function_stub = \%{$self->{FUNCTION_STUB}};
150 my $function_module = \%{$self->{FUNCTION_MODULE}};
153 my $file = shift;
155 my %ordinals;
156 my $type;
157 my $module;
159 $$output->progress("$file");
161 open(IN, "< $file") || die "$file: $!\n";
162 $/ = "\n";
163 my $header = 1;
164 my $lookahead = 0;
165 while($lookahead || defined($_ = <IN>)) {
166 $lookahead = 0;
167 s/^\s*(.*?)\s*$/$1/;
168 s/^(.*?)\s*#.*$/$1/;
169 /^$/ && next;
171 if($header) {
172 if(/^name\s*(\S*)/) { $module = $1; }
173 if(/^type\s*(\w+)/) { $type = $1; }
174 if(/^\d+|@/) { $header = 0 };
175 next;
178 my $ordinal;
179 if(/^(\d+|@)\s+(pascal|pascal16|stdcall|cdecl|register|interrupt|varargs)\s+(\S+)\s*\(\s*(.*?)\s*\)\s*(\S+)$/) {
180 my $calling_convention = $2;
181 my $external_name = $3;
182 my $arguments = $4;
183 my $internal_name = $5;
185 $ordinal = $1;
187 # FIXME: Internal name existing more than once not handled properly
188 $$function_arguments{$internal_name} = $arguments;
189 $$function_calling_convention{$internal_name} = $calling_convention;
190 if(!$$function_module{$internal_name}) {
191 $$function_module{$internal_name} = "$module";
192 } elsif($$function_module{$internal_name} !~ /$module/) {
193 $$function_module{$internal_name} .= " & $module";
195 } elsif(/^(\d+|@)\s+stub\s+(\S+)$/) {
196 my $external_name = $2;
198 $ordinal = $1;
200 my $internal_name;
201 if($type eq "win16") {
202 $internal_name = $external_name . "16";
203 } else {
204 $internal_name = $external_name;
207 # FIXME: Internal name existing more than once not handled properly
208 $$function_stub{$internal_name} = 1;
209 if(!$$function_module{$internal_name}) {
210 $$function_module{$internal_name} = "$module";
211 } elsif($$function_module{$internal_name} !~ /$module/) {
212 $$function_module{$internal_name} .= " & $module";
214 } elsif(/^(\d+|@)\s+(equate|long|word|extern|forward)/) {
215 # ignore
216 } else {
217 my $next_line = <IN>;
218 if($next_line =~ /^\d|@/) {
219 die "$file: $.: syntax error: '$_'\n";
220 } else {
221 $_ .= $next_line;
222 $lookahead = 1;
226 if(defined($ordinal)) {
227 if($ordinal ne "@" && $ordinals{$ordinal}) {
228 $$output->write("$file: ordinal redefined: $_\n");
230 $ordinals{$ordinal}++;
233 close(IN);
236 sub name {
237 my $self = shift;
238 my $name = \${$self->{NAME}};
240 return $$name;
243 sub is_allowed_kind {
244 my $self = shift;
245 my $allowed_kind = \%{$self->{ALLOWED_KIND}};
247 my $kind = shift;
248 if(defined($kind)) {
249 return $$allowed_kind{$kind};
250 } else {
251 return 0;
255 sub is_limited_type {
256 my $self = shift;
257 my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
259 my $type = shift;
261 return $$allowed_modules_limited{$type};
264 sub allowed_type_in_module {
265 my $self = shift;
266 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
267 my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
269 my $type = shift;
270 my @modules = split(/ \& /, shift);
272 if(!$$allowed_modules_limited{$type}) { return 1; }
274 foreach my $module (@modules) {
275 if($$allowed_modules{$type}{$module}) { return 1; }
278 return 0;
281 sub type_used_in_module {
282 my $self = shift;
283 my $used_modules = \%{$self->{USED_MODULES}};
285 my $type = shift;
286 my @modules = split(/ \& /, shift);
288 foreach my $module (@modules) {
289 $$used_modules{$type}{$module} = 1;
292 return ();
295 sub types_not_used {
296 my $self = shift;
297 my $used_modules = \%{$self->{USED_MODULES}};
298 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
300 my $not_used;
301 foreach my $type (sort(keys(%$allowed_modules))) {
302 foreach my $module (sort(keys(%{$$allowed_modules{$type}}))) {
303 if(!$$used_modules{$type}{$module}) {
304 $$not_used{$module}{$type} = 1;
308 return $not_used;
311 sub types_unlimited_used_in_modules {
312 my $self = shift;
314 my $output = \${$self->{OUTPUT}};
315 my $used_modules = \%{$self->{USED_MODULES}};
316 my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
317 my $allowed_modules_unlimited = \%{$self->{ALLOWED_MODULES_UNLIMITED}};
319 my $used_types;
320 foreach my $type (sort(keys(%$allowed_modules_unlimited))) {
321 my $count = 0;
322 my @modules = ();
323 foreach my $module (sort(keys(%{$$used_modules{$type}}))) {
324 $count++;
325 push @modules, $module;
327 if($count) {
328 foreach my $module (@modules) {
329 $$used_types{$type}{$module} = 1;
333 return $used_types;
336 sub translate_argument {
337 my $self = shift;
338 my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
340 my $argument = shift;
342 return $$translate_argument{$argument};
345 sub all_declared_types {
346 my $self = shift;
347 my $translate_argument = \%{$self->{TRANSLATE_ARGUMENT}};
349 return sort(keys(%$translate_argument));
352 sub found_type {
353 my $self = shift;
354 my $type_found = \%{$self->{TYPE_FOUND}};
356 my $name = shift;
358 $$type_found{$name}++;
361 sub type_found {
362 my $self = shift;
363 my $type_found= \%{$self->{TYPE_FOUND}};
365 my $name = shift;
367 return $$type_found{$name};
370 sub all_functions {
371 my $self = shift;
372 my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};
374 return sort(keys(%$function_calling_convention));
377 sub all_functions_found {
378 my $self = shift;
379 my $function_found = \%{$self->{FUNCTION_FOUND}};
381 return sort(keys(%$function_found));
384 sub function_calling_convention {
385 my $self = shift;
386 my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};
388 my $name = shift;
390 return $$function_calling_convention{$name};
393 sub is_function {
394 my $self = shift;
395 my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};
397 my $name = shift;
399 return $$function_calling_convention{$name};
402 sub is_shared_function {
403 my $self = shift;
404 my $function_shared = \%{$self->{FUNCTION_SHARED}};
406 my $name = shift;
408 return $$function_shared{$name};
411 sub found_shared_function {
412 my $self = shift;
413 my $function_shared = \%{$self->{FUNCTION_SHARED}};
415 my $name = shift;
417 $$function_shared{$name} = 1;
420 sub function_arguments {
421 my $self = shift;
422 my $function_arguments = \%{$self->{FUNCTION_ARGUMENTS}};
424 my $name = shift;
426 return $$function_arguments{$name};
429 sub function_module {
430 my $self = shift;
431 my $function_module = \%{$self->{FUNCTION_MODULE}};
433 my $name = shift;
435 return $$function_module{$name};
438 sub function_stub {
439 my $self = shift;
440 my $function_stub = \%{$self->{FUNCTION_STUB}};
442 my $name = shift;
444 return $$function_stub{$name};
447 sub found_function {
448 my $self = shift;
449 my $function_found = \%{$self->{FUNCTION_FOUND}};
451 my $name = shift;
453 $$function_found{$name}++;
456 sub function_found {
457 my $self = shift;
458 my $function_found = \%{$self->{FUNCTION_FOUND}};
460 my $name = shift;
462 return $$function_found{$name};