- Updated API files

- Better headers and prototype checking
- Prototype checking now called --prototype instead of --headers
- New options --headers-{duplicated,misplaced} for
  duplicated/misplaced functions checking of the headers.
- Minor bug fixes.
This commit is contained in:
Patrik Stridvall 2000-05-23 23:37:51 +00:00 committed by Alexandre Julliard
parent 4615e29c58
commit 0d9748159d
9 changed files with 256 additions and 110 deletions

View file

@ -145,14 +145,21 @@ files
dlls/ole32 dlls/ole32
% dlls/ole32/ole2nls.spec
dlls/ole32
% dlls/ole32/ole32.spec % dlls/ole32/ole32.spec
dlls/ole32 dlls/ole32
% dlls/ole32/ole2conv.spec
% dlls/ole32/ole2nls.spec
dlls/ole32
ole
% dlls/ole32/ole2prox.spec
% dlls/ole32/ole2thk.spec
% dlls/ole32/storage.spec % dlls/ole32/storage.spec
dlls/ole32 dlls/ole32
@ -258,6 +265,11 @@ dlls/user
memory memory
windows windows
% dlls/user/ddeml.spec
dlls/user
misc
% dlls/user/user.spec % dlls/user/user.spec
controls controls
@ -393,10 +405,6 @@ dlls/x11drv
% if1632/comm.spec % if1632/comm.spec
% if1632/ddeml.spec
misc
% if1632/dispdib.spec % if1632/dispdib.spec
graphics graphics
@ -414,16 +422,6 @@ relay32
scheduler scheduler
win32 win32
% if1632/ole2conv.spec
% if1632/ole2nls.spec
ole
% if1632/ole2prox.spec
% if1632/ole2thk.spec
% if1632/system.spec % if1632/system.spec
misc misc

View file

@ -52,6 +52,11 @@ sub new {
if(/^%\s+(.*?)$/) { if(/^%\s+(.*?)$/) {
$spec_file = $1; $spec_file = $1;
if(!-f "$wine_dir/$spec_file") {
$$output->write("$module_file: $spec_file: file ($spec_file) doesn't exist or is no file\n");
}
if($wine_dir eq ".") { if($wine_dir eq ".") {
$all_spec_files{$spec_file}--; $all_spec_files{$spec_file}--;
} else { } else {

View file

@ -16,6 +16,7 @@ _sysconf
_xmknod _xmknod
_xstat _xstat
abs abs
accept
access access
acos acos
asctime asctime
@ -26,14 +27,18 @@ atexit
atof atof
atoi atoi
atol atol
bind
bsearch bsearch
bzero bzero
calloc calloc
ceil ceil
cfgetospeed cfgetospeed
chmod chmod
clock
close close
closedir closedir
closesocket
connect
cos cos
cosh cosh
ctime ctime
@ -66,23 +71,39 @@ fputs
fread fread
free free
frexp frexp
freopen
fscanf
fseek fseek
fsetpos fsetpos
fsync fsync
ftell
ftruncate ftruncate
fwrite fwrite
getc
getcwd getcwd
getenv getenv
gethostbyaddr
gethostbyname
gethostname
getlogin getlogin
getnetbyname getnetbyname
getpeername
getpid getpid
getpwuid getpwuid
gets
getservbyname
getsockname
gettimeofday gettimeofday
getuid getuid
gmtime gmtime
htonl
htons
hypot hypot
inet_addr
inet_network inet_network
inet_ntoa
ioctl ioctl
ioctlsocket
isalnum isalnum
isalpha isalpha
isatty isatty
@ -102,6 +123,7 @@ kill
labs labs
ldexp ldexp
ldiv ldiv
listen
localtime localtime
log log
log10 log10
@ -121,6 +143,8 @@ modf
mprotect mprotect
msync msync
munmap munmap
ntohl
ntohs
open open
opendir opendir
perror perror
@ -128,6 +152,7 @@ pipe
poll poll
pow pow
printf printf
putc
putchar putchar
putenv putenv
puts puts
@ -137,19 +162,25 @@ rand
read read
readdir readdir
realloc realloc
recv
recvfrom
remove remove
rename rename
rmdir rmdir
select select
send
sendto
setbuf setbuf
setlocale setlocale
setsid setsid
setsockopt
settimeofday settimeofday
setvbuf setvbuf
shmat shmat
shmctl shmctl
shmdt shmdt
shmget shmget
shutdown
sigaction sigaction
sigaddset sigaddset
sigaltstack sigaltstack
@ -160,6 +191,7 @@ sin
sin sin
sinh sinh
sleep sleep
socket
snprintf snprintf
sprintf sprintf
sqrt sqrt

View file

@ -1,3 +1,8 @@
%double
GLclampd
GLdouble
%long %long
BOOL BOOL
@ -6,9 +11,7 @@ FLOAT
GLbitfield GLbitfield
GLboolean GLboolean
GLbyte GLbyte
GLclampd
GLclampf GLclampf
GLdouble
GLenum GLenum
GLfloat GLfloat
GLint GLint

View file

@ -215,6 +215,7 @@ sub parse_spec_file {
my $output = \${$self->{OUTPUT}}; my $output = \${$self->{OUTPUT}};
my $function_arguments = \%{$self->{FUNCTION_ARGUMENTS}}; my $function_arguments = \%{$self->{FUNCTION_ARGUMENTS}};
my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}}; my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};
my $function_external_name = \%{$self->{FUNCTION_EXTERNAL_NAME}};
my $function_stub = \%{$self->{FUNCTION_STUB}}; my $function_stub = \%{$self->{FUNCTION_STUB}};
my $function_module = \%{$self->{FUNCTION_MODULE}}; my $function_module = \%{$self->{FUNCTION_MODULE}};
my $modules = \%{$self->{MODULES}}; my $modules = \%{$self->{MODULES}};
@ -256,6 +257,7 @@ sub parse_spec_file {
$ordinal = $1; $ordinal = $1;
# FIXME: Internal name existing more than once not handled properly # FIXME: Internal name existing more than once not handled properly
$$function_external_name{$internal_name} = $external_name;
$$function_arguments{$internal_name} = $arguments; $$function_arguments{$internal_name} = $arguments;
$$function_calling_convention{$internal_name} = $calling_convention; $$function_calling_convention{$internal_name} = $calling_convention;
if(!$$function_module{$internal_name}) { if(!$$function_module{$internal_name}) {
@ -571,6 +573,15 @@ sub function_calling_convention {
return $$function_calling_convention{$name}; return $$function_calling_convention{$name};
} }
sub function_external_name {
my $self = shift;
my $function_external_name = \%{$self->{FUNCTION_EXTERNAL_NAME}};
my $name = shift;
return $$function_external_name{$name};
}
sub is_function { sub is_function {
my $self = shift; my $self = shift;
my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}}; my $function_calling_convention = \%{$self->{FUNCTION_CALLING_CONVENTION}};

View file

@ -1,6 +1,16 @@
#!/usr/bin/perl -w #!/usr/bin/perl -w
# Copyright 1999 Patrik Stridvall # Copyright 1999-2000 Patrik Stridvall
# Note that winapi_check are using heuristics quite heavily.
# So always remember that:
#
# "Heuristics are bug ridden by definition.
# If they didn't have bugs, then they'd be algorithms."
#
# In other words, reported bugs are only potential bugs not
# real bugs, so they are called issues rather than bugs.
#
use strict; use strict;
@ -92,6 +102,7 @@ my $modules = 'modules'->new($options, $output, $wine_dir, $current_dir, \&file_
my $win16api = 'winapi'->new($options, $output, "win16", "$winapi_check_dir/win16"); my $win16api = 'winapi'->new($options, $output, "win16", "$winapi_check_dir/win16");
my $win32api = 'winapi'->new($options, $output, "win32", "$winapi_check_dir/win32"); my $win32api = 'winapi'->new($options, $output, "win32", "$winapi_check_dir/win32");
my @winapis = ($win16api, $win32api);
if($options->global) { if($options->global) {
'winapi'->read_all_spec_files($modules, $wine_dir, $current_dir, \&file_type, $win16api, $win32api); 'winapi'->read_all_spec_files($modules, $wine_dir, $current_dir, \&file_type, $win16api, $win32api);
@ -176,12 +187,49 @@ if($options->headers) {
my $linkage = shift; my $linkage = shift;
my $return_type = shift; my $return_type = shift;
my $calling_convention = shift; my $calling_convention = shift;
my $name = shift; my $internal_name = shift;
my $refarguments = shift; my $refargument_types = shift;
my @arguments = @$refarguments; my @argument_types = @$refargument_types;
my $refargument_names = shift;
my @argument_names = @$refargument_names;
my $statements = shift; my $statements = shift;
$declared_functions{$name}++; foreach my $winapi (@winapis) {
my $module = $winapi->function_module($internal_name);
if(!defined($module)) { next }
my $external_name = $winapi->function_external_name($internal_name);
# FIXME: Kludge because of the THUNK variants
if(!defined($external_name)) {
next;
}
my $output_function = sub {
my $message = shift;
$output->write("$file: $module: $return_type ");
$output->write("$calling_convention ") if $calling_convention;
$output->write("$internal_name(" . join(",", @argument_types) . "): $message\n");
};
if(!defined($declared_functions{$winapi->name}{$external_name})) {
$declared_functions{$winapi->name}{$external_name} = "$file";
} elsif($options->headers_duplicated) {
my $message = "declared more than once";
if($file ne $declared_functions{$winapi->name}{$external_name}) {
$message .= ", first declaration in '" . $declared_functions{$winapi->name}{$external_name} . "'";
}
&$output_function("$message");
}
if($options->headers_misplaced) {
if($file =~ /^include\/[^\/]*$/ && $winapi->name eq "win16") {
&$output_function("declaration misplaced");
} elsif($file =~ /^include\/wine\/[^\/]*$/ && $winapi->name eq "win32") {
&$output_function("declaration misplaced");
}
}
}
}; };
my $found_preprocessor = sub { my $found_preprocessor = sub {
@ -221,13 +269,15 @@ foreach my $file ($options->c_files) {
my $return_type = shift; my $return_type = shift;
my $calling_convention = shift; my $calling_convention = shift;
my $internal_name = shift; my $internal_name = shift;
my $external_name = $internal_name;
my $refargument_types = shift; my $refargument_types = shift;
my @argument_types = @$refargument_types; my @argument_types = @$refargument_types;
my $refargument_names = shift; my $refargument_names = shift;
my @argument_names = @$refargument_names; my @argument_names = @$refargument_names;
my $statements = shift; my $statements = shift;
my $external_name16 = $win16api->function_external_name($internal_name);
my $external_name32 = $win32api->function_external_name($internal_name);
if($options->global) { if($options->global) {
$win16api->found_type($return_type) if $options->win16; $win16api->found_type($return_type) if $options->win16;
$win32api->found_type($return_type) if $options->win32; $win32api->found_type($return_type) if $options->win32;
@ -242,40 +292,7 @@ foreach my $file ($options->c_files) {
if($file_type ne "application") { if($file_type ne "application") {
my $module16 = $win16api->function_module($internal_name); my $module16 = $win16api->function_module($internal_name);
if(!defined($module16)) {
if($internal_name =~ /^(.*?)_(.*?)$/) {
my $module2 = lc($1);
my $name2 = $2;
if($win16api->is_module($module2)) {
$module16 = $win16api->function_module($name2);
if(defined($module16)) {
if(uc($module16) !~ /\U$module2\E/) {
$external_name = $name2;
} else {
$module16 = undef;
}
}
}
}
}
my $module32 = $win32api->function_module($internal_name); my $module32 = $win32api->function_module($internal_name);
if(!defined($module32)) {
if($internal_name =~ /^(.*?)_(.*?)$/) {
my $module2 = lc($1);
my $name2 = $2;
if($win32api->is_module($module2)) {
$module32 = $win32api->function_module($name2);
if(defined($module32)) {
if(uc($module32) =~ /\U$module2\E/) {
$external_name = $name2;
} else {
$module32 = undef;
}
}
}
}
}
my $function = 'winapi_function'->new; my $function = 'winapi_function'->new;
$functions{$internal_name} = $function; $functions{$internal_name} = $function;
@ -285,7 +302,8 @@ foreach my $file ($options->c_files) {
$function->file($file); $function->file($file);
$function->return_type($return_type); $function->return_type($return_type);
$function->calling_convention($calling_convention); $function->calling_convention($calling_convention);
$function->external_name($external_name); $function->external_name16($external_name16);
$function->external_name32($external_name32);
$function->internal_name($internal_name); $function->internal_name($internal_name);
$function->argument_types([@argument_types]); $function->argument_types([@argument_types]);
$function->argument_names([@argument_names]); $function->argument_names([@argument_names]);
@ -337,25 +355,43 @@ foreach my $file ($options->c_files) {
} }
} }
if($options->local && $options->headers) { if($options->local && $options->headers && $options->prototype) {
if(!$declared_functions{$internal_name}) { if($options->win16 && $options->report_module($module16)) {
if($options->win16 && $options->report_module($module16)) { if(!defined($external_name16) || (!$nativeapi->is_function($external_name16) &&
&$output16("no prototype"); !defined($declared_functions{$win16api->name}{$external_name16})))
{
if(!defined($external_name16) || ($external_name16 !~ /^DllEntryPoint$/ &&
$internal_name !~ /^I(?:Malloc|Storage)16_fn/ &&
$internal_name !~ /^(?:\Q$module16\E|THUNK|WIN16)_\Q$external_name16\E(?:16)?$/))
{
&$output16("no prototype");
}
} }
if($options->win32 && $options->report_module($module32)) { }
&$output32("no prototype");
if($options->win32 && $options->report_module($module32)) {
if(!defined($external_name32) || (!$nativeapi->is_function($external_name32) && !defined($declared_functions{$win32api->name}{$external_name32})))
{
if(!defined($external_name32) || ($external_name32 !~ /^Dll(?:
Install|CanUnloadNow|GetClassObject|GetVersion|
RegisterServer|RegisterServerEx|UnregisterServer)|DriverProc$/x &&
$internal_name !~ /^COMCTL32_Str/ &&
$internal_name !~ /^(?:\Q$module32\E|wine)_(?:\Q$external_name32\E|\d+)$/))
{
&$output32("no prototype");
}
} }
} }
} }
if($options->local && $options->argument) { if($options->local && $options->argument) {
if($options->win16 && $options->report_module($module16)) { if($options->win16 && $options->report_module($module16)) {
winapi_local::check_function $options, $output16, winapi_local::check_function $options, $output16,
$return_type, $calling_convention, $external_name, $internal_name, [@argument_types], $win16api; $return_type, $calling_convention, $external_name16, $internal_name, [@argument_types], $win16api;
} }
if($options->win32 && $options->report_module($module32)) { if($options->win32 && $options->report_module($module32)) {
winapi_local::check_function $options, $output32, winapi_local::check_function $options, $output32,
$return_type, $calling_convention, $external_name, $internal_name, [@argument_types], $win32api; $return_type, $calling_convention, $external_name32, $internal_name, [@argument_types], $win32api;
} }
} }

View file

@ -66,15 +66,26 @@ sub calling_convention {
return $$calling_convention; return $$calling_convention;
} }
sub external_name { sub external_name16 {
my $self = shift; my $self = shift;
my $external_name = \${$self->{EXTERNAL_NAME}}; my $external_name16 = \${$self->{EXTERNAL_NAME16}};
local $_ = shift; local $_ = shift;
if(defined($_)) { $$external_name = $_; } if(defined($_)) { $$external_name16 = $_; }
return $$external_name; return $$external_name16;
}
sub external_name32 {
my $self = shift;
my $external_name32 = \${$self->{EXTERNAL_NAME32}};
local $_ = shift;
if(defined($_)) { $$external_name32 = $_; }
return $$external_name32;
} }
sub internal_name { sub internal_name {

View file

@ -13,23 +13,23 @@ sub check_function {
my @argument_types = @$refargument_types; my @argument_types = @$refargument_types;
my $winapi = shift; my $winapi = shift;
my $module = $winapi->function_module($external_name); my $module = $winapi->function_module($internal_name);
if($winapi->name eq "win16") { if($winapi->name eq "win16") {
my $name16 = $external_name; my $name16 = $internal_name;
$name16 =~ s/16$//; $name16 =~ s/16$//;
if($name16 ne $external_name && $winapi->function_stub($name16)) { if($name16 ne $internal_name && $winapi->function_stub($name16)) {
if($options->implemented) { if($options->implemented) {
&$output("function implemented but declared as stub in .spec file"); &$output("function implemented but declared as stub in .spec file");
} }
return; return;
} elsif($winapi->function_stub($external_name)) { } elsif($winapi->function_stub($internal_name)) {
if($options->implemented_win32) { if($options->implemented_win32) {
&$output("32-bit variant of function implemented but declared as stub in .spec file"); &$output("32-bit variant of function implemented but declared as stub in .spec file");
} }
return; return;
} }
} elsif($winapi->function_stub($external_name)) { } elsif($winapi->function_stub($internal_name)) {
if($options->implemented) { if($options->implemented) {
&$output("function implemented but declared as stub in .spec file"); &$output("function implemented but declared as stub in .spec file");
} }
@ -80,8 +80,8 @@ sub check_function {
} }
} }
my $declared_calling_convention = $winapi->function_calling_convention($external_name); my $declared_calling_convention = $winapi->function_calling_convention($internal_name);
my @declared_argument_kinds = split(/\s+/, $winapi->function_arguments($external_name)); my @declared_argument_kinds = split(/\s+/, $winapi->function_arguments($internal_name));
if($declared_calling_convention =~ /^register|interrupt$/) { if($declared_calling_convention =~ /^register|interrupt$/) {
push @declared_argument_kinds, "ptr"; push @declared_argument_kinds, "ptr";
@ -112,7 +112,7 @@ sub check_function {
} }
if($#argument_types != -1 && $argument_types[$#argument_types] eq "CONTEXT *" && if($#argument_types != -1 && $argument_types[$#argument_types] eq "CONTEXT *" &&
$external_name !~ /^(Get|Set)ThreadContext$/) # FIXME: Kludge $internal_name !~ /^(Get|Set)ThreadContext$/) # FIXME: Kludge
{ {
$#argument_types--; $#argument_types--;
} }

View file

@ -61,7 +61,7 @@ my %options = (
"calling-convention" => { default => 0, parent => "local", description => "calling convention checking" }, "calling-convention" => { default => 0, parent => "local", description => "calling convention checking" },
"misplaced" => { default => 1, parent => "local", description => "check for misplaced functions" }, "misplaced" => { default => 1, parent => "local", description => "check for misplaced functions" },
"statements" => { default => 0, parent => "local", description => "check for statements inconsistances" }, "statements" => { default => 0, parent => "local", description => "check for statements inconsistances" },
"cross-call" => { default => 0, parent => "statements", description => "check for cross calling functions" }, "cross-call" => { default => 0, parent => "statements", description => "check for cross calling functions" },
"cross-call-win32-win16" => { "cross-call-win32-win16" => {
default => 0, parent => "cross-call", description => "check for cross calls between win32 and win16" default => 0, parent => "cross-call", description => "check for cross calls between win32 and win16"
}, },
@ -71,13 +71,16 @@ my %options = (
"debug-messages" => { default => 0, parent => "statements", description => "check for debug messages inconsistances" }, "debug-messages" => { default => 0, parent => "statements", description => "check for debug messages inconsistances" },
"documentation" => { default => 1, parent => "local", description => "check for documentation inconsistances\n" }, "documentation" => { default => 1, parent => "local", description => "check for documentation inconsistances\n" },
"documentation-width" => { default => 0, parent => "documentation", description => "check for documentation width inconsistances\n" }, "documentation-width" => { default => 0, parent => "documentation", description => "check for documentation width inconsistances\n" },
"prototype" => { default => 0, parent => ["local", "headers"], description => "prototype checking" },
"global" => { default => 1, description => "global checking" }, "global" => { default => 1, description => "global checking" },
"declared" => { default => 1, parent => "global", description => "declared checking" }, "declared" => { default => 1, parent => "global", description => "declared checking" },
"implemented" => { default => 1, parent => "global", description => "implemented checking" }, "implemented" => { default => 1, parent => "global", description => "implemented checking" },
"implemented-win32" => { default => 0, parent => "implemented", description => "implemented as win32 checking" }, "implemented-win32" => { default => 0, parent => "implemented", description => "implemented as win32 checking" },
"include" => { default => 1, parent => "global", description => "include checking" }, "include" => { default => 1, parent => "global", description => "include checking" },
"headers" => { default => 0, parent => "global", description => "headers checking" }, "headers" => { default => 0, parent => "global", description => "headers checking" },
"headers-duplicated" => { default => 0, parent => "headers", description => "duplicated function declarations checking" },
"headers-misplaced" => { default => 0, parent => "headers", description => "misplaced function declarations checking" },
"stubs" => { default => 0, parent => "global", description => "stubs checking" } "stubs" => { default => 0, parent => "global", description => "stubs checking" }
); );
@ -106,6 +109,8 @@ sub new {
my $module = \${$self->{MODULE}}; my $module = \${$self->{MODULE}};
my $global = \${$self->{GLOBAL}}; my $global = \${$self->{GLOBAL}};
my @files;
if($wine_dir eq ".") { if($wine_dir eq ".") {
$$global = 1; $$global = 1;
} else { } else {
@ -151,8 +156,16 @@ sub new {
if(defined($option)) { if(defined($option)) {
my $key = $$option{key}; my $key = $$option{key};
my $parser = $$option{parser}; my $parser = $$option{parser};
my $parent = $$option{parent};
my $refvalue = \${$self->{$key}}; my $refvalue = \${$self->{$key}};
my @parents = ();
if(defined($$option{parent})) {
if(ref($$option{parent}) eq "ARRAY") {
@parents = @{$$option{parent}};
} else {
@parents = $$option{parent};
}
}
if(defined($parser)) { if(defined($parser)) {
$$refvalue = &$parser($prefix,$value); $$refvalue = &$parser($prefix,$value);
@ -167,12 +180,23 @@ sub new {
} }
if((ref($$refvalue) eq "HASH" && $$refvalue->{active}) || $$refvalue) { if((ref($$refvalue) eq "HASH" && $$refvalue->{active}) || $$refvalue) {
while(defined($parent)) { while($#parents >= 0) {
my $parentkey = $options{$parent}{key}; my @old_parents = @parents;
my $refparentvalue = \${$self->{$parentkey}}; @parents = ();
foreach my $parent (@old_parents) {
$$refparentvalue = 1; my $parentkey = $options{$parent}{key};
$parent = $options{$parent}{parent}; my $refparentvalue = \${$self->{$parentkey}};
$$refparentvalue = 1;
if(defined($options{$parent}{parent})) {
if(ref($options{$parent}{parent}) eq "ARRAY") {
push @parents, @{$options{$parent}{parent}};
} else {
push @parents, $options{$parent}{parent};
}
}
}
} }
} }
next; next;
@ -201,7 +225,7 @@ sub new {
return undef; return undef;
} }
push @$c_files, $_; push @files, $_;
} }
} }
@ -209,30 +233,56 @@ sub new {
return $self; return $self;
} }
my $c_paths; my @paths = ();
if($#$c_files == -1 || ($#$c_files == 0 && $$c_files[0] eq $wine_dir)) { my @c_files = ();
$c_paths = "."; my @h_files = ();
foreach my $file (@files) {
if($file =~ /\.c$/) {
push @c_files, $file;
} elsif($file =~ /\.h$/) {
push @h_files, $file;
} else {
push @paths, $file;
}
}
if($#c_files == -1 && $#h_files == -1 &&
($#paths == -1 || ($#paths == 0 && $paths[0] eq $wine_dir)))
{
@paths = ".";
push @h_files, "$wine_dir/include";
} else { } else {
$c_paths = join(" ", @$c_files);
$$global = 0; $$global = 0;
} }
my $h_paths = "$wine_dir/include $wine_dir/include/wine"; if($#paths != -1 || $#c_files != -1) {
my $c_command = "find " . join(" ", @paths, @c_files) . " -name \\*.c";
my %found;
@$c_files = sort(map {
s/^\.\/(.*)$/$1/;
if(defined($found{$_}) || /glue\.c|spec\.c$/) {
();
} else {
$found{$_}++;
$_;
}
} split(/\n/, `$c_command`));
}
@$c_files = sort(map { if($#h_files != -1) {
s/^.\/(.*)$/$1/; my $h_command = "find " . join(" ", @h_files) . " -name \\*.h";
if(/glue\.c|spec\.c$/) { my %found;
();
} else {
$_;
}
} split(/\n/, `find $c_paths -name \\*.c`));
@$h_files = sort(map {
s/^.\/(.*)$/$1/;
$_;
} split(/\n/, `find $h_paths -name \\*.h`));
@$h_files = sort(map {
s/^\.\/(.*)$/$1/;
if(defined($found{$_})) {
();
} else {
$found{$_}++;
$_;
}
} split(/\n/, `$h_command`));
}
return $self; return $self;
} }