- A few more bug fixes
[wine] / tools / winapi / options.pm
1 package options;
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($options &parse_comma_list);
11
12 use vars qw($options);
13
14 sub parse_comma_list {
15     my $prefix = shift;
16     my $value = shift;
17     if(defined($prefix) && $prefix eq "no") {
18         return { active => 0, filter => 0, hash => {} };
19     } elsif(defined($value)) {
20         my %names;
21         for my $name (split /,/, $value) {
22             $names{$name} = 1;
23         }
24         return { active => 1, filter => 1, hash => \%names };
25     } else {
26         return { active => 1, filter => 0, hash => {} };
27     }
28 }
29
30 package _options;
31
32 use strict;
33
34 use config qw($current_dir $wine_dir);
35 use output qw($output);
36
37 sub new {
38     my $proto = shift;
39     my $class = ref($proto) || $proto;
40     my $self  = {};
41     bless ($self, $class);
42
43     my $options_long = \%{$self->{_OPTIONS_LONG}};
44     my $options_short = \%{$self->{_OPTIONS_SHORT}};
45     my $options_usage = \${$self->{_OPTIONS_USAGE}};
46
47     my $refoptions_long = shift;
48     my $refoptions_short = shift;
49     $$options_usage = shift;
50
51     %$options_long = %{$refoptions_long};
52     %$options_short = %{$refoptions_short};
53
54     $self->options_set("default");
55
56     my $arguments = \@{$self->{_ARGUMENTS}};
57
58     my $end_of_options = 0;
59     while(defined($_ = shift @ARGV)) {
60         if(/^--$/) {
61             $end_of_options = 1;
62             next;
63         } elsif($end_of_options) {
64             # Nothing
65         } elsif(/^--(all|none)$/) {
66             $self->options_set("$1");
67             next;
68         } elsif(/^-([^=]*)(=(.*))?$/) {
69             my $name;
70             my $value;
71             if(defined($2)) {
72                 $name = $1;
73                 $value = $3;
74             } else {
75                 $name = $1;
76             }
77             
78             if($name =~ /^([^-].*)$/) {
79                 $name = $$options_short{$1};
80             } else {
81                 $name =~ s/^-(.*)$/$1/;
82             }
83                    
84             my $prefix;
85             if(defined($name) && $name =~ /^no-(.*)$/) {
86                 $name = $1;
87                 $prefix = "no";
88                 if(defined($value)) {
89                     $output->write("options with prefix 'no' can't take parameters\n");
90
91                     return undef;
92                 }
93             }
94
95             my $option;
96             if(defined($name)) {
97                 $option = $$options_long{$name};
98             }
99
100             if(defined($option)) {
101                 my $key = $$option{key};
102                 my $parser = $$option{parser};
103                 my $refvalue = \${$self->{$key}};
104                 my @parents = ();
105                 
106                 if(defined($$option{parent})) {
107                     if(ref($$option{parent}) eq "ARRAY") {
108                         @parents = @{$$option{parent}};
109                     } else {
110                         @parents = $$option{parent};
111                     }
112                 }
113
114                 if(defined($parser)) { 
115                     $$refvalue = &$parser($prefix,$value);
116                 } else {
117                     if(defined($value)) {
118                         $$refvalue = $value;
119                     } elsif(!defined($prefix)) {
120                         $$refvalue = 1;
121                     } else {
122                         $$refvalue = 0;
123                     }
124                 }
125
126                 if((ref($$refvalue) eq "HASH" && $$refvalue->{active}) || $$refvalue) {
127                     while($#parents >= 0) {
128                         my @old_parents = @parents;
129                         @parents = ();
130                         foreach my $parent (@old_parents) {
131                             my $parentkey = $$options_long{$parent}{key};
132                             my $refparentvalue = \${$self->{$parentkey}};
133                             
134                             $$refparentvalue = 1;
135
136                             if(defined($$options_long{$parent}{parent})) {
137                                 if(ref($$options_long{$parent}{parent}) eq "ARRAY") {
138                                     push @parents, @{$$options_long{$parent}{parent}};
139                                 } else {
140                                     push @parents, $$options_long{$parent}{parent};
141                                 }
142                             }
143                         }
144                     }
145                 }
146                 next;
147             }
148         }
149         
150         if(!$end_of_options && /^-(.*)$/) {
151             $output->write("unknown option: $_\n"); 
152             $output->write($$options_usage);
153             exit 1;
154         } else {
155             push @$arguments, $_;
156         }
157     }
158
159     if($self->help) {
160         $output->write($$options_usage);
161         $self->show_help;
162         exit 0;
163     }
164
165     return $self;
166 }
167
168 sub DESTROY {
169 }
170
171 sub parse_files {
172     my $self = shift;
173
174     my $arguments = \@{$self->{_ARGUMENTS}};
175     my $c_files = \@{$self->{_C_FILES}};
176     my $h_files = \@{$self->{_H_FILES}};
177
178     my $error = 0;
179     my @files = ();
180     foreach (@$arguments) {
181         if(!-e $_) {
182             $output->write("$_: no such file or directory\n");
183             $error = 1;
184         } else {
185             push @files, $_;
186         }
187     }
188     if($error) {
189         exit 1;
190     }
191
192     my @paths = ();
193     my @c_files = ();
194     my @h_files = ();
195     foreach my $file (@files) {
196         if($file =~ /\.c$/) {
197             push @c_files, $file;
198         } elsif($file =~ /\.h$/) {
199             push @h_files, $file;
200         } else {
201             push @paths, $file;
202         }
203     }
204
205     if($#c_files == -1 && $#h_files == -1 && $#paths == -1)
206     {
207         @paths = ".";
208     }
209
210     if($#paths != -1 || $#c_files != -1) {
211         my $c_command = "find " . join(" ", @paths, @c_files) . " -name \\*.c";
212         my %found;
213         @$c_files = sort(map {
214             s/^\.\/(.*)$/$1/;
215             if(defined($found{$_})) {
216                 ();
217             } else {
218                 $found{$_}++;
219                 $_;
220             }
221         } split(/\n/, `$c_command`));
222     }
223
224     if($#paths != -1 || $#h_files != -1) {
225         my $h_command = "find " . join(" ", @paths, @h_files) . " -name \\*.h";
226         my %found;
227
228         @$h_files = sort(map {
229             s/^\.\/(.*)$/$1/;
230             if(defined($found{$_})) {
231                 ();
232             } else {
233                 $found{$_}++;
234                 $_;
235             }
236         } split(/\n/, `$h_command`));
237     }
238 }
239
240 sub options_set {
241     my $self = shift;
242
243     my $options_long = \%{$self->{_OPTIONS_LONG}};
244     my $options_short = \%{$self->{_OPTIONS_SHORT}};
245
246     local $_ = shift;
247     for my $name (sort(keys(%$options_long))) {
248         my $option = $$options_long{$name};
249         my $key = uc($name);
250         $key =~ tr/-/_/;
251         $$option{key} = $key;
252         my $refvalue = \${$self->{$key}};
253
254         if(/^default$/) {
255             $$refvalue = $$option{default};
256         } elsif(/^all$/) {
257             if($name !~ /^help|debug|verbose|module$/) {
258                 if(ref($$refvalue) ne "HASH") {
259                     $$refvalue = 1;
260                 } else {
261                     $$refvalue = { active => 1, filter => 0, hash => {} };
262                 }
263             }
264         } elsif(/^none$/) {
265             if($name !~ /^help|debug|verbose|module$/) {
266                 if(ref($$refvalue) ne "HASH") {
267                     $$refvalue = 0;
268                 } else {
269                     $$refvalue = { active => 0, filter => 0, hash => {} };
270                 }
271             }
272         }
273     }
274 }
275
276 sub show_help {
277     my $self = shift;
278
279     my $options_long = \%{$self->{_OPTIONS_LONG}};
280     my $options_short = \%{$self->{_OPTIONS_SHORT}};
281
282     my $maxname = 0;
283     for my $name (sort(keys(%$options_long))) {
284         if(length($name) > $maxname) {
285             $maxname = length($name);
286         }
287     }
288
289     for my $name (sort(keys(%$options_long))) {
290         my $option = $$options_long{$name};
291         my $description = $$option{description};
292         my $default = $$option{default};
293         my $current = ${$self->{$$option{key}}};
294
295         my $value = $current;
296         
297         my $command;
298         if(ref($value) ne "HASH") {
299             if($value) {
300                 $command = "--no-$name";
301             } else {
302                 $command = "--$name";
303             }
304         } else {
305             if($value->{active}) {
306                 $command = "--[no-]$name\[=<value>]";
307             } else {
308                 $command = "--$name\[=<value>]";
309             }
310         }
311
312         $output->write($command);
313         for (0..(($maxname - length($name) + 17) - (length($command) - length($name) + 1))) { $output->write(" "); }
314         if(ref($value) ne "HASH") {
315             if($value) {
316                 $output->write("Disable ");
317             } else {
318                 $output->write("Enable ");
319             }    
320         } else {
321             if($value->{active}) {
322                 $output->write("(Disable) ");
323             } else {
324                 $output->write("Enable ");
325             }
326         }
327         if($default == $current) {
328             $output->write("$description (default)\n");
329         } else {
330             $output->write("$description\n");
331         }    
332     }
333 }
334
335 sub AUTOLOAD {
336     my $self = shift;
337
338     my $name = $_options::AUTOLOAD;
339     $name =~ s/^.*::(.[^:]*)$/\U$1/;
340
341     my $refvalue = $self->{$name};
342     if(!defined($refvalue)) {
343         die "<internal>: options.pm: member $name does not exists\n"; 
344     }
345
346     if(ref($$refvalue) ne "HASH") {
347         return $$refvalue;
348     } else {
349         return $$refvalue->{active};
350     }
351 }
352
353 sub arguments { 
354     my $self = shift;
355
356     my $arguments = \@{$self->{_ARGUMENTS}};
357
358     return @$arguments; 
359 }
360
361 sub c_files {
362     my $self = shift; 
363
364     my $c_files = \@{$self->{_C_FILES}};
365
366     if(!defined(@$c_files)) {
367         $self->parse_files;
368     }
369
370     return @$c_files;
371 }
372
373 sub h_files { 
374     my $self = shift; 
375
376     my $h_files = \@{$self->{_H_FILES}};
377
378     if(!defined(@$h_files)) {
379         $self->parse_files;
380     }
381
382     return @$h_files;
383 }
384
385 1;