X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=perlio.c;h=11f600fc5f9b3999ea9f47e6862e992202f97110;hb=884421df72ae457696a47f102b65bb9c9142c6f8;hp=b59737c6692cebf2853e3473afbfa01e4fd7f42c;hpb=18586f540e901386eb982e521eebc21ac6d8289c;p=p5sagit%2Fp5-mst-13.2.git diff --git a/perlio.c b/perlio.c index b59737c..11f600f 100644 --- a/perlio.c +++ b/perlio.c @@ -5,6 +5,11 @@ */ /* + * Hour after hour for nearly three weary days he had jogged up and down, + * over passes, and through long dales, and across many streams. + */ + +/* * If we have ActivePerl-like PERL_IMPLICIT_SYS then we need a dTHX to get * at the dispatch tables, even when we do not need it for other reasons. * Invent a dSYS macro to abstract this out @@ -101,7 +106,7 @@ perlsio_binmode(FILE *fp, int iotype, int mode) } #ifndef O_ACCMODE -#define O_ACCMODE 3 /* Assume traditional implementation */ +#define O_ACCMODE 3 /* Assume traditional implementation */ #endif int @@ -153,7 +158,11 @@ PerlIO_intmode2str(int rawmode, char *mode, int *writing) 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); @@ -181,7 +190,15 @@ PerlIO_binmode(pTHX_ PerlIO *fp, int iotype, int mode, const char *names) PerlIO * PerlIO_fdupopen(pTHX_ PerlIO *f, CLONE_PARAMS *param, int flags) { -#ifndef PERL_MICRO +#ifdef PERL_MICRO + return NULL; +#else +#ifdef PERL_IMPLICIT_SYS + return PerlSIO_fdupopen(f); +#else +#ifdef WIN32 + return win32_fdupopen(f); +#else if (f) { int fd = PerlLIO_dup(PerlIO_fileno(f)); if (fd >= 0) { @@ -201,6 +218,8 @@ PerlIO_fdupopen(pTHX_ PerlIO *f, CLONE_PARAMS *param, int flags) } #endif return NULL; +#endif +#endif } @@ -282,7 +301,7 @@ PerlIO_tmpfile(void) return tmpfile(); } -#else /* PERLIO_IS_STDIO */ +#else /* PERLIO_IS_STDIO */ #ifdef USE_SFIO @@ -318,12 +337,15 @@ PerlIO_init(pTHX) sfset(sfstdout, SF_SHARE, 0); } +/* This is not the reverse of PerlIO_exportFILE(), PerlIO_releaseFILE() is. */ PerlIO * -PerlIO_importFILE(FILE *stdio, int fl) +PerlIO_importFILE(FILE *stdio, const char *mode) { int fd = fileno(stdio); - PerlIO *r = PerlIO_fdopen(fd, "r+"); - return r; + if (!mode || !*mode) { + mode = "r+"; + } + return PerlIO_fdopen(fd, mode); } FILE * @@ -340,7 +362,7 @@ PerlIO_findFILE(PerlIO *pio) } -#else /* USE_SFIO */ +#else /* USE_SFIO */ /*======================================================================================*/ /* * Implement all the PerlIO interface ourselves. @@ -388,7 +410,7 @@ PerlIO_debug(const char *fmt, ...) if (!s) s = "(none)"; sprintf(buffer, "%s:%" IVdf " ", s, (IV) CopLINE(PL_curcop)); - len = strlen(buffer); + len = strlen(buffer); vsprintf(buffer+len, fmt, ap); PerlLIO_write(dbg, buffer, strlen(buffer)); #else @@ -455,7 +477,7 @@ PerlIO_fdupopen(pTHX_ PerlIO *f, CLONE_PARAMS *param, int flags) PerlIO_funcs *tab = PerlIOBase(f)->tab; PerlIO *new; PerlIO_debug("fdupopen f=%p param=%p\n",(void*)f,(void*)param); - new = (*tab->Dup)(aTHX_ PerlIO_allocate(aTHX),f,param, flags); + new = (*tab->Dup)(aTHX_ PerlIO_allocate(aTHX),f,param, flags); return new; } else { @@ -596,10 +618,6 @@ PerlIO_destruct(pTHX) f++; } } - PerlIO_list_free(aTHX_ PL_known_layers); - PL_known_layers = NULL; - PerlIO_list_free(aTHX_ PL_def_layerlist); - PL_def_layerlist = NULL; } void @@ -617,7 +635,7 @@ PerlIO_pop(pTHX_ PerlIO *f) if ((*l->tab->Popped) (aTHX_ f) != 0) return; } - *f = l->next;; + *f = l->next; Safefree(l); } } @@ -699,7 +717,7 @@ perlio_mg_free(pTHX_ SV *sv, MAGIC *mg) MGVTBL perlio_vtab = { perlio_mg_get, perlio_mg_set, - NULL, /* len */ + NULL, /* len */ perlio_mg_clear, perlio_mg_free }; @@ -734,7 +752,7 @@ XS(XS_io_MODIFY_SCALAR_ATTRIBUTES) XSRETURN(count); } -#endif /* USE_ATTIBUTES_FOR_PERLIO */ +#endif /* USE_ATTIBUTES_FOR_PERLIO */ SV * PerlIO_tab_sv(pTHX_ PerlIO_funcs *tab) @@ -790,9 +808,11 @@ PerlIO_parse_layers(pTHX_ PerlIO_list_t *av, const char *names) * seen as an invalid separator character. */ char q = ((*s == '\'') ? '"' : '\''); - Perl_warn(aTHX_ + if (ckWARN(WARN_LAYER)) + 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 { @@ -825,7 +845,8 @@ PerlIO_parse_layers(pTHX_ PerlIO_list_t *av, const char *names) */ case '\0': e--; - Perl_warn(aTHX_ + if (ckWARN(WARN_LAYER)) + Perl_warner(aTHX_ packWARN(WARN_LAYER), "perlio: argument list not closed for layer \"%.*s\"", (int) (e - s), s); return -1; @@ -838,6 +859,7 @@ PerlIO_parse_layers(pTHX_ PerlIO_list_t *av, const char *names) } } if (e > s) { + bool warn_layer = ckWARN(WARN_LAYER); PerlIO_funcs *layer = PerlIO_find_layer(aTHX_ s, llen, 1); if (layer) { @@ -847,7 +869,8 @@ PerlIO_parse_layers(pTHX_ PerlIO_list_t *av, const char *names) &PL_sv_undef); } else { - Perl_warn(aTHX_ "perlio: unknown layer \"%.*s\"", + if (warn_layer) + Perl_warner(aTHX_ packWARN(WARN_LAYER), "perlio: unknown layer \"%.*s\"", (int) llen, s); return -1; } @@ -867,7 +890,7 @@ PerlIO_default_buffer(pTHX_ PerlIO_list_t *av) tab = &PerlIO_crlf; #else if (PerlIO_stdio.Set_ptrcnt) - tab = &PerlIO_stdio; + tab = &PerlIO_stdio; #endif PerlIO_debug("Pushing %s\n", tab->name); PerlIO_list_push(aTHX_ av, PerlIO_find_layer(aTHX_ tab->name, 0, 0), @@ -893,6 +916,46 @@ PerlIO_layer_fetch(pTHX_ PerlIO_list_t *av, IV n, PerlIO_funcs *def) return def; } +IV +PerlIOPop_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) +{ + if (PerlIOValid(f)) { + PerlIO_flush(f); + PerlIO_pop(aTHX_ f); + return 0; + } + return -1; +} + +PerlIO_funcs PerlIO_remove = { + sizeof(PerlIO_funcs), + "pop", + 0, + PERLIO_K_DUMMY | PERLIO_K_UTF8, + PerlIOPop_pushed, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* flush */ + NULL, /* fill */ + NULL, + NULL, + NULL, + NULL, + NULL, /* get_base */ + NULL, /* get_bufsiz */ + NULL, /* get_ptr */ + NULL, /* get_cnt */ + NULL, /* set_ptrcnt */ +}; + PerlIO_list_t * PerlIO_default_layers(pTHX) { @@ -915,6 +978,7 @@ PerlIO_default_layers(pTHX) PerlIO_define_layer(aTHX_ & PerlIO_mmap); #endif PerlIO_define_layer(aTHX_ & PerlIO_utf8); + PerlIO_define_layer(aTHX_ & PerlIO_remove); PerlIO_define_layer(aTHX_ & PerlIO_byte); PerlIO_list_push(aTHX_ PL_def_layerlist, PerlIO_find_layer(aTHX_ osLayer->name, 0, 0), @@ -968,17 +1032,35 @@ PerlIO_stdstreams(pTHX) PerlIO * PerlIO_push(pTHX_ PerlIO *f, PerlIO_funcs *tab, const char *mode, SV *arg) { - PerlIOl *l = NULL; - Newc('L',l,tab->size,char,PerlIOl); - if (l && f) { - Zero(l, tab->size, char); - l->next = *f; - l->tab = tab; - *f = l; + if (tab->fsize != sizeof(PerlIO_funcs)) { + mismatch: + Perl_croak(aTHX_ "Layer does not match this perl"); + } + if (tab->size) { + PerlIOl *l = NULL; + if (tab->size < sizeof(PerlIOl)) { + goto mismatch; + } + /* Real layer with a data area */ + Newc('L',l,tab->size,char,PerlIOl); + if (l && f) { + Zero(l, tab->size, char); + l->next = *f; + l->tab = tab; + *f = l; + PerlIO_debug("PerlIO_push f=%p %s %s %p\n", (void*)f, tab->name, + (mode) ? mode : "(Null)", (void*)arg); + if ((*l->tab->Pushed) (aTHX_ f, mode, arg, tab) != 0) { + PerlIO_pop(aTHX_ f); + return NULL; + } + } + } + else if (f) { + /* Pseudo-layer where push does its own stack adjust */ PerlIO_debug("PerlIO_push f=%p %s %s %p\n", (void*)f, tab->name, (mode) ? mode : "(Null)", (void*)arg); - if ((*l->tab->Pushed) (aTHX_ f, mode, arg) != 0) { - PerlIO_pop(aTHX_ f); + if ((*tab->Pushed) (aTHX_ f, mode, arg, tab) != 0) { return NULL; } } @@ -986,54 +1068,65 @@ PerlIO_push(pTHX_ PerlIO *f, PerlIO_funcs *tab, const char *mode, SV *arg) } IV -PerlIOPop_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg) +PerlIOBase_binmode(pTHX_ PerlIO *f) { - PerlIO_pop(aTHX_ f); - if (*f) { - PerlIO_flush(f); - PerlIO_pop(aTHX_ f); + if (PerlIOValid(f)) { + /* Is layer suitable for raw stream ? */ + if (PerlIOBase(f)->tab->kind & PERLIO_K_RAW) { + /* Yes - turn off UTF-8-ness, to undo UTF-8 locale effects */ + PerlIOBase(f)->flags &= ~PERLIO_F_UTF8; + } + else { + /* Not suitable - pop it */ + PerlIO_pop(aTHX_ f); + } return 0; - } - return -1; + } + return -1; } IV -PerlIORaw_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg) +PerlIORaw_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { - /* - * Remove the dummy layer - */ - PerlIO_pop(aTHX_ f); - /* - * Pop back to bottom layer - */ + if (PerlIOValid(f)) { + PerlIO *t; + PerlIOl *l; PerlIO_flush(f); - while (!(PerlIOBase(f)->tab->kind & PERLIO_K_RAW)) { - if (*PerlIONext(f)) { - PerlIO_pop(aTHX_ f); + /* + * Strip all layers that are not suitable for a raw stream + */ + t = f; + while (t && (l = *t)) { + if (l->tab->Binmode) { + /* Has a handler - normal case */ + if ((*l->tab->Binmode)(aTHX_ f) == 0) { + if (*t == l) { + /* Layer still there - move down a layer */ + t = PerlIONext(t); + } + } + else { + return -1; + } } else { - /* - * Nothing bellow - push unix on top then remove it - */ - if (PerlIO_push(aTHX_ f, PerlIO_default_btm(), mode, arg)) { - PerlIO_pop(aTHX_ PerlIONext(f)); - } - break; + /* No handler - pop it */ + PerlIO_pop(aTHX_ t); } } - PerlIO_debug(":raw f=%p :%s\n", (void*)f, PerlIOBase(f)->tab->name); - return 0; + if (PerlIOValid(f)) { + PerlIO_debug(":raw f=%p :%s\n", (void*)f, PerlIOBase(f)->tab->name); + return 0; + } } return -1; } int PerlIO_apply_layera(pTHX_ PerlIO *f, const char *mode, - PerlIO_list_t *layers, IV n) + PerlIO_list_t *layers, IV n, IV max) { - IV max = layers->cur; int code = 0; while (n < max) { PerlIO_funcs *tab = PerlIO_layer_fetch(aTHX_ layers, n, NULL); @@ -1056,7 +1149,7 @@ PerlIO_apply_layers(pTHX_ PerlIO *f, const char *mode, const char *names) PerlIO_list_t *layers = PerlIO_list_alloc(aTHX); code = PerlIO_parse_layers(aTHX_ layers, names); if (code == 0) { - code = PerlIO_apply_layera(aTHX_ f, mode, layers, 0); + code = PerlIO_apply_layera(aTHX_ f, mode, layers, 0, layers->cur); } PerlIO_list_free(aTHX_ layers); } @@ -1084,16 +1177,17 @@ PerlIO_binmode(pTHX_ PerlIO *f, int iotype, int mode, const char *names) 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 - */ + /* Fake 5.6 legacy of using this call to turn ON O_TEXT */ #ifdef PERLIO_USING_CRLF /* 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 */ + /* 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 + */ while (*f) { /* Perhaps we should turn on bottom-most aware layer e.g. Ilya's idea that UNIX TTY could serve @@ -1116,31 +1210,10 @@ PerlIO_binmode(pTHX_ PerlIO *f, int iotype, int mode, const char *names) 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. + /* Legacy binmode is now _defined_ as being equivalent to pushing :raw + So code that used to be here is now in PerlIORaw_pushed(). */ - 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_push(aTHX_ f, &PerlIO_raw, Nullch, Nullsv) ? TRUE : FALSE; } } @@ -1196,7 +1269,7 @@ PerlIO_context_layers(pTHX_ const char *mode) * Skip to write part */ const char *s = strchr(type, 0); - if (s && (s - type) < len) { + if (s && (STRLEN)(s - type) < len) { type = s + 1; } } @@ -1212,7 +1285,7 @@ PerlIO_layer_from_ref(pTHX_ SV *sv) * For any scalar type load the handler which is bundled with perl */ if (SvTYPE(sv) < SVt_PVAV) - return PerlIO_find_layer(aTHX_ "Scalar", 6, 1); + return PerlIO_find_layer(aTHX_ "scalar", 6, 1); /* * For other types allow if layer is known but don't try and load it @@ -1252,7 +1325,7 @@ PerlIO_resolve_layers(pTHX_ const char *layers, incdef = 0; } /* - * Don't fail if handler cannot be found :Via(...) etc. may do + * Don't fail if handler cannot be found :via(...) etc. may do * something sensible else we will just stringfy and open * resulting string. */ @@ -1273,8 +1346,13 @@ PerlIO_resolve_layers(pTHX_ const char *layers, 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) @@ -1316,6 +1394,9 @@ PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd, } else { layera = PerlIO_resolve_layers(aTHX_ layers, mode, narg, args); + if (!layera) { + return NULL; + } } /* * Start at "top" of layer stack @@ -1347,8 +1428,9 @@ PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd, * More layers above the one that we used to open - * apply them now */ - if (PerlIO_apply_layera(aTHX_ f, mode, layera, n + 1) - != 0) { + if (PerlIO_apply_layera(aTHX_ f, mode, layera, n + 1, layera->cur) != 0) { + /* If pushing layers fails close the file */ + PerlIO_close(f); f = NULL; } } @@ -1639,17 +1721,16 @@ Perl_PerlIO_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, int cnt) } } + /*--------------------------------------------------------------------------------------*/ /* * utf8 and raw dummy layers */ IV -PerlIOUtf8_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg) +PerlIOUtf8_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { - if (*PerlIONext(f)) { - PerlIO_funcs *tab = PerlIOBase(f)->tab; - PerlIO_pop(aTHX_ f); + if (PerlIOValid(f)) { if (tab->kind & PERLIO_K_UTF8) PerlIOBase(f)->flags |= PERLIO_F_UTF8; else @@ -1660,9 +1741,10 @@ PerlIOUtf8_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg) } PerlIO_funcs PerlIO_utf8 = { + sizeof(PerlIO_funcs), "utf8", - sizeof(PerlIOl), - PERLIO_K_DUMMY | PERLIO_F_UTF8, + 0, + PERLIO_K_DUMMY | PERLIO_K_UTF8, PerlIOUtf8_pushed, NULL, NULL, @@ -1674,22 +1756,23 @@ PerlIO_funcs PerlIO_utf8 = { NULL, NULL, NULL, - NULL, /* flush */ - NULL, /* fill */ + NULL, /* flush */ + NULL, /* fill */ NULL, NULL, NULL, NULL, - NULL, /* get_base */ - NULL, /* get_bufsiz */ - NULL, /* get_ptr */ - NULL, /* get_cnt */ - NULL, /* set_ptrcnt */ + NULL, /* get_base */ + NULL, /* get_bufsiz */ + NULL, /* get_ptr */ + NULL, /* get_cnt */ + NULL, /* set_ptrcnt */ }; PerlIO_funcs PerlIO_byte = { + sizeof(PerlIO_funcs), "bytes", - sizeof(PerlIOl), + 0, PERLIO_K_DUMMY, PerlIOUtf8_pushed, NULL, @@ -1702,17 +1785,17 @@ PerlIO_funcs PerlIO_byte = { NULL, NULL, NULL, - NULL, /* flush */ - NULL, /* fill */ + NULL, /* flush */ + NULL, /* fill */ NULL, NULL, NULL, NULL, - NULL, /* get_base */ - NULL, /* get_bufsiz */ - NULL, /* get_ptr */ - NULL, /* get_cnt */ - NULL, /* set_ptrcnt */ + NULL, /* get_base */ + NULL, /* get_bufsiz */ + NULL, /* get_ptr */ + NULL, /* get_cnt */ + NULL, /* set_ptrcnt */ }; PerlIO * @@ -1726,8 +1809,9 @@ PerlIORaw_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, } PerlIO_funcs PerlIO_raw = { + sizeof(PerlIO_funcs), "raw", - sizeof(PerlIOl), + 0, PERLIO_K_DUMMY, PerlIORaw_pushed, PerlIOBase_popped, @@ -1740,17 +1824,17 @@ PerlIO_funcs PerlIO_raw = { NULL, NULL, NULL, - NULL, /* flush */ - NULL, /* fill */ + NULL, /* flush */ + NULL, /* fill */ NULL, NULL, NULL, NULL, - NULL, /* get_base */ - NULL, /* get_bufsiz */ - NULL, /* get_ptr */ - NULL, /* get_cnt */ - NULL, /* set_ptrcnt */ + NULL, /* get_base */ + NULL, /* get_bufsiz */ + NULL, /* get_ptr */ + NULL, /* get_cnt */ + NULL, /* set_ptrcnt */ }; /*--------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------*/ @@ -1765,44 +1849,46 @@ PerlIOBase_fileno(pTHX_ PerlIO *f) } char * -PerlIO_modestr(PerlIO *f, char *buf) +PerlIO_modestr(PerlIO * f, char *buf) { char *s = buf; - IV flags = PerlIOBase(f)->flags; - if (flags & PERLIO_F_APPEND) { - *s++ = 'a'; - if (flags & PERLIO_F_CANREAD) { - *s++ = '+'; + if (PerlIOValid(f)) { + IV flags = PerlIOBase(f)->flags; + if (flags & PERLIO_F_APPEND) { + *s++ = 'a'; + if (flags & PERLIO_F_CANREAD) { + *s++ = '+'; + } } - } - else if (flags & PERLIO_F_CANREAD) { - *s++ = 'r'; - if (flags & PERLIO_F_CANWRITE) - *s++ = '+'; - } - else if (flags & PERLIO_F_CANWRITE) { - *s++ = 'w'; - if (flags & PERLIO_F_CANREAD) { - *s++ = '+'; + else if (flags & PERLIO_F_CANREAD) { + *s++ = 'r'; + if (flags & PERLIO_F_CANWRITE) + *s++ = '+'; + } + else if (flags & PERLIO_F_CANWRITE) { + *s++ = 'w'; + if (flags & PERLIO_F_CANREAD) { + *s++ = '+'; + } } - } #ifdef PERLIO_USING_CRLF - if (!(flags & PERLIO_F_CRLF)) - *s++ = 'b'; + if (!(flags & PERLIO_F_CRLF)) + *s++ = 'b'; #endif + } *s = '\0'; return buf; } + IV -PerlIOBase_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg) +PerlIOBase_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { PerlIOl *l = PerlIOBase(f); #if 0 const char *omode = mode; char temp[8]; #endif - PerlIO_funcs *tab = PerlIOBase(f)->tab; l->flags &= ~(PERLIO_F_CANREAD | PERLIO_F_CANWRITE | PERLIO_F_TRUNCATE | PERLIO_F_APPEND); if (tab->Set_ptrcnt != NULL) @@ -1887,7 +1973,7 @@ PerlIOBase_read(pTHX_ PerlIO *f, void *vbuf, Size_t count) SSize_t avail = PerlIO_get_cnt(f); SSize_t take = 0; if (avail > 0) - take = (count < avail) ? count : avail; + take = ((SSize_t)count < avail) ? count : avail; if (take > 0) { STDCHAR *ptr = PerlIO_get_ptr(f); Copy(ptr, buf, take, STDCHAR); @@ -2062,7 +2148,9 @@ PerlIO_cleanup(pTHX) { int i; #ifdef USE_ITHREADS - PerlIO_debug("Cleanup %p\n",aTHX); + PerlIO_debug("Cleanup layers for %p\n",aTHX); +#else + PerlIO_debug("Cleanup layers\n"); #endif /* Raise STDIN..STDERR refcount so we don't close them */ for (i=0; i < 3; i++) @@ -2071,6 +2159,15 @@ PerlIO_cleanup(pTHX) /* Restore STDIN..STDERR refcount */ for (i=0; i < 3; i++) PerlIOUnix_refcnt_dec(i); + + if (PL_known_layers) { + PerlIO_list_free(aTHX_ PL_known_layers); + PL_known_layers = NULL; + } + if(PL_def_layerlist) { + PerlIO_list_free(aTHX_ PL_def_layerlist); + PL_def_layerlist = NULL; + } } @@ -2081,9 +2178,9 @@ PerlIO_cleanup(pTHX) */ typedef struct { - struct _PerlIO base; /* The generic part */ - int fd; /* UNIX like file descriptor */ - int oflags; /* open/fcntl flags */ + struct _PerlIO base; /* The generic part */ + int fd; /* UNIX like file descriptor */ + int oflags; /* open/fcntl flags */ } PerlIOUnix; int @@ -2149,12 +2246,12 @@ PerlIOUnix_fileno(pTHX_ PerlIO *f) } IV -PerlIOUnix_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg) +PerlIOUnix_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { - IV code = PerlIOBase_pushed(aTHX_ f, mode, arg); + IV code = PerlIOBase_pushed(aTHX_ f, mode, arg, tab); PerlIOUnix *s = PerlIOSelf(f, PerlIOUnix); if (*PerlIONext(f)) { - /* We never call down so any pending stuff now */ + /* We never call down so do any pending stuff now */ PerlIO_flush(PerlIONext(f)); s->fd = PerlIO_fileno(PerlIONext(f)); /* @@ -2173,7 +2270,7 @@ PerlIOUnix_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)) { if (PerlIOBase(f)->flags & PERLIO_F_OPEN) (*PerlIOBase(f)->tab->Close)(aTHX_ f); } @@ -2195,15 +2292,17 @@ PerlIOUnix_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, mode++; if (!f) { f = PerlIO_allocate(aTHX); - s = PerlIOSelf(PerlIO_push(aTHX_ f, self, mode, PerlIOArg), - PerlIOUnix); } - else - s = PerlIOSelf(f, PerlIOUnix); + if (!PerlIOValid(f)) { + if (!(f = PerlIO_push(aTHX_ f, self, mode, PerlIOArg))) { + return NULL; + } + } + s = PerlIOSelf(f, PerlIOUnix); s->fd = fd; s->oflags = imode; PerlIOBase(f)->flags |= PERLIO_F_OPEN; - PerlIOUnix_refcnt_inc(fd); + PerlIOUnix_refcnt_inc(fd); return f; } else { @@ -2242,8 +2341,10 @@ SSize_t PerlIOUnix_read(pTHX_ PerlIO *f, void *vbuf, Size_t count) { int fd = PerlIOSelf(f, PerlIOUnix)->fd; - if (!(PerlIOBase(f)->flags & PERLIO_F_CANREAD)) + if (!(PerlIOBase(f)->flags & PERLIO_F_CANREAD) || + PerlIOBase(f)->flags & (PERLIO_F_EOF|PERLIO_F_ERROR)) { return 0; + } while (1) { SSize_t len = PerlLIO_read(fd, vbuf, count); if (len >= 0 || errno != EINTR) { @@ -2297,7 +2398,7 @@ PerlIOUnix_close(pTHX_ PerlIO *f) if (PerlIOUnix_refcnt_dec(fd) > 0) { PerlIOBase(f)->flags &= ~PERLIO_F_OPEN; return 0; - } + } } else { SETERRNO(EBADF,SS$_IVCHAN); @@ -2317,12 +2418,14 @@ PerlIOUnix_close(pTHX_ PerlIO *f) } PerlIO_funcs PerlIO_unix = { + sizeof(PerlIO_funcs), "unix", sizeof(PerlIOUnix), PERLIO_K_RAW, PerlIOUnix_pushed, - PerlIOBase_noop_ok, + PerlIOBase_popped, PerlIOUnix_open, + PerlIOBase_binmode, /* binmode */ NULL, PerlIOUnix_fileno, PerlIOUnix_dup, @@ -2332,17 +2435,17 @@ PerlIO_funcs PerlIO_unix = { PerlIOUnix_seek, PerlIOUnix_tell, PerlIOUnix_close, - PerlIOBase_noop_ok, /* flush */ - PerlIOBase_noop_fail, /* fill */ + PerlIOBase_noop_ok, /* flush */ + PerlIOBase_noop_fail, /* fill */ PerlIOBase_eof, PerlIOBase_error, PerlIOBase_clearerr, PerlIOBase_setlinebuf, - NULL, /* get_base */ - NULL, /* get_bufsiz */ - NULL, /* get_ptr */ - NULL, /* get_cnt */ - NULL, /* set_ptrcnt */ + NULL, /* get_base */ + NULL, /* get_bufsiz */ + NULL, /* get_ptr */ + NULL, /* get_cnt */ + NULL, /* set_ptrcnt */ }; /*--------------------------------------------------------------------------------------*/ @@ -2350,15 +2453,28 @@ PerlIO_funcs PerlIO_unix = { * 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 */ + FILE *stdio; /* The stream */ } PerlIOStdio; IV PerlIOStdio_fileno(pTHX_ PerlIO *f) { - return PerlSIO_fileno(PerlIOSelf(f, PerlIOStdio)->stdio); + FILE *s; + if (PerlIOValid(f) && (s = PerlIOSelf(f, PerlIOStdio)->stdio)) { + return PerlSIO_fileno(s); + } + errno = EBADF; + return -1; } char * @@ -2375,40 +2491,69 @@ PerlIOStdio_mode(const char *mode, char *tmode) return ret; } -/* - * This isn't used yet ... - */ IV -PerlIOStdio_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg) +PerlIOStdio_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { - if (*PerlIONext(f)) { - PerlIOStdio *s = PerlIOSelf(f, PerlIOStdio); - char tmode[8]; - FILE *stdio = - PerlSIO_fdopen(PerlIO_fileno(PerlIONext(f)), mode = - PerlIOStdio_mode(mode, tmode)); - if (stdio) { - s->stdio = stdio; - /* We never call down so any pending stuff now */ - PerlIO_flush(PerlIONext(f)); - } - else - return -1; + PerlIO *n; + if (PerlIOValid(f) && PerlIOValid(n = PerlIONext(f))) { + PerlIO_funcs *toptab = PerlIOBase(n)->tab; + if (toptab == tab) { + /* Top is already stdio - pop self (duplicate) and use original */ + PerlIO_pop(aTHX_ f); + return 0; + } else { + int fd = PerlIO_fileno(n); + char tmode[8]; + FILE *stdio; + if (fd >= 0 && (stdio = PerlSIO_fdopen(fd, + mode = PerlIOStdio_mode(mode, tmode)))) { + PerlIOSelf(f, PerlIOStdio)->stdio = stdio; + /* We never call down so do any pending stuff now */ + PerlIO_flush(PerlIONext(f)); + } + else { + return -1; + } + } } - return PerlIOBase_pushed(aTHX_ f, mode, arg); + return PerlIOBase_pushed(aTHX_ f, mode, arg, tab); } + PerlIO * -PerlIO_importFILE(FILE *stdio, int fl) +PerlIO_importFILE(FILE *stdio, const char *mode) { dTHX; PerlIO *f = NULL; if (stdio) { - PerlIOStdio *s = - PerlIOSelf(PerlIO_push - (aTHX_(f = PerlIO_allocate(aTHX)), &PerlIO_stdio, - "r+", Nullsv), PerlIOStdio); - s->stdio = stdio; + PerlIOStdio *s; + if (!mode || !*mode) { + /* 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)); + FILE *f2 = PerlSIO_fdopen(fd, (mode = "r+")); + if (!f2) { + f2 = PerlSIO_fdopen(fd, (mode = "w")); + } + if (!f2) { + f2 = PerlSIO_fdopen(fd, (mode = "r")); + } + if (!f2) { + /* Don't seem to be able to open */ + PerlLIO_close(fd); + return f; + } + fclose(f2); + } + if ((f = PerlIO_push(aTHX_(f = PerlIO_allocate(aTHX)), &PerlIO_stdio, mode, Nullsv))) { + s = PerlIOSelf(f, PerlIOStdio); + s->stdio = stdio; + } } return f; } @@ -2419,7 +2564,7 @@ PerlIOStdio_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, int perm, PerlIO *f, int narg, SV **args) { char tmode[8]; - if (f) { + if (PerlIOValid(f)) { char *path = SvPV_nolen(*args); PerlIOStdio *s = PerlIOSelf(f, PerlIOStdio); FILE *stdio; @@ -2442,16 +2587,22 @@ PerlIOStdio_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, else { FILE *stdio = PerlSIO_fopen(path, mode); if (stdio) { - PerlIOStdio *s = - PerlIOSelf(PerlIO_push - (aTHX_(f = PerlIO_allocate(aTHX)), self, + PerlIOStdio *s; + if (!f) { + f = PerlIO_allocate(aTHX); + } + if ((f = PerlIO_push(aTHX_ f, self, (mode = PerlIOStdio_mode(mode, tmode)), - PerlIOArg), - PerlIOStdio); - s->stdio = stdio; - PerlIOUnix_refcnt_inc(fileno(s->stdio)); + PerlIOArg))) { + s = PerlIOSelf(f, PerlIOStdio); + s->stdio = stdio; + PerlIOUnix_refcnt_inc(fileno(s->stdio)); + } + return f; + } + else { + return NULL; } - return f; } } if (fd >= 0) { @@ -2479,12 +2630,15 @@ PerlIOStdio_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, PerlIOStdio_mode(mode, tmode)); } if (stdio) { - PerlIOStdio *s = - PerlIOSelf(PerlIO_push - (aTHX_(f = PerlIO_allocate(aTHX)), self, - mode, PerlIOArg), PerlIOStdio); - s->stdio = stdio; - PerlIOUnix_refcnt_inc(fileno(s->stdio)); + PerlIOStdio *s; + if (!f) { + f = PerlIO_allocate(aTHX); + } + if ((f = PerlIO_push(aTHX_ f, self, mode, PerlIOArg))) { + s = PerlIOSelf(f, PerlIOStdio); + s->stdio = stdio; + PerlIOUnix_refcnt_inc(fileno(s->stdio)); + } return f; } } @@ -2504,7 +2658,7 @@ PerlIOStdio_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags) int fd = PerlLIO_dup(fileno(stdio)); if (fd >= 0) { char mode[8]; - stdio = fdopen(fd, PerlIO_modestr(o,mode)); + stdio = PerlSIO_fdopen(fd, PerlIO_modestr(o,mode)); } else { /* FIXME: To avoid messy error recovery if dup fails @@ -2526,10 +2680,13 @@ PerlIOStdio_close(pTHX_ PerlIO *f) Sock_size_t optlen = sizeof(int); #endif FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio; + if (!stdio) { + errno = EBADF; + return -1; + } if (PerlIOUnix_refcnt_dec(fileno(stdio)) > 0) { /* Do not close it but do flush any buffers */ - PerlIO_flush(f); - return 0; + return PerlIO_flush(f); } return ( #ifdef SOCKS5_VERSION_NAME @@ -2571,15 +2728,57 @@ PerlIOStdio_read(pTHX_ PerlIO *f, void *vbuf, Size_t count) 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; } @@ -2632,24 +2831,6 @@ PerlIOStdio_flush(pTHX_ PerlIO *f) } 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); @@ -2714,7 +2895,7 @@ PerlIOStdio_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt) FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio; if (ptr != NULL) { #ifdef STDIO_PTR_LVALUE - PerlSIO_set_ptr(stdio, (void*)ptr); /* LHS STDCHAR* cast non-portable */ + PerlSIO_set_ptr(stdio, (void*)ptr); /* LHS STDCHAR* cast non-portable */ #ifdef STDIO_PTR_LVAL_SETS_CNT if (PerlSIO_get_cnt(stdio) != (cnt)) { assert(PerlSIO_get_cnt(stdio) == (cnt)); @@ -2726,35 +2907,101 @@ PerlIOStdio_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt) */ return; #endif -#else /* STDIO_PTR_LVALUE */ +#else /* STDIO_PTR_LVALUE */ PerlProc_abort(); -#endif /* STDIO_PTR_LVALUE */ +#endif /* STDIO_PTR_LVALUE */ } /* * Now (or only) set cnt */ #ifdef STDIO_CNT_LVALUE PerlSIO_set_cnt(stdio, cnt); -#else /* STDIO_CNT_LVALUE */ +#else /* STDIO_CNT_LVALUE */ #if (defined(STDIO_PTR_LVALUE) && defined(STDIO_PTR_LVAL_SETS_CNT)) PerlSIO_set_ptr(stdio, PerlSIO_get_ptr(stdio) + (PerlSIO_get_cnt(stdio) - cnt)); -#else /* STDIO_PTR_LVAL_SETS_CNT */ +#else /* STDIO_PTR_LVAL_SETS_CNT */ PerlProc_abort(); -#endif /* STDIO_PTR_LVAL_SETS_CNT */ -#endif /* STDIO_CNT_LVALUE */ +#endif /* STDIO_PTR_LVAL_SETS_CNT */ +#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 = { + sizeof(PerlIO_funcs), "stdio", sizeof(PerlIOStdio), - PERLIO_K_BUFFERED, - PerlIOBase_pushed, - PerlIOBase_noop_ok, + PERLIO_K_BUFFERED|PERLIO_K_RAW, + PerlIOStdio_pushed, + PerlIOBase_popped, PerlIOStdio_open, + PerlIOBase_binmode, /* binmode */ NULL, PerlIOStdio_fileno, PerlIOStdio_dup, @@ -2782,32 +3029,50 @@ PerlIO_funcs PerlIO_stdio = { PerlIOStdio_get_cnt, #if (defined(STDIO_PTR_LVALUE) && (defined(STDIO_CNT_LVALUE) || defined(STDIO_PTR_LVAL_SETS_CNT))) PerlIOStdio_set_ptrcnt -#else /* STDIO_PTR_LVALUE */ +#else /* STDIO_PTR_LVALUE */ NULL -#endif /* STDIO_PTR_LVALUE */ -#else /* USE_STDIO_PTR */ +#endif /* STDIO_PTR_LVALUE */ +#else /* USE_STDIO_PTR */ NULL, NULL, NULL -#endif /* USE_STDIO_PTR */ +#endif /* USE_STDIO_PTR */ }; +/* Note that calls to PerlIO_exportFILE() are reversed using + * PerlIO_releaseFILE(), not importFILE. */ FILE * -PerlIO_exportFILE(PerlIO *f, int fl) +PerlIO_exportFILE(PerlIO * f, const char *mode) { dTHX; - FILE *stdio; - PerlIO_flush(f); - stdio = fdopen(PerlIO_fileno(f), "r+"); - if (stdio) { - PerlIOStdio *s = - PerlIOSelf(PerlIO_push(aTHX_ f, &PerlIO_stdio, "r+", Nullsv), - PerlIOStdio); - s->stdio = stdio; + FILE *stdio = NULL; + if (PerlIOValid(f)) { + char buf[8]; + PerlIO_flush(f); + if (!mode || !*mode) { + mode = PerlIO_modestr(f, buf); + } + stdio = PerlSIO_fdopen(PerlIO_fileno(f), mode); + if (stdio) { + PerlIOl *l = *f; + /* De-link any lower layers so new :stdio sticks */ + *f = NULL; + if ((f = PerlIO_push(aTHX_ f, &PerlIO_stdio, buf, Nullsv))) { + PerlIOStdio *s = PerlIOSelf(f, PerlIOStdio); + s->stdio = stdio; + /* Link previous lower layers under new one */ + *PerlIONext(f) = l; + } + else { + /* restore layers list */ + *f = l; + } + } } return stdio; } + FILE * PerlIO_findFILE(PerlIO *f) { @@ -2819,12 +3084,27 @@ PerlIO_findFILE(PerlIO *f) } l = *PerlIONext(&l); } - return PerlIO_exportFILE(f, 0); + /* Uses fallback "mode" via PerlIO_modestr() in PerlIO_exportFILE */ + return PerlIO_exportFILE(f, Nullch); } +/* Use this to reverse PerlIO_exportFILE calls. */ void PerlIO_releaseFILE(PerlIO *p, FILE *f) { + PerlIOl *l; + while ((l = *p)) { + if (l->tab == &PerlIO_stdio) { + PerlIOStdio *s = PerlIOSelf(&l, PerlIOStdio); + if (s->stdio == f) { + dTHX; + PerlIO_pop(aTHX_ p); + return; + } + } + p = PerlIONext(p); + } + return; } /*--------------------------------------------------------------------------------------*/ @@ -2833,19 +3113,20 @@ PerlIO_releaseFILE(PerlIO *p, FILE *f) */ IV -PerlIOBuf_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg) +PerlIOBuf_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); int fd = PerlIO_fileno(f); - Off_t posn; if (fd >= 0 && PerlLIO_isatty(fd)) { PerlIOBase(f)->flags |= PERLIO_F_LINEBUF | PERLIO_F_TTY; } - posn = PerlIO_tell(PerlIONext(f)); - if (posn != (Off_t) - 1) { - b->posn = posn; + if (*PerlIONext(f)) { + Off_t posn = PerlIO_tell(PerlIONext(f)); + if (posn != (Off_t) - 1) { + b->posn = posn; + } } - return PerlIOBase_pushed(aTHX_ f, mode, arg); + return PerlIOBase_pushed(aTHX_ f, mode, arg, tab); } PerlIO * @@ -2858,7 +3139,7 @@ PerlIOBuf_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, 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, self) != 0) { return NULL; } } @@ -2872,9 +3153,9 @@ PerlIOBuf_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, */ } f = (*tab->Open) (aTHX_ tab, layers, n - 1, mode, fd, imode, perm, - NULL, narg, args); + f, narg, args); if (f) { - if (PerlIO_push(aTHX_ f, self, mode, PerlIOArg) == 0) { + if (PerlIO_push(aTHX_ f, self, mode, PerlIOArg) == 0) { /* * if push fails during open, open fails. close will pop us. */ @@ -2882,18 +3163,23 @@ PerlIOBuf_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, return NULL; } else { fd = PerlIO_fileno(f); -#ifdef PERLIO_USING_CRLF - /* - * do something about failing setmode()? --jhi - */ - PerlLIO_setmode(fd, O_BINARY); -#endif if (init && fd == 2) { /* * Initial stderr is unbuffered */ PerlIOBase(f)->flags |= PERLIO_F_UNBUF; } +#ifdef PERLIO_USING_CRLF +# ifdef PERLIO_IS_BINMODE_FD + if (PERLIO_IS_BINMODE_FD(fd)) + PerlIO_binmode(f, '<'/*not used*/, O_BINARY, Nullch); + else +# endif + /* + * do something about failing setmode()? --jhi + */ + PerlLIO_setmode(fd, O_BINARY); +#endif } } } @@ -2936,19 +3222,26 @@ PerlIOBuf_flush(pTHX_ PerlIO *f) */ b->posn += (b->ptr - buf); if (b->ptr < b->end) { - /* - * We did not consume all of it + /* We did not consume all of it - try and seek downstream to + our logical position */ - if (PerlIO_seek(n, b->posn, SEEK_SET) == 0) { + if (PerlIOValid(n) && 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)); } + else { + /* Seek failed (e.g. pipe or tty). Do NOT clear buffer or pre-read + data is lost for good - so return saying "ok" having undone + the position adjust + */ + b->posn -= (b->ptr - buf); + return code; + } } } b->ptr = b->end = b->buf; PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF | PERLIO_F_WRBUF); /* 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; @@ -2961,10 +3254,8 @@ PerlIOBuf_fill(pTHX_ PerlIO *f) PerlIO *n = PerlIONext(f); SSize_t avail; /* - * 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. + * Down-stream flush is defined not to loose read data so is harmless. + * we would not normally be fill'ing if there was data left in anycase. */ if (PerlIO_flush(f) != 0) return -1; @@ -2972,9 +3263,15 @@ PerlIOBuf_fill(pTHX_ PerlIO *f) PerlIOBase_flush_linebuf(aTHX); if (!b->buf) - PerlIO_get_base(f); /* allocate via vtable */ + PerlIO_get_base(f); /* allocate via vtable */ b->ptr = b->end = b->buf; + + if (!PerlIOValid(n)) { + PerlIOBase(f)->flags |= PERLIO_F_EOF; + return -1; + } + if (PerlIO_fast_gets(n)) { /* * Layer below is also buffered. We do _NOT_ want to call its @@ -2995,7 +3292,7 @@ PerlIOBuf_fill(pTHX_ PerlIO *f) if (avail > 0) { STDCHAR *ptr = PerlIO_get_ptr(n); SSize_t cnt = avail; - if (avail > b->bufsiz) + if (avail > (SSize_t)b->bufsiz) avail = b->bufsiz; Copy(ptr, b->buf, avail, STDCHAR); PerlIO_set_ptrcnt(n, ptr + avail, cnt - avail); @@ -3082,6 +3379,9 @@ PerlIOBuf_unread(pTHX_ PerlIO *f, const void *vbuf, Size_t count) PerlIOBase(f)->flags &= ~PERLIO_F_EOF; } } + if (count > 0) { + unread += PerlIOBase_unread(aTHX_ f, vbuf, count); + } return unread; } @@ -3163,6 +3463,20 @@ PerlIOBuf_tell(pTHX_ PerlIO *f) } 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); @@ -3247,12 +3561,14 @@ PerlIOBuf_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags) PerlIO_funcs PerlIO_perlio = { + sizeof(PerlIO_funcs), "perlio", sizeof(PerlIOBuf), - PERLIO_K_BUFFERED, + PERLIO_K_BUFFERED|PERLIO_K_RAW, PerlIOBuf_pushed, - PerlIOBase_noop_ok, + PerlIOBuf_popped, PerlIOBuf_open, + PerlIOBase_binmode, /* binmode */ NULL, PerlIOBase_fileno, PerlIOBuf_dup, @@ -3335,9 +3651,9 @@ PerlIOPending_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt) } IV -PerlIOPending_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg) +PerlIOPending_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { - IV code = PerlIOBase_pushed(aTHX_ f, mode, arg); + IV code = PerlIOBase_pushed(aTHX_ f, mode, arg, tab); PerlIOl *l = PerlIOBase(f); /* * Our PerlIO_fast_gets must match what we are pushed on, or sv_gets() @@ -3354,11 +3670,11 @@ PerlIOPending_read(pTHX_ PerlIO *f, void *vbuf, Size_t count) { SSize_t avail = PerlIO_get_cnt(f); SSize_t got = 0; - if (count < avail) + if ((SSize_t)count < avail) avail = count; if (avail > 0) got = PerlIOBuf_read(aTHX_ f, vbuf, avail); - if (got >= 0 && got < count) { + if (got >= 0 && got < (SSize_t)count) { SSize_t more = PerlIO_read(f, ((STDCHAR *) vbuf) + got, count - got); if (more >= 0 || got == 0) @@ -3368,12 +3684,14 @@ PerlIOPending_read(pTHX_ PerlIO *f, void *vbuf, Size_t count) } PerlIO_funcs PerlIO_pending = { + sizeof(PerlIO_funcs), "pending", sizeof(PerlIOBuf), - PERLIO_K_BUFFERED, + PERLIO_K_BUFFERED|PERLIO_K_RAW, /* not sure about RAW here */ PerlIOPending_pushed, - PerlIOBase_noop_ok, + PerlIOBuf_popped, NULL, + PerlIOBase_binmode, /* binmode */ NULL, PerlIOBase_fileno, PerlIOBuf_dup, @@ -3406,17 +3724,17 @@ PerlIO_funcs PerlIO_pending = { */ typedef struct { - PerlIOBuf base; /* PerlIOBuf stuff */ - STDCHAR *nl; /* Position of crlf we "lied" about in the + PerlIOBuf base; /* PerlIOBuf stuff */ + STDCHAR *nl; /* Position of crlf we "lied" about in the * buffer */ } PerlIOCrlf; IV -PerlIOCrlf_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg) +PerlIOCrlf_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { IV code; PerlIOBase(f)->flags |= PERLIO_F_CRLF; - code = PerlIOBuf_pushed(aTHX_ f, mode, arg); + code = PerlIOBuf_pushed(aTHX_ f, mode, arg, tab); #if 0 PerlIO_debug("PerlIOCrlf_pushed f=%p %s %s fl=%08" UVxf "\n", f, PerlIOBase(f)->tab->name, (mode) ? mode : "(Null)", @@ -3483,8 +3801,8 @@ PerlIOCrlf_get_cnt(pTHX_ PerlIO *f) PerlIO_get_base(f); if (PerlIOBase(f)->flags & PERLIO_F_RDBUF) { PerlIOCrlf *c = PerlIOSelf(f, PerlIOCrlf); - if ((PerlIOBase(f)->flags & PERLIO_F_CRLF) && !c->nl) { - STDCHAR *nl = b->ptr; + if ((PerlIOBase(f)->flags & PERLIO_F_CRLF) && (!c->nl || *c->nl == 0xd)) { + STDCHAR *nl = (c->nl) ? c->nl : b->ptr; scan: while (nl < b->end && *nl != 0xd) nl++; @@ -3518,19 +3836,19 @@ PerlIOCrlf_get_cnt(pTHX_ PerlIO *f) } else { int code; - b->ptr++; /* say we have read it as far as + b->ptr++; /* say we have read it as far as * flush() is concerned */ - b->buf++; /* Leave space in front of buffer */ - b->bufsiz--; /* Buffer is thus smaller */ - code = PerlIO_fill(f); /* Fetch some more */ - b->bufsiz++; /* Restore size for next time */ - b->buf--; /* Point at space */ - b->ptr = nl = b->buf; /* Which is what we hand + b->buf++; /* Leave space in front of buffer */ + b->bufsiz--; /* Buffer is thus smaller */ + code = PerlIO_fill(f); /* Fetch some more */ + b->bufsiz++; /* Restore size for next time */ + b->buf--; /* Point at space */ + b->ptr = nl = b->buf; /* Which is what we hand * off */ - b->posn--; /* Buffer starts here */ - *nl = 0xd; /* Fill in the CR */ + b->posn--; /* Buffer starts here */ + *nl = 0xd; /* Fill in the CR */ if (code == 0) - goto test; /* fill() call worked */ + goto test; /* fill() call worked */ /* * CR at EOF - just fall through */ @@ -3549,38 +3867,40 @@ PerlIOCrlf_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt) { PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); PerlIOCrlf *c = PerlIOSelf(f, PerlIOCrlf); - IV flags = PerlIOBase(f)->flags; if (!b->buf) PerlIO_get_base(f); if (!ptr) { if (c->nl) { ptr = c->nl + 1; - if (ptr == b->end && *c->nl == 0xd) { + if (ptr == b->end && *c->nl == 0xd) { /* Defered CR at end of buffer case - we lied about count */ - ptr--; - } - } + ptr--; + } + } else { ptr = b->end; } ptr -= cnt; } else { +#if 0 /* * Test code - delete when it works ... */ + IV flags = PerlIOBase(f)->flags; STDCHAR *chk = (c->nl) ? (c->nl+1) : b->end; - if (ptr+cnt == c->nl && c->nl+1 == b->end && *c->nl == 0xd) { + 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_warn(aTHX_ "ptr wrong %p != %p fl=%08" UVxf + Perl_croak(aTHX_ "ptr wrong %p != %p fl=%08" UVxf " nl=%p e=%p for %d", ptr, chk, flags, c->nl, b->end, cnt); } +#endif } if (c->nl) { if (ptr > c->nl) { @@ -3622,8 +3942,8 @@ PerlIOCrlf_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count) break; } else { - *(b->ptr)++ = 0xd; /* CR */ - *(b->ptr)++ = 0xa; /* LF */ + *(b->ptr)++ = 0xd; /* CR */ + *(b->ptr)++ = 0xa; /* LF */ buf++; if (PerlIOBase(f)->flags & PERLIO_F_LINEBUF) { PerlIO_flush(f); @@ -3658,20 +3978,38 @@ PerlIOCrlf_flush(pTHX_ PerlIO *f) return PerlIOBuf_flush(aTHX_ f); } +IV +PerlIOCrlf_binmode(pTHX_ PerlIO *f) +{ + if ((PerlIOBase(f)->flags & PERLIO_F_CRLF)) { + /* In text mode - flush any pending stuff and flip it */ + 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 + } + return 0; +} + PerlIO_funcs PerlIO_crlf = { + sizeof(PerlIO_funcs), "crlf", sizeof(PerlIOCrlf), - PERLIO_K_BUFFERED | PERLIO_K_CANCRLF, + PERLIO_K_BUFFERED | PERLIO_K_CANCRLF | PERLIO_K_RAW, PerlIOCrlf_pushed, - PerlIOBase_noop_ok, /* popped */ + PerlIOBuf_popped, /* popped */ PerlIOBuf_open, + PerlIOCrlf_binmode, /* binmode */ NULL, PerlIOBase_fileno, PerlIOBuf_dup, - PerlIOBuf_read, /* generic read works with ptr/cnt lies + PerlIOBuf_read, /* generic read works with ptr/cnt lies * ... */ - PerlIOCrlf_unread, /* Put CR,LF in buffer for each '\n' */ - PerlIOCrlf_write, /* Put CR,LF in buffer for each '\n' */ + PerlIOCrlf_unread, /* Put CR,LF in buffer for each '\n' */ + PerlIOCrlf_write, /* Put CR,LF in buffer for each '\n' */ PerlIOBuf_seek, PerlIOBuf_tell, PerlIOBuf_close, @@ -3695,10 +4033,10 @@ PerlIO_funcs PerlIO_crlf = { */ typedef struct { - PerlIOBuf base; /* PerlIOBuf stuff */ - Mmap_t mptr; /* Mapped address */ - Size_t len; /* mapped length */ - STDCHAR *bbuf; /* malloced buffer if map fails */ + PerlIOBuf base; /* PerlIOBuf stuff */ + Mmap_t mptr; /* Mapped address */ + Size_t len; /* mapped length */ + STDCHAR *bbuf; /* malloced buffer if map fails */ } PerlIOMmap; static size_t page_size = 0; @@ -3749,7 +4087,7 @@ PerlIOMmap_map(pTHX_ PerlIO *f) page_size = getpagesize(); # else # if defined(I_SYS_PARAM) && defined(PAGESIZE) - page_size = PAGESIZE; /* compiletime, bad */ + page_size = PAGESIZE; /* compiletime, bad */ # endif # endif #endif @@ -3833,11 +4171,11 @@ PerlIOMmap_get_base(pTHX_ PerlIO *f) /* * We have a write buffer or flushed PerlIOBuf read buffer */ - m->bbuf = b->buf; /* save it in case we need it again */ - b->buf = NULL; /* Clear to trigger below */ + m->bbuf = b->buf; /* save it in case we need it again */ + b->buf = NULL; /* Clear to trigger below */ } if (!b->buf) { - PerlIOMmap_map(aTHX_ f); /* Try and map it */ + PerlIOMmap_map(aTHX_ f); /* Try and map it */ if (!b->buf) { /* * Map did not work - recover PerlIOBuf buffer if we have one @@ -3974,12 +4312,14 @@ PerlIOMmap_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags) PerlIO_funcs PerlIO_mmap = { + sizeof(PerlIO_funcs), "mmap", sizeof(PerlIOMmap), - PERLIO_K_BUFFERED, + PERLIO_K_BUFFERED|PERLIO_K_RAW, PerlIOBuf_pushed, - PerlIOBase_noop_ok, + PerlIOBuf_popped, PerlIOBuf_open, + PerlIOBase_binmode, /* binmode */ NULL, PerlIOBase_fileno, PerlIOMmap_dup, @@ -4002,7 +4342,7 @@ PerlIO_funcs PerlIO_mmap = { PerlIOBuf_set_ptrcnt, }; -#endif /* HAS_MMAP */ +#endif /* HAS_MMAP */ PerlIO * Perl_PerlIO_stdin(pTHX) @@ -4193,11 +4533,10 @@ PerlIO_tmpfile(void) PerlIO *f = NULL; FILE *stdio = PerlSIO_tmpfile(); if (stdio) { - PerlIOStdio *s = - PerlIOSelf(PerlIO_push - (aTHX_(f = PerlIO_allocate(aTHX)), &PerlIO_stdio, - "w+", Nullsv), PerlIOStdio); - s->stdio = stdio; + if ((f = PerlIO_push(aTHX_(PerlIO_allocate(aTHX)), &PerlIO_stdio, "w+", Nullsv))) { + PerlIOStdio *s = PerlIOSelf(f, PerlIOStdio); + s->stdio = stdio; + } } return f; #else @@ -4220,8 +4559,8 @@ PerlIO_tmpfile(void) #undef HAS_FSETPOS #undef HAS_FGETPOS -#endif /* USE_SFIO */ -#endif /* PERLIO_IS_STDIO */ +#endif /* USE_SFIO */ +#endif /* PERLIO_IS_STDIO */ /*======================================================================================*/ /* @@ -4300,7 +4639,7 @@ int vprintf(char *pat, char *args) { _doprnt(pat, args, stdout); - return 0; /* wrong, but perl doesn't use the return + return 0; /* wrong, but perl doesn't use the return * value */ } @@ -4308,7 +4647,7 @@ int vfprintf(FILE *fd, char *pat, char *args) { _doprnt(pat, args, fd); - return 0; /* wrong, but perl doesn't use the return + return 0; /* wrong, but perl doesn't use the return * value */ } @@ -4348,3 +4687,6 @@ PerlIO_sprintf(char *s, int n, const char *fmt, ...) + + +