📄 template.pm
字号:
push(@pstacks, $template->{parse_stack}); } } }} # initialize the template buffersub _init_template { my $self = shift; my $options = $self->{options}; print STDERR "### HTML::Template Memory Debug ### START INIT_TEMPLATE ", $self->{proc_mem}->size(), "\n" if $options->{memory_debug}; if (exists($options->{filename})) { my $filepath = $options->{filepath}; if (not defined $filepath) { $filepath = $self->_find_file($options->{filename}); confess("HTML::Template->new() : Cannot open included file $options->{filename} : file not found.") unless defined($filepath); # we'll need this for future reference - to call stat() for example. $options->{filepath} = $filepath; } confess("HTML::Template->new() : Cannot open included file $options->{filename} : $!") unless defined(open(TEMPLATE, $filepath)); $self->{mtime} = $self->_mtime($filepath); # read into scalar, note the mtime for the record $self->{template} = ""; while (read(TEMPLATE, $self->{template}, 10240, length($self->{template}))) {} close(TEMPLATE); } elsif (exists($options->{scalarref})) { # copy in the template text $self->{template} = ${$options->{scalarref}}; delete($options->{scalarref}); } elsif (exists($options->{arrayref})) { # if we have an array ref, join and store the template text $self->{template} = join("", @{$options->{arrayref}}); delete($options->{arrayref}); } elsif (exists($options->{filehandle})) { # just read everything in in one go local $/ = undef; $self->{template} = readline($options->{filehandle}); delete($options->{filehandle}); } else { confess("HTML::Template : Need to call new with filename, filehandle, scalarref or arrayref parameter specified."); } print STDERR "### HTML::Template Memory Debug ### END INIT_TEMPLATE ", $self->{proc_mem}->size(), "\n" if $options->{memory_debug}; # handle filters if necessary $self->_call_filters(\$self->{template}) if @{$options->{filter}}; return $self;}# handle calling user defined filterssub _call_filters { my $self = shift; my $template_ref = shift; my $options = $self->{options}; my ($format, $sub); foreach my $filter (@{$options->{filter}}) { croak("HTML::Template->new() : bad value set for filter parameter - must be a code ref or a hash ref.") unless ref $filter; # translate into CODE->HASH $filter = { 'format' => 'scalar', 'sub' => $filter } if (ref $filter eq 'CODE'); if (ref $filter eq 'HASH') { $format = $filter->{'format'}; $sub = $filter->{'sub'}; # check types and values croak("HTML::Template->new() : bad value set for filter parameter - hash must contain \"format\" key and \"sub\" key.") unless defined $format and defined $sub; croak("HTML::Template->new() : bad value set for filter parameter - \"format\" must be either 'array' or 'scalar'") unless $format eq 'array' or $format eq 'scalar'; croak("HTML::Template->new() : bad value set for filter parameter - \"sub\" must be a code ref") unless ref $sub and ref $sub eq 'CODE'; # catch errors eval { if ($format eq 'scalar') { # call $sub->($template_ref); } else { # modulate my @array = map { $_."\n" } split("\n", $$template_ref); # call $sub->(\@array); # demodulate $$template_ref = join("", @array); } }; croak("HTML::Template->new() : fatal error occured during filter call: $@") if $@; } else { croak("HTML::Template->new() : bad value set for filter parameter - must be code ref or hash ref"); } } # all done return $template_ref;}# _parse sifts through a template building up the param_map and# parse_stack structures.## The end result is a Template object that is fully ready for# output().sub _parse { my $self = shift; my $options = $self->{options}; $options->{debug} and print STDERR "### HTML::Template Debug ### In _parse:\n"; # setup the stacks and maps - they're accessed by typeglobs that # reference the top of the stack. They are masked so that a loop # can transparently have its own versions. use vars qw(@pstack %pmap @ifstack @ucstack %top_pmap); local (*pstack, *ifstack, *pmap, *ucstack, *top_pmap); # the pstack is the array of scalar refs (plain text from the # template file), VARs, LOOPs, IFs and ELSEs that output() works on # to produce output. Looking at output() should make it clear what # _parse is trying to accomplish. my @pstacks = ([]); *pstack = $pstacks[0]; $self->{parse_stack} = $pstacks[0]; # the pmap binds names to VARs, LOOPs and IFs. It allows param() to # access the right variable. NOTE: output() does not look at the # pmap at all! my @pmaps = ({}); *pmap = $pmaps[0]; *top_pmap = $pmaps[0]; $self->{param_map} = $pmaps[0]; # the ifstack is a temporary stack containing pending ifs and elses # waiting for a /if. my @ifstacks = ([]); *ifstack = $ifstacks[0]; # the ucstack is a temporary stack containing conditions that need # to be bound to param_map entries when their block is finished. # This happens when a conditional is encountered before any other # reference to its NAME. Since a conditional can reference VARs and # LOOPs it isn't possible to make the link right away. my @ucstacks = ([]); *ucstack = $ucstacks[0]; # the loopstack is another temp stack for closing loops. unlike # those above it doesn't get scoped inside loops, therefore it # doesn't need the typeglob magic. my @loopstack = (); # the fstack is a stack of filenames and counters that keeps track # of which file we're in and where we are in it. This allows # accurate error messages even inside included files! # fcounter, fmax and fname are aliases for the current file's info use vars qw($fcounter $fname $fmax); local (*fcounter, *fname, *fmax); my @fstack = ([$options->{filename} || "main template", 1, scalar @{[$self->{template} =~ m/(\n)/g]} + 1 ]); (*fname, *fcounter, *fmax) = \ ( @{$fstack[0]} ); my $NOOP = HTML::Template::NOOP->new(); my $ESCAPE = HTML::Template::ESCAPE->new(); my $URLESCAPE = HTML::Template::URLESCAPE->new(); # all the tags that need NAMEs: my %need_names = map { $_ => 1 } qw(TMPL_VAR TMPL_LOOP TMPL_IF TMPL_UNLESS TMPL_INCLUDE); # variables used below that don't need to be my'd in the loop my ($name, $which, $escape); # handle the old vanguard format $options->{vanguard_compatibility_mode} and $self->{template} =~ s/%([-\w\/\.+]+)%/<TMPL_VAR NAME=$1>/g; # now split up template on '<', leaving them in my @chunks = split(m/(?=<)/, $self->{template}); # all done with template delete $self->{template}; # loop through chunks, filling up pstack my $last_chunk = $#chunks; CHUNK: for (my $chunk_number = 0; $chunk_number <= $last_chunk; $chunk_number++) { next unless defined $chunks[$chunk_number]; my $chunk = $chunks[$chunk_number]; # a general regex to match any and all TMPL_* tags if ($chunk =~ /^< (?:!--\s*)? ( \/?[Tt][Mm][Pp][Ll]_ (?: (?:[Vv][Aa][Rr]) | (?:[Ll][Oo][Oo][Pp]) | (?:[Ii][Ff]) | (?:[Ee][Ll][Ss][Ee]) | (?:[Uu][Nn][Ll][Ee][Ss][Ss]) | (?:[Ii][Nn][Cc][Ll][Uu][Dd][Ee]) ) ) # $1 => $which - start of the tag \s* # ESCAPE attribute (?: [Ee][Ss][Cc][Aa][Pp][Ee] \s*=\s* (?: ( 0 | (?:"0") | (?:'0') ) # $2 => ESCAPE off | ( 1 | (?:"1") | (?:'1') | (?:[Hh][Tt][Mm][Ll]) | (?:"[Hh][Tt][Mm][Ll]") | (?:'[Hh][Tt][Mm][Ll]') | (?:[Uu][Rr][Ll]) | (?:"[Uu][Rr][Ll]") | (?:'[Uu][Rr][Ll]') | ) # $3 => ESCAPE on ) )* # allow multiple ESCAPEs \s* # NAME attribute (?: (?: [Nn][Aa][Mm][Ee] \s*=\s* )? (?: "([^">]*)" # $4 => double-quoted NAME value " | '([^'>]*)' # $5 => single-quoted NAME value | ([^\s=>]*) # $6 => unquoted NAME value ) )? \s* # ESCAPE attribute (?: [Ee][Ss][Cc][Aa][Pp][Ee] \s*=\s* (?: ( 0 | (?:"0") | (?:'0') ) # $7 => ESCAPE off | ( 1 | (?:"1") | (?:'1') | (?:[Hh][Tt][Mm][Ll]) | (?:"[Hh][Tt][Mm][Ll]") | (?:'[Hh][Tt][Mm][Ll]') | (?:[Uu][Rr][Ll]) | (?:"[Uu][Rr][Ll]") | (?:'[Uu][Rr][Ll]') | ) # $8 => ESCAPE on ) )* # allow multiple ESCAPEs \s* (?:--)?> (.*) # $9 => $post - text that comes after the tag $/sx) { $which = uc($1); # which tag is it $escape = $3 || $8; $escape = 0 if $2 || $7; # ESCAPE=0 $escape = 0 unless defined($escape); # what name for the tag? undef for a /tag at most, one of the # following three will be defined undef $name; $name = $4 if defined($4); $name = $5 if defined($5); $name = $6 if defined($6); # allow mixed case in filenames, otherwise flatten $name = lc($name) unless ($which eq 'TMPL_INCLUDE' or $options->{case_sensitive}); my $post = $9; # what comes after on the line # die if we need a name and didn't get one die "HTML::Template->new() : No NAME given to a $which tag at $fname : line $fcounter." if (!defined($name) and $need_names{$which}); # die if we got an escape but can't use one die "HTML::Template->new() : ESCAPE option invalid in a $which tag at $fname : line $fcounter." if ( $escape and ($which ne 'TMPL_VAR')); # take actions depending on which tag found if ($which eq 'TMPL_VAR') { $options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : parsed VAR $name\n"; # if we already have this var, then simply link to the existing # HTML::Template::VAR, else create a new one. my $var; if (exists $pmap{$name}) { $var = $pmap{$name}; (ref($var) eq 'HTML::Template::VAR') or die "HTML::Template->new() : Already used param name $name as a TMPL_LOOP, found in a TMPL_VAR at $fname : line $fcounter."; } else { $var = HTML::Template::VAR->new(); $pmap{$name} = $var; $top_pmap{$name} = HTML::Template::VAR->new() if $options->{global_vars} and not exists $top_pmap{$name}; } # if ESCAPE was set, push an ESCAPE op on the stack before # the variable. output will handle the actual work. if ($escape) { if ($escape =~ /^"?[Uu][Rr][Ll]"?$/) { push(@pstack, $URLESCAPE); } else { push(@pstack, $ESCAPE); } } push(@pstack, $var); } elsif ($which eq 'TMPL_LOOP') { # we've got a loop start $options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : LOOP $name start\n"; # if we already have this loop, then simply link to the existing # HTML::Template::LOOP, else create a new one. my $loop; if (exists $pmap{$name}) { $loop = $pmap{$name}; (ref($loop) eq 'HTML::Template::LOOP') or die "HTML::Template->new() : Already used param name $name as a TMPL_VAR, TMPL_IF or TMPL_UNLESS, found in a TMP_LOOP at $fname : line $fcounter!"; } else { # store the results in a LOOP object - actually just a # thin wrapper around another HTML::Template object. $loop = HTML::Template::LOOP->new(); $pmap{$name} = $loop; } # get it on the loopstack, pstack of the enclosing block push(@pstack, $loop); push(@loopstack, [$loop, $#pstack]); # magic ti
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -