modules.pm 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. #
  2. # Copyright 1999, 2000, 2001 Patrik Stridvall
  3. #
  4. # This library is free software; you can redistribute it and/or
  5. # modify it under the terms of the GNU Lesser General Public
  6. # License as published by the Free Software Foundation; either
  7. # version 2.1 of the License, or (at your option) any later version.
  8. #
  9. # This library is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. # Lesser General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU Lesser General Public
  15. # License along with this library; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  17. #
  18. package modules;
  19. use strict;
  20. use warnings 'all';
  21. use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  22. require Exporter;
  23. @ISA = qw(Exporter);
  24. @EXPORT = qw();
  25. @EXPORT_OK = qw($modules);
  26. use vars qw($modules);
  27. use config qw(
  28. file_type files_skip
  29. file_directory
  30. get_c_files get_spec_files
  31. $current_dir $wine_dir
  32. );
  33. use options qw($options);
  34. use output qw($output);
  35. sub import(@) {
  36. $Exporter::ExportLevel++;
  37. Exporter::import(@_);
  38. $Exporter::ExportLevel--;
  39. if (defined($modules)) {
  40. return;
  41. }
  42. $modules = 'modules'->new;
  43. }
  44. sub get_spec_file_type($) {
  45. my $file = shift;
  46. my $module;
  47. my $type;
  48. $module = $file;
  49. $module =~ s%^.*?([^/]+)\.spec$%$1%;
  50. open(IN, "< $file") || die "$file: $!\n";
  51. local $/ = "\n";
  52. my $header = 1;
  53. my $lookahead = 0;
  54. while($lookahead || defined($_ = <IN>)) {
  55. $lookahead = 0;
  56. s/^\s*(.*?)\s*$/$1/;
  57. s/^(.*?)\s*#.*$/$1/;
  58. /^$/ && next;
  59. if($header) {
  60. if(/^(?:\d+|@)/) { $header = 0; $lookahead = 1; }
  61. next;
  62. }
  63. if(/^(\d+|@)\s+pascal(?:16)?/) {
  64. $type = "win16";
  65. last;
  66. }
  67. }
  68. close(IN);
  69. if(!defined($type)) {
  70. $type = "win32";
  71. }
  72. return ($type, $module);
  73. }
  74. sub find_spec_files($) {
  75. my $self = shift;
  76. my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
  77. my $spec_file2dir = \%{$self->{SPEC_FILE2DIR}};
  78. $output->progress("modules");
  79. my $spec_file_found = {};
  80. my $allowed_dir;
  81. my $spec_file;
  82. my @spec_files = <{dlls/*/*.spec}>;
  83. foreach $spec_file (@spec_files) {
  84. $spec_file =~ /(.*)\/.*\.spec/;
  85. $allowed_dir = $1;
  86. $$spec_file_found{$spec_file}++;
  87. $$spec_file2dir{$spec_file}{$allowed_dir}++;
  88. $$dir2spec_file{$allowed_dir}{$spec_file}++;
  89. # gdi32.dll and gdi.exe have some extra sources in subdirectories
  90. if ($spec_file =~ m!/gdi32\.spec$!)
  91. {
  92. $$spec_file2dir{$spec_file}{"$allowed_dir/enhmfdrv"}++;
  93. $$dir2spec_file{"$allowed_dir/enhmfdrv"}{$spec_file}++;
  94. }
  95. if ($spec_file =~ m!/gdi(?:32|\.exe)\.spec$!)
  96. {
  97. $$spec_file2dir{$spec_file}{"$allowed_dir/mfdrv"}++;
  98. $$dir2spec_file{"$allowed_dir/mfdrv"}{$spec_file}++;
  99. }
  100. }
  101. return $spec_file_found;
  102. }
  103. sub read_spec_files($$) {
  104. my $self = shift;
  105. my $spec_file_found = shift;
  106. my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
  107. my $spec_files16 = \@{$self->{SPEC_FILES16}};
  108. my $spec_files32 = \@{$self->{SPEC_FILES32}};
  109. my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
  110. my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}};
  111. my @spec_files;
  112. if($wine_dir eq ".") {
  113. @spec_files = get_spec_files("winelib");
  114. } else {
  115. my %spec_files = ();
  116. foreach my $dir ($options->directories) {
  117. $dir = "$current_dir/$dir";
  118. $dir =~ s%/\.$%%;
  119. foreach my $spec_file (sort(keys(%{$$dir2spec_file{$dir}}))) {
  120. $spec_files{$spec_file}++;
  121. }
  122. }
  123. @spec_files = sort(keys(%spec_files));
  124. }
  125. @$spec_files16 = ();
  126. @$spec_files32 = ();
  127. foreach my $spec_file (@spec_files) {
  128. (my $type, my $module) = get_spec_file_type("$wine_dir/$spec_file");
  129. $$spec_file2module{$spec_file} = $module;
  130. $$module2spec_file{$module} = $spec_file;
  131. if($type eq "win16") {
  132. push @$spec_files16, $spec_file;
  133. } elsif($type eq "win32") {
  134. push @$spec_files32, $spec_file;
  135. } else {
  136. $output->write("$spec_file: unknown type '$type'\n");
  137. }
  138. }
  139. foreach my $spec_file (@spec_files) {
  140. if(!$$spec_file_found{$spec_file} && $spec_file !~ m%tests/[^/]+$%) {
  141. $output->write("modules: $spec_file: exists but is not specified\n");
  142. }
  143. }
  144. }
  145. sub new($) {
  146. my $proto = shift;
  147. my $class = ref($proto) || $proto;
  148. my $self = {};
  149. bless ($self, $class);
  150. my $spec_file_found = $self->find_spec_files();
  151. $self->read_spec_files($spec_file_found);
  152. return $self;
  153. }
  154. sub all_modules($) {
  155. my $self = shift;
  156. my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}};
  157. return sort(keys(%$module2spec_file));
  158. }
  159. sub is_allowed_module($$) {
  160. my $self = shift;
  161. my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}};
  162. my $module = shift;
  163. return defined($$module2spec_file{$module});
  164. }
  165. sub is_allowed_module_in_file($$$) {
  166. my $self = shift;
  167. my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
  168. my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
  169. my $module = shift;
  170. my $file = shift;
  171. $file =~ s/^\.\///;
  172. my $dir = $file;
  173. $dir =~ s/\/[^\/]*$//;
  174. if($dir =~ m%^include%) {
  175. return 1;
  176. }
  177. foreach my $spec_file (sort(keys(%{$$dir2spec_file{$dir}}))) {
  178. if($$spec_file2module{$spec_file} eq $module) {
  179. return 1;
  180. }
  181. }
  182. return 0;
  183. }
  184. sub allowed_modules_in_file($$) {
  185. my $self = shift;
  186. my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
  187. my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
  188. my $file = shift;
  189. $file =~ s/^\.\///;
  190. my $dir = $file;
  191. $dir =~ s/\/[^\/]*$//;
  192. my %allowed_modules = ();
  193. foreach my $spec_file (sort(keys(%{$$dir2spec_file{$dir}}))) {
  194. my $module = $$spec_file2module{$spec_file};
  195. $allowed_modules{$module}++;
  196. }
  197. my $module = join(" & ", sort(keys(%allowed_modules)));
  198. return $module;
  199. }
  200. sub allowed_dirs_for_module($$) {
  201. my $self = shift;
  202. my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}};
  203. my $spec_file2dir = \%{$self->{SPEC_FILE2DIR}};
  204. my $module = shift;
  205. my $spec_file = $$module2spec_file{$module};
  206. return sort(keys(%{$$spec_file2dir{$spec_file}}));
  207. }
  208. sub allowed_spec_files16($) {
  209. my $self = shift;
  210. my $spec_files16 = \@{$self->{SPEC_FILES16}};
  211. return @$spec_files16;
  212. }
  213. sub allowed_spec_files32($) {
  214. my $self = shift;
  215. my $spec_files32 = \@{$self->{SPEC_FILES32}};
  216. return @$spec_files32;
  217. }
  218. sub found_module_in_dir($$$) {
  219. my $self = shift;
  220. my $module = shift;
  221. my $dir = shift;
  222. my $used_module_dirs = \%{$self->{USED_MODULE_DIRS}};
  223. $dir = "$current_dir/$dir";
  224. $dir =~ s%/\.$%%;
  225. $$used_module_dirs{$module}{$dir}++;
  226. }
  227. sub complete_modules($$) {
  228. my $self = shift;
  229. my $c_files = shift;
  230. my %dirs;
  231. foreach my $file (@$c_files) {
  232. my $dir = file_directory("$current_dir/$file");
  233. $dirs{$dir}++;
  234. }
  235. my @c_files = get_c_files("winelib");
  236. @c_files = files_skip(@c_files);
  237. foreach my $file (@c_files) {
  238. my $dir = file_directory($file);
  239. if(exists($dirs{$dir})) {
  240. $dirs{$dir}--;
  241. }
  242. }
  243. my @complete_modules = ();
  244. foreach my $module ($self->all_modules) {
  245. my $index = -1;
  246. my @dirs = $self->allowed_dirs_for_module($module);
  247. foreach my $dir (@dirs) {
  248. if(exists($dirs{$dir}) && $dirs{$dir} == 0) {
  249. $index++;
  250. }
  251. }
  252. if($index == $#dirs) {
  253. push @complete_modules, $module;
  254. }
  255. }
  256. return @complete_modules;
  257. }
  258. sub global_report($) {
  259. my $self = shift;
  260. my $module2spec_file = \%{$self->{MODULE2SPEC_FILE}};
  261. my $used_module_dirs = \%{$self->{USED_MODULE_DIRS}};
  262. my @messages;
  263. foreach my $dir ($options->directories) {
  264. $dir = "$current_dir/$dir";
  265. $dir =~ s%/\.$%%;
  266. foreach my $module ($self->all_modules) {
  267. if(!$$used_module_dirs{$module}{$dir}) {
  268. my $spec_file = $$module2spec_file{$module};
  269. push @messages, "modules: $spec_file: directory ($dir) is not used\n";
  270. }
  271. }
  272. }
  273. foreach my $message (sort(@messages)) {
  274. $output->write($message);
  275. }
  276. }
  277. 1;