HTML-CMTemplate
view release on metacpan or search on metacpan
CMTemplate.pm view on Meta::CPAN
# again.
$self->__end_block__; # both beginning and ending tag.
# Keep track of this and only open it again if needed.
$self->__add_raw__( $filename, $text, $mtime );
}
sub __onECHO__ {
my $self = shift;
$self->__debug__(\@_);
my $contents = shift;
my $node = $self->__top_TPL__( 'ECHO' );
my $echonode = _ECHO_->new( $self );
$echonode->expr( $contents );
$node->blk( $echonode );
$self->__end_block__;
}
sub __onBREAK__ {
my $self = shift;
$self->__debug__(\@_);
my $contents = shift;
my $node = $self->__top_TPL__( 'BREAK' );
my $breaknode = _BREAK_->new( $self );
$node->blk( $breaknode );
$self->__end_block__;
}
sub __onCONTINUE__ {
my $self = shift;
$self->__debug__(\@_);
my $contents = shift;
my $node = $self->__top_TPL__( 'CONTINUE' );
my $continuenode = _CONTINUE_->new( $self );
$node->blk( $continuenode );
$self->__end_block__;
}
sub __onEXEC__ {
my $self = shift;
$self->__debug__(\@_);
my $contents = shift;
my $node = $self->__top_TPL__( 'EXEC' );
my $execnode = _EXEC_->new( $self );
$execnode->expr( $contents );
$node->blk( $execnode );
$self->__end_block__;
}
sub __onCOMMENT__ {
my $self = shift;
$self->__debug__(\@_);
my $contents = shift;
# NOP: Just eat the tag
}
sub __process_cdata__ {
my $self = shift;
$self->__debug__(\@_);
my ($cdata) = @_;
# If we are in a TPL node, then we should just add the text to the current
# text in that node. Otherwise, something went wrong. We should always
# be prepared to receive text when it comes.
my $node = $self->__top_TPL__( 'text' );
$node->text( $node->text . $cdata );
$self->__debug__( "New CDATA length: " . length( $node->text ) );
}
# This function takes a chunk of text and decides what to do with it. It works
# in a similar fashion to expat, which will take text until you quit giving it
# to it. It simply looks for tags and data in between. When a complete tag is
# found, it passes the information off to a function to have it processed.
# When cdata is found (character data) it dumps it out. Note that there is
# no guarantee that the cdata will come back all at once. This function does
# not do any output buffering on cdata. If it isn't in a tag, it gives you
# everything that it currently has, whether it is the entire set of text
# or not.
sub __process_block__ {
my $self = shift;
$self->__debug__(\@_);
my $str = shift;
# This function only looks for tokens and keeps track of whether or not
# it is inside of a tag. Once a complete tag has been found, it will
# send the name of that tag and all remaining text inside of it to the
# appropriate function.
# If it reaches the end of a buffer and is not inside of a tag, it
# accumulates all text and sends it out to the cdata function.
# Append to the buffer and continue where we left off.
$self->{strbuf} .= $str;
# Note that if we are already inside of a tag, we search from a few
# characters before the boundary. Otherwise, we search from the beginning
# of the unprocessed buffer.
my $curpos = ($self->{parserintag}) ?
$self->{buflen} - $HTML::CMTemplate::tagEndLen + 1:
$self->{bufstart};
$self->__debug__( "Curpos: $curpos" );
$self->{buflen} += length($str);
$self->__debug__( "New Buflen: " . $self->{buflen} );
while ($curpos < $self->{buflen}) {
# In a tag. Get the rest of it, if possible, and send it out for
# processing.
if ($self->{parserintag}) {
$self->__debug__( 'STATE: inside of a tag' );
# Try to find the end of the tag.
my $pos = index( $self->{strbuf}, $HTML::CMTemplate::tagEnd, $curpos );
$self->__debug__( "End tag position: $pos" );
# If we found it, we get all of the stuff inside of the tag and dump
# it into a function.
if ($pos > -1) {
# Found the end tag. Send it on its way.
# Get the internals of the tag:
my $start = $self->{tagstart} + $HTML::CMTemplate::tagStartLen;
my $tag = substr( $self->{strbuf}, $start, $pos - $start );
if ($tag =~ m/^(\w+)(\s+(.*?)\s*)?$/s) {
# $1 contains the name of the tag
# $3 contains the rest of the tag's text, if there is any.
# TODO: Make the function call configurable by a hash or
# something.
$self->__process_tag__($1, (defined($3))?$3:'');
# Once the tag is processed, we are no longer in a tag.
# Move the current position to where we left off and
# continue the loop.
}
# Special case for block tags with no expression, like 'else'
elsif ($tag =~ m/^(\w+)\s*:\s*$/s) {
$self->__debug__(
"Found an expressionless block tag: $tag" );
$self->__process_tag__($1, ':');
}
else {
# The tag was not of the format <?=name expression?>
# So, we take everything inside of the <?= and ?> and
# treat it like it was the expression for the default tag.
# The default tag is set up to be 'echo' by default.
$self->__debug__( "Found a shortcut tag: $tag" );
$self->__process_tag__(
$HTML::CMTemplate::tagNameDefault, $tag);
}
$self->{parserintag} = 0;
$curpos = $pos + $HTML::CMTemplate::tagEndLen;
# Check that the next character is not an endline. If it is,
# we need to eat it.
# TODO: What happens on Windows? Do we need to move it two?
$curpos++ if (substr($self->{strbuf}, $curpos, 1) eq "\n");
# Important to move up the bufstart flag. We have, after all,
# used up the buffer to this point.
$self->{bufstart} = $curpos;
}
else {
# No ending tag found. We need to continue accumulating buffer.
last;
}
}
# Not in a tag. Search for a starting tag or something that looks
# like it might be one. Send out all text. If a tag is found,
# we need to put ourselves into a tag state and set the tagstart
# index.
else {
$self->__debug__( "STATE: Not in a tag" );
# NOTE: There is a tricky boundary case here. If the start tag
# is spanning buffer boundaries (this usually won't happen,
# especially if the file is read in one line at a time, but it
# will definitely happen if it is read in arbitrary sized chunks)
# it could get missed by the parser. (A full substring match will
# fail until the entire tag is seen.) So, when getting ready
# to spit out text, we need to check back a few characters for
# the first character of a start tag. If it is there and it is
# not escaped somehow, we only send out the text up to that
# character. We then defer searching for the start tag until
# the next section of buffer is read in.
my $pos = index( $self->{strbuf}, $HTML::CMTemplate::tagStart, $curpos);
$self->__debug__( "Start tag position: $pos" );
# If we found a start tag, we need to dump the text out and
# set the tag state. TODO: Check for escaped tags!
if ($pos > -1) {
# Found the start tag. Change state and get out.
$self->{parserintag} = 1;
$self->{tagstart} = $pos;
if ($pos > $curpos) {
$self->__process_cdata__(
substr( $self->{strbuf}, $curpos, $pos - $curpos )
);
$curpos = $pos;
}
# exhausted our buffer to this point.
$self->{bufstart} = $curpos;
}
else {
# No start tag found. Double check that the first character
# of the tag is not in the end of the buffer somewhere. If it
# is, then send out the text up to that character. Otherwise,
# send everything out as text.
my $firstchar = substr( $HTML::CMTemplate::tagEnd, 0, 1 );
my $fpos = index(
$self->{strbuf},
$firstchar,
$self->{buflen} - $HTML::CMTemplate::tagEndLen + 1
);
# If nothing like a tag was found, set the position to be
# the character after the end of the buffer. Otherwise,
# use the position of the tag character.
$fpos = ($fpos > -1) ? $fpos : $self->{buflen};
$self->__process_cdata__(
substr( $self->{strbuf}, $curpos, $fpos - $curpos )
);
$curpos = $fpos;
$self->{bufstart} = $curpos;
}
}
}
# We need to do some boundary checking here. If, for example, the bufstart
# flag is beyond the end of the buffer, we should just erase the buffer.
# It's utility is exhausted.
# Otherwise, we need to determine whether it makes sense to kill off part
# of the buffer.
if ($self->{bufstart} > 0) {
$self->__debug__( "Start of buffer not at the beginning. Reducing." );
if ($self->{bufstart} >= $self->{buflen}) {
$self->__debug__( "Buffer completely exhausted. Resetting." );
# Buffer is exhausted. Reset everyone.
$self->{bufstart} = 0;
$self->{strbuf} = '';
$self->{tagstart} = 0;
$self->{buflen} = 0;
}
else {
$self->__debug__( "Buffer partially exhausted. Resetting." );
# Buffer is at least partially exhausted. No point in keeping
# the unused portions around. XXX: Do we need to hold off on this
# case? Should we only kill it if the remaining portion is smaller
# than the unused portion? What kind of metric should determine
# this?
my $start = $self->{bufstart};
$self->{bufstart} = 0;
$self->{buflen} -= ($start + 1);
$self->{tagstart} -= $start;
$self->{strbuf} = substr( $self->{strbuf}, $start );
$self->__debug__( "New buffer length: " . $self->{buflen} );
}
}
}
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# USER SPACE STUFF
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
=pod
I<get_includes()>
Returns an arrayref of included files.
=cut
sub get_includes() {
my $self = shift;
my @includes = (keys(%{$self->{parsedtable}}), keys(%{$self->{rawtable}}));
return \@includes;
}
( run in 0.705 second using v1.01-cache-2.11-cpan-2398b32b56e )