3 # Copyright 2001 Patrik Stridvall
8 $0 =~ m%^(.*?/?tools)/winapi/winapi_extract$%;
9 require "$1/winapi/setup.pm";
13 &file_type &files_skip &files_filter &get_spec_files
14 $current_dir $wine_dir $winapi_dir $winapi_check_dir
16 use output qw($output);
17 use winapi_extract_options qw($options);
23 use winapi qw(@winapis);
27 if($options->spec_files) {
30 foreach my $spec_file (get_spec_files("winelib")) {
34 open(IN, "< $wine_dir/$spec_file");
36 s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begining and end of line
37 s/^(.*?)\s*#.*$/$1/; # remove comments
38 /^$/ && next; # skip empty lines
40 if(/^name\s+(.*?)$/) {
42 $module2spec_file{$module} = $spec_file;
43 } elsif(/^type\s+(.*?)$/) {
45 $module2type{$module} = $type;
54 sub documentation_specifications {
57 my @debug_channels = @{$function->debug_channels};
58 my $documentation = $function->documentation;
59 my $documentation_line = $function->documentation_line;
60 my $return_type = $function->return_type;
61 my $linkage = $function->linkage;
62 my $internal_name = $function->internal_name;
64 if($linkage eq "static") {
69 foreach (split(/\n/, $documentation)) {
70 if(/^\s*\*\s*(\S+)\s*[\(\[]\s*(\w+)\s*\.\s*(\S+)\s*[\)\]]/) {
71 my $external_name = $1;
76 if(1 || !exists($specifications{$module}{unfixed}{$external_name})) {
77 $specifications{$module}{unfixed}{$external_name}{ordinal} = $ordinal;
78 $specifications{$module}{unfixed}{$external_name}{external_name} = $external_name;
79 $specifications{$module}{unfixed}{$external_name}{function} = $function;
81 $output->write("$external_name ($module.$ordinal) already exists\n");
83 } elsif($ordinal =~ /^\d+$/) {
84 if(1 || !exists($specifications{$module}{fixed}{$ordinal})) {
85 $specifications{$module}{fixed}{$ordinal}{ordinal} = $ordinal;
86 $specifications{$module}{fixed}{$ordinal}{external_name} = $external_name;
87 $specifications{$module}{fixed}{$ordinal}{function} = $function;
89 $output->write("$external_name ($module.$ordinal) already exists\n");
91 } elsif($ordinal eq "init") {
92 if(!exists($specifications{$module}{init})) {
93 $specifications{$module}{init}{function} = $function;
95 $output->write("$external_name ($module.$ordinal) already exists\n");
98 if(!exists($specifications{$module}{unknown}{$external_name})) {
99 $specifications{$module}{unknown}{$external_name}{ordinal} = $ordinal;
100 $specifications{$module}{unknown}{$external_name}{external_name} = $external_name;
101 $specifications{$module}{unknown}{$external_name}{function} = $function;
103 $output->write("$external_name ($module.$ordinal) already exists\n");
107 if($options->debug) {
108 $output->write("$external_name ($module.$ordinal)\n");
114 my %module_pseudo_stub_count16;
115 my %module_pseudo_stub_count32;
117 sub statements_stub {
118 my $function = shift;
120 my $statements = $function->statements;
121 if(defined($statements) && $statements =~ /FIXME[^;]*stub/s) {
122 if($options->win16) {
123 foreach my $module16 ($function->modules16) {
124 $module_pseudo_stub_count16{$module16}++;
127 if($options->win32) {
128 foreach my $module32 ($function->modules32) {
129 $module_pseudo_stub_count32{$module32}++;
135 my @c_files = $options->c_files;
136 @c_files = files_skip(@c_files);
137 @c_files = files_filter("winelib", @c_files);
140 my $progress_current = 0;
141 my $progress_max = scalar(@c_files);
143 foreach my $file (@c_files) {
147 if($options->progress) {
148 $output->progress("$file: file $progress_current of $progress_max");
151 my $create_function = sub {
152 if($options->stub_statistics) {
153 return 'winapi_function'->new;
155 return 'function'->new;
159 my $found_function = sub {
160 my $function = shift;
162 my $documentation_line = $function->documentation_line;
163 my $documentation = $function->documentation;
164 my $function_line = $function->function_line;
165 my $linkage = $function->linkage;
166 my $return_type = $function->return_type;
167 my $calling_convention = $function->calling_convention;
168 my $internal_name = $function->internal_name;
169 my $statements = $function->statements;
171 $functions{$internal_name} = $function;
173 $output->prefix_callback(sub { return $function->prefix; });
175 if($options->spec_files) {
176 documentation_specifications($function);
179 if($options->stub_statistics) {
180 statements_stub($function);
186 my $create_type = sub {
190 my $found_type = sub {
194 my $found_preprocessor = sub {
195 my $directive = shift;
196 my $argument = shift;
199 &winapi_parser::parse_c_file($file, $create_function, $found_function, $create_type, $found_type, $found_preprocessor);
201 my @internal_names = keys(%functions);
202 if($#internal_names < 0) {
203 $output->write("$file: doesn't contain any functions\n");
207 sub output_function {
211 my $external_name = shift;
212 my $function = shift;
214 my $internal_name = $function->internal_name;
217 my $calling_convention;
218 my $refargument_kinds;
219 if($type eq "win16") {
220 $return_kind = $function->return_kind16 || "undef";
221 $calling_convention = $function->calling_convention16 || "undef";
222 $refargument_kinds = $function->argument_kinds16;
223 } elsif($type eq "win32") {
224 $return_kind = $function->return_kind32 || "undef";
225 $calling_convention = $function->calling_convention32 || "undef";
226 $refargument_kinds = $function->argument_kinds32;
229 if(defined($refargument_kinds)) {
230 my @argument_kinds = map { $_ || "undef"; } @$refargument_kinds;
231 print OUT "$ordinal $calling_convention $external_name(@argument_kinds) $internal_name\n";
233 print OUT "$ordinal $calling_convention $external_name() $internal_name # FIXME: arguments undefined\n";
237 if($options->spec_files) {
238 foreach my $module (keys(%specifications)) {
239 my $spec_file = $module2spec_file{$module};
240 my $type = $module2type{$module};
242 if(!defined($spec_file) || !defined($type)) {
243 $output->write("$module: doesn't exist\n");
249 $output->progress("$spec_file");
250 open(OUT, "> $wine_dir/$spec_file");
252 print OUT "name $module\n";
253 print OUT "type $type\n";
254 if(exists($specifications{$module}{init})) {
255 my $function = $specifications{$module}{init}{function};
256 print OUT "init " . $function->internal_name . "\n";
261 if(exists($specifications{$module}{init})) {
262 my $function = $specifications{$module}{init}{function};
263 foreach my $debug_channel (@{$function->debug_channels}) {
264 $debug_channels{$debug_channel}++;
267 foreach my $ordinal (sort {$a <=> $b} keys(%{$specifications{$module}{fixed}})) {
268 my $function = $specifications{$module}{fixed}{$ordinal}{function};
269 foreach my $debug_channel (@{$function->debug_channels}) {
270 $debug_channels{$debug_channel}++;
273 foreach my $name (sort(keys(%{$specifications{$module}{unfixed}}))) {
274 my $function = $specifications{$module}{unfixed}{$name}{function};
275 foreach my $debug_channel (@{$function->debug_channels}) {
276 $debug_channels{$debug_channel}++;
279 foreach my $name (sort(keys(%{$specifications{$module}{unknown}}))) {
280 my $function = $specifications{$module}{unknown}{$name}{function};
281 foreach my $debug_channel (@{$function->debug_channels}) {
282 $debug_channels{$debug_channel}++;
286 my @debug_channels = sort(keys(%debug_channels));
287 if($#debug_channels >= 0) {
288 print OUT "debug_channels (" . join(" ", @debug_channels) . ")\n";
298 foreach my $external_name (sort(keys(%{$specifications{$module}{unknown}}))) {
299 my $entry = $specifications{$module}{unknown}{$external_name};
300 my $ordinal = $entry->{ordinal};
301 my $function = $entry->{function};
303 output_function(\*OUT, $type, $ordinal, $external_name, $function);
311 foreach my $ordinal (sort {$a <=> $b} keys(%{$specifications{$module}{fixed}})) {
312 my $entry = $specifications{$module}{fixed}{$ordinal};
313 my $external_name = $entry->{external_name};
314 my $function = $entry->{function};
315 output_function(\*OUT, $type, $ordinal, $external_name, $function);
323 foreach my $external_name (sort(keys(%{$specifications{$module}{unfixed}}))) {
324 my $entry = $specifications{$module}{unfixed}{$external_name};
325 my $ordinal = $entry->{ordinal};
326 my $function = $entry->{function};
327 output_function(\*OUT, $type, $ordinal, $external_name, $function);
335 if($options->stub_statistics) {
336 foreach my $winapi (@winapis) {
337 if($winapi->name eq "win16" && !$options->win16) { next; }
338 if($winapi->name eq "win32" && !$options->win32) { next; }
340 my %module_stub_count;
341 my %module_total_count;
343 foreach my $internal_name ($winapi->all_internal_functions,$winapi->all_functions_stub) {
344 foreach my $module (split(/ \& /, $winapi->function_internal_module($internal_name))) {
345 if($winapi->is_function_stub_in_module($module, $internal_name)) {
346 $module_stub_count{$module}++;
348 $module_total_count{$module}++;
352 foreach my $module ($winapi->all_modules) {
354 if($winapi->name eq "win16") {
355 $pseudo_stubs = $module_pseudo_stub_count16{$module};
356 } elsif($winapi->name eq "win32") {
357 $pseudo_stubs = $module_pseudo_stub_count32{$module};
360 my $real_stubs = $module_stub_count{$module};
361 my $total = $module_total_count{$module};
363 if(!defined($real_stubs)) { $real_stubs = 0; }
364 if(!defined($pseudo_stubs)) { $pseudo_stubs = 0; }
365 if(!defined($total)) { $total = 0;}
367 my $stubs = $real_stubs + $pseudo_stubs;
369 $output->write("*.c: $module: ");
370 $output->write("$stubs of $total functions are stubs ($real_stubs real, $pseudo_stubs pseudo)\n");