?? templateparser.pm
字號(hào):
package TemplateParser;
# ************************************************************
# Description : Parses the template and fills in missing values
# Author : Chad Elliott
# Create Date : 5/17/2002
# ************************************************************
# ************************************************************
# Pragmas
# ************************************************************
use strict;
use Parser;
use vars qw(@ISA);
@ISA = qw(Parser);
# ************************************************************
# Data Section
# ************************************************************
my(%keywords) = ('if' => 1,
'else' => 1,
'endif' => 1,
'noextension' => 1,
'dirname' => 1,
'basename' => 1,
'basenoextension' => 1,
'foreach' => 1,
'forfirst' => 1,
'fornotfirst' => 1,
'fornotlast' => 1,
'forlast' => 1,
'endfor' => 1,
'comment' => 1,
'flag_overrides' => 1,
'marker' => 1,
);
# ************************************************************
# Subroutine Section
# ************************************************************
sub new {
my($class) = shift;
my($prjc) = shift;
my($self) = Parser::new($class);
$self->{'prjc'} = $prjc;
$self->{'ti'} = $prjc->get_template_input();
$self->{'crlf'} = undef;
$self->{'values'} = {};
$self->{'defaults'} = {};
$self->{'lines'} = [];
$self->{'built'} = '';
$self->{'sstack'} = [];
$self->{'lstack'} = [];
$self->{'if_skip'} = 0;
$self->{'foreach'} = {};
$self->{'foreach'}->{'count'} = -1;
$self->{'foreach'}->{'nested'} = 0;
$self->{'foreach'}->{'names'} = [];
$self->{'foreach'}->{'text'} = [];
$self->{'foreach'}->{'scope'} = [];
$self->{'foreach'}->{'temp_scope'} = [];
$self->{'foreach'}->{'processing'} = 0;
return $self;
}
sub basename {
my($self) = shift;
my($file) = shift;
for(my $i = length($file) - 1; $i >= 0; --$i) {
my($ch) = substr($file, $i, 1);
if ($ch eq '/' || $ch eq '\\') {
## The template file may use this value (<%basename_found%>)
## to determine whether a basename removed the directory or not
$self->{'values'}->{'basename_found'} = 1;
return substr($file, $i + 1);
}
}
delete $self->{'values'}->{'basename_found'};
return $file;
}
sub dirname {
my($self) = shift;
my($file) = shift;
for(my $i = length($file) - 1; $i != 0; --$i) {
my($ch) = substr($file, $i, 1);
if ($ch eq '/' || $ch eq '\\') {
## The template file may use this value (<%dirname_found%>)
## to determine whether a dirname removed the basename or not
$self->{'values'}->{'dirname_found'} = 1;
return substr($file, 0, $i);
}
}
delete $self->{'values'}->{'dirname_found'};
return '.';
}
sub strip_line {
my($self) = shift;
my($line) = shift;
## Override strip_line() from Parser.
## We need to preserve leading space and
## there is no comment string in templates.
++$self->{'line_number'};
$line =~ s/\s+$//;
return $line;
}
## Append the current value to the line that is being
## built. This line may be a foreach line or a general
## line without a foreach.
sub append_current {
my($self) = shift;
my($value) = shift;
my($index) = $self->{'foreach'}->{'count'};
if ($index >= 0) {
$self->{'foreach'}->{'text'}->[$index] .= $value;
}
else {
$self->{'built'} .= $value;
}
}
sub adjust_value {
my($self) = shift;
my($name) = shift;
my($value) = shift;
## Perform any additions, subtractions
## or overrides for the template values.
my($addtemp) = $self->{'prjc'}->get_addtemp();
foreach my $at (keys %$addtemp) {
if ($at eq $name) {
my($val) = $$addtemp{$at};
if ($$val[0] > 0) {
if (UNIVERSAL::isa($value, 'ARRAY')) {
$value = [ $$val[1], @$value ];
}
else {
$value = "$$val[1] $value";
}
}
elsif ($$val[0] < 0) {
my($parts) = undef;
if (UNIVERSAL::isa($value, 'ARRAY')) {
my(@copy) = @$value;
$parts = \@copy;
}
else {
$parts = $self->create_array($value);
}
$value = '';
foreach my $part (@$parts) {
if ($part ne $$val[1] && $part ne '') {
$value .= "$part ";
}
}
$value =~ s/^\s+//;
$value =~ s/\s+$//;
}
else {
$value = $$val[1];
}
}
}
return $value;
}
sub set_current_values {
my($self) = shift;
my($name) = shift;
## If any value within a foreach matches the name
## of a hash table within the template input we will
## set the values of that hash table in the current scope
my($ti) = $self->{'ti'};
if (defined $ti) {
my($counter) = $self->{'foreach'}->{'count'};
if ($counter >= 0) {
my($value) = $ti->get_value($name);
if (defined $value && UNIVERSAL::isa($value, 'HASH')) {
my(%copy) = ();
foreach my $key (keys %$value) {
$copy{$key} = $self->adjust_value($key, $$value{$key});
}
$self->{'foreach'}->{'temp_scope'}->[$counter] = \%copy;
}
}
}
}
sub relative {
my($self) = shift;
my($value) = shift;
my($rel) = $self->{'prjc'}->get_relative();
my(@keys) = keys %$rel;
if (defined $value && defined $keys[0] && $value =~ /\$/) {
if (UNIVERSAL::isa($value, 'ARRAY')) {
my(@built) = ();
foreach my $val (@$value) {
push(@built, $self->relative($val));
}
$value = \@built;
}
else {
my($cwd) = $self->getcwd();
my($start) = 0;
my($fixed) = 0;
if ($cwd =~ /[a-z]:[\/\\]/) {
substr($cwd, 0, 1) = uc(substr($cwd, 0, 1));
}
while(substr($value, $start) =~ /(\$\(([^)]+)\))/) {
my($whole) = $1;
my($name) = $2;
my($val) = $$rel{$name};
if (defined $val) {
if ($^O eq 'cygwin' && !$fixed &&
$cwd !~ /[A-Za-z]:/ && $val =~ /[A-Za-z]:/) {
my($cyg) = `cygpath -w $cwd`;
if (defined $cyg) {
$cyg =~ s/\\/\//g;
chop($cwd = $cyg);
$fixed = 1;
}
}
## Fix up the value for Windows (capitalize the drive and
## switch the \\'s to /
$val =~ s/\\/\//g;
if ($val =~ /[a-z]:\//) {
substr($val, 0, 1) = uc(substr($val, 0, 1));
}
if (index($cwd, $val) == 0) {
my($count) = 0;
substr($cwd, 0, length($val)) = '';
while($cwd =~ /^\\/) {
$cwd =~ s/^\///;
}
my($length) = length($cwd);
for(my $i = 0; $i < $length; ++$i) {
if (substr($cwd, $i, 1) eq '/') {
++$count;
}
}
$val = '../' x $count;
$val =~ s/\/$//;
if ($self->{'prjc'}->convert_slashes()) {
$val = $self->slash_to_backslash($val);
}
substr($value, $start) =~ s/\$\([^)]+\)/$val/;
}
}
$start += length($whole);
}
}
}
return $value;
}
sub get_value {
my($self) = shift;
my($name) = shift;
my($value) = undef;
my($counter) = $self->{'foreach'}->{'count'};
## First, check the temporary scope (set inside a foreach)
if ($counter >= 0) {
while(!defined $value && $counter >= 0) {
$value = $self->{'foreach'}->{'temp_scope'}->[$counter]->{$name};
--$counter;
}
$counter = $self->{'foreach'}->{'count'};
}
if (!defined $value) {
## Next, check for a template value
my($ti) = $self->{'ti'};
if (defined $ti) {
$value = $ti->get_value($name);
if (defined $value) {
$value = $self->adjust_value($name, $value);
}
}
if (!defined $value) {
## Next, check the inner to outer foreach
## scopes for overriding values
while(!defined $value && $counter >= 0) {
$value = $self->{'foreach'}->{'scope'}->[$counter]->{$name};
--$counter;
}
## Then get the value from the project creator
if (!defined $value) {
$value = $self->{'prjc'}->get_assignment($name);
## Then get it from our known values
if (!defined $value) {
$value = $self->{'values'}->{$name};
}
}
}
}
return $self->relative($value);
}
sub get_value_with_default {
my($self) = shift;
my($name) = shift;
my($value) = $self->get_value($name);
if (defined $value) {
if (UNIVERSAL::isa($value, 'ARRAY')) {
$value = "@$value";
}
}
else {
$value = $self->{'defaults'}->{$name};
if (!defined $value) {
## Call back onto the project creator to allow
## it to fill in the value before defaulting to an empty string.
$value = $self->{'prjc'}->fill_value($name);
if (!defined $value) {
# print "DEBUG: WARNING: $name defaulting to empty string\n";
$value = '';
}
}
else {
# print "DEBUG: WARNING: $name using default value of $value\n";
}
$value = $self->relative($value);
}
return $value;
}
sub process_foreach {
my($self) = shift;
my($index) = $self->{'foreach'}->{'count'};
my($text) = $self->{'foreach'}->{'text'}->[$index];
my($status) = 1;
my($errorString) = '';
my(@values) = ();
my($names) = $self->create_array($self->{'foreach'}->{'names'}->[$index]);
my($name) = undef;
foreach my $n (@$names) {
my($vals) = $self->get_value($n);
if (defined $vals && $vals ne '') {
if (!UNIVERSAL::isa($vals, 'ARRAY')) {
$vals = $self->create_array($vals);
}
push(@values, @$vals);
}
if (!defined $name) {
$name = $n;
}
}
## Reset the text (it will be regenerated by calling parse_line
$self->{'foreach'}->{'text'}->[$index] = '';
if (defined $values[0]) {
my($inner) = $name;
my($scope) = $self->{'foreach'}->{'scope'}->[$index];
$inner =~ s/s$//;
$$scope{'forlast'} = 0;
$$scope{'fornotlast'} = 1;
$$scope{'forfirst'} = 1;
$$scope{'fornotfirst'} = 0;
for(my $i = 0; $i <= $#values; ++$i) {
my($value) = $values[$i];
## Set the corresponding values in the temporary scope
$self->set_current_values($value);
## Set the special values that only exist
## within a foreach
if ($i != 0) {
$$scope{'forfirst'} = 0;
$$scope{'fornotfirst'} = 1;
}
if ($i == $#values) {
$$scope{'forlast'} = 1;
$$scope{'fornotlast'} = 0;
}
## We don't use adjust_value here because these names
## are generated from a foreach and should not be adjusted.
$$scope{$inner} = $value;
## A tiny hack for VC7
if ($inner eq 'configuration') {
$self->{'prjc'}->update_project_info($self, 1,
['configuration', 'platform'],
'|');
}
## Now parse the line of text, each time
## with different values
++$self->{'foreach'}->{'processing'};
($status, $errorString) = $self->parse_line(undef, $text);
--$self->{'foreach'}->{'processing'};
if (!$status) {
last;
}
}
}
return $status, $errorString;
}
sub handle_end {
my($self) = shift;
my($name) = shift;
my($status) = 1;
my($errorString) = '';
my($end) = pop(@{$self->{'sstack'}});
pop(@{$self->{'lstack'}});
if (!defined $end) {
$status = 0;
$errorString = "ERROR: Unmatched $name\n";
}
elsif ($end eq 'endif') {
$self->{'if_skip'} = 0;
}
elsif ($end eq 'endfor') {
my($index) = $self->{'foreach'}->{'count'};
($status, $errorString) = $self->process_foreach();
if ($status) {
--$self->{'foreach'}->{'count'};
$self->append_current($self->{'foreach'}->{'text'}->[$index]);
}
}
return $status, $errorString;
}
sub get_flag_overrides {
my($self) = shift;
my($name) = shift;
my($type) = shift;
my($value) = undef;
my($file) = $self->get_value($name);
my($prjc) = $self->{'prjc'};
my($fo) = $prjc->{'flag_overrides'};
foreach my $key (keys %$fo) {
if ($key =~ /^$name/) {
foreach my $of (keys %{$$fo{$key}}) {
my($cv) = $of;
if ($prjc->convert_slashes()) {
$cv = $prjc->slash_to_backslash($of);
}
if ($cv eq $file) {
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -