here is some initial Apache-Registry subproject.

There are quite a few issues to resolve, but the basic things work. Need
to write the loader though.

If you want to look at the code look at Apache/RegistryCooker.pm first,
and then on any of (Registry(|BB|BG)|PerlRun).pm

--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/lib/Apache/Registry.pm      Mon Oct  8 16:59:55 2001
@@ -0,0 +1,84 @@
+package Apache::Registry;
+
+use strict;
+use warnings FATAL => 'all';
+
+# we try to develop so we reload ourselves without die'ing on the warning
+no warnings qw(redefine); # XXX, this should go away in production!
+
+$Apache::Registry::VERSION = '1.99_01';
+
+use Apache::RegistryCooker;
+@Apache::Registry::ISA = qw(Apache::RegistryCooker);
+
+sub handler {
+    my $class = (@_ >= 2) ? shift : __PACKAGE__;
+    my $r = shift;
+    return $class->new($r)->default_handler();
+}
+
+my $parent = 'Apache::RegistryCooker';
+# the following code:
+# - specifies package's behavior different from default of $parent class
+# - speeds things up by shortcutting @ISA search, so even if the
+#   default is used we still use the alias
+my %aliases = (
+     new             => 'new',
+     init            => 'init',
+     default_handler => 'default_handler',
+     run             => 'run',
+     can_compile     => 'can_compile',
+     make_namespace  => 'make_namespace',
+     namespace_from  => 'namespace_from_filename',
+     is_cached       => 'is_cached',
+     should_compile  => 'should_compile_if_modified',
+     flush_namespace => 'NOP',
+     cache_it        => 'cache_it',
+     read_script     => 'read_script',
+     rewrite_shebang => 'rewrite_shebang',
+     set_script_name => 'set_script_name',
+     chdir_file      => 'chdir_file_normal',
+     get_mark_line   => 'get_mark_line',
+     compile         => 'compile',
+     error_check     => 'error_check',
+     strip_end_data_segment             => 'strip_end_data_segment',
+     convert_script_to_compiled_handler => 'convert_script_to_compiled_handler',
+    );
+
+# in this module, all the methods are inherited from the same parent
+# class, so we fixup aliases instead of using the source package in
+# first place.
+$aliases{$_} = $parent . "::" . $aliases{$_} for keys %aliases;
+
+__PACKAGE__->install_aliases(\%aliases);
+
+# Note that you don't have to do the aliases if you use defaults, it
+# just speeds things up the first time the sub runs, after that
+# methods are cached.
+#
+# But it's still handy, since you explicitly specify which subs from
+# the parent package you are using
+#
+
+# META: if the ISA search results are cached on the first lookup, may
+# be need to alias only the those that aren't the defaults?
+
+
+1;
+__END__
+
+
+=head1 NAME
+
+Apache::Registry -
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/lib/Apache/PerlRun.pm       Mon Oct  8 16:57:00 2001
@@ -0,0 +1,77 @@
+package Apache::PerlRun;
+
+use strict;
+use warnings FATAL => 'all';
+
+# we try to develop so we reload ourselves without die'ing on the warning
+no warnings qw(redefine); # XXX, this should go away in production!
+
+$Apache::PerlRun::VERSION = '1.99_01';
+
+use Apache::RegistryCooker;
+@Apache::PerlRun::ISA = qw(Apache::RegistryCooker);
+
+# META: prototyping ($$) segfaults on request
+sub handler {
+    my $class = (@_ >= 2) ? shift : __PACKAGE__;
+    my $r = shift;
+    return $class->new($r)->default_handler();
+}
+
+my $parent = 'Apache::RegistryCooker';
+# the following code:
+# - specifies package's behavior different from default of $parent class
+# - speeds things up by shortcutting @ISA search, so even if the
+#   default is used we still use the alias
+my %aliases = (
+     new             => 'new',
+     init            => 'init',
+     default_handler => 'default_handler',
+     run             => 'run',
+     can_compile     => 'can_compile',
+     make_namespace  => 'make_namespace',
+     namespace_from  => 'namespace_from_filename',
+     is_cached       => 'FALSE',
+     should_compile  => 'TRUE',
+     flush_namespace => 'flush_namespace_normal',
+     cache_it        => 'NOP',
+     read_script     => 'read_script',
+     rewrite_shebang => 'rewrite_shebang',
+     set_script_name => 'set_script_name',
+     chdir_file      => 'chdir_file_normal',
+     get_mark_line   => 'get_mark_line',
+     compile         => 'compile',
+     error_check     => 'error_check',
+     strip_end_data_segment             => 'strip_end_data_segment',
+     convert_script_to_compiled_handler => 'convert_script_to_compiled_handler',
+    );
+
+# in this module, all the methods are inherited from the same parent
+# class, so we fixup aliases instead of using the source package in
+# first place.
+$aliases{$_} = $parent . "::" . $aliases{$_} for keys %aliases;
+
+__PACKAGE__->install_aliases(\%aliases);
+
+
+
+
+
+1;
+__END__
+
+
+=head1 NAME
+
+Apache::PerlRun -
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/lib/Apache/RegistryLoader.pm        Tue Oct  9 00:51:47 2001
@@ -0,0 +1,11 @@
+package Apache::RegistryLoader;
+
+# should think about a few loader packages where each package
+# corresponds to its run-time registry package
+
+# or should it be a single package that accepts the desired driver as
+# an argument?
+
+
+1;
+__END__
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/lib/Apache/RegistryNG.pm    Mon Oct  8 16:57:00 2001
@@ -0,0 +1,27 @@
+package Apache::RegistryNG;
+
+# a back-compatibility placeholder
+*Apache::RegistryNG:: = \*Apache::Registry::;
+
+# META: prototyping ($$) segfaults on request
+sub handler {
+    my $class = (@_ >= 2) ? shift : __PACKAGE__;
+    my $r = shift;
+    return $class->new($r)->default_handler();
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Apache::RegistryNG -- See Apache::Registry
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+C<Apache::RegistryNG> is the same as C<Apache::Registry>.
+
+=cut
+
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/lib/Apache/RegistryBB.pm    Mon Oct  8 16:57:00 2001
@@ -0,0 +1,40 @@
+package Apache::RegistryBB;
+
+use strict;
+use warnings FATAL => 'all';
+
+# we try to develop so we reload ourselves without die'ing on the warning
+no warnings qw(redefine); # XXX, this should go away in production!
+
+$Apache::RegistryBB::VERSION = '1.99_01';
+
+use Apache::RegistryCooker;
+@Apache::RegistryBB::ISA = qw(Apache::RegistryCooker);
+
+# META: prototyping ($$) segfaults on request
+sub handler {
+    my $class = (@_ >= 2) ? shift : __PACKAGE__;
+    my $r = shift;
+    return $class->new($r)->default_handler();
+}
+
+# currently all the methods are inherited through the normal ISA
+# search may
+
+1;
+__END__
+
+
+=head1 NAME
+
+Apache::RegistryBB -
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+C<Apache::RegistryBB> uses all the defaults, which do the very minimum
+to compile the file once and run it many times.
+
+=cut
+
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/lib/Apache/RegistryCooker.pm        Tue Oct  9 01:32:12 2001
@@ -0,0 +1,719 @@
+# VERY IMPORTANT: Be very careful modifying the defaults, since many
+# VERY IMPORTANT: packages rely on them. In fact you should never
+# VERY IMPORTANT: modify the defaults after the package gets released,
+# VERY IMPORTANT: since they are a hardcoded part of this suite's API.
+
+package Apache::RegistryCooker;
+
+use strict;
+use warnings FATAL => 'all';
+
+# we try to develop so we reload ourselves without die'ing on the warning
+no warnings qw(redefine); # XXX, this should go away in production!
+
+# META: do we need this? I think we 'require 5.6.0'
+#BEGIN {
+#    if ($] < 5.006) {
+#        $INC{'warnings.pm'} = __FILE__;
+#        *warnings::unimport = sub {};
+#    }
+#}
+
+$Apache::RegistryCooker::VERSION = '1.99';
+
+use Apache::compat ();
+# Should not use Apache::compat, the following methods need to be implemented
+# $r->slurp_filename
+# Apache->untaint
+# $r->clear_rgy_endav
+# $r->stash_rgy_endav
+
+use Apache::Response;
+use Apache::Log;
+use Apache::Const -compile => qw(:common &OPT_EXECCGI);
+use File::Spec::Functions ();
+
+#########################################################################
+# issues
+#
+#########################################################################
+
+# META: who sets this? What's the default?
+unless (defined $Apache::Registry::MarkLine) {
+    $Apache::Registry::MarkLine = 1;
+}
+
+### Optimizations
+#
+# - $o->[CLASS] of the subclass is known at compile time, so should
+#   create the subs using $o->[CLASS] on the fly for each subclass
+#   which wants them
+
+### TODO
+#
+# - who handles END/BEGIN/,CHECK,INIT) blocks?
+# - see META's accross the file
+
+#########################################################################
+# debug flag constants
+#
+#########################################################################
+use constant D_ERROR   => 1;
+use constant D_WARN    => 2;
+use constant D_COMPILE => 4;
+use constant D_NOISE   => 8;
+
+# use Apache::RegistryCooker::DEBUG constant if defined elsewhere
+# before the compilation of this package: D_NOISE devel mode (prod==0)
+use constant DEBUG => Apache::RegistryCooker->can('DEBUG') || D_NOISE;
+
+#########################################################################
+# object's array index's access constants
+#
+#########################################################################
+use constant REQ       => 0;
+use constant FILENAME  => 1;
+use constant URI       => 2;
+use constant MTIME     => 3;
+use constant PACKAGE   => 4;
+use constant CODE      => 5;
+use constant STATUS    => 6;
+use constant CLASS     => 7;
+
+#########################################################################
+# OS specific constants
+#
+#########################################################################
+use constant IS_WIN32 => $^O eq "MSWin32";
+
+#########################################################################
+# constant subs
+#
+#########################################################################
+use constant NOP   => sub {   };
+use constant TRUE  => sub { 1 };
+use constant FALSE => sub { 0 };
+
+
+#########################################################################
+# install the aliases into $class
+#
+#########################################################################
+
+sub install_aliases {
+    my ($class, $rh_aliases) = @_;
+
+    no strict 'refs';
+    while (my($k,$v) = each %$rh_aliases) {
+        if (my $sub = *{$v}{CODE}){
+            #warn "$class: ok: $k => $v";
+            *{$class."::$k"} = $sub;
+        }
+        else {
+            die "$class: $k aliasing failed; sub $v doesn't exist";
+        }
+    }
+}
+
+#########################################################################
+# func: new
+# dflt: new
+# args: $class - class to bless into
+#       $r     - Apache::Request object
+# desc: create the class's object and bless it
+# rtrn: the newly created object
+#########################################################################
+
+sub new {
+    my($class, $r) = @_;
+    my $o = bless [], $class;
+    $o->init($r);
+    #$r->log_error("$$: init class: $class");
+    return $o;
+}
+
+#########################################################################
+# func: init
+# dflt: init
+# desc: initializes the data object's fields: CLASS REQ FILENAME URI
+# args: $r - Apache::Request object
+# rtrn: nothing
+#########################################################################
+
+sub init {
+    $_[0]->[CLASS]    = ref $_[0];
+    $_[0]->[REQ]      = $_[1];
+    $_[0]->[URI]      = $_[1]->uri;
+    $_[0]->[FILENAME] = $_[1]->filename;
+}
+
+#########################################################################
+# func: handler
+# dflt: handler
+# desc: the handler() sub that is expected by Apache
+# args: $class - handler's class
+#       $r     - Apache::Request object
+#       (o)can be called as handler($r) as well (without leading $class)
+# rtrn: handler's response status
+# note: must be implemented in a sub-class unless configured as
+#       Apache::Foo->handler in httpd.conf (because of the
+#       __PACKAGE__, which is tied to the file)
+#########################################################################
+
+# META: prototyping ($$) segfaults on request
+sub handler {
+    my $class = (@_ >= 2) ? shift : __PACKAGE__;
+    my $r = shift;
+    $class->new($r)->default_handler();
+}
+
+#########################################################################
+# func: default_handler
+# dflt: META: see above
+# desc: META: see above
+# args: $o - registry blessed object
+# rtrn: handler's response status
+# note: that's what most sub-class handlers will call
+#########################################################################
+
+sub default_handler {
+    my $o = shift;
+
+    $o->make_namespace;
+
+    if ($o->should_compile) {
+        my $rc = $o->can_compile;
+        return $rc unless $rc == Apache::OK;
+        $o->convert_script_to_compiled_handler;
+    }
+
+    return $o->run;
+}
+
+#########################################################################
+# func: run
+# dflt: run
+# desc: executes the compiled code
+# args: $o - registry blessed object
+# rtrn: execution status (Apache::?)
+#########################################################################
+
+sub run {
+    my $o = shift;
+
+    my $r       = $o->[REQ];
+    my $package = $o->[PACKAGE];
+
+    $o->set_script_name;
+    $o->chdir_file;
+
+    my $rc = Apache::OK;
+    my $cv = \&{"$package\::handler"};
+
+    { # run the code, preserve warnings setup when it's done
+        no warnings;
+        eval { $rc = &{$cv}($r, @_) } if $r->seqno;
+        $o->[STATUS] = $rc;
+    }
+
+    $o->flush_namespace;
+
+    my $errsv = "";
+    if ($@) {
+        $errsv = $@;
+        $@ = ''; #XXX fix me, if we don't do this Apache::exit() breaks
+        $@{$r->uri} = $errsv;
+    }
+
+    # META: handle!
+    #$o->chdir_file("$Apache::Server::CWD/");
+
+    if ($errsv) {
+        $r->log_error($errsv);
+        return Apache::SERVER_ERROR;
+    }
+
+    return wantarray ? (Apache::OK, $rc) : Apache::OK;
+}
+
+
+
+#########################################################################
+# func: can_compile
+# dflt: can_compile
+# desc: checks whether the script is allowed and can be compiled
+# args: $o - registry blessed object
+# rtrn: $rc - return status to forward
+# efct: initializes the data object's fields: MTIME
+#########################################################################
+
+sub can_compile {
+    my $o = shift;
+    my $r = $o->[REQ];
+
+    $r->log_error("$$: $o->[CLASS] executing $o->[FILENAME]")
+        if DEBUG & D_NOISE;
+
+    unless (-r $r->finfo && -s _) {
+        $r->log_error("$$: $o->[FILENAME] not found or unable to stat");
+       return Apache::NOT_FOUND;
+    }
+
+    return Apache::DECLINED if -d _;
+
+    $o->[MTIME] = -M _;
+
+    unless (-x _ or IS_WIN32) {
+        $r->log_reason("file permissions deny server execution",
+                       $o->[FILENAME]);
+        return Apache::FORBIDDEN;
+    }
+
+    if (!($r->allow_options & Apache::OPT_EXECCGI)) {
+        $r->log_reason("Options ExecCGI is off in this directory",
+                       $o->[FILENAME]);
+        return Apache::FORBIDDEN;
+    }
+
+    return Apache::OK;
+
+}
+
+#########################################################################
+# func: make_namespace
+# dflt: make_namespace
+# desc: prepares the namespace
+# args: $o - registry blessed object
+# rtrn: the namespace
+# efct: initializes the field: PACKAGE
+#########################################################################
+
+sub make_namespace {
+    my $o = shift;
+
+    my $package = $o->namespace_from;
+
+    # Escape everything into valid perl identifiers
+    $package =~ s/([^A-Za-z0-9_])/sprintf("_%2x", unpack("C", $1))/eg;
+
+    # make sure that the sub-package doesn't start with a digit
+    $package = "_$package";
+
+    # META: ??? explain
+    $Apache::Registry::curstash = $package;
+
+    # prepend root
+    $package = $o->[CLASS] . "::Cache::$package";
+
+    $o->[PACKAGE] = $package;
+
+    return $package;
+}
+
+#########################################################################
+# func: namespace_from
+# dflt: namespace_from_filename
+# desc: returns a partial raw package name based on filename, uri, else
+# args: $o - registry blessed object
+# rtrn: a unique string
+#########################################################################
+
+*namespace_from = \&namespace_from_filename;
+
+# return a package name based on $r->filename only
+sub namespace_from_filename {
+    my $o = shift;
+
+    my ($volume, $dirs, $file) =
+        File::Spec::Functions::splitpath($o->[FILENAME]);
+    my @dirs = File::Spec::Functions::splitdir($dirs);
+    return join '_', ($volume||''), @dirs, $file;
+}
+
+# return a package name based on $r->uri only
+sub namespace_from_uri {
+    my $o = shift;
+
+    my $path_info = $o->[REQ]->path_info;
+    my $script_name = $path_info && $o->[URI] =~ /$path_info$/ ?
+       substr($o->[URI], 0, length($o->[URI]) - length($path_info)) :
+       $o->[URI];
+
+    # META: do we handle this?
+    # if ($Apache::Registry::NameWithVirtualHost && $o->[REQ]->server->is_virtual) {
+    #    my $name = $o->[REQ]->get_server_name;
+    #    $script_name = join "", $name, $script_name if $name;
+    # }
+
+    $script_name =~ s:/+$:/__INDEX__:;
+
+    return $script_name;
+}
+
+#########################################################################
+# func: convert_script_to_compiled_handler
+# dflt: convert_script_to_compiled_handler
+# desc: reads the script, converts into a handler and compiles it
+# args: $o - registry blessed object
+# rtrn: success/failure status
+#########################################################################
+
+sub convert_script_to_compiled_handler {
+    my $o = shift;
+
+    $o->[REQ]->log_error("$$: Adding package $o->[PACKAGE]")
+        if DEBUG & D_NOISE;
+
+    # get the script's source
+    $o->read_script;
+
+    # convert the shebang line opts into perl code
+    $o->rewrite_shebang;
+
+    # mod_cgi compat, should compile the code while in its dir, so
+    # relative require/open will work.
+    $o->chdir_file;
+
+# ???
+#    # compile this subroutine into the uniq package name
+#    $o->[REQ]->log_error("$$: Apache::Registry::handler eval-ing")
+#        if DEBUG & D_NOISE;
+#    undef &{"$o->[PACKAGE]\::handler"};# unless $Debug && $Debug & 4; #avoid warnings
+#    $o->[PACKAGE]->can('undef_functions') && $o->[PACKAGE]->undef_functions;
+
+    my $line = $o->get_mark_line;
+
+    $o->strip_end_data_segment;
+
+    my $eval = join '',
+                    'package ',
+                    $o->[PACKAGE],
+                    ';use Apache qw(exit);',
+                    "sub handler {\n",
+                    $line,
+                    ${ $o->[CODE] },
+                    "\n}"; # last line comment without newline?
+
+    my %orig_inc = %INC;
+
+#warn "[-- $eval --]";
+    my $rc = $o->compile(\$eval);
+    $o->[REQ]->log_error(qq{$$: Compiled package \"$o->[PACKAGE]\"})
+        if DEBUG & D_NOISE;
+
+    # META: handle!
+    #$o->chdir_file("$Apache::Server::CWD/");
+
+    # %INC cleanup
+    #in case .pl files do not declare package ...;
+    for (keys %INC) {
+       next if $orig_inc{$_};
+       next if /\.pm$/;
+       delete $INC{$_};
+    }
+
+# META: $r->child_terminate is not implemented
+#    if(my $opt = $r->dir_config("PerlRunOnce")) {
+#      $r->child_terminate if lc($opt) eq "on";
+#    }
+
+    $o->cache_it;
+
+    return $rc;
+}
+
+#########################################################################
+# func: cache_it
+# dflt: cache_it
+# desc: mark the package as cached by storing its modification time
+# args: $o - registry blessed object
+# rtrn: nothing
+#########################################################################
+
+sub cache_it {
+    my $o = shift;
+    no strict 'refs';
+    ${$o->[CLASS]}->{ $o->[PACKAGE] }{mtime} = $o->[MTIME];
+}
+
+#########################################################################
+# func: is_cached
+# dflt: is_cached
+# desc: checks whether the package is already cached
+# args: $o - registry blessed object
+# rtrn: TRUE if cached,
+#       FALSE otherwise
+#########################################################################
+
+sub is_cached {
+    my $o = shift;
+    no strict 'refs';
+    exists ${$o->[CLASS]}->{ $o->[PACKAGE] }{mtime};
+}
+
+
+#########################################################################
+# func: should_compile
+# dflt: should_compile_once
+# desc: decide whether code should be compiled or not
+# args: $o - registry blessed object
+# rtrn: TRUE if should compile
+#       FALSE otherwise
+# efct: sets MTIME if it's not set yet
+#########################################################################
+
+*should_compile = \&should_compile_once;
+
+# return false only if the package is cached and its source file
+# wasn't modified
+sub should_compile_if_modified {
+    my $o = shift;
+    $o->[MTIME] ||= -M $o->[REQ]->finfo;
+    no strict 'refs';
+    !($o->is_cached &&
+      ${$o->[CLASS]}->{ $o->[PACKAGE] }{mtime} <= $o->[MTIME]);
+}
+
+# return false if the package is cached already
+sub should_compile_once {
+    not shift->is_cached;
+}
+
+#########################################################################
+# func: flush_namespace
+# dflt: NOP (don't flush)
+# desc: flush the compiled package's namespace
+# args: $o - registry blessed object
+# rtrn: nothing
+#########################################################################
+
+*flush_namespace = \&NOP;
+
+sub flush_namespace_normal {
+    my $o = shift;
+
+    $o->[REQ]->log_error("$$: flushing namespace");
+
+    no strict 'refs';
+    my $tab = \%{ $o->[PACKAGE] . '::' };
+
+    for (keys %$tab) {
+        my $fullname = join '::', $o->[PACKAGE], $_;
+        #code/hash/array/scalar might be imported
+        #make sure the gv does not point elsewhere
+        #before undefing each
+        if (%$fullname) {
+            *{$fullname} = {};
+            undef %$fullname;
+        }
+        if (@$fullname) {
+            *{$fullname} = [];
+            undef @$fullname;
+        }
+        if ($$fullname) {
+            my $tmp; #argh, no such thing as an anonymous scalar
+            *{$fullname} = \$tmp;
+            undef $$fullname;
+        }
+        if (defined &$fullname) {
+            no warnings;
+            local $^W = 0;
+            if (my $p = prototype $fullname) {
+                *{$fullname} = eval "sub ($p) {}";
+            }
+            else {
+                *{$fullname} = sub {};
+            }
+           undef &$fullname;
+       }
+        if (*{$fullname}{IO}) {
+            if (fileno $fullname) {
+                close $fullname;
+            }
+        }
+    }
+}
+
+
+#########################################################################
+# func: read_script
+# dflt: read_script
+# desc: reads the script in
+# args: $o - registry blessed object
+# rtrn: nothing
+# efct: initializes the CODE field with the source script
+#########################################################################
+
+# reads the contents of the file
+sub read_script {
+    my $o = shift;
+
+    $o->[REQ]->log_error("$$: $o->[CLASS] reading $o->[FILENAME]")
+        if DEBUG & D_NOISE;
+    $o->[CODE] = $o->[REQ]->slurp_filename;
+}
+
+#########################################################################
+# func: rewrite_shebang
+# dflt: rewrite_shebang
+# desc: parse the shebang line and convert command line switches
+#       (defined in %switches) into a perl code.
+# args: $o - registry blessed object
+# rtrn: nothing
+# efct: the CODE field gets adjusted
+#########################################################################
+
+my %switches = (
+   'T' => sub {
+       Apache::warn("T switch ignored, ".
+                   "enable with 'PerlTaintCheck On'\n")
+          unless $Apache::__T; "";
+   },
+   'w' => sub { "use warnings;\n" },
+);
+
+sub rewrite_shebang {
+    my $o = shift;
+    my($line) = ${ $o->[CODE] } =~ /^(.*)$/m;
+    my @cmdline = split /\s+/, $line;
+    return unless @cmdline;
+    return unless shift(@cmdline) =~ /^\#!/;
+
+    my $prepend = "";
+    for my $s (@cmdline) {
+       next unless $s =~ s/^-//;
+       last if substr($s,0,1) eq "-";
+       for (split //, $s) {
+           next unless exists $switches{$_};
+           #print STDERR "parsed `$_' switch\n";
+           $prepend .= &{$switches{$_}};
+       }
+    }
+    ${ $o->[CODE] } =~ s/^/$prepend/ if $prepend;
+}
+
+#########################################################################
+# func: set_script_name
+# dflt: set_script_name
+# desc: set $0 to the script's name
+# args: $o - registry blessed object
+# rtrn: nothing
+#########################################################################
+
+sub set_script_name {
+    *0 = \(shift->[FILENAME]);
+}
+
+#########################################################################
+# func: chdir_file
+# dflt: NOP
+# desc: chdirs into $dir
+# args: $o - registry blessed object
+#       $dir - a dir
+# rtrn: nothing (?or success/failure?)
+#########################################################################
+
+*chdir_file = \&NOP;
+
+sub chdir_file_normal {
+    my($o, $dir) = @_;
+    # META: not implemented
+    # META: see todo/api.txt unsafe!
+    # $o->[REQ]->chdir_file($dir ? $dir : $o->[FILENAME]);
+}
+
+#########################################################################
+# func: get_mark_line
+# dflt: get_mark_line
+# desc: generates the perl compiler #line directive
+# args: $o - registry blessed object
+# rtrn: returns the perl compiler #line directive
+#########################################################################
+
+sub get_mark_line {
+    my $o = shift;
+    # META: shouldn't this be $o->[CLASS]?
+    $Apache::Registry::MarkLine ? "\n#line 1 $o->[FILENAME]\n" : "";
+}
+
+#########################################################################
+# func: strip_end_data_segment
+# dflt: strip_end_data_segment
+# desc: remove the trailing non-code from $o->[CODE]
+# args: $o - registry blessed object
+# rtrn: nothing
+#########################################################################
+
+sub strip_end_data_segment {
+    ${ +shift->[CODE] } =~ s/__(END|DATA)__(.*)//s;
+}
+
+
+
+#########################################################################
+# func: compile
+# dflt: compile
+# desc: compile the code in $eval
+# args: $o - registry blessed object
+#       $eval - a ref to a scalar with the code to compile
+# rtrn: success/failure
+#########################################################################
+
+sub compile {
+    my($o, $eval) = @_;
+
+    my $r = $o->[REQ];
+
+    $r->log_error("$$: $o->[CLASS]::compile $o->[FILENAME]")
+        if DEBUG && D_COMPILE;
+
+    $r->clear_rgy_endav;
+    Apache->untaint($$eval);
+    {
+        # let the code define its own warn and strict level
+        no strict;
+        no warnings FATAL => 'all'; # because we use FATAL
+        eval $$eval;
+    }
+
+    $r->stash_rgy_endav;
+    return $o->error_check;
+}
+
+#########################################################################
+# func: error_check
+# dflt: error_check
+# desc: checks $@ for errors
+# args: $o - registry blessed object
+# rtrn: Apache::SERVER_ERROR if $@ is set, Apache::OK otherwise
+#########################################################################
+
+sub error_check {
+    my $o = shift;
+    if ($@ and substr($@,0,4) ne " at ") {
+       $o->[REQ]->log_error("$$: $o->[CLASS]: `$@'");
+       $@{$o->[REQ]->uri} = $@;
+       $@ = ''; #XXX fix me, if we don't do this Apache::exit() breaks
+       return Apache::SERVER_ERROR;
+    }
+    return Apache::OK;
+}
+
+
+1;
+__END__
+
+=head1 NAME
+
+Apache::RegistryCooker -
+
+=head1 SYNOPSIS
+
+
+
+=head1 DESCRIPTION
+
+
+
+=cut
+
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/Makefile.PL Tue Oct  9 01:34:30 2001
@@ -0,0 +1,34 @@
+require 5.6.1;
+
+use ExtUtils::MakeMaker;
+
+use lib qw(lib ../blib/lib);
+
+# enable 'make test|clean'
+use Apache::TestMM qw(test clean);
+
+# prerequisites
+my %require =
+  (
+   "Apache::Test" => "", # any version will do?
+  );
+
+my @scripts = qw(t/TEST);
+
+# accept the configs from comman line
+Apache::TestMM::filter_args();
+Apache::TestMM::generate_script('t/TEST');
+
+WriteMakefile
+    (
+     NAME         => 'Apache::Registry',
+     VERSION_FROM => 'lib/Apache/RegistryCooker.pm',
+     PREREQ_PM    => \%require,
+     clean        => {
+                      FILES => "@{ clean_files() }",
+                     },
+    );
+
+sub clean_files {
+    return [@scripts];
+}
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/MANIFEST    Tue Oct  9 01:37:44 2001
@@ -0,0 +1,22 @@
+MANIFEST                       This list of files
+Makefile.PL
+README
+TODO
+lib/Apache/PerlRun.pm
+lib/Apache/Registry.pm
+lib/Apache/RegistryBB.pm
+lib/Apache/RegistryCooker.pm
+lib/Apache/RegistryLoader.pm
+lib/Apache/RegistryNG.pm
+lib/Apache/Reload.pm
+t/TEST.PL
+t/basic.t
+t/cgi-bin/basic.pl
+t/cgi-bin/closure.pl
+t/cgi-bin/env.pl
+t/cgi-bin/local-conf.pl
+t/cgi-bin/not_executable.pl
+t/cgi-bin/require.pl
+t/closure.t
+t/conf/extra.conf.in
+t/htdocs/index.html
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/README      Mon Oct  8 16:57:00 2001
@@ -0,0 +1 @@
+to be written
\ No newline at end of file
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/TODO        Tue Oct  9 01:31:43 2001
@@ -0,0 +1,36 @@
+- META tags in the modules
+
+---------------
+
+ - print STDERR is buffered in test handlers, whereas warn() works
+   normally. select() helps, but STDERR should be unbuffered in first
+   place.
+
+---------------
+
+> what's the replacement of NameWithVirtualHost? Obviously we need something
+> to distinguish between vhs.
+
+DougM: well, if possible we should distinguish between the uri and
+requested resource instead.  in otherwords, we have the: r->uri =>
+r->filename translation, just need to figure out if r->filename is the
+actual filename or a symlink (readlink can be used to get the real
+filename).  then create a package based on the filename, but with as
+few package:: levels as possible (hopefully none beyond
+Apache::RegistryROOT::filename)
+
+DougM: using filenames makes for long packages names == lengthy
+lookups and more memory than we need.  at least the way it is
+currently implemented where each '/' turns into '::'.  could be that
+s,/,_,g is good enough, but haven't thought about this for a while.
+in any case, we should get rid of the NameWithVirtualHost stuff, its
+caused too many problems in the past.
+
+---------------
+
+Bjarni R. Einarsson <[EMAIL PROTECTED]> has suggested this Registry hack
+http://marc.theaimsgroup.com/?l=apache-modperl-dev&m=98961929702745&w=2
+Message-ID: <[EMAIL PROTECTED]>
+
+---------------
+
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/TEST      Tue Oct  9 01:36:23 2001
@@ -0,0 +1,16 @@
+#!/home/stas/perl/ithread/bin/perl
+# WARNING: this file is generated, edit t/TEST.PL instead
+%Apache::TestConfig::Argv = qw(apxs /home/stas/httpd/prefork/bin/apxs);
+#!perl
+
+use strict;
+use warnings FATAL => 'all';
+
+# XXX: fixme
+#use lib map { "$_/Apache-Test/lib" } qw(. ..);
+#use lib map { "$_/blib/lib"        } qw(. .. ../..);
+#use lib map { "$_/lib"             } qw(. .. ../..);
+
+use Apache::TestRunPerl ();
+
+Apache::TestRunPerl->new->run(@ARGV);
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/conf/.cvsignore   Mon Oct  8 16:57:00 2001
@@ -0,0 +1,4 @@
+mime.types
+extra.conf
+httpd.conf
+apache_test_config.pm
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/conf/extra.conf.in        Tue Oct  9 01:03:46 2001
@@ -0,0 +1,64 @@
+#this file will be Include-d by @ServerRoot@/httpd.conf
+
+Alias /registry_ng/      @ServerRoot@/cgi-bin/
+Alias /registry_bb/      @ServerRoot@/cgi-bin/
+Alias /registry/         @ServerRoot@/cgi-bin/
+Alias /registry_oo_conf/ @ServerRoot@/cgi-bin/
+Alias /perlrun/          @ServerRoot@/cgi-bin/
+
+PerlSwitches -Mlib=@ServerRoot@/../lib
+PerlSwitches -Mlib=@ServerRoot@/../../lib
+
+### DEVMODE: Remove in production ###
+PerlModule Apache::Reload
+PerlPostReadRequestHandler Apache::Reload
+PerlSetVar ReloadAll Off
+PerlSetVar ReloadModules "Apache::*"
+
+PerlModule Apache::RegistryCooker
+
+PerlModule Apache::RegistryNG
+<Location /registry_ng>
+    PerlOptions +GlobalRequest
+    SetHandler perl-script
+    Options +ExecCGI
+    PerlResponseHandler Apache::RegistryNG
+    PerlOptions +ParseHeaders
+</Location>
+
+PerlModule Apache::RegistryBB
+<Location /registry_bb>
+    PerlOptions +GlobalRequest
+    SetHandler perl-script
+    Options +ExecCGI
+    PerlResponseHandler Apache::RegistryBB
+    PerlOptions +ParseHeaders
+</Location>
+
+PerlModule Apache::PerlRun
+<Location /perlrun>
+    PerlOptions +GlobalRequest
+    SetHandler perl-script
+    Options +ExecCGI
+    PerlResponseHandler Apache::PerlRun
+    PerlOptions +ParseHeaders
+</Location>
+
+PerlModule Apache::Registry
+<Location /registry>
+    PerlOptions +GlobalRequest
+    SetHandler perl-script
+    Options +ExecCGI
+    PerlResponseHandler Apache::Registry
+    PerlOptions +ParseHeaders
+</Location>
+
+# META: dumps core on OO handlers
+<Location /registry_oo_conf>
+    PerlOptions +GlobalRequest
+    SetHandler perl-script
+    Options +ExecCGI
+    PerlResponseHandler Apache::Registry->handler
+    PerlOptions +ParseHeaders
+</Location>
+
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/.cvsignore        Mon Oct  8 16:57:00 2001
@@ -0,0 +1,2 @@
+logs
+htdocs
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/basic.t   Tue Oct  9 00:49:14 2001
@@ -0,0 +1,60 @@
+use strict;
+use warnings FATAL => 'all';
+
+use Apache::Registry;
+use Apache::Test;
+use Apache::TestUtil;
+use Apache::TestRequest;
+
+my @modules = qw(registry registry_ng registry_bb perlrun);
+
+plan tests => scalar @modules * 3;
+
+my $cfg = Apache::Test::config();
+
+# very basic compilation/response test
+for my $module (@modules) {
+    my $url = "/$module/basic.pl";
+
+    ok t_cmp(
+             "ok",
+             $cfg->http_raw_get($url),
+             "basic cgi test",
+            );
+}
+
+# test non-executable bit
+for my $module (@modules) {
+    my $url = "/$module/not_executable.pl";
+
+    ok t_cmp(
+             "403 Forbidden",
+             HEAD($url)->status_line(),
+             "non-executable file",
+            );
+}
+
+# test environment pre-set
+for my $module (@modules) {
+    my $url = "/$module/env.pl?foo=bar";
+
+    ok t_cmp(
+             "foo=bar",
+             $cfg->http_raw_get($url),
+             "mod_cgi-like environment pre-set",
+            );
+}
+
+# chdir is not safe yet!
+#
+# require (actually chdir test)
+#for my $module (@modules) {
+#    my $url = "/$module/require.pl";
+
+#    ok t_cmp(
+#             "it works",
+#             $cfg->http_raw_get($url),
+#             "mod_cgi-like environment pre-set",
+#            );
+#}
+
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/TEST.PL   Mon Oct  8 16:57:00 2001
@@ -0,0 +1,13 @@
+#!perl
+
+use strict;
+use warnings FATAL => 'all';
+
+# XXX: fixme
+#use lib map { "$_/Apache-Test/lib" } qw(. ..);
+#use lib map { "$_/blib/lib"        } qw(. .. ../..);
+#use lib map { "$_/lib"             } qw(. .. ../..);
+
+use Apache::TestRunPerl ();
+
+Apache::TestRunPerl->new->run(@ARGV);
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/htdocs/index.html Mon Oct  8 16:57:00 2001
@@ -0,0 +1 @@
+welcome to localhost:8529
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/cgi-bin/closure.pl        Tue Oct  9 01:35:30 2001
@@ -0,0 +1,17 @@
+#!perl -w
+
+# this script will suffer from a closure problem under registry
+# should see it under ::Registry
+# should not see it under ::PerlRun
+
+print "Content-type: text/plain\r\n\r\n";
+
+# this is a closure (when compiled inside handler()):
+my $counter = 0;
+counter();
+
+sub counter {
+    #warn "$$";
+    print ++$counter;
+}
+
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/cgi-bin/not_executable.pl Mon Oct  8 17:13:49 2001
@@ -0,0 +1,10 @@
+#!perl -w
+
+# this test should return forbidden, since it should be not-executable
+
+print "Content-type: text/plain\r\n\r\n";
+print "ok";
+
+__END__
+
+this is some irrelevant data
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/cgi-bin/basic.pl  Mon Oct  8 17:11:05 2001
@@ -0,0 +1,10 @@
+#!perl -w
+
+# test all the basic functionality
+
+print "Content-type: text/plain\r\n\r\n";
+print "ok";
+
+__END__
+
+this is some irrelevant data
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/cgi-bin/env.pl    Tue Oct  9 00:40:48 2001
@@ -0,0 +1,6 @@
+# test env vars
+
+print "Content-type: text/plain\r\n\r\n";
+print exists $ENV{QUERY_STRING} && $ENV{QUERY_STRING};
+
+__END__
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/cgi-bin/require.pl        Tue Oct  9 00:47:28 2001
@@ -0,0 +1,9 @@
+# test the require
+
+print "Content-type: text/plain\r\n\r\n";
+
+use lib qw(.);
+my $file = "./local-conf.pl";
+require $file;
+
+print defined $test_require && $test_require;
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/cgi-bin/local-conf.pl     Tue Oct  9 00:48:47 2001
@@ -0,0 +1,3 @@
+$test_require = 'it works';
+
+1;
--- /dev/null   Thu Jan  1 07:30:00 1970
+++ Apache-Registry/t/closure.t Tue Oct  9 00:26:27 2001
@@ -0,0 +1,125 @@
+use strict;
+use warnings FATAL => 'all';
+
+use Apache::Registry;
+use Apache::Test;
+use File::Spec::Functions;
+use Apache::TestUtil;
+
+# this test tests how various registry packages cache and flush the
+# scripts their run, and whether they check modification on the disk
+# or not
+
+my @modules = qw(registry registry_ng registry_bb perlrun);
+
+plan tests => 6;
+
+my $cfg = Apache::Test::config();
+
+my $file = 'closure.pl';
+my $path = catfile $cfg->{vars}->{serverroot}, 'cgi-bin', $file;
+
+# for all sub-tests in this test, we assume that we always get onto
+# the same interpreter (since there are no other requests happening in
+# parallel
+
+{
+    # Apache::PerlRun
+    # always flush
+    # no cache
+
+    my $url = "/perlrun/$file";
+
+    # should be no closure effect, always returns 1
+    my $first  = $cfg->http_raw_get($url);
+    my $second = $cfg->http_raw_get($url);
+    ok t_cmp(
+             0,
+             $second - $first,
+             "never a closure problem",
+            );
+
+    # modify the file
+    sleep_and_touch_file($path);
+
+    # it doesn't matter, since the script is not cached anyway
+    ok t_cmp(
+             1,
+             $cfg->http_raw_get($url),
+             "never a closure problem",
+            );
+
+}
+
+
+
+{
+    # Apache::Registry
+    # no flush
+    # cache, but reload on modification
+    my $url = "/registry/$file";
+
+    # we don't know what other test has called this uri before, so we
+    # check the difference between two subsequent calls. In this case
+    # the difference should be 1.
+    my $first  = $cfg->http_raw_get($url);
+    my $second = $cfg->http_raw_get($url);
+    ok t_cmp(
+             1,
+             $second - $first,
+             "closure problem should exist",
+            );
+
+    # modify the file
+    sleep_and_touch_file($path);
+
+    # should no notice closure effect on first request
+    ok t_cmp(
+             1,
+             $cfg->http_raw_get($url),
+             "no closure on the first request",
+            );
+
+}
+
+
+
+
+{
+    # Apache::RegistryBB
+    # no flush
+    # cache once, don't check for mods
+    my $url = "/registry_bb/$file";
+
+    # we don't know what other test has called this uri before, so we
+    # check the difference between two subsequent calls. In this case
+    # the difference should be 0.
+    my $first  = $cfg->http_raw_get($url);
+    my $second = $cfg->http_raw_get($url);
+    ok t_cmp(
+             1,
+             $second - $first,
+             "closure problem should exist",
+            );
+
+    # modify the file
+    sleep_and_touch_file($path);
+
+    #
+    my $third = $cfg->http_raw_get($url);
+    ok t_cmp(
+             1,
+             $third - $second,
+             "no reload on mod, closure persist",
+            );
+
+}
+
+
+
+sub sleep_and_touch_file {
+    my $file = shift;
+    sleep 2; # so -M will be different, res: 1 sec, granularity > 1sec
+    my $now = time;
+    utime $now, $now, $file;
+}


_____________________________________________________________________
Stas Bekman             JAm_pH      --   Just Another mod_perl Hacker
http://stason.org/      mod_perl Guide   http://perl.apache.org/guide
mailto:[EMAIL PROTECTED]  http://ticketmaster.com http://apacheweek.com
http://singlesheaven.com http://perl.apache.org http://perlmonth.com/


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

Reply via email to