From 67f0a70c33eb1baa6a329a4611766e6c0da8fb72 Mon Sep 17 00:00:00 2001 From: Patrik Stridvall Date: Thu, 26 Jul 2001 21:42:12 +0000 Subject: [PATCH] - A few more bug fixes - Reorganization continues - New tool (make_filter) for filtering make output added --- tools/winapi/config.pm | 62 ++- tools/winapi/make_filter | 70 +++ tools/winapi/make_filter_options.pm | 35 ++ tools/winapi/make_parser.pm | 664 +++++++++++++++++++++++++ tools/winapi/options.pm | 101 +++- tools/winapi/output.pm | 79 ++- tools/winapi/type.pm | 14 + tools/winapi/winapi_check_options.pm | 8 +- tools/winapi/winapi_extract | 49 +- tools/winapi/winapi_extract_options.pm | 2 +- tools/winapi/winapi_fixup | 38 +- tools/winapi_check/modules.dat | 1 - tools/winapi_check/modules.pm | 81 ++- tools/winapi_check/nativeapi.pm | 30 +- tools/winapi_check/winapi.pm | 114 ++--- tools/winapi_check/winapi_check | 174 +++---- tools/winapi_check/winapi_global.pm | 8 - tools/winapi_check/winapi_parser.pm | 365 ++++++++------ 18 files changed, 1418 insertions(+), 477 deletions(-) create mode 100755 tools/winapi/make_filter create mode 100644 tools/winapi/make_filter_options.pm create mode 100644 tools/winapi/make_parser.pm create mode 100644 tools/winapi/type.pm diff --git a/tools/winapi/config.pm b/tools/winapi/config.pm index 852ef8b8214..3d950e6c442 100644 --- a/tools/winapi/config.pm +++ b/tools/winapi/config.pm @@ -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", @_); } diff --git a/tools/winapi/make_filter b/tools/winapi/make_filter new file mode 100755 index 00000000000..03c6aac34c5 --- /dev/null +++ b/tools/winapi/make_filter @@ -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() { + 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(); diff --git a/tools/winapi/make_filter_options.pm b/tools/winapi/make_filter_options.pm new file mode 100644 index 00000000000..ceecd77bf95 --- /dev/null +++ b/tools/winapi/make_filter_options.pm @@ -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; diff --git a/tools/winapi/make_parser.pm b/tools/winapi/make_parser.pm new file mode 100644 index 00000000000..63037d9bef4 --- /dev/null +++ b/tools/winapi/make_parser.pm @@ -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; diff --git a/tools/winapi/options.pm b/tools/winapi/options.pm index 6ff005fd90d..ac6d0617036 100644 --- a/tools/winapi/options.pm +++ b/tools/winapi/options.pm @@ -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; diff --git a/tools/winapi/output.pm b/tools/winapi/output.pm index 7c9bf0d427c..018d63f3e3f 100644 --- a/tools/winapi/output.pm +++ b/tools/winapi/output.pm @@ -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 { diff --git a/tools/winapi/type.pm b/tools/winapi/type.pm new file mode 100644 index 00000000000..3608355e7bc --- /dev/null +++ b/tools/winapi/type.pm @@ -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; diff --git a/tools/winapi/winapi_check_options.pm b/tools/winapi/winapi_check_options.pm index 22d5e8a466f..88dab8c317b 100644 --- a/tools/winapi/winapi_check_options.pm +++ b/tools/winapi/winapi_check_options.pm @@ -127,16 +127,10 @@ my %options_short = ( "v" => "verbose" ); -my $options_usage = "usage: winapi_fixup [--help] []\n"; +my $options_usage = "usage: winapi_check [--help] []\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); diff --git a/tools/winapi/winapi_extract b/tools/winapi/winapi_extract index c93c1e29e20..842383698d4 100755 --- a/tools/winapi/winapi_extract +++ b/tools/winapi/winapi_extract @@ -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; diff --git a/tools/winapi/winapi_extract_options.pm b/tools/winapi/winapi_extract_options.pm index 0e4e9782000..3d296213c05 100644 --- a/tools/winapi/winapi_extract_options.pm +++ b/tools/winapi/winapi_extract_options.pm @@ -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 = ( diff --git a/tools/winapi/winapi_fixup b/tools/winapi/winapi_fixup index 4a87ba22265..f04313842a2 100755 --- a/tools/winapi/winapi_fixup +++ b/tools/winapi/winapi_fixup @@ -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; diff --git a/tools/winapi_check/modules.dat b/tools/winapi_check/modules.dat index eb72aba5dca..706a32e6dae 100644 --- a/tools/winapi_check/modules.dat +++ b/tools/winapi_check/modules.dat @@ -344,7 +344,6 @@ dlls/user % dlls/user/user.spec controls -dlls/kernel dlls/user misc windows diff --git a/tools/winapi_check/modules.pm b/tools/winapi_check/modules.pm index 34f338e3db2..357e8504dfb 100644 --- a/tools/winapi_check/modules.pm +++ b/tools/winapi_check/modules.pm @@ -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); } } diff --git a/tools/winapi_check/nativeapi.pm b/tools/winapi_check/nativeapi.pm index e73a6ca7136..dc5bf38d349 100644 --- a/tools/winapi_check/nativeapi.pm +++ b/tools/winapi_check/nativeapi.pm @@ -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); } } diff --git a/tools/winapi_check/winapi.pm b/tools/winapi_check/winapi.pm index e58e1fe6f5d..813aa6ad7ef 100644 --- a/tools/winapi_check/winapi.pm +++ b/tools/winapi_check/winapi.pm @@ -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() { 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 % statement\n"); + $output->write("$file: file must begin with % 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}}; diff --git a/tools/winapi_check/winapi_check b/tools/winapi_check/winapi_check index 0c64082ee2f..f327cd56656 100755 --- a/tools/winapi_check/winapi_check +++ b/tools/winapi_check/winapi_check @@ -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; + } } + diff --git a/tools/winapi_check/winapi_global.pm b/tools/winapi_check/winapi_global.pm index bb302e5141c..d58b2849e2c 100644 --- a/tools/winapi_check/winapi_global.pm +++ b/tools/winapi_check/winapi_global.pm @@ -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))) { diff --git a/tools/winapi_check/winapi_parser.pm b/tools/winapi_check/winapi_parser.pm index 077ce10bae6..5aa3b3ad690 100644 --- a/tools/winapi_check/winapi_parser.pm +++ b/tools/winapi_check/winapi_parser.pm @@ -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) {