On Thu, 6 Dec 2001, Doug MacEachern wrote:

> On Fri, 7 Dec 2001, Stas Bekman wrote:
>
> cool!  one major problem with the file layout/linking however.
> neither perlio nor apr is tied to httpd, so the APR PerlIO layer shouldn't
> be either.  that is, it should be possible to use the APR PerlIO layer
> outside of httpd.  there's no need to use the .map stuff for this.  you
> can just create:
> xs/APR/PerlIO
> with:
> apr_perlio.h - was modperl_perlio.h
> apr_perlio.c - was modperl_perlio.c
> PerlIO.xs - just has the BOOT section to add the layer
> PerlIO.pm - use APR () and load PerlIO.so
> Makefile.PL - ModPerl::MM::WriteMakefile(
>                   NAME => 'APR::PerlIO',
>                   VERSION_FROM => 'PerlIO.pm',
>                   OBJECT => 'PerlIO.o apr_perlio.o');

done

> when PerlIO.pm does 'use APR ()' it is a noop inside modperl and
> outside loads libapr, libaprutil and takes care of
> apr_initialize/apr_terminate.

done

> > - currently cannot pass $r|$s via open :( using modperl_global_get_pconf
>
> we can't do that.  pconf can only be used at startup.
> if builtin open doesn't support passing an APR::Pool reference, then we
> need to have an APR::PerlIO::open that does.

the good news is that's apparently a bug in PerlIO, so we may have it
working :)

> another thing to consider is how to map apr_file_t's that are returned by
> existing apache and apr functions.  won't be able to use the builtin open
> for those.

yup, that was on my todo list already.

> functions themselves look good, just a few style comments...

great!

> > +IV
> > +PerlIOAPR_popped(PerlIO *f)
>
> all of these functions should be static.  and should also follow the
> style where return type is on the same line as function name:
> static IV PerlIOAPR_popped(...)

fixed

> > +{
> > +    dTHX;
>
> would be nice if we could "fix" Perl so dTHX is not needed for any of
> these functions.

no more dTHXs in APR PerlIO layer (at least so far), but they are used
internally in the base PerlIO layer to do XS.

> > +    switch (*mode) {
> > +        case 'a' : apr_flag = APR_APPEND | APR_CREATE; break;
> > +        case 'w' : apr_flag = APR_WRITE  | APR_CREATE; break;
> > +        case 'r' : apr_flag = APR_READ;                break;
> > +        default  :
> > +    }
>
> should follow style of other switch statement in modperl.

fixed

> > +IV
> > +PerlIOAPR_close(PerlIO *f)
> > +{
> > +    PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
> > +    IV code = PerlIOBase_close(f);
> > +        if ((apr_file_flush(st->file) != APR_SUCCESS)) {
> > +            /* XXX: error? */
> > +            return 0;
> > +        }
>
> indenting off.

fixed

> > +    /* XXX: what's this for? */
> > +    PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF|PERLIO_F_WRBUF);
>
> turns off buffering flags, dunno if it actually needs to.

removed

> > +PerlIO_funcs PerlIO_APR = {
>
> this should be static too.

fixed

> also TestUtil::apr_io should be TestAPR::perlio.

fixed

> and of course should be
> skipped if perlio isn't available.

>> todo, I guess I need to provide an XS constant that says whether PerlIO
is available, right?

here is the new version of the new layer:

--- /dev/null   Thu Jan  1 07:30:00 1970
+++ t/response/TestAPR/perlio.pm        Sat Dec  8 02:16:04 2001
@@ -0,0 +1,129 @@
+package TestAPR::perlio;
+
+use strict;
+use warnings;# FATAL => 'all';
+
+use Apache::Const -compile => 'OK';
+
+use Apache::Test;
+use Apache::TestUtil;
+use Fcntl qw(SEEK_SET SEEK_CUR SEEK_END);
+
+use APR::PerlIO ();
+
+
+sub handler {
+    my $r = shift;
+
+    # XXX: need to be skipped if perlio is not available
+    plan $r, tests => 9, todo => [2, 5];
+
+    # write file
+    my $file = "/tmp/file$$";
+    t_debug "file $file";
+    open my $fh, ">:APR", $file
+        or die "Cannot open $file for writing: $!";
+    ok ref($fh) eq 'GLOB';
+
+    my $expected = "This is a test: $$";
+    print $fh $expected;
+    close $fh;
+
+    # open() other tests
+    {
+        # non-existant file
+        #my $file = "/this/file/does/not/exist";
+        my $file = "/tmp/mytest";
+        if (open my $fh, "<:APR", $file) {
+            t_debug "must not be able to open $file!";
+            ok 0;
+            close $fh;
+        } else {
+            t_debug "good: failure reason: $!";
+            ok 1;
+        }
+
+    }
+
+    # read() test
+    {
+        open my $fh, "<:APR", $file
+            or die "Cannot open $file for reading: $!";
+        ok ref($fh) eq 'GLOB';
+
+        my $received = <$fh>;
+        close $fh;
+
+        ok t_cmp($expected,
+                 $received,
+                 "read/write file");
+    }
+
+    # seek/tell() tests
+    {
+        open my $fh, "<:APR", $file
+            or die "Cannot open $file for reading: $!";
+
+        my $pos = 3;
+        seek $fh, $pos, SEEK_SET;
+        # XXX: broken
+        my $got = tell($fh);
+        ok t_cmp($pos,
+                 $got,
+                 "seek/tell the file");
+
+        # XXX: test SEEK_CUR SEEK_END
+        close $fh;
+
+    }
+
+
+    # eof() tests
+    {
+        open my $fh, "<:APR", $file
+            or die "Cannot open $file for reading: $!";
+
+        ok t_cmp(0,
+                 int eof($fh), # returns false, not 0
+                 "not end of file");
+        # go to the end and read
+        seek $fh, 0, SEEK_END;
+        my $received = <$fh>;
+
+        ok t_cmp(1,
+                 eof($fh),
+                 "end of file");
+        close $fh;
+    }
+
+    # dup() test
+    {
+        open my $fh, "<:APR", $file
+            or die "Cannot open $file for reading: $!";
+
+        open my $dup_fh, "<&:APR", $fh
+            or die "Cannot dup $file for reading: $!";
+        close $fh;
+        ok ref($dup_fh) eq 'GLOB';
+
+        my $received = <$dup_fh>;
+
+        close $dup_fh;
+        ok t_cmp($expected,
+                 $received,
+                 "read/write a dupped file");
+    }
+
+    # cleanup
+    unlink $file;
+
+    # need tests for stdin/out/err as they are handled specially
+
+    # tmpfile is missing:
+    # consider to use 5.8's syntax:
+    #   open $fh, "+>", undef;
+
+    Apache::OK;
+}
+
+1;

--- /dev/null   Thu Jan  1 07:30:00 1970
+++ xs/APR/PerlIO/apr_perlio.c  Sat Dec  8 02:14:45 2001
@@ -0,0 +1,262 @@
+#include "mod_perl.h"
+#include "apr_perlio.h"
+
+#ifdef PERLIO_LAYERS
+
+/**********************************************************************
+ * The implementation of the Perl IO layer using APR. See perliol.pod *
+ * for the used API's documentation.                                  *
+ **********************************************************************/
+
+typedef struct {
+    PerlIOBuf base;            /* PerlIOBuf stuff */
+    apr_file_t *file;
+    apr_pool_t *pool;
+} PerlIOAPR;
+
+
+/* clean up any structures linked from PerlIOAPR. a layer can be
+ * popped without being closed if the program is dynamically managing
+ * layers on the stream.
+ */
+static IV PerlIOAPR_popped(PerlIO *f)
+{
+    PerlIOAPR *st = PerlIOSelf(f,PerlIOAPR);
+
+    /* XXX: do cleanup here */
+    return 0;
+}
+
+static PerlIO *PerlIOAPR_open(pTHX_ PerlIO_funcs *self,
+                              PerlIO_list_t *layers, IV n,
+                              const char *mode, int fd, int imode,
+                              int perm, PerlIO *f, int narg, SV **args)
+{
+    AV *av_arg;
+    SV *arg = (narg > 0) ? *args : PerlIOArg;
+    PerlIOAPR *st;
+    const char *path;
+    apr_int32_t apr_flag;
+    int len;
+    apr_status_t rc;
+
+    if (!(SvROK(arg) || SvPOK(arg))) {
+        return NULL;
+    }
+
+    if (!f) {
+        f = PerlIO_push(aTHX_ PerlIO_allocate(aTHX), self, mode, arg);
+    }
+    else {
+        f = PerlIO_push(aTHX_ f, self, mode, arg);
+    }
+
+    /* grab the last arg as a filepath */
+    path = (const char *)SvPV_nolen(&arg[narg-1]);
+
+    switch (*mode) {
+      case 'a':
+        apr_flag = APR_APPEND | APR_CREATE;
+        break;
+      case 'w':
+        apr_flag = APR_WRITE  | APR_CREATE;
+        break;
+      case 'r':
+        apr_flag = APR_READ;
+        break;
+    }
+
+    st = PerlIOSelf(f, PerlIOAPR);
+
+    /* XXX: passing r or s to get the pool? */
+    /* XXX: need to move to _pushed? */
+    st->pool = modperl_global_get_pconf();
+
+    if ( (rc = apr_file_open(&st->file, path, apr_flag,
+                             APR_OS_DEFAULT, st->pool)) != APR_SUCCESS) {
+        /* XXX: how do we set $! */
+        char buf[120];
+        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+                     "cannot open file '%s': %s",
+                     path, apr_strerror(rc, buf, sizeof(buf)));
+    }
+
+    return f;
+}
+
+
+static IV PerlIOAPR_fileno(PerlIO *f)
+{
+    /* apr_file_t* is an opaque struct, so fileno is not available */
+    /* XXX: this should be documented in perliol.pod */
+    /* see: 
+http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2001-11/thrd21.html#02040 */
+    /* 
+http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2001-12/threads.html#00217 */
+    return -1;
+}
+
+static PerlIO *PerlIOAPR_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int 
+flags)
+{
+    Size_t count;
+
+    if ((f = PerlIOBase_dup(aTHX_ f, o, param, flags))) {
+        PerlIOAPR *fst = PerlIOSelf(f, PerlIOAPR);
+        PerlIOAPR *ost = PerlIOSelf(o, PerlIOAPR);
+        if ((apr_file_dup(&fst->file, ost->file, ost->pool) == APR_SUCCESS)) {
+            /* XXX: error? */
+            fst->pool = ost->pool;
+        }
+    }
+    /* XXX: else error? */
+    return f;
+}
+
+static SSize_t PerlIOAPR_read(PerlIO *f, void *vbuf, Size_t count)
+{
+    PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
+    apr_status_t rc;
+
+    if ((rc = apr_file_read(st->file, vbuf, &count) != APR_SUCCESS)) {
+        /* XXX: error? */
+        return (SSize_t) -1;
+    }
+    return (SSize_t) count;
+}
+
+
+static SSize_t PerlIOAPR_write(PerlIO *f, const void *vbuf, Size_t count)
+{
+    PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
+    apr_status_t rc;
+
+    if ((rc = apr_file_write(st->file, vbuf, &count) != APR_SUCCESS)) {
+        /* XXX: how do we set $! */
+        char buf[120];
+        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+                     "cannot write to file: %s",
+                     apr_strerror(rc, buf, sizeof(buf)));
+        /* XXX: error? */
+        return (SSize_t) -1;
+    }
+    return (SSize_t) count;
+}
+
+static IV PerlIOAPR_seek(PerlIO *f, Off_t offset, int whence)
+{
+    PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
+    apr_seek_where_t where;
+
+    /* must flush before seek */
+    if ((apr_file_flush(st->file) != APR_SUCCESS)) {
+        return -1;
+    }
+
+    switch(whence) {
+      case 0:
+        where = APR_SET;
+        break;
+      case 1:
+        where = APR_CUR;
+        break;
+      case 2:
+        where = APR_END;
+        break;
+    }
+
+    if ((apr_file_seek(st->file, where, (apr_off_t *)&offset) == APR_SUCCESS)) {
+        return 0;
+    }
+    else {
+        return -1;
+    }
+}
+
+
+static Off_t PerlIOAPR_tell(PerlIO *f)
+{
+    PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
+    apr_off_t offset = 0;
+    /* this is broken, for some reason it returns 6e17 */
+    return (off_t)3;
+
+    if ((apr_file_seek(st->file, APR_CUR, &offset) == APR_SUCCESS)) {
+        return (Off_t) offset;
+    }
+    return (Off_t) -1;
+}
+
+static IV PerlIOAPR_close(PerlIO *f)
+{
+    PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
+    IV code = PerlIOBase_close(f);
+
+    if ((apr_file_flush(st->file) != APR_SUCCESS)) {
+        /* XXX: error? */
+        return 0;
+    }
+    if ((apr_file_close(st->file) == APR_SUCCESS)) {
+        /* XXX: log to error_log? */
+    }
+
+    return code;
+}
+
+
+static IV PerlIOAPR_flush(PerlIO *f)
+{
+    PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
+
+    if ((apr_file_flush(st->file) == APR_SUCCESS)) {
+        return 0;
+    }
+    else {
+        return -1;
+    }
+}
+
+static IV PerlIOAPR_eof(PerlIO *f)
+{
+    PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
+
+    switch (apr_file_eof(st->file)) {
+      case APR_SUCCESS:
+        return 0;
+      case APR_EOF:
+        return 1;
+    }
+}
+
+static PerlIO_funcs PerlIO_APR = {
+    "APR",
+    sizeof(PerlIOAPR),
+    PERLIO_K_BUFFERED,
+    PerlIOBase_pushed,
+    PerlIOAPR_popped,
+    PerlIOAPR_open,
+    NULL,              /* no getarg needed */
+    PerlIOAPR_fileno,
+    PerlIOAPR_dup,
+    PerlIOAPR_read,
+    PerlIOBuf_unread,
+    PerlIOAPR_write,
+    PerlIOAPR_seek,
+    PerlIOAPR_tell,
+    PerlIOAPR_close,
+    PerlIOAPR_flush,
+    PerlIOBuf_fill,
+    PerlIOAPR_eof,
+    PerlIOBase_error,
+    PerlIOBase_clearerr,
+    PerlIOBase_setlinebuf,
+    PerlIOBuf_get_base,
+    PerlIOBuf_bufsiz,
+    PerlIOBuf_get_ptr,
+    PerlIOBuf_get_cnt,
+    PerlIOBuf_set_ptrcnt
+};
+
+void apr_perlio_BOOT(pTHX)
+{
+    PerlIO_define_layer(aTHX_ &PerlIO_APR);
+}
+
+#endif /* PERLIO_LAYERS */

--- /dev/null   Thu Jan  1 07:30:00 1970
+++ xs/APR/PerlIO/apr_perlio.h  Fri Dec  7 14:08:00 2001
@@ -0,0 +1,13 @@
+#ifndef APR_PERLIO_H
+#define APR_PERLIO_H
+
+#ifdef PERLIO_LAYERS
+
+#include "perliol.h"
+#include "apr_file_io.h"
+
+void modperl_perlio_init(pTHX);
+
+#endif /* PERLIO_LAYERS */
+
+#endif /* APR_PERLIO_H */

--- /dev/null   Thu Jan  1 07:30:00 1970
+++ xs/APR/PerlIO/Makefile.PL   Fri Dec  7 13:45:32 2001
@@ -0,0 +1,8 @@
+use lib qw(../lib);
+use ModPerl::MM ();
+
+ModPerl::MM::WriteMakefile(
+    NAME => 'APR::PerlIO',
+    VERSION_FROM => 'PerlIO.pm',
+    OBJECT => 'PerlIO.o apr_perlio.o');
+

--- /dev/null   Thu Jan  1 07:30:00 1970
+++ xs/APR/PerlIO/PerlIO.xs     Fri Dec  7 14:12:27 2001
@@ -0,0 +1,9 @@
+#include "mod_perl.h"
+#include "apr_perlio.h"
+
+MODULE = APR::PerlIO    PACKAGE = APR::PerlIO
+
+PROTOTYPES: disabled
+
+BOOT:
+    apr_perlio_BOOT(aTHXo);

--- /dev/null   Thu Jan  1 07:30:00 1970
+++ xs/APR/PerlIO/PerlIO.pm     Fri Dec  7 14:14:56 2001
@@ -0,0 +1,10 @@
+package APR::PerlIO;
+
+use APR (); # NOOP under modperl
+use XSLoader ();
+
+our $VERSION = '0.01';
+
+XSLoader::load(__PACKAGE__, $VERSION);
+
+1;


_____________________________________________________________________
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