Apache-PSP
view release on metacpan or search on metacpan
lib/Template/PSP.pm view on Meta::CPAN
package Template::PSP;
require 5.005;
use strict;
use Carp;
use HTML::Parser;
use IO::Scalar;
use DBI;
use vars qw($VERSION);
$VERSION = 1.00;
# %tags - list of special HTML tags defined in Template.pm
# %global_tags - list of HTML tags, accessible by all pages
#
# $page - scalar reference to script being created from template
# $frags - html fragments
# $outputflag - process '$' variables
# $perlflag - perl code
# $package - template is being placed in $package
# %tagdata - data associated with tag being created
# %Cache - file time stamps for loaded psp pages
# %Handler - pointers to subroutines for psp pages
# %type - subroutines for handling output types
use vars qw (%tags %global_tags $page $parsefile $frags $outputflag $perlflag
$handlerflag $package %tagdata %Cache %Handler %type $lineno
$top_package $escapeflag $space
);
use vars qw(%QUERY %CGI %FILENAMES %AUTH %COOKIE);
%tags = map {$_ => 1}
( "tag", "loop", "if", "else", "elseif", "perl", "fetch", "output",
"handler", "return", "include", "pspescape" );
sub cleanup
{
no strict 'refs';
push(@{$top_package . "::cleanup_handler"}, shift);
}
sub cleanup_handler
{
my $handlers = shift(@_);
for (my $i=0;$handlers->[$i];$i++)
{
&{$handlers->[$i]}();
}
}
sub setpvar
{
my $item = shift;
my $value = shift;
if ($item)
{
no strict 'refs';
${$top_package . "::" . $item} = $value;
}
}
sub getpvar
{
my $item = shift;
no strict 'refs';
return ${$top_package . "::" . $item};
}
# derive the absolute path based on a
# relative filename and the current file
#
# thanks to Scott Kiehn
#
sub abs_path
{
my $file = shift(@_);
my $prefix = substr($file, 0, 1);
# if this is not an absolute path,
# create an absolute path from it
if ($prefix ne '/')
{
# check for document root abbreviation
if ($prefix eq '~')
{
$file = substr($file, 1);
$file = $ENV{DOCUMENT_ROOT} . $file;
}
# otherwise use relative path based on the current file
else
{
$file = substr( $parsefile, 0, rindex($parsefile, '/') ) . "/" . $file;
}
}
return $file;
}
################################################################
# pspload
# pspload reloads psp pages that have changed on disk and
# puts the code for those pages into their own package based
# on the name of the file being loaded. We run the file
# name passed to pspload through abs_path to be certain that
# the file name is uniquely defined.
sub pspload
{
my ($data, $pkg, $topflag) = @_;
my $parseflag = 0;
my $handler;
my $file;
my ($oldpage, $oldpkg, $oldfrags, $pg, $oldfile, $oldlineno);
if (!ref($data))
{
# data is a file name, not the code
# This file name may have . ../.. or a relative path
# that makes it not uniquely defined
$file = abs_path($data);
if (newfile($file))
{
# we've not loaded the file before, or it
# has changed on disk. Load it.
if (!defined($pkg))
{
$pkg = valid_package_name($file);
}
$parseflag = 1;
}
else
{
$handler = $Handler{$file};
}
}
else
{
$parseflag = 1;
$file = $ENV{SCRIPT_FILENAME};
}
if ($parseflag)
{
my $parser;
my $token;
# we need to create a temporary place
# to store the page as it is building it
$oldlineno = $lineno;
$oldfile = $parsefile;
$oldfrags = $frags;
$oldpage = $page;
$oldpkg = $package;
$frags = 0;
$lineno = 1;
$package = $pkg;
$page = \$pg;
$parsefile = $file;
my $eval = "package $pkg;\n" .
'*getpvar = \&Template::PSP::getpvar;' . "\n" .
'*setpvar = \&Template::PSP::setpvar;' . "\n" .
'*cleanup = \&Template::PSP::cleanup;' . "\n" .
'use CGI::Minimal;' . "\n" .
'use vars qw(%QUERY %CGI %FILENAMES %AUTH %COOKIE);' . "\n";
eval $eval;
append_page("package $pkg;\n");
append_page("no strict;\n");
append_page("sub {\n");
if ($topflag)
{
append_page('$Template::PSP::top_package = ' . $pkg . ";\n");
append_page('Template::PSP::set_hashes(*CGI, *COOKIE, *QUERY, *FILENAMES, *AUTH);' . "\n"); }
else
{
append_page(
'*QUERY = *{$Template::PSP::top_package . "::QUERY"};' . "\n" .
'*CGI = *{$Template::PSP::top_package . "::CGI"};' . "\n" .
'*FILENAMES = *{$Template::PSP::top_package . "::FILENAMES"};' . "\n" .
'*AUTH = *{$Template::PSP::top_package . "::AUTH"};' . "\n" .
'*COOKIE = *{$Template::PSP::top_package . "::COOKIE"};' . "\n");
}
$parser = HTML::Parser->new( api_version => 3,
start_h => [\&start, "tagname,attr,text"],
end_h => [\&end, "tagname,text"],
text_h => [\&text, "text,is_cdata"],
comment_h => [\&comment, "text"],
default_h => [\&default, "text"]
);
# send unbroken text instead of chunks to improve performance
# by reducing the number of function calls
$parser->unbroken_text(1);
$parser->xml_mode(1);
if (ref($data))
{
$parser->parse($$data) || croak "$! in pspload()";
}
else
{
$parser->parse_file($data) || croak "$! while loading file '$data'";
}
if ($topflag)
{
append_page('&Template::PSP::cleanup_handler(\@cleanup_handler);' . "\n");
append_page('select(STDOUT);' . "\n");
}
append_page("return 1;\n");
append_page("}\n");
$handler = eval $$page;
if ($@)
{
psperror($file);
}
if ($file)
{
$Handler{$file} = $handler;
}
no strict 'refs';
# restore globals
$lineno = $oldlineno;
$parsefile = $oldfile;
$frags = $oldfrags;
$page = $oldpage;
$package = $oldpkg;
}
# import export_tags from loaded page
if (defined($package))
{
if (!defined($pkg))
{
$pkg = valid_package_name($file);
}
no strict 'refs';
foreach my $tag (keys %{$pkg . "::export_tags"})
{
${$package . "::custom_tags"}{$tag} = ${$pkg . "::export_tags"}{$tag};
}
}
return $handler;
}
# displays psp page with line numbers
sub pspdebug
{
no strict 'refs';
my @lines = split("\n", $$page);
for (my $i = 1; $i <= $#lines + 1;$i++)
{
print STDERR "<$i> " . $lines[$i-1] . "\n";
}
}
# output error
sub psperror
{
my $tag = shift;
# pspdebug();
# croak "failed when processing " . $tagdata{name} . ": $@\n";
croak $@;
}
# appends code to page
sub append_page
{
no strict 'refs';
${$page} .= join(" ", @_);
}
sub set_hashes (%%%%%)
{
local(*CGI, *COOKIE, *QUERY, *FILENAMES, *AUTH) = @_;
# duplicate environment variables in %CGI
%CGI = %ENV;
# fill %QUERY with query values
lib/Template/PSP.pm view on Meta::CPAN
no strict 'refs';
my $fn = $global_tags{$tagname . "_"} ||
${$package . "::custom_tags"}{$tagname . "_"};
if ($fn)
{
no strict 'refs';
append_page('&' . $fn .'();' . "\n");
return;
}
text($space . $text);
$space = "";
return;
}
# for comments,
# display the comment as provided
sub comment
{
my ($text) = @_;
default($text);
text($space . $text);
$space = "";
return;
return;
}
sub default
{
my ($text) = @_;
$lineno += count_lines($text);
}
# handles all text that is read by the parser
sub text
{
my ($text) = @_;
if (!$escapeflag && $text =~ /^\s*$/s)
{
$space = $text;
return;
}
if ($perlflag)
{
append_page($text);
}
elsif ($outputflag)
{
$text =~ s/\@/\\\@/g;
append_page('print qq{' . $text . '};' . "\n");
}
else
{
no strict 'refs';
$frags++;
${$package . '::__html_' . $frags} = $text;
append_page("print \$" . $package . '::__html_' . $frags . ";\n");;
}
}
#########################################
# BEGIN TAG DEFINITIONS
#
# The tag TAG allows building of non-looping tags.
# three parameters can be passed:
# name - name of tag to create
# body - if set to nonzero, the tag being defined contains
# a body
# output - if set to nonzero, the tag being defined will
# evaluate variables that begin with '$'
sub tag
{
my ($attr) = @_;
my (@attrs) = split(/,/, $attr->{accepts});
# Try to hide global variables for building tag in
# %Template::PSP::tagdata
$tagdata{body} = $attr->{body};
if ($tagdata{body})
{
push(@attrs, "body");
}
$tagdata{global} = $attr->{global};
$tagdata{name} = lc($attr->{name});
$tagdata{oldpage} = $page;
$page = \$tagdata{page};
# For each new tag, create a Perl function
# which will be called when the start tag is
# encountered
append_page('package', $package . ";\n");
append_page("no strict 'refs';\n");
append_page('sub', $tagdata{name}, "{\n");
append_page('my ($attr) = @_;' . "\n");
foreach my $item (@attrs)
{
append_page('my', "\$" . $item, "=", '$attr->{' . $item . "};\n");
}
append_page("#line $lineno $parsefile\n");
# If the tag we are defining will have a body,
# redirect the output from processing the body
# to a Perl scalar ($body). Create a Perl function
# which will be called when the end tag is encountered
if ($tagdata{body})
{
# save all variables
append_page('push(@Template::PSP::attrs, $attr);' . "\n");
( run in 2.188 seconds using v1.01-cache-2.11-cpan-b16cb0d3907 )