rongoral has asked for the wisdom of the Perl Monks concerning the following question:

Greetings Wise Ones of Perl -

I have arrived at the end of my rope (a very short one probably) trying to find an answer to the conundrum I've encountered. It involves parsing files, printing what is found and even executing "embedded" anonymous subs.

I am parsing two files to create a single .html page. The first is a template containing a header, navigation and a footer, while the second contains the content of the page. I have a script that reads in the template and, when it encounters <!-- Begin main body block -->, opens the second file and recursively reads it into the space between <!-- Begin main body block --> and <!-- End main body block -->. This works very well.

While parsing these files, it is possible to encounter another commented block which contains an anonymous subroutine. The code snippet to locate the perl code looks like this:

UPDATE -

As I noted in my response to davidrw, I did do something incredibly stupid while trying to be smart. I was using the shebang line of #!/usr/bin/perl -wT and not untainting the code I was reading in from the other files.

@*&^ newbies !!!

if (m/\<!-- Begin Perl Block --\>/i) { my $perlcode = ''; # Pull in all the perl code while (<PAGE>) { # This is the end of the block last if m/\<!-- End Perl Block --\>/i; $perlcode .= $_; } # Execute the anonymous sub $_ = &{eval $perlcode;}; }

The portion to be parsed may look something like:

<!-- Begin Perl Block --> sub { $text = ''; if ($h_self{form_data}{page} =~ /confirmation|application/i) { $text .= qq[<style type="text/css"> body {font-size: 8pt;font-family: Arial, Helvetica;} table {font-size: 8pt;font-family: Arial, Helvetica;} tr {font-size: 8pt;font-family: Arial, Helvetica;} td {font-size: 8pt;font-family: Arial, Helvetica;} select {font-size: 8pt;font-family: Arial, Helvetica;} input {font-size: 8pt;font-family: Arial, Helvetica;} form {font-size: 8pt;font-family: Arial, Helvetica;} div {font-size: 8pt;font-family: Arial, Helvetica;} p {font-size: 8pt;font-family: Arial, Helvetica;} .red {font-weight: bold;font-size: 10pt;color: red;text-align:right;} .black {font-weight: bold;font-size: 10pt;color: black;text-align:righ +t;} .backfill {background-color:003399;text-align:center;color:white;font- +weight:bold;border: 1px solid white;} .cell {border: 1px solid white;} .edit {width: 50;} </style>]; } return $text; } <!-- End Perl Block -->
As you can see, this portion of HTML code would be inserted into the web page if $h_self{form_data}{page} has a particular value. This is where I am having difficulty. I've found that the '<' in front of <style> and </style> are causing everything between to be ignored. I have tried to escape them with '\' and '\\' and '\\\', but to no avail(Yes the final measure was desperate).

With the left-angle brackets in, I get a result of:

sub { $text = ''; if ($h_self{form_data}{page} =~ /confirmation|application/i) { $text .= qq[]; } return $text; }
But, if I remove them, I get:
sub { $text = ''; if ($h_self{form_data}{page} =~ /confirmation|application/i) { $text .= qq[style type="text/css"> body {font-size: 8pt;font-family: Arial, Helvetica;} table {font-size: 8pt;font-family: Arial, Helvetica;} tr {font-size: 8pt;font-family: Arial, Helvetica;} td {font-size: 8pt;font-family: Arial, Helvetica;} select {font-size: 8pt;font-family: Arial, Helvetica;} input {font-size: 8pt;font-family: Arial, Helvetica;} form {font-size: 8pt;font-family: Arial, Helvetica;} div {font-size: 8pt;font-family: Arial, Helvetica;} p {font-size: 8pt;font-family: Arial, Helvetica;} .red {font-weight: bold;font-size: 10pt;color: red;text-align:right;} .black {font-weight: bold;font-size: 10pt;color: black;text-align:righ +t;} .backfill {background-color:003399;text-align:center;color:white;font- +weight:bold;border: 1px solid white;} .cell {border: 1px solid white;} .edit {width: 50;} /style>]; } return $text; }

So, my question is two-fold:

1. Why does the left-angle bracket cause this behavior? and

2. How do I get around it?

UPDATE

1. The left-angle bracket doesn't cause this behavior! and

2. I get around it by paying closer attention to the pragmas I'm using!!

Please help. me find my backside

In humble supplication - (sorry to have wasted your time, but thank you so much for the help.)

Ron

READMORE tags added by Arunbear

Replies are listed 'Best First'.
Re: < Woes
by davidrw (Prior) on Jul 03, 2005 at 13:24 UTC
    First, I have to ask why (maybe there's a reason e.g. legacy, install/enviroment issues, etc) you're going with this home grown solution and not Template::Toolkit or Mason which both support include files and embedded perl.

    As for the < causing problems, that's curious.. First thought of a work-around is to use a here-doc instead of qq[].

    For the explaination I think that this perldoc perlop snippet holds the answer (hopefully someone more knowledgeable of qq[] can elaborate):

       Finding the end
       The first pass is finding the end of the quoted construct, whether it be a multicharacter delimiter
        ""\nEOF\n"" in the "<<EOF" construct, a "/" that terminates a "qq//" construct, a "]" which terminates
        "qq[]" construct, or a ">" which terminates a fileglob started with "<".


    Update: I'm having troubling reproducing the error -- do you have a simple test case (e.g. one that reads from <DATA>)? The following script works for me:

      Your bit of code works exactly as I would like mine to. =( I've put it into an executable and it does what I expect. However, if I gut the function in the original cgi script and put your code in, it fails. In fact, nothing is printed after the eval statement.

      I have found, however, that if I substitute &lt; for < in the file and then s/\&lt;/\</g; after it is pulled out, the text will then take the form that I want. Now, though as I stated above, I find that the real failure is in the eval portion. But, I cannot pull out the reason using $@. I think that it fails, but it will not say why.

      I am not using Template::Toolkit or the like because I don't know what is going to be on a particular server. I am usually writing code for people who are paying to be hosted on someone's server and I cannot always be sure what is and is not installed there. Likewise, I don't have access to SSH their sites. So, I try to keep it as "pure" as possible. Of course, as anyone will correctly point out, this means that I have to wade through my own errors before the code becomes fit for consumption.

      I must be doing something incredibly stupid. But, I can't see it.

Re: < Woes
by polettix (Vicar) on Jul 03, 2005 at 16:36 UTC
    Where are you printing exactly the results you get? If you're doing that in the browser, it's likely that it will not show them to you.

    Flavio
    perl -ple'$_=reverse' <<<ti.xittelop@oivalf

    Don't fool yourself.
Re: < Woes
by TedPride (Priest) on Jul 03, 2005 at 17:50 UTC
    I don't really see where your code is going wrong, since I don't understand what's wrong about the output, but the following may work better:
    $h_self{form_data}{page} = 'confirmation'; while (<DATA>) { if (m/\<!-- Begin Perl Block --\>/i) { my $perlcode = ''; $perlcode .= $_ while ($_ = <DATA>) && !m/\<!-- End Perl Block + --\>/i; $_ = &{eval $perlcode;}; print; } } __DATA__ <!-- Begin Perl Block --> sub { my $text = ''; if ($h_self{form_data}{page} =~ /confirmation|application/i) { $text = <<OUT; <style type="text/css"> body {font-size: 8pt;font-family: Arial, Helvetica;} table {font-size: 8pt;font-family: Arial, Helvetica;} tr {font-size: 8pt;font-family: Arial, Helvetica;} td {font-size: 8pt;font-family: Arial, Helvetica;} select {font-size: 8pt;font-family: Arial, Helvetica;} input {font-size: 8pt;font-family: Arial, Helvetica;} form {font-size: 8pt;font-family: Arial, Helvetica;} div {font-size: 8pt;font-family: Arial, Helvetica;} p {font-size: 8pt;font-family: Arial, Helvetica;} .red {font-weight: bold;font-size: 10pt;color: red;text-align:right;} .black {font-weight: bold;font-size: 10pt;color: black;text-align:righ +t;} .backfill {background-color:003399;text-align:center;color:white;font- +weight:bold;border: 1px solid white;} .cell {border: 1px solid white;} .edit {width: 50;} </style> OUT # To remove trailing whitespace caused by using <<OUT chomp $text; } return $text; } <!-- End Perl Block -->
    However, you'd be much better off putting your test in the start tag, evaling that, then skipping to the end tag if the test returns 0. This way you don't have to eval anything except the test.