This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Garbage collection.
[perl5.git] / perlio.c
index b232685..7e5a555 100644 (file)
--- a/perlio.c
+++ b/perlio.c
@@ -89,6 +89,7 @@ perlsio_binmode(FILE *fp, int iotype, int mode)
 #  endif
 #else
 #  if defined(USEMYBINMODE)
+    dTHX;
     if (my_binmode(fp, iotype, mode) != FALSE)
        return 1;
     else
@@ -447,7 +448,7 @@ PerlIO_allocate(pTHX)
 PerlIO *
 PerlIO_fdupopen(pTHX_ PerlIO *f, CLONE_PARAMS *param, int flags)
 {
-    if (f && *f) {
+    if (PerlIOValid(f)) {
        PerlIO_funcs *tab = PerlIOBase(f)->tab;
        PerlIO *new;
        PerlIO_debug("fdupopen f=%p param=%p\n",(void*)f,(void*)param);
@@ -1003,7 +1004,7 @@ PerlIORaw_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg)
     /*
      * Pop back to bottom layer
      */
-    if (f && *f) {
+    if (PerlIOValid(f)) {
        PerlIO_flush(f);
        while (!(PerlIOBase(f)->tab->kind & PERLIO_K_RAW)) {
            if (*PerlIONext(f)) {
@@ -1071,32 +1072,79 @@ PerlIO_binmode(pTHX_ PerlIO *f, int iotype, int mode, const char *names)
     PerlIO_debug("PerlIO_binmode f=%p %s %c %x %s\n",
                 (void*)f, PerlIOBase(f)->tab->name, iotype, mode,
                 (names) ? names : "(Null)");
-    /* Can't flush if switching encodings. */
-    if (!(names && memEQ(names, ":encoding(", 10))) {
-        PerlIO_flush(f);
+    if (names) {
+       /* Do not flush etc. if (e.g.) switching encodings.
+          if a pushed layer knows it needs to flush lower layers
+          (for example :unix which is never going to call them)
+          it can do the flush when it is pushed.
+        */
+       return PerlIO_apply_layers(aTHX_ f, NULL, names) == 0 ? TRUE : FALSE;
+    }
+    else {
+       /* FIXME?: Looking down the layer stack seems wrong,
+          but is a way of reaching past (say) an encoding layer
+          to flip CRLF-ness of the layer(s) below
+        */
 #ifdef PERLIO_USING_CRLF
-       if (!names && (mode & O_BINARY)) {
-           PerlIO *top = f;
-           while (*top) {
-               if (PerlIOBase(top)->tab == &PerlIO_crlf) {
-                 PerlIOBase(top)->flags &= ~PERLIO_F_CRLF;
-                 break;
+       /* Legacy binmode only has meaning if O_TEXT has a value distinct from
+          O_BINARY so we can look for it in mode.
+        */
+       if (!(mode & O_BINARY)) {
+           /* Text mode */
+           while (*f) {
+               /* Perhaps we should turn on bottom-most aware layer
+                  e.g. Ilya's idea that UNIX TTY could serve
+                */
+               if (PerlIOBase(f)->tab->kind & PERLIO_K_CANCRLF) {
+                   if (!(PerlIOBase(f)->flags & PERLIO_F_CRLF)) {
+                       /* Not in text mode - flush any pending stuff and flip it */
+                       PerlIO_flush(f);
+                       PerlIOBase(f)->flags |= PERLIO_F_CRLF;
+                   }
+                   /* Only need to turn it on in one layer so we are done */
+                   return TRUE;
                }
-               top = PerlIONext(top);
-               PerlIO_flush(top);
+               f = PerlIONext(f);
            }
+           /* Not finding a CRLF aware layer presumably means we are binary
+              which is not what was requested - so we failed
+              We _could_ push :crlf layer but so could caller
+            */
+           return FALSE;
        }
 #endif
+       /* Either asked for BINMODE or that is normal on this platform
+          see if any CRLF aware layers are present and turn off the flag
+          and possibly remove layer.
+        */
+       while (*f) {
+           if (PerlIOBase(f)->tab->kind & PERLIO_K_CANCRLF) {
+               if ((PerlIOBase(f)->flags & PERLIO_F_CRLF)) {
+                   /* In text mode - flush any pending stuff and flip it */
+                   PerlIO_flush(f);
+                   PerlIOBase(f)->flags &= ~PERLIO_F_CRLF;
+#ifndef PERLIO_USING_CRLF
+                   /* CRLF is unusual case - if this is just the :crlf layer pop it */
+                   if (PerlIOBase(f)->tab == &PerlIO_crlf) {
+                       PerlIO_pop(aTHX_ f);
+                   }
+#endif
+                   /* Normal case is only one layer doing this, so exit on first
+                      abnormal case can always do multiple binmode calls
+                    */
+                   return TRUE;
+               }
+           }
+           f = PerlIONext(f);
+       }
+       return TRUE;
     }
-    return PerlIO_apply_layers(aTHX_ f, NULL, names) == 0 ? TRUE : FALSE;
 }
 
-#undef PerlIO__close
 int
-PerlIO__close(PerlIO *f)
+PerlIO__close(pTHX_ PerlIO *f)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        return (*PerlIOBase(f)->tab->Close) (aTHX_ f);
     else {
        SETERRNO(EBADF, SS$_IVCHAN);
@@ -1104,13 +1152,11 @@ PerlIO__close(PerlIO *f)
     }
 }
 
-#undef PerlIO_close
 int
-PerlIO_close(PerlIO *f)
+Perl_PerlIO_close(pTHX_ PerlIO *f)
 {
-    dTHX;
     int code = -1;
-    if (f && *f) {
+    if (PerlIOValid(f)) {
        code = (*PerlIOBase(f)->tab->Close) (aTHX_ f);
        while (*f) {
            PerlIO_pop(aTHX_ f);
@@ -1119,12 +1165,10 @@ PerlIO_close(PerlIO *f)
     return code;
 }
 
-#undef PerlIO_fileno
 int
-PerlIO_fileno(PerlIO *f)
+Perl_PerlIO_fileno(pTHX_ PerlIO *f)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        return (*PerlIOBase(f)->tab->Fileno) (aTHX_ f);
     else {
        SETERRNO(EBADF, SS$_IVCHAN);
@@ -1252,7 +1296,7 @@ PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd,
        PerlIO_list_t *layera = NULL;
        IV n;
        PerlIO_funcs *tab = NULL;
-       if (f && *f) {
+       if (PerlIOValid(f)) {
            /*
             * This is "reopen" - it is not tested as perl does not use it
             * yet
@@ -1260,9 +1304,9 @@ PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd,
            PerlIOl *l = *f;
            layera = PerlIO_list_alloc(aTHX);
            while (l) {
-               SV *arg =
-                   (l->tab->Getarg) ? (*l->tab->
-                                       Getarg) (aTHX_ &l, NULL, 0) : &PL_sv_undef;
+               SV *arg = (l->tab->Getarg)
+                       ? (*l->tab->Getarg) (aTHX_ &l, NULL, 0)
+                       : &PL_sv_undef;
                PerlIO_list_push(aTHX_ layera, l->tab, arg);
                l = *PerlIONext(&l);
            }
@@ -1313,38 +1357,10 @@ PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd,
 }
 
 
-#undef PerlIO_fdopen
-PerlIO *
-PerlIO_fdopen(int fd, const char *mode)
-{
-    dTHX;
-    return PerlIO_openn(aTHX_ Nullch, mode, fd, 0, 0, NULL, 0, NULL);
-}
-
-#undef PerlIO_open
-PerlIO *
-PerlIO_open(const char *path, const char *mode)
-{
-    dTHX;
-    SV *name = sv_2mortal(newSVpvn(path, strlen(path)));
-    return PerlIO_openn(aTHX_ Nullch, mode, -1, 0, 0, NULL, 1, &name);
-}
-
-#undef PerlIO_reopen
-PerlIO *
-PerlIO_reopen(const char *path, const char *mode, PerlIO *f)
-{
-    dTHX;
-    SV *name = sv_2mortal(newSVpvn(path, strlen(path)));
-    return PerlIO_openn(aTHX_ Nullch, mode, -1, 0, 0, f, 1, &name);
-}
-
-#undef PerlIO_read
 SSize_t
-PerlIO_read(PerlIO *f, void *vbuf, Size_t count)
+Perl_PerlIO_read(pTHX_ PerlIO *f, void *vbuf, Size_t count)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        return (*PerlIOBase(f)->tab->Read) (aTHX_ f, vbuf, count);
     else {
        SETERRNO(EBADF, SS$_IVCHAN);
@@ -1352,12 +1368,10 @@ PerlIO_read(PerlIO *f, void *vbuf, Size_t count)
     }
 }
 
-#undef PerlIO_unread
 SSize_t
-PerlIO_unread(PerlIO *f, const void *vbuf, Size_t count)
+Perl_PerlIO_unread(pTHX_ PerlIO *f, const void *vbuf, Size_t count)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        return (*PerlIOBase(f)->tab->Unread) (aTHX_ f, vbuf, count);
     else {
        SETERRNO(EBADF, SS$_IVCHAN);
@@ -1365,12 +1379,10 @@ PerlIO_unread(PerlIO *f, const void *vbuf, Size_t count)
     }
 }
 
-#undef PerlIO_write
 SSize_t
-PerlIO_write(PerlIO *f, const void *vbuf, Size_t count)
+Perl_PerlIO_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        return (*PerlIOBase(f)->tab->Write) (aTHX_ f, vbuf, count);
     else {
        SETERRNO(EBADF, SS$_IVCHAN);
@@ -1378,12 +1390,10 @@ PerlIO_write(PerlIO *f, const void *vbuf, Size_t count)
     }
 }
 
-#undef PerlIO_seek
 int
-PerlIO_seek(PerlIO *f, Off_t offset, int whence)
+Perl_PerlIO_seek(pTHX_ PerlIO *f, Off_t offset, int whence)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        return (*PerlIOBase(f)->tab->Seek) (aTHX_ f, offset, whence);
     else {
        SETERRNO(EBADF, SS$_IVCHAN);
@@ -1391,12 +1401,10 @@ PerlIO_seek(PerlIO *f, Off_t offset, int whence)
     }
 }
 
-#undef PerlIO_tell
 Off_t
-PerlIO_tell(PerlIO *f)
+Perl_PerlIO_tell(pTHX_ PerlIO *f)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        return (*PerlIOBase(f)->tab->Tell) (aTHX_ f);
     else {
        SETERRNO(EBADF, SS$_IVCHAN);
@@ -1404,11 +1412,9 @@ PerlIO_tell(PerlIO *f)
     }
 }
 
-#undef PerlIO_flush
 int
-PerlIO_flush(PerlIO *f)
+Perl_PerlIO_flush(pTHX_ PerlIO *f)
 {
-    dTHX;
     if (f) {
        if (*f) {
            PerlIO_funcs *tab = PerlIOBase(f)->tab;
@@ -1469,12 +1475,10 @@ PerlIOBase_flush_linebuf(pTHX)
     }
 }
 
-#undef PerlIO_fill
 int
-PerlIO_fill(PerlIO *f)
+Perl_PerlIO_fill(pTHX_ PerlIO *f)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        return (*PerlIOBase(f)->tab->Fill) (aTHX_ f);
     else {
        SETERRNO(EBADF, SS$_IVCHAN);
@@ -1482,11 +1486,10 @@ PerlIO_fill(PerlIO *f)
     }
 }
 
-#undef PerlIO_isutf8
 int
 PerlIO_isutf8(PerlIO *f)
 {
-    if (f && *f)
+    if (PerlIOValid(f))
        return (PerlIOBase(f)->flags & PERLIO_F_UTF8) != 0;
     else {
        SETERRNO(EBADF, SS$_IVCHAN);
@@ -1494,12 +1497,10 @@ PerlIO_isutf8(PerlIO *f)
     }
 }
 
-#undef PerlIO_eof
 int
-PerlIO_eof(PerlIO *f)
+Perl_PerlIO_eof(pTHX_ PerlIO *f)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        return (*PerlIOBase(f)->tab->Eof) (aTHX_ f);
     else {
        SETERRNO(EBADF, SS$_IVCHAN);
@@ -1507,12 +1508,10 @@ PerlIO_eof(PerlIO *f)
     }
 }
 
-#undef PerlIO_error
 int
-PerlIO_error(PerlIO *f)
+Perl_PerlIO_error(pTHX_ PerlIO *f)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        return (*PerlIOBase(f)->tab->Error) (aTHX_ f);
     else {
        SETERRNO(EBADF, SS$_IVCHAN);
@@ -1520,131 +1519,121 @@ PerlIO_error(PerlIO *f)
     }
 }
 
-#undef PerlIO_clearerr
 void
-PerlIO_clearerr(PerlIO *f)
+Perl_PerlIO_clearerr(pTHX_ PerlIO *f)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        (*PerlIOBase(f)->tab->Clearerr) (aTHX_ f);
     else
        SETERRNO(EBADF, SS$_IVCHAN);
 }
 
-#undef PerlIO_setlinebuf
 void
-PerlIO_setlinebuf(PerlIO *f)
+Perl_PerlIO_setlinebuf(pTHX_ PerlIO *f)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        (*PerlIOBase(f)->tab->Setlinebuf) (aTHX_ f);
     else
        SETERRNO(EBADF, SS$_IVCHAN);
 }
 
-#undef PerlIO_has_base
 int
 PerlIO_has_base(PerlIO *f)
 {
-    if (f && *f) {
+    if (PerlIOValid(f)) {
        return (PerlIOBase(f)->tab->Get_base != NULL);
     }
     return 0;
 }
 
-#undef PerlIO_fast_gets
 int
 PerlIO_fast_gets(PerlIO *f)
 {
-    if (f && *f && (PerlIOBase(f)->flags & PERLIO_F_FASTGETS)) {
+    if (PerlIOValid(f) && (PerlIOBase(f)->flags & PERLIO_F_FASTGETS)) {
        PerlIO_funcs *tab = PerlIOBase(f)->tab;
        return (tab->Set_ptrcnt != NULL);
     }
     return 0;
 }
 
-#undef PerlIO_has_cntptr
 int
 PerlIO_has_cntptr(PerlIO *f)
 {
-    if (f && *f) {
+    if (PerlIOValid(f)) {
        PerlIO_funcs *tab = PerlIOBase(f)->tab;
        return (tab->Get_ptr != NULL && tab->Get_cnt != NULL);
     }
     return 0;
 }
 
-#undef PerlIO_canset_cnt
 int
 PerlIO_canset_cnt(PerlIO *f)
 {
-    if (f && *f) {
+    if (PerlIOValid(f)) {
        PerlIOl *l = PerlIOBase(f);
        return (l->tab->Set_ptrcnt != NULL);
     }
     return 0;
 }
 
-#undef PerlIO_get_base
 STDCHAR *
-PerlIO_get_base(PerlIO *f)
+Perl_PerlIO_get_base(pTHX_ PerlIO *f)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        return (*PerlIOBase(f)->tab->Get_base) (aTHX_ f);
     return NULL;
 }
 
-#undef PerlIO_get_bufsiz
 int
-PerlIO_get_bufsiz(PerlIO *f)
+Perl_PerlIO_get_bufsiz(pTHX_ PerlIO *f)
 {
-    dTHX;
-    if (f && *f)
+    if (PerlIOValid(f))
        return (*PerlIOBase(f)->tab->Get_bufsiz) (aTHX_ f);
     return 0;
 }
 
-#undef PerlIO_get_ptr
 STDCHAR *
-PerlIO_get_ptr(PerlIO *f)
+Perl_PerlIO_get_ptr(pTHX_ PerlIO *f)
 {
-    dTHX;
-    PerlIO_funcs *tab = PerlIOBase(f)->tab;
-    if (tab->Get_ptr == NULL)
-       return NULL;
-    return (*tab->Get_ptr) (aTHX_ 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;
 }
 
-#undef PerlIO_get_cnt
 int
-PerlIO_get_cnt(PerlIO *f)
+Perl_PerlIO_get_cnt(pTHX_ PerlIO *f)
 {
-    dTHX;
-    PerlIO_funcs *tab = PerlIOBase(f)->tab;
-    if (tab->Get_cnt == NULL)
-       return 0;
-    return (*tab->Get_cnt) (aTHX_ 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;
 }
 
-#undef PerlIO_set_cnt
 void
-PerlIO_set_cnt(PerlIO *f, int cnt)
+Perl_PerlIO_set_cnt(pTHX_ PerlIO *f, int cnt)
 {
-    dTHX;
-    (*PerlIOBase(f)->tab->Set_ptrcnt) (aTHX_ f, NULL, cnt);
+    if (PerlIOValid(f)) {
+       (*PerlIOBase(f)->tab->Set_ptrcnt) (aTHX_ f, NULL, cnt);
+    }
 }
 
-#undef PerlIO_set_ptrcnt
 void
-PerlIO_set_ptrcnt(PerlIO *f, STDCHAR * ptr, int cnt)
+Perl_PerlIO_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, int cnt)
 {
-    dTHX;
-    PerlIO_funcs *tab = PerlIOBase(f)->tab;
-    if (tab->Set_ptrcnt == NULL) {
-       Perl_croak(aTHX_ "PerlIO buffer snooping abuse");
+    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);
     }
-    (*PerlIOBase(f)->tab->Set_ptrcnt) (aTHX_ f, ptr, cnt);
 }
 
 /*--------------------------------------------------------------------------------------*/
@@ -1655,7 +1644,7 @@ PerlIO_set_ptrcnt(PerlIO *f, STDCHAR * ptr, int cnt)
 IV
 PerlIOUtf8_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg)
 {
-    if (PerlIONext(f)) {
+    if (*PerlIONext(f)) {
        PerlIO_funcs *tab = PerlIOBase(f)->tab;
        PerlIO_pop(aTHX_ f);
        if (tab->kind & PERLIO_K_UTF8)
@@ -1769,7 +1758,7 @@ PerlIO_funcs PerlIO_raw = {
 IV
 PerlIOBase_fileno(pTHX_ PerlIO *f)
 {
-    return PerlIO_fileno(PerlIONext(f));
+    return PerlIOValid(f) ? PerlIO_fileno(PerlIONext(f)) : -1;
 }
 
 char *
@@ -1932,7 +1921,7 @@ PerlIOBase_close(pTHX_ PerlIO *f)
     PerlIO *n = PerlIONext(f);
     if (PerlIO_flush(f) != 0)
        code = -1;
-    if (n && *n && (*PerlIOBase(n)->tab->Close)(aTHX_ n) != 0)
+    if (PerlIOValid(n) && (*PerlIOBase(n)->tab->Close)(aTHX_ n) != 0)
        code = -1;
     PerlIOBase(f)->flags &=
        ~(PERLIO_F_CANREAD | PERLIO_F_CANWRITE | PERLIO_F_OPEN);
@@ -1942,7 +1931,7 @@ PerlIOBase_close(pTHX_ PerlIO *f)
 IV
 PerlIOBase_eof(pTHX_ PerlIO *f)
 {
-    if (f && *f) {
+    if (PerlIOValid(f)) {
        return (PerlIOBase(f)->flags & PERLIO_F_EOF) != 0;
     }
     return 1;
@@ -1951,7 +1940,7 @@ PerlIOBase_eof(pTHX_ PerlIO *f)
 IV
 PerlIOBase_error(pTHX_ PerlIO *f)
 {
-    if (f && *f) {
+    if (PerlIOValid(f)) {
        return (PerlIOBase(f)->flags & PERLIO_F_ERROR) != 0;
     }
     return 1;
@@ -1960,10 +1949,10 @@ PerlIOBase_error(pTHX_ PerlIO *f)
 void
 PerlIOBase_clearerr(pTHX_ PerlIO *f)
 {
-    if (f && *f) {
+    if (PerlIOValid(f)) {
        PerlIO *n = PerlIONext(f);
        PerlIOBase(f)->flags &= ~(PERLIO_F_ERROR | PERLIO_F_EOF);
-       if (n)
+       if (PerlIOValid(n))
            PerlIO_clearerr(n);
     }
 }
@@ -1971,7 +1960,7 @@ PerlIOBase_clearerr(pTHX_ PerlIO *f)
 void
 PerlIOBase_setlinebuf(pTHX_ PerlIO *f)
 {
-    if (f) {
+    if (PerlIOValid(f)) {
        PerlIOBase(f)->flags |= PERLIO_F_LINEBUF;
     }
 }
@@ -1997,7 +1986,7 @@ PerlIO *
 PerlIOBase_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags)
 {
     PerlIO *nexto = PerlIONext(o);
-    if (*nexto) {
+    if (PerlIOValid(nexto)) {
        PerlIO_funcs *tab = PerlIOBase(nexto)->tab;
        f = (*tab->Dup)(aTHX_ f, nexto, param, flags);
     }
@@ -2162,6 +2151,8 @@ PerlIOUnix_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg)
     IV code = PerlIOBase_pushed(aTHX_ f, mode, arg);
     PerlIOUnix *s = PerlIOSelf(f, PerlIOUnix);
     if (*PerlIONext(f)) {
+       /* We never call down so 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
@@ -2393,15 +2384,17 @@ PerlIOStdio_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg)
        FILE *stdio =
            PerlSIO_fdopen(PerlIO_fileno(PerlIONext(f)), mode =
                           PerlIOStdio_mode(mode, tmode));
-       if (stdio)
+       if (stdio) {
            s->stdio = stdio;
+           /* We never call down so any pending stuff now */
+           PerlIO_flush(PerlIONext(f));
+       }
        else
            return -1;
     }
     return PerlIOBase_pushed(aTHX_ f, mode, arg);
 }
 
-#undef PerlIO_importFILE
 PerlIO *
 PerlIO_importFILE(FILE *stdio, int fl)
 {
@@ -2721,7 +2714,6 @@ PerlIOStdio_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt)
         PerlSIO_set_ptr(stdio, (void*)ptr); /* LHS STDCHAR* cast non-portable */
 #ifdef STDIO_PTR_LVAL_SETS_CNT
        if (PerlSIO_get_cnt(stdio) != (cnt)) {
-           dTHX;
            assert(PerlSIO_get_cnt(stdio) == (cnt));
        }
 #endif
@@ -2797,15 +2789,14 @@ PerlIO_funcs PerlIO_stdio = {
 #endif                         /* USE_STDIO_PTR */
 };
 
-#undef PerlIO_exportFILE
 FILE *
 PerlIO_exportFILE(PerlIO *f, int fl)
 {
+    dTHX;
     FILE *stdio;
     PerlIO_flush(f);
     stdio = fdopen(PerlIO_fileno(f), "r+");
     if (stdio) {
-       dTHX;
        PerlIOStdio *s =
            PerlIOSelf(PerlIO_push(aTHX_ f, &PerlIO_stdio, "r+", Nullsv),
                       PerlIOStdio);
@@ -2814,7 +2805,6 @@ PerlIO_exportFILE(PerlIO *f, int fl)
     return stdio;
 }
 
-#undef PerlIO_findFILE
 FILE *
 PerlIO_findFILE(PerlIO *f)
 {
@@ -2829,7 +2819,6 @@ PerlIO_findFILE(PerlIO *f)
     return PerlIO_exportFILE(f, 0);
 }
 
-#undef PerlIO_releaseFILE
 void
 PerlIO_releaseFILE(PerlIO *p, FILE *f)
 {
@@ -2861,21 +2850,17 @@ PerlIOBuf_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)
 {
-    if (f) {
+    if (PerlIOValid(f)) {
        PerlIO *next = PerlIONext(f);
-       PerlIO_funcs *tab =
-           PerlIO_layer_fetch(aTHX_ layers, n - 1, PerlIOBase(next)->tab);
-       next =
-           (*tab->Open) (aTHX_ tab, layers, n - 1, mode, fd, imode, perm,
+       PerlIO_funcs *tab =  PerlIO_layer_fetch(aTHX_ layers, n - 1, PerlIOBase(next)->tab);
+       next = (*tab->Open) (aTHX_ tab, layers, n - 1, mode, fd, imode, perm,
                          next, narg, args);
-       if (!next
-           || (*PerlIOBase(f)->tab->Pushed) (aTHX_ f, mode, PerlIOArg) != 0) {
+       if (!next || (*PerlIOBase(f)->tab->Pushed) (aTHX_ f, mode, PerlIOArg) != 0) {
            return NULL;
        }
     }
     else {
-       PerlIO_funcs *tab =
-           PerlIO_layer_fetch(aTHX_ layers, n - 1, PerlIO_default_btm());
+       PerlIO_funcs *tab = PerlIO_layer_fetch(aTHX_ layers, n - 1, PerlIO_default_btm());
        int init = 0;
        if (*mode == 'I') {
            init = 1;
@@ -2921,13 +2906,13 @@ PerlIOBuf_flush(pTHX_ PerlIO *f)
 {
     PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf);
     int code = 0;
+    PerlIO *n = PerlIONext(f);
     if (PerlIOBase(f)->flags & PERLIO_F_WRBUF) {
        /*
         * write() the buffer
         */
        STDCHAR *buf = b->buf;
        STDCHAR *p = buf;
-       PerlIO *n = PerlIONext(f);
        while (p < b->ptr) {
            SSize_t count = PerlIO_write(n, p, b->ptr - p);
            if (count > 0) {
@@ -2951,17 +2936,17 @@ PerlIOBuf_flush(pTHX_ PerlIO *f)
            /*
             * We did not consume all of it
             */
-           if (PerlIO_seek(PerlIONext(f), b->posn, SEEK_SET) == 0) {
-               b->posn = PerlIO_tell(PerlIONext(f));
+           if (PerlIO_seek(n, b->posn, SEEK_SET) == 0) {
+               /* Reload n as some layers may pop themselves on seek */
+               b->posn = PerlIO_tell(n = PerlIONext(f));
            }
        }
     }
     b->ptr = b->end = b->buf;
     PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF | PERLIO_F_WRBUF);
-    /*
-     * FIXME: Is this right for read case ?
-     */
-    if (PerlIO_flush(PerlIONext(f)) != 0)
+    /* We check for Valid because of dubious decision to make PerlIO_flush(NULL) flush all */
+    /* FIXME: Doing downstream flush may be sub-optimal see PerlIOBuf_fill() below */
+    if (PerlIOValid(n) && PerlIO_flush(n) != 0)
        code = -1;
     return code;
 }
@@ -2973,10 +2958,10 @@ PerlIOBuf_fill(pTHX_ PerlIO *f)
     PerlIO *n = PerlIONext(f);
     SSize_t avail;
     /*
-     * FIXME: doing the down-stream flush is a bad idea if it causes
-     * pre-read data in stdio buffer to be discarded but this is too
-     * simplistic - as it skips _our_ hosekeeping and breaks tell tests.
-     * if (!(PerlIOBase(f)->flags & PERLIO_F_RDBUF)) { }
+     * FIXME: doing the down-stream flush maybe sub-optimal if it causes
+     * pre-read data in stdio buffer to be discarded.
+     * However, skipping the flush also skips _our_ hosekeeping
+     * and breaks tell tests. So we do the flush.
      */
     if (PerlIO_flush(f) != 0)
        return -1;
@@ -2989,7 +2974,7 @@ PerlIOBuf_fill(pTHX_ PerlIO *f)
     b->ptr = b->end = b->buf;
     if (PerlIO_fast_gets(n)) {
        /*
-        * Layer below is also buffered We do _NOT_ want to call its
+        * Layer below is also buffered. We do _NOT_ want to call its
         * ->Read() because that will loop till it gets what we asked for
         * which may hang on a pipe etc. Instead take anything it has to
         * hand, or ask it to fill _once_.
@@ -3032,7 +3017,7 @@ SSize_t
 PerlIOBuf_read(pTHX_ PerlIO *f, void *vbuf, Size_t count)
 {
     PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf);
-    if (f) {
+    if (PerlIOValid(f)) {
        if (!b->ptr)
            PerlIO_get_base(f);
        return PerlIOBase_read(aTHX_ f, vbuf, count);
@@ -3244,7 +3229,6 @@ PerlIOBuf_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt)
        PerlIO_get_base(f);
     b->ptr = ptr;
     if (PerlIO_get_cnt(f) != cnt || b->ptr < b->buf) {
-       dTHX;
        assert(PerlIO_get_cnt(f) == cnt);
        assert(b->ptr >= b->buf);
     }
@@ -3520,11 +3504,13 @@ PerlIOCrlf_get_cnt(pTHX_ PerlIO *f)
                    /*
                     * Blast - found CR as last char in buffer
                     */
+
                    if (b->ptr < nl) {
                        /*
                         * They may not care, defer work as long as
                         * possible
                         */
+                       c->nl = nl;
                        return (nl - b->ptr);
                    }
                    else {
@@ -3545,6 +3531,7 @@ PerlIOCrlf_get_cnt(pTHX_ PerlIO *f)
                        /*
                         * CR at EOF - just fall through
                         */
+                       /* Should we clear EOF though ??? */
                    }
                }
            }
@@ -3563,12 +3550,15 @@ PerlIOCrlf_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt)
     if (!b->buf)
        PerlIO_get_base(f);
     if (!ptr) {
-       if (c->nl)
+       if (c->nl) {
            ptr = c->nl + 1;
+            if (ptr == b->end && *c->nl == 0xd) {
+               /* Defered CR at end of buffer case - we lied about count */
+               ptr--;  
+            }
+        }
        else {
            ptr = b->end;
-           if ((flags & PERLIO_F_CRLF) && ptr > b->buf && ptr[-1] == 0xd)
-               ptr--;
        }
        ptr -= cnt;
     }
@@ -3577,10 +3567,14 @@ PerlIOCrlf_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt)
         * Test code - delete when it works ...
         */
        STDCHAR *chk = (c->nl) ? (c->nl+1) : b->end;
+        if (ptr+cnt == c->nl && c->nl+1 == b->end && *c->nl == 0xd) {
+         /* Defered CR at end of buffer case - we lied about count */
+         chk--;
+        }
        chk -= cnt;
 
-       if (ptr != chk) {
-           Perl_croak(aTHX_ "ptr wrong %p != %p fl=%08" UVxf
+       if (ptr != chk ) {
+           Perl_warn(aTHX_ "ptr wrong %p != %p fl=%08" UVxf
                       " nl=%p e=%p for %d", ptr, chk, flags, c->nl,
                       b->end, cnt);
        }
@@ -3801,7 +3795,7 @@ PerlIOMmap_map(pTHX_ PerlIO *f)
 }
 
 IV
-PerlIOMmap_unmap(PerlIO *f)
+PerlIOMmap_unmap(pTHX_ PerlIO *f)
 {
     PerlIOMmap *m = PerlIOSelf(f, PerlIOMmap);
     PerlIOBuf *b = &m->base;
@@ -3895,7 +3889,7 @@ PerlIOMmap_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count)
         * No, or wrong sort of, buffer
         */
        if (m->len) {
-           if (PerlIOMmap_unmap(f) != 0)
+           if (PerlIOMmap_unmap(aTHX_ f) != 0)
                return 0;
        }
        /*
@@ -3925,7 +3919,7 @@ PerlIOMmap_flush(pTHX_ PerlIO *f)
            /*
             * Unmap the buffer
             */
-           if (PerlIOMmap_unmap(f) != 0)
+           if (PerlIOMmap_unmap(aTHX_ f) != 0)
                code = -1;
        }
        else {
@@ -4007,33 +4001,27 @@ PerlIO_funcs PerlIO_mmap = {
 
 #endif                         /* HAS_MMAP */
 
-#undef PerlIO_stdin
 PerlIO *
-PerlIO_stdin(void)
+Perl_PerlIO_stdin(pTHX)
 {
-    dTHX;
     if (!PL_perlio) {
        PerlIO_stdstreams(aTHX);
     }
     return &PL_perlio[1];
 }
 
-#undef PerlIO_stdout
 PerlIO *
-PerlIO_stdout(void)
+Perl_PerlIO_stdout(pTHX)
 {
-    dTHX;
     if (!PL_perlio) {
        PerlIO_stdstreams(aTHX);
     }
     return &PL_perlio[2];
 }
 
-#undef PerlIO_stderr
 PerlIO *
-PerlIO_stderr(void)
+Perl_PerlIO_stderr(pTHX)
 {
-    dTHX;
     if (!PL_perlio) {
        PerlIO_stdstreams(aTHX);
     }
@@ -4042,7 +4030,6 @@ PerlIO_stderr(void)
 
 /*--------------------------------------------------------------------------------------*/
 
-#undef PerlIO_getname
 char *
 PerlIO_getname(PerlIO *f, char *buf)
 {
@@ -4065,10 +4052,37 @@ PerlIO_getname(PerlIO *f, char *buf)
  * terms of above
  */
 
+#undef PerlIO_fdopen
+PerlIO *
+PerlIO_fdopen(int fd, const char *mode)
+{
+    dTHX;
+    return PerlIO_openn(aTHX_ Nullch, mode, fd, 0, 0, NULL, 0, NULL);
+}
+
+#undef PerlIO_open
+PerlIO *
+PerlIO_open(const char *path, const char *mode)
+{
+    dTHX;
+    SV *name = sv_2mortal(newSVpvn(path, strlen(path)));
+    return PerlIO_openn(aTHX_ Nullch, mode, -1, 0, 0, NULL, 1, &name);
+}
+
+#undef Perlio_reopen
+PerlIO *
+PerlIO_reopen(const char *path, const char *mode, PerlIO *f)
+{
+    dTHX;
+    SV *name = sv_2mortal(newSVpvn(path, strlen(path)));
+    return PerlIO_openn(aTHX_ Nullch, mode, -1, 0, 0, f, 1, &name);
+}
+
 #undef PerlIO_getc
 int
 PerlIO_getc(PerlIO *f)
 {
+    dTHX;
     STDCHAR buf[1];
     SSize_t count = PerlIO_read(f, buf, 1);
     if (count == 1) {
@@ -4081,6 +4095,7 @@ PerlIO_getc(PerlIO *f)
 int
 PerlIO_ungetc(PerlIO *f, int ch)
 {
+    dTHX;
     if (ch != EOF) {
        STDCHAR buf = ch;
        if (PerlIO_unread(f, &buf, 1) == 1)
@@ -4093,6 +4108,7 @@ PerlIO_ungetc(PerlIO *f, int ch)
 int
 PerlIO_putc(PerlIO *f, int ch)
 {
+    dTHX;
     STDCHAR buf = ch;
     return PerlIO_write(f, &buf, 1);
 }
@@ -4101,6 +4117,7 @@ PerlIO_putc(PerlIO *f, int ch)
 int
 PerlIO_puts(PerlIO *f, const char *s)
 {
+    dTHX;
     STRLEN len = strlen(s);
     return PerlIO_write(f, s, len);
 }
@@ -4109,6 +4126,7 @@ PerlIO_puts(PerlIO *f, const char *s)
 void
 PerlIO_rewind(PerlIO *f)
 {
+    dTHX;
     PerlIO_seek(f, (Off_t) 0, SEEK_SET);
     PerlIO_clearerr(f);
 }
@@ -4151,6 +4169,7 @@ PerlIO_printf(PerlIO *f, const char *fmt, ...)
 int
 PerlIO_stdoutf(const char *fmt, ...)
 {
+    dTHX;
     va_list ap;
     int result;
     va_start(ap, fmt);