On 2001-05-10, 20:02:00 (-0700), Doug MacEachern wrote:
> 
> thanks for the patch!  however, Apache::Registry no longer accepts new
> features.  have you looked at Apache::{PerlRun,RegistryNG} ?

No I hadn't - but now I have.  Much nicer code - why hasn't it replaced
Apache::Registry?  Is there any reason I shouldn't run it on my server?

> you would just need to create a new subclass that overrides the
> 'readscript' method and modifies it according to your algorithm.
> if you get that going would be great to post here and/or cpan.

Ok, attached is my proposition for "Apache::RegistryPretty", which
is an improvement over Apache::Registry as long as the input code is
"pretty".  :-)  I subclassed Apache::RegistryNG and wrote a 
replacement for the sub_wrap routine (modifying readscript wouldn't
have worked).

This time I documented it.  If you like the code, would you please
take care of submitting it to "the right place" for me, since I 
haven't a clue about CPAN submission rules?

Thanks!

-- 
Bjarni R. Einarsson                           PGP: 02764305, B7A3AB89
 [EMAIL PROTECTED]                -><-              http://bre.klaki.net/

Check out my open-source email sanitizer: http://mailtools.anomy.net/
package Apache::RegistryPretty;

use Apache::RegistryNG ();
use Apache::Constants qw(:common);
use strict;
use vars qw($VERSION @ISA);
$VERSION = '1.00';
@ISA = qw(Apache::RegistryNG);

#OO replacement for Apache::Registry
#configure like so:
# <Location /perl>
# SetHandler perl-script
# PerlHandler Apache::RegistryPretty->handler
# Options +ExecCGI
# </Location>
# see also: Apache::RegistryBB
 
sub sub_wrap {
    my($pr, $code, $package) = @_;

    $code    ||= $pr->{'code'};
    $package ||= $pr->{'namespace'};

    my ($script, $vars, $subs) = parse_pretty_code($$code);

    my $line = $pr->mark_line;
    my $sub = join(
                   '',
                   'package ',
                   $package,
                   ";\nuse Apache qw(exit);\n",
                   $vars,
                   "sub handler {\n",
                   $line,
                   $script,
                   "\n}\n",
                   $subs # last line comment without newline?
                   );
    $pr->{'sub'} = \$sub;
}

sub parse_pretty_code
{
    my $script = shift;
    my $subs = "";
    my $vars = "";
    
    # Comments just get in the way, kill'em.
    $script =~ s/^#.*$//mg;
    $script =~ s/\n+/\n/sg;
    $script = "1;\n".$script;

    while ($script =~ s/([;}]\s*\n)(sub\s*)([a-z0-9_]+)(\s*{.*?\n}\s*)/$1/si)
    {
        $subs .= $2.$3.$4;
    }

    while ($script =~ s/([;}]\s*)(use\s+[^;]+;\s*)/$1/si)
    {
        $vars .= $2;
    }
    while ($script =~ s/([;}]\s*)(my\s+|local\s+)([\$\@\%\*a-zA-Z_]+|\([^\)]+\))/$1 
$3/si)
    {
        $vars .= $2.$3.";\n";
    }

    return ($script, $vars, $subs);
}

1;

__END__

=head1 NAME

Apache::RegistryPretty - Run unaltered CGI scrips under mod_perl

=head1 SYNOPSIS

 #in httpd.conf

 Alias /perl/ /perl/apache/scripts/ #optional
 PerlModule Apache::RegistryPretty

 <Location /perl>
 SetHandler perl-script
 PerlHandler Apache::RegistryPretty
 Options ExecCGI 
 ...
 </Directory>

=head1 DESCRIPTION

This is a specialization of the B<Apache::RegistryNG> module, which is a
replacement for B<Apache::Registry>.  Most of the documentation for
B<Apache::Registry> applies to this module as well.

The main difference is that this module avoids some of the more onerous
limitations B<Apache::Registry> placed on medium-sized perl scripts which
have subroutines.  With B<Apache::Registry> subroutines would often
incorrectly "remember" variable values between invokations due to them
getting treated as closures by the Perl interpretor (see the B<perlsub>
and B<perlref> man pages for more info).

B<Apache::RegistryPretty> avoids this by attempting to recognize global
variables, package inclusions (use statements) and top level
subroutines.  The recognition makes assumptions about programming style
and use of white space - so it does a better job than B<Apache::Registry> 
with "pretty" perl programs.  Thus the name.

Global variables are expected be defined with "my" or "local".  Their
definitions are stored globally within the generated packages, but
their initialization is postponed and performed within the
auto-generated handler subroutine.

Subroutines begin with a subroutine definition (e.g. "B<sub foo {>")
starting in the first column of the file, and end with a lone curly
bracket ("B<}>"), also in the first column.  Any subroutines that match
these will be implemented in such a fashion that they don't exhibit the
time-warp behavior associated with the original B<Apache::Registry>.

=head1 CAVEATS

See the B<Apache::Registry> documentation.

=head1 INTERNALS

The translations performed by B<Apache::RegistryPretty> are very simple, 
and are probably best illustrated by an example:

   use MIME::Base64; 
   sub foo
   {
      return decode_base64(shift);
   }
   sub bar
   {
      return encode_base64(shift);
   } 
   my $bogus = time();
   print foo(bar("whee")), $bogus, "\n";

Becomes something like this:

   package SomePackage;
   use Apache qw(exit);
   use MIME::Base64;
   my $bogus; 
   sub handler {
      1;
      $bogus = time();
      print foo(bar("whee")), $bogus, "\n";
   }
   sub foo
   {
      return decode_base64(shift);
   }
   sub bar
   {
      return encode_base64(shift);
   }

The handler routine is then called as necessary by B<Apache::RegistryPretty> 
from within an environment that looks enough like a CGI environment to fool
most scripts.

=head1 SEE ALSO

perl(1), mod_perl(3), Apache(3), Apache::Debug(3), Apache::Registry(3)

=head1 AUTHORS

Bjarni Rúnar Einarsson <B<[EMAIL PROTECTED]>>

#!/usr/bin/perl -w
#
# This is a simple hack for testing the routines in 
# Apache::RegistryPretty.  To run it without actually installing
# the RegistryPretty script, do the following:
#
#   mkdir xyz
#   cp RegistryPretty.pm transform.pl xyz/
#   cd xyz
#   ln -s . Apache
#   ./transform.pl </path/to/a/script.pl |less
#
# You do need to have mod_perl installed though.
#
# Incidentally, if the output looks nice you can actually 
# use it as a first draft of a mod_perl version of your 
# script and forget about Apache::Registry etc. altogether.
#
package test;
BEGIN { push @INC, "."; }
use strict;
use Apache::RegistryPretty;

my $func = join('', <>);

my $pr = { 'code' => \$func, 'namespace' => "SomePackage" };
bless($pr);

Apache::RegistryPretty::sub_wrap($pr);

print ${ $pr->{'sub'} };

sub mark_line 
{
    return "";
}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to