Yet another major reorganization and a few new features.
[wine] / tools / winapi_check / modules.pm
1 package modules;
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($modules);
11
12 use vars qw($modules);
13
14 sub new {
15     my $proto = shift;
16     my $class = ref($proto) || $proto;
17     my $self  = {};
18     bless ($self, $class);
19
20     my $options = \${$self->{OPTIONS}};
21     my $output = \${$self->{OUTPUT}};
22     my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
23     my $spec_file2dir = \%{$self->{SPEC_FILE2DIR}};
24     my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
25
26     $$options = shift;
27     $$output = shift;
28     my $wine_dir = shift;
29     my $current_dir = shift;
30     my $file_type = shift;    
31     my $module_file = shift;
32
33     $module_file =~ s/^\.\///;
34
35     my @all_spec_files = map {
36         s/^.\/(.*)$/$1/;
37         if(&$file_type($_) eq "winelib") {
38             $_;
39         } else {
40             ();
41         }
42     } split(/\n/, `find $wine_dir -name \\*.spec`);
43
44     my %all_spec_files;
45     foreach my $file (@all_spec_files) {
46         $all_spec_files{$file}++ ;
47     }
48
49     if($$options->progress) {
50         $$output->progress("modules.dat");
51     }
52
53     my $allowed_dir;
54     my $spec_file;
55
56     open(IN, "< $module_file");
57     local $/ = "\n";
58     while(<IN>) {
59         s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begining and end of line
60         s/^(.*?)\s*#.*$/$1/;  # remove comments
61         /^$/ && next;         # skip empty lines
62
63         if(/^%\s+(.*?)$/) {
64             $spec_file = $1;
65            
66             if(!-f "$wine_dir/$spec_file") {
67                 $$output->write("modules.dat: $spec_file: file ($spec_file) doesn't exist or is no file\n");
68             } 
69
70             if($wine_dir eq ".") {
71                 $all_spec_files{$spec_file}--;
72             } else {
73                 $all_spec_files{"$wine_dir/$spec_file"}--;
74             }
75             $$dir2spec_file{""}{$spec_file}++; # FIXME: Kludge
76             next;
77         } else {
78             $allowed_dir = $1;
79             $$spec_file2dir{$spec_file}{$allowed_dir}++;
80         }
81         $$dir2spec_file{$allowed_dir}{$spec_file}++;
82
83         if(!-d "$wine_dir/$allowed_dir") {
84             $$output->write("modules.dat: $spec_file: directory ($allowed_dir) doesn't exist or is no directory\n");
85         } 
86     }
87     close(IN);
88
89     foreach my $spec_file (sort(keys(%all_spec_files))) {
90         if($all_spec_files{$spec_file} > 0) {
91             $$output->write("modules.dat: $spec_file: exists but is not specified\n");
92         }
93     }
94
95     $modules = $self;
96
97     return $self;
98 }
99
100 sub all_modules {
101     my $self = shift;
102
103     my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}};
104
105     return sort(keys(%$module2spec_file));
106 }
107
108 sub spec_file_module {
109     my $self = shift;
110
111     my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
112     my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}};
113
114     my $spec_file = shift;
115     $spec_file =~ s/^\.\///;
116
117     my $module = shift;
118   
119     $$spec_file2module{$spec_file} = $module;
120     $$module2spec_file{$module} = $spec_file;
121 }
122
123 sub is_allowed_module_in_file {
124     my $self = shift;
125
126     my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
127     my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
128
129     my $module = shift;
130     my $file = shift;
131     $file =~ s/^\.\///;
132
133     my $dir = $file;
134     $dir =~ s/\/[^\/]*$//;
135
136     if($dir =~ m%^include%) {
137         return 1;
138     }
139
140     foreach my $spec_file (sort(keys(%{$$dir2spec_file{$dir}}))) {
141         if($$spec_file2module{$spec_file} eq $module) {
142             return 1;
143         }
144     }
145
146     return 0;
147 }
148
149 sub allowed_modules_in_file {
150     my $self = shift;
151
152     my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
153     my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
154
155     my $file = shift;
156     $file =~ s/^\.\///;
157
158     my $dir = $file;
159     $dir =~ s/\/[^\/]*$//;
160
161     my %allowed_modules = ();
162     foreach my $spec_file (sort(keys(%{$$dir2spec_file{$dir}}))) {
163         my $module = $$spec_file2module{$spec_file};
164         $allowed_modules{$module}++;
165     }
166
167     return join(" & ", sort(keys(%allowed_modules)));
168 }
169
170 sub allowed_dirs_for_module {
171    my $self = shift;
172
173    my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}};
174    my $spec_file2dir = \%{$self->{SPEC_FILE2DIR}};   
175
176    my $module = shift;
177
178    my $spec_file = $$module2spec_file{$module};
179
180    return sort(keys(%{$$spec_file2dir{$spec_file}}));
181 }
182
183 sub allowed_spec_files {
184     my $self = shift;
185
186     my $options = \${$self->{OPTIONS}};
187     my $output = \${$self->{OUTPUT}};
188     my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
189
190     my $wine_dir = shift;
191     my $current_dir = shift;
192
193     my @dirs = map {
194         s/^\.\/(.*)$/$1/;
195         if(/^\.$/) {
196             $current_dir;
197         } else {
198             if($current_dir ne ".") {
199                 "$current_dir/$_";
200             } else {
201                 $_;
202             }
203         }
204     } split(/\n/, `find . -type d ! -name CVS`);
205
206     my %allowed_spec_files = ();
207     foreach my $dir (sort(@dirs)) {
208         foreach my $spec_file (sort(keys(%{$$dir2spec_file{$dir}}))) {
209             $allowed_spec_files{$spec_file}++; 
210         }
211     }
212
213     return sort(keys(%allowed_spec_files));
214 }
215
216 sub found_module_in_dir {
217     my $self = shift;
218
219     my $module = shift;
220     my $dir = shift;
221
222     my $used_module_dirs = \%{$self->{USED_MODULE_DIRS}};
223
224     $$used_module_dirs{$module}{$dir}++;
225 }
226
227 sub global_report {
228     my $self = shift;
229
230     my $output = \${$self->{OUTPUT}};
231     my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
232     my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
233     my $used_module_dirs = \%{$self->{USED_MODULE_DIRS}};
234
235     my @messages;
236     foreach my $dir (sort(keys(%$dir2spec_file))) {
237         if($dir eq "") { next; }
238         foreach my $spec_file (sort(keys(%{$$dir2spec_file{$dir}}))) {
239             my $module = $$spec_file2module{$spec_file};
240             if(!$$used_module_dirs{$module}{$dir}) {
241                 push @messages, "modules.dat: $spec_file: directory ($dir) is not used\n";
242             }
243         }
244     }
245
246     foreach my $message (sort(@messages)) {
247         $$output->write($message);
248     }
249 }
250
251 1;