v3.13 release 3.13
authorJuerd Waalboer <juerd@cpan.org>
Sun, 19 May 2002 23:42:06 +0000 (23:42 +0000)
committerMischa POSLAWSKY <perl@shiar.org>
Fri, 30 Mar 2007 23:49:16 +0000 (01:49 +0200)
Changes
MANIFEST
PLP.pm
PLP/FAQ.pod [new file with mode: 0644]
PLP/Fields.pm
PLP/Functions.pm
PLP/Tie/Delay.pm
plp.vim [new file with mode: 0644]

diff --git a/Changes b/Changes
index e0b66fa0d9c8ff19d7cc8026bd4110b112cbd56d..a03225a664bfcecf1c57caa3db6ed6d0a6767c92 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,3 +1,18 @@
+3.13 - May 20, 2002
+- Added documentation:
+  - PLP
+  - PLP::FAQ
+  - PLP::Fields
+  - PLP::Functions
+- Added predeclared of hashes for use-strict-users ("our"/"use vars"
+  is no longer necessary for the PLP hashes)
+- Added plp.vim for vim syntax highlighting to the distribution
+- Added error reportig to Counter, ReadFile and WriteFile
+- Changed ReadFile and WriteFile to use lexical filehandles
+- Changed PLP::Functions to use Fcntl for improved portability
+- Cleaned up PLP::Fields: removed the PLPdummies
+- Fixed DELETE, EXISTS and FIRSTKEY in PLP::Tie::Delay (added PLPdummy there)
+
 3.12 - May 18, 2002
 - Fixed strict-violation in PLP.pm that happened only without mod_perl
 
index e2bb0f20e0f4c7471ccd503b9cbaa73e6cc06e99..84c9d83c05768edd425569590d0d10e0f73ba8e2 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -4,7 +4,9 @@ MANIFEST
 PLP.pm
 README
 plp.cgi
+plp.vim
 test.pl
+PLP/FAQ.pod
 PLP/Fields.pm
 PLP/Functions.pm
 PLP/Tie/Delay.pm
diff --git a/PLP.pm b/PLP.pm
index ab50f559a909fa4219c0ca3af78ed6fc6bc55a8a..3efbfdb1ac3c70af014a6e42ceaaf4297a0d7185 100644 (file)
--- a/PLP.pm
+++ b/PLP.pm
@@ -1,4 +1,6 @@
-package PLP;
+#--------------#
+  package PLP;
+#--------------#
 
 use v5.6;
 
@@ -10,7 +12,7 @@ use PLP::Tie::Print;
 
 use strict;
 
-our $VERSION = '3.12';
+our $VERSION = '3.13';
 
 # subs in this package:
 #  sendheaders                      Send headers
@@ -219,6 +221,7 @@ sub start {
     PLP::Fields::doit();
     {
        package PLP::Script;
+       use vars qw(%headers %header %cookies %cookie %get %post %fields);
        *headers = \%header;
        *cookies = \%cookie;
        PLP::Functions->import();
@@ -321,6 +324,113 @@ other Perl embedders, there is no need to learn a meta-syntax or object
 model: one can just use the normal Perl constructs. PLP runs under mod_perl
 for speeds comparable to those of PHP, but can also be run as a CGI script.
 
+=head2 PLP Syntax
+
+=over 22
+
+=item C<< <: perl_code(); :> >>
+
+With C<< <: >> and C<< :> >>, you can add Perl code to your document. This is
+what PLP is all about. All code outside of these tags is printed. It is
+possible to mix perl language constructs with normal HTML parts of the document:
+
+    <: unless ($ENV{REMOTE_USER}) { :>
+        You are not logged in.
+    <: } :>
+
+C<< :> >> always stops a code block, even when it is found in a string literal.
+
+=item C<< <:= $expression :> >>
+
+Includes a dynamic expression in your document. The expression is evaluated in
+list context. Please note that the expression should not end a statement: avoid
+semi-colons. No whitespace may be between C<< <: >> and the equal sign.
+
+C<< foo <:= $bar :> $baz >> is like C<< <: print 'foo ', $bar, ' baz'; :> >>.
+
+=item C<< <(filename)> >>
+
+Includes another file before the PLP code is executed. The file is included
+literally, so it shares lexical variables. Because this is a compile-time tag,
+it's fast, but you can't use a variable as the filename. You can create
+recursive includes, so beware of that! Whitespace in the filename is not
+ignored so C<< <( foo.txt)> >> includes the file named C< foo.txt>, including
+the space in its name. A compile-time alternative is include(), which is
+described in L<PLP::Functions>.
+
+=back
+
+=head2 PLP Functions
+
+These are described in L<PLP::Functions>.
+
+=head2 PLP Variables
+
+=over 22
+
+=item $ENV{PLP_NAME}
+
+The URI of the PLP document, without the query string. (Example: C</foo.plp>)
+
+=item $ENV{PLP_FILENAME}
+
+The filename of the PLP document. (Example: C</var/www/index.plp>)
+
+=item $PLP::VERSION
+
+The version of PLP.
+
+=item $PLP::DEBUG
+
+Controls debugging output, and should be treated as a bitmask. The least
+significant bit (1) controls if run-time error messages are reported to the
+browser, the second bit (2) controls if headers are sent twice, so they get
+displayed in the browser. A value of 3 means both features are enabled. The
+default value is 1.
+
+=item $PLP::ERROR
+
+Contains a reference to the code that is used to report run-time errors. You
+can override this to have it in your own design, and you could even make it
+report errors by e-mail. The sub reference gets two arguments: the error message
+as plain text and the error message with special characters encoded with HTML 
+entities.
+
+=item %header, %cookie, %get, %post, %fields
+
+These are described in L<PLP::Fields>.
+
+=back
+
+=head2 Things that you should know about
+
+Not only syntax is important, you should also be aware of some other important
+features. Your script runs inside the package C<PLP::Script> and shouldn't
+leave it. This is because when your script ends, all global variables in the
+C<PLP::Script> package are destroyed, which is very important if you run under
+mod_perl (they would retain their values if they weren't explicitly destroyed).
+
+Until your first output, you are printing to a tied filehandle C<PLPOUT>. On
+first output, headers are sent to the browser and C<STDOUT> is selected for
+efficiency. To set headers, you must assign to C<$header{ $header_name}> before
+any output. This means the opening C<< <: >> have to be the first characters in
+your document, without any whitespace in front of them. If you start output and
+try to set headers later, an error message will appear telling you on which
+line your output started.
+
+Because the interpreter that mod_perl uses never ends, C<END { }> blocks won't
+work properly. You should use C<PLP_END { };> instead. Note that this is a not
+a built-in construct, so it needs proper termination with a semi-colon (as do
+<eval> and <do>).
+
+Under mod_perl, modules are loaded only once. A good modular design can improve
+performance because of this, but you will have to B<reload> the modules
+yourself when there are newer versions. 
+
+The special hashes are tied hashes and do not always behave the way you expect,
+especially when mixed with modules that expect normal CGI environments, like
+CGI.pm. Read L<PLP::Fields> for information more about this.
+
 =head1 WEBSITE
 
 For now, all documentation is on the website. Everything will be POD one day,
@@ -329,7 +439,7 @@ but until that day, you will need to visit http://plp.juerd.nl/
 =head1 FAQ
 
 A lot of questions are asked often, so before asking yours, please read the 
-FAQ that is located at http://plp.juerd.nl/faq.plp
+FAQ at L<PLP::FAQ>.
 
 =head1 NO WARRANTY
 
diff --git a/PLP/FAQ.pod b/PLP/FAQ.pod
new file mode 100644 (file)
index 0000000..2aac805
--- /dev/null
@@ -0,0 +1,119 @@
+=head1 Frequently Asked Questions about PLP
+
+=over 10
+
+=item What does PLP stand for?
+
+PerlPage. The name used to be HTMPL, but HyperText Markup with Perl Language was too long.
+
+=item Is PLP hard to install?
+
+No, it actually is very simple and easy. Quick startup hints are in the PLP main
+documentation, extensive installation instructions are on the PLP website.
+
+=item Is Perl code harder than PHP code?
+
+Yes, it is. But when you get used to Perl, you will probably dislike PHP for
+the rest of your life. Perl is faster and far more powerful. For both Perl
+beginners and more advanced Perl coders, PerlMonks is a good Perl forum community.
+(Please note: PLP is not Perl. Perl is a complete programming language and is
+not restricted to web based applications. PLP B<uses> Perl, but many people
+use Perl without PLP.
+
+=item Can PLP be used with mod_perl?
+
+Yes. As of 3.00, PLP can be used with mod_perl! And it's very fast!
+
+=item You seem to promote dirty programming. Can I use strict with PLP?
+
+PLP can be used for quick-and-dirty hacks in a way similar to PHP. However, it
+is suitable for larger applications as well. You can use strict if you want.
+mod_perl Users might like to know that globals are automatically destroyed (as
+long as you do not switch packages).
+
+=item How can I make PLP faster?
+
+With mod_perl, PLP is a lot faster than with CGI. CGI scripts execute an
+external interpreter, but mod_perl is a Perl interpreter inside Apache.
+
+=item I already use mod_perl, can I make my scripts even faster?
+
+Well, you already have scripts that probably are faster than PHP equivalents,
+but speed maniacs always want more. Modules are cached, so with a proper module
+design, you can add a little more speed.
+
+=item Can I use Perl's CGI module with PLP?
+
+You certainly can! If you do not want %get and %post and the like, just not use
+them. They will be generated on first access, so if you never access them, the
+hashes are never filled.
+
+If you want to use CGI.pm's header functions, C<select STDOUT;> first, to break
+out of PLP's tied C<PLPOUT> filehandle.
+
+=item Why does C<< <($filename)> >> not work?
+
+C<< <(...)> >> is a compile-time tag, opposed to C<include()>, which is evaluated at
+run-time. At compile time, variables are not yet known, and PLP will try to
+include a file literally called C<$filename>.
+
+    <: $filename = 'foo.inc.plp'; include($filename); :>
+
+=item Why do my variables not work in my C<include()>d file?
+
+That is because your variable is lexical (declared with C<my>), and the file is
+evaluated in its own scope, just as with Perl's built-in C<do> and C<require>.
+You can pass variables through subroutine parameters or by using globals
+variables. Another solution is using PLP's C<< <(...)> >> tag.
+
+=item But why do they work with C<< <()> >> then?
+
+Because it places the external file is placed inside of the other,
+B<before> the code is executed (at compile-time).
+
+=item Why do my C<END> blocks never get executed?
+
+If they are not, you are probably running under mod_perl. The blocks are
+executed when the interpreter stops, but the mod_perl interpreter is not exited
+after the PLP script has ended. Use C<PLP_END> blocks instead. Please note that
+C<PLP_END> is a normal statement, so you may need a semicolon.
+
+    <html><body>
+    <: PLP_END { :>
+        </body></html>
+    <: } :>
+
+=item Can I disable the error messages?
+
+You can not disable compile-time errors (syntax errors), but you can disable
+run-time errors. To do so, set the 0-bit (1) of C<$PLP::DEBUG> off. If you only
+want error reporting disabled for a single command, use Perl's C<eval BLOCK>
+function (not C<eval "">, but C<eval {}>, which is not slow or insecure.).
+
+    <: $PLP::DEBUG ^= 1 if $PLP::DEBUG & 1; :>
+
+=item Can I have my own error messages?
+
+Yes, you can! Of course, you can not override compile-time errors like syntax
+errors, but run-time error messages use C<$PLP::ERROR>, which is a reference to a
+sub that gets two arguments: the error message itself, and an html-encoded
+version.
+
+    <:
+        $PLP::ERROR = sub {
+            my ($plain, $html) = @_;
+            print '<font color="red">', $html, '</font>';
+        };
+    :>
+
+=item Is there a way to see the headers that PLP sends?
+
+There is. Set C<$PLP::DEBUG>'s 1-bit (2), and it will output a plain text header
+before outputting the other one.
+
+    <: $PLP::DEBUG ^= 2 unless $PLP::DEBUG & 2 :>
+
+=back
+
+=cut
+
index 14d30b65b83028156ec4d440dd08d7daaa618179..b7e7e950c31956579dff9a09a023b61a6644d34d 100644 (file)
@@ -3,22 +3,12 @@
 #----------------------#
 use strict;
 
-=head1 PLP::Fields
-
-Has only one function: doit(), which ties the hashes %get, %post, %fields and %header in
-PLP::Script. Also generates %cookie immediately.
-
-    PLP::Fields::doit();
-
-This module is part of the PLP internals. Don't use it yourself.
-
-=cut
-
+# Has only one function: doit(), which ties the hashes %get, %post, %fields and %header in
+# PLP::Script. Also generates %cookie immediately.
 sub doit {
     tie %PLP::Script::get, 'PLP::Tie::Delay', 'PLP::Script::get', sub {
        my %get;
-       my $get;
-       $get = $ENV{QUERY_STRING};
+       my $get = $ENV{QUERY_STRING};
        if ($get ne ''){
            for (split /[&;]/, $get) {
                my @keyval = split /=/, $_, 2;
@@ -38,8 +28,10 @@ sub doit {
        } else {
            read(*STDIN, $post, $ENV{CONTENT_LENGTH});
        }
-       if (defined($post) && $post ne '' &&
-           ($ENV{CONTENT_TYPE} eq '' || $ENV{CONTENT_TYPE} eq 'application/x-www-form-urlencoded')){
+       if (defined $post
+           and $post ne ''
+           and $ENV{CONTENT_TYPE} =~ m!^(?:application/x-www-form-urlencoded|$)!
+       ){
            for (split /&/, $post) {
                my @keyval = split /=/, $_, 2;
                PLP::Functions::DecodeURI(@keyval);
@@ -51,8 +43,10 @@ sub doit {
     };
 
     tie %PLP::Script::fields, 'PLP::Tie::Delay', 'PLP::Script::fields', sub {
-       $PLP::Script::get{PLPdummy}, $PLP::Script::post{PLPdummy}; # Trigger creation
-       return {%PLP::Script::get, %PLP::Script::post}
+#      $PLP::Script::get{PLPdummy}, $PLP::Script::post{PLPdummy}; # Trigger creation
+#      No longer necessary, as PLP::Tie::Delay has been fixed since 3.00
+#      And fixed even more in 3.13
+       return { %PLP::Script::get, %PLP::Script::post };
     };
 
     tie %PLP::Script::header, 'PLP::Tie::Headers';
@@ -66,3 +60,61 @@ sub doit {
 
 }
 1;
+
+=head1 NAME
+
+PLP::Fields - Special hashes for PLP
+
+=head1 DESCRIPTION
+
+For your convenience, PLP uses hashes to put things in. Some of these are tied
+hashes, so they contain a bit magic. For example, building the hash can be
+delayed until you actually use the hash.
+
+=over 10
+
+=item C<%get> and C<%post>
+
+These are built from the C<key=value&key=value> (or C<key=value;key=value>
+strings in query string and post content. C<%post> is not built if the content
+type is not C<application/x-www-form-urlencoded>. In post content, the
+semi-colon is not a valid separator.
+
+These hashes aren't built until they are used, to speed up your script if you
+don't use them. Because POST content can only be read once, you can C<use CGI;>
+and just never access C<%post> to avoid its building.
+
+With a query string of C<key=firstvalue&key=secondvalue>, C<$get{key}> will
+contain only C<secondvalue>. You can access both elements by using the array
+reference C<$get{'@key'}>, which will contain C<[ 'firstvalue', 'secondvalue'
+]>.
+
+=item C<%fields>
+
+This hash combines %get and %post, and triggers creation of both. POST gets
+precedence over GET (note: not even the C<@>-keys contain both values).
+
+=item C<%cookie>, C<%cookies>
+
+This is built immediately, because cookies are usually short in length. Cookies
+are not automatically url-decoded.
+
+=item C<%header>, C<%headers>
+
+In this hash, you can set headers. Underscores are converted to normal minus
+signs, so you can leave out quotes. The hash is case insensitive: the case used
+when sending the headers is the one you used first. The following are equal:
+
+    $header{CONTENT_TYPE}
+    $header{'Content-Type'}
+    $header{Content_Type}
+    $headers{CONTENT_type}
+
+=back
+
+=head1 AUTHOR
+
+Juerd Waalboer <juerd@juerd.nl>
+
+=cut
+
index e07caa5846deaa696c96efe2902f26aca5f31108..61d145dbc2e2948c520f655cc2f32d922bb0810c 100644 (file)
@@ -2,6 +2,7 @@
   package PLP::Functions;
 #-------------------------#
 use base 'Exporter';
+use Fcntl qw(:flock);
 use strict;
 
 our @EXPORT = qw/HiddenFields Entity DecodeURI EncodeURI Entity include PLP_END
@@ -114,34 +115,45 @@ sub AddCookie ($) {
 }
 
 sub ReadFile ($) {
-    local *READFILE;
     local $/ = undef;
-    open (READFILE, '<', $_[0]);
-    my $r = <READFILE>;
-    close READFILE;
+    open (my $fh, '<', $_[0]) or do {
+       PLP::error("Cannot open $_[0] for reading ($!)", 1);
+       return undef;
+    };
+    my $r = readline $fh;
+    close $fh;
     return $r;
 }
 
 sub WriteFile ($$) {
-    local *WRITEFILE;
-    open (WRITEFILE, '>', $_[0]);
-    flock WRITEFILE, 2;
-    print WRITEFILE $_[1];
-    close WRITEFILE;
+    open (my $fh, '>', $_[0]) or do {
+       PLP::error("Cannot open $_[0] for writing ($!)", 1);
+       return undef;
+    };
+    flock $fh, LOCK_EX;
+    print $fh $_[1] or do {
+       PLP::error("Cannot write to $_[0] ($!)");
+       return undef;
+    };
+    close $fh or do {
+       PLP::error("Cannot close $_[0] ($!)");
+       return undef;
+    };
+    return 1;
 }
 
 sub Counter ($) {
-    local *COUNTER;
     local $/ = undef;
-    open           COUNTER, '+<', $_[0] or
-    open          COUNTER, '>',  $_[0] or return undef;
-    flock          COUNTER, 2;
-    seek           COUNTER, 0, 0;
-    my $counter = <COUNTER>;
-    seek           COUNTER, 0, 0;
-    truncate       COUNTER, 0;
-    print          COUNTER ++$counter;
-    close          COUNTER;
+    my             $fh;
+    open           $fh, '+<', $_[0] or
+    open          $fh, '>',  $_[0] or return undef;
+    flock          $fh, 2;
+    seek           $fh, 0, 0;
+    my $counter = <$fh>;
+    seek           $fh, 0, 0;
+    truncate       $fh, 0;
+    print          $fh ++$counter   or return undef;
+    close          $fh              or return undef;
     return $counter;
 }
 
@@ -177,5 +189,105 @@ sub AutoURL ($) {
     return defined wantarray ? $$ref : undef;
 }
 
-
 1;
+
+=head1 NAME
+
+PLP::Functions - Functions that are available in PLP documents
+
+=head1 DESCRIPTION
+
+The functions are exported into the PLP::Script package that is used by PLP documents. Although uppercased letters are unusual in Perl, they were chosen to stand out.
+
+Most of these functions are context-hybird. Before using them, one should know about contexts in Perl. The three major contexts are: B<void>, B<scalar> and B<list> context. You'll find more about context in L<perlfunc>.
+
+Some context examples:
+
+    print foo();  # foo is in list context (print LIST)
+    foo();        # foo is in void context
+    $bar = foo(); # foo is in scalar context
+    @bar = foo(); # foo is in list context
+    length foo(); # foo is in scalar context (length EXPR)
+
+=head2 The functions
+
+=over 10
+
+=item Include FILENAME
+
+Executes another PLP file, that will be parsed (i.e. code must be in C<< <: :> >>). As with Perl's C<do>, the file is evaluated in its own lexical file scope, so lexical variables (C<my> variables) are not shared. PLP's C<< <(filename)> >> includes at compile-time, is faster and is doesn't create a lexical scope (it shares lexical variables).
+
+=item include FILENAME
+
+An alias for C<Include>.
+
+=item PLP_END BLOCK
+
+Adds a piece of code that is executed when at the end of the PLP document. This is useful when creating a template file:
+
+    <html><body>       <!-- this is template.plp -->
+    <: PLP_END { :>
+    </body></html>
+    <: } :>
+
+    <(template.plp)>   <!-- this is index.plp -->
+    Hello, world!
+
+You should use this function instead of Perl's built-in C<END> blocks, because those do not work properly with mod_perl.
+
+=item Entity LIST
+
+Replaces HTML syntax characters by HTML entities, so they can be displayed literally. You should always use this on user input (or database output), to avoid cross-site-scripting vurnerabilities. This function does not do everything the L<HTML::Entity> does.
+
+In void context, B<changes> the values of the given variables. In other contexts, returns the changed versions.
+
+    <: print Entity($user_input); :>
+
+=item EncodeURI LIST
+
+Replaces characters by their %-encoded values.
+
+In void context, B<changes> the values of the given variables. In other contexts, returns the changed versions.
+
+    <a href="/foo.plp?name=<:= EncodeURI($name) :>">Link</a>
+
+=item DecodeURI LIST
+
+Decodes %-encoded strings.
+
+In void context, B<changes> the values of the given variables. In other contexts, returns the changed versions.
+
+=item ReadFile FILENAME
+
+Returns the contents of FILENAME in one large string. Returns undef on failure.
+
+=item WriteFile FILENAME, STRING
+
+Writes STRING to FILENAME (overwrites FILENAME if it already exists). Returns true on success, false on failure.
+
+=item Counter FILENAME
+
+Increases the contents of FILENAME by one and returns the new value. Returns undef on failure. Fails silently.
+
+    You are visitor number <:= Counter('counter.txt') :>.
+
+=item AutoURL STRING
+
+Replaces URLs (actually, replace things that look like URLs) by links.
+
+In void context, B<changes> the value of the given variable. In other contexts, returns the changed version.
+
+    <: print AutoURL(Entity($user_input)); :>
+
+=item AddCookie STRING
+
+Adds a Set-Cookie header. STRING must be a valid Set-Cookie header value.
+
+=back
+
+=head1 AUTHOR
+
+Juerd Waalboer <juerd@juerd.nl>
+
+=cut
+
index 267b6204b0c6363fda746528c6f2f1cf81380e22..ea136b83091c835f00fbf86144d9e01f50573db1 100644 (file)
@@ -17,55 +17,55 @@ This module is part of the PLP internals and probably not of any use to others.
 
 sub _replace {
     my ($self) = @_;
-    untie %{$self->[0]};
-    %{$self->[0]} = %{ $self->[1]->() };
+    untie %{ $self->[0] };
+    %{ $self->[0] } = %{ $self->[1]->() };
 }
 
 sub TIEHASH {
     my ($class, $hash, $source) = @_;
-    return bless [$hash, $source], $class;
+    return bless [ $hash, $source ], $class;
 }
 
 sub FETCH {
     my ($self, $key) = @_;
     $self->_replace;
-    return ${$self->[0]}{$key};
+    return ${ $self->[0] }{$key};
 }
 
 sub STORE {
     my ($self, $key, $value) = @_;
     $self->_replace;
-    return ${$self->[0]}{$key} = $value;
+    return ${ $self->[0] }{$key} = $value;
 }
 
 sub DELETE {
     my ($self, $key) = @_;
     $self->_replace;
-    return delete ${$self->[0]}{key};
+    return delete ${ $self->[0] }{$key};
 }
 
 sub CLEAR {
     my ($self) = @_;
     $self->_replace;
-    return %{$self->[0]};
+    return %{ $self->[0] };
 }
 
 sub EXISTS {
     my ($self, $key) = @_;
     $self->_replace;
-    return exists ${$self->[0]}{key};
+    return exists ${ $self->[0] }{$key};
 }
 
 sub FIRSTKEY {
     my ($self) = @_;
     $self->_replace;
-    return exists ${$self->[0]}{key};
+    return 'PLPdummy';
 }
 
 sub NEXTKEY {
     my ($self) = @_;
-    $self->_replace;
-    return each %$$self;
+    # Let's hope this never happens. (It's shouldn't.)
+    return undef;
 }
 
 sub UNTIE   { }
diff --git a/plp.vim b/plp.vim
new file mode 100644 (file)
index 0000000..31b55c1
--- /dev/null
+++ b/plp.vim
@@ -0,0 +1,39 @@
+" Vim syntax file
+" Language:    PLP (Perl in HTML)
+" Maintainer:  Juerd <juerd@juerd.nl>
+" Last Change: 2002 May 19
+" Cloned From: aspperl.vim
+
+" Add to filetype.vim the following line (without quote sign):
+" au BufNewFile,BufRead *.plp setf plp
+
+" For version 5.x: Clear all syntax items
+" For version 6.x: Quit when a syntax file was already loaded
+if version < 600
+  syntax clear
+elseif exists("b:current_syntax")
+  finish
+endif
+
+if !exists("main_syntax")
+  let main_syntax = 'perlscript'
+endif
+
+if version < 600
+  so <sfile>:p:h/html.vim
+  syn include @PLPPerlScript <sfile>:p:h/perl.vim
+else
+  runtime! syntax/html.vim
+  unlet b:current_syntax
+  syn include @PLPPerlScript syntax/perl.vim
+endif
+
+syn cluster htmlPreproc add=PLPPerlScriptInsideHtmlTags
+
+syn region  PLPPerlScriptInsideHtmlTags keepend matchgroup=Delimiter start=+<:=\=+ end=+:>+ contains=@PLPPerlScript
+
+syn cluster htmlPreproc add=PLPIncludeTag
+
+syn region  PLPIncludeTag keepend matchgroup=Delimiter start=+<(+ end=+)>+ contains=@PLPIncludeFilename
+
+let b:current_syntax = "plp"