Update Changes.
[p5sagit/p5-mst-13.2.git] / perlio.c
index fa69c44..925e3fb 100644 (file)
--- a/perlio.c
+++ b/perlio.c
@@ -20,7 +20,7 @@
 #endif
 /*
  * This file provides those parts of PerlIO abstraction
- * which are not #defined in iperlsys.h.
+ * which are not #defined in perlio.h.
  * Which these are depends on various Configure #ifdef's
  */
 
 #define PERL_IN_PERLIO_C
 #include "perl.h"
 
+#ifndef PERLIO_LAYERS
+int
+PerlIO_apply_layers(pTHX_ PerlIO *f, const char *mode, const char *names)
+{
+ if (!names || !*names || strEQ(names,":crlf") || strEQ(names,":raw"))
+  {
+   return 0;
+  }
+ Perl_croak(aTHX_ "Cannot apply \"%s\" in non-PerlIO perl",names);
+ /* NOTREACHED */
+ return -1;
+}
+#endif
+
 #if !defined(PERL_IMPLICIT_SYS)
 
 #ifdef PERLIO_IS_STDIO
@@ -88,6 +102,8 @@ PerlIO_init(void)
 /* Implement all the PerlIO interface ourselves.
  */
 
+#include "perliol.h"
+
 /* We _MUST_ have <unistd.h> if we are using lseek() and may have large files */
 #ifdef I_UNISTD
 #include <unistd.h>
@@ -98,29 +114,28 @@ PerlIO_init(void)
 
 #include "XSUB.h"
 
-#undef printf
-void PerlIO_debug(char *fmt,...) __attribute__((format(printf,1,2)));
+void PerlIO_debug(const char *fmt,...) __attribute__((format(__printf__,1,2)));
 
 void
-PerlIO_debug(char *fmt,...)
+PerlIO_debug(const char *fmt,...)
 {
  static int dbg = 0;
+ va_list ap;
+ va_start(ap,fmt);
  if (!dbg)
   {
-   char *s = getenv("PERLIO_DEBUG");
+   char *s = PerlEnv_getenv("PERLIO_DEBUG");
    if (s && *s)
-    dbg = open(s,O_WRONLY|O_CREAT|O_APPEND,0666);
+    dbg = PerlLIO_open3(s,O_WRONLY|O_CREAT|O_APPEND,0666);
    else
     dbg = -1;
   }
  if (dbg > 0)
   {
    dTHX;
-   va_list ap;
    SV *sv = newSVpvn("",0);
    char *s;
    STRLEN len;
-   va_start(ap,fmt);
    s = CopFILE(PL_curcop);
    if (!s)
     s = "(none)";
@@ -128,77 +143,14 @@ PerlIO_debug(char *fmt,...)
    Perl_sv_vcatpvf(aTHX_ sv, fmt, &ap);
 
    s = SvPV(sv,len);
-   write(dbg,s,len);
-   va_end(ap);
+   PerlLIO_write(dbg,s,len);
    SvREFCNT_dec(sv);
   }
+ va_end(ap);
 }
 
 /*--------------------------------------------------------------------------------------*/
 
-typedef struct _PerlIO_funcs PerlIO_funcs;
-struct _PerlIO_funcs
-{
- char *                name;
- Size_t                size;
- IV            kind;
- IV            (*Fileno)(PerlIO *f);
- PerlIO *      (*Fdopen)(PerlIO_funcs *tab, int fd, const char *mode);
- PerlIO *      (*Open)(PerlIO_funcs *tab, const char *path, const char *mode);
- int           (*Reopen)(const char *path, const char *mode, PerlIO *f);
- IV            (*Pushed)(PerlIO *f,const char *mode);
- IV            (*Popped)(PerlIO *f);
- /* Unix-like functions - cf sfio line disciplines */
- SSize_t       (*Read)(PerlIO *f, void *vbuf, Size_t count);
- SSize_t       (*Unread)(PerlIO *f, const void *vbuf, Size_t count);
- SSize_t       (*Write)(PerlIO *f, const void *vbuf, Size_t count);
- IV            (*Seek)(PerlIO *f, Off_t offset, int whence);
- Off_t         (*Tell)(PerlIO *f);
- IV            (*Close)(PerlIO *f);
- /* Stdio-like buffered IO functions */
- IV            (*Flush)(PerlIO *f);
- IV            (*Fill)(PerlIO *f);
- IV            (*Eof)(PerlIO *f);
- IV            (*Error)(PerlIO *f);
- void          (*Clearerr)(PerlIO *f);
- void          (*Setlinebuf)(PerlIO *f);
- /* Perl's snooping functions */
- STDCHAR *     (*Get_base)(PerlIO *f);
- Size_t                (*Get_bufsiz)(PerlIO *f);
- STDCHAR *     (*Get_ptr)(PerlIO *f);
- SSize_t       (*Get_cnt)(PerlIO *f);
- void          (*Set_ptrcnt)(PerlIO *f,STDCHAR *ptr,SSize_t cnt);
-};
-
-struct _PerlIO
-{
- PerlIOl *     next;       /* Lower layer */
- PerlIO_funcs *        tab;        /* Functions for this layer */
- IV            flags;      /* Various flags for state */
-};
-
-/*--------------------------------------------------------------------------------------*/
-
-/* Flag values */
-#define PERLIO_F_EOF           0x00010000
-#define PERLIO_F_CANWRITE      0x00020000
-#define PERLIO_F_CANREAD       0x00040000
-#define PERLIO_F_ERROR         0x00080000
-#define PERLIO_F_TRUNCATE      0x00100000
-#define PERLIO_F_APPEND                0x00200000
-#define PERLIO_F_BINARY                0x00400000
-#define PERLIO_F_UTF8          0x00800000
-#define PERLIO_F_LINEBUF       0x01000000
-#define PERLIO_F_WRBUF         0x02000000
-#define PERLIO_F_RDBUF         0x04000000
-#define PERLIO_F_TEMP          0x08000000
-#define PERLIO_F_OPEN          0x10000000
-
-#define PerlIOBase(f)      (*(f))
-#define PerlIOSelf(f,type) ((type *)PerlIOBase(f))
-#define PerlIONext(f)      (&(PerlIOBase(f)->next))
-
-/*--------------------------------------------------------------------------------------*/
 /* Inner level routines */
 
 /* Table of pointers to the PerlIO structs (malloc'ed) */
@@ -241,8 +193,10 @@ PerlIO_cleantable(PerlIO **tablep)
    for (i=PERLIO_TABLE_SIZE-1; i > 0; i--)
     {
      PerlIO *f = table+i;
-     if (*f)
-      PerlIO_close(f);
+     if (*f) 
+      {
+       PerlIO_close(f);
+      }
     }
    Safefree(table);
    *tablep = NULL;
@@ -270,36 +224,8 @@ PerlIO_pop(PerlIO *f)
   }
 }
 
-#undef PerlIO_close
-int
-PerlIO_close(PerlIO *f)
-{
- int code = (*PerlIOBase(f)->tab->Close)(f);
- while (*f)
-  {
-   PerlIO_pop(f);
-  }
- return code;
-}
-
-
 /*--------------------------------------------------------------------------------------*/
-/* Given the abstraction above the public API functions */
-
-#undef PerlIO_fileno
-int
-PerlIO_fileno(PerlIO *f)
-{
- return (*PerlIOBase(f)->tab->Fileno)(f);
-}
-
-
-extern PerlIO_funcs PerlIO_unix;
-extern PerlIO_funcs PerlIO_perlio;
-extern PerlIO_funcs PerlIO_stdio;
-#ifdef HAS_MMAP
-extern PerlIO_funcs PerlIO_mmap;
-#endif
+/* XS Interface for perl code */
 
 XS(XS_perlio_import)
 {
@@ -322,7 +248,7 @@ XS(XS_perlio_unimport)
 }
 
 SV *
-PerlIO_find_layer(char *name, STRLEN len)
+PerlIO_find_layer(const char *name, STRLEN len)
 {
  dTHX;
  SV **svp;
@@ -335,6 +261,90 @@ PerlIO_find_layer(char *name, STRLEN len)
  return NULL;
 }
 
+
+static int
+perlio_mg_set(pTHX_ SV *sv, MAGIC *mg)
+{
+ if (SvROK(sv))
+  {
+   IO *io = GvIOn((GV *)SvRV(sv));
+   PerlIO *ifp = IoIFP(io);
+   PerlIO *ofp = IoOFP(io);
+   AV *av = (AV *) mg->mg_obj;
+   Perl_warn(aTHX_ "set %_ %p %p %p",sv,io,ifp,ofp);
+  }
+ return 0;
+}
+
+static int
+perlio_mg_get(pTHX_ SV *sv, MAGIC *mg)
+{
+ if (SvROK(sv))
+  {
+   IO *io = GvIOn((GV *)SvRV(sv));
+   PerlIO *ifp = IoIFP(io);
+   PerlIO *ofp = IoOFP(io);
+   AV *av = (AV *) mg->mg_obj;
+   Perl_warn(aTHX_ "get %_ %p %p %p",sv,io,ifp,ofp);
+  }
+ return 0;
+}
+
+static int
+perlio_mg_clear(pTHX_ SV *sv, MAGIC *mg)
+{
+ Perl_warn(aTHX_ "clear %_",sv);
+ return 0;
+}
+
+static int
+perlio_mg_free(pTHX_ SV *sv, MAGIC *mg)
+{
+ Perl_warn(aTHX_ "free %_",sv);
+ return 0;
+}
+
+MGVTBL perlio_vtab = {
+ perlio_mg_get,
+ perlio_mg_set,
+ NULL, /* len */
+ NULL,
+ perlio_mg_free
+};
+
+XS(XS_io_MODIFY_SCALAR_ATTRIBUTES)
+{
+ dXSARGS;
+ SV *sv    = SvRV(ST(1));
+ AV *av    = newAV();
+ MAGIC *mg;
+ int count = 0;
+ int i;
+ sv_magic(sv, (SV *)av, '~', NULL, 0);
+ SvRMAGICAL_off(sv);
+ mg = mg_find(sv,'~');
+ mg->mg_virtual = &perlio_vtab;
+ mg_magical(sv);
+ Perl_warn(aTHX_ "attrib %_",sv);
+ for (i=2; i < items; i++)
+  {
+   STRLEN len;
+   const char *name = SvPV(ST(i),len);
+   SV *layer  = PerlIO_find_layer(name,len);
+   if (layer)
+    {
+     av_push(av,SvREFCNT_inc(layer));
+    }
+   else
+    {
+     ST(count) = ST(i);
+     count++;
+    }
+  }
+ SvREFCNT_dec(av);
+ XSRETURN(count);
+}
+
 void
 PerlIO_define_layer(PerlIO_funcs *tab)
 {
@@ -354,14 +364,18 @@ PerlIO_default_layer(I32 n)
  int len;
  if (!PerlIO_layer_hv)
   {
-   char *s  = getenv("PERLIO");
+   const char *s  = PerlEnv_getenv("PERLIO");
    newXS("perlio::import",XS_perlio_import,__FILE__);
    newXS("perlio::unimport",XS_perlio_unimport,__FILE__);
-   PerlIO_layer_hv = get_hv("perlio::layers",GV_ADD|GV_ADDMULTI);
-   PerlIO_layer_av = get_av("perlio::layers",GV_ADD|GV_ADDMULTI);
+#if 0
+   newXS("io::MODIFY_SCALAR_ATTRIBUTES",XS_io_MODIFY_SCALAR_ATTRIBUTES,__FILE__);
+#endif
+   PerlIO_layer_hv = get_hv("open::layers",GV_ADD|GV_ADDMULTI);
+   PerlIO_layer_av = get_av("open::layers",GV_ADD|GV_ADDMULTI);
    PerlIO_define_layer(&PerlIO_unix);
    PerlIO_define_layer(&PerlIO_perlio);
    PerlIO_define_layer(&PerlIO_stdio);
+   PerlIO_define_layer(&PerlIO_crlf);
 #ifdef HAS_MMAP
    PerlIO_define_layer(&PerlIO_mmap);
 #endif
@@ -370,14 +384,16 @@ PerlIO_default_layer(I32 n)
     {
      while (*s)
       {
-       while (*s && isspace((unsigned char)*s))
+       while (*s && isSPACE((unsigned char)*s))
         s++;
        if (*s)
         {
-         char *e = s;
+         const char *e = s;
          SV *layer;
-         while (*e && !isspace((unsigned char)*e))
+         while (*e && !isSPACE((unsigned char)*e))
           e++;
+         if (*s == ':')
+          s++;
          layer = PerlIO_find_layer(s,e-s);
          if (layer)
           {
@@ -415,6 +431,46 @@ PerlIO_default_layer(I32 n)
  return tab;
 }
 
+int
+PerlIO_apply_layers(pTHX_ PerlIO *f, const char *mode, const char *names)
+{
+ if (names)
+  {
+   const char *s = names;
+   while (*s)
+    {
+     while (isSPACE(*s))
+      s++;
+     if (*s == ':')
+      s++;
+     if (*s)
+      {
+       const char *e = s;
+       while (*e && *e != ':' && !isSPACE(*e))
+        e++;
+       if (e > s)
+        {
+         SV *layer = PerlIO_find_layer(s,e-s);
+         if (layer)
+          {
+           PerlIO_funcs *tab = INT2PTR(PerlIO_funcs *, SvIV(SvRV(layer)));
+           if (tab)
+            {
+             PerlIO *new = PerlIO_push(f,tab,mode);
+             if (!new)
+              return -1;
+            }
+          }
+         else
+          Perl_warn(aTHX_ "perlio: unknown layer \"%.*s\"",(e-s),s);
+        }
+       s = e;
+      }
+    }
+  }
+ return 0;
+}
+
 #define PerlIO_default_top() PerlIO_default_layer(-1)
 #define PerlIO_default_btm() PerlIO_default_layer(0)
 
@@ -430,6 +486,50 @@ PerlIO_stdstreams()
   }
 }
 
+PerlIO *
+PerlIO_push(PerlIO *f,PerlIO_funcs *tab,const char *mode)
+{
+ PerlIOl *l = NULL;
+ Newc('L',l,tab->size,char,PerlIOl);
+ if (l)
+  {
+   Zero(l,tab->size,char);
+   l->next = *f;
+   l->tab  = tab;
+   *f      = l;
+   if ((*l->tab->Pushed)(f,mode) != 0)
+    {
+     PerlIO_pop(f);
+     return NULL;
+    }
+  }
+ return f;
+}
+
+/*--------------------------------------------------------------------------------------*/
+/* Given the abstraction above the public API functions */
+
+#undef PerlIO_close
+int
+PerlIO_close(PerlIO *f)
+{
+ int code = (*PerlIOBase(f)->tab->Close)(f);
+ while (*f)
+  {
+   PerlIO_pop(f);
+  }
+ return code;
+}
+
+#undef PerlIO_fileno
+int
+PerlIO_fileno(PerlIO *f)
+{
+ return (*PerlIOBase(f)->tab->Fileno)(f);
+}
+
+
+
 #undef PerlIO_fdopen
 PerlIO *
 PerlIO_fdopen(int fd, const char *mode)
@@ -450,57 +550,6 @@ PerlIO_open(const char *path, const char *mode)
  return (*tab->Open)(tab,path,mode);
 }
 
-IV
-PerlIOBase_pushed(PerlIO *f, const char *mode)
-{
- PerlIOl *l = PerlIOBase(f);
- l->flags  &= ~(PERLIO_F_CANREAD|PERLIO_F_CANWRITE|
-                PERLIO_F_TRUNCATE|PERLIO_F_APPEND|PERLIO_F_BINARY);
- if (mode)
-  {
-   switch (*mode++)
-    {
-     case 'r':
-      l->flags = PERLIO_F_CANREAD;
-      break;
-     case 'a':
-      l->flags = PERLIO_F_APPEND|PERLIO_F_CANWRITE;
-      break;
-     case 'w':
-      l->flags = PERLIO_F_TRUNCATE|PERLIO_F_CANWRITE;
-      break;
-     default:
-      errno = EINVAL;
-      return -1;
-    }
-   while (*mode)
-    {
-     switch (*mode++)
-      {
-       case '+':
-        l->flags |= PERLIO_F_CANREAD|PERLIO_F_CANWRITE;
-        break;
-       case 'b':
-        l->flags |= PERLIO_F_BINARY;
-        break;
-      default:
-       errno = EINVAL;
-       return -1;
-      }
-    }
-  }
- else
-  {
-   if (l->next)
-    {
-     l->flags |= l->next->flags &
-                 (PERLIO_F_CANREAD|PERLIO_F_CANWRITE|
-                   PERLIO_F_TRUNCATE|PERLIO_F_APPEND|PERLIO_F_BINARY);
-    }
-  }
- return 0;
-}
-
 #undef PerlIO_reopen
 PerlIO *
 PerlIO_reopen(const char *path, const char *mode, PerlIO *f)
@@ -721,24 +770,61 @@ PerlIOBase_fileno(PerlIO *f)
  return PerlIO_fileno(PerlIONext(f));
 }
 
-PerlIO *
-PerlIO_push(PerlIO *f,PerlIO_funcs *tab,const char *mode)
+IV
+PerlIOBase_pushed(PerlIO *f, const char *mode)
 {
- PerlIOl *l = NULL;
- Newc('L',l,tab->size,char,PerlIOl);
- if (l)
+ PerlIOl *l = PerlIOBase(f);
+ l->flags  &= ~(PERLIO_F_CANREAD|PERLIO_F_CANWRITE|
+                PERLIO_F_TRUNCATE|PERLIO_F_APPEND|PERLIO_F_BINARY);
+ if (mode)
   {
-   Zero(l,tab->size,char);
-   l->next = *f;
-   l->tab  = tab;
-   *f      = l;
-   if ((*l->tab->Pushed)(f,mode) != 0)
+   switch (*mode++)
     {
-     PerlIO_pop(f);
-     return NULL;
+     case 'r':
+      l->flags = PERLIO_F_CANREAD;
+      break;
+     case 'a':
+      l->flags = PERLIO_F_APPEND|PERLIO_F_CANWRITE;
+      break;
+     case 'w':
+      l->flags = PERLIO_F_TRUNCATE|PERLIO_F_CANWRITE;
+      break;
+     default:
+      errno = EINVAL;
+      return -1;
+    }
+   while (*mode)
+    {
+     switch (*mode++)
+      {
+       case '+':
+        l->flags |= PERLIO_F_CANREAD|PERLIO_F_CANWRITE;
+        break;
+       case 'b':
+        l->flags |= PERLIO_F_BINARY;
+        break;
+      default:
+       errno = EINVAL;
+       return -1;
+      }
     }
   }
- return f;
+ else
+  {
+   if (l->next)
+    {
+     l->flags |= l->next->flags &
+                 (PERLIO_F_CANREAD|PERLIO_F_CANWRITE|
+                   PERLIO_F_TRUNCATE|PERLIO_F_APPEND|PERLIO_F_BINARY);
+    }
+  }
+ return 0;
+}
+
+IV
+PerlIOBase_popped(PerlIO *f)
+{
+ return 0;
 }
 
 SSize_t
@@ -812,8 +898,6 @@ PerlIOBase_setlinebuf(PerlIO *f)
 
 }
 
-
-
 /*--------------------------------------------------------------------------------------*/
 /* Bottom-most level for UNIX-like case */
 
@@ -861,6 +945,11 @@ PerlIOUnix_oflags(const char *mode)
      oflags |= O_WRONLY;
     break;
   }
+ if (*mode == 'b')
+  {
+   oflags |= O_BINARY;
+   mode++; 
+  }   
  if (*mode || oflags == -1)
   {
    errno = EINVAL;
@@ -902,7 +991,7 @@ PerlIOUnix_open(PerlIO_funcs *self, const char *path,const char *mode)
  int oflags = PerlIOUnix_oflags(mode);
  if (oflags != -1)
   {
-   int fd = open(path,oflags,0666);
+   int fd = PerlLIO_open3(path,oflags,0666);
    if (fd >= 0)
     {
      PerlIOUnix *s = PerlIOSelf(PerlIO_push(f = PerlIO_allocate(),self,mode),PerlIOUnix);
@@ -923,7 +1012,7 @@ PerlIOUnix_reopen(const char *path, const char *mode, PerlIO *f)
   (*PerlIOBase(f)->tab->Close)(f);
  if (oflags != -1)
   {
-   int fd = open(path,oflags,0666);
+   int fd = PerlLIO_open3(path,oflags,0666);
    if (fd >= 0)
     {
      s->fd = fd;
@@ -943,7 +1032,7 @@ PerlIOUnix_read(PerlIO *f, void *vbuf, Size_t count)
   return 0;
  while (1)
   {
-   SSize_t len = read(fd,vbuf,count);
+   SSize_t len = PerlLIO_read(fd,vbuf,count);
    if (len >= 0 || errno != EINTR)
     {
      if (len < 0)
@@ -961,7 +1050,7 @@ PerlIOUnix_write(PerlIO *f, const void *vbuf, Size_t count)
  int fd = PerlIOSelf(f,PerlIOUnix)->fd;
  while (1)
   {
-   SSize_t len = write(fd,vbuf,count);
+   SSize_t len = PerlLIO_write(fd,vbuf,count);
    if (len >= 0 || errno != EINTR)
     {
      if (len < 0)
@@ -974,7 +1063,7 @@ PerlIOUnix_write(PerlIO *f, const void *vbuf, Size_t count)
 IV
 PerlIOUnix_seek(PerlIO *f, Off_t offset, int whence)
 {
- Off_t new = lseek(PerlIOSelf(f,PerlIOUnix)->fd,offset,whence);
+ Off_t new = PerlLIO_lseek(PerlIOSelf(f,PerlIOUnix)->fd,offset,whence);
  PerlIOBase(f)->flags &= ~PERLIO_F_EOF;
  return (new == (Off_t) -1) ? -1 : 0;
 }
@@ -982,7 +1071,7 @@ PerlIOUnix_seek(PerlIO *f, Off_t offset, int whence)
 Off_t
 PerlIOUnix_tell(PerlIO *f)
 {
- return lseek(PerlIOSelf(f,PerlIOUnix)->fd,0,SEEK_CUR);
+ return PerlLIO_lseek(PerlIOSelf(f,PerlIOUnix)->fd,0,SEEK_CUR);
 }
 
 IV
@@ -990,7 +1079,7 @@ PerlIOUnix_close(PerlIO *f)
 {
  int fd = PerlIOSelf(f,PerlIOUnix)->fd;
  int code = 0;
- while (close(fd) != 0)
+ while (PerlLIO_close(fd) != 0)
   {
    if (errno != EINTR)
     {
@@ -1021,8 +1110,8 @@ PerlIO_funcs PerlIO_unix = {
  PerlIOUnix_seek,
  PerlIOUnix_tell,
  PerlIOUnix_close,
- PerlIOBase_noop_ok,
- PerlIOBase_noop_fail,
+ PerlIOBase_noop_ok,   /* flush */
+ PerlIOBase_noop_fail, /* fill */
  PerlIOBase_eof,
  PerlIOBase_error,
  PerlIOBase_clearerr,
@@ -1037,15 +1126,6 @@ PerlIO_funcs PerlIO_unix = {
 /*--------------------------------------------------------------------------------------*/
 /* stdio as a layer */
 
-#if defined(USE_64_BIT_STDIO) && defined(HAS_FSEEKO) && !defined(USE_FSEEK64)
-#define fseek fseeko
-#endif
-
-#if defined(USE_64_BIT_STDIO) && defined(HAS_FTELLO) && !defined(USE_FTELL64)
-#define ftell ftello
-#endif
-
-
 typedef struct
 {
  struct _PerlIO        base;
@@ -1198,14 +1278,33 @@ PerlIOStdio_tell(PerlIO *f)
 IV
 PerlIOStdio_close(PerlIO *f)
 {
- return fclose(PerlIOSelf(f,PerlIOStdio)->stdio);
+ FILE *stdio = PerlIOSelf(f,PerlIOStdio)->stdio;
+ return fclose(stdio);
 }
 
 IV
 PerlIOStdio_flush(PerlIO *f)
 {
  FILE *stdio = PerlIOSelf(f,PerlIOStdio)->stdio;
- return fflush(stdio);
+ if (PerlIOBase(f)->flags & PERLIO_F_CANWRITE)
+  {
+   return fflush(stdio);
+  }
+ else
+  {
+#if 0
+   /* FIXME: This discards ungetc() and pre-read stuff which is
+      not right if this is just a "sync" from a layer above
+      Suspect right design is to do _this_ but not have layer above
+      flush this layer read-to-read
+    */
+   /* Not writeable - sync by attempting a seek */
+   int err = errno;
+   if (fseek(stdio,(Off_t) 0, SEEK_CUR) != 0)
+    errno = err;
+#endif
+  }
+ return 0;
 }
 
 IV
@@ -1213,8 +1312,12 @@ PerlIOStdio_fill(PerlIO *f)
 {
  FILE *stdio = PerlIOSelf(f,PerlIOStdio)->stdio;
  int c;
- if (fflush(stdio) != 0)
-  return EOF;
+ /* fflush()ing read-only streams can cause trouble on some stdio-s */
+ if ((PerlIOBase(f)->flags & PERLIO_F_CANWRITE))
+  {
+   if (fflush(stdio) != 0)
+    return EOF;
+  }
  c = fgetc(stdio);
  if (c == EOF || ungetc(c,stdio) != c)
   return EOF;
@@ -1386,18 +1489,6 @@ PerlIO_releaseFILE(PerlIO *p, FILE *f)
 /*--------------------------------------------------------------------------------------*/
 /* perlio buffer layer */
 
-typedef struct
-{
- struct _PerlIO base;
- Off_t         posn;       /* Offset of buf into the file */
- STDCHAR *     buf;        /* Start of buffer */
- STDCHAR *     end;        /* End of valid part of buffer */
- STDCHAR *     ptr;        /* Current position in buffer */
- Size_t                bufsiz;     /* Size of buffer */
- IV            oneword;    /* Emergency buffer */
-} PerlIOBuf;
-
-
 PerlIO *
 PerlIOBuf_fdopen(PerlIO_funcs *self, int fd, const char *mode)
 {
@@ -1422,7 +1513,6 @@ PerlIOBuf_fdopen(PerlIO_funcs *self, int fd, const char *mode)
  return f;
 }
 
-
 PerlIO *
 PerlIOBuf_open(PerlIO_funcs *self, const char *path, const char *mode)
 {
@@ -1464,14 +1554,15 @@ PerlIOBuf_flush(PerlIO *f)
    /* write() the buffer */
    STDCHAR *p = b->buf;
    int count;
+   PerlIO *n = PerlIONext(f);
    while (p < b->ptr)
     {
-     count = PerlIO_write(PerlIONext(f),p,b->ptr - p);
+     count = PerlIO_write(n,p,b->ptr - p);
      if (count > 0)
       {
        p += count;
       }
-     else if (count < 0)
+     else if (count < 0 || PerlIO_error(n))
       {
        PerlIOBase(f)->flags |= PERLIO_F_ERROR;
        code = -1;
@@ -1495,6 +1586,7 @@ PerlIOBuf_flush(PerlIO *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)
   code = -1;
  return code;
@@ -1504,11 +1596,53 @@ IV
 PerlIOBuf_fill(PerlIO *f)
 {
  PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
+ 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))
+  {
+  }
+  */
  if (PerlIO_flush(f) != 0)
   return -1;
+
  b->ptr = b->end = b->buf;
- avail = PerlIO_read(PerlIONext(f),b->ptr,b->bufsiz);
+ if (PerlIO_fast_gets(n))
+  {
+   /* 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_.
+    */
+   avail  = PerlIO_get_cnt(n);
+   if (avail <= 0)
+    {
+     avail = PerlIO_fill(n);
+     if (avail == 0)
+      avail = PerlIO_get_cnt(n);
+     else
+      {
+       if (!PerlIO_error(n) && PerlIO_eof(n))
+        avail = 0;
+      }
+    }
+   if (avail > 0)
+    {
+     STDCHAR *ptr = PerlIO_get_ptr(n);
+     SSize_t cnt  = avail;
+     if (avail > b->bufsiz)
+      avail = b->bufsiz;
+     Copy(ptr,b->buf,avail,STDCHAR);
+     PerlIO_set_ptrcnt(n,ptr+avail,cnt-avail);
+    }
+  }
+ else
+  {
+   avail = PerlIO_read(n,b->ptr,b->bufsiz);
+  }
  if (avail <= 0)
   {
    if (avail == 0)
@@ -1541,7 +1675,7 @@ PerlIOBuf_read(PerlIO *f, void *vbuf, Size_t count)
       avail = count;
      if (avail > 0)
       {
-       Copy(b->ptr,buf,avail,char);
+       Copy(b->ptr,buf,avail,STDCHAR);
        got     += avail;
        b->ptr  += avail;
        count   -= avail;
@@ -1590,7 +1724,7 @@ PerlIOBuf_unread(PerlIO *f, const void *vbuf, Size_t count)
      buf    -= avail;
      if (buf != b->ptr)
       {
-       Copy(buf,b->ptr,avail,char);
+       Copy(buf,b->ptr,avail,STDCHAR);
       }
      count  -= avail;
      unread += avail;
@@ -1636,7 +1770,7 @@ PerlIOBuf_write(PerlIO *f, const void *vbuf, Size_t count)
     {
      if (avail)
       {
-       Copy(buf,b->ptr,avail,char);
+       Copy(buf,b->ptr,avail,STDCHAR);
        count   -= avail;
        buf     += avail;
        written += avail;
@@ -1700,17 +1834,6 @@ PerlIOBuf_setlinebuf(PerlIO *f)
   }
 }
 
-void
-PerlIOBuf_set_cnt(PerlIO *f, int cnt)
-{
- PerlIOBuf *b = PerlIOSelf(f,PerlIOBuf);
- dTHX;
- if (!b->buf)
-  PerlIO_get_base(f);
- b->ptr = b->end - cnt;
- assert(b->ptr >= b->buf);
-}
-
 STDCHAR *
 PerlIOBuf_get_ptr(PerlIO *f)
 {
@@ -1805,6 +1928,40 @@ PerlIO_funcs PerlIO_perlio = {
  PerlIOBuf_set_ptrcnt,
 };
 
+/*--------------------------------------------------------------------------------------*/
+/* crlf - translation currently just a copy of perlio to prove
+   that extra buffering which real one will do is not an issue.
+ */
+
+PerlIO_funcs PerlIO_crlf = {
+ "crlf",
+ sizeof(PerlIOBuf),
+ 0,
+ PerlIOBase_fileno,
+ PerlIOBuf_fdopen,
+ PerlIOBuf_open,
+ PerlIOBuf_reopen,
+ PerlIOBase_pushed,
+ PerlIOBase_noop_ok,
+ PerlIOBuf_read,
+ PerlIOBuf_unread,
+ PerlIOBuf_write,
+ PerlIOBuf_seek,
+ PerlIOBuf_tell,
+ PerlIOBuf_close,
+ PerlIOBuf_flush,
+ PerlIOBuf_fill,
+ PerlIOBase_eof,
+ PerlIOBase_error,
+ PerlIOBase_clearerr,
+ PerlIOBuf_setlinebuf,
+ PerlIOBuf_get_base,
+ PerlIOBuf_bufsiz,
+ PerlIOBuf_get_ptr,
+ PerlIOBuf_get_cnt,
+ PerlIOBuf_set_ptrcnt,
+};
+
 #ifdef HAS_MMAP
 /*--------------------------------------------------------------------------------------*/
 /* mmap as "buffer" layer */
@@ -2111,8 +2268,6 @@ PerlIO_funcs PerlIO_mmap = {
 
 #endif /* HAS_MMAP */
 
-
-
 void
 PerlIO_init(void)
 {
@@ -2224,7 +2379,13 @@ PerlIO_vprintf(PerlIO *f, const char *fmt, va_list ap)
  SV *sv = newSVpvn("",0);
  char *s;
  STRLEN len;
+#ifdef NEED_VA_COPY
+ va_list apc;
+ Perl_va_copy(ap, apc);
+ sv_vcatpvf(sv, fmt, &apc);
+#else
  sv_vcatpvf(sv, fmt, &ap);
+#endif
  s = SvPV(sv,len);
  return PerlIO_write(f,s,len);
 }
@@ -2257,8 +2418,18 @@ PerlIO_stdoutf(const char *fmt,...)
 PerlIO *
 PerlIO_tmpfile(void)
 {
- dTHX;
  /* I have no idea how portable mkstemp() is ... */
+#if defined(WIN32) || !defined(HAVE_MKSTEMP)
+ PerlIO *f = NULL;
+ FILE *stdio = tmpfile();
+ if (stdio)
+  {
+   PerlIOStdio *s = PerlIOSelf(PerlIO_push(f = PerlIO_allocate(),&PerlIO_stdio,"w+"),PerlIOStdio);
+   s->stdio  = stdio;
+  }
+ return f;
+#else
+ dTHX;
  SV *sv = newSVpv("/tmp/PerlIO_XXXXXX",0);
  int fd = mkstemp(SvPVX(sv));
  PerlIO *f = NULL;
@@ -2269,10 +2440,11 @@ PerlIO_tmpfile(void)
     {
      PerlIOBase(f)->flags |= PERLIO_F_TEMP;
     }
-   unlink(SvPVX(sv));
+   PerlLIO_unlink(SvPVX(sv));
    SvREFCNT_dec(sv);
   }
  return f;
+#endif
 }
 
 #undef HAS_FSETPOS
@@ -2314,7 +2486,7 @@ int
 PerlIO_getpos(PerlIO *f, Fpos_t *pos)
 {
  *pos = PerlIO_tell(f);
- return *pos != -1;
+ return *pos == -1 ? -1 : 0;
 }
 #else
 #ifndef PERLIO_IS_STDIO
@@ -2359,7 +2531,8 @@ PerlIO_vsprintf(char *s, int n, const char *fmt, va_list ap)
    if (strlen(s) >= (STRLEN)n)
     {
      dTHX;
-     PerlIO_puts(Perl_error_log,"panic: sprintf overflow - memory corrupted!\n");
+     (void)PerlIO_puts(Perl_error_log,
+                      "panic: sprintf overflow - memory corrupted!\n");
      my_exit(1);
     }
   }