3 # Copyright 2001 Patrik Stridvall
8 $0 =~ m%^(.*?/?tools)/winapi/winapi_extract$%;
9 require "$1/winapi/setup.pm";
13 &file_type &file_skip &files_skip &get_spec_files
14 $current_dir $wine_dir $winapi_dir $winapi_check_dir
21 my $output = output->new;
24 "debug" => { default => 0, description => "debug mode" },
25 "help" => { default => 0, description => "help mode" },
26 "verbose" => { default => 0, description => "verbose mode" },
28 "progress" => { default => 1, description => "show progress" },
30 "win16" => { default => 1, description => "Win16 extraction" },
31 "win32" => { default => 1, description => "Win32 extraction" },
33 "local" => { default => 1, description => "local extraction" },
34 "global" => { default => 1, description => "global extraction" },
36 "spec-files" => { default => 1, parent => "global", description => "spec files extraction" },
45 my $options_usage = "usage: winapi_extract [--help] [<files>]\n";
47 my $options = options->new(\%options_long, \%options_short, $options_usage);
54 foreach my $spec_file (get_spec_files) {
58 open(IN, "< $wine_dir/$spec_file");
60 s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begining and end of line
61 s/^(.*?)\s*#.*$/$1/; # remove comments
62 /^$/ && next; # skip empty lines
64 if(/^name\s+(.*?)$/) {
66 $module2spec_file{$module} = $spec_file;
67 } elsif(/^type\s+(.*?)$/) {
69 $module2type{$module} = $type;
76 my $win16api = winapi->new($options, $output, "win16", "$winapi_check_dir/win16");
77 my $win32api = winapi->new($options, $output, "win32", "$winapi_check_dir/win32");
78 my @winapis = ($win16api, $win32api);
82 my @files = files_skip($options->c_files);
85 my $progress_current = 0;
86 my $progress_max = scalar(@files);
88 foreach my $file (@files) {
92 if($options->progress) {
93 output->progress("$file: file $progress_current of $progress_max");
96 my $found_function = sub {
98 my $refdebug_channels = shift;
99 my @debug_channels = @$refdebug_channels;
100 my $documentation = shift;
102 my $return_type = shift;
103 my $calling_convention = shift;
104 my $internal_name = shift;
105 my $refargument_types = shift;
106 my @argument_types = @$refargument_types;
107 my $refargument_names = shift;
108 my @argument_names = @$refargument_names;
109 my $refargument_documentations = shift;
110 my @argument_documentations = @$refargument_documentations;
111 my $statements = shift;
115 if($linkage eq "static") {
120 foreach (split(/\n/, $documentation)) {
121 if(/^\s*\*\s*(\w+|\@)\s*[\(\[]\s*(\w+)\s*\.\s*(\@|\d+)\s*[\)\]]/) {
122 my $external_name = $1;
126 if($ordinal eq "@") {
127 $specifications{$module}{unfixed}{$external_name}{debug_channels} = [@debug_channels];
128 $specifications{$module}{unfixed}{$external_name}{internal_name} = $internal_name;
129 $specifications{$module}{unfixed}{$external_name}{external_name} = $external_name;
130 $specifications{$module}{unfixed}{$external_name}{ordinal} = $ordinal;
131 $specifications{$module}{unfixed}{$external_name}{arguments} = [@argument_types];
133 $specifications{$module}{fixed}{$ordinal}{debug_channels} = [@debug_channels];
134 $specifications{$module}{fixed}{$ordinal}{ordinal} = $ordinal;
135 $specifications{$module}{fixed}{$ordinal}{internal_name} = $internal_name;
136 $specifications{$module}{fixed}{$ordinal}{external_name} = $external_name;
137 $specifications{$module}{fixed}{$ordinal}{arguments} = [@argument_types];
140 if($options->debug) {
141 output->write("$file: $external_name ($module.$ordinal)\n");
148 my $found_preprocessor = sub {
149 my $directive = shift;
150 my $argument = shift;
153 winapi_parser::parse_c_file $options, $output, $file, $found_function, $found_preprocessor;
155 if($functions == 0) {
156 output->write("$file: doesn't contain any functions\n");
160 sub output_function {
163 my $function = shift;
165 my $internal_name = $function->{internal_name};
166 my $external_name = $function->{external_name};
167 my $ordinal = $function->{ordinal};
168 my @arguments = @{$function->{arguments}};
171 foreach my $argument (@arguments) {
173 if($type eq "win16") {
174 $argument2 = $win16api->translate_argument($argument);
176 $argument2 = $win32api->translate_argument($argument);
178 if(!defined($argument2)) {
179 $argument2 = "undef";
182 if($argument2 eq "longlong") {
183 push @arguments2, ("long", "long");
185 push @arguments2, $argument2;
189 if($type eq "win16") {
190 print OUT "$ordinal pascal $external_name(@arguments2) $internal_name\n";
192 print OUT "$ordinal stdcall $external_name(@arguments2) $internal_name\n";
196 if($options->spec_files) {
197 foreach my $module (keys(%specifications)) {
198 my $spec_file = $module2spec_file{$module};
199 my $type = $module2type{$module};
201 if(!defined($spec_file) || !defined($type)) {
202 output->write("$module: doesn't exist\n");
208 output->progress("$spec_file");
209 open(OUT, "> $wine_dir/$spec_file");
211 print OUT "name $module\n";
212 print OUT "type $type\n";
216 foreach my $ordinal (sort {$a <=> $b} keys(%{$specifications{$module}{fixed}})) {
217 my $function = $specifications{$module}{fixed}{$ordinal};
218 foreach my $debug_channel (@{$function->{debug_channels}}) {
219 $debug_channels{$debug_channel}++;
222 foreach my $name (sort(keys(%{$specifications{$module}{unfixed}}))) {
223 my $function = $specifications{$module}{unfixed}{$name};
224 foreach my $debug_channel (@{$function->{debug_channels}}) {
225 $debug_channels{$debug_channel}++;
229 my @debug_channels = sort(keys(%debug_channels));
230 if($#debug_channels >= 0) {
231 print OUT "debug_channels (" . join(" ", @debug_channels) . ")\n";
236 foreach my $ordinal (sort {$a <=> $b} keys(%{$specifications{$module}{fixed}})) {
237 my $function = $specifications{$module}{fixed}{$ordinal};
238 output_function(\*OUT, $type, $function);
242 foreach my $name (sort(keys(%{$specifications{$module}{unfixed}}))) {
247 my $function = $specifications{$module}{unfixed}{$name};
248 output_function(\*OUT, $type, $function);
253 output->hide_progress;