*
*/
-
#define VOIDUSED 1
#ifdef PERL_MICRO
# include "uconfig.h"
/* Implement all the PerlIO interface ourselves.
*/
+/* 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,...)
{
struct _PerlIO
{
- IV flags;
+ 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;
- int oneword;
+ Off_t posn; /* Offset of f->buf into the file */
+ int oneword; /* An if-all-else-fails area as a buffer */
};
-int _perlio_size = 0;
+/* 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 = 2;
+ f->bufsiz = 4096;
New('B',f->buf,f->bufsiz,char);
if (!f->buf)
{
}
f->ptr = f->buf;
f->end = f->ptr;
- PerlIO_debug(__FUNCTION__ " f=%p b=%p p=%p e=%p\n",
- f,f->buf,f->ptr,f->end);
}
+
+/* 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)
{
- PerlIO_debug(__FUNCTION__ " f=%p flags=%08X c=%d buf=%p ptr=%p\n",
- f,f->flags,(f->ptr-f->buf),f->buf,f->ptr);
if (f->flags & PERLIO_F_WRBUF)
{
+ /* write() the buffer */
STDCHAR *p = f->buf;
int count;
while (p < f->ptr)
}
else if (count < 0 && errno != EINTR)
{
+ f->flags |= PERLIO_F_ERROR;
code = -1;
break;
}
}
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);
}
}
else
{
int i;
- for (i=_perlio_size; i >= 0; i--)
+ for (i=_perlio_size-1; i >= 0; i--)
{
if ((f = _perlio[i]))
{
PerlIO_oflags(const char *mode)
{
int oflags = -1;
- PerlIO_debug(__FUNCTION__ " %s = ",mode);
switch(*mode)
{
case 'r':
break;
case 'a':
- oflags = O_CREAT|O_TRUNC|O_APPEND;
+ oflags = O_CREAT|O_APPEND;
if (*++mode == '+')
{
oflags |= O_RDWR;
errno = EINVAL;
oflags = -1;
}
- PerlIO_debug(" %X '%s'\n",oflags,mode);
return oflags;
}
PerlIO *
PerlIO_allocate(void)
{
+ /* Find a free slot in the table, growing table as necessary */
PerlIO *f;
int i = 0;
while (1)
while (i < _perlio_size)
{
f = table[i];
- PerlIO_debug(__FUNCTION__ " try %d %p\n",i,f);
if (!f)
{
Newz('F',f,1,PerlIO);
f->flags |= (PERLIO_F_OPEN|PERLIO_F_USED);
}
}
- PerlIO_debug(__FUNCTION__ " fd=%d m=%s f=%p\n",fd,mode,f);
return f;
}
int
PerlIO_close(PerlIO *f)
{
- int code = -1;
+ int code = 0;
if (f)
{
- PerlIO_flush(f);
- while ((code = close(f->fd)) && errno == EINTR);
+ 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)
void
PerlIO_cleanup(void)
{
+ /* Close all the files */
int i;
- PerlIO_debug(__FUNCTION__ "\n");
for (i=_perlio_size-1; i >= 0; i--)
{
PerlIO *f = _perlio[i];
int fd = open(path,oflags,0666);
if (fd >= 0)
{
- PerlIO_debug(__FUNCTION__ "fd=%d\n",fd);
f = PerlIO_fdopen(fd,mode);
if (!f)
close(fd);
}
}
- PerlIO_debug(__FUNCTION__ " path=%s m=%s f=%p\n",path,mode,f);
return f;
}
PerlIO *
PerlIO_reopen(const char *path, const char *mode, PerlIO *f)
{
- PerlIO_debug(__FUNCTION__ " n=%s m=%s f=%p\n",path,mode,f);
if (f)
{
int oflags = PerlIO_oflags(mode);
int fd = open(path,oflags,0666);
if (fd >= 0)
{
- PerlIO_debug(__FUNCTION__ "fd=%d\n",fd);
f->oflags = oflags;
f->flags |= (PERLIO_F_OPEN|PERLIO_F_USED);
}
PerlIO_fdopen(1,"w");
PerlIO_fdopen(2,"w");
}
- PerlIO_debug(__FUNCTION__ "\n");
}
#undef PerlIO_stdin
{
if (f)
{
- dTHX;
if (!f->buf)
PerlIO_alloc_buf(f);
f->ptr = ptr;
- assert(f->ptr >= f->buf);
- if (PerlIO_get_cnt(f) != cnt)
+ if (PerlIO_get_cnt(f) != cnt || f->ptr < f->buf)
{
dTHX;
- assert(PerlIO_get_cnt(f) != cnt);
+ assert(PerlIO_get_cnt(f) == cnt);
+ assert(f->ptr >= f->buf);
}
+ f->flags |= PERLIO_F_RDBUF;
}
}
char *
PerlIO_getname(PerlIO *f, char *buf)
{
-#ifdef VMS
- return fgetname(f,buf);
-#else
dTHX;
Perl_croak(aTHX_ "Don't know how to get file name");
return NULL;
-#endif
}
#undef PerlIO_ungetc
int
PerlIO_ungetc(PerlIO *f, int ch)
{
- PerlIO_debug(__FUNCTION__ " f=%p c=%c\n",f,ch);
if (f->buf && (f->flags & PERLIO_F_RDBUF) && f->ptr > f->buf)
{
*--(f->ptr) = ch;
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 (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)
STDCHAR buf;
int count = PerlIO_read(f,&buf,1);
if (count == 1)
- return buf;
+ return (unsigned char) buf;
return -1;
}
{
const STDCHAR *buf = (const STDCHAR *) vbuf;
Size_t written = 0;
- PerlIO_debug(__FUNCTION__ " f=%p c=%d\n",f,count);
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)
{
- Size_t avail = f->bufsiz - (f->ptr - f->buf);
- if (count < avail)
+ 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)
avail--;
written++;
if (ch == '\n')
- PerlIO_flush(f);
+ {
+ PerlIO_flush(f);
+ break;
+ }
}
}
else
PerlIO_putc(PerlIO *f, int ch)
{
STDCHAR buf = ch;
- PerlIO_write(f,&ch,1);
+ PerlIO_write(f,&buf,1);
}
#undef PerlIO_tell
Off_t
PerlIO_tell(PerlIO *f)
{
- Off_t posn = f->posn + (f->ptr - f->buf);
+ Off_t posn = f->posn;
+ if (f->buf)
+ posn += (f->ptr - f->buf);
return posn;
}
int
PerlIO_seek(PerlIO *f, Off_t offset, int whence)
{
- int code = PerlIO_flush(f);
+ int code;
+ code = PerlIO_flush(f);
if (code == 0)
{
f->flags &= ~PERLIO_F_EOF;
- f->posn = lseek(f->fd,offset,whence);
+ f->posn = PerlLIO_lseek(f->fd,offset,whence);
if (f->posn == (Off_t) -1)
{
f->posn = 0;
PerlIO_vprintf(PerlIO *f, const char *fmt, va_list ap)
{
dTHX;
- SV *sv = newSV(strlen(fmt));
+ SV *sv = newSVpvn("",0);
char *s;
STRLEN len;
sv_vcatpvf(sv, fmt, &ap);
s = SvPV(sv,len);
- return (PerlIO_write(f,s,len) == len) ? 1 : 0;
+ return PerlIO_write(f,s,len);
}
#undef PerlIO_printf
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)
{
- PerlIO *f = PerlIO_fdopen(fd,"w+");
+ f = PerlIO_fdopen(fd,"w+");
if (f)
{
f->flags |= PERLIO_F_TEMP;
PerlIO_importFILE(FILE *f, int fl)
{
int fd = fileno(f);
+ /* Should really push stdio discipline when we have them */
return PerlIO_fdopen(fd,"r+");
}
PerlIO_exportFILE(PerlIO *f, int fl)
{
PerlIO_flush(f);
+ /* Should really push stdio discipline when we have them */
return fdopen(PerlIO_fileno(f),"r+");
}