You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl-cvs@perl.apache.org by st...@apache.org on 2001/12/17 17:20:27 UTC
cvs commit: modperl-2.0/xs/APR/PerlIO apr_perlio.c apr_perlio.h Makefile.PL PerlIO.xs PerlIO.pm
stas 01/12/17 08:20:27
Added: t/response/TestAPR perlio.pm
xs/APR/PerlIO apr_perlio.c apr_perlio.h Makefile.PL
PerlIO.xs PerlIO.pm
Log:
- implements APR::PerlIO layer
- implements apr_file_t to APR::PerlIO conversion hooks (one way) (two
different sets for 5.6.1 and 5.7.2+)
- tests (conversion hooks are tested in Apache::SubProcess)
Revision Changes Path
1.1 modperl-2.0/t/response/TestAPR/perlio.pm
Index: perlio.pm
===================================================================
package TestAPR::perlio;
use strict;
use warnings;# FATAL => 'all';
use Apache::Const -compile => 'OK';
use Apache::Test;
use Apache::TestUtil;
use APR::PerlIO ();
use Fcntl ();
use File::Spec::Functions qw(catfile);
sub handler {
my $r = shift;
plan $r, tests => 9, todo => [5], have_perl 'iolayers';
my $vars = Apache::Test::config()->{vars};
my $dir = catfile $vars->{documentroot}, "perlio";
t_mkdir($dir);
# write file
my $file = catfile $dir, "test";
t_debug "open file $file";
my $foo = "bar";
open my $fh, ">:APR", $file, $r
or die "Cannot open $file for writing: $!";
ok ref($fh) eq 'GLOB';
my $expected = "This is a test: $$";
t_debug "write to a file: $expected";
print $fh $expected;
close $fh;
# open() other tests
{
# non-existant file
my $file = "/this/file/does/not/exist";
t_write_file("/tmp/testing", "some stuff");
if (open my $fh, "<:APR", $file, $r) {
t_debug "must not be able to open $file!";
ok 0;
close $fh;
}
else {
t_debug "good! cannot open/doesn't exist: $!";
ok 1;
}
}
# read() test
{
open my $fh, "<:APR", $file, $r
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, $r
or die "Cannot open $file for reading: $!";
my $pos = 3;
seek $fh, $pos, Fcntl::SEEK_SET();
# XXX: broken
my $got = tell($fh);
ok t_cmp($pos,
$got,
"seek/tell the file");
# XXX: test Fcntl::SEEK_CUR() Fcntl::SEEK_END()
close $fh;
}
# eof() tests
{
open my $fh, "<:APR", $file, $r
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, Fcntl::SEEK_END();
my $received = <$fh>;
ok t_cmp(1,
eof($fh),
"end of file");
close $fh;
}
# dup() test
{
open my $fh, "<:APR", $file, $r
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");
}
# XXX: need tests
# - for stdin/out/err as they are handled specially
# - unbuffered read $|=1?
# XXX: tmpfile is missing:
# consider to use 5.8's syntax:
# open $fh, "+>", undef;
# cleanup: t_mkdir will remove the whole tree including the file
Apache::OK;
}
1;
1.1 modperl-2.0/xs/APR/PerlIO/apr_perlio.c
Index: apr_perlio.c
===================================================================
#include "mod_perl.h"
#include "apr_perlio.h"
/* XXX: prerequisites to have things working
* open(): perl 5.7.2 patch 13534 is required
* dup() : apr cvs date: 2001/12/06 13:43:45
* tell(): the patch isn't in yet.
*
* XXX: it's not enough to check for PERLIO_LAYERS, some functionality
* and bug fixes were added only in the late 5.7.2, whereas
* PERLIO_LAYERS is available in 5.7.1
*/
#ifdef PERLIO_LAYERS /* 5.7.2+ */
/**********************************************************************
* The PerlIO APR layer.
* The PerlIO API is documented in perliol.pod.
**********************************************************************/
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);
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;
SV *sv;
if ( !(SvROK(arg) || SvPOK(arg)) ) {
return NULL;
}
/* XXX: why passing only SV* for arg, check this out in PerlIO_push */
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(args[narg-2]);
switch (*mode) {
case 'a':
apr_flag = APR_APPEND | APR_CREATE;
break;
case 'w':
apr_flag = APR_WRITE | APR_CREATE | APR_TRUNCATE;
break;
case 'r':
apr_flag = APR_READ;
break;
}
st = PerlIOSelf(f, PerlIOAPR);
sv = args[narg-1];
st->pool = modperl_sv2pool(aTHX_ sv);
rc = apr_file_open(&st->file, path, apr_flag, APR_OS_DEFAULT, st->pool);
if (rc != APR_SUCCESS) {
PerlIOBase(f)->flags |= PERLIO_F_ERROR;
return NULL;
}
else {
PerlIOBase(f)->flags |= PERLIO_F_OPEN;
return f;
}
}
static IV PerlIOAPR_fileno(PerlIO *f)
{
/* apr_file_t* is an opaque struct, so fileno is not available */
/* XXX: this -1 workaround 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;
apr_status_t rc;
if ( (f = PerlIOBase_dup(aTHX_ f, o, param, flags)) ) {
PerlIOAPR *fst = PerlIOSelf(f, PerlIOAPR);
PerlIOAPR *ost = PerlIOSelf(o, PerlIOAPR);
rc = apr_file_dup(&fst->file, ost->file, ost->pool);
if (rc == APR_SUCCESS) {
fst->pool = ost->pool;
return f;
}
}
return NULL;
}
/* currrently read is very not-optimized, since in many cases the read
* process happens a char by char. Need to find a way to snoop on APR
* read buffer from PerlIO, or implement our own buffering layer here
*/
static SSize_t PerlIOAPR_read(PerlIO *f, void *vbuf, Size_t count)
{
PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
apr_status_t rc;
dTHX;
// fprintf(stderr, "in read: count %d, %s\n", (int)count, (char*) vbuf);
rc = apr_file_read(st->file, vbuf, &count);
// fprintf(stderr, "out read: count %d, %s\n", (int)count, (char*) vbuf);
if (rc == APR_SUCCESS) {
return (SSize_t) count;
}
else {
return (SSize_t) -1;
}
}
static SSize_t PerlIOAPR_write(PerlIO *f, const void *vbuf, Size_t count)
{
PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
apr_status_t rc;
// fprintf(stderr, "in write: count %d, %s\n", (int)count, (char*) vbuf);
rc = apr_file_write(st->file, vbuf, &count);
if (rc == APR_SUCCESS) {
return (SSize_t) count;
}
else {
return (SSize_t) -1;
}
}
static IV PerlIOAPR_seek(PerlIO *f, Off_t offset, int whence)
{
PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
apr_seek_where_t where;
apr_status_t rc;
/* XXX: must flush before seek? */
rc = apr_file_flush(st->file);
if (rc != APR_SUCCESS) {
return -1;
}
switch(whence) {
case 0:
where = APR_SET;
break;
case 1:
where = APR_CUR;
break;
case 2:
where = APR_END;
break;
}
rc = apr_file_seek(st->file, where, (apr_off_t *)&offset);
if (rc == APR_SUCCESS) {
return 0;
}
else {
return -1;
}
}
static Off_t PerlIOAPR_tell(PerlIO *f)
{
PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
apr_off_t offset = 0;
apr_status_t rc;
/* this is broken, for some reason it returns 6e17 */
rc = apr_file_seek(st->file, APR_CUR, &offset);
if (rc == APR_SUCCESS) {
return (Off_t) offset;
}
else {
return (Off_t) -1;
}
}
static IV PerlIOAPR_close(PerlIO *f)
{
PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
IV code = PerlIOBase_close(f);
apr_status_t rc;
const char *new_path;
apr_file_name_get(&new_path, st->file);
// fprintf(stderr, "closing file %s\n", new_path);
rc = apr_file_flush(st->file);
if (rc != APR_SUCCESS) {
return -1;
}
rc = apr_file_close(st->file);
if (rc != APR_SUCCESS) {
return -1;
}
return code;
}
static IV PerlIOAPR_flush(PerlIO *f)
{
PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
apr_status_t rc;
rc = apr_file_flush(st->file);
if (rc == APR_SUCCESS) {
return 0;
}
else {
return -1;
}
}
static IV PerlIOAPR_fill(PerlIO *f)
{
return -1;
}
static IV PerlIOAPR_eof(PerlIO *f)
{
PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
apr_status_t rc;
rc = apr_file_eof(st->file);
switch (rc) {
case APR_SUCCESS:
return 0;
case APR_EOF:
return 1;
}
}
static PerlIO_funcs PerlIO_APR = {
"APR",
sizeof(PerlIOAPR),
PERLIO_K_BUFFERED | PERLIO_K_MULTIARG, /* XXX: document the flag in perliol.pod */
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,
PerlIOAPR_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_init(pTHX)
{
APR_REGISTER_OPTIONAL_FN(apr_perlio_apr_file_to_PerlIO);
APR_REGISTER_OPTIONAL_FN(apr_perlio_apr_file_to_glob);
PerlIO_define_layer(aTHX_ &PerlIO_APR);
}
/* ***** End of PerlIOAPR tab ***** */
/* ***** PerlIO <=> apr_file_t helper functions ***** */
PerlIO *apr_perlio_apr_file_to_PerlIO(pTHX_ apr_file_t *file,
apr_pool_t *pool, int type)
{
char *mode;
const char *layers = ":APR";
PerlIO *f = PerlIO_allocate(aTHX);
switch (type) {
case APR_PERLIO_HOOK_WRITE:
mode = "w";
break;
case APR_PERLIO_HOOK_READ:
mode = "r";
break;
default:
/* */
};
PerlIO_apply_layers(aTHX_ f, mode, layers);
if (f) {
PerlIOAPR *st = PerlIOSelf(f, PerlIOAPR);
/* XXX: should we dup first? the timeout could close the fh! */
st->pool = pool;
st->file = file;
PerlIOBase(f)->flags |= PERLIO_F_OPEN;
return f;
}
else {
return NULL;
}
}
/*
* type: APR_PERLIO_HOOK_READ | APR_PERLIO_HOOK_WRITE
*/
static SV *apr_perlio_PerlIO_to_glob(pTHX_ PerlIO *pio, int type)
{
SV *retval = modperl_perl_gensym(aTHX_ "APR::PerlIO");
GV *gv = (GV*)SvRV(retval);
gv_IOadd(gv);
switch (type) {
case APR_PERLIO_HOOK_WRITE:
IoOFP(GvIOp(gv)) = pio;
IoFLAGS(GvIOp(gv)) |= IOf_FLUSH;
break;
case APR_PERLIO_HOOK_READ:
IoIFP(GvIOp(gv)) = pio;
break;
default:
/* */
};
return sv_2mortal(retval);
}
SV *apr_perlio_apr_file_to_glob(pTHX_ apr_file_t *file,
apr_pool_t *pool, int type)
{
return apr_perlio_PerlIO_to_glob(aTHX_
apr_perlio_apr_file_to_PerlIO(aTHX_ file, pool, type),
type);
}
#else /* NOT PERLIO_LAYERS (5.6.1) */
FILE *apr_perlio_apr_file_to_FILE(pTHX_ apr_file_t *file, int type)
{
FILE *retval;
char *mode;
int fd;
apr_os_file_t os_file;
apr_status_t rc;
switch (type) {
case APR_PERLIO_HOOK_WRITE:
mode = "w";
break;
case APR_PERLIO_HOOK_READ:
mode = "r";
break;
default:
/* */
};
/* convert to the OS representation of file */
rc = apr_os_file_get(&os_file, file);
if (rc != APR_SUCCESS) {
croak("filedes retrieval failed!");
}
fd = PerlLIO_dup(os_file);
// Perl_warn(aTHX_ "fd old: %d, new %d\n", os_file, fd);
if (!(retval = PerlIO_fdopen(fd, mode))) {
PerlLIO_close(fd);
croak("fdopen failed!");
}
return retval;
}
/*
*
* type: APR_PERLIO_HOOK_READ | APR_PERLIO_HOOK_WRITE
*/
SV *apr_perlio_apr_file_to_glob(pTHX_ apr_file_t *file,
apr_pool_t *pool, int type)
{
SV *retval = modperl_perl_gensym(aTHX_ "APR::PerlIO");
GV *gv = (GV*)SvRV(retval);
gv_IOadd(gv);
switch (type) {
case APR_PERLIO_HOOK_WRITE:
IoOFP(GvIOp(gv)) = apr_perlio_apr_file_to_FILE(aTHX_ file, type);
IoFLAGS(GvIOp(gv)) |= IOf_FLUSH;
break;
case APR_PERLIO_HOOK_READ:
IoIFP(GvIOp(gv)) = apr_perlio_apr_file_to_FILE(aTHX_ file, type);
break;
default:
/* */
};
return sv_2mortal(retval);
}
void apr_perlio_init(pTHX)
{
APR_REGISTER_OPTIONAL_FN(apr_perlio_apr_file_to_glob);
}
#endif /* PERLIO_LAYERS */
1.1 modperl-2.0/xs/APR/PerlIO/apr_perlio.h
Index: apr_perlio.h
===================================================================
#ifndef APR_PERLIO_H
#define APR_PERLIO_H
#ifdef PERLIO_LAYERS
#include "perliol.h"
#else
#include "iperlsys.h"
#endif
#include "apr_portable.h"
#include "apr_file_io.h"
#ifndef MP_SOURCE_SCAN
#include "apr_optional.h"
#endif
#define APR_PERLIO_HOOK_READ 0
#define APR_PERLIO_HOOK_WRITE 1
void apr_perlio_init(pTHX);
/* The following functions can be used from other .so libs, they just
* need to load APR::PerlIO perl module first
*/
#ifndef MP_SOURCE_SCAN
#ifdef PERLIO_LAYERS
PerlIO *apr_perlio_apr_file_to_PerlIO(pTHX_ apr_file_t *file,
apr_pool_t *pool, int type);
APR_DECLARE_OPTIONAL_FN(PerlIO *,
apr_perlio_apr_file_to_PerlIO,
(pTHX_ apr_file_t *file, apr_pool_t *pool, int type));
#endif /* PERLIO_LAYERS */
SV *apr_perlio_apr_file_to_glob(pTHX_ apr_file_t *file,
apr_pool_t *pool, int type);
APR_DECLARE_OPTIONAL_FN(SV *,
apr_perlio_apr_file_to_glob,
(pTHX_ apr_file_t *file, apr_pool_t *pool, int type));
#endif /* MP_SOURCE_SCAN */
#endif /* APR_PERLIO_H */
1.1 modperl-2.0/xs/APR/PerlIO/Makefile.PL
Index: Makefile.PL
===================================================================
use lib qw(../lib);
use ModPerl::MM ();
ModPerl::MM::WriteMakefile(
NAME => 'APR::PerlIO',
VERSION_FROM => 'PerlIO.pm',
OBJECT => 'PerlIO.o apr_perlio.o');
1.1 modperl-2.0/xs/APR/PerlIO/PerlIO.xs
Index: PerlIO.xs
===================================================================
#include "mod_perl.h"
#include "apr_perlio.h"
MODULE = APR::PerlIO PACKAGE = APR::PerlIO
PROTOTYPES: disabled
BOOT:
apr_perlio_init(aTHX);
1.1 modperl-2.0/xs/APR/PerlIO/PerlIO.pm
Index: PerlIO.pm
===================================================================
package APR::PerlIO;
require 5.6.1;
our $VERSION = '0.01';
use APR::XSLoader ();
APR::XSLoader::load __PACKAGE__;
# XXX: The PerlIO layer is available only since 5.8.0 (5.7.2 p13534)
1;