Change files which are mysteriously different to mainline to be
[p5sagit/p5-mst-13.2.git] / perlio.c
index 85b036c..4ed8f03 100644 (file)
--- a/perlio.c
+++ b/perlio.c
@@ -1,6 +1,6 @@
 /*    perlio.c
  *
- *    Copyright (c) 1996, Nick Ing-Simmons
+ *    Copyright (c) 1996-2000, Nick Ing-Simmons
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -8,36 +8,43 @@
  */
 
 #define VOIDUSED 1
-#include "config.h"
+#ifdef PERL_MICRO
+#   include "uconfig.h"
+#else
+#   include "config.h"
+#endif
 
-#define PERLIO_NOT_STDIO 0 
+#define PERLIO_NOT_STDIO 0
 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
-#define PerlIO FILE
+/* #define PerlIO FILE */
 #endif
 /*
- * This file provides those parts of PerlIO abstraction 
- * which are not #defined in perlio.h.
- * Which these are depends on various Configure #ifdef's 
+ * This file provides those parts of PerlIO abstraction
+ * which are not #defined in iperlsys.h.
+ * Which these are depends on various Configure #ifdef's
  */
 
 #include "EXTERN.h"
+#define PERL_IN_PERLIO_C
 #include "perl.h"
 
-#ifdef PERLIO_IS_STDIO 
+#if !defined(PERL_IMPLICIT_SYS)
+
+#ifdef PERLIO_IS_STDIO
 
 void
-PerlIO_init()
+PerlIO_init(void)
 {
- /* Does nothing (yet) except force this file to be included 
+ /* Does nothing (yet) except force this file to be included
     in perl binary. That allows this file to force inclusion
-    of other functions that may be required by loadable 
-    extensions e.g. for FileHandle::tmpfile  
+    of other functions that may be required by loadable
+    extensions e.g. for FileHandle::tmpfile
  */
 }
 
 #undef PerlIO_tmpfile
 PerlIO *
-PerlIO_tmpfile()
+PerlIO_tmpfile(void)
 {
  return tmpfile();
 }
@@ -49,435 +56,799 @@ PerlIO_tmpfile()
 #undef HAS_FSETPOS
 #undef HAS_FGETPOS
 
-/* This section is just to make sure these functions 
+/* This section is just to make sure these functions
    get pulled in from libsfio.a
 */
 
 #undef PerlIO_tmpfile
 PerlIO *
-PerlIO_tmpfile()
+PerlIO_tmpfile(void)
 {
  return sftmp(0);
 }
 
 void
-PerlIO_init()
+PerlIO_init(void)
 {
- /* Force this file to be included  in perl binary. Which allows 
-  *  this file to force inclusion  of other functions that may be 
-  *  required by loadable  extensions e.g. for FileHandle::tmpfile  
+ /* Force this file to be included  in perl binary. Which allows
+  *  this file to force inclusion  of other functions that may be
+  *  required by loadable  extensions e.g. for FileHandle::tmpfile
   */
 
  /* Hack
   * sfio does its own 'autoflush' on stdout in common cases.
-  * Flush results in a lot of lseek()s to regular files and 
+  * Flush results in a lot of lseek()s to regular files and
   * lot of small writes to pipes.
   */
  sfset(sfstdout,SF_SHARE,0);
 }
 
-#else
+#else /* USE_SFIO */
+
+/*======================================================================================*/
 
-/* Implement all the PerlIO interface using stdio. 
-   - this should be only file to include <stdio.h>
+/* Implement all the PerlIO interface ourselves.
 */
 
-#undef PerlIO_stderr
+/* We _MUST_ have <unistd.h> if we are using lseek() and may have large files */
+#ifdef I_UNISTD
+#include <unistd.h>
+#endif
+
+#undef printf
+void PerlIO_debug(char *fmt,...) __attribute__((format(printf,1,2)));
+
+void
+PerlIO_debug(char *fmt,...)
+{
+ static int dbg = 0;
+ if (!dbg)
+  {
+   char *s = getenv("PERLIO_DEBUG");
+   if (s && *s)
+    dbg = open(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);
+   sv_vcatpvf(sv, fmt, &ap);
+   s = SvPV(sv,len);
+   write(dbg,s,len);
+   va_end(ap);
+   SvREFCNT_dec(sv);
+  }
+}
+
+#define PERLIO_F_EOF           0x010000
+#define PERLIO_F_ERROR         0x020000
+#define PERLIO_F_LINEBUF       0x040000
+#define PERLIO_F_TEMP          0x080000
+#define PERLIO_F_RDBUF         0x100000
+#define PERLIO_F_WRBUF         0x200000
+#define PERLIO_F_OPEN          0x400000
+#define PERLIO_F_USED          0x800000
+
+struct _PerlIO
+{
+ IV       flags;      /* Various flags for state */
+ IV       fd;         /* Maybe pointer on some OSes */
+ int      oflags;     /* open/fcntl flags */
+ 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 */
+ Off_t    posn;       /* Offset of f->buf into the file */
+ int      oneword;    /* An if-all-else-fails area as a buffer */
+};
+
+/* Table of pointers to the PerlIO structs (malloc'ed) */
+PerlIO **_perlio     = NULL;
+int _perlio_size     = 0;
+
+void
+PerlIO_alloc_buf(PerlIO *f)
+{
+ if (!f->bufsiz)
+  f->bufsiz = 4096;
+ New('B',f->buf,f->bufsiz,char);
+ if (!f->buf)
+  {
+   f->buf = (STDCHAR *)&f->oneword;
+   f->bufsiz = sizeof(f->oneword);
+  }
+ f->ptr = f->buf;
+ f->end = f->ptr;
+}
+
+
+/* This "flush" is akin to sfio's sync in that it handles files in either
+   read or write state
+*/
+#undef PerlIO_flush
+int
+PerlIO_flush(PerlIO *f)
+{
+ int code = 0;
+ if (f)
+  {
+   if (f->flags & PERLIO_F_WRBUF)
+    {
+     /* write() the buffer */
+     STDCHAR *p = f->buf;
+     int count;
+     while (p < f->ptr)
+      {
+       count = write(f->fd,p,f->ptr - p);
+       if (count > 0)
+        {
+         p += count;
+        }
+       else if (count < 0 && errno != EINTR)
+        {
+         f->flags |= PERLIO_F_ERROR;
+         code = -1;
+         break;
+        }
+      }
+     f->posn += (p - f->buf);
+    }
+   else if (f->flags & PERLIO_F_RDBUF)
+    {
+     /* Note position change */
+     f->posn += (f->ptr - f->buf);
+     if (f->ptr < f->end)
+      {
+       /* We did not consume all of it */
+       f->posn = lseek(f->fd,f->posn,SEEK_SET);
+      }
+    }
+   f->ptr = f->end = f->buf;
+   f->flags &= ~(PERLIO_F_RDBUF|PERLIO_F_WRBUF);
+  }
+ else
+  {
+   int i;
+   for (i=_perlio_size-1; i >= 0; i--)
+    {
+     if ((f = _perlio[i]))
+      {
+       if (PerlIO_flush(f) != 0)
+        code = -1;
+      }
+    }
+  }
+ return code;
+}
+
+int
+PerlIO_oflags(const char *mode)
+{
+ int oflags = -1;
+ switch(*mode)
+  {
+   case 'r':
+    oflags = O_RDONLY;
+    if (*++mode == '+')
+     {
+      oflags = O_RDWR;
+      mode++;
+     }
+    break;
+
+   case 'w':
+    oflags = O_CREAT|O_TRUNC;
+    if (*++mode == '+')
+     {
+      oflags |= O_RDWR;
+      mode++;
+     }
+    else
+     oflags |= O_WRONLY;
+    break;
+
+   case 'a':
+    oflags = O_CREAT|O_APPEND;
+    if (*++mode == '+')
+     {
+      oflags |= O_RDWR;
+      mode++;
+     }
+    else
+     oflags |= O_WRONLY;
+    break;
+  }
+ if (*mode || oflags == -1)
+  {
+   errno = EINVAL;
+   oflags = -1;
+  }
+ return oflags;
+}
+
+PerlIO *
+PerlIO_allocate(void)
+{
+ /* Find a free slot in the table, growing table as necessary */
+ PerlIO *f;
+ int i = 0;
+ while (1)
+  {
+   PerlIO **table = _perlio;
+   while (i < _perlio_size)
+    {
+     f = table[i];
+     if (!f)
+      {
+       Newz('F',f,1,PerlIO);
+       if (!f)
+        return NULL;
+       table[i] = f;
+      }
+     if (!(f->flags & PERLIO_F_USED))
+      {
+       Zero(f,1,PerlIO);
+       f->flags = PERLIO_F_USED;
+       return f;
+      }
+     i++;
+    }
+   Newz('I',table,_perlio_size+16,PerlIO *);
+   if (!table)
+    return NULL;
+   Copy(_perlio,table,_perlio_size,PerlIO *);
+   if (_perlio)
+    Safefree(_perlio);
+   _perlio = table;
+   _perlio_size += 16;
+  }
+}
+
+#undef PerlIO_fdopen
+PerlIO *
+PerlIO_fdopen(int fd, const char *mode)
+{
+ PerlIO *f = NULL;
+ if (fd >= 0)
+  {
+   if ((f = PerlIO_allocate()))
+    {
+     f->fd     = fd;
+     f->oflags = PerlIO_oflags(mode);
+     f->flags  |= (PERLIO_F_OPEN|PERLIO_F_USED);
+    }
+  }
+ return f;
+}
+
+#undef PerlIO_fileno
+int
+PerlIO_fileno(PerlIO *f)
+{
+ if (f && (f->flags & PERLIO_F_OPEN))
+  {
+   return f->fd;
+  }
+ return -1;
+}
+
+#undef PerlIO_close
+int
+PerlIO_close(PerlIO *f)
+{
+ int code = 0;
+ if (f)
+  {
+   if (PerlIO_flush(f) != 0)
+    code = -1;
+   while (close(f->fd) != 0)
+    {
+     if (errno != EINTR)
+      {
+       code = -1;
+       break;
+      }
+    }
+   f->flags &= ~PERLIO_F_OPEN;
+   f->fd     = -1;
+   if (f->buf && f->buf != (STDCHAR *) &f->oneword)
+    {
+     Safefree(f->buf);
+    }
+   f->buf = NULL;
+   f->ptr = f->end = f->buf;
+   f->flags &= ~(PERLIO_F_USED|PERLIO_F_RDBUF|PERLIO_F_WRBUF);
+  }
+ return code;
+}
+
+void
+PerlIO_cleanup(void)
+{
+ /* Close all the files */
+ int i;
+ for (i=_perlio_size-1; i >= 0; i--)
+  {
+   PerlIO *f = _perlio[i];
+   if (f)
+    {
+     PerlIO_close(f);
+     Safefree(f);
+    }
+  }
+ if (_perlio)
+  Safefree(_perlio);
+ _perlio      = NULL;
+ _perlio_size = 0;
+}
+
+#undef PerlIO_open
 PerlIO *
-PerlIO_stderr()
+PerlIO_open(const char *path, const char *mode)
 {
- return (PerlIO *) stderr;
+ PerlIO *f = NULL;
+ int oflags = PerlIO_oflags(mode);
+ if (oflags != -1)
+  {
+   int fd = open(path,oflags,0666);
+   if (fd >= 0)
+    {
+     f = PerlIO_fdopen(fd,mode);
+     if (!f)
+      close(fd);
+    }
+  }
+ return f;
+}
+
+#undef PerlIO_reopen
+PerlIO *
+PerlIO_reopen(const char *path, const char *mode, PerlIO *f)
+{
+ if (f)
+  {
+   int oflags = PerlIO_oflags(mode);
+   PerlIO_close(f);
+   if (oflags != -1)
+    {
+     int fd = open(path,oflags,0666);
+     if (fd >= 0)
+      {
+       f->oflags = oflags;
+       f->flags  |= (PERLIO_F_OPEN|PERLIO_F_USED);
+      }
+    }
+   else
+    {
+     return NULL;
+    }
+  }
+ return PerlIO_open(path,mode);
+}
+
+void
+PerlIO_init(void)
+{
+ if (!_perlio)
+  {
+   atexit(&PerlIO_cleanup);
+   PerlIO_fdopen(0,"r");
+   PerlIO_fdopen(1,"w");
+   PerlIO_fdopen(2,"w");
+  }
 }
 
 #undef PerlIO_stdin
 PerlIO *
-PerlIO_stdin()
+PerlIO_stdin(void)
 {
- return (PerlIO *) stdin;
+ if (!_perlio)
+  PerlIO_init();
+ return _perlio[0];
 }
 
 #undef PerlIO_stdout
 PerlIO *
-PerlIO_stdout()
+PerlIO_stdout(void)
 {
- return (PerlIO *) stdout;
+ if (!_perlio)
+  PerlIO_init();
+ return _perlio[1];
+}
+
+#undef PerlIO_stderr
+PerlIO *
+PerlIO_stderr(void)
+{
+ if (!_perlio)
+  PerlIO_init();
+ return _perlio[2];
 }
 
 #undef PerlIO_fast_gets
-int 
-PerlIO_fast_gets(f)
-PerlIO *f;
+int
+PerlIO_fast_gets(PerlIO *f)
 {
-#if defined(USE_STDIO_PTR) && defined(STDIO_PTR_LVALUE) && defined(STDIO_CNT_LVALUE)
  return 1;
-#else
- return 0;
-#endif
 }
 
 #undef PerlIO_has_cntptr
-int 
-PerlIO_has_cntptr(f)
-PerlIO *f;
+int
+PerlIO_has_cntptr(PerlIO *f)
 {
-#if defined(USE_STDIO_PTR)
  return 1;
-#else
- return 0;
-#endif
 }
 
 #undef PerlIO_canset_cnt
-int 
-PerlIO_canset_cnt(f)
-PerlIO *f;
+int
+PerlIO_canset_cnt(PerlIO *f)
 {
-#if defined(USE_STDIO_PTR) && defined(STDIO_CNT_LVALUE)
  return 1;
-#else
- return 0;
-#endif
 }
 
 #undef PerlIO_set_cnt
 void
-PerlIO_set_cnt(f,cnt)
-PerlIO *f;
-int cnt;
-{
- if (cnt < -1)
-  warn("Setting cnt to %d\n",cnt);
-#if defined(USE_STDIO_PTR) && defined(STDIO_CNT_LVALUE)
- FILE_cnt(f) = cnt;
-#else
- croak("Cannot set 'cnt' of FILE * on this system");
-#endif
+PerlIO_set_cnt(PerlIO *f, int cnt)
+{
+ if (f)
+  {
+   dTHX;
+   if (!f->buf)
+    PerlIO_alloc_buf(f);
+   f->ptr = f->end - cnt;
+   assert(f->ptr >= f->buf);
+  }
 }
 
-#undef PerlIO_set_ptrcnt
-void
-PerlIO_set_ptrcnt(f,ptr,cnt)
-PerlIO *f;
-STDCHAR *ptr;
-int cnt;
-{
-#ifdef FILE_bufsiz
- STDCHAR *e = FILE_base(f) + FILE_bufsiz(f);
- int ec = e - ptr;
- if (ptr > e + 1)
-  warn("Setting ptr %p > end+1 %p\n", ptr, e + 1);
- if (cnt != ec)
-  warn("Setting cnt to %d, ptr implies %d\n",cnt,ec);
-#endif
-#if defined(USE_STDIO_PTR) && defined(STDIO_PTR_LVALUE)
- FILE_ptr(f) = ptr;
-#else
- croak("Cannot set 'ptr' of FILE * on this system");
-#endif
-#if defined(USE_STDIO_PTR) && defined(STDIO_CNT_LVALUE)
- FILE_cnt(f) = cnt;
-#else
- croak("Cannot set 'cnt' of FILE * on this system");
-#endif
+#undef PerlIO_get_cnt
+int
+PerlIO_get_cnt(PerlIO *f)
+{
+ if (f)
+  {
+   if (!f->buf)
+    PerlIO_alloc_buf(f);
+   if (f->flags & PERLIO_F_RDBUF)
+    return (f->end - f->ptr);
+  }
+ return 0;
 }
 
-#undef PerlIO_get_cnt
-int 
-PerlIO_get_cnt(f)
-PerlIO *f;
+#undef PerlIO_set_ptrcnt
+void
+PerlIO_set_ptrcnt(PerlIO *f, STDCHAR *ptr, int cnt)
 {
-#ifdef FILE_cnt
- return FILE_cnt(f);
-#else
- croak("Cannot get 'cnt' of FILE * on this system");
- return -1;
-#endif
+ if (f)
+  {
+   if (!f->buf)
+    PerlIO_alloc_buf(f);
+   f->ptr = ptr;
+   if (PerlIO_get_cnt(f) != cnt || f->ptr < f->buf)
+    {
+     dTHX;
+     assert(PerlIO_get_cnt(f) == cnt);
+     assert(f->ptr >= f->buf);
+    }
+   f->flags |= PERLIO_F_RDBUF;
+  }
 }
 
 #undef PerlIO_get_bufsiz
-int 
-PerlIO_get_bufsiz(f)
-PerlIO *f;
+int
+PerlIO_get_bufsiz(PerlIO *f)
 {
-#ifdef FILE_bufsiz
- return FILE_bufsiz(f);
-#else
- croak("Cannot get 'bufsiz' of FILE * on this system");
+ if (f)
+  {
+   if (!f->buf)
+    PerlIO_alloc_buf(f);
+   return f->bufsiz;
+  }
  return -1;
-#endif
 }
 
 #undef PerlIO_get_ptr
 STDCHAR *
-PerlIO_get_ptr(f)
-PerlIO *f;
+PerlIO_get_ptr(PerlIO *f)
 {
-#ifdef FILE_ptr
- return FILE_ptr(f);
-#else
- croak("Cannot get 'ptr' of FILE * on this system");
+ if (f)
+  {
+   if (!f->buf)
+    PerlIO_alloc_buf(f);
+   return f->ptr;
+  }
  return NULL;
-#endif
 }
 
 #undef PerlIO_get_base
 STDCHAR *
-PerlIO_get_base(f)
-PerlIO *f;
+PerlIO_get_base(PerlIO *f)
 {
-#ifdef FILE_base
- return FILE_base(f);
-#else
- croak("Cannot get 'base' of FILE * on this system");
+ if (f)
+  {
+   if (!f->buf)
+    PerlIO_alloc_buf(f);
+   return f->buf;
+  }
  return NULL;
-#endif
 }
 
-#undef PerlIO_has_base 
-int 
-PerlIO_has_base(f)
-PerlIO *f;
+#undef PerlIO_has_base
+int
+PerlIO_has_base(PerlIO *f)
 {
-#ifdef FILE_base
- return 1;
-#else
- return 0;
-#endif
+ if (f)
+  {
+   if (!f->buf)
+    PerlIO_alloc_buf(f);
+   return f->buf != NULL;
+  }
 }
 
 #undef PerlIO_puts
 int
-PerlIO_puts(f,s)
-PerlIO *f;
-const char *s;
-{
- return fputs(s,f);
-}
-
-#undef PerlIO_open 
-PerlIO * 
-PerlIO_open(path,mode)
-const char *path;
-const char *mode;
+PerlIO_puts(PerlIO *f, const char *s)
 {
- return fopen(path,mode);
+ STRLEN len = strlen(s);
+ return PerlIO_write(f,s,len);
 }
 
-#undef PerlIO_fdopen
-PerlIO * 
-PerlIO_fdopen(fd,mode)
-int fd;
-const char *mode;
-{
- return fdopen(fd,mode);
-}
-
-#undef PerlIO_reopen
-PerlIO * 
-PerlIO_reopen(name, mode, f)
-const char *name;
-const char *mode;
-PerlIO *f;
+#undef PerlIO_eof
+int
+PerlIO_eof(PerlIO *f)
 {
- return freopen(name,mode,f);
+ if (f)
+  {
+   return (f->flags & PERLIO_F_EOF) != 0;
+  }
+ return 1;
 }
 
-#undef PerlIO_close
-int      
-PerlIO_close(f)
-PerlIO *f;
+#undef PerlIO_getname
+char *
+PerlIO_getname(PerlIO *f, char *buf)
 {
- return fclose(f);
+ dTHX;
+ Perl_croak(aTHX_ "Don't know how to get file name");
+ return NULL;
 }
 
-#undef PerlIO_eof
-int      
-PerlIO_eof(f)
-PerlIO *f;
+#undef PerlIO_ungetc
+int
+PerlIO_ungetc(PerlIO *f, int ch)
 {
- return feof(f);
+ if (f->buf && (f->flags & PERLIO_F_RDBUF) && f->ptr > f->buf)
+  {
+   *--(f->ptr) = ch;
+   return ch;
+  }
+ return -1;
 }
 
-#undef PerlIO_getname
-char *
-PerlIO_getname(f,buf)
-PerlIO *f;
-char *buf;
+#undef PerlIO_read
+SSize_t
+PerlIO_read(PerlIO *f, void *vbuf, Size_t count)
 {
-#ifdef VMS
- return fgetname(f,buf);
-#else
- croak("Don't know how to get file name");
-#endif
+ STDCHAR *buf = (STDCHAR *) vbuf;
+ if (f)
+  {
+   Size_t got = 0;
+   if (!f->ptr)
+    PerlIO_alloc_buf(f);
+   if ((f->oflags & (O_RDONLY|O_WRONLY|O_RDWR)) == O_WRONLY)
+    return 0;
+   while (count > 0)
+    {
+     SSize_t avail = (f->end - f->ptr);
+     if ((SSize_t) count < avail)
+      avail = count;
+     if (avail > 0)
+      {
+       Copy(f->ptr,buf,avail,char);
+       got     += avail;
+       f->ptr  += avail;
+       count   -= avail;
+       buf     += avail;
+      }
+     if (count && (f->ptr >= f->end))
+      {
+       PerlIO_flush(f);
+       f->ptr = f->end = f->buf;
+       avail = read(f->fd,f->ptr,f->bufsiz);
+       if (avail <= 0)
+        {
+         if (avail == 0)
+          f->flags |= PERLIO_F_EOF;
+         else if (errno == EINTR)
+          continue;
+         else
+          f->flags |= PERLIO_F_ERROR;
+         break;
+        }
+       f->end   = f->buf+avail;
+       f->flags |= PERLIO_F_RDBUF;
+      }
+    }
+   return got;
+  }
+ return 0;
 }
 
 #undef PerlIO_getc
-int      
-PerlIO_getc(f)
-PerlIO *f;
+int
+PerlIO_getc(PerlIO *f)
 {
- return fgetc(f);
+ STDCHAR buf;
+ int count = PerlIO_read(f,&buf,1);
+ if (count == 1)
+  return (unsigned char) buf;
+ return -1;
 }
 
 #undef PerlIO_error
-int      
-PerlIO_error(f)
-PerlIO *f;
+int
+PerlIO_error(PerlIO *f)
 {
- return ferror(f);
+ if (f)
+  {
+   return f->flags & PERLIO_F_ERROR;
+  }
+ return 1;
 }
 
 #undef PerlIO_clearerr
 void
-PerlIO_clearerr(f)
-PerlIO *f;
+PerlIO_clearerr(PerlIO *f)
 {
- clearerr(f);
-}
-
-#undef PerlIO_flush
-int      
-PerlIO_flush(f)
-PerlIO *f;
-{
- return Fflush(f);
-}
-
-#undef PerlIO_fileno
-int      
-PerlIO_fileno(f)
-PerlIO *f;
-{
- return fileno(f);
+ if (f)
+  {
+   f->flags &= ~PERLIO_F_ERROR;
+  }
 }
 
 #undef PerlIO_setlinebuf
 void
-PerlIO_setlinebuf(f)
-PerlIO *f;
+PerlIO_setlinebuf(PerlIO *f)
 {
-#ifdef HAS_SETLINEBUF
-    setlinebuf(f);
-#else
-    setvbuf(f, Nullch, _IOLBF, 0);
-#endif
-}
-
-#undef PerlIO_putc
-int      
-PerlIO_putc(f,ch)
-PerlIO *f;
-int ch;
-{
- putc(ch,f);
-}
-
-#undef PerlIO_ungetc
-int      
-PerlIO_ungetc(f,ch)
-PerlIO *f;
-int ch;
-{
- ungetc(ch,f);
-}
-
-#undef PerlIO_read
-int      
-PerlIO_read(f,buf,count)
-PerlIO *f;
-void *buf;
-size_t count;
-{
- return fread(buf,1,count,f);
+ if (f)
+  {
+   f->flags &= ~PERLIO_F_LINEBUF;
+  }
 }
 
 #undef PerlIO_write
-int      
-PerlIO_write(f,buf,count)
-PerlIO *f;
-const void *buf;
-size_t count;
+SSize_t
+PerlIO_write(PerlIO *f, const void *vbuf, Size_t count)
 {
- return fwrite1(buf,1,count,f);
+ const STDCHAR *buf = (const STDCHAR *) vbuf;
+ Size_t written = 0;
+ if (f)
+  {
+   if (!f->buf)
+    PerlIO_alloc_buf(f);
+   if ((f->oflags & (O_RDONLY|O_WRONLY|O_RDWR)) == O_RDONLY)
+    return 0;
+   while (count > 0)
+    {
+     SSize_t avail = f->bufsiz - (f->ptr - f->buf);
+     if ((SSize_t) count < avail)
+      avail = count;
+     f->flags |= PERLIO_F_WRBUF;
+     if (f->flags & PERLIO_F_LINEBUF)
+      {
+       while (avail > 0)
+        {
+         int ch = *buf++;
+         *(f->ptr)++ = ch;
+         count--;
+         avail--;
+         written++;
+         if (ch == '\n')
+          {
+           PerlIO_flush(f);
+           break;
+          }
+        }
+      }
+     else
+      {
+       if (avail)
+        {
+         Copy(buf,f->ptr,avail,char);
+         count   -= avail;
+         buf     += avail;
+         written += avail;
+         f->ptr  += avail;
+        }
+      }
+     if (f->ptr >= (f->buf + f->bufsiz))
+      PerlIO_flush(f);
+    }
+  }
+ return written;
 }
 
-#undef PerlIO_vprintf
-int      
-PerlIO_vprintf(f,fmt,ap)
-PerlIO *f;
-const char *fmt;
-va_list ap;
+#undef PerlIO_putc
+int
+PerlIO_putc(PerlIO *f, int ch)
 {
- return vfprintf(f,fmt,ap);
+ STDCHAR buf = ch;
+ PerlIO_write(f,&buf,1);
 }
 
-
 #undef PerlIO_tell
-long
-PerlIO_tell(f)
-PerlIO *f;
+Off_t
+PerlIO_tell(PerlIO *f)
 {
- return ftell(f);
+ Off_t posn = f->posn;
+ if (f->buf)
+  posn += (f->ptr - f->buf);
+ return posn;
 }
 
 #undef PerlIO_seek
 int
-PerlIO_seek(f,offset,whence)
-PerlIO *f;
-off_t offset;
-int whence;
+PerlIO_seek(PerlIO *f, Off_t offset, int whence)
 {
- return fseek(f,offset,whence);
+ int code;
+ code = PerlIO_flush(f);
+ if (code == 0)
+  {
+   f->flags &= ~PERLIO_F_EOF;
+   f->posn = PerlLIO_lseek(f->fd,offset,whence);
+   if (f->posn == (Off_t) -1)
+    {
+     f->posn = 0;
+     code = -1;
+    }
+  }
+ return code;
 }
 
 #undef PerlIO_rewind
 void
-PerlIO_rewind(f)
-PerlIO *f;
+PerlIO_rewind(PerlIO *f)
 {
- rewind(f);
+ PerlIO_seek(f,(Off_t)0,SEEK_SET);
+}
+
+#undef PerlIO_vprintf
+int
+PerlIO_vprintf(PerlIO *f, const char *fmt, va_list ap)
+{
+ dTHX;
+ SV *sv = newSVpvn("",0);
+ char *s;
+ STRLEN len;
+ sv_vcatpvf(sv, fmt, &ap);
+ s = SvPV(sv,len);
+ return PerlIO_write(f,s,len);
 }
 
 #undef PerlIO_printf
-int      
-#ifdef I_STDARG
+int
 PerlIO_printf(PerlIO *f,const char *fmt,...)
-#else
-PerlIO_printf(f,fmt,va_alist)
-PerlIO *f;
-const char *fmt;
-va_dcl
-#endif
 {
  va_list ap;
  int result;
-#ifdef I_STDARG
  va_start(ap,fmt);
-#else
- va_start(ap);
-#endif
- result = vfprintf(f,fmt,ap);
+ result = PerlIO_vprintf(f,fmt,ap);
  va_end(ap);
  return result;
 }
 
 #undef PerlIO_stdoutf
-int      
-#ifdef I_STDARG
+int
 PerlIO_stdoutf(const char *fmt,...)
-#else
-PerlIO_stdoutf(fmt, va_alist)
-const char *fmt;
-va_dcl
-#endif
 {
  va_list ap;
  int result;
-#ifdef I_STDARG
  va_start(ap,fmt);
-#else
- va_start(ap);
-#endif
  result = PerlIO_vprintf(PerlIO_stdout(),fmt,ap);
  va_end(ap);
  return result;
@@ -485,54 +856,61 @@ va_dcl
 
 #undef PerlIO_tmpfile
 PerlIO *
-PerlIO_tmpfile()
-{
- return tmpfile();
+PerlIO_tmpfile(void)
+{
+ dTHX;
+ /* I have no idea how portable mkstemp() is ... */
+ 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)
+    {
+     f->flags |= PERLIO_F_TEMP;
+    }
+   unlink(SvPVX(sv));
+   SvREFCNT_dec(sv);
+  }
+ return f;
 }
 
 #undef PerlIO_importFILE
 PerlIO *
-PerlIO_importFILE(f,fl)
-FILE *f;
-int fl;
+PerlIO_importFILE(FILE *f, int fl)
 {
- return f;
+ int fd = fileno(f);
+ /* Should really push stdio discipline when we have them */
+ return PerlIO_fdopen(fd,"r+");
 }
 
 #undef PerlIO_exportFILE
 FILE *
-PerlIO_exportFILE(f,fl)
-PerlIO *f;
-int fl;
+PerlIO_exportFILE(PerlIO *f, int fl)
 {
- return f;
+ PerlIO_flush(f);
+ /* Should really push stdio discipline when we have them */
+ return fdopen(PerlIO_fileno(f),"r+");
 }
 
 #undef PerlIO_findFILE
 FILE *
-PerlIO_findFILE(f)
-PerlIO *f;
+PerlIO_findFILE(PerlIO *f)
 {
- return f;
+ return PerlIO_exportFILE(f,0);
 }
 
 #undef PerlIO_releaseFILE
 void
-PerlIO_releaseFILE(p,f)
-PerlIO *p;
-FILE *f;
+PerlIO_releaseFILE(PerlIO *p, FILE *f)
 {
 }
 
-void
-PerlIO_init()
-{
- /* Does nothing (yet) except force this file to be included 
-    in perl binary. That allows this file to force inclusion
-    of other functions that may be required by loadable 
-    extensions e.g. for FileHandle::tmpfile  
- */
-}
+#undef HAS_FSETPOS
+#undef HAS_FGETPOS
+
+/*======================================================================================*/
 
 #endif /* USE_SFIO */
 #endif /* PERLIO_IS_STDIO */
@@ -540,21 +918,21 @@ PerlIO_init()
 #ifndef HAS_FSETPOS
 #undef PerlIO_setpos
 int
-PerlIO_setpos(f,pos)
-PerlIO *f;
-const Fpos_t *pos;
+PerlIO_setpos(PerlIO *f, const Fpos_t *pos)
 {
- return PerlIO_seek(f,*pos,0); 
+ return PerlIO_seek(f,*pos,0);
 }
 #else
 #ifndef PERLIO_IS_STDIO
 #undef PerlIO_setpos
 int
-PerlIO_setpos(f,pos)
-PerlIO *f;
-const Fpos_t *pos;
+PerlIO_setpos(PerlIO *f, const Fpos_t *pos)
 {
+#if defined(USE_64_BIT_STDIO) && defined(USE_FSETPOS64)
+ return fsetpos64(f, pos);
+#else
  return fsetpos(f, pos);
+#endif
 }
 #endif
 #endif
@@ -562,9 +940,7 @@ const Fpos_t *pos;
 #ifndef HAS_FGETPOS
 #undef PerlIO_getpos
 int
-PerlIO_getpos(f,pos)
-PerlIO *f;
-Fpos_t *pos;
+PerlIO_getpos(PerlIO *f, Fpos_t *pos)
 {
  *pos = PerlIO_tell(f);
  return 0;
@@ -573,11 +949,13 @@ Fpos_t *pos;
 #ifndef PERLIO_IS_STDIO
 #undef PerlIO_getpos
 int
-PerlIO_getpos(f,pos)
-PerlIO *f;
-Fpos_t *pos;
+PerlIO_getpos(PerlIO *f, Fpos_t *pos)
 {
+#if defined(USE_64_BIT_STDIO) && defined(USE_FSETPOS64)
+ return fgetpos64(f, pos);
+#else
  return fgetpos(f, pos);
+#endif
 }
 #endif
 #endif
@@ -585,9 +963,14 @@ Fpos_t *pos;
 #if (defined(PERLIO_IS_STDIO) || !defined(USE_SFIO)) && !defined(HAS_VPRINTF)
 
 int
-vprintf(fd, pat, args)
-FILE *fd;
-char *pat, *args;
+vprintf(char *pat, char *args)
+{
+    _doprnt(pat, args, stdout);
+    return 0;          /* wrong, but perl doesn't use the return value */
+}
+
+int
+vfprintf(FILE *fd, char *pat, char *args)
 {
     _doprnt(pat, args, fd);
     return 0;          /* wrong, but perl doesn't use the return value */
@@ -596,19 +979,16 @@ char *pat, *args;
 #endif
 
 #ifndef PerlIO_vsprintf
-int 
-PerlIO_vsprintf(s,n,fmt,ap)
-char *s;
-const char *fmt;
-int n;
-va_list ap;
+int
+PerlIO_vsprintf(char *s, int n, const char *fmt, va_list ap)
 {
  int val = vsprintf(s, fmt, ap);
  if (n >= 0)
   {
    if (strlen(s) >= (STRLEN)n)
     {
-     PerlIO_puts(PerlIO_stderr(),"panic: sprintf overflow - memory corrupted!\n");
+     dTHX;
+     PerlIO_puts(Perl_error_log,"panic: sprintf overflow - memory corrupted!\n");
      my_exit(1);
     }
   }
@@ -617,27 +997,17 @@ va_list ap;
 #endif
 
 #ifndef PerlIO_sprintf
-int      
-#ifdef I_STDARG
+int
 PerlIO_sprintf(char *s, int n, const char *fmt,...)
-#else
-PerlIO_sprintf(s, n, fmt, va_alist)
-char *s;
-int n;
-const char *fmt;
-va_dcl
-#endif
 {
  va_list ap;
  int result;
-#ifdef I_STDARG
  va_start(ap,fmt);
-#else
- va_start(ap);
-#endif
  result = PerlIO_vsprintf(s, n, fmt, ap);
  va_end(ap);
  return result;
 }
 #endif
 
+#endif /* !PERL_IMPLICIT_SYS */
+