A Tiny Perl Server Pages Engine 
by Andy Yuen

Listing One
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- Simple changing font size demo -->
<HTML><HEAD>
<TITLE>Simple Changing Font Size Demo</TITLE>
</HEAD>
<BODY>
<H3>PSP Simple Changing Font Size Demo</H3><P>
For loop incrementing font size from 1 to 5: <P>
<%-- You should not see this--%>
<% for(1..5) { %>
    <!-- iterated html text -->
    <FONT SIZE="<%= $_ %>" > Size = <%= $_ %> </FONT> <BR>
<% } %>
</BODY>
</HTML>

Listing Two
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  <HTML><HEAD>
  <TITLE>Simple Custom Tag</TITLE>
  </HEAD>
  <BODY>
  <H3>PSP Simple Custom Tag Demo</H3><P>
  The curent date and time: <test:date format="%Y-%m-%d %a %H:%M:%S" />
  </BODY>
  </HTML>

Listing Three
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Nested Custom Tag Demo</TITLE>
</HEAD>

<BODY>
<H3>PSP Nested Custom Tag Demo</H3><P>
<UL>

<test:loop repts=10>
<LI>
<test:if>
  <test:condition><%= (rand > .5) %></test:condition>
  <test:then>Head</test:then>
  <test:else>Tail</test:else>
</test:if>
</test:loop>

</UL>

</BODY>
</HTML>

Listing Four
#!perl
# ********************************************************************
# This script is generated by the PSP translator based on a PSP file.
# ********************************************************************
# import section
use PSP::Writer;
use PSP::TagObjFactory;
use CGI;

# custom tag modules import if any
~~IMPORT~~

# declaration section
~~INIT~~

# PSP initialization
my $out = new PSP::Writer;
my $request = new CGI;
my $response = $request;
my $psp = new PSP::TagObjFactory($request, $response, "errPage.tpl");
my @PSP_stack;
my $PSP_out = $out;

# header section
~~HEADER~~
# PSP body
~~BODY~~
# send buffered output to STDOUT
$out->flush(\*STDOUT);

Listing Five
{
push @PSP_stack, $out;
push @PSP_stack, $PSP_out;
$PSP_out = $out;
$out = new PSP::Writer;
my $PSP_tag;
$PSP_tag = qq(<test:date format="%Y-%m-%d %a %H:%M:%S" />);
my $tagobj_0 = $psp->createTagObj($PSP_out, $out, $PSP_tag);
if ($tagobj_0->doTagStart() == 1) {
    my $pred_0 = 1;
    while ($pred_0) {
        $pred_0 = $tagobj_0->doBody();
    }
}
$tagobj_0->doTagEnd();
$psp->houseKeeping($PSP_out, $out);
$PSP_out = pop @PSP_stack;
$out = pop @PSP_stack;
}


Listing Six
package test::date;

use POSIX;
use PSP::TagHandler;
@ISA = qw(PSP::TagHandler);

# constructor
sub new {
    my $class = shift;
    my $self = $class->SUPER::new(@_);
    $self->{'format'} = '%c';
    return $self;
}
# handler for processing the start of a custom tag
sub doTagStart {
    my $self = shift;
    my $out = $self->{'body'}->out();
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
    $out->print(strftime($self->{'format'},$sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst));
    return 0;
}
# handler for the format attribute
sub format {
    my $self = shift;
    $self->{'format'} = shift if @_;
    return $self->{'format'};
}
1;

Listing Seven

package test::loop;

use PSP::TagHandler;
@ISA = qw(PSP::TagHandler);

# constructor
sub new {
    my $class = shift;
    my $self = $class->SUPER::new(@_);
    $self->{'repts'} = undef;
    return $self;
}
# handler for processing the body of a custom tag
sub doBody {
    my $self = shift;
    my $body = $self->{'body'};
    my $out = $body->out;
    # output the tag body only for the specified number
    # of times
    if ($self->{'repts'}--) {
        $out->print($body->body);
        return 3;
    }
    return 0;
}
# handler for the repts attribute
sub repts {
    my $self = shift;
    $self->{'repts'} = shift if @_;
    return $self->{'repts'};
}
1;

Listing Eight
package test::if;

use PSP::TagHandler;
@ISA = qw(PSP::TagHandler);
1;

Listing Nine
package test::condition;

use PSP::TagHandler;
@ISA = qw(PSP::TagHandler);

# constructor
sub new {
    my $class = shift;
    my $self = $class->SUPER::new(@_);
   return $self;
}
# handler for processing the start of a custom tag
sub doTagStart {
    my $self = shift;
    #check if enclosed in test::if
    my $parent = $self->findAncestorWithClass("test::if");
    if (defined($parent)) {
        # save the parent object
        $self->{'parent'} = $parent;
        return 1;
    }
    $self->errorPage("errPage.tpl", 
        "&lt;test:condition&gt; 
                    not enclosed in &lt;test:if&gt;&lt;test:if&gt;");
    return 0;
}
# handler for processing the body of a custom tag
sub doBody {
    my $self = shift;
    my $body = $self->{'body'};
    my $out = $body->out;
    my $text = $body->body;
    my $parent = $self->{'parent'};

    # create condition variable in parent object
    $parent->vars('condition', sprintf("%d", $text));
    return 0;
}
1;


Listing Ten
package test::then;

use PSP::TagHandler;
@ISA = qw(PSP::TagHandler);

# constructor
sub new {
    my $class = shift;
    my $self = $class->SUPER::new(@_);
    return $self;
}
# handler for processing the start of a custom tag
sub doTagStart {
    my $self = shift;

    #check if enclosed in test::if
    my $parent = $self->findAncestorWithClass("test::if");
    if (defined($parent)) {
        # save the parent object
        $self->{'parent'} = $parent;
        return 1;
    }
    $self->errorPage("errPage.tpl", 
        "&lt;then:condition&gt; 
                   not enclosed in &lt;test:if&gt;&lt;test:if&gt;");
    return 0;
}
# handler for processing the body of a custom tag
sub doBody {
    my $self = shift;
    my $body = $self->{'body'};
    my $out = $body->out;
    my $text = $body->body;
    my $parent = $self->{'parent'};

    # check if a condition has been set in the parent object
    my $cond = $parent->vars('condition');
    if (!defined($cond)) {
        $self->errorPage("errPage.tpl", 
            "&lt;test:then&gt; without &lt;test:condition&gt;");
    }
    # output the tag body only if the condition is true
    if ( $cond == 1) {
        $out->print($text);
    }
    return 0;
}
1;





5

