- Begun implementation of a C statements parser.
[wine] / tools / winapi_check / nativeapi.pm
1 package nativeapi;
2
3 use strict;
4
5 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
6 require Exporter;
7
8 @ISA = qw(Exporter);
9 @EXPORT = qw();
10 @EXPORT_OK = qw($nativeapi);
11
12 use vars qw($nativeapi);
13
14 use config qw(&file_type $current_dir $wine_dir $winapi_check_dir);
15 use options qw($options);
16 use output qw($output);
17
18 $nativeapi = 'nativeapi'->new;
19
20 sub new {
21     my $proto = shift;
22     my $class = ref($proto) || $proto;
23     my $self  = {};
24     bless ($self, $class);
25
26     my $functions = \%{$self->{FUNCTIONS}};
27     my $conditionals = \%{$self->{CONDITIONALS}};
28     my $conditional_headers = \%{$self->{CONDITIONAL_HEADERS}};
29     my $conditional_functions = \%{$self->{CONDITIONAL_FUNCTIONS}};
30
31     my $api_file = "$winapi_check_dir/nativeapi.dat";
32     my $configure_in_file = "$wine_dir/configure.in";
33     my $config_h_in_file = "$wine_dir/include/config.h.in";
34
35     $api_file =~ s/^\.\///;
36     $configure_in_file =~ s/^\.\///;
37     $config_h_in_file =~ s/^\.\///;
38
39     if($options->progress) {
40         $output->progress("$api_file");
41     }
42
43     open(IN, "< $api_file");
44     local $/ = "\n";
45     while(<IN>) {
46         s/^\s*(.*?)\s*$/$1/; # remove whitespace at begin and end of line
47         s/^(.*?)\s*#.*$/$1/; # remove comments
48         /^$/ && next;        # skip empty lines   
49
50         $$functions{$_}++;
51     }
52     close(IN);
53
54     if($options->progress) {
55         $output->progress("$configure_in_file");
56     }
57
58     my $again = 0;
59     open(IN, "< $configure_in_file");   
60     local $/ = "\n";
61     while($again || (defined($_ = <IN>))) {
62         $again = 0;
63         chomp;
64         if(/^(.*?)\\$/) {
65             my $current = $1;
66             my $next = <IN>;
67             if(defined($next)) {
68                 # remove trailing whitespace
69                 $current =~ s/\s+$//;
70
71                 # remove leading whitespace
72                 $next =~ s/^\s+//;
73
74                 $_ = $current . " " . $next;
75
76                 $again = 1;
77                 next;
78             }
79         }
80
81         # remove leading and trailing whitespace
82         s/^\s*(.*?)\s*$/$1/;
83
84         # skip emty lines
85         if(/^$/) { next; }
86
87         # skip comments
88         if(/^dnl/) { next; }
89
90         if(/^AC_CHECK_HEADERS\(\s*([^,\)]*)(?:,|\))?/) {
91             foreach my $name (split(/\s+/, $1)) {
92                 $$conditional_headers{$name}++;
93             }
94         } elsif(/^AC_CHECK_FUNCS\(\s*([^,\)]*)(?:,|\))?/) {
95             foreach my $name (split(/\s+/, $1)) {
96                 $$conditional_functions{$name}++;
97             }
98         } elsif(/^AC_FUNC_ALLOCA/) {
99             $$conditional_headers{"alloca.h"}++;
100         }
101
102     }
103     close(IN);
104
105     if($options->progress) {
106         $output->progress("$config_h_in_file");
107     }
108
109     open(IN, "< $config_h_in_file");
110     local $/ = "\n";
111     while(<IN>) {
112         # remove leading and trailing whitespace
113         s/^\s*(.*?)\s*$/$1/;
114
115         # skip emty lines
116         if(/^$/) { next; }
117
118         if(/^\#undef\s+(\S+)$/) {
119             $$conditionals{$1}++;
120         }
121     }
122     close(IN);
123
124     $nativeapi = $self;
125
126     return $self;
127 }
128
129 sub is_function {
130     my $self = shift;
131     my $functions = \%{$self->{FUNCTIONS}};
132
133     my $name = shift;
134
135     return $$functions{$name};
136 }
137
138 sub is_conditional {
139     my $self = shift;
140     my $conditionals = \%{$self->{CONDITIONALS}};
141
142     my $name = shift;
143
144     return $$conditionals{$name};
145 }
146
147 sub found_conditional {
148     my $self = shift;
149     my $conditional_found = \%{$self->{CONDITIONAL_FOUND}};
150
151     my $name = shift;
152
153     $$conditional_found{$name}++;
154 }
155
156 sub is_conditional_header {
157     my $self = shift;
158     my $conditional_headers = \%{$self->{CONDITIONAL_HEADERS}};
159
160     my $name = shift;
161
162     return $$conditional_headers{$name};
163 }
164
165 sub is_conditional_function {
166     my $self = shift;
167     my $conditional_functions = \%{$self->{CONDITIONAL_FUNCTIONS}};
168
169     my $name = shift;
170
171     return $$conditional_functions{$name};
172 }
173
174 sub global_report {
175     my $self = shift;
176
177     my $output = \${$self->{OUTPUT}};
178     my $conditional_found = \%{$self->{CONDITIONAL_FOUND}};
179     my $conditionals = \%{$self->{CONDITIONALS}};
180
181     my @messages;
182     foreach my $name (sort(keys(%$conditionals))) {
183         if($name =~ /^const|inline|size_t$/) { next; }
184
185         if(0 && !$$conditional_found{$name}) {
186             push @messages, "config.h.in: conditional $name not used\n";
187         }
188     }
189
190     foreach my $message (sort(@messages)) {
191         $output->write($message);
192     }
193 }
194
195 1;