Changed the GDI driver interface to pass an opaque PHYSDEV pointer
[wine] / tools / winapi_check / winapi_options.pm
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 #
18
19 package winapi_options;
20
21 use strict;
22
23 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
24 require Exporter;
25
26 @ISA = qw(Exporter);
27 @EXPORT = qw(&parse_comma_list);
28 @EXPORT_OK = qw($options);
29
30 use vars qw($options);
31
32 use config qw($current_dir $wine_dir);
33 use output qw($output);
34
35 sub parser_comma_list {
36     my $prefix = shift;
37     my $value = shift;
38     if(defined($prefix) && $prefix eq "no") {
39         return { active => 0, filter => 0, hash => {} };
40     } elsif(defined($value)) {
41         my %names;
42         for my $name (split /,/, $value) {
43             $names{$name} = 1;
44         }
45         return { active => 1, filter => 1, hash => \%names };
46     } else {
47         return { active => 1, filter => 0, hash => {} };
48     }
49 }
50
51 my %options = (
52     "debug" => { default => 0, description => "debug mode" },
53     "help" => { default => 0, description => "help mode" },
54     "verbose" => { default => 0, description => "verbose mode" },
55
56     "progress" => { default => 1, description => "show progress" },
57
58     "win16" => { default => 1, description => "Win16 checking" },
59     "win32" => { default => 1, description => "Win32 checking" },
60
61     "shared" =>  { default => 0, description => "show shared functions between Win16 and Win32" },
62     "shared-segmented" =>  { default => 0, description => "segmented shared functions between Win16 and Win32 checking" },
63
64     "config" => { default => 1, parent => "local", description => "check configuration include consistancy" },
65     "config-unnessary" => { default => 0, parent => "config", description => "check for unnessary #include \"config.h\"" },
66
67     "spec-mismatch" => { default => 0, description => "spec file mismatch checking" },
68
69     "local" =>  { default => 1, description => "local checking" },
70     "module" => { 
71         default => { active => 1, filter => 0, hash => {} },
72         parent => "local",
73         parser => \&parser_comma_list,
74         description => "module filter"
75     },
76
77     "argument" => { default => 1, parent => "local", description => "argument checking" },
78     "argument-count" => { default => 1, parent => "argument", description => "argument count checking" },
79     "argument-forbidden" => {
80         default => { active => 1, filter => 0, hash => {} },
81         parent => "argument",
82         parser => \&parser_comma_list,
83         description => "argument forbidden checking"
84     },
85     "argument-kind" => {
86         default => { active => 1, filter => 1, hash => { double => 1 } },
87         parent => "argument",
88         parser => \&parser_comma_list,
89         description => "argument kind checking"
90     },
91     "calling-convention" => { default => 1, parent => "local", description => "calling convention checking" },
92     "calling-convention-win16" => { default => 0, parent => "calling-convention", description => "calling convention checking (Win16)" },
93     "calling-convention-win32" => { default => 1, parent => "calling-convention", description => "calling convention checking (Win32)" },
94     "misplaced" => { default => 1, parent => "local", description => "check for misplaced functions" },
95     "statements"  => { default => 0, parent => "local", description => "check for statements inconsistances" },
96     "cross-call" => { default => 0, parent => "statements",  description => "check for cross calling functions" },
97     "cross-call-win32-win16" => { 
98         default => 0, parent => "cross-call", description => "check for cross calls between win32 and win16"
99      },
100     "cross-call-unicode-ascii" => { 
101         default => 0, parent => "cross-call", description => "check for cross calls between Unicode and ASCII" 
102     },
103     "debug-messages" => { default => 0, parent => "statements", description => "check for debug messages inconsistances" },
104
105     "documentation" => {
106         default => 1,
107         parent => "local", 
108         description => "check for documentation inconsistances"
109         },
110     "documentation-pedantic" => { 
111         default => 0, 
112         parent => "documentation", 
113         description => "be pendantic when checking for documentation inconsistances"
114         },
115
116     "documentation-arguments" => {
117         default => 1,
118         parent => "documentation",
119         description => "check for arguments documentation inconsistances\n"
120         },
121     "documentation-comment-indent" => {
122         default => 0, 
123         parent => "documentation", description => "check for documentation comment indent inconsistances"
124         },
125     "documentation-comment-width" => {
126         default => 0, 
127         parent => "documentation", description => "check for documentation comment width inconsistances"
128         },
129     "documentation-name" => {
130         default => 1,
131         parent => "documentation",
132         description => "check for documentation name inconsistances\n"
133         },
134     "documentation-ordinal" => {
135         default => 1,
136         parent => "documentation",
137         description => "check for documentation ordinal inconsistances\n"
138         },
139     "documentation-wrong" => {
140         default => 1,
141         parent => "documentation",
142         description => "check for wrong documentation\n"
143         },
144
145     "prototype" => {default => 0, parent => ["local", "headers"], description => "prototype checking" },
146     "global" => { default => 1, description => "global checking" },
147     "declared" => { default => 1, parent => "global", description => "declared checking" },
148     "implemented" => { default => 0, parent => "local", description => "implemented checking" },
149     "implemented-win32" => { default => 0, parent => "implemented", description => "implemented as win32 checking" },
150     "include" => { default => 1, parent => "global", description => "include checking" },
151
152     "headers" => { default => 0, description => "headers checking" },
153     "headers-duplicated" => { default => 0, parent => "headers", description => "duplicated function declarations checking" },
154     "headers-misplaced" => { default => 0, parent => "headers", description => "misplaced function declarations checking" },
155     "headers-needed" => { default => 1, parent => "headers", description => "headers needed checking" },
156     "headers-unused" => { default => 0, parent => "headers", description => "headers unused checking" },
157 );
158
159 my %short_options = (
160     "d" => "debug",
161     "?" => "help",
162     "v" => "verbose"
163 );
164
165 sub new {
166     my $proto = shift;
167     my $class = ref($proto) || $proto;
168     my $self  = {};
169     bless ($self, $class);
170
171     $self->options_set("default");
172
173     my $c_files = \@{$self->{C_FILES}};
174     my $h_files = \@{$self->{H_FILES}};
175     my $module = \${$self->{MODULE}};
176     my $global = \${$self->{GLOBAL}};
177     my $headers = \${$self->{HEADERS}};
178
179     my @files;
180
181     if($wine_dir eq ".") {
182         $$global = 1;
183     } else {
184         $$global = 0;
185     }
186
187     while(defined($_ = shift @ARGV)) {
188         if(/^--(all|none)$/) {
189             $self->options_set("$1");
190             next;
191         } elsif(/^-([^=]*)(=(.*))?$/) {
192             my $name;
193             my $value;
194             if(defined($2)) {
195                 $name = $1;
196                 $value = $3;
197             } else {
198                 $name = $1;
199             }
200             
201             if($name =~ /^([^-].*)$/) {
202                 $name = $short_options{$1};
203             } else {
204                 $name =~ s/^-(.*)$/$1/;
205             }
206                    
207             my $prefix;
208             if(defined($name) && $name =~ /^no-(.*)$/) {
209                 $name = $1;
210                 $prefix = "no";
211                 if(defined($value)) {
212                     $output->write("options with prefix 'no' can't take parameters\n");
213
214                     return undef;
215                 }
216             }
217
218             my $option;
219             if(defined($name)) {
220                 $option = $options{$name};
221             }
222
223             if(defined($option)) {
224                 my $key = $$option{key};
225                 my $parser = $$option{parser};
226                 my $refvalue = \${$self->{$key}};
227                 my @parents = ();
228                 
229                 if(defined($$option{parent})) {
230                     if(ref($$option{parent}) eq "ARRAY") {
231                         @parents = @{$$option{parent}};
232                     } else {
233                         @parents = $$option{parent};
234                     }
235                 }
236
237                 if(defined($parser)) { 
238                     $$refvalue = &$parser($prefix,$value);
239                 } else {
240                     if(defined($value)) {
241                         $$refvalue = $value;
242                     } elsif(!defined($prefix)) {
243                         $$refvalue = 1;
244                     } else {
245                         $$refvalue = 0;
246                     }
247                 }
248
249                 if((ref($$refvalue) eq "HASH" && $$refvalue->{active}) || $$refvalue) {
250                     while($#parents >= 0) {
251                         my @old_parents = @parents;
252                         @parents = ();
253                         foreach my $parent (@old_parents) {
254                             my $parentkey = $options{$parent}{key};
255                             my $refparentvalue = \${$self->{$parentkey}};
256                             
257                             $$refparentvalue = 1;
258
259                             if(defined($options{$parent}{parent})) {
260                                 if(ref($options{$parent}{parent}) eq "ARRAY") {
261                                     push @parents, @{$options{$parent}{parent}};
262                                 } else {
263                                     push @parents, $options{$parent}{parent};
264                                 }
265                             }
266                         }
267                     }
268                 }
269                 next;
270             }    
271         }
272         
273         if(/^--module-dlls$/) {
274             my @dirs = `cd dlls && find . -type d ! -name CVS`;
275             my %names;
276             for my $dir (@dirs) {
277                 chomp $dir;
278                 $dir =~ s/^\.\/(.*)$/$1/;
279                 next if $dir eq "";
280                 $names{$dir} = 1;
281             }
282             $$module = { active => 1, filter => 1, hash => \%names };
283         }       
284         elsif(/^-(.*)$/) {
285             $output->write("unknown option: $_\n"); 
286
287             return undef;
288         } else {
289             if(!-e $_) {
290                 $output->write("$_: no such file or directory\n");
291
292                 return undef;
293             }
294
295             push @files, $_;
296         }
297     }
298
299     if($self->help) {
300         return $self;
301     }
302
303     my @paths = ();
304     my @c_files = ();
305     my @h_files = ();
306     foreach my $file (@files) {
307         if($file =~ /\.c$/) {
308             push @c_files, $file;
309         } elsif($file =~ /\.h$/) {
310             push @h_files, $file;
311         } else {
312             push @paths, $file;
313         }
314     }
315
316     if($#h_files >= 0) {
317         $$headers = 1;
318     }
319
320     if($#c_files == -1 && $#h_files == -1 &&
321        ($#paths == -1 || ($#paths == 0 && $paths[0] eq $wine_dir)))
322     {
323         @paths = ".";
324     } else {
325         $$global = 0;
326     }
327
328     if($#paths != -1 || $#c_files != -1) {
329         my $c_command = "find " . join(" ", @paths, @c_files) . " -name \\*.c";
330         my %found;
331         @$c_files = sort(map {
332             s/^\.\/(.*)$/$1/;
333             if(defined($found{$_}) || /glue\.c|spec\.c$/) {
334                 ();
335             } else {
336                 $found{$_}++;
337                 $_;
338             }
339         } split(/\n/, `$c_command`));
340     }
341
342     if($#paths != -1 || $#h_files != -1) {
343         my $h_command = "find " . join(" ", @paths, @h_files) . " -name \\*.h";
344         my %found;
345
346         @$h_files = sort(map {
347             s/^\.\/(.*)$/$1/;
348             if(defined($found{$_})) {
349                 ();
350             } else {
351                 $found{$_}++;
352                 $_;
353             }
354         } split(/\n/, `$h_command`));
355     }
356
357     $options = $self;
358
359     return $self;
360 }
361
362 sub DESTROY {
363 }
364
365 sub options_set {
366     my $self = shift;
367
368     local $_ = shift;
369     for my $name (sort(keys(%options))) {
370         my $option = $options{$name};
371         my $key = uc($name);
372         $key =~ tr/-/_/;
373         $$option{key} = $key;
374         my $refvalue = \${$self->{$key}};
375
376         if(/^default$/) {
377             $$refvalue = $$option{default};
378         } elsif(/^all$/) {
379             if($name !~ /^help|debug|verbose|module$/) {
380                 if(ref($$refvalue) ne "HASH") {
381                     $$refvalue = 1;
382                 } else {
383                     $$refvalue = { active => 1, filter => 0, hash => {} };
384                 }
385             }
386         } elsif(/^none$/) {
387             if($name !~ /^help|debug|verbose|module$/) {
388                 if(ref($$refvalue) ne "HASH") {
389                     $$refvalue = 0;
390                 } else {
391                     $$refvalue = { active => 0, filter => 0, hash => {} };
392                 }
393             }
394         }
395     }
396 }
397
398 sub show_help {
399     my $self = shift;
400
401     my $maxname = 0;
402     for my $name (sort(keys(%options))) {
403         if(length($name) > $maxname) {
404             $maxname = length($name);
405         }
406     }
407
408     print "usage: winapi-check [--help] [<files>]\n";
409     print "\n";
410     for my $name (sort(keys(%options))) {
411         my $option = $options{$name};
412         my $description = $$option{description};
413         my $default = $$option{default};
414         my $current = ${$self->{$$option{key}}};
415
416         my $value = $current;
417         
418         my $output;
419         if(ref($value) ne "HASH") {
420             if($value) {
421                 $output = "--no-$name";
422             } else {
423                 $output = "--$name";
424             }
425         } else {
426             if($value->{active}) {
427                 $output = "--[no-]$name\[=<value>]";
428             } else {
429                 $output = "--$name\[=<value>]";
430             }
431         }
432
433         print "$output";
434         for (0..(($maxname - length($name) + 17) - (length($output) - length($name) + 1))) { print " "; }
435         if(ref($value) ne "HASH") {
436             if($value) {
437                 print "Disable ";
438             } else {
439                 print "Enable ";
440             }    
441         } else {
442             if($value->{active}) {
443                 print "(Disable) ";
444             } else {
445                 print "Enable ";
446             }
447         }
448         if($default == $current) {
449             print "$description (default)\n";
450         } else {
451             print "$description\n";
452         }    
453     }
454 }
455
456 sub AUTOLOAD {
457     my $self = shift;
458
459     my $name = $winapi_options::AUTOLOAD;
460     $name =~ s/^.*::(.[^:]*)$/\U$1/;
461
462     my $refvalue = $self->{$name};
463     if(!defined($refvalue)) {
464         die "<internal>: winapi_options.pm: member $name does not exists\n"; 
465     }
466
467     if(ref($$refvalue) ne "HASH") {
468         return $$refvalue;
469     } else {
470         return $$refvalue->{active};
471     }
472 }
473
474 sub c_files { my $self = shift; return @{$self->{C_FILES}}; }
475
476 sub h_files { my $self = shift; return @{$self->{H_FILES}}; }
477
478 sub report_module {
479     my $self = shift;
480     my $refvalue = $self->{MODULE};
481     
482     my $name = shift;
483
484     if(defined($name)) {
485         return $$refvalue->{active} && (!$$refvalue->{filter} || $$refvalue->{hash}->{$name}); 
486     } else {
487         return 0;
488     } 
489 }
490
491 sub report_argument_forbidden {
492     my $self = shift;   
493     my $refargument_forbidden = $self->{ARGUMENT_FORBIDDEN};
494
495     my $type = shift;
496
497     return $$refargument_forbidden->{active} && (!$$refargument_forbidden->{filter} || $$refargument_forbidden->{hash}->{$type}); 
498 }
499
500 sub report_argument_kind {
501     my $self = shift;
502     my $refargument_kind = $self->{ARGUMENT_KIND};
503
504     my $kind = shift;
505
506     return $$refargument_kind->{active} && (!$$refargument_kind->{filter} || $$refargument_kind->{hash}->{$kind}); 
507
508 }
509
510 1;
511