#include "XSUB.h"
+/* Call the callback or PerlIOBase, and return failure. */
+#define Perl_PerlIO_or_Base(f, callback, base, failure, args) \
+ if (PerlIOValid(f)) { \
+ PerlIO_funcs *tab = PerlIOBase(f)->tab; \
+ if (tab && tab->callback) \
+ return (*tab->callback) args; \
+ else \
+ return PerlIOBase_ ## base args; \
+ } \
+ else \
+ SETERRNO(EBADF, SS_IVCHAN); \
+ return failure
+
+/* Call the callback or fail, and return failure. */
+#define Perl_PerlIO_or_fail(f, callback, failure, args) \
+ if (PerlIOValid(f)) { \
+ PerlIO_funcs *tab = PerlIOBase(f)->tab; \
+ if (tab && tab->callback) \
+ return (*tab->callback) args; \
+ SETERRNO(EINVAL, LIB_INVARG); \
+ } \
+ else \
+ SETERRNO(EBADF, SS_IVCHAN); \
+ return failure
+
+/* Call the callback or PerlIOBase, and be void. */
+#define Perl_PerlIO_or_Base_void(f, callback, base, args) \
+ if (PerlIOValid(f)) { \
+ PerlIO_funcs *tab = PerlIOBase(f)->tab; \
+ if (tab && tab->callback) \
+ (*tab->callback) args; \
+ else \
+ PerlIOBase_ ## base args; \
+ } \
+ else \
+ SETERRNO(EBADF, SS_IVCHAN)
+
+/* Call the callback or fail, and be void. */
+#define Perl_PerlIO_or_fail_void(f, callback, args) \
+ if (PerlIOValid(f)) { \
+ PerlIO_funcs *tab = PerlIOBase(f)->tab; \
+ if (tab && tab->callback) \
+ (*tab->callback) args; \
+ else \
+ SETERRNO(EINVAL, LIB_INVARG); \
+ } \
+ else \
+ SETERRNO(EBADF, SS_IVCHAN)
+
int
perlsio_binmode(FILE *fp, int iotype, int mode)
{
#include <sys/mman.h>
#endif
-
+/*
+ * Why is this here - not in perlio.h? RMB
+ */
void PerlIO_debug(const char *fmt, ...)
- __attribute__ ((format(__printf__, 1, 2)));
+ __attribute__format__(__printf__, 1, 2);
void
PerlIO_debug(const char *fmt, ...)
{
if (PerlIOValid(f)) {
PerlIO_funcs *tab = PerlIOBase(f)->tab;
- PerlIO *new;
PerlIO_debug("fdupopen f=%p param=%p\n",(void*)f,(void*)param);
- new = (*tab->Dup)(aTHX_ PerlIO_allocate(aTHX),f,param, flags);
- return new;
- }
- else {
- SETERRNO(EBADF, SS_IVCHAN);
- return NULL;
+ if (tab && tab->Dup)
+ return (*tab->Dup)(aTHX_ PerlIO_allocate(aTHX), f, param, flags);
+ else {
+ return PerlIOBase_dup(aTHX_ PerlIO_allocate(aTHX), f, param, flags);
+ }
}
+ else
+ SETERRNO(EBADF, SS_IVCHAN);
+
+ return NULL;
}
void
}
}
+/* Return as an array the stack of layers on a filehandle. Note that
+ * the stack is returned top-first in the array, and there are three
+ * times as many array elements as there are layers in the stack: the
+ * first element of a layer triplet is the name, the second one is the
+ * arguments, and the third one is the flags. */
+
+AV *
+PerlIO_get_layers(pTHX_ PerlIO *f)
+{
+ AV *av = newAV();
+
+ if (PerlIOValid(f)) {
+ PerlIOl *l = PerlIOBase(f);
+
+ while (l) {
+ SV *name = l->tab && l->tab->name ?
+ newSVpv(l->tab->name, 0) : &PL_sv_undef;
+ SV *arg = l->tab && l->tab->Getarg ?
+ (*l->tab->Getarg)(aTHX_ &l, 0, 0) : &PL_sv_undef;
+ av_push(av, name);
+ av_push(av, arg);
+ av_push(av, newSViv((IV)l->flags));
+ l = l->next;
+ }
+ }
+
+ return av;
+}
+
/*--------------------------------------------------------------------------------------*/
/*
* XS Interface for perl code
} else {
SV *pkgsv = newSVpvn("PerlIO", 6);
SV *layer = newSVpvn(name, len);
- ENTER;
+ CV *cv = get_cv("PerlIO::Layer::NoWarnings", FALSE);
+ ENTER;
SAVEINT(PL_in_load_module);
+ if (cv) {
+ SAVESPTR(PL_warnhook);
+ PL_warnhook = (SV *) cv;
+ }
PL_in_load_module++;
/*
* The two SVs are magically freed by load_module
return sv;
}
+XS(XS_PerlIO__Layer__NoWarnings)
+{
+ /* This is used as a %SIG{__WARN__} handler to supress warnings
+ during loading of layers.
+ */
+ dXSARGS;
+ if (items)
+ PerlIO_debug("warning:%s\n",SvPV_nolen(ST(0)));
+ XSRETURN(0);
+}
+
XS(XS_PerlIO__Layer__find)
{
dXSARGS;
__FILE__);
#endif
newXS("PerlIO::Layer::find", XS_PerlIO__Layer__find, __FILE__);
+ newXS("PerlIO::Layer::NoWarnings", XS_PerlIO__Layer__NoWarnings, __FILE__);
}
PerlIO_funcs *
*f = l;
PerlIO_debug("PerlIO_push f=%p %s %s %p\n", (void*)f, tab->name,
(mode) ? mode : "(Null)", (void*)arg);
- if ((*l->tab->Pushed) (aTHX_ f, mode, arg, tab) != 0) {
+ if (*l->tab->Pushed &&
+ (*l->tab->Pushed) (aTHX_ f, mode, arg, tab) != 0) {
PerlIO_pop(aTHX_ f);
return NULL;
}
/* Pseudo-layer where push does its own stack adjust */
PerlIO_debug("PerlIO_push f=%p %s %s %p\n", (void*)f, tab->name,
(mode) ? mode : "(Null)", (void*)arg);
- if ((*tab->Pushed) (aTHX_ f, mode, arg, tab) != 0) {
- return NULL;
+ if (tab->Pushed &&
+ (*tab->Pushed) (aTHX_ f, mode, arg, tab) != 0) {
+ return NULL;
}
}
return f;
int
PerlIO__close(pTHX_ PerlIO *f)
{
- if (PerlIOValid(f))
- return (*PerlIOBase(f)->tab->Close) (aTHX_ f);
+ if (PerlIOValid(f)) {
+ PerlIO_funcs *tab = PerlIOBase(f)->tab;
+ if (tab && tab->Close)
+ return (*tab->Close)(aTHX_ f);
+ else
+ return PerlIOBase_close(aTHX_ f);
+ }
else {
SETERRNO(EBADF, SS_IVCHAN);
return -1;
int
Perl_PerlIO_close(pTHX_ PerlIO *f)
{
- int code = -1;
- if (PerlIOValid(f)) {
- code = (*PerlIOBase(f)->tab->Close) (aTHX_ f);
- while (*f) {
- PerlIO_pop(aTHX_ f);
- }
+ int code = PerlIO__close(aTHX_ f);
+ while (PerlIOValid(f)) {
+ PerlIO_pop(aTHX_ f);
}
return code;
}
int
Perl_PerlIO_fileno(pTHX_ PerlIO *f)
{
- if (PerlIOValid(f))
- return (*PerlIOBase(f)->tab->Fileno) (aTHX_ f);
- else {
- SETERRNO(EBADF, SS_IVCHAN);
- return -1;
- }
+ Perl_PerlIO_or_Base(f, Fileno, fileno, -1, (aTHX_ f));
}
static const char *
PerlIO_debug("openn(%s,'%s','%s',%d,%x,%o,%p,%d,%p)\n",
tab->name, layers, mode, fd, imode, perm,
(void*)f, narg, (void*)args);
- f = (*tab->Open) (aTHX_ tab, layera, n, mode, fd, imode, perm,
- f, narg, args);
+ if (tab->Open)
+ f = (*tab->Open) (aTHX_ tab, layera, n, mode, fd, imode, perm,
+ f, narg, args);
+ else {
+ SETERRNO(EINVAL, LIB_INVARG);
+ f = NULL;
+ }
if (f) {
if (n + 1 < layera->cur) {
/*
SSize_t
Perl_PerlIO_read(pTHX_ PerlIO *f, void *vbuf, Size_t count)
{
- if (PerlIOValid(f))
- return (*PerlIOBase(f)->tab->Read) (aTHX_ f, vbuf, count);
- else {
- SETERRNO(EBADF, SS_IVCHAN);
- return -1;
- }
+ Perl_PerlIO_or_Base(f, Read, read, -1, (aTHX_ f, vbuf, count));
}
SSize_t
Perl_PerlIO_unread(pTHX_ PerlIO *f, const void *vbuf, Size_t count)
{
- if (PerlIOValid(f))
- return (*PerlIOBase(f)->tab->Unread) (aTHX_ f, vbuf, count);
- else {
- SETERRNO(EBADF, SS_IVCHAN);
- return -1;
- }
+ Perl_PerlIO_or_Base(f, Unread, unread, -1, (aTHX_ f, vbuf, count));
}
SSize_t
Perl_PerlIO_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count)
{
- if (PerlIOValid(f))
- return (*PerlIOBase(f)->tab->Write) (aTHX_ f, vbuf, count);
- else {
- SETERRNO(EBADF, SS_IVCHAN);
- return -1;
- }
+ Perl_PerlIO_or_fail(f, Write, -1, (aTHX_ f, vbuf, count));
}
int
Perl_PerlIO_seek(pTHX_ PerlIO *f, Off_t offset, int whence)
{
- if (PerlIOValid(f))
- return (*PerlIOBase(f)->tab->Seek) (aTHX_ f, offset, whence);
- else {
- SETERRNO(EBADF, SS_IVCHAN);
- return -1;
- }
+ Perl_PerlIO_or_fail(f, Seek, -1, (aTHX_ f, offset, whence));
}
Off_t
Perl_PerlIO_tell(pTHX_ PerlIO *f)
{
- if (PerlIOValid(f))
- return (*PerlIOBase(f)->tab->Tell) (aTHX_ f);
- else {
- SETERRNO(EBADF, SS_IVCHAN);
- return -1;
- }
+ Perl_PerlIO_or_fail(f, Tell, -1, (aTHX_ f));
}
int
if (f) {
if (*f) {
PerlIO_funcs *tab = PerlIOBase(f)->tab;
- if (tab && tab->Flush) {
+
+ if (tab && tab->Flush)
return (*tab->Flush) (aTHX_ f);
- }
- else {
- PerlIO_debug("Cannot flush f=%p :%s\n", (void*)f, tab->name);
- SETERRNO(EBADF, SS_IVCHAN);
- return -1;
- }
+ else
+ return 0; /* If no Flush defined, silently succeed. */
}
else {
PerlIO_debug("Cannot flush f=%p\n", (void*)f);
int
Perl_PerlIO_fill(pTHX_ PerlIO *f)
{
- if (PerlIOValid(f))
- return (*PerlIOBase(f)->tab->Fill) (aTHX_ f);
- else {
- SETERRNO(EBADF, SS_IVCHAN);
- return -1;
- }
+ Perl_PerlIO_or_fail(f, Fill, -1, (aTHX_ f));
}
int
PerlIO_isutf8(PerlIO *f)
{
- if (PerlIOValid(f))
- return (PerlIOBase(f)->flags & PERLIO_F_UTF8) != 0;
- else {
- SETERRNO(EBADF, SS_IVCHAN);
- return -1;
- }
+ if (PerlIOValid(f))
+ return (PerlIOBase(f)->flags & PERLIO_F_UTF8) != 0;
+ else
+ SETERRNO(EBADF, SS_IVCHAN);
+
+ return -1;
}
int
Perl_PerlIO_eof(pTHX_ PerlIO *f)
{
- if (PerlIOValid(f))
- return (*PerlIOBase(f)->tab->Eof) (aTHX_ f);
- else {
- SETERRNO(EBADF, SS_IVCHAN);
- return -1;
- }
+ Perl_PerlIO_or_Base(f, Eof, eof, -1, (aTHX_ f));
}
int
Perl_PerlIO_error(pTHX_ PerlIO *f)
{
- if (PerlIOValid(f))
- return (*PerlIOBase(f)->tab->Error) (aTHX_ f);
- else {
- SETERRNO(EBADF, SS_IVCHAN);
- return -1;
- }
+ Perl_PerlIO_or_Base(f, Error, error, -1, (aTHX_ f));
}
void
Perl_PerlIO_clearerr(pTHX_ PerlIO *f)
{
- if (PerlIOValid(f))
- (*PerlIOBase(f)->tab->Clearerr) (aTHX_ f);
- else
- SETERRNO(EBADF, SS_IVCHAN);
+ Perl_PerlIO_or_Base_void(f, Clearerr, clearerr, (aTHX_ f));
}
void
Perl_PerlIO_setlinebuf(pTHX_ PerlIO *f)
{
- if (PerlIOValid(f))
- (*PerlIOBase(f)->tab->Setlinebuf) (aTHX_ f);
- else
- SETERRNO(EBADF, SS_IVCHAN);
+ Perl_PerlIO_or_Base_void(f, Setlinebuf, setlinebuf, (aTHX_ f));
}
int
PerlIO_has_base(PerlIO *f)
{
- if (PerlIOValid(f)) {
- return (PerlIOBase(f)->tab->Get_base != NULL);
- }
- return 0;
+ if (PerlIOValid(f)) {
+ PerlIO_funcs *tab = PerlIOBase(f)->tab;
+
+ if (tab)
+ return (tab->Get_base != NULL);
+ SETERRNO(EINVAL, LIB_INVARG);
+ }
+ else
+ SETERRNO(EBADF, SS_IVCHAN);
+
+ return 0;
}
int
PerlIO_fast_gets(PerlIO *f)
{
if (PerlIOValid(f) && (PerlIOBase(f)->flags & PERLIO_F_FASTGETS)) {
- PerlIO_funcs *tab = PerlIOBase(f)->tab;
- return (tab->Set_ptrcnt != NULL);
+ PerlIO_funcs *tab = PerlIOBase(f)->tab;
+
+ if (tab)
+ return (tab->Set_ptrcnt != NULL);
+ SETERRNO(EINVAL, LIB_INVARG);
}
+ else
+ SETERRNO(EBADF, SS_IVCHAN);
+
return 0;
}
{
if (PerlIOValid(f)) {
PerlIO_funcs *tab = PerlIOBase(f)->tab;
- return (tab->Get_ptr != NULL && tab->Get_cnt != NULL);
+
+ if (tab)
+ return (tab->Get_ptr != NULL && tab->Get_cnt != NULL);
+ SETERRNO(EINVAL, LIB_INVARG);
}
+ else
+ SETERRNO(EBADF, SS_IVCHAN);
+
return 0;
}
PerlIO_canset_cnt(PerlIO *f)
{
if (PerlIOValid(f)) {
- PerlIOl *l = PerlIOBase(f);
- return (l->tab->Set_ptrcnt != NULL);
+ PerlIO_funcs *tab = PerlIOBase(f)->tab;
+
+ if (tab)
+ return (tab->Set_ptrcnt != NULL);
+ SETERRNO(EINVAL, LIB_INVARG);
}
+ else
+ SETERRNO(EBADF, SS_IVCHAN);
+
return 0;
}
STDCHAR *
Perl_PerlIO_get_base(pTHX_ PerlIO *f)
{
- if (PerlIOValid(f))
- return (*PerlIOBase(f)->tab->Get_base) (aTHX_ f);
- return NULL;
+ Perl_PerlIO_or_fail(f, Get_base, NULL, (aTHX_ f));
}
int
Perl_PerlIO_get_bufsiz(pTHX_ PerlIO *f)
{
- if (PerlIOValid(f))
- return (*PerlIOBase(f)->tab->Get_bufsiz) (aTHX_ f);
- return 0;
+ Perl_PerlIO_or_fail(f, Get_bufsiz, -1, (aTHX_ f));
}
STDCHAR *
Perl_PerlIO_get_ptr(pTHX_ PerlIO *f)
{
- if (PerlIOValid(f)) {
- PerlIO_funcs *tab = PerlIOBase(f)->tab;
- if (tab->Get_ptr == NULL)
- return NULL;
- return (*tab->Get_ptr) (aTHX_ f);
- }
- return NULL;
+ Perl_PerlIO_or_fail(f, Get_ptr, NULL, (aTHX_ f));
}
int
Perl_PerlIO_get_cnt(pTHX_ PerlIO *f)
{
- if (PerlIOValid(f)) {
- PerlIO_funcs *tab = PerlIOBase(f)->tab;
- if (tab->Get_cnt == NULL)
- return 0;
- return (*tab->Get_cnt) (aTHX_ f);
- }
- return 0;
+ Perl_PerlIO_or_fail(f, Get_cnt, -1, (aTHX_ f));
}
void
Perl_PerlIO_set_cnt(pTHX_ PerlIO *f, int cnt)
{
- if (PerlIOValid(f)) {
- (*PerlIOBase(f)->tab->Set_ptrcnt) (aTHX_ f, NULL, cnt);
- }
+ Perl_PerlIO_or_fail_void(f, Set_ptrcnt, (aTHX_ f, NULL, cnt));
}
void
Perl_PerlIO_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, int cnt)
{
- if (PerlIOValid(f)) {
- PerlIO_funcs *tab = PerlIOBase(f)->tab;
- if (tab->Set_ptrcnt == NULL) {
- Perl_croak(aTHX_ "PerlIO buffer snooping abuse");
- }
- (*PerlIOBase(f)->tab->Set_ptrcnt) (aTHX_ f, ptr, cnt);
- }
+ Perl_PerlIO_or_fail_void(f, Set_ptrcnt, (aTHX_ f, ptr, cnt));
}
PerlIO *old, int narg, SV **args)
{
PerlIO_funcs *tab = PerlIO_default_btm();
- return (*tab->Open) (aTHX_ tab, layers, n - 1, mode, fd, imode, perm,
- old, narg, args);
+ if (tab && tab->Open)
+ return (*tab->Open) (aTHX_ tab, layers, n - 1, mode, fd, imode, perm,
+ old, narg, args);
+ SETERRNO(EINVAL, LIB_INVARG);
+ return NULL;
}
PerlIO_funcs PerlIO_raw = {
IV
PerlIOBase_close(pTHX_ PerlIO *f)
{
- IV code = 0;
- PerlIO *n = PerlIONext(f);
- if (PerlIO_flush(f) != 0)
- code = -1;
- if (PerlIOValid(n) && (*PerlIOBase(n)->tab->Close)(aTHX_ n) != 0)
- code = -1;
- PerlIOBase(f)->flags &=
- ~(PERLIO_F_CANREAD | PERLIO_F_CANWRITE | PERLIO_F_OPEN);
+ IV code = -1;
+ if (PerlIOValid(f)) {
+ PerlIO *n = PerlIONext(f);
+ code = PerlIO_flush(f);
+ PerlIOBase(f)->flags &=
+ ~(PERLIO_F_CANREAD | PERLIO_F_CANWRITE | PERLIO_F_OPEN);
+ while (PerlIOValid(n)) {
+ PerlIO_funcs *tab = PerlIOBase(n)->tab;
+ if (tab && tab->Close) {
+ if ((*tab->Close)(aTHX_ n) != 0)
+ code = -1;
+ break;
+ }
+ else {
+ PerlIOBase(n)->flags &=
+ ~(PERLIO_F_CANREAD | PERLIO_F_CANWRITE | PERLIO_F_OPEN);
+ }
+ n = PerlIONext(n);
+ }
+ }
+ else {
+ SETERRNO(EBADF, SS_IVCHAN);
+ }
return code;
}
PerlIO *nexto = PerlIONext(o);
if (PerlIOValid(nexto)) {
PerlIO_funcs *tab = PerlIOBase(nexto)->tab;
- f = (*tab->Dup)(aTHX_ f, nexto, param, flags);
+ if (tab && tab->Dup)
+ f = (*tab->Dup)(aTHX_ f, nexto, param, flags);
+ else
+ f = PerlIOBase_dup(aTHX_ f, nexto, param, flags);
}
if (f) {
PerlIO_funcs *self = PerlIOBase(o)->tab;
- SV *arg = Nullsv;
+ SV *arg;
char buf[8];
PerlIO_debug("PerlIOBase_dup %s f=%p o=%p param=%p\n",
self->name, (void*)f, (void*)o, (void*)param);
- if (self->Getarg) {
- arg = (*self->Getarg)(aTHX_ o,param,flags);
+ if (self->Getarg)
+ arg = (*self->Getarg)(aTHX_ o, param, flags);
+ else {
+ arg = Nullsv;
}
f = PerlIO_push(aTHX_ f, self, PerlIO_modestr(o,buf), arg);
if (arg) {
return PerlIOSelf(f, PerlIOUnix)->fd;
}
+static void
+PerlIOUnix_setfd(pTHX_ PerlIO *f, int fd, int imode)
+{
+ PerlIOUnix *s = PerlIOSelf(f, PerlIOUnix);
+#if defined(WIN32)
+ Stat_t st;
+ if (PerlLIO_fstat(fd, &st) == 0) {
+ if (!S_ISREG(st.st_mode)) {
+ PerlIO_debug("%d is not regular file\n",fd);
+ PerlIOBase(f)->flags |= PERLIO_F_NOTREG;
+ }
+ else {
+ PerlIO_debug("%d _is_ a regular file\n",fd);
+ }
+ }
+#endif
+ s->fd = fd;
+ s->oflags = imode;
+ PerlIOUnix_refcnt_inc(fd);
+}
+
IV
PerlIOUnix_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab)
{
IV code = PerlIOBase_pushed(aTHX_ f, mode, arg, tab);
- PerlIOUnix *s = PerlIOSelf(f, PerlIOUnix);
if (*PerlIONext(f)) {
/* We never call down so do any pending stuff now */
PerlIO_flush(PerlIONext(f));
- s->fd = PerlIO_fileno(PerlIONext(f));
/*
* XXX could (or should) we retrieve the oflags from the open file
* handle rather than believing the "mode" we are passed in? XXX
* Should the value on NULL mode be 0 or -1?
*/
- s->oflags = mode ? PerlIOUnix_oflags(mode) : -1;
+ PerlIOUnix_setfd(aTHX_ f, PerlIO_fileno(PerlIONext(f)),
+ mode ? PerlIOUnix_oflags(mode) : -1);
}
PerlIOBase(f)->flags |= PERLIO_F_OPEN;
+
return code;
}
}
}
if (fd >= 0) {
- PerlIOUnix *s;
if (*mode == 'I')
mode++;
if (!f) {
return NULL;
}
}
- s = PerlIOSelf(f, PerlIOUnix);
- s->fd = fd;
- s->oflags = imode;
+ PerlIOUnix_setfd(aTHX_ f, fd, imode);
PerlIOBase(f)->flags |= PERLIO_F_OPEN;
- PerlIOUnix_refcnt_inc(fd);
return f;
}
else {
f = PerlIOBase_dup(aTHX_ f, o, param, flags);
if (f) {
/* If all went well overwrite fd in dup'ed lay with the dup()'ed fd */
- PerlIOUnix *s = PerlIOSelf(f, PerlIOUnix);
- s->fd = fd;
- PerlIOUnix_refcnt_inc(fd);
+ PerlIOUnix_setfd(aTHX_ f, fd, os->oflags);
return f;
}
}
while (1) {
SSize_t len = PerlLIO_read(fd, vbuf, count);
if (len >= 0 || errno != EINTR) {
- if (len < 0)
- PerlIOBase(f)->flags |= PERLIO_F_ERROR;
- else if (len == 0 && count != 0)
+ if (len < 0) {
+ if (errno != EAGAIN) {
+ PerlIOBase(f)->flags |= PERLIO_F_ERROR;
+ }
+ }
+ else if (len == 0 && count != 0) {
PerlIOBase(f)->flags |= PERLIO_F_EOF;
+ SETERRNO(0,0);
+ }
return len;
}
PERL_ASYNC_CHECK();
while (1) {
SSize_t len = PerlLIO_write(fd, vbuf, count);
if (len >= 0 || errno != EINTR) {
- if (len < 0)
- PerlIOBase(f)->flags |= PERLIO_F_ERROR;
+ if (len < 0) {
+ if (errno != EAGAIN) {
+ PerlIOBase(f)->flags |= PERLIO_F_ERROR;
+ }
+ }
return len;
}
PERL_ASYNC_CHECK();
IV
PerlIOUnix_seek(pTHX_ PerlIO *f, Off_t offset, int whence)
{
- Off_t new =
- PerlLIO_lseek(PerlIOSelf(f, PerlIOUnix)->fd, offset, whence);
+ int fd = PerlIOSelf(f, PerlIOUnix)->fd;
+ Off_t new;
+ if (PerlIOBase(f)->flags & PERLIO_F_NOTREG) {
+#ifdef ESPIPE
+ SETERRNO(ESPIPE, LIB_INVARG);
+#else
+ SETERRNO(EINVAL, LIB_INVARG);
+#endif
+ return -1;
+ }
+ new = PerlLIO_lseek(fd, offset, whence);
+ if (new == (Off_t) - 1)
+ {
+ return -1;
+ }
PerlIOBase(f)->flags &= ~PERLIO_F_EOF;
- return (new == (Off_t) - 1) ? -1 : 0;
+ return 0;
}
Off_t
return f;
}
+static int
+PerlIOStdio_invalidate_fileno(pTHX_ FILE *f)
+{
+ /* XXX this could use PerlIO_canset_fileno() and
+ * PerlIO_set_fileno() support from Configure
+ */
+# if defined(__GLIBC__)
+ /* There may be a better way for GLIBC:
+ - libio.h defines a flag to not close() on cleanup
+ */
+ f->_fileno = -1;
+ return 1;
+# elif defined(__sun__)
+# if defined(_LP64)
+ /* On solaris, if _LP64 is defined, the FILE structure is this:
+ *
+ * struct FILE {
+ * long __pad[16];
+ * };
+ *
+ * It turns out that the fd is stored in the top 32 bits of
+ * file->__pad[4]. The lower 32 bits contain flags. file->pad[5] appears
+ * to contain a pointer or offset into another structure. All the
+ * remaining fields are zero.
+ *
+ * We set the top bits to -1 (0xFFFFFFFF).
+ */
+ f->__pad[4] |= 0xffffffff00000000L;
+ assert(fileno(f) == 0xffffffff);
+# else /* !defined(_LP64) */
+ /* _file is just a unsigned char :-(
+ Not clear why we dup() rather than using -1
+ even if that would be treated as 0xFF - so will
+ a dup fail ...
+ */
+ f->_file = PerlLIO_dup(fileno(f));
+# endif /* defined(_LP64) */
+ return 1;
+# elif defined(__hpux)
+ f->__fileH = 0xff;
+ f->__fileL = 0xff;
+ return 1;
+ /* Next one ->_file seems to be a reasonable fallback, i.e. if
+ your platform does not have special entry try this one.
+ [For OSF only have confirmation for Tru64 (alpha)
+ but assume other OSFs will be similar.]
+ */
+# elif defined(_AIX) || defined(__osf__) || defined(__irix__)
+ f->_file = -1;
+ return 1;
+# elif defined(__FreeBSD__)
+ /* There may be a better way on FreeBSD:
+ - we could insert a dummy func in the _close function entry
+ f->_close = (int (*)(void *)) dummy_close;
+ */
+ f->_file = -1;
+ return 1;
+# elif defined(__CYGWIN__)
+ /* There may be a better way on CYGWIN:
+ - we could insert a dummy func in the _close function entry
+ f->_close = (int (*)(void *)) dummy_close;
+ */
+ f->_file = -1;
+ return 1;
+# elif defined(WIN32)
+# if defined(__BORLANDC__)
+ f->fd = PerlLIO_dup(fileno(f));
+# elif defined(UNDER_CE)
+ /* WIN_CE does not have access to FILE internals, it hardly has FILE
+ structure at all
+ */
+# else
+ f->_file = -1;
+# endif
+ return 1;
+# else
+#if 0
+ /* Sarathy's code did this - we fall back to a dup/dup2 hack
+ (which isn't thread safe) instead
+ */
+# error "Don't know how to set FILE.fileno on your platform"
+#endif
+ return 0;
+# endif
+}
+
IV
PerlIOStdio_close(pTHX_ PerlIO *f)
{
-#ifdef SOCKS5_VERSION_NAME
- int optval;
- Sock_size_t optlen = sizeof(int);
-#endif
FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
if (!stdio) {
errno = EBADF;
}
else {
int fd = fileno(stdio);
- int dupfd = -1;
- IV result;
+ int socksfd = 0;
+ int invalidate = 0;
+ IV result = 0;
+ int saveerr = 0;
+ int dupfd = 0;
+#ifdef SOCKS5_VERSION_NAME
+ /* Socks lib overrides close() but stdio isn't linked to
+ that library (though we are) - so we must call close()
+ on sockets on stdio's behalf.
+ */
+ int optval;
+ Sock_size_t optlen = sizeof(int);
+ if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *) &optval, &optlen) == 0) {
+ socksfd = 1;
+ invalidate = 1;
+ }
+#endif
if (PerlIOUnix_refcnt_dec(fd) > 0) {
/* File descriptor still in use */
- if (fd < 3) {
- /* For STD* handles don't close the stdio at all */
+ invalidate = 1;
+ socksfd = 0;
+ }
+ if (invalidate) {
+ /* For STD* handles don't close the stdio at all
+ this is because we have shared the FILE * too
+ */
+ if (stdio == stdin) {
+ /* Some stdios are buggy fflush-ing inputs */
+ return 0;
+ }
+ else if (stdio == stdout || stdio == stderr) {
return PerlIO_flush(f);
}
- else {
- /* Tricky - must fclose(stdio) to free memory but not close(fd) */
+ /* Tricky - must fclose(stdio) to free memory but not close(fd)
+ Use Sarathy's trick from maint-5.6 to invalidate the
+ fileno slot of the FILE *
+ */
+ result = PerlIO_flush(f);
+ saveerr = errno;
+ if (!(invalidate = PerlIOStdio_invalidate_fileno(aTHX_ stdio))) {
dupfd = PerlLIO_dup(fd);
}
- }
- result = (
-#ifdef SOCKS5_VERSION_NAME
- (getsockopt
- (PerlIO_fileno(f), SOL_SOCKET, SO_TYPE, (void *) &optval,
- &optlen) <
- 0) ? PerlSIO_fclose(stdio) : close(PerlIO_fileno(f))
-#else
- PerlSIO_fclose(stdio)
-#endif
- );
- if (dupfd >= 0) {
- /* We need to restore fd from the saved copy */
- if (PerlLIO_dup2(dupfd,fd) != fd)
- result = -1;
- if (PerlLIO_close(dupfd) != 0)
- result = -1;
+ }
+ result = PerlSIO_fclose(stdio);
+ /* We treat error from stdio as success if we invalidated
+ errno may NOT be expected EBADF
+ */
+ if (invalidate && result != 0) {
+ errno = saveerr;
+ result = 0;
+ }
+ if (socksfd) {
+ /* in SOCKS case let close() determine return value */
+ result = close(fd);
+ }
+ if (dupfd) {
+ PerlLIO_dup2(dupfd,fd);
+ PerlLIO_close(dupfd);
}
return result;
- }
-
+ }
}
-
-
SSize_t
PerlIOStdio_read(pTHX_ PerlIO *f, void *vbuf, Size_t count)
{
FILE *s = PerlIOSelf(f, PerlIOStdio)->stdio;
SSize_t got = 0;
- if (count == 1) {
- STDCHAR *buf = (STDCHAR *) vbuf;
- /*
- * Perl is expecting PerlIO_getc() to fill the buffer Linux's
- * stdio does not do that for fread()
- */
- int ch = PerlSIO_fgetc(s);
- if (ch != EOF) {
- *buf = ch;
- got = 1;
+ for (;;) {
+ if (count == 1) {
+ STDCHAR *buf = (STDCHAR *) vbuf;
+ /*
+ * Perl is expecting PerlIO_getc() to fill the buffer Linux's
+ * stdio does not do that for fread()
+ */
+ int ch = PerlSIO_fgetc(s);
+ if (ch != EOF) {
+ *buf = ch;
+ got = 1;
+ }
}
+ else
+ got = PerlSIO_fread(vbuf, 1, count, s);
+ if (got >= 0 || errno != EINTR)
+ break;
+ PERL_ASYNC_CHECK();
+ SETERRNO(0,0); /* just in case */
}
- else
- got = PerlSIO_fread(vbuf, 1, count, s);
return got;
}
SSize_t
PerlIOStdio_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count)
{
- return PerlSIO_fwrite(vbuf, 1, count,
- PerlIOSelf(f, PerlIOStdio)->stdio);
+ SSize_t got;
+ for (;;) {
+ got = PerlSIO_fwrite(vbuf, 1, count,
+ PerlIOSelf(f, PerlIOStdio)->stdio);
+ if (got >= 0 || errno != EINTR)
+ break;
+ PERL_ASYNC_CHECK();
+ SETERRNO(0,0); /* just in case */
+ }
+ return got;
}
IV
#ifdef USE_STDIO_PTR
PerlIOStdio_get_ptr,
PerlIOStdio_get_cnt,
-#if (defined(STDIO_PTR_LVALUE) && (defined(STDIO_CNT_LVALUE) || defined(STDIO_PTR_LVAL_SETS_CNT)))
- PerlIOStdio_set_ptrcnt
-#else /* STDIO_PTR_LVALUE */
- NULL
-#endif /* STDIO_PTR_LVALUE */
-#else /* USE_STDIO_PTR */
+# if defined(HAS_FAST_STDIO) && defined(USE_FAST_STDIO)
+ PerlIOStdio_set_ptrcnt,
+# else
+ NULL,
+# endif /* HAS_FAST_STDIO && USE_FAST_STDIO */
+#else
NULL,
NULL,
- NULL
-#endif /* USE_STDIO_PTR */
+ NULL,
+#endif /* USE_STDIO_PTR */
};
/* Note that calls to PerlIO_exportFILE() are reversed using
#ifdef PERLIO_USING_CRLF
# ifdef PERLIO_IS_BINMODE_FD
if (PERLIO_IS_BINMODE_FD(fd))
- PerlIO_binmode(f, '<'/*not used*/, O_BINARY, Nullch);
+ PerlIO_binmode(aTHX_ f, '<'/*not used*/, O_BINARY, Nullch);
else
# endif
/*
* b->posn is file position where b->buf was read, or will be written
*/
Off_t posn = b->posn;
- if ((PerlIOBase(f)->flags & PERLIO_F_APPEND) &&
+ if ((PerlIOBase(f)->flags & PERLIO_F_APPEND) &&
(PerlIOBase(f)->flags & PERLIO_F_WRBUF)) {
#if 1
/* As O_APPEND files are normally shared in some sense it is better
*/
PerlIO_flush(f);
#else
- /* when file is NOT shared then this is sufficient */
+ /* when file is NOT shared then this is sufficient */
PerlIO_seek(PerlIONext(f),0, SEEK_END);
#endif
posn = b->posn = PerlIO_tell(PerlIONext(f));
PerlIO *
PerlIO_tmpfile(void)
{
- /*
- * I have no idea how portable mkstemp() is ...
- */
-#if defined(WIN32) || !defined(HAVE_MKSTEMP)
- dTHX;
- PerlIO *f = NULL;
- FILE *stdio = PerlSIO_tmpfile();
- if (stdio) {
- if ((f = PerlIO_push(aTHX_(PerlIO_allocate(aTHX)), &PerlIO_stdio, "w+", Nullsv))) {
- PerlIOStdio *s = PerlIOSelf(f, PerlIOStdio);
- s->stdio = stdio;
- }
- }
- return f;
-#else
- dTHX;
- SV *sv = newSVpv("/tmp/PerlIO_XXXXXX", 0);
- int fd = mkstemp(SvPVX(sv));
- PerlIO *f = NULL;
- if (fd >= 0) {
- f = PerlIO_fdopen(fd, "w+");
- if (f) {
- PerlIOBase(f)->flags |= PERLIO_F_TEMP;
- }
- PerlLIO_unlink(SvPVX(sv));
- SvREFCNT_dec(sv);
- }
- return f;
-#endif
+ dTHX;
+ PerlIO *f = NULL;
+ int fd = -1;
+ SV *sv = Nullsv;
+ GV *gv = gv_fetchpv("File::Temp::tempfile", FALSE, SVt_PVCV);
+
+ if (!gv) {
+ ENTER;
+ Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT,
+ newSVpvn("File::Temp", 10), Nullsv, Nullsv, Nullsv);
+ gv = gv_fetchpv("File::Temp::tempfile", FALSE, SVt_PVCV);
+ GvIMPORTED_CV_on(gv);
+ LEAVE;
+ }
+
+ if (gv && GvCV(gv)) {
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ PUTBACK;
+ if (call_sv((SV*)GvCV(gv), G_SCALAR)) {
+ GV *gv = (GV*)SvRV(newSVsv(*PL_stack_sp--));
+ IO *io = gv ? GvIO(gv) : 0;
+ fd = io ? PerlIO_fileno(IoIFP(io)) : -1;
+ }
+ SPAGAIN;
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+ }
+
+ if (fd >= 0) {
+ f = PerlIO_fdopen(fd, "w+");
+ if (sv) {
+ if (f)
+ PerlIOBase(f)->flags |= PERLIO_F_TEMP;
+ PerlLIO_unlink(SvPVX(sv));
+ SvREFCNT_dec(sv);
+ }
+ }
+
+ return f;
}
#undef HAS_FSETPOS