📄 templateparser.pm
字号:
my($ret) = 1;
foreach my $v (split(/\s*\&\&\s*/, $str)) {
$ret &&= $self->process_compound_if($v);
if ($ret == 0) {
return 0;
}
}
$status = 1;
}
else {
## See if we need to reverse the return value
my($not) = 0;
if ($str =~ /^!(.*)/) {
$not = 1;
$str = $1;
}
## Get the value based on the string
my($val) = ($str =~ /flag_overrides\(([^\)]+),\s*([^\)]+)\)/ ?
$self->get_flag_overrides($1, $2) :
$self->get_value($str));
## See if any portion of the value is defined and not empty
my($ret) = 0;
if (defined $val) {
if (UNIVERSAL::isa($val, 'ARRAY')) {
foreach my $v (@$val) {
if ($v ne '') {
$ret = 1;
last;
}
}
}
elsif ($val ne '') {
$ret = 1;
}
}
return ($not ? !$ret : $ret);
}
return $status;
}
sub handle_if {
my($self) = shift;
my($val) = shift;
my($name) = 'endif';
push(@{$self->{'lstack'}}, $self->get_line_number() . " $val");
if ($self->{'if_skip'}) {
push(@{$self->{'sstack'}}, "*$name");
}
else {
## Determine if we are skipping the portion of this if statement
## $val will always be defined since we won't get into this method
## without properly parsing the if statement.
$self->{'if_skip'} = !$self->process_compound_if($val);
push(@{$self->{'sstack'}}, $name);
}
}
sub handle_else {
my($self) = shift;
my(@scopy) = @{$self->{'sstack'}};
## This method does not take into account that
## multiple else clauses could be supplied to a single if.
## Someday, this may be fixed.
if (defined $scopy[$#scopy] && $scopy[$#scopy] eq 'endif') {
$self->{'if_skip'} ^= 1;
}
}
sub handle_foreach {
my($self) = shift;
my($val) = shift;
my($name) = 'endfor';
my($status) = 1;
my($errorString) = undef;
push(@{$self->{'lstack'}}, $self->get_line_number());
if (!$self->{'if_skip'}) {
my($vname) = undef;
if ($val =~ /([^,]+),(.*)/) {
$vname = $1;
$val = $2;
$vname =~ s/^\s+//;
$vname =~ s/\s+$//;
$val =~ s/^\s+//;
$val =~ s/\s+$//;
## Due to the way flag_overrides works, we can't allow
## the user to name the foreach variable when dealing
## with custom types.
if ($val =~ /^custom_type\->/ || $val eq 'custom_types') {
$status = 0;
$errorString = 'The foreach variable can not be ' .
'named when dealing with custom types';
}
elsif ($val =~ /^grouped_.*_file\->/ || $val =~ /^grouped_.*files$/) {
$status = 0;
$errorString = 'The foreach variable can not be ' .
'named when dealing with grouped files';
}
}
push(@{$self->{'sstack'}}, $name);
++$self->{'foreach'}->{'count'};
my($index) = $self->{'foreach'}->{'count'};
$self->{'foreach'}->{'name'}->[$index] = $vname;
$self->{'foreach'}->{'names'}->[$index] = $val;
$self->{'foreach'}->{'text'}->[$index] = '';
$self->{'foreach'}->{'scope'}->[$index] = {};
}
else {
push(@{$self->{'sstack'}}, "*$name");
}
return $status, $errorString;
}
sub handle_special {
my($self) = shift;
my($name) = shift;
my($val) = shift;
## If $name (fornotlast, forfirst, etc.) is set to 1
## Then we append the $val onto the current string that's
## being built.
if (!$self->{'if_skip'}) {
if ($self->get_value($name)) {
$self->append_current($val);
}
}
}
sub handle_uc {
my($self) = shift;
my($name) = shift;
if (!$self->{'if_skip'}) {
$self->append_current(uc($self->get_value_with_default($name)));
}
}
sub handle_lc {
my($self) = shift;
my($name) = shift;
if (!$self->{'if_skip'}) {
$self->append_current(lc($self->get_value_with_default($name)));
}
}
sub handle_ucw {
my($self) = shift;
my($name) = shift;
if (!$self->{'if_skip'}) {
my($val) = $self->get_value_with_default($name);
substr($val, 0, 1) = uc(substr($val, 0, 1));
while($val =~ /[_\s]([a-z])/) {
my($uc) = uc($1);
$val =~ s/(_|\s)([a-z])/$1$uc/;
}
$self->append_current($val);
}
}
sub handle_noextension {
my($self) = shift;
my($name) = shift;
if (!$self->{'if_skip'}) {
my($val) = $self->get_value_with_default($name);
$val =~ s/\.[^\.]+$//;
$self->append_current($val);
}
}
sub handle_dirname {
my($self) = shift;
my($name) = shift;
if (!$self->{'if_skip'}) {
$self->append_current(
$self->dirname($self->get_value_with_default($name)));
}
}
sub handle_basename {
my($self) = shift;
my($name) = shift;
if (!$self->{'if_skip'}) {
$self->append_current(
$self->basename($self->get_value_with_default($name)));
}
}
sub handle_basenoextension {
my($self) = shift;
my($name) = shift;
if (!$self->{'if_skip'}) {
my($val) = $self->basename($self->get_value_with_default($name));
$val =~ s/\.[^\.]+$//;
$self->append_current($val);
}
}
sub handle_flag_overrides {
my($self) = shift;
my($name) = shift;
my($type) = '';
($name, $type) = split(/,\s*/, $name);
if (!$self->{'if_skip'}) {
my($value) = $self->get_flag_overrides($name, $type);
if (defined $value) {
$self->append_current($value);
}
}
}
sub handle_marker {
my($self) = shift;
my($name) = shift;
if (!$self->{'if_skip'}) {
my($value) = $self->{'prjc'}->get_verbatim($name);
if (defined $value) {
$self->append_current($value);
}
}
}
sub process_name {
my($self) = shift;
my($line) = shift;
my($length) = 0;
my($status) = 1;
my($errorString) = undef;
if ($line eq '') {
}
elsif ($line =~ /^(\w+)(\(([^\)]+|\".*\"|flag_overrides\([^\)]+,\s*[^\)]+\))\)|\->\w+([\w\-\>]+)?)?%>/) {
## Split the line into a name and value
my($name, $val) = ();
if ($line =~ /([^%\(]+)(\(([^%]+)\))?%>/) {
$name = lc($1);
$val = $3;
}
$length += length($name);
if (defined $val) {
## Add the length of the value plus 2 for the surrounding ()
$length += length($val) + 2;
}
if (defined $keywords{$name}) {
if ($name eq 'endif') {
($status, $errorString) = $self->handle_endif($name);
}
elsif ($name eq 'if') {
$self->handle_if($val);
}
elsif ($name eq 'endfor') {
($status, $errorString) = $self->handle_endfor($name);
}
elsif ($name eq 'foreach') {
($status, $errorString) = $self->handle_foreach($val);
}
elsif ($name eq 'fornotlast' || $name eq 'forlast' ||
$name eq 'fornotfirst' || $name eq 'forfirst') {
$self->handle_special($name, $self->process_special($val));
}
elsif ($name eq 'else') {
$self->handle_else();
}
elsif ($name eq 'flag_overrides') {
$self->handle_flag_overrides($val);
}
elsif ($name eq 'noextension') {
$self->handle_noextension($val);
}
elsif ($name eq 'basenoextension') {
$self->handle_basenoextension($val);
}
elsif ($name eq 'basename') {
$self->handle_basename($val);
}
elsif ($name eq 'marker') {
$self->handle_marker($val);
}
elsif ($name eq 'dirname') {
$self->handle_dirname($val);
}
elsif ($name eq 'comment') {
## Ignore the contents of the comment
}
elsif ($name eq 'uc') {
$self->handle_uc($val);
}
elsif ($name eq 'ucw') {
$self->handle_ucw($val);
}
elsif ($name eq 'lc') {
$self->handle_lc($val);
}
}
else {
if (!$self->{'if_skip'}) {
if (defined $val && !defined $self->{'defaults'}->{$name}) {
$self->{'defaults'}->{$name} = $self->process_special($val);
}
$self->append_current($self->get_value_with_default($name));
}
}
}
else {
my($error) = $line;
my($length) = length($line);
for(my $i = 0; $i < $length; ++$i) {
my($part) = substr($line, $i, 2);
if ($part eq '%>') {
$error = substr($line, 0, $i + 2);
last;
}
}
$status = 0;
$errorString = "Unable to parse line starting at $error";
}
return $status, $errorString, $length;
}
sub collect_data {
my($self) = shift;
my($prjc) = $self->{'prjc'};
my($cwd) = $self->getcwd();
my($relwd) = $prjc->reverse_relative($cwd);
## Set the current working directory
if ($self->{'cslashes'}) {
$cwd = $prjc->slash_to_backslash($cwd);
}
$self->{'values'}->{'cwd'} = $cwd;
## Set the relative working directory
$relwd =~ s/\$\([^\)]+\)[\/\\]//;
if ($self->{'cslashes'}) {
$relwd = $prjc->slash_to_backslash($relwd);
}
$self->{'values'}->{'relwd'} = $relwd;
## Collect the components into {'values'} somehow
foreach my $key (keys %{$prjc->{'valid_components'}}) {
my(@list) = $prjc->get_component_list($key);
if (defined $list[0]) {
$self->{'values'}->{$key} = \@list;
}
}
## A tiny hack (mainly for VC6 projects)
## for the workspace creator. It needs to know the
## target names to match up with the project name.
$prjc->update_project_info($self, 0, ['project_name']);
## This is for all projects
$prjc->update_project_info($self, 1, ['after']);
## VC7 Projects need to know the GUID.
## We need to save this value in our known values
## since each guid generated will be different. We need
## this to correspond to the same guid used in the workspace.
my($guid) = $prjc->update_project_info($self, 1, ['guid']);
$self->{'values'}->{'guid'} = $guid;
}
sub parse_line {
my($self) = shift;
my($ih) = shift;
my($line) = shift;
my($status) = 1;
my($errorString) = undef;
my($length) = length($line);
my($name) = 0;
my($startempty) = ($length == 0 ? 1 : 0);
my($append_name) = 0;
## If processing a foreach or the line only
## contains a keyword, then we do
## not need to add a newline to the end.
if ($self->{'foreach'}->{'processing'} == 0) {
my($is_only_keyword) = undef;
if ($line =~ /^\s*<%(\w+)(\([^\)]+\))?%>$/) {
$is_only_keyword = defined $keywords{$1};
}
if (!$is_only_keyword) {
$line .= $self->{'crlf'};
$length += $self->{'clen'};
}
}
if ($self->{'foreach'}->{'count'} < 0) {
$self->{'built'} = '';
}
for(my $i = 0; $i < $length; ++$i) {
my($part) = substr($line, $i, 2);
if ($part eq '<%') {
++$i;
$name = 1;
}
elsif ($part eq '%>') {
++$i;
$name = 0;
if ($append_name) {
$append_name = 0;
if (!$self->{'if_skip'}) {
$self->append_current($part);
}
}
}
elsif ($name) {
my($substr) = substr($line, $i);
my($efcheck) = ($substr =~ /^endfor\%\>/);
my($focheck) = ($efcheck ? 0 : ($substr =~ /^foreach\(/));
if ($focheck && $self->{'foreach'}->{'count'} >= 0) {
++$self->{'foreach'}->{'nested'};
}
if ($self->{'foreach'}->{'count'} < 0 ||
$self->{'foreach'}->{'processing'} > $self->{'foreach'}->{'nested'} ||
(($efcheck || $focheck) &&
$self->{'foreach'}->{'nested'} == $self->{'foreach'}->{'processing'})) {
my($nlen) = 0;
($status,
$errorString,
$nlen) = $self->process_name($substr);
if ($status && $nlen == 0) {
$errorString = "Could not parse this line at column $i";
$status = 0;
}
if (!$status) {
last;
}
$i += ($nlen - 1);
}
else {
$name = 0;
if (!$self->{'if_skip'}) {
$self->append_current('<%' . substr($line, $i, 1));
$append_name = 1;
}
}
if ($efcheck && $self->{'foreach'}->{'nested'} > 0) {
--$self->{'foreach'}->{'nested'};
}
}
else {
if (!$self->{'if_skip'}) {
$self->append_current(substr($line, $i, 1));
}
}
}
if ($self->{'foreach'}->{'count'} < 0) {
## If the line started out empty and we're not
## skipping from the start or the built up line is not empty
if ($startempty ||
($self->{'built'} ne $self->{'crlf'} && $self->{'built'} ne '')) {
push(@{$self->{'lines'}}, $self->{'built'});
}
}
return $status, $errorString;
}
sub parse_file {
my($self) = shift;
my($input) = shift;
$self->collect_data();
my($status, $errorString) = $self->read_file($input);
if ($status) {
my($sstack) = $self->{'sstack'};
if (defined $$sstack[0]) {
my($lstack) = $self->{'lstack'};
$status = 0;
$errorString = "Missing an $$sstack[0] starting at $$lstack[0]";
}
}
if (!$status) {
my($linenumber) = $self->get_line_number();
$errorString = "$input: line $linenumber:\n$errorString";
}
return $status, $errorString;
}
sub get_lines {
my($self) = shift;
return $self->{'lines'};
}
1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -