int
PerlIO_apply_layers(pTHX_ PerlIO *f, const char *mode, const char *names)
{
- if (!names || !*names || strEQ(names, ":crlf") || strEQ(names, ":raw")) {
+ if (!names || !*names
+ || strEQ(names, ":crlf")
+ || strEQ(names, ":raw")
+ || strEQ(names, ":bytes")
+ ) {
return 0;
}
Perl_croak(aTHX_ "Cannot apply \"%s\" in non-PerlIO perl", names);
Perl_warner(aTHX_ packWARN(WARN_LAYER),
"perlio: invalid separator character %c%c%c in layer specification list %s",
q, *s, q, s);
+ SETERRNO(EINVAL, LIB$_INVARG);
return -1;
}
do {
return PerlIO_apply_layers(aTHX_ f, NULL, names) == 0 ? TRUE : FALSE;
}
else {
+ if (*f) {
+ /* Turn off UTF-8-ness, to undo UTF-8 locale effects
+ This may be too simplistic!
+ */
+ PerlIOBase(f)->flags &= ~PERLIO_F_UTF8;
+ }
/* 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
else {
av = def;
}
- PerlIO_parse_layers(aTHX_ av, layers);
- return av;
+ if (PerlIO_parse_layers(aTHX_ av, layers) == 0) {
+ return av;
+ }
+ else {
+ PerlIO_list_free(aTHX_ av);
+ return (PerlIO_list_t *) NULL;
+ }
}
else {
if (incdef)
}
else {
layera = PerlIO_resolve_layers(aTHX_ layers, mode, narg, args);
+ if (!layera) {
+ return NULL;
+ }
}
/*
* Start at "top" of layer stack
PerlIO_funcs PerlIO_utf8 = {
"utf8",
sizeof(PerlIOl),
- PERLIO_K_DUMMY | PERLIO_F_UTF8,
+ PERLIO_K_DUMMY | PERLIO_K_UTF8,
PerlIOUtf8_pushed,
NULL,
NULL,
sizeof(PerlIOUnix),
PERLIO_K_RAW,
PerlIOUnix_pushed,
- PerlIOBase_noop_ok,
+ PerlIOBase_popped,
PerlIOUnix_open,
NULL,
PerlIOUnix_fileno,
* stdio as a layer
*/
+#if defined(VMS) && !defined(STDIO_BUFFER_WRITABLE)
+/* perl5.8 - This ensures the last minute VMS ungetc fix is not
+ broken by the last second glibc 2.3 fix
+ */
+#define STDIO_BUFFER_WRITABLE
+#endif
+
+
typedef struct {
struct _PerlIO base;
FILE *stdio; /* The stream */
/* We need to probe to see how we can open the stream
so start with read/write and then try write and read
we dup() so that we can fclose without loosing the fd.
+
+ Note that the errno value set by a failing fdopen
+ varies between stdio implementations.
*/
int fd = PerlLIO_dup(fileno(stdio));
char *mode = "r+";
FILE *f2 = fdopen(fd, mode);
PerlIOStdio *s;
- if (!f2 && errno == EINVAL) {
+ if (!f2) {
mode = "w";
f2 = fdopen(fd, mode);
}
- if (!f2 && errno == EINVAL) {
+ if (!f2) {
mode = "r";
f2 = fdopen(fd, mode);
}
if (!f2) {
/* Don't seem to be able to open */
+ PerlLIO_close(fd);
return f;
}
fclose(f2);
SSize_t
PerlIOStdio_unread(pTHX_ PerlIO *f, const void *vbuf, Size_t count)
{
- FILE *s = PerlIOSelf(f, PerlIOStdio)->stdio;
- STDCHAR *buf = ((STDCHAR *) vbuf) + count - 1;
SSize_t unread = 0;
- while (count > 0) {
- int ch = *buf-- & 0xff;
- if (PerlSIO_ungetc(ch, s) != ch)
- break;
- unread++;
- count--;
+ FILE *s = PerlIOSelf(f, PerlIOStdio)->stdio;
+
+#ifdef STDIO_BUFFER_WRITABLE
+ if (PerlIO_fast_gets(f) && PerlIO_has_base(f)) {
+ STDCHAR *buf = ((STDCHAR *) vbuf) + count;
+ STDCHAR *base = PerlIO_get_base(f);
+ SSize_t cnt = PerlIO_get_cnt(f);
+ STDCHAR *ptr = PerlIO_get_ptr(f);
+ SSize_t avail = ptr - base;
+ if (avail > 0) {
+ if (avail > count) {
+ avail = count;
+ }
+ ptr -= avail;
+ Move(buf-avail,ptr,avail,STDCHAR);
+ count -= avail;
+ unread += avail;
+ PerlIO_set_ptrcnt(f,ptr,cnt+avail);
+ if (PerlSIO_feof(s) && unread >= 0)
+ PerlSIO_clearerr(s);
+ }
+ }
+ else
+#endif
+ if (PerlIO_has_cntptr(f)) {
+ /* We can get pointer to buffer but not its base
+ Do ungetc() but check chars are ending up in the
+ buffer
+ */
+ STDCHAR *eptr = (STDCHAR*)PerlSIO_get_ptr(s);
+ STDCHAR *buf = ((STDCHAR *) vbuf) + count;
+ while (count > 0) {
+ int ch = *--buf & 0xFF;
+ if (ungetc(ch,s) != ch) {
+ /* ungetc did not work */
+ break;
+ }
+ if ((STDCHAR*)PerlSIO_get_ptr(s) != --eptr || ((*eptr & 0xFF) != ch)) {
+ /* Did not change pointer as expected */
+ fgetc(s); /* get char back again */
+ break;
+ }
+ /* It worked ! */
+ count--;
+ unread++;
+ }
+ }
+
+ if (count > 0) {
+ unread += PerlIOBase_unread(aTHX_ f, vbuf, count);
}
return unread;
}
}
IV
-PerlIOStdio_fill(pTHX_ PerlIO *f)
-{
- FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
- int c;
- /*
- * fflush()ing read-only streams can cause trouble on some stdio-s
- */
- if ((PerlIOBase(f)->flags & PERLIO_F_CANWRITE)) {
- if (PerlSIO_fflush(stdio) != 0)
- return EOF;
- }
- c = PerlSIO_fgetc(stdio);
- if (c == EOF || PerlSIO_ungetc(c, stdio) != c)
- return EOF;
- return 0;
-}
-
-IV
PerlIOStdio_eof(pTHX_ PerlIO *f)
{
return PerlSIO_feof(PerlIOSelf(f, PerlIOStdio)->stdio);
#endif /* STDIO_CNT_LVALUE */
}
+
#endif
+IV
+PerlIOStdio_fill(pTHX_ PerlIO *f)
+{
+ FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio;
+ int c;
+ /*
+ * fflush()ing read-only streams can cause trouble on some stdio-s
+ */
+ if ((PerlIOBase(f)->flags & PERLIO_F_CANWRITE)) {
+ if (PerlSIO_fflush(stdio) != 0)
+ return EOF;
+ }
+ c = PerlSIO_fgetc(stdio);
+ if (c == EOF)
+ return EOF;
+
+#if (defined(STDIO_PTR_LVALUE) && (defined(STDIO_CNT_LVALUE) || defined(STDIO_PTR_LVAL_SETS_CNT)))
+
+#ifdef STDIO_BUFFER_WRITABLE
+ if (PerlIO_fast_gets(f) && PerlIO_has_base(f)) {
+ /* Fake ungetc() to the real buffer in case system's ungetc
+ goes elsewhere
+ */
+ STDCHAR *base = (STDCHAR*)PerlSIO_get_base(stdio);
+ SSize_t cnt = PerlSIO_get_cnt(stdio);
+ STDCHAR *ptr = (STDCHAR*)PerlSIO_get_ptr(stdio);
+ if (ptr == base+1) {
+ *--ptr = (STDCHAR) c;
+ PerlIOStdio_set_ptrcnt(aTHX_ f,ptr,cnt+1);
+ if (PerlSIO_feof(stdio))
+ PerlSIO_clearerr(stdio);
+ return 0;
+ }
+ }
+ else
+#endif
+ if (PerlIO_has_cntptr(f)) {
+ STDCHAR ch = c;
+ if (PerlIOStdio_unread(aTHX_ f,&ch,1) == 1) {
+ return 0;
+ }
+ }
+#endif
+
+#if defined(VMS)
+ /* An ungetc()d char is handled separately from the regular
+ * buffer, so we stuff it in the buffer ourselves.
+ * Should never get called as should hit code above
+ */
+ *(--((*stdio)->_ptr)) = (unsigned char) c;
+ (*stdio)->_cnt++;
+#else
+ /* If buffer snoop scheme above fails fall back to
+ using ungetc().
+ */
+ if (PerlSIO_ungetc(c, stdio) != c)
+ return EOF;
+#endif
+ return 0;
+}
+
+
+
PerlIO_funcs PerlIO_stdio = {
"stdio",
sizeof(PerlIOStdio),
PERLIO_K_BUFFERED,
PerlIOBase_pushed,
- PerlIOBase_noop_ok,
+ PerlIOBase_popped,
PerlIOStdio_open,
NULL,
PerlIOStdio_fileno,
/* Reload n as some layers may pop themselves on seek */
b->posn = PerlIO_tell(n = PerlIONext(f));
}
+ else {
+ return code;
+ }
}
}
b->ptr = b->end = b->buf;
PerlIOBase(f)->flags &= ~PERLIO_F_EOF;
}
}
+ if (count > 0) {
+ unread += PerlIOBase_unread(aTHX_ f, vbuf, count);
+ }
return unread;
}
}
IV
+PerlIOBuf_popped(pTHX_ PerlIO *f)
+{
+ IV code = PerlIOBase_popped(aTHX_ f);
+ PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf);
+ if (b->buf && b->buf != (STDCHAR *) & b->oneword) {
+ Safefree(b->buf);
+ }
+ b->buf = NULL;
+ b->ptr = b->end = b->buf;
+ PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF | PERLIO_F_WRBUF);
+ return code;
+}
+
+IV
PerlIOBuf_close(pTHX_ PerlIO *f)
{
IV code = PerlIOBase_close(aTHX_ f);
sizeof(PerlIOBuf),
PERLIO_K_BUFFERED,
PerlIOBuf_pushed,
- PerlIOBase_noop_ok,
+ PerlIOBuf_popped,
PerlIOBuf_open,
NULL,
PerlIOBase_fileno,
sizeof(PerlIOBuf),
PERLIO_K_BUFFERED,
PerlIOPending_pushed,
- PerlIOBase_noop_ok,
+ PerlIOBuf_popped,
NULL,
NULL,
PerlIOBase_fileno,
sizeof(PerlIOCrlf),
PERLIO_K_BUFFERED | PERLIO_K_CANCRLF,
PerlIOCrlf_pushed,
- PerlIOBase_noop_ok, /* popped */
+ PerlIOBuf_popped, /* popped */
PerlIOBuf_open,
NULL,
PerlIOBase_fileno,
sizeof(PerlIOMmap),
PERLIO_K_BUFFERED,
PerlIOBuf_pushed,
- PerlIOBase_noop_ok,
+ PerlIOBuf_popped,
PerlIOBuf_open,
NULL,
PerlIOBase_fileno,