|  | # | 
|  | # Copyright 1999, 2000, 2001 Patrik Stridvall | 
|  | # | 
|  | # This library is free software; you can redistribute it and/or | 
|  | # modify it under the terms of the GNU Lesser General Public | 
|  | # License as published by the Free Software Foundation; either | 
|  | # version 2.1 of the License, or (at your option) any later version. | 
|  | # | 
|  | # This library is distributed in the hope that it will be useful, | 
|  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | # Lesser General Public License for more details. | 
|  | # | 
|  | # You should have received a copy of the GNU Lesser General Public | 
|  | # License along with this library; if not, write to the Free Software | 
|  | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | # | 
|  |  | 
|  | package modules; | 
|  |  | 
|  | use strict; | 
|  |  | 
|  | use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); | 
|  | require Exporter; | 
|  |  | 
|  | @ISA = qw(Exporter); | 
|  | @EXPORT = qw(); | 
|  | @EXPORT_OK = qw($modules); | 
|  |  | 
|  | use vars qw($modules); | 
|  |  | 
|  | use config qw( | 
|  | file_type files_skip | 
|  | file_directory | 
|  | get_c_files get_spec_files | 
|  | $current_dir $wine_dir | 
|  | $winapi_check_dir | 
|  | ); | 
|  | use options qw($options); | 
|  | use output qw($output); | 
|  |  | 
|  | sub import(@) { | 
|  | $Exporter::ExportLevel++; | 
|  | Exporter::import(@_); | 
|  | $Exporter::ExportLevel--; | 
|  |  | 
|  | if (defined($modules)) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | $modules = 'modules'->new; | 
|  | } | 
|  |  | 
|  | sub get_spec_file_type($) { | 
|  | my $file = shift; | 
|  |  | 
|  | my $module; | 
|  | my $type; | 
|  |  | 
|  | $module = $file; | 
|  | $module =~ s%^.*?([^/]+)\.spec$%$1%; | 
|  |  | 
|  | open(IN, "< $file") || die "$file: $!\n"; | 
|  | local $/ = "\n"; | 
|  | my $header = 1; | 
|  | my $lookahead = 0; | 
|  | while($lookahead || defined($_ = <IN>)) { | 
|  | $lookahead = 0; | 
|  | s/^\s*(.*?)\s*$/$1/; | 
|  | s/^(.*?)\s*#.*$/$1/; | 
|  | /^$/ && next; | 
|  |  | 
|  | if($header)  { | 
|  | if(/^(?:\d+|@)/) { $header = 0; $lookahead = 1; } | 
|  | next; | 
|  | } | 
|  |  | 
|  | if(/^(\d+|@)\s+pascal(?:16)?/) { | 
|  | $type = "win16"; | 
|  | last; | 
|  | } | 
|  | } | 
|  | close(IN); | 
|  |  | 
|  | if(!defined($type)) { | 
|  | $type = "win32"; | 
|  | } | 
|  |  | 
|  | return ($type, $module); | 
|  | } | 
|  |  | 
|  | sub find_spec_files($) { | 
|  | my $self = shift; | 
|  |  | 
|  | my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}}; | 
|  | my $spec_file2dir = \%{$self->{SPEC_FILE2DIR}}; | 
|  |  | 
|  | $output->progress("modules"); | 
|  |  | 
|  | my $spec_file_found = {}; | 
|  | my $allowed_dir; | 
|  | my $spec_file; | 
|  |  | 
|  | my @spec_files = <{dlls/*/*.spec,dlls/*/*/*.spec}>; | 
|  |  | 
|  | foreach $spec_file (@spec_files) { | 
|  | $spec_file =~ /(.*)\/.*\.spec/; | 
|  |  | 
|  | $allowed_dir = $1; | 
|  |  | 
|  | $$spec_file_found{$spec_file}++; | 
|  | $$spec_file2dir{$spec_file}{$allowed_dir}++; | 
|  | $$dir2spec_file{$allowed_dir}{$spec_file}++; | 
|  | } | 
|  |  | 
|  | return $spec_file_found; | 
|  | } | 
|  |  | 
|  | sub read_spec_files($$) { | 
|  | my $self = shift; | 
|  |  | 
|  | my $spec_file_found = shift; | 
|  |  | 
|  | my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}}; | 
|  | my $spec_files16 = \@{$self->{SPEC_FILES16}}; | 
|  | my $spec_files32 = \@{$self->{SPEC_FILES32}}; | 
|  | my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}}; | 
|  | my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}}; | 
|  |  | 
|  | my @spec_files; | 
|  | if($wine_dir eq ".") { | 
|  | @spec_files = get_spec_files("winelib"); | 
|  | } else { | 
|  | my %spec_files = (); | 
|  | foreach my $dir ($options->directories) { | 
|  | $dir = "$current_dir/$dir"; | 
|  | $dir =~ s%/\.$%%; | 
|  | foreach my $spec_file (sort(keys(%{$$dir2spec_file{$dir}}))) { | 
|  | $spec_files{$spec_file}++; | 
|  | } | 
|  | } | 
|  | @spec_files = sort(keys(%spec_files)); | 
|  | } | 
|  |  | 
|  | @$spec_files16 = (); | 
|  | @$spec_files32 = (); | 
|  | foreach my $spec_file (@spec_files) { | 
|  | (my $type, my $module) = get_spec_file_type("$wine_dir/$spec_file"); | 
|  |  | 
|  | $$spec_file2module{$spec_file} = $module; | 
|  | $$module2spec_file{$module} = $spec_file; | 
|  |  | 
|  | if($type eq "win16") { | 
|  | push @$spec_files16, $spec_file; | 
|  | } elsif($type eq "win32") { | 
|  | push @$spec_files32, $spec_file; | 
|  | } else { | 
|  | $output->write("$spec_file: unknown type '$type'\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | foreach my $spec_file (@spec_files) { | 
|  | if(!$$spec_file_found{$spec_file} && $spec_file !~ m%tests/[^/]+$%) { | 
|  | $output->write("modules: $spec_file: exists but is not specified\n"); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | sub new($) { | 
|  | my $proto = shift; | 
|  | my $class = ref($proto) || $proto; | 
|  | my $self  = {}; | 
|  | bless ($self, $class); | 
|  |  | 
|  | my $spec_file_found = $self->find_spec_files(); | 
|  | $self->read_spec_files($spec_file_found); | 
|  |  | 
|  | return $self; | 
|  | } | 
|  |  | 
|  | sub all_modules($) { | 
|  | my $self = shift; | 
|  |  | 
|  | my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}}; | 
|  |  | 
|  | return sort(keys(%$module2spec_file)); | 
|  | } | 
|  |  | 
|  | sub is_allowed_module($$) { | 
|  | my $self = shift; | 
|  |  | 
|  | my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}}; | 
|  |  | 
|  | my $module = shift; | 
|  |  | 
|  | return defined($$module2spec_file{$module}); | 
|  | } | 
|  |  | 
|  | sub is_allowed_module_in_file($$$) { | 
|  | my $self = shift; | 
|  |  | 
|  | my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}}; | 
|  | my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}}; | 
|  |  | 
|  | my $module = shift; | 
|  | my $file = shift; | 
|  | $file =~ s/^\.\///; | 
|  |  | 
|  | my $dir = $file; | 
|  | $dir =~ s/\/[^\/]*$//; | 
|  |  | 
|  | if($dir =~ m%^include%) { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | foreach my $spec_file (sort(keys(%{$$dir2spec_file{$dir}}))) { | 
|  | if($$spec_file2module{$spec_file} eq $module) { | 
|  | return 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | sub allowed_modules_in_file($$) { | 
|  | my $self = shift; | 
|  |  | 
|  | my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}}; | 
|  | my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}}; | 
|  |  | 
|  | my $file = shift; | 
|  | $file =~ s/^\.\///; | 
|  |  | 
|  | my $dir = $file; | 
|  | $dir =~ s/\/[^\/]*$//; | 
|  |  | 
|  | my %allowed_modules = (); | 
|  | foreach my $spec_file (sort(keys(%{$$dir2spec_file{$dir}}))) { | 
|  | my $module = $$spec_file2module{$spec_file}; | 
|  | $allowed_modules{$module}++; | 
|  | } | 
|  |  | 
|  | my $module = join(" & ", sort(keys(%allowed_modules))); | 
|  |  | 
|  | return $module; | 
|  | } | 
|  |  | 
|  | sub allowed_dirs_for_module($$) { | 
|  | my $self = shift; | 
|  |  | 
|  | my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}}; | 
|  | my $spec_file2dir = \%{$self->{SPEC_FILE2DIR}}; | 
|  |  | 
|  | my $module = shift; | 
|  |  | 
|  | my $spec_file = $$module2spec_file{$module}; | 
|  |  | 
|  | return sort(keys(%{$$spec_file2dir{$spec_file}})); | 
|  | } | 
|  |  | 
|  | sub allowed_spec_files16($) { | 
|  | my $self = shift; | 
|  |  | 
|  | my $spec_files16 = \@{$self->{SPEC_FILES16}}; | 
|  |  | 
|  | return @$spec_files16; | 
|  | } | 
|  |  | 
|  | sub allowed_spec_files32($) { | 
|  | my $self = shift; | 
|  |  | 
|  | my $spec_files32 = \@{$self->{SPEC_FILES32}}; | 
|  |  | 
|  | return @$spec_files32; | 
|  | } | 
|  |  | 
|  | sub found_module_in_dir($$$) { | 
|  | my $self = shift; | 
|  |  | 
|  | my $module = shift; | 
|  | my $dir = shift; | 
|  |  | 
|  | my $used_module_dirs = \%{$self->{USED_MODULE_DIRS}}; | 
|  |  | 
|  | $dir = "$current_dir/$dir"; | 
|  | $dir =~ s%/\.$%%; | 
|  |  | 
|  | $$used_module_dirs{$module}{$dir}++; | 
|  | } | 
|  |  | 
|  | sub complete_modules($$) { | 
|  | my $self = shift; | 
|  |  | 
|  | my $c_files = shift; | 
|  |  | 
|  | my %dirs; | 
|  |  | 
|  | foreach my $file (@$c_files) { | 
|  | my $dir = file_directory("$current_dir/$file"); | 
|  | $dirs{$dir}++; | 
|  | } | 
|  |  | 
|  | my @c_files = get_c_files("winelib"); | 
|  | @c_files = files_skip(@c_files); | 
|  | foreach my $file (@c_files) { | 
|  | my $dir = file_directory($file); | 
|  | if(exists($dirs{$dir})) { | 
|  | $dirs{$dir}--; | 
|  | } | 
|  | } | 
|  |  | 
|  | my @complete_modules = (); | 
|  | foreach my $module ($self->all_modules) { | 
|  | my $index = -1; | 
|  | my @dirs = $self->allowed_dirs_for_module($module); | 
|  | foreach my $dir (@dirs) { | 
|  | if(exists($dirs{$dir}) && $dirs{$dir} == 0) { | 
|  | $index++; | 
|  | } | 
|  | } | 
|  | if($index == $#dirs) { | 
|  | push @complete_modules, $module; | 
|  | } | 
|  | } | 
|  |  | 
|  | return @complete_modules; | 
|  | } | 
|  |  | 
|  | sub global_report($) { | 
|  | my $self = shift; | 
|  |  | 
|  | my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}}; | 
|  | my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}}; | 
|  | my $used_module_dirs = \%{$self->{USED_MODULE_DIRS}}; | 
|  |  | 
|  | my @messages; | 
|  | foreach my $dir ($options->directories) { | 
|  | $dir = "$current_dir/$dir"; | 
|  | $dir =~ s%/\.$%%; | 
|  | foreach my $module ($self->all_modules) { | 
|  | if(!$$used_module_dirs{$module}{$dir}) { | 
|  | my $spec_file = $$module2spec_file{$module}; | 
|  | push @messages, "modules: $spec_file: directory ($dir) is not used\n"; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | foreach my $message (sort(@messages)) { | 
|  | $output->write($message); | 
|  | } | 
|  | } | 
|  |  | 
|  | 1; |