| package winapi_options; | |
| use strict; | |
| sub parser_comma_list { | |
| my $prefix = shift; | |
| my $value = shift; | |
| if(defined($prefix) && $prefix eq "no") { | |
| return { active => 0, filter => 0, hash => {} }; | |
| } elsif(defined($value)) { | |
| my %names; | |
| for my $name (split /,/, $value) { | |
| $names{$name} = 1; | |
| } | |
| return { active => 1, filter => 1, hash => \%names }; | |
| } else { | |
| return { active => 1, filter => 0, hash => {} }; | |
| } | |
| } | |
| my %options = ( | |
| "debug" => { default => 0, description => "debug mode" }, | |
| "help" => { default => 0, description => "help mode" }, | |
| "verbose" => { default => 0, description => "verbose mode" }, | |
| "progress" => { default => 1, description => "show progress" }, | |
| "win16" => { default => 1, description => "Win16 checking" }, | |
| "win32" => { default => 1, description => "Win32 checking" }, | |
| "shared" => { default => 0, description => "show shared functions between Win16 and Win32" }, | |
| "shared-segmented" => { default => 0, description => "segmented shared functions between Win16 and Win32 checking" }, | |
| "config" => { default => 1, description => "check configuration include consistancy" }, | |
| "config-unnessary" => { default => 0, parent => "config", description => "check for unnessary #include \"config.h\"" }, | |
| "local" => { default => 1, description => "local checking" }, | |
| "module" => { | |
| default => { active => 1, filter => 0, hash => {} }, | |
| parent => "local", | |
| parser => \&parser_comma_list, | |
| description => "module filter" | |
| }, | |
| "argument" => { default => 1, parent => "local", description => "argument checking" }, | |
| "argument-count" => { default => 1, parent => "argument", description => "argument count checking" }, | |
| "argument-forbidden" => { | |
| default => { active => 1, filter => 0, hash => {} }, | |
| parent => "argument", | |
| parser => \&parser_comma_list, | |
| description => "argument forbidden checking" | |
| }, | |
| "argument-kind" => { | |
| default => { active => 0, filter => 0, hash => {} }, | |
| parent => "argument", | |
| parser => \&parser_comma_list, | |
| description => "argument kind checking" | |
| }, | |
| "calling-convention" => { default => 0, parent => "local", description => "calling convention checking" }, | |
| "misplaced" => { default => 0, parent => "local", description => "check for misplaced functions" }, | |
| "cross-call" => { default => 0, parent => "local", description => "check for cross calling functions" }, | |
| "documentation" => { default => 0, parent => "local", description => "check for documentation inconsistances\n" }, | |
| "global" => { default => 1, description => "global checking" }, | |
| "declared" => { default => 1, parent => "global", description => "declared checking" }, | |
| "implemented" => { default => 1, parent => "global", description => "implemented checking" }, | |
| "implemented-win32" => { default => 0, parent => "implemented", description => "implemented as win32 checking" }, | |
| "include" => { default => 1, parent => "global", description => "include checking" } | |
| ); | |
| my %short_options = ( | |
| "d" => "debug", | |
| "?" => "help", | |
| "v" => "verbose" | |
| ); | |
| sub new { | |
| my $proto = shift; | |
| my $class = ref($proto) || $proto; | |
| my $self = {}; | |
| bless ($self, $class); | |
| my $refarguments = shift; | |
| my @ARGV = @$refarguments; | |
| for my $name (sort(keys(%options))) { | |
| my $option = $options{$name}; | |
| my $key = uc($name); | |
| $key =~ tr/-/_/; | |
| $$option{key} = $key; | |
| my $refvalue = \${$self->{$key}}; | |
| $$refvalue = $$option{default}; | |
| } | |
| my $files = \@{$self->{FILES}}; | |
| my $module = \${$self->{MODULE}}; | |
| my $global = \${$self->{GLOBAL}}; | |
| $$global = 0; | |
| while(defined($_ = shift @ARGV)) { | |
| if(/^-([^=]*)(=(.*))?$/) { | |
| my $name; | |
| my $value; | |
| if(defined($2)) { | |
| $name = $1; | |
| $value = $3; | |
| } else { | |
| $name = $1; | |
| } | |
| if($name =~ /^([^-].*)$/) { | |
| $name = $short_options{$1}; | |
| } else { | |
| $name =~ s/^-(.*)$/$1/; | |
| } | |
| my $prefix; | |
| if($name =~ /^no-(.*)$/) { | |
| $name = $1; | |
| $prefix = "no"; | |
| if(defined($value)) { | |
| print STDERR "<internal>: options with prefix 'no' can't take parameters\n"; | |
| exit 1; | |
| } | |
| } | |
| my $option = $options{$name}; | |
| if(defined($option)) { | |
| my $key = $$option{key}; | |
| my $parser = $$option{parser}; | |
| my $refvalue = \${$self->{$key}}; | |
| if(defined($parser)) { | |
| $$refvalue = &$parser($prefix,$value); | |
| } else { | |
| if(defined($value)) { | |
| $$refvalue = $value; | |
| } elsif(!defined($prefix)) { | |
| $$refvalue = 1; | |
| } else { | |
| $$refvalue = 0; | |
| } | |
| } | |
| next; | |
| } | |
| } | |
| if(/^--module-dlls$/) { | |
| my @dirs = `cd dlls && find ./ -type d ! -name CVS`; | |
| my %names; | |
| for my $dir (@dirs) { | |
| chomp $dir; | |
| $dir =~ s/^\.\/(.*)$/$1/; | |
| next if $dir eq ""; | |
| $names{$dir} = 1; | |
| } | |
| $$module = { active => 1, filter => 1, hash => \%names }; | |
| } | |
| elsif(/^-(.*)$/) { | |
| print STDERR "<internal>: unknown option: $&\n"; | |
| print STDERR "<internal>: usage: winapi-check [--help] [<files>]\n"; | |
| exit 1; | |
| } else { | |
| push @$files, $_; | |
| } | |
| } | |
| my $paths; | |
| if($#$files == -1) { | |
| $paths = "."; | |
| $$global = 1; | |
| } else { | |
| $paths = join(" ",@$files); | |
| } | |
| @$files = map { | |
| s/^.\/(.*)$/$1/; | |
| if(!/spec\.c$/) { | |
| $_; | |
| } else { | |
| (); | |
| } | |
| } split(/\n/, `find $paths -name \\*.c`); | |
| return $self; | |
| } | |
| sub show_help { | |
| my $self = shift; | |
| my $maxname = 0; | |
| for my $name (sort(keys(%options))) { | |
| if(length($name) > $maxname) { | |
| $maxname = length($name); | |
| } | |
| } | |
| print "usage: winapi-check [--help] [<files>]\n"; | |
| print "\n"; | |
| for my $name (sort(keys(%options))) { | |
| my $option = $options{$name}; | |
| my $description = $$option{description}; | |
| my $default = $$option{default}; | |
| my $output; | |
| if(ref($default) ne "HASH") { | |
| if($default) { | |
| $output = "--no-$name"; | |
| } else { | |
| $output = "--$name"; | |
| } | |
| } else { | |
| if($default->{active}) { | |
| $output = "--[no-]$name\[=<value>]"; | |
| } else { | |
| $output = "--$name\[=<value>]"; | |
| } | |
| } | |
| print "$output"; | |
| for (0..(($maxname - length($name) + 14) - (length($output) - length($name) + 1))) { print " "; } | |
| if(ref($default) ne "HASH") { | |
| if($default) { | |
| print "Disable $description\n"; | |
| } else { | |
| print "Enable $description\n"; | |
| } | |
| } else { | |
| if($default->{active}) { | |
| print "(Disable) $description\n"; | |
| } else { | |
| print "Enable $description\n"; | |
| } | |
| } | |
| } | |
| } | |
| sub AUTOLOAD { | |
| my $self = shift; | |
| my $name = $winapi_options::AUTOLOAD; | |
| $name =~ s/^.*::(.[^:]*)$/\U$1/; | |
| my $refvalue = $self->{$name}; | |
| if(!defined($refvalue)) { | |
| die "<internal>: winapi_options.pm: member $name does not exists\n"; | |
| } | |
| return $$refvalue; | |
| } | |
| sub files { my $self = shift; return @{$self->{FILES}}; } | |
| sub report_module { | |
| my $self = shift; | |
| my $module = $self->module; | |
| my $name = shift; | |
| if(defined($name)) { | |
| return $module->{active} && (!$module->{filter} || $module->{hash}->{$name}); | |
| } else { | |
| return 0; | |
| } | |
| } | |
| sub report_argument_forbidden { | |
| my $self = shift; | |
| my $argument_forbidden = $self->argument_forbidden; | |
| my $type = shift; | |
| return $argument_forbidden->{active} && (!$argument_forbidden->{filter} || $argument_forbidden->{hash}->{$type}); | |
| } | |
| sub report_argument_kind { | |
| my $self = shift; | |
| my $argument_kind = $self->argument_kind; | |
| my $kind = shift; | |
| return $argument_kind->{active} && (!$argument_kind->{filter} || $argument_kind->{hash}->{$kind}); | |
| } | |
| 1; | |