- A few more bug fixes

- Reorganization continues
- New tool (make_filter) for filtering make output added
This commit is contained in:
Patrik Stridvall 2001-07-26 21:42:12 +00:00 committed by Alexandre Julliard
parent 9a57ef4de1
commit 67f0a70c33
18 changed files with 1418 additions and 477 deletions

View File

@ -10,9 +10,10 @@ require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(
&file_absolutize &file_normalize
&file_directory
&file_type &files_filter
&file_skip &files_skip
&get_c_files &get_h_files &get_spec_files
&file_skip &files_skip
&get_api_files &get_c_files &get_h_files &get_spec_files
);
@EXPORT_OK = qw(
$current_dir $wine_dir $winapi_dir $winapi_check_dir
@ -22,6 +23,8 @@ use vars qw($current_dir $wine_dir $winapi_dir $winapi_check_dir);
use output qw($output);
use File::Find;
sub file_type {
local $_ = shift;
@ -30,7 +33,7 @@ sub file_type {
m%^(?:libtest|rc|server|tests|tools)/% && return "";
m%^(?:programs|debugger|miscemu)/% && return "wineapp";
m%^(?:library|tsx11|unicode)/% && return "library";
m%^windows/x11drv/wineclipsrv.c% && return "application";
m%^windows/x11drv/wineclipsrv\.c$% && return "application";
return "winelib";
}
@ -56,8 +59,9 @@ sub file_skip {
m%^(?:libtest|programs|rc|server|tests|tools)/% && return 1;
m%^(?:debugger|miscemu|tsx11|server|unicode)/% && return 1;
m%^dlls/wineps/data/% && return 1;
m%^windows/x11drv/wineclipsrv.c% && return 1;
m%^dlls/winmm/wineoss/midipatch.c% && return 1;
m%^windows/x11drv/wineclipsrv\.c$% && return 1;
m%^dlls/winmm/wineoss/midipatch\.c$% && return 1;
m%(?:glue|spec)\.c$% && return 1;
return 0;
}
@ -98,25 +102,57 @@ sub file_normalize {
return $_;
}
sub file_directory {
my $file = shift;
$file =~ s%^./%%;
my $dir = $file;
$dir =~ s%/?[^/]*$%%;
if(!$dir) {
$dir = ".";
}
return $dir;
}
sub _get_files {
my $extension = shift;
my $type = shift;
my $dir = shift;
$output->progress("$wine_dir: searching for *.$extension");
my @files = map {
s%^\./%%;
s%^$wine_dir/%%;
if(file_type($_) eq $type) {
$_;
} else {
();
if(!defined($dir)) {
$dir = $wine_dir;
}
my @files;
my @dirs = ($dir);
while(defined(my $dir = shift @dirs)) {
opendir(DIR, $dir);
my @entries= readdir(DIR);
closedir(DIR);
foreach (@entries) {
$_ = "$dir/$_";
if(/\.\.?$/) {
# Nothing
} elsif(-d $_) {
push @dirs, $_;
} elsif(/\.$extension$/ && (!defined($type) || file_type($_) eq $type)) {
s%^$wine_dir/%%;
push @files, $_;
}
}
} split(/\n/, `find $wine_dir -name \\*.$extension`);
}
return @files;
}
sub get_api_files {
my $name = shift;
return _get_files("api", undef, "$winapi_check_dir/$name");
}
sub get_c_files { return _get_files("c", @_); }
sub get_h_files { return _get_files("h", @_); }
sub get_spec_files { return _get_files("spec", @_); }

70
tools/winapi/make_filter Executable file
View File

@ -0,0 +1,70 @@
#! /usr/bin/perl -w
use strict;
BEGIN {
$0 =~ m%^(.*?/?tools)/winapi/make_filter$%;
require "$1/winapi/setup.pm";
}
use config qw($current_dir $wine_dir);
use output qw($output);
use make_filter_options qw($options);
use make_parser;
if($options->progress) {
$output->enable_progress;
} else {
$output->disable_progress;
}
########################################################################
# main
########################################################################
my $command = join(" ", $options->arguments);
open(IN, "($command) 2>&1 |");
while(<IN>) {
chomp;
if(!&make_parser::line($_)) {
next;
}
my $directory = &make_parser::directory();
my $file = &make_parser::file_name();
my $line = &make_parser::file_line();
my $message = &make_parser::message();
if(&make_parser::tool() eq "make") {
if($directory && $directory ne ".") {
$output->progress("$directory: make");
}
} elsif($message) {
if($file && $line) {
if($directory) {
$output->write("$directory/$file:$line: $message\n");
} else {
$output->write("$file:$line: $message\n");
}
} elsif($file) {
if($directory) {
$output->write("$directory/$file: $message\n");
} else {
$output->write("$file: $message\n");
}
} else {
if($directory) {
$output->write("$directory: " . &make_parser::tool() . ": $message\n");
} else {
$output->write(".: " . &make_parser::tool() . ": $message\n");
}
}
}
}
close(IN);
$output->hide_progress();

View File

@ -0,0 +1,35 @@
package make_filter_options;
use base qw(options);
use strict;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw();
@EXPORT_OK = qw($options);
use options qw($options &parse_comma_list);
my %options_long = (
"debug" => { default => 0, description => "debug mode" },
"help" => { default => 0, description => "help mode" },
"verbose" => { default => 0, description => "verbose mode" },
"progress" => { default => 1, description => "show progress" },
"pedantic" => { default => 0, description => "be pedantic" },
);
my %options_short = (
"d" => "debug",
"?" => "help",
"v" => "verbose"
);
my $options_usage = "usage: make_filter [--help]\n";
$options = '_options'->new(\%options_long, \%options_short, $options_usage);
1;

664
tools/winapi/make_parser.pm Normal file
View File

@ -0,0 +1,664 @@
package make_parser;
use strict;
use output qw($output);
########################################################################
# global
########################################################################
my $current;
my $tool;
my $directory;
my $file;
my $line;
my $function;
my $message;
sub directory { return $directory; }
sub tool { return $tool; }
sub file_name { return $file; }
sub file_line { return $line; }
sub message { return $message; }
########################################################################
# error
########################################################################
sub error {
$output->write("make_filter: $tool: can't parse output: '$current'\n");
exit 1;
}
########################################################################
# line
########################################################################
sub line {
local $_ = shift;
$file = "";
$line = "";
$message = "";
$current = $_;
my ($new_tool, $read_files, $write_files, $remove_files) = command($_);
if(defined($new_tool)) {
$tool = $new_tool;
$function = "";
my $progress = "$directory: $tool: ";
if($#$read_files >= 0) {
$progress .= "read[" . join(" ", @{$read_files}) . "]";
}
if($#$write_files >= 0) {
if($#$read_files >= 0) {
$progress .= ", ";
}
$progress .= "write[" . join(" ", @{$write_files}) . "]";
}
if($#$remove_files >= 0) {
if($#$read_files >= 0 || $#$write_files >= 0) {
$progress .= ", ";
}
$progress .= "remove[" . join(" ", @{$remove_files}) . "]";
}
if($tool =~ /^cd|make$/) {
# Nothing
} elsif($tool =~ /^ld$/) {
$progress =~ s/read\[.*?\]/read[*.o]/; # FIXME: Kludge
$output->progress($progress)
} else {
$output->progress($progress)
}
return 0;
}
if(/^Wine build complete\.$/) {
# Nothing
} elsif(s/^make\[(\d+)\]:\s*//) {
$tool = "make";
make_output($1, $_);
} elsif($tool eq "bison" && /^conflicts:\s+\d+\s+shift\/reduce$/) {
# Nothing
} elsif($tool eq "gcc" && /^In file included from (.+?):(\d+):$/) {
# Nothing
} elsif($tool =~ /^gcc|ld$/ && s/^(.+?\.o(?:\(.*?\))?):\s*//) {
ld_output($1, $_)
} elsif($tool eq "gcc" && s/^(.+?\.[chly]):\s*//) {
gcc_output($1, $_);
} elsif($tool eq "winebuild" && s/^(.+?\.spec):\s*//) {
winebuild_output($1, $_);
} elsif($tool eq "wmc" && s/^(.+?\.mc):\s*//) {
wmc_output($1, $_);
} elsif($tool eq "wrc" && s/^(.+?\.rc):\s*//) {
wrc_output($1, $_);
} elsif($tool eq "cd" && s/^\/bin\/sh:\s*cd:\s*//) {
parse_cd_output($_);
} else {
error($_)
}
$file =~ s/^\.\///;
return 1;
}
########################################################################
# make_output
########################################################################
sub make_output {
my $level = shift;
local $_ = shift;
$file = "";
$message = "";
if(0) {
# Nothing
} elsif(/^\*\*\* \[(.*?)\] Error (\d+)$/) {
# Nothing
} elsif(/^\*\*\* Warning:\s+/) { #
if(/^File \`(.+?)\' has modification time in the future \((.+?) > \(.+?\)\)$/) {
# Nothing
} else {
error();
}
} elsif(/^\`(.*?)\' is up to date.$/) {
# Nothing
} elsif(/^\[(.*?)\] Error (\d+) \(ignored\)$/) {
# Nothing
} elsif(/^(Entering|Leaving) directory \`(.*?)\'$/) {
if($1 eq "Entering") {
$directory = $2;
} else {
$directory = "";
}
my @components;
foreach my $component (split(/\//, $directory)) {
if($component eq "wine") {
@components = ();
} else {
push @components, $component;
}
}
$directory = join("/", @components);
} elsif(/^Nothing to be done for \`(.*?)\'.$/) {
# Nothing
} elsif(s/^warning:\s+//) {
if(/^Clock skew detected. Your build may be incomplete.$/) {
# Nothing
} else {
error();
}
} else {
error();
}
}
########################################################################
# command
########################################################################
sub command {
local $_ = shift;
my $tool;
my $file;
my $read_files = ["<???>"];
my $write_files = ["<???>"];
my $remove_files = [];
s/^\s*(.*?)\s*$/$1/;
if(s/^\[\s+-d\s+(.*?)\s+\]\s+\|\|\s+//) {
# Nothing
}
if(s/^ar\s*//) {
$tool = "ar";
($read_files, $write_files) = ar_command($_);
} elsif(s/^as\s*//) {
$tool = "as";
($read_files, $write_files) = as_command($_);
} elsif(s/^bison\s*//) {
$tool = "bison";
($read_files, $write_files) = bison_command($_);
} elsif(s/^cd\s*//) {
$tool = "cd";
($read_files, $write_files) = cd_command($_);
} elsif(s/^flex\s*//) {
$tool = "flex";
($read_files, $write_files) = flex_command($_);
} elsif(s/^for\s*//) {
$tool = "for";
($read_files, $write_files) = for_command($_);
} elsif(s/^\/usr\/bin\/install\s*//) {
$tool = "install";
($read_files, $write_files) = install_command($_);
} elsif(s/^ld\s*//) {
$tool = "ld";
($read_files, $write_files) = ld_command($_);
} elsif(s/^\/sbin\/ldconfig\s*//) {
$tool = "ldconfig";
($read_files, $write_files) = ldconfig_command();
} elsif(s/^gcc\s*//) {
$tool = "gcc";
($read_files, $write_files) = gcc_command($_);
} elsif(s/^(?:(?:\.\.\/)+|\.\/)tools\/makedep\s*//) {
$tool = "makedep";
($read_files, $write_files) = makedep_command($_);
} elsif(s/^mkdir\s*//) {
$tool = "mkdir";
($read_files, $write_files) = mkdir_command($_);
} elsif(s/^ranlib\s*//) {
$tool = "ranlib";
($read_files, $write_files) = ranlib_command($_);
} elsif(s/^rm\s*//) {
$tool = "rm";
($read_files, $write_files, $remove_files) = rm_command($_);
} elsif(s/^sed\s*//) {
$tool = "sed";
($read_files, $write_files) = sed_command($_);
} elsif(s/^strip\s*//) {
$tool = "sed";
($read_files, $write_files) = strip_command($_);
} elsif(s/^LD_LIBRARY_PATH="(?:(?:\.\.\/)*unicode)?:\$LD_LIBRARY_PATH"\s+(?:\.\.\/)*tools\/winebuild\/winebuild\s*//) {
$tool = "winebuild";
($read_files, $write_files) = winebuild_command($_);
} elsif(s/^LD_LIBRARY_PATH="(?:(?:\.\.\/)*unicode)?:\$LD_LIBRARY_PATH"\s+(?:\.\.\/)*tools\/wmc\/wmc\s*//) {
$tool = "wmc";
($read_files, $write_files) = wmc_command($_);
} elsif(s/^LD_LIBRARY_PATH="(?:(?:\.\.\/)*unicode)?:\$LD_LIBRARY_PATH"\s+(?:\.\.\/)*tools\/wrc\/wrc\s*//) {
$tool = "wrc";
($read_files, $write_files) = wrc_command($_);
}
return ($tool, $read_files, $write_files, $remove_files);
}
########################################################################
# ar_command
########################################################################
sub ar_command {
local $_ = shift;
my $read_files;
my $write_files;
if(/rc\s+(\S+)(\s+\S+)+$/) {
$write_files = [$1];
$read_files = $2;
$read_files =~ s/^\s*//;
$read_files = [split(/\s+/, $read_files)];
} else {
error();
}
return ($read_files, $write_files);
}
########################################################################
# as_command
########################################################################
sub as_command {
local $_ = shift;
my $read_files;
my $write_files;
if(/-o\s+(\S+)\s+(\S+)$/) {
$write_files = [$1];
$read_files = [$2];
} else {
error();
}
return ($read_files, $write_files);
}
########################################################################
# bision_command
########################################################################
sub bison_command {
local $_ = shift;
return ([], []);
}
########################################################################
# cd_command
########################################################################
sub cd_command {
local $_ = shift;
return ([], []);
}
########################################################################
# cd_output
########################################################################
sub cd_output {
local $_ = shift;
if(/^(.*?): No such file or directory/) {
$message = "directory '$1' doesn't exist";
}
}
########################################################################
# flex_command
########################################################################
sub flex_command {
local $_ = shift;
return ([], []);
}
########################################################################
# for_command
########################################################################
sub for_command {
local $_ = shift;
return ([], []);
}
########################################################################
# gcc_command
########################################################################
sub gcc_command {
my $read_files;
my $write_files;
if(/-o\s+(\S+)\s+(\S+)$/) {
$write_files = [$1];
$read_files = [$2];
} elsif(/-o\s+(\S+)/) {
$write_files = [$1];
$read_files = ["<???>"];
} elsif(/^-shared.*?-o\s+(\S+)/) {
$write_files = [$1];
$read_files = ["<???>"];
} else {
error();
}
return ($read_files, $write_files);
}
########################################################################
# gcc_output
########################################################################
sub gcc_output {
$file = shift;
local $_ = shift;
if(s/^(\d+):\s+//) {
$line = $1;
if(s/^warning:\s+//) {
my $supress = 0;
if(0) {
# Nothing
} elsif(/^\(near initialization for \`(.*?)\'\)$/) {
$supress = 0;
} elsif(/^\`(.*?)\' defined but not used$/) {
$supress = 0;
} elsif(/^\`(.*?)\' is not at beginning of declaration$/) {
$supress = 0;
} elsif(/^\`%x\' yields only last 2 digits of year in some locales$/) {
$supress = 1;
} elsif(/^(.*?) format, different type arg \(arg (\d+)\)$/) {
$supress = 0;
} elsif(/^assignment from incompatible pointer type$/) {
$supress = 0;
} elsif(/^comparison between signed and unsigned$/) {
$supress = 0;
} elsif(/^comparison of unsigned expression < 0 is always false$/) {
$supress = 0;
} elsif(/^comparison of unsigned expression >= 0 is always true$/) {
$supress = 0;
} elsif(/^conflicting types for built-in function \`(.*?)\'$/) {
$supress = 0;
} elsif(/^empty body in an if-statement$/) {
$supress = 0;
} elsif(/^empty body in an else-statement$/) {
$supress = 0;
} elsif(/^implicit declaration of function \`(.*?)\'$/) {
$supress = 0;
} elsif(/^initialization from incompatible pointer type$/) {
$supress = 0;
} elsif(/^missing initializer$/) {
$supress = 0;
} elsif(/^ordered comparison of pointer with integer zero$/) {
$supress = 0;
} elsif(/^passing arg (\d+) of pointer to function from incompatible pointer type$/) {
$supress = 0;
} elsif(/^passing arg (\d+) of \`(\S+)\' from incompatible pointer type$/) {
$supress = 0;
} elsif(/^passing arg (\d+) of \`(\S+)\' makes integer from pointer without a cast$/) {
$supress = 0;
} elsif(/^type of \`(.*?)\' defaults to \`(.*?)\'$/) {
$supress = 0;
} else {
error();
}
if(!$supress) {
if($function) {
$message = "function $function: $_";
} else {
$message = "$_";
}
} else {
$message = "";
}
} elsif(/^\`(.*?)\' undeclared \(first use in this function\)$/) {
$message = "$_";
} elsif(/^\(Each undeclared identifier is reported only once$/) {
$message = "$_";
} elsif(/^for each function it appears in.\)$/) {
$message = "$_";
} elsif(/^parse error before `(.*?)'$/) {
$message = "$_";
} elsif(/^$/) {
$message = "$_";
} else {
error();
}
} elsif(/^In function \`(.*?)\':$/) {
$function = $1;
} elsif(/^At top level:$/) {
$function = "";
} else {
error();
}
}
########################################################################
# install_command
########################################################################
sub install_command {
local $_ = shift;
return ([], []);
}
########################################################################
# ld_command
########################################################################
sub ld_command {
local $_ = shift;
my $read_files;
my $write_files;
if(/-r\s+(.*?)\s+-o\s+(\S+)$/) {
$write_files = [$2];
$read_files = [split(/\s+/, $1)];
} else {
error();
}
return ($read_files, $write_files);
}
########################################################################
# ld_output
########################################################################
sub ld_output {
$file = shift;
local $_ = shift;
if(/^the use of \`(.+?)\' is dangerous, better use \`(.+?)\'$/) {
# nothing
}
}
########################################################################
# ldconfig_command
########################################################################
sub ldconfig_command {
local $_ = shift;
return ([], []);
}
########################################################################
# makedep_command
########################################################################
sub makedep_command {
local $_ = shift;
return ([], []);
}
########################################################################
# mkdir_command
########################################################################
sub mkdir_command {
local $_ = shift;
return ([], []);
}
########################################################################
# ranlib_command
########################################################################
sub ranlib_command {
local $_ = shift;
my $read_files;
my $write_files;
$read_files = [split(/\s+/)];
$write_files = [];
return ($read_files, $write_files);
}
########################################################################
# rm_command
########################################################################
sub rm_command {
local $_ = shift;
s/^-f\s*//;
return ([], [], [split(/\s+/, $_)]);
}
########################################################################
# sed_command
########################################################################
sub sed_command {
local $_ = shift;
return ([], []);
}
########################################################################
# strip_command
########################################################################
sub strip_command {
local $_ = shift;
return ([], []);
}
########################################################################
# winebuild_command
########################################################################
sub winebuild_command {
local $_ = shift;
return ([], []);
}
########################################################################
# winebuild_output
########################################################################
sub winebuild_output {
$file = shift;
local $_ = shift;
$message = $_;
}
########################################################################
# wmc_command
########################################################################
sub wmc_command {
local $_ = shift;
my $read_files;
my $write_files;
if(/\s+(\S+)$/) {
my $mc_file = $1;
my $rc_file = $mc_file;
$rc_file =~ s/\.mc$/.rc/;
$write_files = [$rc_file];
$read_files = [$mc_file];
} else {
error();
}
return ($read_files, $write_files);
}
########################################################################
# wmc_output
########################################################################
sub wmc_output {
$file = shift;
local $_ = shift;
}
########################################################################
# wrc_command
########################################################################
sub wrc_command {
local $_ = shift;
my $read_files;
my $write_files;
if(/\s+(\S+)$/) {
my $rc_file = $1;
my $o_file = $rc_file;
$o_file =~ s/\.rc$/.o/;
$write_files = [$o_file];
$read_files = [$rc_file];
} else {
error();
}
return ($read_files, $write_files);
}
########################################################################
# wrc_output
########################################################################
sub wrc_output {
$file = shift;
local $_ = shift;
}
1;

View File

@ -40,9 +40,9 @@ sub new {
my $self = {};
bless ($self, $class);
my $options_long = \%{$self->{OPTIONS_LONG}};
my $options_short = \%{$self->{OPTIONS_SHORT}};
my $options_usage = \${$self->{OPTIONS_USAGE}};
my $options_long = \%{$self->{_OPTIONS_LONG}};
my $options_short = \%{$self->{_OPTIONS_SHORT}};
my $options_usage = \${$self->{_OPTIONS_USAGE}};
my $refoptions_long = shift;
my $refoptions_short = shift;
@ -53,12 +53,16 @@ sub new {
$self->options_set("default");
my $c_files = \@{$self->{C_FILES}};
my $h_files = \@{$self->{H_FILES}};
my @files;
my $arguments = \@{$self->{_ARGUMENTS}};
my $end_of_options = 0;
while(defined($_ = shift @ARGV)) {
if(/^--(all|none)$/) {
if(/^--$/) {
$end_of_options = 1;
next;
} elsif($end_of_options) {
# Nothing
} elsif(/^--(all|none)$/) {
$self->options_set("$1");
next;
} elsif(/^-([^=]*)(=(.*))?$/) {
@ -143,17 +147,12 @@ sub new {
}
}
if(/^-(.*)$/) {
if(!$end_of_options && /^-(.*)$/) {
$output->write("unknown option: $_\n");
$output->write($$options_usage);
exit 1;
} else {
if(!-e $_) {
$output->write("$_: no such file or directory\n");
exit 1;
}
push @files, $_;
push @$arguments, $_;
}
}
@ -163,6 +162,33 @@ sub new {
exit 0;
}
return $self;
}
sub DESTROY {
}
sub parse_files {
my $self = shift;
my $arguments = \@{$self->{_ARGUMENTS}};
my $c_files = \@{$self->{_C_FILES}};
my $h_files = \@{$self->{_H_FILES}};
my $error = 0;
my @files = ();
foreach (@$arguments) {
if(!-e $_) {
$output->write("$_: no such file or directory\n");
$error = 1;
} else {
push @files, $_;
}
}
if($error) {
exit 1;
}
my @paths = ();
my @c_files = ();
my @h_files = ();
@ -186,7 +212,7 @@ sub new {
my %found;
@$c_files = sort(map {
s/^\.\/(.*)$/$1/;
if(defined($found{$_}) || /glue\.c|spec\.c$/) {
if(defined($found{$_})) {
();
} else {
$found{$_}++;
@ -209,18 +235,13 @@ sub new {
}
} split(/\n/, `$h_command`));
}
return $self;
}
sub DESTROY {
}
sub options_set {
my $self = shift;
my $options_long = \%{$self->{OPTIONS_LONG}};
my $options_short = \%{$self->{OPTIONS_SHORT}};
my $options_long = \%{$self->{_OPTIONS_LONG}};
my $options_short = \%{$self->{_OPTIONS_SHORT}};
local $_ = shift;
for my $name (sort(keys(%$options_long))) {
@ -255,8 +276,8 @@ sub options_set {
sub show_help {
my $self = shift;
my $options_long = \%{$self->{OPTIONS_LONG}};
my $options_short = \%{$self->{OPTIONS_SHORT}};
my $options_long = \%{$self->{_OPTIONS_LONG}};
my $options_short = \%{$self->{_OPTIONS_SHORT}};
my $maxname = 0;
for my $name (sort(keys(%$options_long))) {
@ -329,8 +350,36 @@ sub AUTOLOAD {
}
}
sub c_files { my $self = shift; return @{$self->{C_FILES}}; }
sub arguments {
my $self = shift;
sub h_files { my $self = shift; return @{$self->{H_FILES}}; }
my $arguments = \@{$self->{_ARGUMENTS}};
return @$arguments;
}
sub c_files {
my $self = shift;
my $c_files = \@{$self->{_C_FILES}};
if(!defined(@$c_files)) {
$self->parse_files;
}
return @$c_files;
}
sub h_files {
my $self = shift;
my $h_files = \@{$self->{_H_FILES}};
if(!defined(@$h_files)) {
$self->parse_files;
}
return @$h_files;
}
1;

View File

@ -26,6 +26,7 @@ sub new {
my $self = {};
bless ($self, $class);
my $progress_enabled = \${$self->{PROGRESS_ENABLED}};
my $progress = \${$self->{PROGRESS}};
my $last_progress = \${$self->{LAST_PROGRESS}};
my $last_time = \${$self->{LAST_TIME}};
@ -33,6 +34,7 @@ sub new {
my $prefix = \${$self->{PREFIX}};
my $prefix_callback = \${$self->{PREFIX_CALLBACK}};
$$progress_enabled = 1;
$$progress = "";
$$last_progress = "";
$$last_time = 0;
@ -43,62 +45,91 @@ sub new {
return $self;
}
sub DESTROY {
my $self = shift;
$self->hide_progress;
}
sub enable_progress {
my $self = shift;
my $progress_enabled = \${$self->{PROGRESS_ENABLED}};
$$progress_enabled = 1;
}
sub disable_progress {
my $self = shift;
my $progress_enabled = \${$self->{PROGRESS_ENABLED}};
$$progress_enabled = 0;
}
sub show_progress {
my $self = shift;
my $progress_enabled = \${$self->{PROGRESS_ENABLED}};
my $progress = \${$self->{PROGRESS}};
my $last_progress = \${$self->{LAST_PROGRESS}};
my $progress_count = \${$self->{PROGRESS_COUNT}};
$$progress_count++;
if($$progress_count > 0 && $$progress && $stderr_isatty) {
print STDERR $$progress;
$$last_progress = $$progress;
if($$progress_enabled) {
if($$progress_count > 0 && $$progress && $stderr_isatty) {
print STDERR $$progress;
$$last_progress = $$progress;
}
}
}
sub hide_progress {
my $self = shift;
my $progress_enabled = \${$self->{PROGRESS_ENABLED}};
my $progress = \${$self->{PROGRESS}};
my $last_progress = \${$self->{LAST_PROGRESS}};
my $progress_count = \${$self->{PROGRESS_COUNT}};
$$progress_count--;
if($$last_progress && $stderr_isatty) {
my $message;
for (1..length($$last_progress)) {
$message .= " ";
if($$progress_enabled) {
if($$last_progress && $stderr_isatty) {
my $message;
for (1..length($$last_progress)) {
$message .= " ";
}
print STDERR $message;
undef $$last_progress;
}
print STDERR $message;
undef $$last_progress;
}
}
sub update_progress {
my $self = shift;
my $progress_enabled = \${$self->{PROGRESS_ENABLED}};
my $progress = \${$self->{PROGRESS}};
my $last_progress = \${$self->{LAST_PROGRESS}};
my $prefix = "";
my $suffix = "";
if($$last_progress) {
for (1..length($$last_progress)) {
$prefix .= "";
}
my $diff = length($$last_progress)-length($$progress);
if($diff > 0) {
for (1..$diff) {
$suffix .= " ";
if($$progress_enabled) {
my $prefix = "";
my $suffix = "";
if($$last_progress) {
for (1..length($$last_progress)) {
$prefix .= "";
}
for (1..$diff) {
$suffix .= "";
my $diff = length($$last_progress)-length($$progress);
if($diff > 0) {
for (1..$diff) {
$suffix .= " ";
}
for (1..$diff) {
$suffix .= "";
}
}
}
print STDERR $prefix . $$progress . $suffix;
$$last_progress = $$progress;
}
print STDERR $prefix . $$progress . $suffix;
$$last_progress = $$progress;
}
sub progress {

14
tools/winapi/type.pm Normal file
View File

@ -0,0 +1,14 @@
package type;
use strict;
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
bless ($self, $class);
return $self;
}
1;

View File

@ -127,16 +127,10 @@ my %options_short = (
"v" => "verbose"
);
my $options_usage = "usage: winapi_fixup [--help] [<files>]\n";
my $options_usage = "usage: winapi_check [--help] [<files>]\n";
$options = '_winapi_check_options'->new(\%options_long, \%options_short, $options_usage);
my $global = \${$options->{GLOBAL}};
if($wine_dir ne ".") {
$$global = 0;
}
package _winapi_check_options;
use base qw(_options);

View File

@ -13,18 +13,18 @@ use config qw(
&file_type &files_skip &files_filter &get_spec_files
$current_dir $wine_dir $winapi_dir $winapi_check_dir
);
use modules;
use nativeapi;
use output qw($output);
use options;
use winapi;
use winapi_extract_options qw($options);
use function;
use type;
use winapi_function;
use winapi_parser;
use winapi_extract_options qw($options);
use winapi qw(@winapis);
my %module2spec_file;
my %module2type;
{
if($options->spec_files) {
local $_;
foreach my $spec_file (get_spec_files("winelib")) {
@ -49,22 +49,6 @@ my %module2type;
}
}
my $modules = 'modules'->new($options, $output, $wine_dir, $current_dir, \&file_type, "$winapi_check_dir/modules.dat");
my $win16api = 'winapi'->new($options, $output, "win16", "$winapi_check_dir/win16");
my $win32api = 'winapi'->new($options, $output, "win32", "$winapi_check_dir/win32");
my @winapis = ($win16api, $win32api);
if($wine_dir eq ".") {
'winapi'->read_all_spec_files($modules, $wine_dir, $current_dir, \&file_type, $win16api, $win32api);
} else {
my @spec_files = $modules->allowed_spec_files($wine_dir, $current_dir);
'winapi'->read_spec_files($modules, $wine_dir, $current_dir, \@spec_files, $win16api, $win32api);
}
my $nativeapi = 'nativeapi'->new($options, $output, "$winapi_check_dir/nativeapi.dat",
"$wine_dir/configure.in", "$wine_dir/include/config.h.in");
my %specifications;
sub documentation_specifications {
@ -164,6 +148,14 @@ foreach my $file (@c_files) {
$output->progress("$file: file $progress_current of $progress_max");
}
my $create_function = sub {
if($options->stub_statistics) {
return 'winapi_function'->new;
} else {
return 'function'->new;
}
};
my $found_function = sub {
my $function = shift;
@ -191,12 +183,20 @@ foreach my $file (@c_files) {
$output->prefix("");
};
my $create_type = sub {
return 'type'->new;
};
my $found_type = sub {
my $type = shift;
};
my $found_preprocessor = sub {
my $directive = shift;
my $argument = shift;
};
&winapi_parser::parse_c_file($options, $file, $found_function, $found_preprocessor);
&winapi_parser::parse_c_file($file, $create_function, $found_function, $create_type, $found_type, $found_preprocessor);
my @internal_names = keys(%functions);
if($#internal_names < 0) {
@ -342,7 +342,7 @@ if($options->stub_statistics) {
foreach my $internal_name ($winapi->all_internal_functions,$winapi->all_functions_stub) {
foreach my $module (split(/ \& /, $winapi->function_internal_module($internal_name))) {
if($winapi->function_stub($internal_name)) {
if($winapi->is_function_stub_in_module($module, $internal_name)) {
$module_stub_count{$module}++;
}
$module_total_count{$module}++;
@ -372,4 +372,3 @@ if($options->stub_statistics) {
}
}
$output->hide_progress;

View File

@ -26,7 +26,7 @@ my %options_long = (
"global" => { default => 1, description => "global extraction" },
"spec-files" => { default => 1, parent => "global", description => "spec files extraction" },
"stub-statistics" => { default => 0, parent => "global", description => "stub statistics" },
"stub-statistics" => { default => 1, parent => "global", description => "stub statistics" },
);
my %options_short = (

View File

@ -17,24 +17,14 @@ use config qw(
$current_dir $wine_dir $winapi_dir $winapi_check_dir
);
use output qw($output);
use modules;
use util;
use winapi;
use winapi_parser;
use winapi_fixup_options qw($options);
use modules qw($modules);
use winapi qw($win16api $win32api @winapis);
my $modules = 'modules'->new($options, $output, $wine_dir, $current_dir, \&file_type, "$winapi_check_dir/modules.dat");
my $win16api = 'winapi'->new($options, $output, "win16", "$winapi_check_dir/win16");
my $win32api = 'winapi'->new($options, $output, "win32", "$winapi_check_dir/win32");
my @winapis = ($win16api, $win32api);
if($wine_dir eq ".") {
'winapi'->read_all_spec_files($modules, $wine_dir, $current_dir, \&file_type, $win16api, $win32api);
} else {
my @spec_files = $modules->allowed_spec_files($wine_dir, $current_dir);
'winapi'->read_spec_files($modules, $wine_dir, $current_dir, \@spec_files, $win16api, $win32api);
}
use type;
use util;
use winapi_function;
use winapi_parser;
my @c_files = $options->c_files;
@c_files = files_skip(@c_files);
@ -58,6 +48,10 @@ foreach my $file (@c_files) {
my %documentation_line_used;
my $create_function = sub {
return 'winapi_function'->new;
};
my $found_function = sub {
my $function = shift;
@ -434,12 +428,21 @@ foreach my $file (@c_files) {
$output->prefix("");
};
my $create_type = sub {
return 'type'->new;
};
my $found_type = sub {
my $type = shift;
};
my $found_preprocessor = sub {
my $directive = shift;
my $argument = shift;
};
&winapi_parser::parse_c_file($options, $file, $found_function, $found_preprocessor);
&winapi_parser::parse_c_file($file, $create_function, $found_function, $create_type, $found_type, $found_preprocessor);
my $editor = sub {
local *IN = shift;
@ -598,4 +601,3 @@ foreach my $file (@c_files) {
}
}
$output->hide_progress;

View File

@ -344,7 +344,6 @@ dlls/user
% dlls/user/user.spec
controls
dlls/kernel
dlls/user
misc
windows

View File

@ -11,30 +11,33 @@ require Exporter;
use vars qw($modules);
use config qw(
&file_type &files_skip
&file_directory
&get_c_files
$current_dir $wine_dir
$winapi_check_dir
);
use options qw($options);
use output qw($output);
$modules = 'modules'->new;
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
bless ($self, $class);
my $options = \${$self->{OPTIONS}};
my $output = \${$self->{OUTPUT}};
my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
my $spec_file2dir = \%{$self->{SPEC_FILE2DIR}};
my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
$$options = shift;
$$output = shift;
my $wine_dir = shift;
my $current_dir = shift;
my $file_type = shift;
my $module_file = shift;
$module_file =~ s/^\.\///;
my $module_file = "$winapi_check_dir/modules.dat";
my @all_spec_files = map {
s/^.\/(.*)$/$1/;
if(&$file_type($_) eq "winelib") {
if(file_type($_) eq "winelib") {
$_;
} else {
();
@ -46,8 +49,8 @@ sub new {
$all_spec_files{$file}++ ;
}
if($$options->progress) {
$$output->progress("modules.dat");
if($options->progress) {
$output->progress("modules.dat");
}
my $allowed_dir;
@ -64,7 +67,7 @@ sub new {
$spec_file = $1;
if(!-f "$wine_dir/$spec_file") {
$$output->write("modules.dat: $spec_file: file ($spec_file) doesn't exist or is no file\n");
$output->write("modules.dat: $spec_file: file ($spec_file) doesn't exist or is no file\n");
}
if($wine_dir eq ".") {
@ -81,14 +84,14 @@ sub new {
$$dir2spec_file{$allowed_dir}{$spec_file}++;
if(!-d "$wine_dir/$allowed_dir") {
$$output->write("modules.dat: $spec_file: directory ($allowed_dir) doesn't exist or is no directory\n");
$output->write("modules.dat: $spec_file: directory ($allowed_dir) doesn't exist or is no directory\n");
}
}
close(IN);
foreach my $spec_file (sort(keys(%all_spec_files))) {
if($all_spec_files{$spec_file} > 0) {
$$output->write("modules.dat: $spec_file: exists but is not specified\n");
$output->write("modules.dat: $spec_file: exists but is not specified\n");
}
}
@ -105,6 +108,44 @@ sub all_modules {
return sort(keys(%$module2spec_file));
}
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 spec_file_module {
my $self = shift;
@ -183,13 +224,8 @@ sub allowed_dirs_for_module {
sub allowed_spec_files {
my $self = shift;
my $options = \${$self->{OPTIONS}};
my $output = \${$self->{OUTPUT}};
my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
my $wine_dir = shift;
my $current_dir = shift;
my @dirs = map {
s/^\.\/(.*)$/$1/;
if(/^\.$/) {
@ -227,7 +263,6 @@ sub found_module_in_dir {
sub global_report {
my $self = shift;
my $output = \${$self->{OUTPUT}};
my $dir2spec_file = \%{$self->{DIR2SPEC_FILE}};
my $spec_file2module = \%{$self->{SPEC_FILE2MODULE}};
my $used_module_dirs = \%{$self->{USED_MODULE_DIRS}};
@ -244,7 +279,7 @@ sub global_report {
}
foreach my $message (sort(@messages)) {
$$output->write($message);
$output->write($message);
}
}

View File

@ -11,31 +11,33 @@ require Exporter;
use vars qw($nativeapi);
use config qw(&file_type $current_dir $wine_dir $winapi_check_dir);
use options qw($options);
use output qw($output);
$nativeapi = 'nativeapi'->new;
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
bless ($self, $class);
my $options = \${$self->{OPTIONS}};
my $output = \${$self->{OUTPUT}};
my $functions = \%{$self->{FUNCTIONS}};
my $conditionals = \%{$self->{CONDITIONALS}};
my $conditional_headers = \%{$self->{CONDITIONAL_HEADERS}};
my $conditional_functions = \%{$self->{CONDITIONAL_FUNCTIONS}};
$$options = shift;
$$output = shift;
my $api_file = shift;
my $configure_in_file = shift;
my $config_h_in_file = shift;
my $api_file = "$winapi_check_dir/nativeapi.dat";
my $configure_in_file = "$wine_dir/configure.in";
my $config_h_in_file = "$wine_dir/include/config.h.in";
$api_file =~ s/^\.\///;
$configure_in_file =~ s/^\.\///;
$config_h_in_file =~ s/^\.\///;
if($$options->progress) {
$$output->progress("$api_file");
if($options->progress) {
$output->progress("$api_file");
}
open(IN, "< $api_file");
@ -49,8 +51,8 @@ sub new {
}
close(IN);
if($$options->progress) {
$$output->progress("$configure_in_file");
if($options->progress) {
$output->progress("$configure_in_file");
}
my $again = 0;
@ -100,8 +102,8 @@ sub new {
}
close(IN);
if($$options->progress) {
$$output->progress("$config_h_in_file");
if($options->progress) {
$output->progress("$config_h_in_file");
}
open(IN, "< $config_h_in_file");
@ -186,7 +188,7 @@ sub global_report {
}
foreach my $message (sort(@messages)) {
$$output->write($message);
$output->write($message);
}
}

View File

@ -11,49 +11,53 @@ require Exporter;
use vars qw($win16api $win32api @winapis);
use config qw(
&file_type
&get_api_files &get_spec_files
$current_dir $wine_dir
);
use modules qw($modules);
use options qw($options);
use output qw($output);
$win16api = 'winapi'->new("win16");
$win32api = 'winapi'->new("win32");
@winapis = ($win16api, $win32api);
my @spec_files = get_spec_files("winelib");
foreach my $file (@spec_files) {
(my $type, my $module) = 'winapi'->get_spec_file_type("$wine_dir/$file");
$modules->spec_file_module($file, $module);
}
if($wine_dir eq ".") {
'winapi'->read_spec_files(\@spec_files);
} else {
@spec_files = $modules->allowed_spec_files;
'winapi'->read_spec_files(\@spec_files);
}
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
bless ($self, $class);
my $options = \${$self->{OPTIONS}};
my $output = \${$self->{OUTPUT}};
my $name = \${$self->{NAME}};
$$options = shift;
$$output = shift;
$$name = shift;
my $path = shift;
if($$options->progress) {
$$output->progress("$path: searching for *.api");
}
my @files = map {
s%^\./%%;
$_;
} split(/\n/, `find $path -name \\*.api`);
foreach my $file (@files) {
foreach my $file (get_api_files($$name)) {
my $module = $file;
if($$options->progress) {
$$output->lazy_progress("$file");
if($options->progress) {
$output->lazy_progress("$file");
}
$module =~ s/.*?\/([^\/]*?)\.api$/$1/;
$self->parse_api_file($file,$module);
}
if($$name eq "win16") {
$win16api = $self;
} elsif($$name eq "win32") {
$win32api = $self;
}
push @winapis, $self;
return $self;
}
@ -68,8 +72,6 @@ sub win32api {
sub parse_api_file {
my $self = shift;
my $options = \${$self->{OPTIONS}};
my $output = \${$self->{OUTPUT}};
my $allowed_kind = \%{$self->{ALLOWED_KIND}};
my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
my $allowed_modules_limited = \%{$self->{ALLOWED_MODULES_LIMITED}};
@ -85,11 +87,11 @@ sub parse_api_file {
my $extension = 0;
my $forbidden = 0;
if($$options->progress) {
$$output->progress("$file");
if($options->progress) {
$output->progress("$file");
}
open(IN, "< $file") || die "$file: $!\n";
open(IN, "< $wine_dir/$file") || die "$wine_dir/$file: $!\n";
$/ = "\n";
while(<IN>) {
s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begin and end of line
@ -143,12 +145,12 @@ sub parse_api_file {
if(!$forbidden) {
if(defined($module)) {
if($$allowed_modules_unlimited{$type}) {
$$output->write("$file: type ($type) already specificed as an unlimited type\n");
$output->write("$file: type ($type) already specificed as an unlimited type\n");
} elsif(!$$allowed_modules{$type}{$module}) {
$$allowed_modules{$type}{$module} = 1;
$$allowed_modules_limited{$type} = 1;
} else {
$$output->write("$file: type ($type) already specificed\n");
$output->write("$file: type ($type) already specificed\n");
}
} else {
$$allowed_modules_unlimited{$type} = 1;
@ -157,14 +159,14 @@ sub parse_api_file {
$$allowed_modules_limited{$type} = 1;
}
if(defined($$translate_argument{$type}) && $$translate_argument{$type} ne $kind) {
$$output->write("$file: type ($type) respecified as different kind ($kind != $$translate_argument{$type})\n");
$output->write("$file: type ($type) respecified as different kind ($kind != $$translate_argument{$type})\n");
} else {
$$translate_argument{$type} = $kind;
}
$$type_format{$module}{$type} = $format;
} else {
$$output->write("$file: file must begin with %<type> statement\n");
$output->write("$file: file must begin with %<type> statement\n");
exit 1;
}
}
@ -201,16 +203,10 @@ sub read_spec_files {
my $proto = shift;
my $class = ref($proto) || $proto;
my $modules = shift;
my $wine_dir = shift;
my $current_dir = shift;
my $files = shift;
my $win16api = shift;
my $win32api = shift;
foreach my $file (@$files) {
(my $type, my $module) = 'winapi'->get_spec_file_type("$wine_dir/$file");
$modules->spec_file_module($file, $module);
if($type eq "win16") {
$win16api->parse_spec_file("$wine_dir/$file");
} elsif($type eq "win32") {
@ -246,34 +242,9 @@ sub read_spec_files {
}
}
sub read_all_spec_files {
my $proto = shift;
my $class = ref($proto) || $proto;
my $modules = shift;
my $wine_dir = shift;
my $current_dir = shift;
my $file_type = shift;
my $win16api = shift;
my $win32api = shift;
my @files = map {
s%^$wine_dir/%%;
if(&$file_type($_) eq "winelib") {
$_;
} else {
();
}
} split(/\n/, `find $wine_dir -name \\*.spec`);
'winapi'->read_spec_files($modules, $wine_dir, $current_dir, \@files, $win16api, $win32api);
}
sub parse_spec_file {
my $self = shift;
my $options = \${$self->{OPTIONS}};
my $output = \${$self->{OUTPUT}};
my $function_internal_arguments = \%{$self->{FUNCTION_INTERNAL_ARGUMENTS}};
my $function_external_arguments = \%{$self->{FUNCTION_EXTERNAL_ARGUMENTS}};
my $function_internal_ordinal = \%{$self->{FUNCTION_INTERNAL_ORDINAL}};
@ -297,8 +268,8 @@ sub parse_spec_file {
my $module;
my $module_file;
if($$options->progress) {
$$output->lazy_progress("$file");
if($options->progress) {
$output->lazy_progress("$file");
}
open(IN, "< $file") || die "$file: $!\n";
@ -366,10 +337,10 @@ sub parse_spec_file {
$$function_external_module{$external_name} .= " & $module";
}
if(0 && $$options->spec_mismatch) {
if(0 && $options->spec_mismatch) {
if($external_name eq "@") {
if($internal_name !~ /^\U$module\E_$ordinal$/) {
$$output->write("$file: $external_name: the internal name ($internal_name) mismatch\n");
$output->write("$file: $external_name: the internal name ($internal_name) mismatch\n");
}
} else {
my $name = $external_name;
@ -393,7 +364,7 @@ sub parse_spec_file {
if(uc($internal_name) ne uc($external_name) &&
$internal_name !~ /(\Q$name\E|\Q$name1\E|\Q$name2\E|\Q$name3\E|\Q$name4\E|\Q$name5\E)/)
{
$$output->write("$file: $external_name: internal name ($internal_name) mismatch\n");
$output->write("$file: $external_name: internal name ($internal_name) mismatch\n");
}
}
}
@ -466,7 +437,7 @@ sub parse_spec_file {
if(defined($ordinal)) {
if($ordinal ne "@" && $ordinals{$ordinal}) {
$$output->write("$file: ordinal redefined: $_\n");
$output->write("$file: ordinal redefined: $_\n");
}
$ordinals{$ordinal}++;
}
@ -556,7 +527,6 @@ sub types_not_used {
sub types_unlimited_used_in_modules {
my $self = shift;
my $output = \${$self->{OUTPUT}};
my $used_modules = \%{$self->{USED_MODULES}};
my $allowed_modules = \%{$self->{ALLOWED_MODULES}};
my $allowed_modules_unlimited = \%{$self->{ALLOWED_MODULES_UNLIMITED}};

View File

@ -20,38 +20,25 @@ BEGIN {
}
use config qw(
&file_type &files_filter &files_skip
&get_h_files
$current_dir $wine_dir $winapi_dir $winapi_check_dir
&files_filter &files_skip
&get_h_files
$current_dir $wine_dir
);
use modules;
use nativeapi;
use output qw($output);
use winapi_check_options qw($options);
use modules qw($modules);
use nativeapi qw($nativeapi);
use winapi qw($win16api $win32api @winapis);
use preprocessor;
use type;
use util qw(&is_subset);
use winapi;
use winapi_documentation;
use winapi_function;
use winapi_local;
use winapi_global;
use winapi_check_options qw($options);
use winapi_parser;
my $modules = 'modules'->new($options, $output, $wine_dir, $current_dir, \&file_type, "$winapi_check_dir/modules.dat");
my $win16api = 'winapi'->new($options, $output, "win16", "$winapi_check_dir/win16");
my $win32api = 'winapi'->new($options, $output, "win32", "$winapi_check_dir/win32");
my @winapis = ($win16api, $win32api);
if($options->global) {
'winapi'->read_all_spec_files($modules, $wine_dir, $current_dir, \&file_type, $win16api, $win32api);
} else {
my @spec_files = $modules->allowed_spec_files($wine_dir, $current_dir);
'winapi'->read_spec_files($modules, $wine_dir, $current_dir, \@spec_files, $win16api, $win32api);
}
my $nativeapi = 'nativeapi'->new($options, $output, "$winapi_check_dir/nativeapi.dat", "$wine_dir/configure.in", "$wine_dir/include/config.h.in");
my %declared_functions;
my %include2info;
@ -125,6 +112,10 @@ if($options->headers) {
$output->progress("$file: file $progress_current of $progress_max");
}
my $create_function = sub {
return 'winapi_function'->new;
};
my $found_function = sub {
my $function = shift;
@ -156,6 +147,15 @@ if($options->headers) {
$output->write("duplicate declaration (first declaration at $file:$function_line)\n");
}
}
$output->prefix("");
};
my $create_type = sub {
return 'type'->new;
};
my $found_type = sub {
my $type = shift;
};
my $found_preprocessor = sub {
@ -163,7 +163,7 @@ if($options->headers) {
my $argument = shift;
};
&winapi_parser::parse_c_file($options, $file, $found_function, $found_preprocessor);
&winapi_parser::parse_c_file($file, $create_function, $found_function, $create_type, $found_type, $found_preprocessor);
}
}
@ -188,6 +188,10 @@ foreach my $file (@c_files) {
if(!($file_dir =~ s/(.*?)\/[^\/]*$/$1/)) {
$file_dir = ".";
}
my $create_function = sub {
return 'winapi_function'->new;
};
my $found_function = sub {
my $function = shift;
@ -273,19 +277,19 @@ foreach my $file (@c_files) {
}
}
if($options->local && $options->argument) {
if($options->local && $options->argument && defined($statements)) {
&winapi_local::check_function($function);
}
if($options->local && $options->statements) {
if($options->local && $options->statements && defined($statements)) {
&winapi_local::check_statements(\%functions, $function);
}
if($options->local && $options->documentation &&
(defined($module16) || defined($module32)) &&
$linkage ne "static" && ($linkage ne "" || defined($statements)))
$linkage eq "" && defined($statements))
{
&winapi_documentation::check_documentation($function);
# &winapi_documentation::check_documentation($function);
}
if(1) {
@ -386,6 +390,15 @@ foreach my $file (@c_files) {
}
}
};
my $create_type = sub {
return 'type'->new;
};
my $found_type = sub {
my $type = shift;
};
my $preprocessor = 'preprocessor'->new($found_include, $found_conditional);
my $found_preprocessor = sub {
my $directive = shift;
@ -511,7 +524,7 @@ foreach my $file (@c_files) {
}
};
&winapi_parser::parse_c_file($options, $file, $found_function, $found_preprocessor);
&winapi_parser::parse_c_file($file, $create_function, $found_function, $create_type, $found_type, $found_preprocessor);
if($options->config_unnessary) {
if($config && $conditional == 0) {
@ -522,74 +535,69 @@ foreach my $file (@c_files) {
&winapi_local::check_file($file, \%functions);
}
$output->hide_progress;
if($options->global) {
my @complete_modules = $modules->complete_modules(\@c_files);
my %complete_module;
if($options->declared) {
my %dirs;
foreach my $file (@c_files) {
my $dir = $file;
$dir =~ s%/?[^/]*$%%;
if($dir) {
if($current_dir ne ".") {
$dir = "$current_dir/$dir";
}
} else {
$dir = "$current_dir";
}
$dirs{$dir}++;
foreach my $module (@complete_modules) {
$complete_module{$module}++;
}
foreach my $module ($modules->all_modules) {
my $incomplete = 0;
foreach my $module_dir ($modules->allowed_dirs_for_module($module)) {
my $found = 0;
foreach my $dir (sort(keys(%dirs))) {
if($module_dir eq $dir) {
$found = 1;
last;
}
}
if(!$found) {
$incomplete = 1;
}
}
if(!$incomplete) {
if($options->declared) {
foreach my $winapi (@winapis) {
if(!$winapi->is_module($module)) { next; }
my $functions = $module2functions{$module};
foreach my $internal_name ($winapi->all_internal_functions_in_module($module)) {
my $function = $functions->{$internal_name};
if(!defined($function) && !$nativeapi->is_function($internal_name) &&
!($module eq "user" && $internal_name =~
/^(?:GlobalAddAtomA|GlobalDeleteAtom|GlobalFindAtomA|
GlobalGetAtomNameA|lstrcmpiA)$/x))
{
$output->write("*.c: $module: $internal_name: " .
"function declared but not implemented or declared external\n");
}
if($options->declared) {
foreach my $module (@complete_modules) {
foreach my $winapi (@winapis) {
if(!$winapi->is_module($module)) { next; }
my $functions = $module2functions{$module};
foreach my $internal_name ($winapi->all_internal_functions_in_module($module)) {
my $function = $functions->{$internal_name};
if(!defined($function) && !$nativeapi->is_function($internal_name) &&
!($module eq "user" && $internal_name =~
/^(?:GlobalAddAtomA|GlobalDeleteAtom|GlobalFindAtomA|
GlobalGetAtomNameA|lstrcmpiA)$/x))
{
$output->write("*.c: $module: $internal_name: " .
"function declared but not implemented or declared external\n");
}
}
}
}
}
}
if($options->global) {
&winapi_documentation::report_documentation;
if($options->headers_unused) {
foreach my $name (sort(keys(%include2info))) {
if(!$include2info{$name}{used}) {
if($options->include) {
$output->write("*.c: $name: include file is never used\n");
if($options->argument && $options->argument_forbidden) {
foreach my $winapi (@winapis) {
my $types_not_used = $winapi->types_not_used;
foreach my $module (sort(keys(%$types_not_used))) {
if(!$complete_module{$module}) { next; }
foreach my $type (sort(keys(%{$$types_not_used{$module}}))) {
$output->write("*.c: $module: type ($type) not used\n");
}
}
}
}
&winapi_global::check(\%type_found);
my $all_modules = 1;
foreach my $module ($modules->all_modules) {
if(!$complete_module{$module}) {
$all_modules = 0;
}
}
if($all_modules) {
&winapi_documentation::report_documentation;
if($options->headers_unused) {
foreach my $name (sort(keys(%include2info))) {
if(!$include2info{$name}{used}) {
if($options->include) {
$output->write("*.c: $name: include file is never used\n");
}
}
}
}
&winapi_global::check(\%type_found);
$modules->global_report;
$nativeapi->global_report;
$modules->global_report;
$nativeapi->global_report;
}
}

View File

@ -35,14 +35,6 @@ sub _check {
}
if($options->argument && $options->argument_forbidden) {
my $not_used = $winapi->types_not_used;
foreach my $module (sort(keys(%$not_used))) {
foreach my $type (sort(keys(%{$$not_used{$module}}))) {
$output->write("*.c: $module: type ($type) not used\n");
}
}
my $types_used = $winapi->types_unlimited_used_in_modules;
foreach my $type (sort(keys(%$types_used))) {

View File

@ -3,93 +3,131 @@ package winapi_parser;
use strict;
use output qw($output);
use winapi_function;
use options qw($options);
sub parse_c_file {
my $options = shift;
my $file = shift;
my $function_create_callback = shift;
my $function_found_callback = shift;
my $type_create_callback = shift;
my $type_found_callback = shift;
my $preprocessor_found_callback = shift;
# global
my $debug_channels = [];
# local
my $documentation_line;
my $documentation;
my $function_line;
my $linkage;
my $return_type;
my $calling_convention;
my $internal_name = "";
my $argument_types;
my $argument_names;
my $argument_documentations;
my $statements;
my $function_begin = sub {
$documentation_line = shift;
$documentation = shift;
$function_line = shift;
$linkage = shift;
$return_type= shift;
$calling_convention = shift;
$internal_name = shift;
$argument_types = shift;
$argument_names = shift;
$argument_documentations = shift;
if(defined($argument_names) && defined($argument_types) &&
$#$argument_names == -1)
{
foreach my $n (0..$#$argument_types) {
push @$argument_names, "";
my $in_function = 0;
my $function_begin;
my $function_end;
{
my $documentation_line;
my $documentation;
my $function_line;
my $linkage;
my $return_type;
my $calling_convention;
my $internal_name = "";
my $argument_types;
my $argument_names;
my $argument_documentations;
my $statements;
$function_begin = sub {
$documentation_line = shift;
$documentation = shift;
$function_line = shift;
$linkage = shift;
$return_type= shift;
$calling_convention = shift;
$internal_name = shift;
$argument_types = shift;
$argument_names = shift;
$argument_documentations = shift;
if(defined($argument_names) && defined($argument_types) &&
$#$argument_names == -1)
{
foreach my $n (0..$#$argument_types) {
push @$argument_names, "";
}
}
}
if(defined($argument_documentations) &&
$#$argument_documentations == -1)
{
foreach my $n (0..$#$argument_documentations) {
push @$argument_documentations, "";
if(defined($argument_documentations) &&
$#$argument_documentations == -1)
{
foreach my $n (0..$#$argument_documentations) {
push @$argument_documentations, "";
}
}
}
$in_function = 1;
};
$statements = undef;
};
my $function_end = sub {
my $function = 'winapi_function'->new;
$function_end = sub {
$statements = shift;
if(!defined($documentation_line)) {
$documentation_line = 0;
}
my $function = &$function_create_callback();
if(!defined($documentation_line)) {
$documentation_line = 0;
}
$function->file($file);
$function->debug_channels([@$debug_channels]);
$function->documentation_line($documentation_line);
$function->documentation($documentation);
$function->function_line($function_line);
$function->linkage($linkage);
$function->return_type($return_type);
$function->calling_convention($calling_convention);
$function->internal_name($internal_name);
if(defined($argument_types)) {
$function->argument_types([@$argument_types]);
}
if(defined($argument_names)) {
$function->argument_names([@$argument_names]);
}
if(defined($argument_documentations)) {
$function->argument_documentations([@$argument_documentations]);
}
$function->statements($statements);
&$function_found_callback($function);
$function->file($file);
$function->debug_channels([@$debug_channels]);
$function->documentation_line($documentation_line);
$function->documentation($documentation);
$function->function_line($function_line);
$function->linkage($linkage);
$function->return_type($return_type);
$function->calling_convention($calling_convention);
$function->internal_name($internal_name);
if(defined($argument_types)) {
$function->argument_types([@$argument_types]);
}
if(defined($argument_names)) {
$function->argument_names([@$argument_names]);
}
if(defined($argument_documentations)) {
$function->argument_documentations([@$argument_documentations]);
}
$function->statements($statements);
$in_function = 0;
};
}
my $in_type = 0;
my $type_begin;
my $type_end;
{
my $type;
$type_begin = sub {
$type = shift;
$in_type = 1;
};
$type_end = sub {
my $names = shift;
foreach my $name (@$names) {
if($type =~ /^(?:struct|enum)/) {
# $output->write("typedef $type {\n");
# $output->write("} $name;\n");
} else {
# $output->write("typedef $type $name;\n");
}
}
$in_type = 0;
};
}
&$function_found_callback($function);
$internal_name = "";
};
my %regs_entrypoints;
my @comment_lines = ();
my @comments = ();
my $statements;
my $level = 0;
my $extern_c = 0;
my $again = 0;
@ -263,8 +301,20 @@ sub parse_c_file {
$statements .= "$line\n";
}
if($internal_name && $level == 0) {
&$function_end;
if($level == 0) {
if($in_function) {
&$function_end($statements);
$statements = undef;
} elsif($in_type) {
if(/^\s*(?:WINE_PACKED\s+)?((?:\*\s*)?\w+\s*(?:\s*,\s*(?:\*+\s*)?\w+)*\s*);/s) {
my @parts = split(/\s*,\s*/, $1);
&$type_end([@parts]);
} elsif(/;/s) {
die "$file: $.: syntax error: '$_'\n";
} else {
$lookahead = 1;
}
}
}
next;
} elsif(/(extern\s+|static\s+)?((struct\s+|union\s+|enum\s+|signed\s+|unsigned\s+)?\w+((\s*\*)+\s*|\s+))
@ -358,7 +408,8 @@ sub parse_c_file {
$function_line, $linkage, $return_type, $calling_convention, $name,
\@argument_types,\@argument_names,\@argument_documentations);
if($level == 0) {
&$function_end;
&$function_end($statements);
$statements = undef;
}
} elsif(/__ASM_GLOBAL_FUNC\(\s*(.*?)\s*,/s) {
my @lines = split(/\n/, $&);
@ -368,95 +419,20 @@ sub parse_c_file {
&$function_begin($documentation_line, $documentation,
$function_line, "", "void", "__asm", $1);
$statements = "";
&$function_end;
} elsif(/DC_(GET_X_Y_16|GET_VAL_16)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s){
my @lines = split(/\n/, $&);
my $function_line = $. - scalar(@lines) + 1;
$_ = $'; $again = 1;
my $return16 = $2 . "16";
my $name16 = $3 . "16";
$return16 =~ s/^(COLORREF|DWORD)16$/$1/;
my @arguments = ("HDC16");
&$function_begin($documentation_line, $documentation,
$function_line, "", $return16, "WINAPI", $name16, \@arguments);
$statements = "";
&$function_end;
} elsif(/DC_(GET_VAL_32)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,.*?\)/s) {
my @lines = split(/\n/, $&);
my $function_line = $. - scalar(@lines) + 1;
$_ = $'; $again = 1;
my $return32 = $2;
my $name32 = $3;
my @arguments32 = ("HDC");
&$function_end;
&$function_begin($documentation_line, $documentation,
$function_line, "", $return32, "WINAPI", $name32, \@arguments32);
$statements = "";
&$function_end;
} elsif(/DC_(GET_VAL_EX_16)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
my @lines = split(/\n/, $&);
my $function_line = $. - scalar(@lines) + 1;
$_ = $'; $again = 1;
my @arguments16 = ("HDC16", "LP" . $5 . "16");
&$function_begin($documentation_line, $documentation,
$function_line, "", "BOOL16", "WINAPI", $2 . "16", \@arguments16);
$statements = "";
&$function_end;
} elsif(/DC_(GET_VAL_EX_32)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
my @lines = split(/\n/, $&);
my $function_line = $. - scalar(@lines) + 1;
$_ = $'; $again = 1;
my @arguments32 = ("HDC", "LP" . $5);
&$function_begin($documentation_line, $documentation,
$function_line, "", "BOOL", "WINAPI", $2, \@arguments32);
$statements = "";
&$function_end;
} elsif(/DC_(SET_MODE_16)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
my @lines = split(/\n/, $&);
my $function_line = $. - scalar(@lines) + 1;
$_ = $'; $again = 1;
my @arguments16 = ("HDC16", "INT16");
&$function_begin($documentation_line, $documentation,
$function_line, "", "INT16", "WINAPI", $2 . "16", \@arguments16);
$statements = "";
&$function_end;
} elsif(/DC_(SET_MODE_32)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
my @lines = split(/\n/, $&);
my $function_line = $. - scalar(@lines) + 1;
$_ = $'; $again = 1;
my @arguments32 = ("HDC", "INT");
&$function_begin($documentation_line, $documentation,
$function_line, "", "INT", "WINAPI", $2, \@arguments32);
$statements = "";
&$function_end;
&$function_end("");
} elsif(/WAVEIN_SHORTCUT_0\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
my @lines = split(/\n/, $&);
my $function_line = $. - scalar(@lines) + 1;
$_ = $'; $again = 1;
my @arguments16 = ("HWAVEIN16");
my @arguments32 = ("HWAVEIN");
&$function_begin($documentation_line, $documentation,
$function_line, "", "UINT16", "WINAPI", "waveIn" . $1 . "16", \@arguments16);
$statements = "";
&$function_end;
&$function_end("");
&$function_begin($documentation_line, $documentation,
$function_line, "", "UINT", "WINAPI", "waveIn" . $1, \@arguments32);
$statements = "";
&$function_end;
&$function_end("");
} elsif(/WAVEOUT_SHORTCUT_0\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
my @lines = split(/\n/, $&);
my $function_line = $. - scalar(@lines) + 1;
@ -467,11 +443,10 @@ sub parse_c_file {
my @arguments32 = ("HWAVEOUT");
&$function_begin($documentation_line, $documentation,
$function_line, "", "UINT16", "WINAPI", "waveOut" . $1 . "16", \@arguments16);
$statements = "";
&$function_end;
&$function_end("");
&$function_begin($documentation_line, $documentation,
$function_line, "", "UINT", "WINAPI", "waveOut" . $1, \@arguments32);
&$function_end;
&$function_end("");
} elsif(/WAVEOUT_SHORTCUT_(1|2)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
my @lines = split(/\n/, $&);
my $function_line = $. - scalar(@lines) + 1;
@ -483,21 +458,19 @@ sub parse_c_file {
my @arguments32 = ("HWAVEOUT", $4);
&$function_begin($documentation_line, $documentation,
$function_line, "", "UINT16", "WINAPI", "waveOut" . $2 . "16", \@arguments16);
$statements = "";
&$function_end;
&$function_end("");
&$function_begin($documentation_line, $documentation,
$function_line, "", "UINT", "WINAPI", "waveOut" . $2, \@arguments32);
&$function_end;
&$function_end("");
} elsif($1 eq 2) {
my @arguments16 = ("UINT16", $4);
my @arguments32 = ("UINT", $4);
&$function_begin($documentation_line, $documentation,
$function_line, "", "UINT16", "WINAPI", "waveOut". $2 . "16", \@arguments16);
$statements = "";
&$function_end;
&$function_end("");
&$function_begin($documentation_line, $documentation,
$function_line, "", "UINT", "WINAPI", "waveOut" . $2, \@arguments32);
&$function_end;
&$function_end("");
}
} elsif(/DEFINE_REGS_ENTRYPOINT_\d+\(\s*(\S*)\s*,\s*([^\s,\)]*).*?\)/s) {
$_ = $'; $again = 1;
@ -508,6 +481,74 @@ sub parse_c_file {
} elsif(/(DEFAULT|DECLARE)_DEBUG_CHANNEL\s*\((\S+)\)/s) {
$_ = $'; $again = 1;
push @$debug_channels, $1;
} elsif(/typedef\s+(enum|struct|union)(?:\s+(\w+))?\s*\{/s) {
$_ = $'; $again = 1;
$level++;
my $type = $1;
if(defined($2)) {
$type .= " $2";
}
&$type_begin($type);
} elsif(/typedef\s+
((?:const\s+|enum\s+|long\s+|signed\s+|short\s+|struct\s+|union\s+|unsigned\s+)*?)
(\w+)
(?:\s+const)?
((?:\s*\*+\s*|\s+)\w+\s*(?:\[[^\]]*\])?
(?:\s*,\s*(?:\s*\*+\s*|\s+)\w+\s*(?:\[[^\]]*\])?)*)
\s*;/sx)
{
$_ = $'; $again = 1;
my $type = "$1 $2";
my @names;
my @parts = split(/\s*,\s*/, $2);
foreach my $part (@parts) {
if($part =~ /(?:\s*(\*+)\s*|\s+)(\w+)\s*(\[[^\]]*\])?/) {
my $name = $2;
if(defined($1)) {
$name = "$1$2";
}
if(defined($3)) {
$name .= $3;
}
push @names, $name;
}
}
&$type_begin($type);
&$type_end([@names]);
} elsif(/typedef\s+
(?:(?:const\s+|enum\s+|long\s+|signed\s+|short\s+|struct\s+|union\s+|unsigned\s+)*?)
(\w+)\s+
(?:(\w+)\s*)?
\((?:(\w+)\s+)?\s*\*\s*(\w+)\s*\)\s*
(?:\(([^\)]*)\)|\[([^\]]*)\])\s*;/sx)
{
$_ = $'; $again = 1;
my $type;
if(defined($2) || defined($3)) {
my $cc = $2 || $3;
if(defined($5)) {
$type = "$1 ($cc *)($5)";
} else {
$type = "$1 ($cc *)[$6]";
}
} else {
if(defined($5)) {
$type = "$1 (*)($5)";
} else {
$type = "$1 (*)[$6]";
}
}
my $name = $4;
&$type_begin($type);
&$type_end([$name]);
} elsif(/typedef[^\{;]*;/s) {
$_ = $'; $again = 1;
$output->write("$file: $.: can't parse: '$&'\n");
} elsif(/typedef[^\{]*\{[^\}]*\}[^;];/s) {
$_ = $'; $again = 1;
$output->write("$file: $.: can't parse: '$&'\n");
} elsif(/\'[^\']*\'/s) {
$_ = $'; $again = 1;
} elsif(/\"[^\"]*\"/s) {