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);
19 if($options->progress) {
20 $output->enable_progress;
22 $output->disable_progress;
29 use winapi qw(@winapis);
33 if($options->spec_files) {
36 foreach my $spec_file (get_spec_files("winelib")) {
40 open(IN, "< $wine_dir/$spec_file");
42 s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begining and end of line
43 s/^(.*?)\s*#.*$/$1/; # remove comments
44 /^$/ && next; # skip empty lines
46 if(/^name\s+(.*?)$/) {
48 $module2spec_file{$module} = $spec_file;
49 } elsif(/^type\s+(.*?)$/) {
51 $module2type{$module} = $type;
60 sub documentation_specifications {
63 my @debug_channels = @{$function->debug_channels};
64 my $documentation = $function->documentation;
65 my $documentation_line = $function->documentation_line;
66 my $return_type = $function->return_type;
67 my $linkage = $function->linkage;
68 my $internal_name = $function->internal_name;
70 if($linkage eq "static") {
75 foreach (split(/\n/, $documentation)) {
76 if(/^\s*\*\s*(\S+)\s*[\(\[]\s*(\w+)\s*\.\s*(\S+)\s*[\)\]]/) {
77 my $external_name = $1;
82 if(1 || !exists($specifications{$module}{unfixed}{$external_name})) {
83 $specifications{$module}{unfixed}{$external_name}{ordinal} = $ordinal;
84 $specifications{$module}{unfixed}{$external_name}{external_name} = $external_name;
85 $specifications{$module}{unfixed}{$external_name}{function} = $function;
87 $output->write("$external_name ($module.$ordinal) already exists\n");
89 } elsif($ordinal =~ /^\d+$/) {
90 if(1 || !exists($specifications{$module}{fixed}{$ordinal})) {
91 $specifications{$module}{fixed}{$ordinal}{ordinal} = $ordinal;
92 $specifications{$module}{fixed}{$ordinal}{external_name} = $external_name;
93 $specifications{$module}{fixed}{$ordinal}{function} = $function;
95 $output->write("$external_name ($module.$ordinal) already exists\n");
97 } elsif($ordinal eq "init") {
98 if(!exists($specifications{$module}{init})) {
99 $specifications{$module}{init}{function} = $function;
101 $output->write("$external_name ($module.$ordinal) already exists\n");
104 if(!exists($specifications{$module}{unknown}{$external_name})) {
105 $specifications{$module}{unknown}{$external_name}{ordinal} = $ordinal;
106 $specifications{$module}{unknown}{$external_name}{external_name} = $external_name;
107 $specifications{$module}{unknown}{$external_name}{function} = $function;
109 $output->write("$external_name ($module.$ordinal) already exists\n");
113 if($options->debug) {
114 $output->write("$external_name ($module.$ordinal)\n");
120 my %module_pseudo_stub_count16;
121 my %module_pseudo_stub_count32;
123 sub statements_stub {
124 my $function = shift;
126 my $statements = $function->statements;
127 if(defined($statements) && $statements =~ /FIXME[^;]*stub/s) {
128 if($options->win16) {
129 foreach my $module16 ($function->modules16) {
130 $module_pseudo_stub_count16{$module16}++;
133 if($options->win32) {
134 foreach my $module32 ($function->modules32) {
135 $module_pseudo_stub_count32{$module32}++;
141 my @c_files = $options->c_files;
142 @c_files = files_skip(@c_files);
143 @c_files = files_filter("winelib", @c_files);
146 my $progress_current = 0;
147 my $progress_max = scalar(@c_files);
149 foreach my $file (@c_files) {
153 $output->progress("$file (file $progress_current of $progress_max)");
155 my $create_function = sub {
156 if($options->stub_statistics) {
157 return 'winapi_function'->new;
159 return 'function'->new;
163 my $found_function = sub {
164 my $function = shift;
166 my $internal_name = $function->internal_name;
167 $functions{$internal_name} = $function;
169 $output->progress("$file (file $progress_current of $progress_max): $internal_name");
170 $output->prefix_callback(sub { return $function->prefix; });
172 my $documentation_line = $function->documentation_line;
173 my $documentation = $function->documentation;
174 my $function_line = $function->function_line;
175 my $linkage = $function->linkage;
176 my $return_type = $function->return_type;
177 my $calling_convention = $function->calling_convention;
178 my $statements = $function->statements;
180 if($options->spec_files) {
181 documentation_specifications($function);
184 if($options->stub_statistics) {
185 statements_stub($function);
191 my $create_type = sub {
195 my $found_type = sub {
199 my $found_preprocessor = sub {
200 my $directive = shift;
201 my $argument = shift;
204 &winapi_parser::parse_c_file($file, $create_function, $found_function, $create_type, $found_type, $found_preprocessor);
206 my @internal_names = keys(%functions);
207 if($#internal_names < 0) {
208 $output->write("$file: doesn't contain any functions\n");
212 sub output_function {
216 my $external_name = shift;
217 my $function = shift;
219 my $internal_name = $function->internal_name;
222 my $calling_convention;
223 my $refargument_kinds;
224 if($type eq "win16") {
225 $return_kind = $function->return_kind16 || "undef";
226 $calling_convention = $function->calling_convention16 || "undef";
227 $refargument_kinds = $function->argument_kinds16;
228 } elsif($type eq "win32") {
229 $return_kind = $function->return_kind32 || "undef";
230 $calling_convention = $function->calling_convention32 || "undef";
231 $refargument_kinds = $function->argument_kinds32;
234 if(defined($refargument_kinds)) {
235 my @argument_kinds = map { $_ || "undef"; } @$refargument_kinds;
236 print OUT "$ordinal $calling_convention $external_name(@argument_kinds) $internal_name\n";
238 print OUT "$ordinal $calling_convention $external_name() $internal_name # FIXME: arguments undefined\n";
242 if($options->spec_files) {
243 foreach my $module (keys(%specifications)) {
244 my $spec_file = $module2spec_file{$module};
245 my $type = $module2type{$module};
247 if(!defined($spec_file) || !defined($type)) {
248 $output->write("$module: doesn't exist\n");
254 $output->progress("$spec_file");
255 open(OUT, "> $wine_dir/$spec_file");
257 print OUT "name $module\n";
258 print OUT "type $type\n";
259 if(exists($specifications{$module}{init})) {
260 my $function = $specifications{$module}{init}{function};
261 print OUT "init " . $function->internal_name . "\n";
266 if(exists($specifications{$module}{init})) {
267 my $function = $specifications{$module}{init}{function};
268 foreach my $debug_channel (@{$function->debug_channels}) {
269 $debug_channels{$debug_channel}++;
272 foreach my $ordinal (sort {$a <=> $b} keys(%{$specifications{$module}{fixed}})) {
273 my $function = $specifications{$module}{fixed}{$ordinal}{function};
274 foreach my $debug_channel (@{$function->debug_channels}) {
275 $debug_channels{$debug_channel}++;
278 foreach my $name (sort(keys(%{$specifications{$module}{unfixed}}))) {
279 my $function = $specifications{$module}{unfixed}{$name}{function};
280 foreach my $debug_channel (@{$function->debug_channels}) {
281 $debug_channels{$debug_channel}++;
284 foreach my $name (sort(keys(%{$specifications{$module}{unknown}}))) {
285 my $function = $specifications{$module}{unknown}{$name}{function};
286 foreach my $debug_channel (@{$function->debug_channels}) {
287 $debug_channels{$debug_channel}++;
291 my @debug_channels = sort(keys(%debug_channels));
292 if($#debug_channels >= 0) {
293 print OUT "debug_channels (" . join(" ", @debug_channels) . ")\n";
303 foreach my $external_name (sort(keys(%{$specifications{$module}{unknown}}))) {
304 my $entry = $specifications{$module}{unknown}{$external_name};
305 my $ordinal = $entry->{ordinal};
306 my $function = $entry->{function};
308 output_function(\*OUT, $type, $ordinal, $external_name, $function);
316 foreach my $ordinal (sort {$a <=> $b} keys(%{$specifications{$module}{fixed}})) {
317 my $entry = $specifications{$module}{fixed}{$ordinal};
318 my $external_name = $entry->{external_name};
319 my $function = $entry->{function};
320 output_function(\*OUT, $type, $ordinal, $external_name, $function);
328 foreach my $external_name (sort(keys(%{$specifications{$module}{unfixed}}))) {
329 my $entry = $specifications{$module}{unfixed}{$external_name};
330 my $ordinal = $entry->{ordinal};
331 my $function = $entry->{function};
332 output_function(\*OUT, $type, $ordinal, $external_name, $function);
340 if($options->stub_statistics) {
341 foreach my $winapi (@winapis) {
342 if($winapi->name eq "win16" && !$options->win16) { next; }
343 if($winapi->name eq "win32" && !$options->win32) { next; }
345 my %module_stub_count;
346 my %module_total_count;
348 foreach my $internal_name ($winapi->all_internal_functions,$winapi->all_functions_stub) {
349 foreach my $module (split(/ \& /, $winapi->function_internal_module($internal_name))) {
350 if($winapi->is_function_stub_in_module($module, $internal_name)) {
351 $module_stub_count{$module}++;
353 $module_total_count{$module}++;
357 foreach my $module ($winapi->all_modules) {
359 if($winapi->name eq "win16") {
360 $pseudo_stubs = $module_pseudo_stub_count16{$module};
361 } elsif($winapi->name eq "win32") {
362 $pseudo_stubs = $module_pseudo_stub_count32{$module};
365 my $real_stubs = $module_stub_count{$module};
366 my $total = $module_total_count{$module};
368 if(!defined($real_stubs)) { $real_stubs = 0; }
369 if(!defined($pseudo_stubs)) { $pseudo_stubs = 0; }
370 if(!defined($total)) { $total = 0;}
372 my $stubs = $real_stubs + $pseudo_stubs;
374 $output->write("*.c: $module: ");
375 $output->write("$stubs of $total functions are stubs ($real_stubs real, $pseudo_stubs pseudo)\n");