Merge pull request #228 from DOCGroup/jwillemsen-patch-1
[MPC.git] / modules / Depgen / Preprocessor.pm
blobdc9de901dc5a49c42f20fa8db1545f8cb3b35553
1 package Preprocessor;
3 # ************************************************************
4 # Description : Preprocesses the supplied file.
5 # Author : Chad Elliott
6 # Create Date : 2/10/2002
7 # ************************************************************
9 # ************************************************************
10 # Pragmas
11 # ************************************************************
13 use strict;
14 use FileHandle;
15 use File::Basename;
17 # ************************************************************
18 # Subroutine Section
19 # ************************************************************
21 sub new {
22 my($class, $macros, $ipaths, $exclude) = @_;
23 return bless {'macros' => $macros,
24 'ipaths' => $ipaths,
25 'exclude' => $exclude,
26 'files' => {},
27 'ifound' => {},
28 'recurse' => 0,
29 }, $class;
33 sub process {
34 my($self, $file, $noinline, $noincs) = @_;
35 my $fh = new FileHandle();
37 ## Open the file, but if we can't we'll just silently ignore it.
38 if (open($fh, $file)) {
39 my @zero;
40 my $ifcount = 0;
41 my $files = $self->{'files'};
42 my $dir = dirname($file);
44 ## We only need to keep track of recursion inside this block
45 my $recurse = ++$self->{'recurse'};
47 $$files{$file} = [];
48 while(<$fh>) {
49 ## As an optimization, use a very simple regular expression on the
50 ## outside that all of the inner regular expressions have in
51 ## common. That way we go down the path of if elsif only if it is
52 ## even possible due to the outside regular expression.
53 ## index() is faster than a regular expression, so use index first.
54 next if (index($_, '#') == -1 || not /^\s*#/);
56 ## Remove same line c comments (no need to worry about c++
57 ## comments due to the regular expressions) inside this if statement.
58 ## This saves about 5% off of processing the ace directory
59 ## and we only need to strip comments if we are actually
60 ## going to look at the string.
61 $_ =~ s/\/\*.*\*\///o;
63 if (/^\s*#\s*endif/) {
64 --$ifcount;
65 if (defined $zero[0] && $ifcount == $zero[$#zero]) {
66 pop(@zero);
69 elsif (/^\s*#\s*if\s+0/) {
70 push(@zero, $ifcount);
71 ++$ifcount;
73 elsif (/^\s*#\s*if/) {
74 ++$ifcount;
76 elsif (!defined $zero[0] &&
77 /^\s*#\s*include\s+[<"]([^">]+)[">]/o) {
78 ## Locate the include file
79 my $inc;
80 if (exists $self->{'ifound'}->{$dir} &&
81 exists $self->{'ifound'}->{$dir}->{$1}) {
82 $inc = $self->{'ifound'}->{$dir}->{$1};
84 else {
85 foreach my $dirp (@{$self->{'ipaths'}}) {
86 if (-r "$dirp/$1") {
87 $inc = "$dirp/$1";
88 last;
92 if (!defined $inc) {
93 ## If the file we're currently looking at contains a
94 ## directory name then, we need to look for include
95 ## files in that directory.
96 if (-r "$dir/$1") {
97 $inc = "$dir/$1";
100 $self->{'ifound'}->{$dir}->{$1} = $inc;
103 ## If we've found the include file, then process it too.
104 next if (not defined $inc);
106 $inc =~ s/\\/\//go;
107 if (!$noinline ||
108 ($recurse == 1 || $inc !~ /\.i(nl)?$/o)) {
109 push(@{$$files{$file}}, $inc);
110 if (!defined $$files{$inc}) {
111 ## Process this file, but do not return the include files
112 if (!defined $self->{'exclude'}->{substr($inc, rindex($inc, '/') + 1)}) {
113 $self->process($inc, $noinline, 1);
119 close($fh);
121 ## We only need to keep track of recursion inside this block
122 --$self->{'recurse'};
125 ## This has to be outside the if (open(...
126 ## If the last file to be processed isn't accessible then
127 ## we still need to return the array reference of includes.
128 if (!$noincs) {
129 my @files = ($file);
130 my %ifiles;
132 foreach my $processed (@files) {
133 foreach my $inc (@{$self->{'files'}->{$processed}}) {
134 if (!defined $ifiles{$inc}) {
135 $ifiles{$inc} = 1;
136 push(@files, $inc);
140 shift(@files);
141 return \@files;