summaryrefslogtreecommitdiff
path: root/modules/Depgen
diff options
context:
space:
mode:
authorelliott_c <ocielliottc@users.noreply.github.com>2007-03-22 13:40:17 +0000
committerelliott_c <ocielliottc@users.noreply.github.com>2007-03-22 13:40:17 +0000
commit74a12ccd024964043dfaf7c556757c6d871f6c04 (patch)
treee57004bcbad72e76551400e83371f435f9b29585 /modules/Depgen
parent292a5e1b6a6741fe1f297252ecb3de0a7a155c25 (diff)
downloadMPC-74a12ccd024964043dfaf7c556757c6d871f6c04.tar.gz
ChangeLogTag: Thu Mar 22 14:36:53 UTC 2007 Chad Elliott <elliott_c@ociweb.com>
Diffstat (limited to 'modules/Depgen')
-rw-r--r--modules/Depgen/DependencyEditor.pm118
-rw-r--r--modules/Depgen/DependencyGenerator.pm77
-rw-r--r--modules/Depgen/DependencyWriter.pm33
-rw-r--r--modules/Depgen/DependencyWriterFactory.pm42
-rw-r--r--modules/Depgen/Driver.pm255
-rw-r--r--modules/Depgen/MakeDependencyWriter.pm32
-rw-r--r--modules/Depgen/MakeObjectGenerator.pm47
-rw-r--r--modules/Depgen/NMakeDependencyWriter.pm53
-rw-r--r--modules/Depgen/NMakeObjectGenerator.pm28
-rw-r--r--modules/Depgen/ObjectGenerator.pm32
-rw-r--r--modules/Depgen/ObjectGeneratorFactory.pm42
-rw-r--r--modules/Depgen/Preprocessor.pm147
12 files changed, 906 insertions, 0 deletions
diff --git a/modules/Depgen/DependencyEditor.pm b/modules/Depgen/DependencyEditor.pm
new file mode 100644
index 00000000..646ae2ae
--- /dev/null
+++ b/modules/Depgen/DependencyEditor.pm
@@ -0,0 +1,118 @@
+package DependencyEditor;
+
+# ************************************************************
+# Description : Edits existing dependencies.
+# Author : Chad Elliott
+# Create Date : 2/10/2002
+# ************************************************************
+
+# ************************************************************
+# Pragmas
+# ************************************************************
+
+use strict;
+use FileHandle;
+
+use DependencyGenerator;
+
+# ************************************************************
+# Subroutine Section
+# ************************************************************
+
+sub new {
+ return bless {
+ }, $_[0];
+}
+
+
+sub process {
+ my($self) = shift;
+ my($output) = shift;
+ my($type) = shift;
+ my($noinline) = shift;
+ my($macros) = shift;
+ my($ipaths) = shift;
+ my($replace) = shift;
+ my($exclude) = shift;
+ my($files) = shift;
+
+ ## Back up the original file and receive the contents
+ my($contents) = undef;
+ if (-s $output) {
+ $contents = [];
+ if (!$self->backup($output, $contents)) {
+ print STDERR "ERROR: Unable to backup $output\n";
+ return 1;
+ }
+ }
+
+ ## Write out the new file
+ my($fh) = new FileHandle();
+ if (open($fh, ">$output")) {
+ if (defined $contents) {
+ foreach my $line (@$contents) {
+ print $fh $line;
+ }
+ }
+
+ print $fh "# DO NOT DELETE THIS LINE -- depgen.pl uses it.\n",
+ "# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.\n\n";
+
+ my($dep) = new DependencyGenerator($macros, $ipaths, $replace,
+ $type, $noinline, $exclude);
+ ## Sort the files so the dependencies are reproducible
+ foreach my $file (sort @$files) {
+ print $fh $dep->process($file), "\n";
+ }
+
+ print $fh "# IF YOU PUT ANYTHING HERE IT WILL GO AWAY\n";
+ close($fh);
+ }
+ else {
+ print STDERR "ERROR: Unable to open $output for output\n";
+ return 1;
+ }
+
+ return 0;
+}
+
+
+sub backup {
+ my($self) = shift;
+ my($source) = shift;
+ my($contents) = shift;
+ my($status) = 0;
+ my($fh) = new FileHandle();
+ my($backup) = "$source.bak";
+
+ if (open($fh, $source)) {
+ my($oh) = new FileHandle();
+ if (open($oh, ">$backup")) {
+ my($record) = 1;
+ $status = 1;
+ while(<$fh>) {
+ print $oh $_;
+ if ($record) {
+ if (index($_, 'DO NOT DELETE') >= 0) {
+ $record = undef;
+ }
+ else {
+ push(@$contents, $_);
+ }
+ }
+ }
+ close($oh);
+
+ ## Set file permission
+ my(@buf) = stat($source);
+ if (defined $buf[8] && defined $buf[9]) {
+ utime($buf[8], $buf[9], $backup);
+ }
+ }
+ close($fh);
+ }
+ return $status;
+}
+
+
+1;
diff --git a/modules/Depgen/DependencyGenerator.pm b/modules/Depgen/DependencyGenerator.pm
new file mode 100644
index 00000000..58caa43b
--- /dev/null
+++ b/modules/Depgen/DependencyGenerator.pm
@@ -0,0 +1,77 @@
+package DependencyGenerator;
+
+# ************************************************************
+# Description : Runs the correct dependency generator on the file.
+# Author : Chad Elliott
+# Create Date : 2/10/2002
+# ************************************************************
+
+# ************************************************************
+# Pragmas
+# ************************************************************
+
+use strict;
+
+use Preprocessor;
+use DependencyWriterFactory;
+use ObjectGeneratorFactory;
+
+# ************************************************************
+# Subroutine Section
+# ************************************************************
+
+sub new {
+ my($class) = shift;
+ my($macros) = shift;
+ my($ipaths) = shift;
+ my($replace) = shift;
+ my($type) = shift;
+ my($noinline) = shift;
+ my($exclude) = shift;
+ my($self) = bless {'pre' => new Preprocessor($macros,
+ $ipaths, $exclude),
+ 'replace' => $replace,
+ 'dwrite' => DependencyWriterFactory::create($type),
+ 'objgen' => ObjectGeneratorFactory::create($type),
+ 'noinline' => $noinline,
+ }, $class;
+
+ ## Set the current working directory, but
+ ## escape regular expression special characters
+ $self->{'cwd'} = Cwd::getcwd() . '/';
+ $self->{'cwd'} =~ s/([\+\-\\\$\[\]\(\)\.])/\\$1/g;
+
+ ## Sort the replace keys to get the longest key first. This way
+ ## when we are replacing portions of the file path, we replace the
+ ## most we can.
+ my(@repkeys) = sort { length($b) <=> length($a) } keys %$replace;
+ $self->{'repkeys'} = \@repkeys;
+
+ return $self;
+}
+
+
+sub process {
+ my($self) = shift;
+ my($file) = shift;
+
+ ## Generate the dependency string
+ my($depstr) = $self->{'dwrite'}->process(
+ $self->{'objgen'}->process($file),
+ $self->{'pre'}->process($file, $self->{'noinline'}));
+
+ ## Perform the replacements on the dependency string
+ if ($depstr =~ s/$self->{'cwd'}//go) {
+ }
+ else {
+ my($replace) = $self->{'replace'};
+ foreach my $rep (@{$self->{'repkeys'}}) {
+ $depstr =~ s/$rep/$$replace{$rep}/g;
+ }
+ }
+
+ return $depstr;
+}
+
+
+1;
diff --git a/modules/Depgen/DependencyWriter.pm b/modules/Depgen/DependencyWriter.pm
new file mode 100644
index 00000000..c0c82430
--- /dev/null
+++ b/modules/Depgen/DependencyWriter.pm
@@ -0,0 +1,33 @@
+package DependencyWriter;
+
+# ************************************************************
+# Description : Base class for all Dependency Writers.
+# Author : Chad Elliott
+# Create Date : 2/10/2002
+# ************************************************************
+
+# ************************************************************
+# Pragmas
+# ************************************************************
+
+use strict;
+
+# ************************************************************
+# Subroutine Section
+# ************************************************************
+
+sub new {
+ return bless {
+ }, $_[0];
+}
+
+
+sub process {
+ #my($self) = shift;
+ #my($objects) = shift;
+ #my($files) = shift;
+ return '';
+}
+
+
+1;
diff --git a/modules/Depgen/DependencyWriterFactory.pm b/modules/Depgen/DependencyWriterFactory.pm
new file mode 100644
index 00000000..fd530747
--- /dev/null
+++ b/modules/Depgen/DependencyWriterFactory.pm
@@ -0,0 +1,42 @@
+package DependencyWriterFactory;
+
+# ************************************************************
+# Description : Create DependencyWriter objects.
+# Author : Chad Elliott
+# Create Date : 5/23/2003
+# ************************************************************
+
+# ************************************************************
+# Pragmas
+# ************************************************************
+
+use strict;
+
+use DependencyWriter;
+
+# ************************************************************
+# Data Section
+# ************************************************************
+
+my($writers) = {};
+
+# ************************************************************
+# Subroutine Section
+# ************************************************************
+
+sub register {
+ $writers = shift;
+}
+
+
+sub create {
+ if (defined $$writers{$_[0]}) {
+ return $$writers{$_[0]}->new();
+ }
+
+ print STDERR "WARNING: Invalid dependency writer type: $_[0]\n";
+ return new DependencyWriter();
+}
+
+
+1;
diff --git a/modules/Depgen/Driver.pm b/modules/Depgen/Driver.pm
new file mode 100644
index 00000000..3f4e2cc9
--- /dev/null
+++ b/modules/Depgen/Driver.pm
@@ -0,0 +1,255 @@
+package Driver;
+
+# ************************************************************
+# Description : Generate dependencies for Make and NMake.
+# Author : Chad Elliott
+# Create Date : 3/21/2007
+# ************************************************************
+
+# ************************************************************
+# Pragma Section
+# ************************************************************
+
+use strict;
+use File::Basename;
+
+use DependencyEditor;
+
+# ************************************************************
+# Data Section
+# ************************************************************
+
+my($version) = '1.1';
+my($os) = ($^O eq 'MSWin32' ? 'Windows' : 'UNIX');
+my(%types) = ();
+my(%defaults) = ('UNIX' => 'make',
+ 'Windows' => 'nmake',
+ );
+
+# ************************************************************
+# Subroutine Section
+# ************************************************************
+
+sub BEGIN {
+ my($fh) = new FileHandle();
+ my(%writers) = ();
+ my(%generators) = ();
+
+ ## Find all the dependency writers and object generators
+ foreach my $dir (@INC) {
+ if (opendir($fh, $dir)) {
+ foreach my $module (readdir($fh)) {
+ if ($module =~ /(.+)DependencyWriter\.pm$/) {
+ my($type) = lc($1);
+ my($class) = $module;
+ $class =~ s/\.pm$//;
+ require $module;
+ $writers{$type} = $class;
+ $types{$type} = 1;
+ }
+ elsif ($module =~ /(.+)ObjectGenerator\.pm$/) {
+ my($type) = lc($1);
+ my($class) = $module;
+ $class =~ s/\.pm$//;
+ require $module;
+ $generators{$type} = $class;
+ }
+ }
+ closedir($fh);
+ }
+ }
+
+ ## Register them with the right factory
+ DependencyWriterFactory::register(\%writers);
+ ObjectGeneratorFactory::register(\%generators);
+}
+
+
+sub new {
+ my($class) = shift;
+ my($self) = bless {'automatic' => [],
+ }, $class;
+
+ foreach my $add (@_) {
+ if ($add =~ /(UNIX|Windows)=(.*)/) {
+ $defaults{$1} = $2;
+ }
+ elsif ($add =~ /automatic=(.*)/) {
+ my(@auto) = split(/,/, $1);
+ $self->{'automatic'} = \@auto;
+ }
+ else {
+ print "WARNING: Unknown parameter: $add\n";
+ }
+ }
+
+ return $self;
+}
+
+
+sub usageAndExit {
+ my($self) = shift;
+ my($opt) = shift;
+ my($base) = basename($0);
+
+ if (defined $opt) {
+ print "$opt.\n";
+ }
+
+ print "$base v$version\n" .
+ "Usage: $base [-D<MACRO>[=VALUE]] [-I<include dir>] ",
+ (defined $self->{'automatic'}->[0] ? "[-A] " : ''),
+ "[-R <VARNAME>]\n" .
+ " " . (" " x length($base)) .
+ " [-e <file>] [-f <output file>] [-i] [-t <type>] [-n]\n" .
+ " " . (" " x length($base)) . " <files...>\n" .
+ "\n";
+ if (defined $self->{'automatic'}->[0]) {
+ print "-A Replace paths equal to the following variables with ",
+ "the corresponding \$()\n value: ",
+ join(', ', @{$self->{'automatic'}}), ".\n";
+ }
+ print "-D This option sets a macro to an optional value.\n" .
+ "-I The -I option adds an include directory.\n" .
+ "-R Replace \$VARNAME paths with \$(VARNAME).\n" .
+ "-e Exclude dependencies generated by <file>, but not <file> " .
+ "itself.\n" .
+ "-f Specifies the output file. This file will be edited if it " .
+ "already\n exists.\n" .
+ "-i Do not print an error if no source files are provided.\n" .
+ "-n Do not include inline files (ending in .i or .inl) in the " .
+ "dependencies.\n" .
+ "-t Use specified type (";
+ my(@keys) = sort keys %types;
+ for(my $i = 0; $i <= $#keys; ++$i) {
+ print "$keys[$i]" .
+ ($i != $#keys ? $i == $#keys - 1 ? ' or ' : ', ' : '');;
+ }
+ print ") instead of the default.\n" .
+ " The default is ";
+ @keys = sort keys %defaults;
+ for(my $i = 0; $i <= $#keys; ++$i) {
+ my($def) = $keys[$i];
+ print $defaults{$def} . " on $def" .
+ ($i != $#keys ? $i == $#keys - 1 ? ' and ' : ', ' : '');
+ }
+ print ".\n";
+ exit(0);
+}
+
+
+sub setReplace {
+ my($self) = shift;
+ my($replace) = shift;
+ my($name) = shift;
+ my($value) = shift;
+
+ if (defined $name) {
+ ## The key will be used in a regular expression.
+ ## So, we need to escape some special characters.
+ $name = File::Spec->canonpath($name);
+ $name =~ s/([\+\-\\\$\[\]\(\)\.])/\\$1/g;
+
+ $$replace{$name} = $value;
+ }
+}
+
+
+sub run {
+ my($self) = shift;
+ my($args) = shift;
+ my($argc) = scalar(@$args);
+ my($type) = $defaults{$os};
+ my($noinline) = undef;
+ my(@files) = ();
+ my(%macros) = ();
+ my(@ipaths) = ();
+ my(%replace) = ();
+ my(%exclude) = ();
+ my($output) = '-';
+ my($needsrc) = 1;
+
+ for(my $i = 0; $i < $argc; ++$i) {
+ my($arg) = $$args[$i];
+ if ($arg =~ /^\-D(\w+)(=(.*))?/) {
+ $macros{$1} = $3;
+ }
+ elsif ($arg =~ /^\-I(.*)/) {
+ push(@ipaths, File::Spec->canonpath($1));
+ }
+ elsif ($arg eq '-A') {
+ foreach my $auto (@{$self->{'automatic'}}) {
+ $self->setReplace(\%replace, $ENV{$auto}, '$(' . $auto . ')');
+ }
+ }
+ elsif ($arg eq '-R') {
+ ++$i;
+ $arg = $$args[$i];
+ if (defined $arg) {
+ my($val) = $ENV{$arg};
+ if (defined $val) {
+ $self->setReplace(\%replace, $val, "\$($arg)");
+ }
+ }
+ else {
+ $self->usageAndExit('Invalid use of -R');
+ }
+ }
+ elsif ($arg eq '-e') {
+ ++$i;
+ $arg = $$args[$i];
+ if (defined $arg) {
+ $exclude{$arg} = 1;
+ }
+ else {
+ $self->usageAndExit('Invalid use of -e');
+ }
+ }
+ elsif ($arg eq '-f') {
+ ++$i;
+ $arg = $$args[$i];
+ if (defined $arg) {
+ $output = $arg;
+ }
+ else {
+ $self->usageAndExit('Invalid use of -f');
+ }
+ }
+ elsif ($arg eq '-i') {
+ $needsrc = undef;
+ }
+ elsif ($arg eq '-n') {
+ $noinline = 1;
+ }
+ elsif ($arg eq '-h') {
+ $self->usageAndExit();
+ }
+ elsif ($arg eq '-t') {
+ ++$i;
+ $arg = $$args[$i];
+ if (defined $arg && defined $types{$arg}) {
+ $type = $arg;
+ }
+ else {
+ $self->usageAndExit('Invalid use of -t');
+ }
+ }
+ elsif ($arg =~ /^[\-+]/) {
+ ## We will ignore unknown options
+ ## Some options for aCC start with +
+ }
+ else {
+ push(@files, $arg);
+ }
+ }
+
+ if (!defined $files[0]) {
+ if ($needsrc) {
+ $self->usageAndExit('No files specified');
+ }
+ }
+
+ my($editor) = new DependencyEditor();
+ return $editor->process($output, $type, $noinline, \%macros,
+ \@ipaths, \%replace, \%exclude, \@files);
+}
diff --git a/modules/Depgen/MakeDependencyWriter.pm b/modules/Depgen/MakeDependencyWriter.pm
new file mode 100644
index 00000000..ee9d0db4
--- /dev/null
+++ b/modules/Depgen/MakeDependencyWriter.pm
@@ -0,0 +1,32 @@
+package MakeDependencyWriter;
+
+# ************************************************************
+# Description : Generates generic Makefile dependencies.
+# Author : Chad Elliott
+# Create Date : 2/10/2002
+# ************************************************************
+
+# ************************************************************
+# Pragmas
+# ************************************************************
+
+use strict;
+use DependencyWriter;
+
+use vars qw(@ISA);
+@ISA = qw(DependencyWriter);
+
+# ************************************************************
+# Subroutine Section
+# ************************************************************
+
+sub process {
+ my($objects) = $_[1];
+ my($files) = $_[2];
+
+ ## Sort the dependencies to make them reproducible
+ return "@$objects: \\\n " . join(" \\\n ", sort @$files) . "\n";
+}
+
+
+1;
diff --git a/modules/Depgen/MakeObjectGenerator.pm b/modules/Depgen/MakeObjectGenerator.pm
new file mode 100644
index 00000000..67e5cf17
--- /dev/null
+++ b/modules/Depgen/MakeObjectGenerator.pm
@@ -0,0 +1,47 @@
+package MakeObjectGenerator;
+
+# ************************************************************
+# Description : Generates object files for generic Makefiles.
+# Author : Chad Elliott
+# Create Date : 5/23/2003
+# ************************************************************
+
+# ************************************************************
+# Pragmas
+# ************************************************************
+
+use strict;
+use ObjectGenerator;
+
+use vars qw(@ISA);
+@ISA = qw(ObjectGenerator);
+
+# ************************************************************
+# Subroutine Section
+# ************************************************************
+
+sub process {
+ my($noext) = $_[1];
+ my(@objects) = ();
+ my(@exts) = ('o');
+ my(@dirs) = (defined $ENV{VDIR} ? $ENV{VDIR} : '');
+ $noext =~ s/\.[^\.]+$//o;
+
+ if (defined $ENV{SOEXT}) {
+ push(@exts, $ENV{SOEXT});
+ }
+ if (defined $ENV{VSHDIR}) {
+ push(@dirs, $ENV{VSHDIR});
+ }
+
+ foreach my $dirs (@dirs) {
+ foreach my $ext (@exts) {
+ push(@objects, "$dirs$noext.$ext");
+ }
+ }
+
+ return \@objects;
+}
+
+
+1;
diff --git a/modules/Depgen/NMakeDependencyWriter.pm b/modules/Depgen/NMakeDependencyWriter.pm
new file mode 100644
index 00000000..90340656
--- /dev/null
+++ b/modules/Depgen/NMakeDependencyWriter.pm
@@ -0,0 +1,53 @@
+package NMakeDependencyWriter;
+
+# ************************************************************
+# Description : Generates NMake dependencies.
+# Author : Chad Elliott
+# Create Date : 2/10/2002
+# ************************************************************
+
+# ************************************************************
+# Pragmas
+# ************************************************************
+
+use strict;
+use DependencyWriter;
+
+use vars qw(@ISA);
+@ISA = qw(DependencyWriter);
+
+# ************************************************************
+# Subroutine Section
+# ************************************************************
+
+sub process {
+ my($sources) = $_[1];
+ my($files) = $_[2];
+ my($total) = 0;
+
+ $$sources[0] =~ s/\//\\/g;
+ $$sources[0] =~ s/\\\\/\\/g;
+ my($dep) = "$$sources[0] :\\\n";
+
+ ## Sort the dependencies to make them reproducible
+ foreach my $file (sort @$files) {
+ $file =~ s/\//\\/g;
+ $file =~ s/\\\\/\\/g;
+ if ($file ne $$sources[0]) {
+ $dep .= "\t\"$file\"\\\n";
+ ++$total;
+ }
+ }
+
+ if ($total == 0) {
+ $dep = '';
+ }
+ else {
+ $dep .= "\n\n";
+ }
+
+ return $dep;
+}
+
+
+1;
diff --git a/modules/Depgen/NMakeObjectGenerator.pm b/modules/Depgen/NMakeObjectGenerator.pm
new file mode 100644
index 00000000..ac4f11fa
--- /dev/null
+++ b/modules/Depgen/NMakeObjectGenerator.pm
@@ -0,0 +1,28 @@
+package NMakeObjectGenerator;
+
+# ************************************************************
+# Description : Generates object files for NMake Makefiles.
+# Author : Chad Elliott
+# Create Date : 5/23/2003
+# ************************************************************
+
+# ************************************************************
+# Pragmas
+# ************************************************************
+
+use strict;
+use ObjectGenerator;
+
+use vars qw(@ISA);
+@ISA = qw(ObjectGenerator);
+
+# ************************************************************
+# Subroutine Section
+# ************************************************************
+
+sub process {
+ return [ $_[1] ];
+}
+
+
+1;
diff --git a/modules/Depgen/ObjectGenerator.pm b/modules/Depgen/ObjectGenerator.pm
new file mode 100644
index 00000000..d7e92070
--- /dev/null
+++ b/modules/Depgen/ObjectGenerator.pm
@@ -0,0 +1,32 @@
+package ObjectGenerator;
+
+# ************************************************************
+# Description : Base class for all Object Generators.
+# Author : Chad Elliott
+# Create Date : 5/23/2003
+# ************************************************************
+
+# ************************************************************
+# Pragmas
+# ************************************************************
+
+use strict;
+
+# ************************************************************
+# Subroutine Section
+# ************************************************************
+
+sub new {
+ return bless {
+ }, $_[0];
+}
+
+
+sub process {
+ #my($self) = shift;
+ #my($file) = shift;
+ return [];
+}
+
+
+1;
diff --git a/modules/Depgen/ObjectGeneratorFactory.pm b/modules/Depgen/ObjectGeneratorFactory.pm
new file mode 100644
index 00000000..a9d90ae7
--- /dev/null
+++ b/modules/Depgen/ObjectGeneratorFactory.pm
@@ -0,0 +1,42 @@
+package ObjectGeneratorFactory;
+
+# ************************************************************
+# Description : Create ObjectGenerator objects.
+# Author : Chad Elliott
+# Create Date : 5/23/2003
+# ************************************************************
+
+# ************************************************************
+# Pragmas
+# ************************************************************
+
+use strict;
+
+use ObjectGenerator;
+
+# ************************************************************
+# Data Section
+# ************************************************************
+
+my($generators) = {};
+
+# ************************************************************
+# Subroutine Section
+# ************************************************************
+
+sub register {
+ $generators = shift;
+}
+
+
+sub create {
+ if (defined $$generators{$_[0]}) {
+ return $$generators{$_[0]}->new();
+ }
+
+ print STDERR "WARNING: Invalid object generator type: $_[0]\n";
+ return new ObjectGenerator();
+}
+
+
+1;
diff --git a/modules/Depgen/Preprocessor.pm b/modules/Depgen/Preprocessor.pm
new file mode 100644
index 00000000..66e5d206
--- /dev/null
+++ b/modules/Depgen/Preprocessor.pm
@@ -0,0 +1,147 @@
+package Preprocessor;
+
+# ************************************************************
+# Description : Preprocesses the supplied file.
+# Author : Chad Elliott
+# Create Date : 2/10/2002
+# ************************************************************
+
+# ************************************************************
+# Pragmas
+# ************************************************************
+
+use strict;
+use FileHandle;
+use File::Basename;
+
+# ************************************************************
+# Subroutine Section
+# ************************************************************
+
+sub new {
+ my($class) = shift;
+ my($macros) = shift;
+ my($ipaths) = shift;
+ my($exclude) = shift;
+ return bless {'macros' => $macros,
+ 'ipaths' => $ipaths,
+ 'exclude' => $exclude,
+ 'files' => {},
+ 'ifound' => {},
+ 'recurse' => 0,
+ }, $class;
+}
+
+
+sub process {
+ my($self) = shift;
+ my($file) = shift;
+ my($noinline) = shift;
+ my($noincs) = shift;
+ my($fh) = new FileHandle();
+
+ if (open($fh, $file)) {
+ my($ifcount) = 0;
+ my(@zero) = ();
+ my($files) = $self->{'files'};
+ my($recurse) = ++$self->{'recurse'};
+ my($dir) = dirname($file);
+
+ $$files{$file} = [];
+ while(<$fh>) {
+ ## As an optimization, use a very simple regular expression on the
+ ## outside that all of the inner regular expressions have in
+ ## common. That way we go down the path of if elsif only if it is
+ ## even possible due to the outside regular expression.
+ ## index() is faster than a regular expression, so use index first.
+ next if (index($_, '#') == -1 || not /^\s*#/);
+
+ ## Remove same line c comments (no need to worry about c++
+ ## comments due to the regular expressions) inside this if statement.
+ ## This saves about 5% off of processing the ace directory
+ ## and we only need to strip comments if we are actually
+ ## going to look at the string.
+ $_ =~ s/\/\*.*\*\///o;
+
+ if (/^\s*#\s*endif/) {
+ --$ifcount;
+ if (defined $zero[0] && $ifcount == $zero[$#zero]) {
+ pop(@zero);
+ }
+ }
+ elsif (/^\s*#\s*if\s+0/) {
+ push(@zero, $ifcount);
+ ++$ifcount;
+ }
+ elsif (/^\s*#\s*if/) {
+ ++$ifcount;
+ }
+ elsif (!defined $zero[0] &&
+ /^\s*#\s*include\s+[<"]([^">]+)[">]/o) {
+ ## Locate the include file
+ my($inc) = undef;
+ if (exists $self->{'ifound'}->{$1}) {
+ $inc = $self->{'ifound'}->{$1};
+ }
+ else {
+ foreach my $dirp (@{$self->{'ipaths'}}) {
+ if (-r "$dirp/$1") {
+ $inc = "$dirp/$1";
+ last;
+ }
+ }
+
+ if (!defined $inc) {
+ ## If the file we're currently looking at contains a
+ ## directory name then, we need to look for include
+ ## files in that directory.
+ if (-r "$dir/$1") {
+ $inc = "$dir/$1";
+ }
+ }
+ $self->{'ifound'}->{$1} = $inc;
+ }
+
+ ## If we've found the include file, then process it too.
+ next if (not defined $inc);
+
+ $inc =~ s/\\/\//go;
+ if (!$noinline ||
+ ($recurse == 1 || $inc !~ /\.i(nl)?$/o)) {
+ push(@{$$files{$file}}, $inc);
+ if (!defined $$files{$inc}) {
+ ## Process this file, but do not return the include files
+ if (!defined $self->{'exclude'}->{substr($inc, rindex($inc, '/') + 1)}) {
+ $self->process($inc, $noinline, 1);
+ }
+ }
+ }
+ }
+ }
+ close($fh);
+
+ --$self->{'recurse'};
+ }
+
+ ## This has to be outside the if (open(...
+ ## If the last file to be processed isn't accessable then
+ ## we still need to return the array reference of includes.
+ if (!$noincs) {
+ my(@files) = ($file);
+ my(%ifiles) = ();
+
+ foreach my $processed (@files) {
+ foreach my $inc (@{$self->{'files'}->{$processed}}) {
+ if (!defined $ifiles{$inc}) {
+ $ifiles{$inc} = 1;
+ push(@files, $inc);
+ }
+ }
+ }
+ shift(@files);
+ return \@files;
+ }
+}
+
+
+1;